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:
authorYimingWu <xp8110@outlook.com>2019-10-24 15:36:28 +0300
committerYimingWu <xp8110@outlook.com>2019-10-24 15:36:28 +0300
commite910924b37a3fdffeb38ac14c656c16f107a9c0d (patch)
treeab626478bbb650837fd54140cfbb30a04edb6a26
parentf60406ff257c3309418413b5af76373010fb2a6f (diff)
parent42eef8f81a6aea27094985347ab802dc6bb91a61 (diff)
Merge remote-tracking branch 'origin/master' into soc-2019-npr
-rw-r--r--.clang-format10
-rw-r--r--.github/stale.yml22
-rw-r--r--CMakeLists.txt31
-rw-r--r--GNUmakefile16
-rw-r--r--build_files/build_environment/CMakeLists.txt6
-rw-r--r--build_files/build_environment/cmake/check_software.cmake8
-rw-r--r--build_files/build_environment/cmake/ffmpeg.cmake8
-rw-r--r--build_files/build_environment/cmake/harvest.cmake6
-rw-r--r--build_files/build_environment/cmake/libglu.cmake40
-rw-r--r--build_files/build_environment/cmake/mesa.cmake54
-rw-r--r--build_files/build_environment/cmake/opus.cmake35
-rw-r--r--build_files/build_environment/cmake/theora.cmake2
-rw-r--r--build_files/build_environment/cmake/versions.cmake12
-rw-r--r--build_files/build_environment/cmake/vpx.cmake2
-rwxr-xr-xbuild_files/build_environment/install_deps.sh36
-rw-r--r--build_files/buildbot/buildbot_utils.py2
-rw-r--r--build_files/buildbot/config/blender_linux.cmake23
-rw-r--r--build_files/buildbot/slave_pack.py20
-rw-r--r--build_files/buildbot/slave_update.py2
-rw-r--r--build_files/cmake/Modules/GTestTesting.cmake8
-rw-r--r--build_files/cmake/buildinfo.cmake21
-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/macros.cmake11
-rw-r--r--build_files/cmake/platform/platform_apple.cmake23
-rw-r--r--build_files/cmake/platform/platform_unix.cmake44
-rw-r--r--build_files/cmake/platform/platform_win32.cmake46
-rwxr-xr-xbuild_files/utils/make_test.py11
-rwxr-xr-xbuild_files/utils/make_update.py122
-rwxr-xr-xbuild_files/utils/make_utils.py14
-rw-r--r--build_files/windows/configure_ninja.cmd12
-rw-r--r--build_files/windows/parse_arguments.cmd2
-rw-r--r--doc/doxygen/Doxyfile2
-rwxr-xr-xdoc/manpage/blender.1.py21
-rwxr-xr-xdoc/python_api/sphinx_doc_update.py38
-rw-r--r--extern/audaspace/src/devices/SoftwareDevice.cpp2
-rw-r--r--extern/cuew/src/cuew.c19
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc3
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h22
-rw-r--r--extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h18
-rw-r--r--extern/quadriflow/CMakeLists.txt75
-rw-r--r--extern/quadriflow/README.blender5
-rw-r--r--extern/quadriflow/patches/blender.patch118
-rw-r--r--extern/quadriflow/src/config.hpp5
-rw-r--r--extern/quadriflow/src/hierarchy.cpp3
-rw-r--r--intern/clog/clog.c1
-rw-r--r--intern/cycles/blender/addon/properties.py6
-rw-r--r--intern/cycles/blender/addon/ui.py2
-rw-r--r--intern/cycles/blender/blender_camera.cpp2
-rw-r--r--intern/cycles/blender/blender_object.cpp5
-rw-r--r--intern/cycles/blender/blender_shader.cpp12
-rw-r--r--intern/cycles/blender/blender_sync.cpp3
-rw-r--r--intern/cycles/blender/blender_viewport.cpp16
-rw-r--r--intern/cycles/blender/blender_viewport.h4
-rw-r--r--intern/cycles/device/device.cpp1
-rw-r--r--intern/cycles/device/device_cpu.cpp6
-rw-r--r--intern/cycles/device/device_cuda.cpp6
-rw-r--r--intern/cycles/device/device_memory.h1
-rw-r--r--intern/cycles/device/device_optix.cpp704
-rw-r--r--intern/cycles/kernel/CMakeLists.txt24
-rw-r--r--intern/cycles/kernel/bvh/bvh.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h12
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h20
-rw-r--r--intern/cycles/kernel/filter/filter_transform_gpu.h6
-rw-r--r--intern/cycles/kernel/filter/filter_transform_sse.h6
-rw-r--r--intern/cycles/kernel/kernel_passes.h4
-rw-r--r--intern/cycles/kernel/kernel_path.h2
-rw-r--r--intern/cycles/kernel/kernel_types.h14
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp4
-rw-r--r--intern/cycles/kernel/shaders/node_mix.osl4
-rw-r--r--intern/cycles/kernel/svm/svm_color_util.h12
-rw-r--r--intern/cycles/kernel/svm/svm_noise.h2
-rw-r--r--intern/cycles/render/buffers.cpp2
-rw-r--r--intern/cycles/render/denoising.cpp4
-rw-r--r--intern/cycles/render/film.cpp2
-rw-r--r--intern/cycles/render/nodes.cpp14
-rw-r--r--intern/cycles/render/shader.cpp2
-rw-r--r--intern/cycles/util/util_defines.h192
-rw-r--r--intern/cycles/util/util_hash.h6
-rw-r--r--intern/cycles/util/util_static_assert.h16
-rw-r--r--intern/ffmpeg/ffmpeg_compat.h36
-rw-r--r--intern/ghost/GHOST_C-api.h43
-rw-r--r--intern/ghost/GHOST_ISystem.h27
-rw-r--r--intern/ghost/GHOST_IWindow.h8
-rw-r--r--intern/ghost/GHOST_Types.h26
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp64
-rw-r--r--intern/ghost/intern/GHOST_System.h27
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h8
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm205
-rw-r--r--intern/ghost/intern/GHOST_SystemNULL.h5
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp1
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.h1
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp77
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h25
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp262
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h18
-rw-r--r--intern/ghost/intern/GHOST_Window.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h9
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm220
-rw-r--r--intern/ghost/intern/GHOST_WindowNULL.h7
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.cpp92
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.h1
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp295
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h12
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp236
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h10
-rw-r--r--intern/ghost/test/CMakeLists.txt40
-rw-r--r--intern/guardedalloc/intern/mallocn.c2
-rw-r--r--intern/libmv/libmv/autotrack/callbacks.h2
-rw-r--r--intern/mikktspace/mikktspace.c5
-rw-r--r--intern/numaapi/README.blender2
-rw-r--r--intern/numaapi/source/build_config.h27
-rw-r--r--intern/opensubdiv/internal/opensubdiv_topology_refiner.cc19
-rw-r--r--intern/opensubdiv/opensubdiv_topology_refiner_capi.h8
-rw-r--r--intern/quadriflow/CMakeLists.txt2
-rw-r--r--release/darwin/Blender.app/Contents/Resources/arrowdown.pdfbin0 -> 4114 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/arrowleft.pdfbin0 -> 4108 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/arrowright.pdfbin0 -> 4113 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/arrowup.pdfbin0 -> 4105 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/crossc.pdfbin0 -> 4079 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/eraser.pdfbin0 -> 4187 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/eyedropper.pdfbin0 -> 4500 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/knife.pdfbin0 -> 4134 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/paint_cursor_cross.pdfbin0 -> 4300 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/paint_cursor_dot.pdfbin0 -> 4147 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/pen.pdfbin0 -> 4173 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/scrollew.pdfbin0 -> 4157 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/scrollns.pdfbin0 -> 4175 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/scrollnsew.pdfbin0 -> 4317 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/splith.pdfbin0 -> 4351 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/splitv.pdfbin0 -> 4343 bytes
-rw-r--r--release/darwin/Blender.app/Contents/Resources/zoomin.pdf674
-rw-r--r--release/darwin/Blender.app/Contents/Resources/zoomout.pdf676
-rw-r--r--release/datafiles/blender_icons16/icon16_desktop.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_external_drive.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_network_drive.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_desktop.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_external_drive.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_network_drive.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.draw_sharp.datbin0 -> 2492 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.elastic_deform.datbin0 -> 19340 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.mask.datbin2420 -> 1916 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.pinch.datbin2834 -> 2456 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.pose.datbin0 -> 1322 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.simplify.datbin3050 -> 5480 bytes
-rw-r--r--release/datafiles/icons/brush.sculpt.snake_hook.datbin2024 -> 5624 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.border_hide.datbin764 -> 620 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.border_mask.datbin980 -> 980 bytes
-rw-r--r--release/datafiles/icons/ops.sculpt.mesh_filter.datbin0 -> 2060 bytes
-rw-r--r--release/datafiles/userdef/userdef_default.c18
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c5
-rw-r--r--release/freedesktop/org.blender.Blender.appdata.xml21
-rw-r--r--release/scripts/modules/bl_app_override/__init__.py8
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py1
-rw-r--r--release/scripts/modules/bpy_extras/image_utils.py37
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py71
-rw-r--r--release/scripts/modules/bpy_extras/mesh_utils.py31
-rw-r--r--release/scripts/modules/bpy_extras/node_shader_utils.py47
-rw-r--r--release/scripts/modules/bpy_types.py129
-rw-r--r--release/scripts/modules/rna_manual_reference.py46
-rw-r--r--release/scripts/modules/rna_prop_ui.py7
-rw-r--r--release/scripts/presets/keyconfig/blender.py15
-rw-r--r--release/scripts/presets/keyconfig/blender_27x.py15
-rw-r--r--release/scripts/presets/keyconfig/industry_compatible.py8
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py125
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py18
-rw-r--r--release/scripts/startup/bl_operators/add_mesh_torus.py2
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py2
-rw-r--r--release/scripts/startup/bl_operators/sequencer.py97
-rw-r--r--release/scripts/startup/bl_operators/userpref.py5
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_lightmap.py7
-rw-r--r--release/scripts/startup/bl_operators/wm.py7
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py16
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lattice.py7
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py38
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py97
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py3
-rw-r--r--release/scripts/startup/bl_ui/space_console.py2
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py98
-rw-r--r--release/scripts/startup/bl_ui/space_image.py3
-rw-r--r--release/scripts/startup/bl_ui/space_info.py8
-rw-r--r--release/scripts/startup/bl_ui/space_node.py9
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py13
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py38
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py1
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py28
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py105
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py38
-rw-r--r--release/scripts/templates_py/operator_mesh_add.py17
-rw-r--r--release/scripts/templates_py/operator_modal_draw.py1
-rw-r--r--release/scripts/templates_py/ui_tool_simple.py11
-rw-r--r--release/windows/icons/cursors/arrowdown.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/arrowleft.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/arrowright.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/arrowup.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/cross.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/crossa.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/crossb.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/crossc.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/eraser.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/eyedropper.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/forbidden.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/handopen.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/knife.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/moveew.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/movens.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/pencil.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/pointer.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/scrollew.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/scrollns.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/scrollnsew.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/splith.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/splitv.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/zoomin.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/cursors/zoomout.curbin0 -> 30894 bytes
-rw-r--r--release/windows/icons/winblender.rc27
-rw-r--r--source/blender/alembic/ABC_alembic.h5
-rw-r--r--source/blender/alembic/intern/abc_archive.cc20
-rw-r--r--source/blender/alembic/intern/abc_archive.h4
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc8
-rw-r--r--source/blender/alembic/intern/abc_exporter.h2
-rw-r--r--source/blender/alembic/intern/abc_hair.cc8
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc31
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc17
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h5
-rw-r--r--source/blender/blenkernel/BKE_action.h4
-rw-r--r--source/blender/blenkernel/BKE_animsys.h3
-rw-r--r--source/blender/blenkernel/BKE_appdir.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h4
-rw-r--r--source/blender/blenkernel/BKE_brush.h7
-rw-r--r--source/blender/blenkernel/BKE_curve.h7
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h5
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h4
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h1
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h9
-rw-r--r--source/blender/blenkernel/BKE_image.h6
-rw-r--r--source/blender/blenkernel/BKE_layer.h12
-rw-r--r--source/blender/blenkernel/BKE_library.h6
-rw-r--r--source/blender/blenkernel/BKE_mesh.h29
-rw-r--r--source/blender/blenkernel/BKE_mesh_remesh_voxel.h7
-rw-r--r--source/blender/blenkernel/BKE_mirror.h45
-rw-r--r--source/blender/blenkernel/BKE_modifier.h3
-rw-r--r--source/blender/blenkernel/BKE_multires.h4
-rw-r--r--source/blender/blenkernel/BKE_node.h5
-rw-r--r--source/blender/blenkernel/BKE_object.h6
-rw-r--r--source/blender/blenkernel/BKE_object_facemap.h5
-rw-r--r--source/blender/blenkernel/BKE_paint.h11
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h102
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h10
-rw-r--r--source/blender/blenkernel/BKE_scene.h7
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h1
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h5
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h2
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h61
-rw-r--r--source/blender/blenkernel/BKE_subdiv_deform.h40
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h7
-rw-r--r--source/blender/blenkernel/BKE_subdiv_topology.h31
-rw-r--r--source/blender/blenkernel/BKE_text.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt17
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c54
-rw-r--r--source/blender/blenkernel/intern/action.c4
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c16
-rw-r--r--source/blender/blenkernel/intern/appdir.c2
-rw-r--r--source/blender/blenkernel/intern/armature.c4
-rw-r--r--source/blender/blenkernel/intern/armature_update.c36
-rw-r--r--source/blender/blenkernel/intern/brush.c604
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c2
-rw-r--r--source/blender/blenkernel/intern/cachefile.c2
-rw-r--r--source/blender/blenkernel/intern/cloth.c2
-rw-r--r--source/blender/blenkernel/intern/collection.c5
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c91
-rw-r--r--source/blender/blenkernel/intern/curve.c85
-rw-r--r--source/blender/blenkernel/intern/displist.c8
-rw-r--r--source/blender/blenkernel/intern/editlattice.c31
-rw-r--r--source/blender/blenkernel/intern/editmesh.c21
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c2
-rw-r--r--source/blender/blenkernel/intern/font.c3
-rw-r--r--source/blender/blenkernel/intern/gpencil.c18
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c17
-rw-r--r--source/blender/blenkernel/intern/image.c41
-rw-r--r--source/blender/blenkernel/intern/layer.c149
-rw-r--r--source/blender/blenkernel/intern/library.c34
-rw-r--r--source/blender/blenkernel/intern/library_remap.c3
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c181
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c12
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.c122
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c6
-rw-r--r--source/blender/blenkernel/intern/mirror.c419
-rw-r--r--source/blender/blenkernel/intern/modifier.c17
-rw-r--r--source/blender/blenkernel/intern/movieclip.c4
-rw-r--r--source/blender/blenkernel/intern/multires.c56
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c2
-rw-r--r--source/blender/blenkernel/intern/nla.c4
-rw-r--r--source/blender/blenkernel/intern/node.c68
-rw-r--r--source/blender/blenkernel/intern/object.c17
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c8
-rw-r--r--source/blender/blenkernel/intern/object_facemap.c38
-rw-r--r--source/blender/blenkernel/intern/object_update.c4
-rw-r--r--source/blender/blenkernel/intern/packedFile.c13
-rw-r--r--source/blender/blenkernel/intern/paint.c65
-rw-r--r--source/blender/blenkernel/intern/particle.c4
-rw-r--r--source/blender/blenkernel/intern/pbvh.c592
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c38
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h1
-rw-r--r--source/blender/blenkernel/intern/pbvh_parallel.cc145
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c56
-rw-r--r--source/blender/blenkernel/intern/scene.c23
-rw-r--r--source/blender/blenkernel/intern/seqcache.c7
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c2
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c3
-rw-r--r--source/blender/blenkernel/intern/seqprefetch.c51
-rw-r--r--source/blender/blenkernel/intern/sequencer.c10
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c83
-rw-r--r--source/blender/blenkernel/intern/smoke.c26
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c690
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c237
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c21
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c8
-rw-r--r--source/blender/blenkernel/intern/subdiv_topology.c34
-rw-r--r--source/blender/blenkernel/intern/text.c60
-rw-r--r--source/blender/blenlib/BLI_array_ref.h12
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h34
-rw-r--r--source/blender/blenlib/BLI_fileops.h1
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h8
-rw-r--r--source/blender/blenlib/BLI_hash_cxx.h8
-rw-r--r--source/blender/blenlib/BLI_kdtree_impl.h10
-rw-r--r--source/blender/blenlib/BLI_map.h232
-rw-r--r--source/blender/blenlib/BLI_math_geom.h6
-rw-r--r--source/blender/blenlib/BLI_memblock.h11
-rw-r--r--source/blender/blenlib/BLI_set.h80
-rw-r--r--source/blender/blenlib/BLI_sort.h2
-rw-r--r--source/blender/blenlib/BLI_stack_cxx.h2
-rw-r--r--source/blender/blenlib/BLI_string_map.h48
-rw-r--r--source/blender/blenlib/BLI_vector.h19
-rw-r--r--source/blender/blenlib/BLI_vector_set.h (renamed from source/blender/blenlib/BLI_set_vector.h)132
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c2
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c23
-rw-r--r--source/blender/blenlib/intern/BLI_temporary_allocator.cc2
-rw-r--r--source/blender/blenlib/intern/BLI_timer.c1
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c126
-rw-r--r--source/blender/blenlib/intern/expr_pylike_eval.c8
-rw-r--r--source/blender/blenlib/intern/fileops.c195
-rw-r--r--source/blender/blenlib/intern/gsqueue.c216
-rw-r--r--source/blender/blenlib/intern/listbase.c2
-rw-r--r--source/blender/blenlib/intern/math_matrix.c4
-rw-r--r--source/blender/blenlib/intern/math_solvers.c6
-rw-r--r--source/blender/blenlib/intern/scanfill.c2
-rw-r--r--source/blender/blenlib/intern/sort.c2
-rw-r--r--source/blender/blenlib/intern/stack.c15
-rw-r--r--source/blender/blenlib/intern/storage.c7
-rw-r--r--source/blender/blenlib/intern/task.c36
-rw-r--r--source/blender/blenloader/intern/readfile.c173
-rw-r--r--source/blender/blenloader/intern/versioning_250.c14
-rw-r--r--source/blender/blenloader/intern/versioning_270.c3
-rw-r--r--source/blender/blenloader/intern/versioning_280.c95
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c22
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c107
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c40
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c30
-rw-r--r--source/blender/blenloader/intern/writefile.c45
-rw-r--r--source/blender/blentranslation/msgfmt/CMakeLists.txt4
-rw-r--r--source/blender/bmesh/CMakeLists.txt2
-rw-r--r--source/blender/bmesh/bmesh.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_duplicate.c139
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_duplicate.h33
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c85
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h7
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c4
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c2
-rw-r--r--source/blender/collada/AnimationImporter.cpp2
-rw-r--r--source/blender/collada/BCAnimationCurve.cpp2
-rw-r--r--source/blender/collada/BlenderContext.cpp2
-rw-r--r--source/blender/collada/ImageExporter.cpp2
-rw-r--r--source/blender/collada/collada_internal.cpp2
-rw-r--r--source/blender/collada/collada_utils.cpp10
-rw-r--r--source/blender/compositor/CMakeLists.txt1
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h4
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h7
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h12
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc41
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h136
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc41
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h180
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc8
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc151
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc26
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc53
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc29
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc20
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc44
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c71
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c7
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl23
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl76
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl1
-rw-r--r--source/blender/draw/engines/external/external_engine.c5
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c4
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c246
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c208
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h13
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c5
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl5
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl3
-rw-r--r--source/blender/draw/engines/select/select_draw_utils.c11
-rw-r--r--source/blender/draw/engines/select/select_engine.c4
-rw-r--r--source/blender/draw/engines/select/select_private.h2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl3
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl28
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl7
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c23
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_taa.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c56
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c137
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h25
-rw-r--r--source/blender/draw/engines/workbench/workbench_studiolight.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c10
-rw-r--r--source/blender/draw/intern/DRW_render.h46
-rw-r--r--source/blender/draw/intern/draw_anim_viz.c11
-rw-r--r--source/blender/draw/intern/draw_armature.c1
-rw-r--r--source/blender/draw/intern/draw_cache.c6
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h8
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c85
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h5
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c161
-rw-r--r--source/blender/draw/intern/draw_common.c4
-rw-r--r--source/blender/draw/intern/draw_common.h1
-rw-r--r--source/blender/draw/intern/draw_hair.c41
-rw-r--r--source/blender/draw/intern/draw_instance_data.c4
-rw-r--r--source/blender/draw/intern/draw_instance_data.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c260
-rw-r--r--source/blender/draw/intern/draw_manager.h320
-rw-r--r--source/blender/draw/intern/draw_manager_data.c917
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c696
-rw-r--r--source/blender/draw/intern/draw_view.c38
-rw-r--r--source/blender/draw/intern/draw_view.h1
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c12
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c46
-rw-r--r--source/blender/draw/modes/object_mode.c515
-rw-r--r--source/blender/draw/modes/overlay_mode.c38
-rw-r--r--source/blender/draw/modes/sculpt_mode.c3
-rw-r--r--source/blender/draw/modes/shaders/common_globals_lib.glsl1
-rw-r--r--source/blender/draw/modes/shaders/common_view_lib.glsl70
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl30
-rw-r--r--source/blender/draw/modes/shaders/object_camera_image_frag.glsl2
-rw-r--r--source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl12
-rw-r--r--source/blender/draw/modes/shaders/object_outline_detect_frag.glsl40
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl14
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl7
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl17
-rw-r--r--source/blender/draw/modes/shaders/volume_velocity_vert.glsl15
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c2
-rw-r--r--source/blender/editors/animation/anim_filter.c4
-rw-r--r--source/blender/editors/animation/anim_markers.c69
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c269
-rw-r--r--source/blender/editors/animation/drivers.c55
-rw-r--r--source/blender/editors/animation/keyframes_draw.c3
-rw-r--r--source/blender/editors/animation/keyframing.c2
-rw-r--r--source/blender/editors/armature/armature_select.c9
-rw-r--r--source/blender/editors/armature/pose_edit.c47
-rw-r--r--source/blender/editors/armature/pose_select.c3
-rw-r--r--source/blender/editors/armature/pose_slide.c26
-rw-r--r--source/blender/editors/armature/pose_transform.c221
-rw-r--r--source/blender/editors/armature/pose_utils.c9
-rw-r--r--source/blender/editors/curve/curve_ops.c3
-rw-r--r--source/blender/editors/curve/editcurve.c9
-rw-r--r--source/blender/editors/curve/editcurve_add.c1
-rw-r--r--source/blender/editors/curve/editcurve_paint.c8
-rw-r--r--source/blender/editors/curve/editcurve_select.c10
-rw-r--r--source/blender/editors/curve/editcurve_undo.c2
-rw-r--r--source/blender/editors/curve/editfont.c6
-rw-r--r--source/blender/editors/curve/editfont_undo.c2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c16
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c2
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c75
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c51
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c29
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h7
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_ops_versioning.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c263
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c297
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c106
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c2
-rw-r--r--source/blender/editors/include/ED_anim_api.h20
-rw-r--r--source/blender/editors/include/ED_armature.h10
-rw-r--r--source/blender/editors/include/ED_fileselect.h2
-rw-r--r--source/blender/editors/include/ED_gpencil.h7
-rw-r--r--source/blender/editors/include/ED_image.h2
-rw-r--r--source/blender/editors/include/ED_keyframing.h13
-rw-r--r--source/blender/editors/include/ED_mesh.h14
-rw-r--r--source/blender/editors/include/ED_object.h10
-rw-r--r--source/blender/editors/include/ED_paint.h33
-rw-r--r--source/blender/editors/include/ED_particle.h10
-rw-r--r--source/blender/editors/include/ED_screen.h10
-rw-r--r--source/blender/editors/include/ED_view3d.h4
-rw-r--r--source/blender/editors/include/UI_icons.h6
-rw-r--r--source/blender/editors/include/UI_interface.h5
-rw-r--r--source/blender/editors/include/UI_resources.h3
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface.c9
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_context_menu.c39
-rw-r--r--source/blender/editors/interface/interface_draw.c12
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c1
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_gpencil_color.c324
-rw-r--r--source/blender/editors/interface/interface_handlers.c21
-rw-r--r--source/blender/editors/interface/interface_icons.c1
-rw-r--r--source/blender/editors/interface/interface_icons_event.c7
-rw-r--r--source/blender/editors/interface/interface_intern.h6
-rw-r--r--source/blender/editors/interface/interface_layout.c52
-rw-r--r--source/blender/editors/interface/interface_ops.c9
-rw-r--r--source/blender/editors/interface/interface_query.c46
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c2
-rw-r--r--source/blender/editors/interface/interface_region_popover.c3
-rw-r--r--source/blender/editors/interface/interface_region_popup.c2
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/interface/interface_widgets.c10
-rw-r--r--source/blender/editors/interface/resources.c10
-rw-r--r--source/blender/editors/interface/view2d.c2
-rw-r--r--source/blender/editors/interface/view2d_ops.c12
-rw-r--r--source/blender/editors/io/io_alembic.c5
-rw-r--r--source/blender/editors/lattice/editlattice_select.c6
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c3
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c1
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c32
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c6
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c20
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c1
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c24
-rw-r--r--source/blender/editors/mesh/editmesh_select.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c202
-rw-r--r--source/blender/editors/mesh/mesh_data.c141
-rw-r--r--source/blender/editors/mesh/meshtools.c38
-rw-r--r--source/blender/editors/metaball/mball_edit.c6
-rw-r--r--source/blender/editors/object/object_add.c32
-rw-r--r--source/blender/editors/object/object_bake.c4
-rw-r--r--source/blender/editors/object/object_bake_api.c8
-rw-r--r--source/blender/editors/object/object_collection.c8
-rw-r--r--source/blender/editors/object/object_edit.c60
-rw-r--r--source/blender/editors/object/object_modifier.c4
-rw-r--r--source/blender/editors/object/object_relations.c11
-rw-r--r--source/blender/editors/object/object_remesh.c268
-rw-r--r--source/blender/editors/object/object_select.c4
-rw-r--r--source/blender/editors/object/object_transform.c3
-rw-r--r--source/blender/editors/physics/particle_edit.c350
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c27
-rw-r--r--source/blender/editors/physics/particle_object.c6
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c8
-rw-r--r--source/blender/editors/physics/rigidbody_object.c2
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/render/render_preview.c4
-rw-r--r--source/blender/editors/render/render_shading.c14
-rw-r--r--source/blender/editors/render/render_view.c11
-rw-r--r--source/blender/editors/scene/scene_edit.c5
-rw-r--r--source/blender/editors/screen/area.c34
-rw-r--r--source/blender/editors/screen/area_query.c2
-rw-r--r--source/blender/editors/screen/area_utils.c1
-rw-r--r--source/blender/editors/screen/glutil.c2
-rw-r--r--source/blender/editors/screen/screen_context.c8
-rw-r--r--source/blender/editors/screen/screen_draw.c4
-rw-r--r--source/blender/editors/screen/screen_edit.c80
-rw-r--r--source/blender/editors/screen/screen_ops.c64
-rw-r--r--source/blender/editors/screen/screen_user_menu.c24
-rw-r--r--source/blender/editors/screen/workspace_edit.c10
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c406
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c22
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c88
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c78
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c625
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h33
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c69
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c69
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c75
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c2246
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h35
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c109
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c1
-rw-r--r--source/blender/editors/sound/sound_ops.c3
-rw-r--r--source/blender/editors/space_action/action_edit.c8
-rw-r--r--source/blender/editors/space_action/action_select.c182
-rw-r--r--source/blender/editors/space_clip/clip_draw.c284
-rw-r--r--source/blender/editors/space_clip/clip_intern.h1
-rw-r--r--source/blender/editors/space_clip/clip_ops.c137
-rw-r--r--source/blender/editors/space_clip/space_clip.c1
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c4
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c6
-rw-r--r--source/blender/editors/space_clip/tracking_ops_utils.c4
-rw-r--r--source/blender/editors/space_console/space_console.c4
-rw-r--r--source/blender/editors/space_file/file_intern.h6
-rw-r--r--source/blender/editors/space_file/file_ops.c179
-rw-r--r--source/blender/editors/space_file/file_panels.c54
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_file/filesel.c118
-rw-r--r--source/blender/editors/space_file/space_file.c122
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c14
-rw-r--r--source/blender/editors/space_graph/graph_draw.c4
-rw-r--r--source/blender/editors/space_graph/graph_edit.c10
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_image/image_edit.c18
-rw-r--r--source/blender/editors/space_image/image_intern.h3
-rw-r--r--source/blender/editors/space_image/image_ops.c358
-rw-r--r--source/blender/editors/space_image/image_undo.c1058
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_nla/nla_select.c47
-rw-r--r--source/blender/editors/space_node/drawnode.c46
-rw-r--r--source/blender/editors/space_node/node_add.c2
-rw-r--r--source/blender/editors/space_node/node_draw.c10
-rw-r--r--source/blender/editors/space_node/node_group.c116
-rw-r--r--source/blender/editors/space_node/node_relationships.c2
-rw-r--r--source/blender/editors/space_node/node_select.c108
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c8
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c5
-rw-r--r--source/blender/editors/space_script/script_edit.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c50
-rw-r--r--source/blender/editors/space_text/space_text.c4
-rw-r--r--source/blender/editors/space_text/text_format_lua.c34
-rw-r--r--source/blender/editors/space_text/text_format_osl.c10
-rw-r--r--source/blender/editors/space_text/text_format_pov.c10
-rw-r--r--source/blender/editors/space_text/text_format_pov_ini.c6
-rw-r--r--source/blender/editors/space_text/text_format_py.c10
-rw-r--r--source/blender/editors/space_text/text_ops.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c34
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c12
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_armature.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_camera.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_empty.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_forcefield.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_light.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c29
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c23
-rw-r--r--source/blender/editors/transform/transform.c10
-rw-r--r--source/blender/editors/transform/transform.h1
-rw-r--r--source/blender/editors/transform/transform_convert.c27
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c8
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c3
-rw-r--r--source/blender/editors/transform/transform_convert_object.c12
-rw-r--r--source/blender/editors/transform/transform_convert_particle.c4
-rw-r--r--source/blender/editors/transform/transform_generics.c18
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c57
-rw-r--r--source/blender/editors/transform/transform_input.c4
-rw-r--r--source/blender/editors/transform/transform_ops.c4
-rw-r--r--source/blender/editors/transform/transform_orientations.c1
-rw-r--r--source/blender/editors/transform/transform_snap_object.c5
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c14
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c8
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.h9
-rw-r--r--source/blender/freestyle/intern/view_map/Interface1D.h10
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c14
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h14
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c5
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c16
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c15
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c1
-rw-r--r--source/blender/gpu/CMakeLists.txt4
-rw-r--r--source/blender/gpu/GPU_batch.h13
-rw-r--r--source/blender/gpu/GPU_buffers.h24
-rw-r--r--source/blender/gpu/GPU_extensions.h28
-rw-r--r--source/blender/gpu/GPU_platform.h75
-rw-r--r--source/blender/gpu/GPU_shader_interface.h9
-rw-r--r--source/blender/gpu/GPU_viewport.h10
-rw-r--r--source/blender/gpu/intern/gpu_batch.c234
-rw-r--r--source/blender/gpu/intern/gpu_batch_utils.c1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c520
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c35
-rw-r--r--source/blender/gpu/intern/gpu_draw.c1
-rw-r--r--source/blender/gpu/intern/gpu_element.c2
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c99
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c6
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c9
-rw-r--r--source/blender/gpu/intern/gpu_platform.c229
-rw-r--r--source/blender/gpu/intern/gpu_private.h8
-rw-r--r--source/blender/gpu/intern/gpu_shader.c7
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.c5
-rw-r--r--source/blender/gpu/intern/gpu_texture.c1
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c25
-rw-r--r--source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl19
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl25
-rw-r--r--source/blender/imbuf/IMB_imbuf.h35
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h2
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h2
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c18
-rw-r--r--source/blender/imbuf/intern/anim_movie.c61
-rw-r--r--source/blender/imbuf/intern/filetype.c4
-rw-r--r--source/blender/imbuf/intern/imageprocess.c5
-rw-r--r--source/blender/imbuf/intern/indexer.c2
-rw-r--r--source/blender/imbuf/intern/jp2.c2
-rw-r--r--source/blender/imbuf/intern/rectop.c92
-rw-r--r--source/blender/imbuf/intern/util.c4
-rw-r--r--source/blender/makesdna/DNA_ID.h12
-rw-r--r--source/blender/makesdna/DNA_brush_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_brush_types.h11
-rw-r--r--source/blender/makesdna/DNA_curve_types.h7
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h2
-rw-r--r--source/blender/makesdna/DNA_gpu_types.h26
-rw-r--r--source/blender/makesdna/DNA_layer_types.h21
-rw-r--r--source/blender/makesdna/DNA_mesh_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h7
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h20
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h6
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h10
-rw-r--r--source/blender/makesdna/DNA_space_types.h7
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h56
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h6
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c1
-rw-r--r--source/blender/makesrna/RNA_access.h3
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_access.c30
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c77
-rw-r--r--source/blender/makesrna/intern/rna_access_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_action.c6
-rw-r--r--source/blender/makesrna/intern/rna_animation.c3
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c4
-rw-r--r--source/blender/makesrna/intern/rna_boid.c4
-rw-r--r--source/blender/makesrna/intern/rna_brush.c117
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c1
-rw-r--r--source/blender/makesrna/intern/rna_curve.c17
-rw-r--r--source/blender/makesrna/intern/rna_define.c5
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c9
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c4
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c31
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c6
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c6
-rw-r--r--source/blender/makesrna/intern/rna_layer.c38
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c2
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_material.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c68
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c10
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c14
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c15
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c4
-rw-r--r--source/blender/makesrna/intern/rna_particle.c8
-rw-r--r--source/blender/makesrna/intern/rna_pose.c18
-rw-r--r--source/blender/makesrna/intern/rna_rna.c14
-rw-r--r--source/blender/makesrna/intern/rna_scene.c101
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_screen.c6
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c14
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c49
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c4
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c6
-rw-r--r--source/blender/makesrna/intern/rna_space.c45
-rw-r--r--source/blender/makesrna/intern/rna_text.c74
-rw-r--r--source/blender/makesrna/intern/rna_text_api.c31
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c6
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c114
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c33
-rw-r--r--source/blender/makesrna/intern/rna_workspace_api.c2
-rw-r--r--source/blender/modifiers/intern/MOD_array.c4
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c2
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c2
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c112
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c6
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c5
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c22
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c6
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c4
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c10
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c8
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c8
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_mdd.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_pc2.c4
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c378
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c39
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c5
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c2
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c75
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c4
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c148
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c70
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c37
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c2
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c66
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_util.c8
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c24
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c4
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c2
-rw-r--r--source/blender/nodes/CMakeLists.txt2
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c369
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.c41
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.c17
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.c6
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops.c16
-rw-r--r--source/blender/python/generic/bgl.c2
-rw-r--r--source/blender/python/generic/blf_py_api.c5
-rw-r--r--source/blender/python/generic/idprop_py_api.c9
-rw-r--r--source/blender/python/generic/imbuf_py_api.c124
-rw-r--r--source/blender/python/generic/py_capi_utils.c53
-rw-r--r--source/blender/python/generic/py_capi_utils.h11
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c2
-rw-r--r--source/blender/python/intern/bpy.c98
-rw-r--r--source/blender/python/intern/bpy_app_translations.c8
-rw-r--r--source/blender/python/intern/bpy_library_load.c2
-rw-r--r--source/blender/python/intern/bpy_props.c23
-rw-r--r--source/blender/python/intern/bpy_rna.c81
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c50
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c23
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.c2
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c66
-rw-r--r--source/blender/python/mathutils/mathutils_kdtree.c4
-rw-r--r--source/blender/render/intern/source/pipeline.c6
-rw-r--r--source/blender/render/intern/source/pointdensity.c2
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h28
-rw-r--r--source/blender/windowmanager/WM_types.h2
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c1667
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c135
-rw-r--r--source/blender/windowmanager/intern/wm_files.c2
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c4
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c14
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c22
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c257
-rw-r--r--source/blender/windowmanager/intern/wm_platform_support.c219
-rw-r--r--source/blender/windowmanager/intern/wm_platform_support.h30
-rw-r--r--source/blender/windowmanager/intern/wm_splash_screen.c108
-rw-r--r--source/blender/windowmanager/intern/wm_window.c272
-rw-r--r--source/blender/windowmanager/intern/wm_window_private.h42
-rw-r--r--source/blender/windowmanager/wm_cursors.h117
-rw-r--r--source/creator/CMakeLists.txt31
-rw-r--r--source/creator/creator_args.c2
-rw-r--r--source/creator/creator_signals.c6
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/gtests/blenlib/BLI_delaunay_2d_test.cc31
-rw-r--r--tests/gtests/blenlib/BLI_kdopbvh_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_map_test.cc38
-rw-r--r--tests/gtests/blenlib/BLI_memiter_test.cc8
-rw-r--r--tests/gtests/blenlib/BLI_set_test.cc16
-rw-r--r--tests/gtests/blenlib/BLI_stack_cxx_test.cc13
-rw-r--r--tests/gtests/blenlib/BLI_string_map_test.cc9
-rw-r--r--tests/gtests/blenlib/BLI_string_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_vector_set_test.cc (renamed from tests/gtests/blenlib/BLI_set_vector_test.cc)59
-rw-r--r--tests/gtests/blenlib/BLI_vector_test.cc16
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt2
-rw-r--r--tests/gtests/blenlib/stubs/bf_intern_eigen_stubs.h7
-rwxr-xr-xtests/python/ffmpeg_tests.py9
936 files changed, 25862 insertions, 12535 deletions
diff --git a/.clang-format b/.clang-format
index c4561ce960f..be3546fc49d 100644
--- a/.clang-format
+++ b/.clang-format
@@ -222,6 +222,16 @@ ForEachMacros:
- ITER_PIXELS
- ITER_SLOTS
- ITER_SLOTS_BEGIN
+ - LOOP_EDITED_POINTS
+ - LOOP_KEYS
+ - LOOP_POINTS
+ - LOOP_SELECTED_KEYS
+ - LOOP_SELECTED_POINTS
+ - LOOP_TAGGED_KEYS
+ - LOOP_TAGGED_POINTS
+ - LOOP_UNSELECTED_POINTS
+ - LOOP_VISIBLE_KEYS
+ - LOOP_VISIBLE_POINTS
- LISTBASE_CIRCULAR_BACKWARD_BEGIN
- LISTBASE_CIRCULAR_FORWARD_BEGIN
- LISTBASE_FOREACH
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 00000000000..9c563f2dee0
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,22 @@
+# Configuration for probot-stale - https://github.com/probot/stale
+# This file is used on Blender's GitHub mirror to automatically close any pull request
+# and invite contributors to join the official development platform on blender.org
+
+# Number of days of inactivity before an Issue or Pull Request becomes stale
+daysUntilStale: 1
+
+# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
+# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
+daysUntilClose: 1
+
+# Label to use when marking as stale
+staleLabel: stale
+
+# Comment to post when closing a stale Issue or Pull Request.
+closeComment: >
+ This issue has been automatically closed, because this repository is only
+ used as a mirror of git.blender.org. Blender development happens on
+ developer.blender.org.
+
+ To get started contributing code, please read:
+ https://wiki.blender.org/wiki/Process/Contributing_Code
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 258e79b7d4a..ba051b82671 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,6 +16,7 @@
#
# The Original Code is Copyright (C) 2006, Blender Foundation
# All rights reserved.
+#
# ***** END GPL LICENSE BLOCK *****
#-----------------------------------------------------------------------------
@@ -460,14 +461,14 @@ mark_as_advanced(WITH_CXX_GUARDEDALLOC)
option(WITH_ASSERT_ABORT "Call abort() when raising an assertion through BLI_assert()" ON)
mark_as_advanced(WITH_ASSERT_ABORT)
-option(WITH_BOOST "Enable features depending on boost" ON)
+option(WITH_BOOST "Enable features depending on boost" ON)
+option(WITH_TBB "Enable features depending on TBB (OpenVDB, OpenImageDenoise, sculpt multithreading)" ON)
# Unit testsing
option(WITH_GTESTS "Enable GTest unit testing" OFF)
option(WITH_OPENGL_RENDER_TESTS "Enable OpenGL render related unit testing (Experimental)" OFF)
option(WITH_OPENGL_DRAW_TESTS "Enable OpenGL UI drawing related unit testing (Experimental)" OFF)
-
# Documentation
if(UNIX AND NOT APPLE)
option(WITH_DOC_MANPAGE "Create a manual page (Unix manpage)" OFF)
@@ -584,6 +585,11 @@ if("${CMAKE_GENERATOR}" MATCHES "Ninja")
mark_as_advanced(WITH_NINJA_POOL_JOBS)
endif()
+if(UNIX AND NOT APPLE)
+ option(WITH_CXX11_ABI "Use native C++11 ABI of compiler" ON)
+ mark_as_advanced(WITH_CXX11_ABI)
+endif()
+
# avoid using again
option_defaults_clear()
@@ -1395,13 +1401,16 @@ if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_LOGICAL_OP -Wlogical-op)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNDEF -Wundef)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_INIT_SELF -Winit-self) # needs -Wuninitialized
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_NULL -Wnonnull) # C only
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_MISSING_INCLUDE_DIRS -Wmissing-include-dirs)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_TYPE_LIMITS -Wtype-limits)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_FORMAT_SIGN -Wformat-signedness)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_RESTRICT -Wrestrict)
+ # C-only.
+ ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_NULL -Wnonnull)
+ ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ABSOLUTE_VALUE -Wabsolute-value)
+
# gcc 4.2 gives annoying warnings on every file with this
if(NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "4.3")
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNINITIALIZED -Wuninitialized)
@@ -1610,15 +1619,19 @@ if(WITH_PYTHON)
endif()
endif()
-if(
+if(MSVC)
+ # MSVC needs to be tested first, since clang on windows will
+ # match the compiler test below but clang-cl does not accept -std=c++11
+ # since it is on by default and cannot be turned off.
+ #
+ # Nothing special is needed, C++11 features are available by default.
+elseif(
CMAKE_COMPILER_IS_GNUCC OR
CMAKE_C_COMPILER_ID MATCHES "Clang" OR
CMAKE_C_COMPILER_ID MATCHES "Intel"
)
# TODO(sergey): Do we want c++11 or gnu-c++11 here?
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
-elseif(MSVC)
- # Nothing special is needed, C++11 features are available by default.
else()
message(FATAL_ERROR "Unknown compiler ${CMAKE_C_COMPILER_ID}, can't enable C++11 build")
endif()
@@ -1634,6 +1647,12 @@ if(
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11")
endif()
+if(UNIX AND NOT APPLE)
+ if(NOT WITH_CXX11_ABI)
+ set(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
+ endif()
+endif()
+
# Include warnings first, so its possible to disable them with user defined flags
# eg: -Wno-uninitialized
set(CMAKE_C_FLAGS "${C_WARNINGS} ${CMAKE_C_FLAGS} ${PLATFORM_CFLAGS}")
diff --git a/GNUmakefile b/GNUmakefile
index d960a67e407..e52fd38a7e3 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -192,6 +192,16 @@ ifndef PYTHON
PYTHON:=python3
endif
+# For macOS python3 is not installed by default, so fallback to python binary
+# 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
+ ifeq (, $(shell command -v $(PYTHON)))
+ PYTHON:=python
+ endif
+ endif
+endif
# -----------------------------------------------------------------------------
# additional targets for the build configuration
@@ -374,7 +384,7 @@ package_archive: .FORCE
# Tests
#
test: .FORCE
- python3 ./build_files/utils/make_test.py "$(BUILD_DIR)"
+ $(PYTHON) ./build_files/utils/make_test.py "$(BUILD_DIR)"
# run pep8 check check on scripts we distribute.
test_pep8: .FORCE
@@ -530,11 +540,11 @@ icons_geom: .FORCE
"$(BLENDER_DIR)/release/datafiles/blender_icons_geom_update.py"
update: .FORCE
- python3 ./build_files/utils/make_update.py
+ $(PYTHON) ./build_files/utils/make_update.py
format: .FORCE
PATH="../lib/${OS_NCASE}/llvm/bin/:$(PATH)" \
- python3 source/tools/utils_maintenance/clang_format_paths.py $(PATHS)
+ $(PYTHON) source/tools/utils_maintenance/clang_format_paths.py $(PATHS)
# -----------------------------------------------------------------------------
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index 9756ad28454..c7d8de22890 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -128,6 +128,7 @@ if(NOT WIN32 OR ENABLE_MINGW64)
include(cmake/ogg.cmake)
include(cmake/vorbis.cmake)
include(cmake/theora.cmake)
+ include(cmake/opus.cmake)
include(cmake/vpx.cmake)
include(cmake/x264.cmake)
include(cmake/xvidcore.cmake)
@@ -157,4 +158,9 @@ if(UNIX)
include(cmake/sqlite.cmake)
endif()
+if(UNIX AND NOT APPLE)
+ include(cmake/libglu.cmake)
+ include(cmake/mesa.cmake)
+endif()
+
include(cmake/harvest.cmake)
diff --git a/build_files/build_environment/cmake/check_software.cmake b/build_files/build_environment/cmake/check_software.cmake
index 30dea754e20..f5774551879 100644
--- a/build_files/build_environment/cmake/check_software.cmake
+++ b/build_files/build_environment/cmake/check_software.cmake
@@ -17,10 +17,16 @@
# ***** END GPL LICENSE BLOCK *****
if(UNIX)
+ if(APPLE)
+ set(_libtoolize_name glibtoolize)
+ else()
+ set(_libtoolize_name libtoolize)
+ endif()
+
set(_required_software
autoconf
automake
- libtoolize
+ ${_libtoolize_name}
nasm
yasm
tclsh
diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake
index 27d817e8948..9ff52914f53 100644
--- a/build_files/build_environment/cmake/ffmpeg.cmake
+++ b/build_files/build_environment/cmake/ffmpeg.cmake
@@ -16,10 +16,10 @@
#
# ***** END GPL LICENSE BLOCK *****
-set(FFMPEG_CFLAGS "-I${mingw_LIBDIR}/lame/include -I${mingw_LIBDIR}/openjpeg/include/ -I${mingw_LIBDIR}/ogg/include -I${mingw_LIBDIR}/vorbis/include -I${mingw_LIBDIR}/theora/include -I${mingw_LIBDIR}/vpx/include -I${mingw_LIBDIR}/x264/include -I${mingw_LIBDIR}/xvidcore/include -I${mingw_LIBDIR}/zlib/include")
-set(FFMPEG_LDFLAGS "-L${mingw_LIBDIR}/lame/lib -L${mingw_LIBDIR}/openjpeg/lib -L${mingw_LIBDIR}/ogg/lib -L${mingw_LIBDIR}/vorbis/lib -L${mingw_LIBDIR}/theora/lib -L${mingw_LIBDIR}/vpx/lib -L${mingw_LIBDIR}/x264/lib -L${mingw_LIBDIR}/xvidcore/lib -L${mingw_LIBDIR}/zlib/lib")
+set(FFMPEG_CFLAGS "-I${mingw_LIBDIR}/lame/include -I${mingw_LIBDIR}/openjpeg/include/ -I${mingw_LIBDIR}/ogg/include -I${mingw_LIBDIR}/vorbis/include -I${mingw_LIBDIR}/theora/include -I${mingw_LIBDIR}/opus/include -I${mingw_LIBDIR}/vpx/include -I${mingw_LIBDIR}/x264/include -I${mingw_LIBDIR}/xvidcore/include -I${mingw_LIBDIR}/zlib/include")
+set(FFMPEG_LDFLAGS "-L${mingw_LIBDIR}/lame/lib -L${mingw_LIBDIR}/openjpeg/lib -L${mingw_LIBDIR}/ogg/lib -L${mingw_LIBDIR}/vorbis/lib -L${mingw_LIBDIR}/theora/lib -L${mingw_LIBDIR}/opus/lib -L${mingw_LIBDIR}/vpx/lib -L${mingw_LIBDIR}/x264/lib -L${mingw_LIBDIR}/xvidcore/lib -L${mingw_LIBDIR}/zlib/lib")
set(FFMPEG_EXTRA_FLAGS --pkg-config-flags=--static --extra-cflags=${FFMPEG_CFLAGS} --extra-ldflags=${FFMPEG_LDFLAGS})
-set(FFMPEG_ENV PKG_CONFIG_PATH=${mingw_LIBDIR}/openjpeg/lib/pkgconfig:${mingw_LIBDIR}/x264/lib/pkgconfig:${mingw_LIBDIR}/vorbis/lib/pkgconfig:${mingw_LIBDIR}/ogg/lib/pkgconfig:${mingw_LIBDIR})
+set(FFMPEG_ENV PKG_CONFIG_PATH=${mingw_LIBDIR}/openjpeg/lib/pkgconfig:${mingw_LIBDIR}/x264/lib/pkgconfig:${mingw_LIBDIR}/vorbis/lib/pkgconfig:${mingw_LIBDIR}/ogg/lib/pkgconfig:${mingw_LIBDIR}:${mingw_LIBDIR}/vpx/lib/pkgconfig:${mingw_LIBDIR}/theora/lib/pkgconfig:${mingw_LIBDIR}/openjpeg/lib/pkgconfig:${mingw_LIBDIR}/opus/lib/pkgconfig:)
if(WIN32)
set(FFMPEG_ENV set ${FFMPEG_ENV} &&)
@@ -73,6 +73,7 @@ ExternalProject_Add(external_ffmpeg
--disable-libgsm
--disable-libspeex
--enable-libvpx
+ --enable-libopus
--prefix=${LIBDIR}/ffmpeg
--enable-libtheora
--enable-libvorbis
@@ -130,6 +131,7 @@ add_dependencies(
external_openjpeg
external_xvidcore
external_x264
+ external_opus
external_vpx
external_theora
external_vorbis
diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake
index 526e72e2e33..cc596b2c786 100644
--- a/build_files/build_environment/cmake/harvest.cmake
+++ b/build_files/build_environment/cmake/harvest.cmake
@@ -192,6 +192,7 @@ harvest(theora/lib ffmpeg/lib "*.a")
harvest(tiff/include tiff/include "*.h")
harvest(tiff/lib tiff/lib "*.a")
harvest(vorbis/lib ffmpeg/lib "*.a")
+harvest(opus/lib ffmpeg/lib "*.a")
harvest(vpx/lib ffmpeg/lib "*.a")
harvest(webp/lib ffmpeg/lib "*.a")
harvest(x264/lib ffmpeg/lib "*.a")
@@ -199,4 +200,9 @@ harvest(xvidcore/lib ffmpeg/lib "*.a")
harvest(embree/include embree/include "*.h")
harvest(embree/lib embree/lib "*.a")
+if(UNIX AND NOT APPLE)
+ harvest(libglu/lib mesa/lib "*.so*")
+ harvest(mesa/lib mesa/lib "*.so*")
+endif()
+
endif()
diff --git a/build_files/build_environment/cmake/libglu.cmake b/build_files/build_environment/cmake/libglu.cmake
new file mode 100644
index 00000000000..d1b7647eca3
--- /dev/null
+++ b/build_files/build_environment/cmake/libglu.cmake
@@ -0,0 +1,40 @@
+# ***** 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(LIBGLU_CFLAGS "-static-libgcc")
+set(LIBGLU_CXXFLAGS "-static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a")
+set(LIBGLU_LDFLAGS "-pthread -static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a")
+
+set(LIBGLU_EXTRA_FLAGS
+ CFLAGS=${LIBGLU_CFLAGS}
+ CXXFLAGS=${LIBGLU_CXXFLAGS}
+ LDFLAGS=${LIBGLU_LDFLAGS}
+)
+
+ExternalProject_Add(external_libglu
+ URL ${LIBGLU_URI}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH MD5=${LIBGLU_HASH}
+ PREFIX ${BUILD_DIR}/libglu
+ CONFIGURE_COMMAND ${CONFIGURE_ENV} &&
+ cd ${BUILD_DIR}/libglu/src/external_libglu/ &&
+ ${CONFIGURE_COMMAND_NO_TARGET} --prefix=${LIBDIR}/libglu ${LIBGLU_EXTRA_FLAGS}
+ BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/libglu/src/external_libglu/ && make -j${MAKE_THREADS}
+ INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/libglu/src/external_libglu/ && make install
+ INSTALL_DIR ${LIBDIR}/libglu
+)
diff --git a/build_files/build_environment/cmake/mesa.cmake b/build_files/build_environment/cmake/mesa.cmake
new file mode 100644
index 00000000000..6994d1c5813
--- /dev/null
+++ b/build_files/build_environment/cmake/mesa.cmake
@@ -0,0 +1,54 @@
+# ***** 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(MESA_CFLAGS "-static-libgcc")
+set(MESA_CXXFLAGS "-static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a")
+set(MESA_LDFLAGS "-L${LIBDIR}/zlib/lib -pthread -static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a -l:libz_pic.a")
+
+set(MESA_EXTRA_FLAGS
+ CFLAGS=${MESA_CFLAGS}
+ CXXFLAGS=${MESA_CXXFLAGS}
+ LDFLAGS=${MESA_LDFLAGS}
+ --enable-glx=gallium-xlib
+ --with-gallium-drivers=swrast
+ --disable-dri
+ --disable-gbm
+ --disable-egl
+ --disable-gles1
+ --disable-gles2
+ --disable-llvm-shared-libs
+ --with-llvm-prefix=${LIBDIR}/llvm
+)
+
+ExternalProject_Add(external_mesa
+ URL ${MESA_URI}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH MD5=${MESA_HASH}
+ PREFIX ${BUILD_DIR}/mesa
+ CONFIGURE_COMMAND ${CONFIGURE_ENV} &&
+ cd ${BUILD_DIR}/mesa/src/external_mesa/ &&
+ ${CONFIGURE_COMMAND_NO_TARGET} --prefix=${LIBDIR}/mesa ${MESA_EXTRA_FLAGS}
+ BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/mesa/src/external_mesa/ && make -j${MAKE_THREADS}
+ INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/mesa/src/external_mesa/ && make install
+ INSTALL_DIR ${LIBDIR}/mesa
+)
+
+add_dependencies(
+ external_mesa
+ ll
+)
diff --git a/build_files/build_environment/cmake/opus.cmake b/build_files/build_environment/cmake/opus.cmake
new file mode 100644
index 00000000000..abaad94fa28
--- /dev/null
+++ b/build_files/build_environment/cmake/opus.cmake
@@ -0,0 +1,35 @@
+# ***** 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 *****
+
+ExternalProject_Add(external_opus
+ URL ${OPUS_URI}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH SHA256=${OPUS_HASH}
+ PREFIX ${BUILD_DIR}/opus
+ CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/opus
+ --disable-shared
+ --enable-static
+ --with-pic
+ BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && make -j${MAKE_THREADS}
+ INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && make install
+ INSTALL_DIR ${LIBDIR}/opus
+)
+
+if(MSVC)
+ set_target_properties(external_opus PROPERTIES FOLDER Mingw)
+endif()
diff --git a/build_files/build_environment/cmake/theora.cmake b/build_files/build_environment/cmake/theora.cmake
index 5d41fab5740..b1352c40e37 100644
--- a/build_files/build_environment/cmake/theora.cmake
+++ b/build_files/build_environment/cmake/theora.cmake
@@ -16,7 +16,7 @@
#
# ***** END GPL LICENSE BLOCK *****
-if (UNIX)
+if(UNIX)
set(THEORA_CONFIGURE_ENV ${CONFIGURE_ENV} && export HAVE_PDFLATEX=no)
else()
set(THEORA_CONFIGURE_ENV ${CONFIGURE_ENV})
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index c3b713096d6..1c9e5c5a4f6 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -192,6 +192,10 @@ set(VPX_VERSION 1.7.0)
set(VPX_URI https://github.com/webmproject/libvpx/archive/v${VPX_VERSION}/libvpx-v${VPX_VERSION}.tar.gz)
set(VPX_HASH 1fec931eb5c94279ad219a5b6e0202358e94a93a90cfb1603578c326abfc1238)
+set(OPUS_VERSION 1.3.1)
+set(OPUS_URI https://archive.mozilla.org/pub/opus/opus-${OPUS_VERSION}.tar.gz)
+set(OPUS_HASH 65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d)
+
set(X264_URI http://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20180811-2245-stable.tar.bz2)
set(X264_HASH ae8a868a0e236a348b35d79f3ee80294b169d1195408b689f9851383661ed7aa)
@@ -306,3 +310,11 @@ set(EMBREE_HASH 3d4a1147002ff43939d45140aa9d6fb8)
set(OIDN_VERSION 1.0.0)
set(OIDN_URI https://github.com/OpenImageDenoise/oidn/releases/download/v${OIDN_VERSION}/oidn-${OIDN_VERSION}.src.zip)
set(OIDN_HASH 19fe67b0164e8f020ac8a4f520defe60)
+
+set(LIBGLU_VERSION 9.0.1)
+set(LIBGLU_URI ftp://ftp.freedesktop.org/pub/mesa/glu/glu-${LIBGLU_VERSION}.tar.xz)
+set(LIBGLU_HASH 151aef599b8259efe9acd599c96ea2a3)
+
+set(MESA_VERSION 18.3.1)
+set(MESA_URI ftp://ftp.freedesktop.org/pub/mesa//mesa-${MESA_VERSION}.tar.xz)
+set(MESA_HASH d60828056d77bfdbae0970f9b15fb1be)
diff --git a/build_files/build_environment/cmake/vpx.cmake b/build_files/build_environment/cmake/vpx.cmake
index 1c3a7081b59..741493859e2 100644
--- a/build_files/build_environment/cmake/vpx.cmake
+++ b/build_files/build_environment/cmake/vpx.cmake
@@ -49,6 +49,8 @@ ExternalProject_Add(external_vpx
--disable-avx2
--disable-unit-tests
--disable-examples
+ --enable-vp8
+ --enable-vp9
${VPX_EXTRA_FLAGS}
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vpx/src/external_vpx/ && make -j${MAKE_THREADS}
INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vpx/src/external_vpx/ && make install
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index f594add3a5b..fd3ebe241a2 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -431,6 +431,9 @@ X264_VERSION_MIN=0.118
VPX_USE=false
VPX_VERSION_MIN=0.9.7
VPX_DEV=""
+OPUS_USE=false
+OPUS_VERSION_MIN=1.1.1
+OPUS_DEV=""
MP3LAME_USE=false
MP3LAME_DEV=""
OPENJPEG_USE=false
@@ -2754,6 +2757,10 @@ compile_FFmpeg() {
extra="$extra --enable-libvpx"
fi
+ if [ "$OPUS_USE" = true ]; then
+ extra="$extra --enable-libopus"
+ fi
+
if [ "$MP3LAME_USE" = true ]; then
extra="$extra --enable-libmp3lame"
fi
@@ -2991,6 +2998,14 @@ install_DEB() {
install_packages_DEB $VPX_DEV
VPX_USE=true
fi
+
+ PRINT ""
+ OPUS_DEV="libopus-dev"
+ check_package_version_ge_DEB $OPUS_DEV $OPUS_VERSION_MIN
+ if [ $? -eq 0 ]; then
+ install_packages_DEB $OPUS_DEV
+ OPUS_USE=true
+ fi
fi
# Check cmake/glew versions and disable features for older distros.
@@ -3601,8 +3616,17 @@ install_RPM() {
install_packages_RPM $VPX_DEV
VPX_USE=true
fi
+
PRINT ""
install_packages_RPM libspnav-devel
+
+ PRINT ""
+ OPUS_DEV="libopus-devel"
+ check_package_version_ge_RPM $OPUS_DEV $OPUS_VERSION_MIN
+ if [ $? -eq 0 ]; then
+ install_packages_RPM $OPUS_DEV
+ OPUS_USE=true
+ fi
fi
PRINT ""
@@ -4077,6 +4101,14 @@ install_ARCH() {
install_packages_ARCH $VPX_DEV
VPX_USE=true
fi
+
+ PRINT ""
+ OPUS_DEV="opus"
+ check_package_version_ge_ARCH $OPUS_DEV $OPUS_VERSION_MIN
+ if [ $? -eq 0 ]; then
+ install_packages_ARCH $OPUS_DEV
+ OPUS_USE=true
+ fi
fi
@@ -4633,6 +4665,10 @@ print_info_ffmpeglink() {
_packages="$_packages $VPX_DEV"
fi
+ if [ "$OPUS_USE" = true ]; then
+ _packages="$_packages $OPUS_DEV"
+ fi
+
if [ "$MP3LAME_USE" = true ]; then
_packages="$_packages $MP3LAME_DEV"
fi
diff --git a/build_files/buildbot/buildbot_utils.py b/build_files/buildbot/buildbot_utils.py
index 6891b91aa1e..eded6646671 100644
--- a/build_files/buildbot/buildbot_utils.py
+++ b/build_files/buildbot/buildbot_utils.py
@@ -20,6 +20,7 @@
import argparse
import os
+import re
import subprocess
import sys
@@ -27,6 +28,7 @@ class Builder:
def __init__(self, name, branch):
self.name = name
self.branch = branch
+ self.is_release_branch = re.match("^blender-v(.*)-release$", branch) is not None
# Buildbot runs from build/ directory
self.blender_dir = os.path.abspath(os.path.join('..', 'blender.git'))
diff --git a/build_files/buildbot/config/blender_linux.cmake b/build_files/buildbot/config/blender_linux.cmake
index 6806684e88b..2047c28deb9 100644
--- a/build_files/buildbot/config/blender_linux.cmake
+++ b/build_files/buildbot/config/blender_linux.cmake
@@ -2,33 +2,20 @@
include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/config/blender_release.cmake")
-# For libc-2.24 we are using chroot which runs on a 64bit system.
-# There we can not use CPU bitness check since it is always 64bit. So instead
-# we check for a specific libraries.
-#
-# Other builders we are running in a bare virtual machine, and the libraries
-# are installed to /opt/.
-# We assume that only 64bit builders exists in such configuration.
-if(EXISTS "/lib/x86_64-linux-gnu/libc-2.24.so")
- message(STATUS "Building in GLibc-2.24 environment")
- set(LIBDIR_NAME "linux_x86_64")
-elseif(EXISTS "/lib/i386-linux-gnu//libc-2.24.so")
- message(STATUS "Building in GLibc-2.24 environment")
- set(LIBDIR_NAME "linux_i686")
-else()
- message(STATUS "Building in generic 64bit environment")
- set(LIBDIR_NAME "linux_x86_64")
-endif()
+message(STATUS "Building in CentOS 7 64bit environment")
+set(LIBDIR_NAME "linux_centos7_x86_64")
# Default to only build Blender
set(WITH_BLENDER ON CACHE BOOL "" FORCE)
# ######## Linux-specific build options ########
# Options which are specific to Linux-only platforms
+
set(WITH_DOC_MANPAGE OFF CACHE BOOL "" FORCE)
# ######## Official release-specific build options ########
# Options which are specific to Linux release builds only
+
set(WITH_JACK_DYNLOAD ON CACHE BOOL "" FORCE)
set(WITH_SDL_DYNLOAD ON CACHE BOOL "" FORCE)
set(WITH_SYSTEM_GLEW OFF CACHE BOOL "" FORCE)
@@ -40,7 +27,7 @@ set(WITH_PYTHON_INSTALL_REQUESTS ON CACHE BOOL "" FORCE)
# ######## Release environment specific settings ########
-set(LIBDIR "/opt/blender-deps/${LIBDIR_NAME}" CACHE BOOL "" FORCE)
+set(LIBDIR "${CMAKE_CURRENT_LIST_DIR}/../../../../lib/${LIBDIR_NAME}" CACHE STRING "" FORCE)
# Platform specific configuration, to ensure static linking against everything.
diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py
index a7729843a0e..5bef2b81739 100644
--- a/build_files/buildbot/slave_pack.py
+++ b/build_files/buildbot/slave_pack.py
@@ -32,8 +32,9 @@ def get_package_name(builder, platform=None):
package_name = 'blender-' + info.full_version
if platform:
package_name += '-' + platform
- if builder.branch != 'master' and info.is_development_build:
- package_name = builder.branch + "-" + package_name
+ if not (builder.branch == 'master' or builder.is_release_branch):
+ if info.is_development_build:
+ package_name = builder.branch + "-" + package_name
return package_name
@@ -47,6 +48,7 @@ def create_buildbot_upload_zip(builder, package_files):
try:
z = zipfile.ZipFile(buildbot_upload_zip, "w", compression=zipfile.ZIP_STORED)
for filepath, filename in package_files:
+ print("Packaged", filename)
z.write(filepath, arcname=filename)
z.close()
except Exception as ex:
@@ -147,20 +149,6 @@ def pack_linux(builder):
py_target = os.path.join(builder.install_dir, info.version)
buildbot_utils.call(builder.command_prefix + ['find', py_target, '-iname', '*.so', '-exec', 'strip', '-s', '{}', ';'])
- # Copy all specific files which are too specific to be copied by
- # the CMake rules themselves
- print("Copying extra scripts and libs...")
-
- extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra')
- mesalibs = os.path.join(extra, 'mesalibs' + str(builder.bits) + '.tar.bz2')
- software_gl = os.path.join(builder.blender_dir, 'release', 'bin', 'blender-softwaregl')
- icons = os.path.join(builder.blender_dir, 'release', 'freedesktop', 'icons')
-
- os.system('tar -xpf %s -C %s' % (mesalibs, builder.install_dir))
- os.system('cp %s %s' % (software_gl, builder.install_dir))
- os.system('cp -r %s %s' % (icons, builder.install_dir))
- os.system('chmod 755 %s' % (os.path.join(builder.install_dir, 'blender-softwaregl')))
-
# Construct package name
platform_name = 'linux-' + blender_glibc + '-' + blender_arch
package_name = get_package_name(builder, platform_name)
diff --git a/build_files/buildbot/slave_update.py b/build_files/buildbot/slave_update.py
index 39f449b87bc..36a7ae31c84 100644
--- a/build_files/buildbot/slave_update.py
+++ b/build_files/buildbot/slave_update.py
@@ -28,4 +28,4 @@ if __name__ == "__main__":
# Run make update which handles all libraries and submodules.
make_update = os.path.join(builder.blender_dir, "build_files", "utils", "make_update.py")
- buildbot_utils.call([sys.executable, make_update, '--no-blender', "--use-tests"])
+ buildbot_utils.call([sys.executable, make_update, '--no-blender', "--use-tests", "--use-centos-libraries"])
diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake
index 1c98a6456b8..a93e829e6b0 100644
--- a/build_files/cmake/Modules/GTestTesting.cmake
+++ b/build_files/cmake/Modules/GTestTesting.cmake
@@ -48,6 +48,14 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
if(WITH_OPENMP_STATIC)
target_link_libraries(${TARGET_NAME} ${OpenMP_LIBRARIES})
endif()
+
+ get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(GENERATOR_IS_MULTI_CONFIG)
+ string(REPLACE "\${BUILD_TYPE}" "$<CONFIG>" TEST_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+ else()
+ string(REPLACE "\${BUILD_TYPE}" "" TEST_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+ endif()
+
set_target_properties(${TARGET_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${TESTS_OUTPUT_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TESTS_OUTPUT_DIR}"
diff --git a/build_files/cmake/buildinfo.cmake b/build_files/cmake/buildinfo.cmake
index ec43534528a..cef6b94ee2e 100644
--- a/build_files/cmake/buildinfo.cmake
+++ b/build_files/cmake/buildinfo.cmake
@@ -145,22 +145,13 @@ if(EXISTS ${SOURCE_DIR}/.git)
unset(_git_changed_files)
endif()
-# BUILD_PLATFORM and BUILD_PLATFORM are taken from CMake
+# BUILD_PLATFORM is taken from CMake
# but BUILD_DATE and BUILD_TIME are platform dependent
-if(UNIX)
- if(NOT BUILD_DATE)
- execute_process(COMMAND date "+%Y-%m-%d" OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
- endif()
- if(NOT BUILD_TIME)
- execute_process(COMMAND date "+%H:%M:%S" OUTPUT_VARIABLE BUILD_TIME OUTPUT_STRIP_TRAILING_WHITESPACE)
- endif()
-elseif(WIN32)
- if(NOT BUILD_DATE)
- execute_process(COMMAND cmd /c date /t OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
- endif()
- if(NOT BUILD_TIME)
- execute_process(COMMAND cmd /c time /t OUTPUT_VARIABLE BUILD_TIME OUTPUT_STRIP_TRAILING_WHITESPACE)
- endif()
+if(NOT BUILD_DATE)
+ STRING(TIMESTAMP BUILD_DATE "%Y-%m-%d" UTC)
+endif()
+if(NOT BUILD_TIME)
+ STRING(TIMESTAMP BUILD_TIME "%H:%M:%S" UTC)
endif()
# Write a file with the BUILD_HASH define
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index 403d38f6a05..4c47c4c4dba 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -49,6 +49,7 @@ set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
set(WITH_QUADRIFLOW ON CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION ON CACHE BOOL "" FORCE)
set(WITH_SDL ON CACHE BOOL "" FORCE)
+set(WITH_TBB ON CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 37cbfa27972..6d0f160c764 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -54,5 +54,6 @@ set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
set(WITH_QUADRIFLOW OFF CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
+set(WITH_TBB OFF CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE)
set(WITH_X11_XF86VMODE OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index cb338f40a7b..cf849519c83 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -50,6 +50,7 @@ set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
set(WITH_QUADRIFLOW ON CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION ON CACHE BOOL "" FORCE)
set(WITH_SDL ON CACHE BOOL "" FORCE)
+set(WITH_TBB ON CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index e159dd9e5ee..c3025be34ba 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -460,13 +460,16 @@ function(setup_liblinks
target_link_libraries(${target} ${OSL_LIBRARIES})
endif()
if(WITH_OPENVDB)
- target_link_libraries(${target} ${OPENVDB_LIBRARIES} ${TBB_LIBRARIES} ${BLOSC_LIBRARIES})
+ target_link_libraries(${target} ${OPENVDB_LIBRARIES} ${BLOSC_LIBRARIES})
endif()
if(WITH_OPENIMAGEIO)
target_link_libraries(${target} ${OPENIMAGEIO_LIBRARIES})
endif()
if(WITH_OPENIMAGEDENOISE)
- target_link_libraries(${target} ${OPENIMAGEDENOISE_LIBRARIES} ${TBB_LIBRARIES})
+ target_link_libraries(${target} ${OPENIMAGEDENOISE_LIBRARIES})
+ endif()
+ if(WITH_TBB)
+ target_link_libraries(${target} ${TBB_LIBRARIES})
endif()
if(WITH_OPENCOLORIO)
target_link_libraries(${target} ${OPENCOLORIO_LIBRARIES})
@@ -1209,7 +1212,9 @@ macro(openmp_delayload
)
if(MSVC)
if(WITH_OPENMP)
- if(MSVC_VERSION EQUAL 1800)
+ if(MSVC_CLANG)
+ set(OPENMP_DLL_NAME "libomp")
+ elseif(MSVC_VERSION EQUAL 1800)
set(OPENMP_DLL_NAME "vcomp120")
else()
set(OPENMP_DLL_NAME "vcomp140")
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index 249546dd216..3ae3b2b66b5 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -157,7 +157,7 @@ if(WITH_CODEC_FFMPEG)
avcodec avdevice avformat avutil
mp3lame swscale x264 xvidcore
theora theoradec theoraenc
- vorbis vorbisenc vorbisfile ogg
+ vorbis vorbisenc vorbisfile ogg opus
vpx swresample)
set(FFMPEG_LIBPATH ${FFMPEG}/lib)
endif()
@@ -313,9 +313,7 @@ endif()
if(WITH_OPENVDB)
set(OPENVDB ${LIBDIR}/openvdb)
set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
- set(TBB_INCLUDE_DIRS ${LIBDIR}/tbb/include)
- set(TBB_LIBRARIES ${LIBDIR}/tbb/lib/libtbb.a)
- set(OPENVDB_LIBRARIES openvdb blosc ${TBB_LIBRARIES})
+ set(OPENVDB_LIBRARIES openvdb blosc)
set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
set(OPENVDB_DEFINITIONS)
endif()
@@ -386,14 +384,25 @@ endif()
if(WITH_OPENIMAGEDENOISE)
find_package(OpenImageDenoise)
- find_package(TBB)
if(NOT OPENIMAGEDENOISE_FOUND)
set(WITH_OPENIMAGEDENOISE OFF)
message(STATUS "OpenImageDenoise not found")
- elseif(NOT TBB_FOUND)
+ endif()
+endif()
+
+if(WITH_TBB)
+ find_package(TBB)
+endif()
+
+if(NOT WITH_TBB OR NOT TBB_FOUND)
+ if(WITH_OPENIMAGEDENOISE)
+ message(STATUS "TBB not found, disabling OpenImageDenoise")
set(WITH_OPENIMAGEDENOISE OFF)
- message(STATUS "TBB not found")
+ endif()
+ if(WITH_OPENVDB)
+ message(STATUS "TBB not found, disabling OpenVDB")
+ set(WITH_OPENVDB OFF)
endif()
endif()
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 1b3f9cf3fad..c48780ebd6a 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -22,14 +22,30 @@
# Detect precompiled library directory
if(NOT DEFINED LIBDIR)
+ # Path to a locally compiled libraries.
set(LIBDIR_NAME ${CMAKE_SYSTEM_NAME}_${CMAKE_SYSTEM_PROCESSOR})
string(TOLOWER ${LIBDIR_NAME} LIBDIR_NAME)
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_NAME})
-else()
- message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
+ set(LIBDIR_NATIVE_ABI ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_NAME})
+
+ # Path to precompiled libraries with known CentOS 7 ABI.
+ set(LIBDIR_CENTOS7_ABI ${CMAKE_SOURCE_DIR}/../lib/linux_centos7_x86_64)
+
+ # Choose the best suitable libraries.
+ if(EXISTS ${LIBDIR_NATIVE_ABI})
+ set(LIBDIR ${LIBDIR_NATIVE_ABI})
+ elseif(EXISTS ${LIBDIR_CENTOS7_ABI})
+ set(LIBDIR ${LIBDIR_CENTOS7_ABI})
+ set(WITH_CXX11_ABI OFF)
+ endif()
+
+ # Avoid namespace pollustion.
+ unset(LIBDIR_NATIVE_ABI)
+ unset(LIBDIR_CENTOS7_ABI)
endif()
if(EXISTS ${LIBDIR})
+ message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
+
file(GLOB LIB_SUBDIRS ${LIBDIR}/*)
# NOTE: Make sure "proper" compiled zlib comes first before the one
# which is a part of OpenCollada. They have different ABI, and we
@@ -244,13 +260,8 @@ endif()
if(WITH_OPENVDB)
find_package_wrapper(OpenVDB)
- find_package_wrapper(TBB)
find_package_wrapper(Blosc)
- if(NOT TBB_FOUND)
- set(WITH_OPENVDB OFF)
- set(WITH_OPENVDB_BLOSC OFF)
- message(STATUS "TBB not found, disabling OpenVDB")
- elseif(NOT OPENVDB_FOUND)
+ if(NOT OPENVDB_FOUND)
set(WITH_OPENVDB OFF)
set(WITH_OPENVDB_BLOSC OFF)
message(STATUS "OpenVDB not found, disabling it")
@@ -416,6 +427,21 @@ if(WITH_OPENSUBDIV)
endif()
endif()
+if(WITH_TBB)
+ find_package_wrapper(TBB)
+endif()
+
+if(NOT WITH_TBB OR NOT TBB_FOUND)
+ if(WITH_OPENIMAGEDENOISE)
+ message(STATUS "TBB not found, disabling OpenImageDenoise")
+ set(WITH_OPENIMAGEDENOISE OFF)
+ endif()
+ if(WITH_OPENVDB)
+ message(STATUS "TBB not found, disabling OpenVDB")
+ set(WITH_OPENVDB OFF)
+ endif()
+endif()
+
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
if(HAIKU)
list(APPEND PLATFORM_LINKLIBS -lnetwork)
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index b2277c440fe..ef7722b0aef 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -35,6 +35,22 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
else()
message("Unable to detect the Visual Studio redist directory, copying of the runtime dlls will not work, try running from the visual studio developer prompt.")
endif()
+ # 1) CMake has issues detecting openmp support in clang-cl so we have to provide
+ # the right switches here.
+ # 2) While the /openmp switch *should* work, it currently doesn't as for clang 9.0.0
+ if(WITH_OPENMP)
+ set(OPENMP_CUSTOM ON)
+ set(OPENMP_FOUND ON)
+ set(OpenMP_C_FLAGS "/clang:-fopenmp")
+ set(OpenMP_CXX_FLAGS "/clang:-fopenmp")
+ GET_FILENAME_COMPONENT(LLVMROOT "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\LLVM\\LLVM;]" ABSOLUTE CACHE)
+ set(CLANG_OPENMP_DLL "${LLVMROOT}/bin/libomp.dll")
+ set(CLANG_OPENMP_LIB "${LLVMROOT}/lib/libomp.lib")
+ if(NOT EXISTS "${CLANG_OPENMP_DLL}")
+ message(FATAL_ERROR "Clang OpenMP library (${CLANG_OPENMP_DLL}) not found.")
+ endif()
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \"${CLANG_OPENMP_LIB}\"")
+ endif()
endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ${WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS})
@@ -96,7 +112,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
list(APPEND PLATFORM_LINKLIBS
- ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32
+ ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32
advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp
)
@@ -475,25 +491,20 @@ endif()
if(WITH_OPENVDB)
set(BLOSC_LIBRARIES optimized ${LIBDIR}/blosc/lib/libblosc.lib debug ${LIBDIR}/blosc/lib/libblosc_d.lib)
- set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
- set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
set(OPENVDB ${LIBDIR}/openVDB)
set(OPENVDB_LIBPATH ${OPENVDB}/lib)
- set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include ${TBB_INCLUDE_DIR})
- set(OPENVDB_LIBRARIES optimized ${OPENVDB_LIBPATH}/openvdb.lib debug ${OPENVDB_LIBPATH}/openvdb_d.lib ${TBB_LIBRARIES} ${BLOSC_LIBRARIES})
+ set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
+ set(OPENVDB_LIBRARIES optimized ${OPENVDB_LIBPATH}/openvdb.lib debug ${OPENVDB_LIBPATH}/openvdb_d.lib ${BLOSC_LIBRARIES})
set(OPENVDB_DEFINITIONS -DNOMINMAX)
endif()
if(WITH_OPENIMAGEDENOISE)
- set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
- set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
set(OPENIMAGEDENOISE ${LIBDIR}/OpenImageDenoise)
set(OPENIMAGEDENOISE_LIBPATH ${LIBDIR}/OpenImageDenoise/lib)
- set(OPENIMAGEDENOISE_INCLUDE_DIRS ${OPENIMAGEDENOISE}/include ${TBB_INCLUDE_DIR})
+ set(OPENIMAGEDENOISE_INCLUDE_DIRS ${OPENIMAGEDENOISE}/include)
set(OPENIMAGEDENOISE_LIBRARIES
optimized ${OPENIMAGEDENOISE_LIBPATH}/OpenImageDenoise.lib ${OPENIMAGEDENOISE_LIBPATH}/common.lib ${OPENIMAGEDENOISE_LIBPATH}/mkldnn.lib
- debug ${OPENIMAGEDENOISE_LIBPATH}/OpenImageDenoise_d.lib ${OPENIMAGEDENOISE_LIBPATH}/common_d.lib ${OPENIMAGEDENOISE_LIBPATH}/mkldnn_d.lib
- ${TBB_LIBRARIES})
+ debug ${OPENIMAGEDENOISE_LIBPATH}/OpenImageDenoise_d.lib ${OPENIMAGEDENOISE_LIBPATH}/common_d.lib ${OPENIMAGEDENOISE_LIBPATH}/mkldnn_d.lib)
set(OPENIMAGEDENOISE_DEFINITIONS)
endif()
@@ -558,6 +569,21 @@ if(WITH_SYSTEM_AUDASPACE)
set(AUDASPACE_PY_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace-py.lib)
endif()
+if(WITH_TBB)
+ set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
+ set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
+ set(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR})
+else()
+ if(WITH_OPENIMAGEDENOISE)
+ message(STATUS "TBB disabled, also disabling OpenImageDenoise")
+ set(WITH_OPENIMAGEDENOISE OFF)
+ endif()
+ if(WITH_OPENVDB)
+ message(STATUS "TBB disabled, also disabling OpenVDB")
+ set(WITH_OPENVDB OFF)
+ endif()
+endif()
+
# used in many places so include globally, like OpenGL
blender_include_dirs_sys("${PTHREADS_INCLUDE_DIRS}")
diff --git a/build_files/utils/make_test.py b/build_files/utils/make_test.py
index b89afc738ce..309ab36ecdd 100755
--- a/build_files/utils/make_test.py
+++ b/build_files/utils/make_test.py
@@ -30,26 +30,27 @@ cmake_command = args.cmake_command
config = args.config
build_dir = args.build_directory
-if shutil.which(ctest_command) is None:
+if make_utils.command_missing(ctest_command):
sys.stderr.write("ctest not found, can't run tests\n")
sys.exit(1)
-if shutil.which(git_command) is None:
+if make_utils.command_missing(git_command):
sys.stderr.write("git not found, can't run tests\n")
sys.exit(1)
# Test if we are building a specific release version.
-release_version = make_utils.git_branch_release_version(git_command)
+branch = make_utils.git_branch(git_command)
+release_version = make_utils.git_branch_release_version(branch)
lib_tests_dirpath = os.path.join('..', 'lib', "tests")
if not os.path.exists(lib_tests_dirpath):
print("Tests files not found, downloading...")
- if shutil.which(svn_command) is None:
+ if make_utils.command_missing(svn_command):
sys.stderr.write("svn not found, can't checkout test files\n")
sys.exit(1)
- if shutil.which(cmake_command) is None:
+ if make_utils.command_missing(cmake_command):
sys.stderr.write("cmake not found, can't checkout test files\n")
sys.exit(1)
diff --git a/build_files/utils/make_update.py b/build_files/utils/make_update.py
index 2cbbd1ffd72..ec72514fdfc 100755
--- a/build_files/utils/make_update.py
+++ b/build_files/utils/make_update.py
@@ -28,14 +28,17 @@ def parse_arguments():
parser.add_argument("--use-tests", action="store_true")
parser.add_argument("--svn-command", default="svn")
parser.add_argument("--git-command", default="git")
+ parser.add_argument("--use-centos-libraries", action="store_true")
return parser.parse_args()
+def get_blender_git_root():
+ return check_output([args.git_command, "rev-parse", "--show-toplevel"])
# Setup for precompiled libraries and tests from svn.
def svn_update(args, release_version):
svn_non_interactive = [args.svn_command, '--non-interactive']
- lib_dirpath = os.path.join('..', 'lib')
+ lib_dirpath = os.path.join(get_blender_git_root(), '..', 'lib')
svn_url = make_utils.svn_libraries_base_url(release_version)
# Checkout precompiled libraries
@@ -46,6 +49,8 @@ def svn_update(args, release_version):
# this script is bundled as part of the precompiled libraries. However it
# is used by the buildbot.
lib_platform = "win64_vc14"
+ elif args.use_centos_libraries:
+ lib_platform = "linux_centos7_x86_64"
else:
# No precompiled libraries for Linux.
lib_platform = None
@@ -56,7 +61,7 @@ def svn_update(args, release_version):
if not os.path.exists(lib_platform_dirpath):
print_stage("Checking out Precompiled Libraries")
- if shutil.which(args.svn_command) is None:
+ if make_utils.command_missing(args.svn_command):
sys.stderr.write("svn not found, can't checkout libraries\n")
sys.exit(1)
@@ -70,7 +75,7 @@ def svn_update(args, release_version):
if not os.path.exists(lib_tests_dirpath):
print_stage("Checking out Tests")
- if shutil.which(args.svn_command) is None:
+ if make_utils.command_missing(args.svn_command):
sys.stderr.write("svn not found, can't checkout tests\n")
sys.exit(1)
@@ -82,34 +87,40 @@ def svn_update(args, release_version):
if os.path.isdir(lib_dirpath):
for dirname in os.listdir(lib_dirpath):
+ dirpath = os.path.join(lib_dirpath, dirname)
+
if dirname == ".svn":
+ # Cleanup must be run from svn root directory if it exists.
+ if not make_utils.command_missing(args.svn_command):
+ call(svn_non_interactive + ["cleanup", lib_dirpath])
continue
- dirpath = os.path.join(lib_dirpath, dirname)
svn_dirpath = os.path.join(dirpath, ".svn")
svn_root_dirpath = os.path.join(lib_dirpath, ".svn")
if os.path.isdir(dirpath) and \
(os.path.exists(svn_dirpath) or os.path.exists(svn_root_dirpath)):
- if shutil.which(args.svn_command) is None:
+ if make_utils.command_missing(args.svn_command):
sys.stderr.write("svn not found, can't update libraries\n")
sys.exit(1)
- call(svn_non_interactive + ["cleanup", dirpath])
+ # Cleanup to continue with interrupted downloads.
+ if os.path.exists(svn_dirpath):
+ call(svn_non_interactive + ["cleanup", dirpath])
+ # Switch to appropriate branch and update.
call(svn_non_interactive + ["switch", svn_url + dirname, dirpath])
call(svn_non_interactive + ["update", dirpath])
-
-# Update blender repository.
-def blender_update_skip(args):
- if shutil.which(args.git_command) is None:
+# Test if git repo can be updated.
+def git_update_skip(args, check_remote_exists=True):
+ if make_utils.command_missing(args.git_command):
sys.stderr.write("git not found, can't update code\n")
sys.exit(1)
# Abort if a rebase is still progress.
- rebase_merge = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-merge'])
- rebase_apply = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-apply'])
- merge_head = check_output([args.git_command, 'rev-parse', '--git-path', 'MERGE_HEAD'])
+ rebase_merge = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-merge'], exit_on_error=False)
+ rebase_apply = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-apply'], exit_on_error=False)
+ merge_head = check_output([args.git_command, 'rev-parse', '--git-path', 'MERGE_HEAD'], exit_on_error=False)
if os.path.exists(rebase_merge) or \
os.path.exists(rebase_apply) or \
os.path.exists(merge_head):
@@ -121,49 +132,92 @@ def blender_update_skip(args):
return "you have unstaged changes"
# Test if there is an upstream branch configured
- branch = check_output([args.git_command, "rev-parse", "--abbrev-ref", "HEAD"])
- remote = check_output([args.git_command, "config", "branch." + branch + ".remote"], exit_on_error=False)
- if len(remote) == 0:
- return "no remote branch to pull from"
+ if check_remote_exists:
+ branch = check_output([args.git_command, "rev-parse", "--abbrev-ref", "HEAD"])
+ remote = check_output([args.git_command, "config", "branch." + branch + ".remote"], exit_on_error=False)
+ if len(remote) == 0:
+ return "no remote branch to pull from"
- return None
+ return ""
+# Update blender repository.
def blender_update(args):
print_stage("Updating Blender Git Repository")
call([args.git_command, "pull", "--rebase"])
# Update submodules.
-def submodules_update(args, release_version):
+def submodules_update(args, release_version, branch):
print_stage("Updating Submodules")
- if shutil.which(args.git_command) is None:
+ if make_utils.command_missing(args.git_command):
sys.stderr.write("git not found, can't update code\n")
sys.exit(1)
- call([args.git_command, "submodule", "update", "--init", "--recursive"])
+ # Update submodules to latest master or appropriate release branch.
if not release_version:
- # Update submodules to latest master if not building a specific release.
- # In that case submodules are set to a specific revision, which is checked
- # out by running "git submodule update".
- call([args.git_command, "submodule", "foreach", "git", "checkout", "master"])
- call([args.git_command, "submodule", "foreach", "git", "pull", "--rebase", "origin", "master"])
+ branch = "master"
+
+ submodules = [
+ ("release/scripts/addons", branch),
+ ("release/scripts/addons_contrib", branch),
+ ("release/datafiles/locale", branch),
+ ("source/tools", branch),
+ ]
+
+ # Initialize submodules only if needed.
+ for submodule_path, submodule_branch in submodules:
+ if not os.path.exists(os.path.join(submodule_path, ".git")):
+ call([args.git_command, "submodule", "update", "--init", "--recursive"])
+ break
+
+ # Checkout appropriate branch and pull changes.
+ skip_msg = ""
+ for submodule_path, submodule_branch in submodules:
+ cwd = os.getcwd()
+ try:
+ os.chdir(submodule_path)
+ msg = git_update_skip(args, check_remote_exists=False)
+ if msg:
+ skip_msg += submodule_path + " skipped: " + msg + "\n"
+ else:
+ if make_utils.git_branch(args.git_command) != submodule_branch:
+ call([args.git_command, "fetch", "origin"])
+ call([args.git_command, "checkout", submodule_branch])
+ call([args.git_command, "pull", "--rebase", "origin", submodule_branch])
+ finally:
+ os.chdir(cwd)
+
+ return skip_msg
if __name__ == "__main__":
args = parse_arguments()
- blender_skipped = None
+ blender_skip_msg = ""
+ submodules_skip_msg = ""
# Test if we are building a specific release version.
- release_version = make_utils.git_branch_release_version(args.git_command)
+ branch = make_utils.git_branch(args.git_command)
+ release_version = make_utils.git_branch_release_version(branch)
if not args.no_libraries:
svn_update(args, release_version)
if not args.no_blender:
- blender_skipped = blender_update_skip(args)
- if not blender_skipped:
+ blender_skip_msg = git_update_skip(args)
+ if blender_skip_msg:
+ blender_skip_msg = "Blender repository skipped: " + blender_skip_msg + "\n"
+ else:
blender_update(args)
if not args.no_submodules:
- submodules_update(args, release_version)
-
- if blender_skipped:
- print_stage("Blender repository skipped: " + blender_skipped)
+ submodules_skip_msg = submodules_update(args, release_version, branch)
+
+ # Report any skipped repositories at the end, so it's not as easy to miss.
+ skip_msg = blender_skip_msg + submodules_skip_msg
+ if skip_msg:
+ print_stage(skip_msg.strip())
+
+ # For failed submodule update we throw an error, since not having correct
+ # submodules can make Blender throw errors.
+ # For Blender itself we don't and consider "make update" to be a command
+ # you can use while working on uncommitted code.
+ if submodules_skip_msg:
+ sys.exit(1)
diff --git a/build_files/utils/make_utils.py b/build_files/utils/make_utils.py
index 0c63a18b0ba..7b21bc607a4 100755
--- a/build_files/utils/make_utils.py
+++ b/build_files/utils/make_utils.py
@@ -3,6 +3,7 @@
# Utility functions for make update and make tests.
import re
+import shutil
import subprocess
import sys
@@ -34,7 +35,7 @@ def check_output(cmd, exit_on_error=True):
return output.strip()
-def git_branch_release_version(git_command):
+def git_branch(git_command):
# Test if we are building a specific release version.
try:
branch = subprocess.check_output([git_command, "rev-parse", "--abbrev-ref", "HEAD"])
@@ -42,7 +43,9 @@ def git_branch_release_version(git_command):
sys.stderr.write("Failed to get Blender git branch\n")
sys.exit(1)
- branch = branch.strip().decode('utf8')
+ return branch.strip().decode('utf8')
+
+def git_branch_release_version(branch):
release_version = re.search("^blender-v(.*)-release$", branch)
if release_version:
release_version = release_version.group(1)
@@ -54,3 +57,10 @@ def svn_libraries_base_url(release_version):
else:
svn_branch = "trunk"
return "https://svn.blender.org/svnroot/bf-blender/" + svn_branch + "/lib/"
+
+def command_missing(command):
+ # Support running with Python 2 for macOS
+ if sys.version_info >= (3, 0):
+ return shutil.which(command) is None
+ else:
+ return False
diff --git a/build_files/windows/configure_ninja.cmd b/build_files/windows/configure_ninja.cmd
index 995d8d56fa8..8f766e855a6 100644
--- a/build_files/windows/configure_ninja.cmd
+++ b/build_files/windows/configure_ninja.cmd
@@ -30,9 +30,15 @@ set LLVM_DIR=
:DetectionComplete
set CC=%LLVM_DIR%\bin\clang-cl
set CXX=%LLVM_DIR%\bin\clang-cl
- rem build and tested against 2017 15.7
- set CFLAGS=-m64 -fmsc-version=1914
- set CXXFLAGS=-m64 -fmsc-version=1914
+ if "%BUILD_VS_YEAR%" == "2019" (
+ rem build and tested against 2019 16.2
+ set CFLAGS=-m64 -fmsc-version=1922
+ set CXXFLAGS=-m64 -fmsc-version=1922
+ ) else (
+ rem build and tested against 2017 15.7
+ set CFLAGS=-m64 -fmsc-version=1914
+ set CXXFLAGS=-m64 -fmsc-version=1914
+ )
if "%WITH_ASAN%"=="1" (
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_COMPILER_ASAN=On
)
diff --git a/build_files/windows/parse_arguments.cmd b/build_files/windows/parse_arguments.cmd
index 47c6f81adb3..5f60e321a56 100644
--- a/build_files/windows/parse_arguments.cmd
+++ b/build_files/windows/parse_arguments.cmd
@@ -13,7 +13,7 @@ if NOT "%1" == "" (
set BUILD_TYPE=Debug
REM Build Configurations
) else if "%1" == "builddir" (
- set BUILD_DIR_OVERRRIDE="%BLENDER_DIR%..\%2"
+ set BUILD_DIR_OVERRRIDE=%BLENDER_DIR%..\%2
shift /1
) else if "%1" == "with_tests" (
set TESTS_CMAKE_ARGS=%TESTS_CMAKE_ARGS% -DWITH_GTESTS=On
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index 366d0b1b507..4380b94890a 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.81"
+PROJECT_NUMBER = "V2.82"
# 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 4be16c15ec7..fc2200ab859 100755
--- a/doc/manpage/blender.1.py
+++ b/doc/manpage/blender.1.py
@@ -30,11 +30,11 @@ and <output-filename> is where to write the generated man page.
# <pep8 compliant>
+import os
import subprocess
import sys
import time
-import datetime
def man_format(data):
@@ -52,11 +52,18 @@ outfilename = sys.argv[2]
cmd = [blender_bin, "--help"]
print(" executing:", " ".join(cmd))
-blender_help = subprocess.check_output(cmd).decode(encoding="utf-8")
-blender_version = subprocess.check_output([blender_bin, "--version"]).decode(encoding="utf-8").strip()
-blender_version = blender_version.split("build")[0].rstrip()
-blender_version = blender_version.partition(" ")[2] # remove 'Blender' prefix.
-date_string = datetime.date.fromtimestamp(time.time()).strftime("%B %d, %Y")
+blender_help = subprocess.run(
+ cmd, env={"ASAN_OPTIONS": "exitcode=0"}, 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_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:
+ # Happens when built without WITH_BUILD_INFO e.g.
+ date_string = time.strftime("%B %d, %Y", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
+else:
+ blender_date = blender_date.strip().partition(" ")[2] # remove 'date:' prefix
+ date_string = time.strftime("%B %d, %Y", time.strptime(blender_date, "%Y-%m-%d"))
outfile = open(outfilename, "w")
fw = outfile.write
@@ -80,7 +87,7 @@ is a full-featured 3D application. It supports the entirety of the 3D pipeline -
Use Blender to create 3D images and animations, films and commercials, content for games, architectural and industrial visualizatons, and scientific visualizations.
-http://www.blender.org''')
+https://www.blender.org''')
fw('''
.SH OPTIONS''')
diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py
index 995991c4afd..78bfd3c85b8 100755
--- a/doc/python_api/sphinx_doc_update.py
+++ b/doc/python_api/sphinx_doc_update.py
@@ -94,10 +94,10 @@ def main():
rsync_base = "rsync://%s@%s:%s" % (args.user, args.rsync_server, args.rsync_root)
- blenver = blenver_zip = ""
+ blenver = api_blenver = api_blenver_zip = ""
api_name = ""
branch = ""
- is_release = False
+ is_release = is_beta = False
# I) Update local mirror using rsync.
rsync_mirror_cmd = ("rsync", "--delete-after", "-avzz", rsync_base, args.mirror_dir)
@@ -118,11 +118,14 @@ def main():
"import sys, bpy\n"
"with open(sys.argv[-1], 'w') as f:\n"
" is_release = bpy.app.version_cycle in {'rc', 'release'}\n"
+ " is_beta = bpy.app.version_cycle in {'beta'}\n"
" branch = bpy.app.build_branch.split()[0].decode()\n"
" f.write('%d\\n' % is_release)\n"
+ " f.write('%d\\n' % is_beta)\n"
" f.write('%s\\n' % branch)\n"
+ " f.write('%d.%d%s\\n' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char))\n"
" f.write('%d.%d%s\\n' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char)\n"
- " if is_release else '%s\\n' % branch)\n"
+ " if (is_release or is_beta) else '%s\\n' % branch)\n"
" f.write('%d_%d%s_release' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char)\n"
" if is_release else '%d_%d_%d' % bpy.app.version)\n"
)
@@ -130,8 +133,9 @@ def main():
"--python-expr", getver_script, "--", getver_file)
subprocess.run(get_ver_cmd)
with open(getver_file) as f:
- is_release, branch, blenver, blenver_zip = f.read().split("\n")
+ is_release, is_beta, branch, blenver, api_blenver, api_blenver_zip = f.read().split("\n")
is_release = bool(int(is_release))
+ is_beta = bool(int(is_beta))
os.remove(getver_file)
# IV) Build doc.
@@ -143,14 +147,17 @@ def main():
os.chdir(curr_dir)
# V) Cleanup existing matching dir in server mirror (if any), and copy new doc.
- api_name = blenver
+ api_name = api_blenver
api_dir = os.path.join(args.mirror_dir, api_name)
if os.path.exists(api_dir):
- shutil.rmtree(api_dir)
+ if os.path.islink(api_dir):
+ os.remove(api_dir)
+ else:
+ shutil.rmtree(api_dir)
os.rename(os.path.join(tmp_dir, "sphinx-out"), api_dir)
# VI) Create zip archive.
- zip_name = "blender_python_reference_%s" % blenver_zip # We can't use 'release' postfix here...
+ zip_name = "blender_python_reference_%s" % api_blenver_zip # We can't use 'release' postfix here...
zip_path = os.path.join(args.mirror_dir, zip_name)
with zipfile.ZipFile(zip_path, 'w') as zf:
for dirname, _, filenames in os.walk(api_dir):
@@ -163,12 +170,27 @@ def main():
# VII) Create symlinks and html redirects.
if is_release:
symlink = os.path.join(args.mirror_dir, "current")
- os.remove(symlink)
+ if os.path.exists(symlink):
+ if os.path.islink(symlink):
+ os.remove(symlink)
+ else:
+ shutil.rmtree(symlink)
os.symlink("./%s" % api_name, symlink)
with open(os.path.join(args.mirror_dir, "250PythonDoc/index.html"), 'w') as f:
f.write("<html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\""
"content=\"0;url=../%s/\"></head><body>Redirecting...</body></html>" % api_name)
+ elif is_beta:
+ # We do not have any particular symlink for that stage.
+ pass
elif branch == "master":
+ # Also create a symlink from version number to actual master api doc.
+ symlink = os.path.join(args.mirror_dir, blenver)
+ if os.path.exists(symlink):
+ if os.path.islink(symlink):
+ os.remove(symlink)
+ else:
+ shutil.rmtree(symlink)
+ os.symlink("./%s" % api_name, symlink)
with open(os.path.join(args.mirror_dir, "blender_python_api/index.html"), 'w') as f:
f.write("<html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\""
"content=\"0;url=../%s/\"></head><body>Redirecting...</body></html>" % api_name)
diff --git a/extern/audaspace/src/devices/SoftwareDevice.cpp b/extern/audaspace/src/devices/SoftwareDevice.cpp
index c944b9ed12d..8c16c75e8e3 100644
--- a/extern/audaspace/src/devices/SoftwareDevice.cpp
+++ b/extern/audaspace/src/devices/SoftwareDevice.cpp
@@ -78,7 +78,7 @@ bool SoftwareDevice::SoftwareHandle::pause(bool keep)
}
SoftwareDevice::SoftwareHandle::SoftwareHandle(SoftwareDevice* device, std::shared_ptr<IReader> reader, std::shared_ptr<PitchReader> pitch, std::shared_ptr<ResampleReader> resampler, std::shared_ptr<ChannelMapperReader> mapper, bool keep) :
- m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_old_volume(0), m_loopcount(0),
+ m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(0.0f), m_old_volume(0.0f), m_loopcount(0),
m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()),
m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0),
m_flags(RENDER_CONE), m_stop(nullptr), m_stop_data(nullptr), m_status(STATUS_PLAYING), m_device(device)
diff --git a/extern/cuew/src/cuew.c b/extern/cuew/src/cuew.c
index 1f386c4e5d3..a0146741494 100644
--- a/extern/cuew/src/cuew.c
+++ b/extern/cuew/src/cuew.c
@@ -859,6 +859,23 @@ int cuewNvrtcVersion(void) {
return 0;
}
+static size_t safe_strnlen(const char *s, size_t maxlen) {
+ size_t length;
+ for (length = 0; length < maxlen; s++, length++) {
+ if (*s == '\0') {
+ break;
+ }
+ }
+ return length;
+}
+
+static char *safe_strncpy(char *dest, const char *src, size_t n) {
+ const size_t src_len = safe_strnlen(src, n - 1);
+ memcpy(dest, src, src_len);
+ dest[src_len] = '\0';
+ return dest;
+}
+
int cuewCompilerVersion(void) {
const char *path = cuewCompilerPath();
const char *marker = "Cuda compilation tools, release ";
@@ -874,7 +891,7 @@ int cuewCompilerVersion(void) {
}
/* get --version output */
- strncpy(command, path, sizeof(command));
+ safe_strncpy(command, path, sizeof(command));
strncat(command, " --version", sizeof(command) - strlen(path));
pipe = popen(command, "r");
if (!pipe) {
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
index 35a73d9f308..0eeba8ab6c2 100644
--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
@@ -221,9 +221,8 @@ namespace lemon {
const std::string &opt)
{
Opts::iterator o = _opts.find(opt);
- Opts::iterator s = _opts.find(syn);
LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'");
- LEMON_ASSERT(s==_opts.end(), "Option already used: '"+syn+"'");
+ LEMON_ASSERT(_opts.find(syn)==_opts.end(), "Option already used: '"+syn+"'");
ParData p;
p.help=opt;
p.mandatory=false;
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h
deleted file mode 100644
index b9699a223fb..00000000000
--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/config.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#define LEMON_VERSION ""
-/* #undef LEMON_HAVE_LONG_LONG */
-
-/* #undef LEMON_HAVE_LP */
-/* #undef LEMON_HAVE_MIP */
-/* #undef LEMON_HAVE_GLPK */
-/* #undef LEMON_HAVE_CPLEX */
-/* #undef LEMON_HAVE_SOPLEX */
-/* #undef LEMON_HAVE_CLP */
-/* #undef LEMON_HAVE_CBC */
-
-#define _LEMON_CPLEX 1
-#define _LEMON_CLP 2
-#define _LEMON_GLPK 3
-#define _LEMON_SOPLEX 4
-#define _LEMON_CBC 5
-
-/* #undef LEMON_DEFAULT_LP */
-/* #undef LEMON_DEFAULT_MIP */
-
-/* #undef LEMON_USE_PTHREAD */
-/* #undef LEMON_USE_WIN32_THREADS */
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
index 6ccad33e68e..388e990ec3b 100644
--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
+++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
@@ -234,7 +234,7 @@ namespace lemon {
int in_arc, join, u_in, v_in, u_out, v_out;
Value delta;
- const Value MAX;
+ const Value MAX_VALUE;
public:
@@ -649,9 +649,9 @@ namespace lemon {
NetworkSimplex(const GR& graph, bool arc_mixing = true) :
_graph(graph), _node_id(graph), _arc_id(graph),
_arc_mixing(arc_mixing),
- MAX(std::numeric_limits<Value>::max()),
+ MAX_VALUE(std::numeric_limits<Value>::max()),
INF(std::numeric_limits<Value>::has_infinity ?
- std::numeric_limits<Value>::infinity() : MAX)
+ std::numeric_limits<Value>::infinity() : MAX_VALUE)
{
// Check the number types
LEMON_ASSERT(std::numeric_limits<Value>::is_signed,
@@ -1076,9 +1076,9 @@ namespace lemon {
for (int i = 0; i != _arc_num; ++i) {
Value c = _lower[i];
if (c >= 0) {
- _cap[i] = _upper[i] < MAX ? _upper[i] - c : INF;
+ _cap[i] = _upper[i] < MAX_VALUE ? _upper[i] - c : INF;
} else {
- _cap[i] = _upper[i] < MAX + c ? _upper[i] - c : INF;
+ _cap[i] = _upper[i] < MAX_VALUE + c ? _upper[i] - c : INF;
}
_supply[_source[i]] -= c;
_supply[_target[i]] += c;
@@ -1282,7 +1282,7 @@ namespace lemon {
d = _flow[e];
if (_pred_dir[u] == DIR_DOWN) {
c = _cap[e];
- d = c >= MAX ? INF : c - d;
+ d = c >= MAX_VALUE ? INF : c - d;
}
if (d < delta) {
delta = d;
@@ -1297,7 +1297,7 @@ namespace lemon {
d = _flow[e];
if (_pred_dir[u] == DIR_UP) {
c = _cap[e];
- d = c >= MAX ? INF : c - d;
+ d = c >= MAX_VALUE ? INF : c - d;
}
if (d <= delta) {
delta = d;
@@ -1559,7 +1559,7 @@ namespace lemon {
_pi[_target[in_arc]]) >= 0) continue;
findJoinNode();
bool change = findLeavingArc();
- if (delta >= MAX) return false;
+ if (delta >= MAX_VALUE) return false;
changeFlow(change);
if (change) {
updateTreeStructure();
@@ -1598,7 +1598,7 @@ namespace lemon {
while (pivot.findEnteringArc()) {
findJoinNode();
bool change = findLeavingArc();
- if (delta >= MAX) return UNBOUNDED;
+ if (delta >= MAX_VALUE) return UNBOUNDED;
changeFlow(change);
if (change) {
updateTreeStructure();
diff --git a/extern/quadriflow/CMakeLists.txt b/extern/quadriflow/CMakeLists.txt
index 488d95a48b9..0f10b8fe707 100644
--- a/extern/quadriflow/CMakeLists.txt
+++ b/extern/quadriflow/CMakeLists.txt
@@ -23,12 +23,15 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
add_c_flag(
"-Wno-unused-result"
)
+ remove_cc_flag(
+ "-Wmissing-declarations"
+ )
endif()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
-if (WIN32)
+if(WIN32)
add_definitions(-D_USE_MATH_DEFINES)
endif()
@@ -39,10 +42,11 @@ set(LEMON_SOURCE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${LEMON_3RD_PATH})
set(LEMON_SRC ${LEMON_SOURCE_ROOT_DIR}/lemon)
set(LEMON_INCLUDE_DIRS ${LEMON_SOURCE_ROOT_DIR})
+set(LEMON_GEN_DIR ${CMAKE_BINARY_DIR}/extern/quadriflow/${LEMON_3RD_PATH})
configure_file(
${LEMON_SRC}/config.h.in
- ${LEMON_SRC}/config.h
- )
+ ${LEMON_GEN_DIR}/lemon/config.h
+)
set(LEMON_SOURCES
${LEMON_SRC}/arg_parser.cc
${LEMON_SRC}/base.cc
@@ -51,13 +55,14 @@ set(LEMON_SOURCES
${LEMON_SRC}/lp_skeleton.cc
${LEMON_SRC}/random.cc
${LEMON_SRC}/bits/windows.cc
- )
+)
set(INC
src
3rd/pcg32
3rd/pss
${LEMON_INCLUDE_DIRS}
+ ${LEMON_GEN_DIR}
)
set(INC_SYS
@@ -66,37 +71,37 @@ set(INC_SYS
)
set(SRC
- src/adjacent-matrix.cpp
- src/adjacent-matrix.hpp
- src/compare-key.hpp
- src/config.hpp
- src/dedge.cpp
- src/dedge.hpp
- src/disajoint-tree.hpp
- src/dset.hpp
- src/field-math.hpp
- src/flow.hpp
- src/hierarchy.cpp
- src/hierarchy.hpp
- src/loader.cpp
- src/loader.hpp
- src/localsat.cpp
- src/localsat.hpp
- src/merge-vertex.cpp
- src/merge-vertex.hpp
- src/optimizer.cpp
- src/optimizer.hpp
- src/parametrizer.cpp
- src/parametrizer-flip.cpp
- src/parametrizer-int.cpp
- src/parametrizer-mesh.cpp
- src/parametrizer-scale.cpp
- src/parametrizer-sing.cpp
- src/parametrizer.hpp
- src/serialize.hpp
- src/subdivide.cpp
- src/subdivide.hpp
- ${LEMON_SOURCES}
+ src/adjacent-matrix.cpp
+ src/adjacent-matrix.hpp
+ src/compare-key.hpp
+ src/config.hpp
+ src/dedge.cpp
+ src/dedge.hpp
+ src/disajoint-tree.hpp
+ src/dset.hpp
+ src/field-math.hpp
+ src/flow.hpp
+ src/hierarchy.cpp
+ src/hierarchy.hpp
+ src/loader.cpp
+ src/loader.hpp
+ src/localsat.cpp
+ src/localsat.hpp
+ src/merge-vertex.cpp
+ src/merge-vertex.hpp
+ src/optimizer.cpp
+ src/optimizer.hpp
+ src/parametrizer.cpp
+ src/parametrizer-flip.cpp
+ src/parametrizer-int.cpp
+ src/parametrizer-mesh.cpp
+ src/parametrizer-scale.cpp
+ src/parametrizer-sing.cpp
+ src/parametrizer.hpp
+ src/serialize.hpp
+ src/subdivide.cpp
+ src/subdivide.hpp
+ ${LEMON_SOURCES}
)
set(LIB
diff --git a/extern/quadriflow/README.blender b/extern/quadriflow/README.blender
new file mode 100644
index 00000000000..c88a6d43353
--- /dev/null
+++ b/extern/quadriflow/README.blender
@@ -0,0 +1,5 @@
+Project: QuadriFlow
+URL: https://github.com/hjwdzh/QuadriFlow
+License: MIT and Boost Software License
+Upstream version: 27a6867
+Local modifications: Apply patches/blender.patch
diff --git a/extern/quadriflow/patches/blender.patch b/extern/quadriflow/patches/blender.patch
new file mode 100644
index 00000000000..55fdd123e3b
--- /dev/null
+++ b/extern/quadriflow/patches/blender.patch
@@ -0,0 +1,118 @@
+diff --git a/extern/quadriflow/src/config.hpp b/extern/quadriflow/src/config.hpp
+index 842b885..bf597ad 100644
+--- a/extern/quadriflow/src/config.hpp
++++ b/extern/quadriflow/src/config.hpp
+@@ -1,6 +1,11 @@
+ #ifndef CONFIG_H_
+ #define CONFIG_H_
+
++/* Workaround a bug in boost 1.68, until we upgrade to a newer version. */
++#if defined(__clang__) && defined(WIN32)
++ #include <boost/type_traits/is_assignable.hpp>
++ using namespace boost;
++#endif
+ // Move settings to cmake to make CMake happy :)
+
+ // #define WITH_SCALE
+diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
+index 35a73d9..0eeba8a 100644
+--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
++++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc
+@@ -221,9 +221,8 @@ namespace lemon {
+ const std::string &opt)
+ {
+ Opts::iterator o = _opts.find(opt);
+- Opts::iterator s = _opts.find(syn);
+ LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'");
+- LEMON_ASSERT(s==_opts.end(), "Option already used: '"+syn+"'");
++ LEMON_ASSERT(_opts.find(syn)==_opts.end(), "Option already used: '"+syn+"'");
+ ParData p;
+ p.help=opt;
+ p.mandatory=false;
+diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
+index 6ccad33..388e990 100644
+--- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
++++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/network_simplex.h
+@@ -234,7 +234,7 @@ namespace lemon {
+ int in_arc, join, u_in, v_in, u_out, v_out;
+ Value delta;
+
+- const Value MAX;
++ const Value MAX_VALUE;
+
+ public:
+
+@@ -649,9 +649,9 @@ namespace lemon {
+ NetworkSimplex(const GR& graph, bool arc_mixing = true) :
+ _graph(graph), _node_id(graph), _arc_id(graph),
+ _arc_mixing(arc_mixing),
+- MAX(std::numeric_limits<Value>::max()),
++ MAX_VALUE(std::numeric_limits<Value>::max()),
+ INF(std::numeric_limits<Value>::has_infinity ?
+- std::numeric_limits<Value>::infinity() : MAX)
++ std::numeric_limits<Value>::infinity() : MAX_VALUE)
+ {
+ // Check the number types
+ LEMON_ASSERT(std::numeric_limits<Value>::is_signed,
+@@ -1076,9 +1076,9 @@ namespace lemon {
+ for (int i = 0; i != _arc_num; ++i) {
+ Value c = _lower[i];
+ if (c >= 0) {
+- _cap[i] = _upper[i] < MAX ? _upper[i] - c : INF;
++ _cap[i] = _upper[i] < MAX_VALUE ? _upper[i] - c : INF;
+ } else {
+- _cap[i] = _upper[i] < MAX + c ? _upper[i] - c : INF;
++ _cap[i] = _upper[i] < MAX_VALUE + c ? _upper[i] - c : INF;
+ }
+ _supply[_source[i]] -= c;
+ _supply[_target[i]] += c;
+@@ -1282,7 +1282,7 @@ namespace lemon {
+ d = _flow[e];
+ if (_pred_dir[u] == DIR_DOWN) {
+ c = _cap[e];
+- d = c >= MAX ? INF : c - d;
++ d = c >= MAX_VALUE ? INF : c - d;
+ }
+ if (d < delta) {
+ delta = d;
+@@ -1297,7 +1297,7 @@ namespace lemon {
+ d = _flow[e];
+ if (_pred_dir[u] == DIR_UP) {
+ c = _cap[e];
+- d = c >= MAX ? INF : c - d;
++ d = c >= MAX_VALUE ? INF : c - d;
+ }
+ if (d <= delta) {
+ delta = d;
+@@ -1559,7 +1559,7 @@ namespace lemon {
+ _pi[_target[in_arc]]) >= 0) continue;
+ findJoinNode();
+ bool change = findLeavingArc();
+- if (delta >= MAX) return false;
++ if (delta >= MAX_VALUE) return false;
+ changeFlow(change);
+ if (change) {
+ updateTreeStructure();
+@@ -1598,7 +1598,7 @@ namespace lemon {
+ while (pivot.findEnteringArc()) {
+ findJoinNode();
+ bool change = findLeavingArc();
+- if (delta >= MAX) return UNBOUNDED;
++ if (delta >= MAX_VALUE) return UNBOUNDED;
+ changeFlow(change);
+ if (change) {
+ updateTreeStructure();
+diff --git a/extern/quadriflow/src/hierarchy.cpp b/extern/quadriflow/src/hierarchy.cpp
+index c333256..8cc41da 100644
+--- a/extern/quadriflow/src/hierarchy.cpp
++++ b/extern/quadriflow/src/hierarchy.cpp
+@@ -1133,7 +1133,8 @@ void Hierarchy::propagateConstraints() {
+ auto& COw = mCOw[l];
+ auto& COw_next = mCOw[l + 1];
+ auto& toUpper = mToUpper[l];
+- MatrixXd& S = mS[l];
++ // FIXME
++ // MatrixXd& S = mS[l];
+
+ for (uint32_t i = 0; i != mV[l + 1].cols(); ++i) {
+ Vector2i upper = toUpper.col(i);
diff --git a/extern/quadriflow/src/config.hpp b/extern/quadriflow/src/config.hpp
index 842b885a209..bf597ad0f39 100644
--- a/extern/quadriflow/src/config.hpp
+++ b/extern/quadriflow/src/config.hpp
@@ -1,6 +1,11 @@
#ifndef CONFIG_H_
#define CONFIG_H_
+/* Workaround a bug in boost 1.68, until we upgrade to a newer version. */
+#if defined(__clang__) && defined(WIN32)
+ #include <boost/type_traits/is_assignable.hpp>
+ using namespace boost;
+#endif
// Move settings to cmake to make CMake happy :)
// #define WITH_SCALE
diff --git a/extern/quadriflow/src/hierarchy.cpp b/extern/quadriflow/src/hierarchy.cpp
index c333256a139..8cc41da23d0 100644
--- a/extern/quadriflow/src/hierarchy.cpp
+++ b/extern/quadriflow/src/hierarchy.cpp
@@ -1133,7 +1133,8 @@ void Hierarchy::propagateConstraints() {
auto& COw = mCOw[l];
auto& COw_next = mCOw[l + 1];
auto& toUpper = mToUpper[l];
- MatrixXd& S = mS[l];
+ // FIXME
+ // MatrixXd& S = mS[l];
for (uint32_t i = 0; i != mV[l + 1].cols(); ++i) {
Vector2i upper = toUpper.col(i);
diff --git a/intern/clog/clog.c b/intern/clog/clog.c
index da94acd97b1..9074e0f85e1 100644
--- a/intern/clog/clog.c
+++ b/intern/clog/clog.c
@@ -174,6 +174,7 @@ static void clg_str_append(CLogStringBuf *cstr, const char *str)
clg_str_append_with_len(cstr, str, strlen(str));
}
+ATTR_PRINTF_FORMAT(2, 0)
static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
{
/* Use limit because windows may use '-1' for a formatting error. */
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 8623b38a271..840ab557132 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -957,7 +957,7 @@ class CyclesLightSettings(bpy.types.PropertyGroup):
class CyclesWorldSettings(bpy.types.PropertyGroup):
sampling_method: EnumProperty(
- name="Sampling method",
+ name="Sampling Method",
description="How to sample the background light",
items=enum_world_mis,
default='AUTOMATIC',
@@ -1331,12 +1331,12 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
subtype="PIXEL",
)
denoising_relative_pca: BoolProperty(
- name="Relative filter",
+ name="Relative Filter",
description="When removing pixels that don't carry information, use a relative threshold instead of an absolute one (can help to reduce artifacts, but might cause detail loss around edges)",
default=False,
)
denoising_store_passes: BoolProperty(
- name="Store denoising passes",
+ name="Store Denoising Passes",
description="Store the denoising feature passes and the noisy image",
default=False,
update=update_render_passes,
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 44ed28e9e02..b2624b2aa81 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1772,7 +1772,7 @@ class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- return not use_optix(context)
+ return CyclesButtonsPanel.poll(context) and not use_optix(context)
def draw(self, context):
layout = self.layout
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index 3b19e78894a..c84d6e1572b 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -899,7 +899,7 @@ BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render,
params.height = height;
}
- update_viewport_display_passes(b_v3d, params.passes, false);
+ update_viewport_display_passes(b_v3d, params.passes);
return params;
}
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 59509d20fb2..5520cfd5ecf 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -541,7 +541,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
const bool show_lights = BlenderViewportParameters(b_v3d).use_scene_lights;
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
- const bool has_local_view = b_v3d && b_v3d.local_view();
BL::Depsgraph::object_instances_iterator b_instance_iter;
for (b_depsgraph.object_instances.begin(b_instance_iter);
@@ -555,10 +554,10 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
/* test if object needs to be hidden */
const bool show_self = b_instance.show_self();
- const bool show_local_view = !has_local_view || b_ob.local_view_get(b_v3d);
const bool show_particles = b_instance.show_particles();
+ const bool show_in_viewport = !b_v3d || b_ob.visible_in_viewport_get(b_v3d);
- if (show_local_view && (show_self || show_particles)) {
+ if (show_in_viewport && (show_self || show_particles)) {
/* object itself */
sync_object(b_depsgraph,
b_view_layer,
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 362155f22ac..22dbc3fba79 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -1340,6 +1340,14 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
graph->connect(background->output("Background"), out->input("Surface"));
}
else if (!new_viewport_parameters.use_scene_world) {
+ float3 world_color;
+ if (b_world) {
+ world_color = get_float3(b_world.color());
+ }
+ else {
+ world_color = make_float3(0.0f, 0.0f, 0.0f);
+ }
+
BackgroundNode *background = new BackgroundNode();
graph->add(background);
@@ -1347,7 +1355,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
graph->add(light_path);
MixNode *mix_scene_with_background = new MixNode();
- mix_scene_with_background->color2 = get_float3(b_world.color());
+ mix_scene_with_background->color2 = world_color;
graph->add(mix_scene_with_background);
EnvironmentTextureNode *texture_environment = new EnvironmentTextureNode();
@@ -1369,7 +1377,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
MixNode *mix_background_with_environment = new MixNode();
mix_background_with_environment->fac = new_viewport_parameters.studiolight_background_alpha;
- mix_background_with_environment->color1 = get_float3(b_world.color());
+ mix_background_with_environment->color1 = world_color;
graph->add(mix_background_with_environment);
ShaderNode *out = graph->output();
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 1a166d171bc..f04455ff75e 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -344,7 +344,7 @@ void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
Film prevfilm = *film;
if (b_v3d) {
- film->display_pass = update_viewport_display_passes(b_v3d, film->passes, true);
+ film->display_pass = update_viewport_display_passes(b_v3d, film->passes);
}
film->exposure = get_float(cscene, "film_exposure");
@@ -520,7 +520,6 @@ int BlenderSync::get_denoising_pass(BL::RenderPass &b_pass)
vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer)
{
vector<Pass> passes;
- Pass::add(PASS_COMBINED, passes);
/* loop over passes */
BL::RenderLayer::passes_iterator b_pass_iter;
diff --git a/intern/cycles/blender/blender_viewport.cpp b/intern/cycles/blender/blender_viewport.cpp
index a74b20f150b..73ef5f94720 100644
--- a/intern/cycles/blender/blender_viewport.cpp
+++ b/intern/cycles/blender/blender_viewport.cpp
@@ -72,23 +72,13 @@ PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceVi
return display_pass;
}
-PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d,
- vector<Pass> &passes,
- bool reset_passes)
+PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes)
{
if (b_v3d) {
PassType display_pass = BlenderViewportParameters::get_viewport_display_render_pass(b_v3d);
- if (reset_passes) {
- passes.clear();
- /* We always need a combined pass for now. It would be a good optimization
- * to support rendering without combined pass. */
- Pass::add(PASS_COMBINED, passes);
- }
-
- if (display_pass != PASS_COMBINED) {
- Pass::add(display_pass, passes);
- }
+ passes.clear();
+ Pass::add(display_pass, passes);
return display_pass;
}
diff --git a/intern/cycles/blender/blender_viewport.h b/intern/cycles/blender/blender_viewport.h
index 564c4f2b210..f26d0d38115 100644
--- a/intern/cycles/blender/blender_viewport.h
+++ b/intern/cycles/blender/blender_viewport.h
@@ -49,9 +49,7 @@ class BlenderViewportParameters {
static PassType get_viewport_display_render_pass(BL::SpaceView3D &b_v3d);
};
-PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d,
- vector<Pass> &passes,
- bool reset_passes);
+PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes);
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index fe8a814cd14..76670351734 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -643,6 +643,7 @@ void Device::free_memory()
{
devices_initialized_mask = 0;
cuda_devices.free_memory();
+ optix_devices.free_memory();
opencl_devices.free_memory();
cpu_devices.free_memory();
network_devices.free_memory();
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index b2d923dfdf0..c2843a61e6d 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -114,6 +114,12 @@ template<typename F> class KernelFunctions {
architecture_name = "SSE2";
kernel = kernel_sse2;
}
+#else
+ {
+ /* Dummy to prevent the architecture if below become
+ * conditional when WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
+ * is not defined. */
+ }
#endif
if (strcmp(architecture_name, logged_architecture) != 0) {
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index 00dd37f089c..b5e10b0c2cb 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -454,6 +454,12 @@ class CUDADevice : public Device {
VLOG(1) << "Using precompiled kernel.";
return cubin;
}
+ const string ptx = path_get(string_printf("lib/%s_compute_%d%d.ptx", name, major, minor));
+ VLOG(1) << "Testing for pre-compiled kernel " << ptx << ".";
+ if (path_exists(ptx)) {
+ VLOG(1) << "Using precompiled kernel.";
+ return ptx;
+ }
}
const string common_cflags = compile_kernel_get_common_cflags(
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index 5b43ce8b0bc..272da6a9ad3 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -224,6 +224,7 @@ class device_memory {
protected:
friend class CUDADevice;
+ friend class OptiXDevice;
/* Only create through subclasses. */
device_memory(Device *device, const char *name, MemoryType type);
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index 84d7ecf6934..e230662e698 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -169,6 +169,7 @@ class OptiXDevice : public Device {
OptixModule optix_module = NULL;
OptixPipeline pipelines[NUM_PIPELINES] = {};
+ bool motion_blur = false;
bool need_texture_info = false;
device_vector<SbtRecord> sbt_data;
device_vector<TextureInfo> texture_info;
@@ -176,7 +177,14 @@ class OptiXDevice : public Device {
vector<device_only_memory<uint8_t>> blas;
OptixTraversableHandle tlas_handle = 0;
+ // TODO(pmours): This is copied from device_cuda.cpp, so move to common code eventually
+ int can_map_host = 0;
+ size_t map_host_used = 0;
+ size_t map_host_limit = 0;
+ size_t device_working_headroom = 32 * 1024 * 1024LL; // 32MB
+ size_t device_texture_headroom = 128 * 1024 * 1024LL; // 128MB
map<device_memory *, CUDAMem> cuda_mem_map;
+ bool move_texture_to_host = false;
public:
OptiXDevice(DeviceInfo &info_, Stats &stats_, Profiler &profiler_, bool background_)
@@ -198,6 +206,25 @@ class OptiXDevice : public Device {
// Make that CUDA context current
const CUDAContextScope scope(cuda_context);
+ // Limit amount of host mapped memory (see init_host_memory in device_cuda.cpp)
+ size_t default_limit = 4 * 1024 * 1024 * 1024LL;
+ size_t system_ram = system_physical_ram();
+ if (system_ram > 0) {
+ if (system_ram / 2 > default_limit) {
+ map_host_limit = system_ram - default_limit;
+ }
+ else {
+ map_host_limit = system_ram / 2;
+ }
+ }
+ else {
+ VLOG(1) << "Mapped host memory disabled, failed to get system RAM";
+ }
+
+ // Check device support for pinned host memory
+ check_result_cuda(
+ cuDeviceGetAttribute(&can_map_host, CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY, cuda_device));
+
// Create OptiX context for this device
OptixDeviceContextOptions options = {};
# ifdef WITH_CYCLES_LOGGING
@@ -337,7 +364,12 @@ class OptiXDevice : public Device {
# endif
pipeline_options.pipelineLaunchParamsVariableName = "__params"; // See kernel_globals.h
- if (requested_features.use_object_motion) {
+ // Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds
+ // This is necessary since objects may be reported to have motion if the Vector pass is
+ // active, but may still need to be rendered without motion blur if that isn't active as well
+ motion_blur = requested_features.use_object_motion;
+
+ if (motion_blur) {
pipeline_options.usesMotionBlur = true;
// Motion blur can insert motion transforms into the traversal graph
// It is no longer a two-level graph then, so need to set flags to allow any configuration
@@ -820,6 +852,7 @@ class OptiXDevice : public Device {
device_only_memory<char> temp_mem(this, "temp_build_mem");
temp_mem.alloc_to_device(sizes.tempSizeInBytes);
+ out_data.type = MEM_DEVICE_ONLY;
out_data.data_type = TYPE_UNKNOWN;
out_data.data_elements = 1;
out_data.data_size = sizes.outputSizeInBytes;
@@ -872,7 +905,7 @@ class OptiXDevice : public Device {
size_t num_motion_steps = 1;
Attribute *motion_keys = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (mesh->use_motion_blur && motion_keys) {
+ if (motion_blur && mesh->use_motion_blur && motion_keys) {
num_motion_steps = mesh->motion_steps;
}
@@ -881,20 +914,23 @@ class OptiXDevice : public Device {
// Get AABBs for each motion step
for (size_t step = 0; step < num_motion_steps; ++step) {
+ // The center step for motion vertices is not stored in the attribute
const float3 *keys = mesh->curve_keys.data();
-
size_t center_step = (num_motion_steps - 1) / 2;
- // The center step for motion vertices is not stored in the attribute
if (step != center_step) {
- keys = motion_keys->data_float3() +
- (step > center_step ? step - 1 : step) * num_segments;
+ size_t attr_offset = (step > center_step) ? step - 1 : step;
+ // Technically this is a float4 array, but sizeof(float3) is the same as sizeof(float4)
+ keys = motion_keys->data_float3() + attr_offset * mesh->curve_keys.size();
}
- for (size_t i = step * num_segments, j = 0; j < num_curves; ++j) {
+ size_t i = step * num_segments;
+ for (size_t j = 0; j < num_curves; ++j) {
const Mesh::Curve c = mesh->get_curve(j);
+
for (size_t k = 0; k < c.num_segments(); ++i, ++k) {
BoundBox bounds = BoundBox::empty;
c.bounds_grow(k, keys, mesh->curve_radius.data(), bounds);
+
aabb_data[i].minX = bounds.min.x;
aabb_data[i].minY = bounds.min.y;
aabb_data[i].minZ = bounds.min.z;
@@ -917,7 +953,6 @@ class OptiXDevice : public Device {
// Disable visibility test anyhit program, since it is already checked during intersection
// Those trace calls that require anyhit can force it with OPTIX_RAY_FLAG_ENFORCE_ANYHIT
unsigned int build_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT;
-
OptixBuildInput build_input = {};
build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
build_input.aabbArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
@@ -940,7 +975,7 @@ class OptiXDevice : public Device {
size_t num_motion_steps = 1;
Attribute *motion_keys = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (mesh->use_motion_blur && motion_keys) {
+ if (motion_blur && mesh->use_motion_blur && motion_keys) {
num_motion_steps = mesh->motion_steps;
}
@@ -975,7 +1010,6 @@ class OptiXDevice : public Device {
// No special build flags for triangle primitives
unsigned int build_flags = OPTIX_GEOMETRY_FLAG_NONE;
-
OptixBuildInput build_input = {};
build_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES;
build_input.triangleArray.vertexBuffers = (CUdeviceptr *)vertex_ptrs.data();
@@ -1040,7 +1074,7 @@ class OptiXDevice : public Device {
instance.visibilityMask = (ob->mesh->has_volume ? 3 : 1);
// Insert motion traversable if object has motion
- if (ob->use_motion()) {
+ if (motion_blur && ob->use_motion()) {
blas.emplace_back(this, "motion_transform");
device_only_memory<uint8_t> &motion_transform_gpu = blas.back();
motion_transform_gpu.alloc_to_device(sizeof(OptixSRTMotionTransform) +
@@ -1161,131 +1195,162 @@ class OptiXDevice : public Device {
void mem_alloc(device_memory &mem) override
{
- const CUDAContextScope scope(cuda_context);
+ if (mem.type == MEM_PIXELS && !background) {
+ assert(!"mem_alloc not supported for pixels.");
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ assert(!"mem_alloc not supported for textures.");
+ }
+ else {
+ generic_alloc(mem);
+ }
+ }
- mem.device_size = mem.memory_size();
-
- if (mem.type == MEM_TEXTURE && mem.interpolation != INTERPOLATION_NONE) {
- CUDAMem &cmem = cuda_mem_map[&mem]; // Lock and get associated memory information
-
- CUDA_TEXTURE_DESC tex_desc = {};
- tex_desc.flags = CU_TRSF_NORMALIZED_COORDINATES;
- CUDA_RESOURCE_DESC res_desc = {};
-
- switch (mem.extension) {
- default:
- assert(0);
- case EXTENSION_REPEAT:
- tex_desc.addressMode[0] = tex_desc.addressMode[1] = tex_desc.addressMode[2] =
- CU_TR_ADDRESS_MODE_WRAP;
- break;
- case EXTENSION_EXTEND:
- tex_desc.addressMode[0] = tex_desc.addressMode[1] = tex_desc.addressMode[2] =
- CU_TR_ADDRESS_MODE_CLAMP;
- break;
- case EXTENSION_CLIP:
- tex_desc.addressMode[0] = tex_desc.addressMode[1] = tex_desc.addressMode[2] =
- CU_TR_ADDRESS_MODE_BORDER;
- break;
- }
+ CUDAMem *generic_alloc(device_memory &mem, size_t pitch_padding = 0)
+ {
+ CUDAContextScope scope(cuda_context);
- switch (mem.interpolation) {
- default: // Default to linear for unsupported interpolation types
- case INTERPOLATION_LINEAR:
- tex_desc.filterMode = CU_TR_FILTER_MODE_LINEAR;
- break;
- case INTERPOLATION_CLOSEST:
- tex_desc.filterMode = CU_TR_FILTER_MODE_POINT;
- break;
- }
+ CUdeviceptr device_pointer = 0;
+ size_t size = mem.memory_size() + pitch_padding;
- CUarray_format format;
- switch (mem.data_type) {
- default:
- assert(0);
- case TYPE_UCHAR:
- format = CU_AD_FORMAT_UNSIGNED_INT8;
- break;
- case TYPE_UINT16:
- format = CU_AD_FORMAT_UNSIGNED_INT16;
- break;
- case TYPE_UINT:
- format = CU_AD_FORMAT_UNSIGNED_INT32;
- break;
- case TYPE_INT:
- format = CU_AD_FORMAT_SIGNED_INT32;
- break;
- case TYPE_FLOAT:
- format = CU_AD_FORMAT_FLOAT;
- break;
- case TYPE_HALF:
- format = CU_AD_FORMAT_HALF;
- break;
- }
+ CUresult mem_alloc_result = CUDA_ERROR_OUT_OF_MEMORY;
+ const char *status = "";
+
+ /* First try allocating in device memory, respecting headroom. We make
+ * an exception for texture info. It is small and frequently accessed,
+ * so treat it as working memory.
+ *
+ * If there is not enough room for working memory, we will try to move
+ * textures to host memory, assuming the performance impact would have
+ * been worse for working memory. */
+ bool is_texture = (mem.type == MEM_TEXTURE) && (&mem != &texture_info);
+ bool is_image = is_texture && (mem.data_height > 1);
- if (mem.data_depth > 1) { /* 3D texture using array. */
- CUDA_ARRAY3D_DESCRIPTOR desc;
- desc.Width = mem.data_width;
- desc.Height = mem.data_height;
- desc.Depth = mem.data_depth;
- desc.Format = format;
- desc.NumChannels = mem.data_elements;
- desc.Flags = 0;
+ size_t headroom = (is_texture) ? device_texture_headroom : device_working_headroom;
- check_result_cuda(cuArray3DCreate(&cmem.array, &desc));
- mem.device_pointer = (device_ptr)cmem.array;
+ size_t total = 0, free = 0;
+ cuMemGetInfo(&free, &total);
+
+ /* Move textures to host memory if needed. */
+ if (!move_texture_to_host && !is_image && (size + headroom) >= free) {
+ move_textures_to_host(size + headroom - free, is_texture);
+ cuMemGetInfo(&free, &total);
+ }
- res_desc.resType = CU_RESOURCE_TYPE_ARRAY;
- res_desc.res.array.hArray = cmem.array;
+ /* Allocate in device memory. */
+ if (!move_texture_to_host && (size + headroom) < free) {
+ mem_alloc_result = cuMemAlloc(&device_pointer, size);
+ if (mem_alloc_result == CUDA_SUCCESS) {
+ status = " in device memory";
}
- else if (mem.data_height > 0) { /* 2D texture using array. */
- CUDA_ARRAY_DESCRIPTOR desc;
- desc.Width = mem.data_width;
- desc.Height = mem.data_height;
- desc.Format = format;
- desc.NumChannels = mem.data_elements;
-
- check_result_cuda(cuArrayCreate(&cmem.array, &desc));
- mem.device_pointer = (device_ptr)cmem.array;
-
- res_desc.resType = CU_RESOURCE_TYPE_ARRAY;
- res_desc.res.array.hArray = cmem.array;
+ }
+
+ /* Fall back to mapped host memory if needed and possible. */
+ void *map_host_pointer = 0;
+ bool free_map_host = false;
+
+ if (mem_alloc_result != CUDA_SUCCESS && can_map_host &&
+ map_host_used + size < map_host_limit) {
+ if (mem.shared_pointer) {
+ /* Another device already allocated host memory. */
+ mem_alloc_result = CUDA_SUCCESS;
+ map_host_pointer = mem.shared_pointer;
}
else {
- check_result_cuda(cuMemAlloc((CUdeviceptr *)&mem.device_pointer, mem.device_size));
+ /* Allocate host memory ourselves. */
+ mem_alloc_result = cuMemHostAlloc(
+ &map_host_pointer, size, CU_MEMHOSTALLOC_DEVICEMAP | CU_MEMHOSTALLOC_WRITECOMBINED);
+ mem.shared_pointer = map_host_pointer;
+ free_map_host = true;
+ }
- res_desc.resType = CU_RESOURCE_TYPE_LINEAR;
- res_desc.res.linear.devPtr = (CUdeviceptr)mem.device_pointer;
- res_desc.res.linear.format = format;
- res_desc.res.linear.numChannels = mem.data_elements;
- res_desc.res.linear.sizeInBytes = mem.device_size;
+ if (mem_alloc_result == CUDA_SUCCESS) {
+ cuMemHostGetDevicePointer_v2(&device_pointer, mem.shared_pointer, 0);
+ map_host_used += size;
+ status = " in host memory";
+
+ /* Replace host pointer with our host allocation. Only works if
+ * CUDA memory layout is the same and has no pitch padding. Also
+ * does not work if we move textures to host during a render,
+ * since other devices might be using the memory. */
+ if (!move_texture_to_host && pitch_padding == 0 && mem.host_pointer &&
+ mem.host_pointer != mem.shared_pointer) {
+ memcpy(mem.shared_pointer, mem.host_pointer, size);
+ mem.host_free();
+ mem.host_pointer = mem.shared_pointer;
+ }
+ }
+ else {
+ status = " failed, out of host memory";
}
+ }
+ else if (mem_alloc_result != CUDA_SUCCESS) {
+ status = " failed, out of device and host memory";
+ }
- check_result_cuda(cuTexObjectCreate(&cmem.texobject, &res_desc, &tex_desc, NULL));
+ if (mem.name) {
+ VLOG(1) << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")" << status;
+ }
- int flat_slot = 0;
- if (string_startswith(mem.name, "__tex_image")) {
- flat_slot = atoi(mem.name + string(mem.name).rfind("_") + 1);
- }
+ if (mem_alloc_result != CUDA_SUCCESS) {
+ set_error(string_printf("Buffer allocate %s", status));
+ return NULL;
+ }
+
+ mem.device_pointer = (device_ptr)device_pointer;
+ mem.device_size = size;
+ stats.mem_alloc(size);
- if (flat_slot >= texture_info.size())
- texture_info.resize(flat_slot + 128);
+ if (!mem.device_pointer) {
+ return NULL;
+ }
+
+ /* Insert into map of allocations. */
+ CUDAMem *cmem = &cuda_mem_map[&mem];
+ cmem->map_host_pointer = map_host_pointer;
+ cmem->free_map_host = free_map_host;
+ return cmem;
+ }
- TextureInfo &info = texture_info[flat_slot];
- info.data = (uint64_t)cmem.texobject;
- info.cl_buffer = 0;
- info.interpolation = mem.interpolation;
- info.extension = mem.extension;
- info.width = mem.data_width;
- info.height = mem.data_height;
- info.depth = mem.data_depth;
+ void tex_alloc(device_memory &mem)
+ {
+ CUDAContextScope scope(cuda_context);
+
+ /* General variables for both architectures */
+ string bind_name = mem.name;
+ size_t dsize = datatype_size(mem.data_type);
+ size_t size = mem.memory_size();
+
+ CUaddress_mode address_mode = CU_TR_ADDRESS_MODE_WRAP;
+ switch (mem.extension) {
+ case EXTENSION_REPEAT:
+ address_mode = CU_TR_ADDRESS_MODE_WRAP;
+ break;
+ case EXTENSION_EXTEND:
+ address_mode = CU_TR_ADDRESS_MODE_CLAMP;
+ break;
+ case EXTENSION_CLIP:
+ address_mode = CU_TR_ADDRESS_MODE_BORDER;
+ break;
+ default:
+ assert(0);
+ break;
+ }
- // Texture information has changed and needs an update, delay this to next launch
- need_texture_info = true;
+ CUfilter_mode filter_mode;
+ if (mem.interpolation == INTERPOLATION_CLOSEST) {
+ filter_mode = CU_TR_FILTER_MODE_POINT;
}
else {
- // This is not a texture but simple linear memory
- check_result_cuda(cuMemAlloc((CUdeviceptr *)&mem.device_pointer, mem.device_size));
+ filter_mode = CU_TR_FILTER_MODE_LINEAR;
+ }
+
+ /* Data Storage */
+ if (mem.interpolation == INTERPOLATION_NONE) {
+ generic_alloc(mem);
+ generic_copy_to(mem);
// Update data storage pointers in launch parameters
# define KERNEL_TEX(data_type, tex_name) \
@@ -1294,77 +1359,233 @@ class OptiXDevice : public Device {
mem.name, offsetof(KernelParams, tex_name), &mem.device_pointer, sizeof(device_ptr));
# include "kernel/kernel_textures.h"
# undef KERNEL_TEX
+ return;
}
- stats.mem_alloc(mem.device_size);
- }
+ /* Image Texture Storage */
+ CUarray_format_enum format;
+ switch (mem.data_type) {
+ case TYPE_UCHAR:
+ format = CU_AD_FORMAT_UNSIGNED_INT8;
+ break;
+ case TYPE_UINT16:
+ format = CU_AD_FORMAT_UNSIGNED_INT16;
+ break;
+ case TYPE_UINT:
+ format = CU_AD_FORMAT_UNSIGNED_INT32;
+ break;
+ case TYPE_INT:
+ format = CU_AD_FORMAT_SIGNED_INT32;
+ break;
+ case TYPE_FLOAT:
+ format = CU_AD_FORMAT_FLOAT;
+ break;
+ case TYPE_HALF:
+ format = CU_AD_FORMAT_HALF;
+ break;
+ default:
+ assert(0);
+ return;
+ }
- void mem_copy_to(device_memory &mem) override
- {
- if (!mem.host_pointer || mem.host_pointer == mem.shared_pointer)
- return;
- if (!mem.device_pointer)
- mem_alloc(mem); // Need to allocate memory first if it does not exist yet
+ CUDAMem *cmem = NULL;
+ CUarray array_3d = NULL;
+ size_t src_pitch = mem.data_width * dsize * mem.data_elements;
+ size_t dst_pitch = src_pitch;
- const CUDAContextScope scope(cuda_context);
+ if (mem.data_depth > 1) {
+ /* 3D texture using array, there is no API for linear memory. */
+ CUDA_ARRAY3D_DESCRIPTOR desc;
- if (mem.type == MEM_TEXTURE && mem.interpolation != INTERPOLATION_NONE) {
- const CUDAMem &cmem = cuda_mem_map[&mem]; // Lock and get associated memory information
+ desc.Width = mem.data_width;
+ desc.Height = mem.data_height;
+ desc.Depth = mem.data_depth;
+ desc.Format = format;
+ desc.NumChannels = mem.data_elements;
+ desc.Flags = 0;
- size_t src_pitch = mem.data_width * datatype_size(mem.data_type) * mem.data_elements;
+ VLOG(1) << "Array 3D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
- if (mem.data_depth > 1) {
- CUDA_MEMCPY3D param;
- memset(&param, 0, sizeof(param));
- param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
- param.dstArray = cmem.array;
- param.srcMemoryType = CU_MEMORYTYPE_HOST;
- param.srcHost = mem.host_pointer;
- param.srcPitch = src_pitch;
- param.WidthInBytes = param.srcPitch;
- param.Height = mem.data_height;
- param.Depth = mem.data_depth;
+ check_result_cuda(cuArray3DCreate(&array_3d, &desc));
- check_result_cuda(cuMemcpy3D(&param));
+ if (!array_3d) {
+ return;
}
- else if (mem.data_height > 0) {
- CUDA_MEMCPY2D param;
- memset(&param, 0, sizeof(param));
- param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
- param.dstArray = cmem.array;
- param.srcMemoryType = CU_MEMORYTYPE_HOST;
- param.srcHost = mem.host_pointer;
- param.srcPitch = src_pitch;
- param.WidthInBytes = param.srcPitch;
- param.Height = mem.data_height;
-
- check_result_cuda(cuMemcpy2D(&param));
+
+ CUDA_MEMCPY3D param;
+ memset(&param, 0, sizeof(param));
+ param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
+ param.dstArray = array_3d;
+ param.srcMemoryType = CU_MEMORYTYPE_HOST;
+ param.srcHost = mem.host_pointer;
+ param.srcPitch = src_pitch;
+ param.WidthInBytes = param.srcPitch;
+ param.Height = mem.data_height;
+ param.Depth = mem.data_depth;
+
+ check_result_cuda(cuMemcpy3D(&param));
+
+ mem.device_pointer = (device_ptr)array_3d;
+ mem.device_size = size;
+ stats.mem_alloc(size);
+
+ cmem = &cuda_mem_map[&mem];
+ cmem->texobject = 0;
+ cmem->array = array_3d;
+ }
+ else if (mem.data_height > 0) {
+ /* 2D texture, using pitch aligned linear memory. */
+ int alignment = 0;
+ check_result_cuda(cuDeviceGetAttribute(
+ &alignment, CU_DEVICE_ATTRIBUTE_TEXTURE_PITCH_ALIGNMENT, cuda_device));
+ dst_pitch = align_up(src_pitch, alignment);
+ size_t dst_size = dst_pitch * mem.data_height;
+
+ cmem = generic_alloc(mem, dst_size - mem.memory_size());
+ if (!cmem) {
+ return;
}
- else {
- check_result_cuda(
- cuMemcpyHtoD((CUdeviceptr)mem.device_pointer, mem.host_pointer, mem.device_size));
+
+ CUDA_MEMCPY2D param;
+ memset(&param, 0, sizeof(param));
+ param.dstMemoryType = CU_MEMORYTYPE_DEVICE;
+ param.dstDevice = mem.device_pointer;
+ param.dstPitch = dst_pitch;
+ param.srcMemoryType = CU_MEMORYTYPE_HOST;
+ param.srcHost = mem.host_pointer;
+ param.srcPitch = src_pitch;
+ param.WidthInBytes = param.srcPitch;
+ param.Height = mem.data_height;
+
+ check_result_cuda(cuMemcpy2DUnaligned(&param));
+ }
+ else {
+ /* 1D texture, using linear memory. */
+ cmem = generic_alloc(mem);
+ if (!cmem) {
+ return;
}
+
+ check_result_cuda(cuMemcpyHtoD(mem.device_pointer, mem.host_pointer, size));
+ }
+
+ /* Kepler+, bindless textures. */
+ int flat_slot = 0;
+ if (string_startswith(mem.name, "__tex_image")) {
+ int pos = string(mem.name).rfind("_");
+ flat_slot = atoi(mem.name + pos + 1);
}
else {
- // This is not a texture but simple linear memory
- check_result_cuda(
- cuMemcpyHtoD((CUdeviceptr)mem.device_pointer, mem.host_pointer, mem.device_size));
+ assert(0);
+ }
+
+ CUDA_RESOURCE_DESC resDesc;
+ memset(&resDesc, 0, sizeof(resDesc));
+
+ if (array_3d) {
+ resDesc.resType = CU_RESOURCE_TYPE_ARRAY;
+ resDesc.res.array.hArray = array_3d;
+ resDesc.flags = 0;
+ }
+ else if (mem.data_height > 0) {
+ resDesc.resType = CU_RESOURCE_TYPE_PITCH2D;
+ resDesc.res.pitch2D.devPtr = mem.device_pointer;
+ resDesc.res.pitch2D.format = format;
+ resDesc.res.pitch2D.numChannels = mem.data_elements;
+ resDesc.res.pitch2D.height = mem.data_height;
+ resDesc.res.pitch2D.width = mem.data_width;
+ resDesc.res.pitch2D.pitchInBytes = dst_pitch;
+ }
+ else {
+ resDesc.resType = CU_RESOURCE_TYPE_LINEAR;
+ resDesc.res.linear.devPtr = mem.device_pointer;
+ resDesc.res.linear.format = format;
+ resDesc.res.linear.numChannels = mem.data_elements;
+ resDesc.res.linear.sizeInBytes = mem.device_size;
}
+
+ CUDA_TEXTURE_DESC texDesc;
+ memset(&texDesc, 0, sizeof(texDesc));
+ texDesc.addressMode[0] = address_mode;
+ texDesc.addressMode[1] = address_mode;
+ texDesc.addressMode[2] = address_mode;
+ texDesc.filterMode = filter_mode;
+ texDesc.flags = CU_TRSF_NORMALIZED_COORDINATES;
+
+ check_result_cuda(cuTexObjectCreate(&cmem->texobject, &resDesc, &texDesc, NULL));
+
+ /* Resize once */
+ if (flat_slot >= texture_info.size()) {
+ /* Allocate some slots in advance, to reduce amount
+ * of re-allocations. */
+ texture_info.resize(flat_slot + 128);
+ }
+
+ /* Set Mapping and tag that we need to (re-)upload to device */
+ TextureInfo &info = texture_info[flat_slot];
+ info.data = (uint64_t)cmem->texobject;
+ info.cl_buffer = 0;
+ info.interpolation = mem.interpolation;
+ info.extension = mem.extension;
+ info.width = mem.data_width;
+ info.height = mem.data_height;
+ info.depth = mem.data_depth;
+ need_texture_info = true;
}
- void mem_copy_from(device_memory &mem, int y, int w, int h, int elem) override
+ void mem_copy_to(device_memory &mem) override
{
- // Calculate linear memory offset and size
- const size_t size = elem * w * h;
- const size_t offset = elem * y * w;
+ if (mem.type == MEM_PIXELS) {
+ assert(!"mem_copy_to not supported for pixels.");
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free(mem);
+ tex_alloc(mem);
+ }
+ else {
+ if (!mem.device_pointer) {
+ generic_alloc(mem);
+ }
+ generic_copy_to(mem);
+ }
+ }
+
+ void generic_copy_to(device_memory &mem)
+ {
if (mem.host_pointer && mem.device_pointer) {
- const CUDAContextScope scope(cuda_context);
- check_result_cuda(cuMemcpyDtoH(
- (char *)mem.host_pointer + offset, (CUdeviceptr)mem.device_pointer + offset, size));
+ CUDAContextScope scope(cuda_context);
+
+ if (mem.host_pointer != mem.shared_pointer) {
+ check_result_cuda(
+ cuMemcpyHtoD((CUdeviceptr)mem.device_pointer, mem.host_pointer, mem.memory_size()));
+ }
+ }
+ }
+
+ void mem_copy_from(device_memory &mem, int y, int w, int h, int elem) override
+ {
+ if (mem.type == MEM_PIXELS && !background) {
+ assert(!"mem_copy_from not supported for pixels.");
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ assert(!"mem_copy_from not supported for textures.");
}
- else if (mem.host_pointer) {
- memset((char *)mem.host_pointer + offset, 0, size);
+ else {
+ // Calculate linear memory offset and size
+ const size_t size = elem * w * h;
+ const size_t offset = elem * y * w;
+
+ if (mem.host_pointer && mem.device_pointer) {
+ const CUDAContextScope scope(cuda_context);
+ check_result_cuda(cuMemcpyDtoH(
+ (char *)mem.host_pointer + offset, (CUdeviceptr)mem.device_pointer + offset, size));
+ }
+ else if (mem.host_pointer) {
+ memset((char *)mem.host_pointer + offset, 0, size);
+ }
}
}
@@ -1384,30 +1605,145 @@ class OptiXDevice : public Device {
void mem_free(device_memory &mem) override
{
- assert(mem.device_pointer);
+ if (mem.type == MEM_PIXELS && !background) {
+ assert(!"mem_free not supported for pixels.");
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free(mem);
+ }
+ else {
+ generic_free(mem);
+ }
+ }
- const CUDAContextScope scope(cuda_context);
+ void generic_free(device_memory &mem)
+ {
+ if (mem.device_pointer) {
+ CUDAContextScope scope(cuda_context);
+ const CUDAMem &cmem = cuda_mem_map[&mem];
+
+ if (cmem.map_host_pointer) {
+ /* Free host memory. */
+ if (cmem.free_map_host) {
+ cuMemFreeHost(cmem.map_host_pointer);
+ if (mem.host_pointer == mem.shared_pointer) {
+ mem.host_pointer = 0;
+ }
+ mem.shared_pointer = 0;
+ }
- if (mem.type == MEM_TEXTURE && mem.interpolation != INTERPOLATION_NONE) {
- CUDAMem &cmem = cuda_mem_map[&mem]; // Lock and get associated memory information
+ map_host_used -= mem.device_size;
+ }
+ else {
+ /* Free device memory. */
+ cuMemFree(mem.device_pointer);
+ }
- if (cmem.array)
- cuArrayDestroy(cmem.array);
- else
- cuMemFree((CUdeviceptr)mem.device_pointer);
+ stats.mem_free(mem.device_size);
+ mem.device_pointer = 0;
+ mem.device_size = 0;
- if (cmem.texobject)
+ cuda_mem_map.erase(cuda_mem_map.find(&mem));
+ }
+ }
+
+ void tex_free(device_memory &mem)
+ {
+ if (mem.device_pointer) {
+ CUDAContextScope scope(cuda_context);
+ const CUDAMem &cmem = cuda_mem_map[&mem];
+
+ if (cmem.texobject) {
+ /* Free bindless texture. */
cuTexObjectDestroy(cmem.texobject);
+ }
+
+ if (cmem.array) {
+ /* Free array. */
+ cuArrayDestroy(cmem.array);
+ stats.mem_free(mem.device_size);
+ mem.device_pointer = 0;
+ mem.device_size = 0;
+
+ cuda_mem_map.erase(cuda_mem_map.find(&mem));
+ }
+ else {
+ generic_free(mem);
+ }
}
- else {
- // This is not a texture but simple linear memory
- cuMemFree((CUdeviceptr)mem.device_pointer);
+ }
+
+ void move_textures_to_host(size_t size, bool for_texture)
+ {
+ /* Signal to reallocate textures in host memory only. */
+ move_texture_to_host = true;
+
+ while (size > 0) {
+ /* Find suitable memory allocation to move. */
+ device_memory *max_mem = NULL;
+ size_t max_size = 0;
+ bool max_is_image = false;
+
+ foreach (auto &pair, cuda_mem_map) {
+ device_memory &mem = *pair.first;
+ CUDAMem *cmem = &pair.second;
+
+ bool is_texture = (mem.type == MEM_TEXTURE) && (&mem != &texture_info);
+ bool is_image = is_texture && (mem.data_height > 1);
+
+ /* Can't move this type of memory. */
+ if (!is_texture || cmem->array) {
+ continue;
+ }
+
+ /* Already in host memory. */
+ if (cmem->map_host_pointer) {
+ continue;
+ }
+
+ /* For other textures, only move image textures. */
+ if (for_texture && !is_image) {
+ continue;
+ }
+
+ /* Try to move largest allocation, prefer moving images. */
+ if (is_image > max_is_image || (is_image == max_is_image && mem.device_size > max_size)) {
+ max_is_image = is_image;
+ max_size = mem.device_size;
+ max_mem = &mem;
+ }
+ }
+
+ /* Move to host memory. This part is mutex protected since
+ * multiple CUDA devices could be moving the memory. The
+ * first one will do it, and the rest will adopt the pointer. */
+ if (max_mem) {
+ VLOG(1) << "Move memory from device to host: " << max_mem->name;
+
+ static thread_mutex move_mutex;
+ thread_scoped_lock lock(move_mutex);
+
+ /* Preserve the original device pointer, in case of multi device
+ * we can't change it because the pointer mapping would break. */
+ device_ptr prev_pointer = max_mem->device_pointer;
+ size_t prev_size = max_mem->device_size;
+
+ tex_free(*max_mem);
+ tex_alloc(*max_mem);
+ size = (max_size >= size) ? 0 : size - max_size;
+
+ max_mem->device_pointer = prev_pointer;
+ max_mem->device_size = prev_size;
+ }
+ else {
+ break;
+ }
}
- stats.mem_free(mem.device_size);
+ /* Update texture info array with new pointers. */
+ update_texture_info();
- mem.device_size = 0;
- mem.device_pointer = 0;
+ move_texture_to_host = false;
}
void const_copy_to(const char *name, void *host, size_t size) override
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index ea8aa197b6f..78da584e132 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -389,11 +389,20 @@ if(WITH_CYCLES_CUDA_BINARIES)
set(cuda_cubins)
macro(CYCLES_CUDA_KERNEL_ADD arch prev_arch name flags sources experimental)
- set(cuda_cubin ${name}_${arch}.cubin)
+ if(${arch} MATCHES "compute_.*")
+ set(format "ptx")
+ else()
+ set(format "cubin")
+ endif()
+ set(cuda_file ${name}_${arch}.${format})
set(kernel_sources ${sources})
if(NOT ${prev_arch} STREQUAL "none")
- set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.cubin)
+ if(${prev_arch} MATCHES "compute_.*")
+ set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.ptx)
+ else()
+ set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.cubin)
+ endif()
endif()
set(cuda_kernel_src "/kernels/cuda/${name}.cu")
@@ -406,7 +415,7 @@ if(WITH_CYCLES_CUDA_BINARIES)
-I ${CMAKE_CURRENT_SOURCE_DIR}/..
-I ${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda
--use_fast_math
- -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin})
+ -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_file})
if(${experimental})
set(cuda_flags ${cuda_flags} -D __KERNEL_EXPERIMENTAL__)
@@ -440,20 +449,21 @@ if(WITH_CYCLES_CUDA_BINARIES)
-v
-cuda-toolkit-dir "${CUDA_TOOLKIT_ROOT_DIR}"
DEPENDS ${kernel_sources} cycles_cubin_cc)
+ set(cuda_file ${cuda_cubin})
else()
add_custom_command(
- OUTPUT ${cuda_cubin}
+ OUTPUT ${cuda_file}
COMMAND ${CUDA_NVCC_EXECUTABLE}
-arch=${arch}
${CUDA_NVCC_FLAGS}
- --cubin
+ --${format}
${CMAKE_CURRENT_SOURCE_DIR}${cuda_kernel_src}
--ptxas-options="-v"
${cuda_flags}
DEPENDS ${kernel_sources})
endif()
- delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${cuda_cubin}" ${CYCLES_INSTALL_PATH}/lib)
- list(APPEND cuda_cubins ${cuda_cubin})
+ delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${cuda_file}" ${CYCLES_INSTALL_PATH}/lib)
+ list(APPEND cuda_cubins ${cuda_file})
unset(cuda_debug_flags)
endmacro()
diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h
index d0bc1fe4b36..0346f5e09e7 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -575,7 +575,7 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
- return rtc_ray.tfar == -INFINITY;
+ return ctx.num_hits;
}
# endif /* __EMBREE__ */
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 7d7ccfa7774..2f73434706c 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -303,9 +303,7 @@ ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf)
ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd)
{
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
@@ -321,9 +319,7 @@ ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const Sha
ccl_device int bsdf_microfacet_ggx_clearcoat_setup(MicrofacetBsdf *bsdf, const ShaderData *sd)
{
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
@@ -366,9 +362,7 @@ ccl_device int bsdf_microfacet_ggx_aniso_setup(MicrofacetBsdf *bsdf)
ccl_device int bsdf_microfacet_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd)
{
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0));
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
index 07be33ee6b5..9780dd87415 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -378,12 +378,8 @@ ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf)
{
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f);
- bsdf->extra->color.x = saturate(bsdf->extra->color.x);
- bsdf->extra->color.y = saturate(bsdf->extra->color.y);
- bsdf->extra->color.z = saturate(bsdf->extra->color.z);
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->color = saturate3(bsdf->extra->color);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
}
@@ -568,9 +564,7 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf)
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->ior = max(0.0f, bsdf->ior);
- bsdf->extra->color.x = saturate(bsdf->extra->color.x);
- bsdf->extra->color.y = saturate(bsdf->extra->color.y);
- bsdf->extra->color.z = saturate(bsdf->extra->color.z);
+ bsdf->extra->color = saturate3(bsdf->extra->color);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
@@ -583,12 +577,8 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsd
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->ior = max(0.0f, bsdf->ior);
- bsdf->extra->color.x = saturate(bsdf->extra->color.x);
- bsdf->extra->color.y = saturate(bsdf->extra->color.y);
- bsdf->extra->color.z = saturate(bsdf->extra->color.z);
- bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
- bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
- bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
+ bsdf->extra->color = saturate3(bsdf->extra->color);
+ bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID;
diff --git a/intern/cycles/kernel/filter/filter_transform_gpu.h b/intern/cycles/kernel/filter/filter_transform_gpu.h
index 41bbadb621d..adc85881fe5 100644
--- a/intern/cycles/kernel/filter/filter_transform_gpu.h
+++ b/intern/cycles/kernel/filter/filter_transform_gpu.h
@@ -76,9 +76,9 @@ ccl_device void kernel_filter_construct_transform(const ccl_global float *ccl_re
filter_calculate_scale(feature_scale, use_time);
/* === Generate the feature transformation. ===
- * This transformation maps the num_features-dimentional feature space to a reduced feature
- * (r-feature) space which generally has fewer dimensions. This mainly helps to prevent
- * overfitting. */
+ * This transformation maps the num_features-dimensional feature space to a reduced feature
+ * (r-feature) space which generally has fewer dimensions.
+ * This mainly helps to prevent overfitting. */
float feature_matrix[DENOISE_FEATURES * DENOISE_FEATURES];
math_matrix_zero(feature_matrix, num_features);
FOR_PIXEL_WINDOW
diff --git a/intern/cycles/kernel/filter/filter_transform_sse.h b/intern/cycles/kernel/filter/filter_transform_sse.h
index 830444645d7..5a124b5d73b 100644
--- a/intern/cycles/kernel/filter/filter_transform_sse.h
+++ b/intern/cycles/kernel/filter/filter_transform_sse.h
@@ -73,9 +73,9 @@ ccl_device void kernel_filter_construct_transform(const float *ccl_restrict buff
filter_calculate_scale_sse(feature_scale, use_time);
/* === Generate the feature transformation. ===
- * This transformation maps the num_features-dimentional feature space to a reduced feature
- * (r-feature) space which generally has fewer dimensions. This mainly helps to prevent
- * overfitting. */
+ * This transformation maps the num_features-dimensional feature space to a reduced feature
+ * (r-feature) space which generally has fewer dimensions.
+ * This mainly helps to prevent over-fitting. */
float4 feature_matrix_sse[DENOISE_FEATURES * DENOISE_FEATURES];
math_matrix_zero_sse(feature_matrix_sse, num_features);
FOR_PIXEL_WINDOW_SSE
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index 4a424866efe..c1d74dddc2a 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -397,7 +397,9 @@ ccl_device_inline void kernel_write_result(KernelGlobals *kg,
float alpha;
float3 L_sum = path_radiance_clamp_and_sum(kg, L, &alpha);
- kernel_write_pass_float4(buffer, make_float4(L_sum.x, L_sum.y, L_sum.z, alpha));
+ if (kernel_data.film.pass_flag & PASSMASK(COMBINED)) {
+ kernel_write_pass_float4(buffer, make_float4(L_sum.x, L_sum.y, L_sum.z, alpha));
+ }
kernel_write_light_passes(kg, buffer, L);
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index d45ffe9c7df..55abe39c465 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -459,7 +459,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
throughput /= probability;
}
+# ifdef __DENOISING_FEATURES__
kernel_update_denoising_features(kg, sd, state, L);
+# endif
# ifdef __AO__
/* ambient occlusion */
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 7aef34b00a2..1e5534b0c17 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -925,7 +925,8 @@ enum ShaderDataObjectFlag {
SD_OBJECT_HAS_VOLUME_ATTRIBUTES)
};
-typedef ccl_addr_space struct ShaderData {
+typedef ccl_addr_space struct ccl_align(16) ShaderData
+{
/* position */
float3 P;
/* smooth normal for shading */
@@ -1010,11 +1011,16 @@ typedef ccl_addr_space struct ShaderData {
/* At the end so we can adjust size in ShaderDataTinyStorage. */
struct ShaderClosure closure[MAX_CLOSURE];
-} ShaderData;
+}
+ShaderData;
-typedef ccl_addr_space struct ShaderDataTinyStorage {
+/* ShaderDataTinyStorage needs the same alignment as ShaderData, or else
+ * the pointer cast in AS_SHADER_DATA invokes undefined behavior. */
+typedef ccl_addr_space struct ccl_align(16) ShaderDataTinyStorage
+{
char pad[sizeof(ShaderData) - sizeof(ShaderClosure) * MAX_CLOSURE];
-} ShaderDataTinyStorage;
+}
+ShaderDataTinyStorage;
#define AS_SHADER_DATA(shader_data_tiny_storage) ((ShaderData *)shader_data_tiny_storage)
/* Path State */
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 2698ed59e64..1b161fbc8ee 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -483,11 +483,11 @@ static bool set_attribute_float3(float3 f, TypeDesc type, bool derivatives, void
return set_attribute_float3(fv, type, derivatives, val);
}
-/* Attributes with the TypeRGBA type descriptor should be retrived and stored
+/* Attributes with the TypeRGBA type descriptor should be retrieved and stored
* in a float array of size 4 (e.g. node_vertex_color.osl), this array have
* a type descriptor TypeFloatArray4. If the storage is not a TypeFloatArray4,
* we either store the first three components in a vector, store the average of
- * the components in a float, or fail the retrival and do nothing. We allow
+ * the components in a float, or fail the retrieval and do nothing. We allow
* this for the correct operation of the Attribute node.
*/
diff --git a/intern/cycles/kernel/shaders/node_mix.osl b/intern/cycles/kernel/shaders/node_mix.osl
index 8caea6803ed..9fbd3391ade 100644
--- a/intern/cycles/kernel/shaders/node_mix.osl
+++ b/intern/cycles/kernel/shaders/node_mix.osl
@@ -91,12 +91,12 @@ color node_mix_diff(float t, color col1, color col2)
color node_mix_dark(float t, color col1, color col2)
{
- return min(col1, col2) * t + col1 * (1.0 - t);
+ return mix(col1, min(col1, col2), t);
}
color node_mix_light(float t, color col1, color col2)
{
- return max(col1, col2 * t);
+ return mix(col1, max(col1, col2), t);
}
color node_mix_dodge(float t, color col1, color col2)
diff --git a/intern/cycles/kernel/svm/svm_color_util.h b/intern/cycles/kernel/svm/svm_color_util.h
index 3a6a5ba782f..1a0fa03305e 100644
--- a/intern/cycles/kernel/svm/svm_color_util.h
+++ b/intern/cycles/kernel/svm/svm_color_util.h
@@ -92,12 +92,12 @@ ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2)
ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2)
{
- return min(col1, col2) * t + col1 * (1.0f - t);
+ return interp(col1, min(col1, col2), t);
}
ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2)
{
- return max(col1, col2 * t);
+ return interp(col1, max(col1, col2), t);
}
ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2)
@@ -255,13 +255,7 @@ ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2)
ccl_device float3 svm_mix_clamp(float3 col)
{
- float3 outcol = col;
-
- outcol.x = saturate(col.x);
- outcol.y = saturate(col.y);
- outcol.z = saturate(col.z);
-
- return outcol;
+ return saturate3(col);
}
ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h
index b67c1e9cb7e..a16b226d8de 100644
--- a/intern/cycles/kernel/svm/svm_noise.h
+++ b/intern/cycles/kernel/svm/svm_noise.h
@@ -313,7 +313,7 @@ ccl_device_inline ssef bi_mix(ssef p, ssef f)
* (s2, s3) is generated by moving v2 and v3 to the first and second
* places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and
* fourth values are unused.
- * 3. Interplate g0 and g1 along the z axis to get the final value.
+ * 3. Interpolate g0 and g1 along the z axis to get the final value.
* g1 is generated by populating an ssef with the second value of g.
* Only the first value is important in the final ssef.
*
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index ad3827df7e3..49e15d9eaf1 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -43,8 +43,6 @@ BufferParams::BufferParams()
denoising_data_pass = false;
denoising_clean_pass = false;
denoising_prefiltered_pass = false;
-
- Pass::add(PASS_COMBINED, passes);
}
void BufferParams::get_offset_stride(int &offset, int &stride)
diff --git a/intern/cycles/render/denoising.cpp b/intern/cycles/render/denoising.cpp
index 39bd8ce00c2..4d819d1119e 100644
--- a/intern/cycles/render/denoising.cpp
+++ b/intern/cycles/render/denoising.cpp
@@ -866,8 +866,10 @@ Denoiser::Denoiser(DeviceInfo &device_info)
TaskScheduler::init();
/* Initialize device. */
- DeviceRequestedFeatures req;
device = Device::create(device_info, stats, profiler, true);
+
+ DeviceRequestedFeatures req;
+ req.use_denoising = true;
device->load_kernels(req);
}
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 5bf7ba97515..7f5bec2a66e 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -293,8 +293,6 @@ NODE_DEFINE(Film)
Film::Film() : Node(node_type)
{
- Pass::add(PASS_COMBINED, passes);
-
use_light_visibility = false;
filter_table_offset = TABLE_OFFSET_INVALID;
cryptomatte_passes = CRYPT_NONE;
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 71f1863ea49..b58e10a7b52 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -5567,11 +5567,21 @@ void MapRangeNode::expand(ShaderGraph *graph)
ShaderOutput *result_out = output("Result");
if (!result_out->links.empty()) {
ClampNode *clamp_node = new ClampNode();
- clamp_node->min = to_min;
- clamp_node->max = to_max;
graph->add(clamp_node);
graph->relink(result_out, clamp_node->output("Result"));
graph->connect(result_out, clamp_node->input("Value"));
+ if (input("To Min")->link) {
+ graph->connect(input("To Min")->link, clamp_node->input("Min"));
+ }
+ else {
+ clamp_node->min = to_min;
+ }
+ if (input("To Max")->link) {
+ graph->connect(input("To Max")->link, clamp_node->input("Max"));
+ }
+ else {
+ clamp_node->max = to_max;
+ }
}
}
}
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index ec85e516832..00d9cd5e672 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -703,6 +703,8 @@ void ShaderManager::get_requested_features(Scene *scene,
requested_features->nodes_features |= NODE_FEATURE_BUMP;
if (shader->displacement_method == DISPLACE_BOTH) {
requested_features->nodes_features |= NODE_FEATURE_BUMP_STATE;
+ requested_features->max_nodes_group = max(requested_features->max_nodes_group,
+ NODE_GROUP_LEVEL_1);
}
}
/* On top of volume nodes, also check if we need volume sampling because
diff --git a/intern/cycles/util/util_defines.h b/intern/cycles/util/util_defines.h
index 2778cffba3a..b29d4163133 100644
--- a/intern/cycles/util/util_defines.h
+++ b/intern/cycles/util/util_defines.h
@@ -16,127 +16,127 @@
*/
#ifndef __UTIL_DEFINES_H__
-# define __UTIL_DEFINES_H__
+#define __UTIL_DEFINES_H__
/* Bitness */
-# if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || \
- defined(_M_X64)
-# define __KERNEL_64_BIT__
-# endif
+#if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || \
+ defined(_M_X64)
+# define __KERNEL_64_BIT__
+#endif
/* Qualifiers for kernel code shared by CPU and GPU */
-# ifndef __KERNEL_GPU__
-# define ccl_device static inline
-# define ccl_device_noinline static
-# define ccl_device_noinline_cpu ccl_device_noinline
-# define ccl_global
-# define ccl_static_constant static const
-# define ccl_constant const
-# define ccl_local
-# define ccl_local_param
-# define ccl_private
-# define ccl_restrict __restrict
-# define ccl_ref &
-# define ccl_optional_struct_init
-# define __KERNEL_WITH_SSE_ALIGN__
-
-# if defined(_WIN32) && !defined(FREE_WINDOWS)
-# define ccl_device_inline static __forceinline
-# define ccl_device_forceinline static __forceinline
-# define ccl_align(...) __declspec(align(__VA_ARGS__))
-# ifdef __KERNEL_64_BIT__
-# define ccl_try_align(...) __declspec(align(__VA_ARGS__))
-# else /* __KERNEL_64_BIT__ */
-# undef __KERNEL_WITH_SSE_ALIGN__
+#ifndef __KERNEL_GPU__
+# define ccl_device static inline
+# define ccl_device_noinline static
+# define ccl_device_noinline_cpu ccl_device_noinline
+# define ccl_global
+# define ccl_static_constant static const
+# define ccl_constant const
+# define ccl_local
+# define ccl_local_param
+# define ccl_private
+# define ccl_restrict __restrict
+# define ccl_ref &
+# define ccl_optional_struct_init
+# define __KERNEL_WITH_SSE_ALIGN__
+
+# if defined(_WIN32) && !defined(FREE_WINDOWS)
+# define ccl_device_inline static __forceinline
+# define ccl_device_forceinline static __forceinline
+# define ccl_align(...) __declspec(align(__VA_ARGS__))
+# ifdef __KERNEL_64_BIT__
+# define ccl_try_align(...) __declspec(align(__VA_ARGS__))
+# else /* __KERNEL_64_BIT__ */
+# undef __KERNEL_WITH_SSE_ALIGN__
/* No support for function arguments (error C2719). */
-# define ccl_try_align(...)
-# endif /* __KERNEL_64_BIT__ */
-# define ccl_may_alias
-# define ccl_always_inline __forceinline
-# define ccl_never_inline __declspec(noinline)
-# define ccl_maybe_unused
-# else /* _WIN32 && !FREE_WINDOWS */
-# define ccl_device_inline static inline __attribute__((always_inline))
-# define ccl_device_forceinline static inline __attribute__((always_inline))
-# define ccl_align(...) __attribute__((aligned(__VA_ARGS__)))
-# ifndef FREE_WINDOWS64
-# define __forceinline inline __attribute__((always_inline))
-# endif
-# define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__)))
-# define ccl_may_alias __attribute__((__may_alias__))
-# define ccl_always_inline __attribute__((always_inline))
-# define ccl_never_inline __attribute__((noinline))
-# define ccl_maybe_unused __attribute__((used))
-# endif /* _WIN32 && !FREE_WINDOWS */
+# define ccl_try_align(...)
+# endif /* __KERNEL_64_BIT__ */
+# define ccl_may_alias
+# define ccl_always_inline __forceinline
+# define ccl_never_inline __declspec(noinline)
+# define ccl_maybe_unused
+# else /* _WIN32 && !FREE_WINDOWS */
+# define ccl_device_inline static inline __attribute__((always_inline))
+# define ccl_device_forceinline static inline __attribute__((always_inline))
+# define ccl_align(...) __attribute__((aligned(__VA_ARGS__)))
+# ifndef FREE_WINDOWS64
+# define __forceinline inline __attribute__((always_inline))
+# endif
+# define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__)))
+# define ccl_may_alias __attribute__((__may_alias__))
+# define ccl_always_inline __attribute__((always_inline))
+# define ccl_never_inline __attribute__((noinline))
+# define ccl_maybe_unused __attribute__((used))
+# endif /* _WIN32 && !FREE_WINDOWS */
/* Use to suppress '-Wimplicit-fallthrough' (in place of 'break'). */
-# ifndef ATTR_FALLTHROUGH
-# if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */
-# define ATTR_FALLTHROUGH __attribute__((fallthrough))
-# else
-# define ATTR_FALLTHROUGH ((void)0)
-# endif
+# ifndef ATTR_FALLTHROUGH
+# if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */
+# define ATTR_FALLTHROUGH __attribute__((fallthrough))
+# else
+# define ATTR_FALLTHROUGH ((void)0)
# endif
-# endif /* __KERNEL_GPU__ */
+# endif
+#endif /* __KERNEL_GPU__ */
/* macros */
/* hints for branch prediction, only use in code that runs a _lot_ */
-# if defined(__GNUC__) && defined(__KERNEL_CPU__)
-# define LIKELY(x) __builtin_expect(!!(x), 1)
-# define UNLIKELY(x) __builtin_expect(!!(x), 0)
-# else
-# define LIKELY(x) (x)
-# define UNLIKELY(x) (x)
-# endif
-
-# if defined(__GNUC__) || defined(__clang__)
-# if defined(__cplusplus)
+#if defined(__GNUC__) && defined(__KERNEL_CPU__)
+# define LIKELY(x) __builtin_expect(!!(x), 1)
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+# define LIKELY(x) (x)
+# define UNLIKELY(x) (x)
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+# if defined(__cplusplus)
/* Some magic to be sure we don't have reference in the type. */
template<typename T> static inline T decltype_helper(T x)
{
return x;
}
-# define TYPEOF(x) decltype(decltype_helper(x))
-# else
-# define TYPEOF(x) typeof(x)
-# endif
+# define TYPEOF(x) decltype(decltype_helper(x))
+# else
+# define TYPEOF(x) typeof(x)
# endif
+#endif
/* Causes warning:
* incompatible types when assigning to type 'Foo' from type 'Bar'
* ... the compiler optimizes away the temp var */
-# ifdef __GNUC__
-# define CHECK_TYPE(var, type) \
- { \
- TYPEOF(var) * __tmp; \
- __tmp = (type *)NULL; \
- (void)__tmp; \
- } \
- (void)0
-
-# define CHECK_TYPE_PAIR(var_a, var_b) \
- { \
- TYPEOF(var_a) * __tmp; \
- __tmp = (typeof(var_b) *)NULL; \
- (void)__tmp; \
- } \
- (void)0
-# else
-# define CHECK_TYPE(var, type)
-# define CHECK_TYPE_PAIR(var_a, var_b)
-# endif
+#ifdef __GNUC__
+# define CHECK_TYPE(var, type) \
+ { \
+ TYPEOF(var) * __tmp; \
+ __tmp = (type *)NULL; \
+ (void)__tmp; \
+ } \
+ (void)0
+
+# define CHECK_TYPE_PAIR(var_a, var_b) \
+ { \
+ TYPEOF(var_a) * __tmp; \
+ __tmp = (typeof(var_b) *)NULL; \
+ (void)__tmp; \
+ } \
+ (void)0
+#else
+# define CHECK_TYPE(var, type)
+# define CHECK_TYPE_PAIR(var_a, var_b)
+#endif
/* can be used in simple macros */
-# define CHECK_TYPE_INLINE(val, type) ((void)(((type)0) != (val)))
-
-# ifndef __KERNEL_GPU__
-# include <cassert>
-# define util_assert(statement) assert(statement)
-# else
-# define util_assert(statement)
-# endif
+#define CHECK_TYPE_INLINE(val, type) ((void)(((type)0) != (val)))
+
+#ifndef __KERNEL_GPU__
+# include <cassert>
+# define util_assert(statement) assert(statement)
+#else
+# define util_assert(statement)
+#endif
#endif /* __UTIL_DEFINES_H__ */
diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h
index 53140e40fc9..ca48758efcd 100644
--- a/intern/cycles/util/util_hash.h
+++ b/intern/cycles/util/util_hash.h
@@ -47,7 +47,8 @@ CCL_NAMESPACE_BEGIN
c -= b; \
c ^= rot(b, 4); \
b += a; \
- }
+ } \
+ ((void)0)
#define final(a, b, c) \
{ \
@@ -65,7 +66,8 @@ CCL_NAMESPACE_BEGIN
b -= rot(a, 14); \
c ^= b; \
c -= rot(b, 24); \
- }
+ } \
+ ((void)0)
ccl_device_inline uint hash_uint(uint kx)
{
diff --git a/intern/cycles/util/util_static_assert.h b/intern/cycles/util/util_static_assert.h
index b4b972a4036..ceb52830319 100644
--- a/intern/cycles/util/util_static_assert.h
+++ b/intern/cycles/util/util_static_assert.h
@@ -15,18 +15,18 @@
*/
#ifndef __UTIL_STATIC_ASSERT_H__
-# define __UTIL_STATIC_ASSERT_H__
+#define __UTIL_STATIC_ASSERT_H__
CCL_NAMESPACE_BEGIN
/* TODO(sergey): In theory CUDA might work with own static assert
* implementation since it's just pure C++.
*/
-# ifdef __KERNEL_GPU__
-# ifndef static_assert
-# define static_assert(statement, message)
-# endif
-# endif /* __KERNEL_GPU__ */
+#ifdef __KERNEL_GPU__
+# ifndef static_assert
+# define static_assert(statement, message)
+# endif
+#endif /* __KERNEL_GPU__ */
/* TODO(sergey): For until C++11 is a bare minimum for us,
* we do a bit of a trickery to show meaningful message so
@@ -42,8 +42,8 @@ CCL_NAMESPACE_BEGIN
* After C++11 bump it should be possible to glue structure
* name to the error message,
*/
-# define static_assert_align(st, align) \
- static_assert((sizeof(st) % (align) == 0), "Structure must be strictly aligned") // NOLINT
+#define static_assert_align(st, align) \
+ static_assert((sizeof(st) % (align) == 0), "Structure must be strictly aligned") // NOLINT
CCL_NAMESPACE_END
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h
index d254fa76ba9..123e18430a9 100644
--- a/intern/ffmpeg/ffmpeg_compat.h
+++ b/intern/ffmpeg/ffmpeg_compat.h
@@ -528,35 +528,21 @@ bool av_check_encoded_with_ffmpeg(AVFormatContext *ctx)
return false;
}
-FFMPEG_INLINE
-AVRational av_get_r_frame_rate_compat(AVFormatContext *ctx, const AVStream *stream)
+/* Libav doesn't have av_guess_frame_rate().
+ * It was introduced in FFmpeg's lavf 55.1.100. */
+#ifdef AV_USING_LIBAV
+AVRational av_guess_frame_rate(AVFormatContext *ctx, AVStream *stream, AVFrame *frame)
{
- /* If the video is encoded with FFmpeg and we are decoding with FFmpeg
- * as well it seems to be more reliable to use r_frame_rate (tbr).
- *
- * For other cases we fall back to avg_frame_rate (fps) when possible.
- */
-#ifdef AV_USING_FFMPEG
- if (av_check_encoded_with_ffmpeg(ctx)) {
- return stream->r_frame_rate;
- }
-#endif
-
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 23, 1)
- /* For until r_frame_rate was deprecated use it. */
+ (void)ctx;
+ (void)frame;
+# if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 23, 1)
+ /* For until r_frame_rate was deprecated (in Libav) use it. */
return stream->r_frame_rate;
-#else
-# ifdef AV_USING_FFMPEG
- /* Some of the videos might have average frame rate set to, while the
- * r_frame_rate will show a correct value. This happens, for example, for
- * OGG video files saved with Blender. */
- if (stream->avg_frame_rate.den == 0) {
- return stream->r_frame_rate;
- }
-# endif
+# else
return stream->avg_frame_rate;
-#endif
+# endif
}
+#endif
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 32, 0)
# define AV_OPT_SEARCH_FAKE_OBJ 0
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 9c6a0861280..720929ce945 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -66,6 +66,25 @@ extern GHOST_SystemHandle GHOST_CreateSystem(void);
extern GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle);
/**
+ * Show a system message box to the user
+ * \param systemhandle The handle to the system
+ * \param title Title of the message box
+ * \param message Message of the message box
+ * \param help_label Text to show on the help button that opens a link
+ * \param continue_label Text to show on the ok button that continues
+ * \param link Optional (hyper)link to a webpage to show when pressing help
+ * \param dialog_options Options to configure the message box.
+ * \return void.
+ */
+extern void GHOST_ShowMessageBox(GHOST_SystemHandle systemhandle,
+ const char *title,
+ const char *message,
+ const char *help_label,
+ const char *continue_label,
+ const char *link,
+ GHOST_DialogOptions dialog_options);
+
+/**
* Creates an event consumer object
* \param eventCallback The event callback routine.
* \param userdata Pointer to user data returned to the callback routine.
@@ -176,10 +195,22 @@ extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings);
+extern GHOST_WindowHandle GHOST_CreateDialogWindow(GHOST_SystemHandle systemhandle,
+ GHOST_WindowHandle parent_windowhandle,
+ const char *title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type,
+ GHOST_GLSettings glSettings);
+
/**
* Create a new offscreen context.
* Never explicitly delete the context, use disposeContext() instead.
* \param systemhandle The handle to the system
+ * \param platform_support_callback An optional callback to check platform support
* \return A handle to the new context ( == NULL if creation failed).
*/
extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle);
@@ -207,6 +238,8 @@ extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandl
*/
extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata);
+extern int GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle);
+
/**
* Dispose a window.
* \param systemhandle The handle to the system
@@ -316,7 +349,8 @@ extern GHOST_TSuccess GHOST_EndProgressBar(GHOST_WindowHandle windowhandle);
extern GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle);
/**
- * Set the shape of the cursor.
+ * Set the shape of the cursor. If the shape is not supported by the platform,
+ * it will use the default cursor instead.
* \param windowhandle The handle to the window
* \param cursorshape The new cursor shape type id.
* \return Indication of success.
@@ -325,6 +359,13 @@ extern GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle,
GHOST_TStandardCursor cursorshape);
/**
+ * Test if the standard cursor shape is supported by current platform.
+ * \return Indication of success.
+ */
+extern GHOST_TSuccess GHOST_HasCursorShape(GHOST_WindowHandle windowhandle,
+ GHOST_TStandardCursor cursorshape);
+
+/**
* Set the shape of the cursor to a custom cursor of specified size.
* \param windowhandle The handle to the window
* \param bitmap The bitmap data for the cursor.
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 27be80a2f20..b781de266bc 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -235,7 +235,8 @@ class GHOST_ISystem {
* \param state: The state of the window when opened.
* \param type: The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
- * \param exclusive: Use to show the window on top and ignore others (used fullscreen).
+ * \param exclusive: Use to show the window on top and ignore others (used full-screen).
+ * \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized.
* \param parentWindow: Parent (embedder) window
* \return The new window (or 0 if creation failed).
*/
@@ -248,7 +249,8 @@ class GHOST_ISystem {
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
- const GHOST_TEmbedderWindowID parentWindow = 0) = 0;
+ const bool is_dialog = false,
+ const GHOST_IWindow *parentWindow = NULL) = 0;
/**
* Dispose a window.
@@ -435,6 +437,27 @@ class GHOST_ISystem {
*/
virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0;
+ /***************************************************************************************
+ * System Message Box.
+ ***************************************************************************************/
+
+ /**
+ * Show a system message box
+ *
+ * \param title The title of the message box
+ * \param message The message to display
+ * \param help_label Help button label
+ * \param continue_label Continue button label
+ * \param link An optional hyperlink
+ * \param dialog_options Options how to display the message
+ */
+ virtual GHOST_TSuccess showMessageBox(const char * /*title*/,
+ const char * /*message*/,
+ const char * /*help_label*/,
+ const char * /*continue_label*/,
+ const char * /*link*/,
+ GHOST_DialogOptions /*dialog_options*/) const = 0;
+
protected:
/**
* Initialize the system.
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 1a1844bfe41..c19d4bdf6bd 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -241,6 +241,8 @@ class GHOST_IWindow {
*/
virtual void setUserData(const GHOST_TUserDataPtr userData) = 0;
+ virtual bool isDialog() const = 0;
+
/**
* Returns the tablet data (pressure etc).
* \return The tablet data (pressure etc).
@@ -280,6 +282,12 @@ class GHOST_IWindow {
virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) = 0;
/**
+ * Test if the standard cursor shape is supported by current platform.
+ * \return Indication of success.
+ */
+ virtual GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) = 0;
+
+ /**
* Set the shape of the cursor to a custom cursor.
* \param bitmap The bitmap data for the cursor.
* \param mask The mask data for the cursor.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 68516c3ecf8..32472373b17 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -58,6 +58,11 @@ typedef enum {
GHOST_glAlphaBackground = (1 << 2),
} GHOST_GLFlags;
+typedef enum GHOST_DialogOptions {
+ GHOST_DialogWarning = (1 << 0),
+ GHOST_DialogError = (1 << 1),
+} GHOST_DialogOptions;
+
#ifdef _MSC_VER
typedef __int64 GHOST_TInt64;
typedef unsigned __int64 GHOST_TUns64;
@@ -197,11 +202,27 @@ typedef enum {
GHOST_kStandardCursorInfo,
GHOST_kStandardCursorDestroy,
GHOST_kStandardCursorHelp,
- GHOST_kStandardCursorCycle,
- GHOST_kStandardCursorSpray,
GHOST_kStandardCursorWait,
GHOST_kStandardCursorText,
GHOST_kStandardCursorCrosshair,
+ GHOST_kStandardCursorCrosshairA,
+ GHOST_kStandardCursorCrosshairB,
+ GHOST_kStandardCursorCrosshairC,
+ GHOST_kStandardCursorPencil,
+ GHOST_kStandardCursorUpArrow,
+ GHOST_kStandardCursorDownArrow,
+ GHOST_kStandardCursorVerticalSplit,
+ GHOST_kStandardCursorHorizontalSplit,
+ GHOST_kStandardCursorEraser,
+ GHOST_kStandardCursorKnife,
+ GHOST_kStandardCursorEyedropper,
+ GHOST_kStandardCursorZoomIn,
+ GHOST_kStandardCursorZoomOut,
+ GHOST_kStandardCursorMove,
+ GHOST_kStandardCursorNSEWScroll,
+ GHOST_kStandardCursorNSScroll,
+ GHOST_kStandardCursorEWScroll,
+ GHOST_kStandardCursorStop,
GHOST_kStandardCursorUpDown,
GHOST_kStandardCursorLeftRight,
GHOST_kStandardCursorTopSide,
@@ -214,7 +235,6 @@ typedef enum {
GHOST_kStandardCursorBottomLeftCorner,
GHOST_kStandardCursorCopy,
GHOST_kStandardCursorCustom,
- GHOST_kStandardCursorPencil,
GHOST_kStandardCursorNumCursors
} GHOST_TStandardCursor;
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 78f171af7d1..eeb23ea7471 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -47,6 +47,18 @@ GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle)
return system->disposeSystem();
}
+void GHOST_ShowMessageBox(GHOST_SystemHandle systemhandle,
+ const char *title,
+ const char *message,
+ const char *help_label,
+ const char *continue_label,
+ const char *link,
+ GHOST_DialogOptions dialog_options)
+{
+ GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
+ system->showMessageBox(title, message, help_label, continue_label, link, dialog_options);
+}
+
GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback,
GHOST_TUserDataPtr userdata)
{
@@ -140,7 +152,33 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
return (GHOST_WindowHandle)system->createWindow(
- title, left, top, width, height, state, type, glSettings, false);
+ title, left, top, width, height, state, type, glSettings, false, false);
+}
+
+GHOST_WindowHandle GHOST_CreateDialogWindow(GHOST_SystemHandle systemhandle,
+ GHOST_WindowHandle parent_windowhandle,
+ const char *title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type,
+ GHOST_GLSettings glSettings)
+{
+ GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
+
+ return (GHOST_WindowHandle)system->createWindow(title,
+ left,
+ top,
+ width,
+ height,
+ state,
+ type,
+ glSettings,
+ false,
+ true,
+ (GHOST_IWindow *)parent_windowhandle);
}
GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle)
@@ -156,6 +194,13 @@ void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr
window->setUserData(userdata);
}
+int GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle)
+{
+ GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
+
+ return (int)window->isDialog();
+}
+
GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
GHOST_WindowHandle windowhandle)
{
@@ -264,6 +309,14 @@ GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle,
return window->setCursorShape(cursorshape);
}
+GHOST_TSuccess GHOST_HasCursorShape(GHOST_WindowHandle windowhandle,
+ GHOST_TStandardCursor cursorshape)
+{
+ GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
+
+ return window->hasCursorShape(cursorshape);
+}
+
GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle,
GHOST_TUns8 *bitmap,
GHOST_TUns8 *mask,
@@ -610,8 +663,13 @@ GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandl
GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
{
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
-
- return context->activateDrawingContext();
+ if (context) {
+ return context->activateDrawingContext();
+ }
+ else {
+ GHOST_PRINT("GHOST_ActivateOpenGLContext: Context not valid");
+ return GHOST_kFailure;
+ }
}
GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index fbf8af01e59..893592e3cf5 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -105,14 +105,6 @@ class GHOST_System : public GHOST_ISystem {
***************************************************************************************/
/**
- * Inherited from GHOST_ISystem but left pure virtual
- *
- * virtual GHOST_TUns8 getNumDisplays() const = 0;
- * virtual void getMainDisplayDimensions(...) const = 0;
- * virtual GHOST_IWindow* createWindow(..)
- */
-
- /**
* Dispose a window.
* \param window Pointer to the window to be disposed.
* \return Indication of success.
@@ -317,6 +309,25 @@ class GHOST_System : public GHOST_ISystem {
*/
virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0;
+ /**
+ * Show a system message box
+ * \param title The title of the message box
+ * \param message The message to display
+ * \param help_label Help button label
+ * \param continue_label Continue button label
+ * \param link An optional hyperlink
+ * \param dialog_options Options how to display the message
+ */
+ virtual GHOST_TSuccess showMessageBox(const char * /*title*/,
+ const char * /*message*/,
+ const char * /*help_label */,
+ const char * /*continue_label */,
+ const char * /*link*/,
+ GHOST_DialogOptions /*dialog_options*/) const
+ {
+ return GHOST_kFailure;
+ };
+
protected:
/**
* Initialize the system.
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index 109dd6c180d..1e44c3e31d4 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -109,7 +109,8 @@ class GHOST_SystemCocoa : public GHOST_System {
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
- const GHOST_TEmbedderWindowID parentWindow = 0);
+ const bool is_dialog = false,
+ const GHOST_IWindow *parentWindow = NULL);
/**
* Create a new offscreen context.
@@ -232,6 +233,11 @@ class GHOST_SystemCocoa : public GHOST_System {
GHOST_TSuccess handleApplicationBecomeActiveEvent();
/**
+ * \return True if any dialog window is open.
+ */
+ bool hasDialogWindow();
+
+ /**
* External objects should call this when they send an event outside processEvents.
*/
void notifyExternalEventProcessed();
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 376ebfa2a21..68bac7d153b 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -578,12 +578,13 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
menuItem = [appMenu addItemWithTitle:@"Hide Blender"
action:@selector(hide:)
keyEquivalent:@"h"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
menuItem = [appMenu addItemWithTitle:@"Hide others"
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"];
- [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
+ [menuItem
+ setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
[appMenu addItemWithTitle:@"Show All"
action:@selector(unhideAllApplications:)
@@ -592,7 +593,7 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
menuItem = [appMenu addItemWithTitle:@"Quit Blender"
action:@selector(terminate:)
keyEquivalent:@"q"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
menuItem = [[NSMenuItem alloc] init];
[menuItem setSubmenu:appMenu];
@@ -608,19 +609,20 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
menuItem = [windowMenu addItemWithTitle:@"Minimize"
action:@selector(performMiniaturize:)
keyEquivalent:@"m"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
[windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen"
action:@selector(toggleFullScreen:)
keyEquivalent:@"f"];
- [menuItem setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
+ [menuItem
+ setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
menuItem = [windowMenu addItemWithTitle:@"Close"
action:@selector(performClose:)
keyEquivalent:@"w"];
- [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
menuItem = [[NSMenuItem alloc] init];
[menuItem setSubmenu:windowMenu];
@@ -681,8 +683,8 @@ void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns
// Returns max window contents (excluding title bar...)
NSRect contentRect = [NSWindow
contentRectForFrameRect:frame
- styleMask:(NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask)];
+ styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable)];
width = contentRect.size.width;
height = contentRect.size.height;
@@ -705,7 +707,8 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
- const GHOST_TEmbedderWindowID parentWindow)
+ const bool is_dialog,
+ const GHOST_IWindow *parentWindow)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
GHOST_IWindow *window = NULL;
@@ -714,8 +717,8 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title,
NSRect frame = [[NSScreen mainScreen] visibleFrame];
NSRect contentRect = [NSWindow
contentRectForFrameRect:frame
- styleMask:(NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask)];
+ styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable)];
GHOST_TInt32 bottom = (contentRect.size.height - 1) - height - top;
@@ -733,7 +736,9 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title,
state,
type,
glSettings.flags & GHOST_glStereoVisual,
- glSettings.flags & GHOST_glDebugContext);
+ glSettings.flags & GHOST_glDebugContext,
+ is_dialog,
+ (GHOST_WindowCocoa *)parentWindow);
if (window->getValid()) {
// Store the pointer to the window
@@ -853,10 +858,12 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_T
GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys &keys) const
{
- keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSCommandKeyMask) ? true : false);
- keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSAlternateKeyMask) ? true : false);
- keys.set(GHOST_kModifierKeyLeftShift, (m_modifierMask & NSShiftKeyMask) ? true : false);
- keys.set(GHOST_kModifierKeyLeftControl, (m_modifierMask & NSControlKeyMask) ? true : false);
+ keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSEventModifierFlagCommand) ? true : false);
+ keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSEventModifierFlagOption) ? true : false);
+ keys.set(GHOST_kModifierKeyLeftShift,
+ (m_modifierMask & NSEventModifierFlagShift) ? true : false);
+ keys.set(GHOST_kModifierKeyLeftControl,
+ (m_modifierMask & NSEventModifierFlagControl) ? true : false);
return GHOST_kSuccess;
}
@@ -912,7 +919,7 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
#endif
do {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
@@ -931,16 +938,16 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
// get keyDown events delivered to the view because they are
// special hotkeys to switch between views, so override directly
- if ([event type] == NSKeyDown && [event keyCode] == kVK_Tab &&
- ([event modifierFlags] & NSControlKeyMask)) {
+ if ([event type] == NSEventTypeKeyDown && [event keyCode] == kVK_Tab &&
+ ([event modifierFlags] & NSEventModifierFlagControl)) {
handleKeyEvent(event);
}
else {
// For some reason NSApp is swallowing the key up events when modifier
// key is pressed, even if there seems to be no apparent reason to do
// so, as a workaround we always handle these up events.
- if ([event type] == NSKeyUp &&
- ([event modifierFlags] & (NSCommandKeyMask | NSAlternateKeyMask)))
+ if ([event type] == NSEventTypeKeyUp &&
+ ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagOption)))
handleKeyEvent(event);
[NSApp sendEvent:event];
@@ -968,6 +975,13 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
// Note: called from NSApplication delegate
GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
{
+ for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
+ GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow;
+ if (window->isDialog()) {
+ [window->getCocoaWindow() makeKeyAndOrderFront:nil];
+ }
+ }
+
// Update the modifiers key mask, as its status may have changed when the application
// was not active (that is when update events are sent to another application).
unsigned int modifiers;
@@ -982,31 +996,31 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
modifiers = [[[NSApplication sharedApplication] currentEvent] modifierFlags];
- if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
- pushEvent(
- new GHOST_EventKey(getMilliSeconds(),
- (modifiers & NSShiftKeyMask) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
- window,
- GHOST_kKeyLeftShift));
+ if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
+ pushEvent(new GHOST_EventKey(getMilliSeconds(),
+ (modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
+ window,
+ GHOST_kKeyLeftShift));
}
- if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) {
+ if ((modifiers & NSEventModifierFlagControl) != (m_modifierMask & NSEventModifierFlagControl)) {
pushEvent(new GHOST_EventKey(getMilliSeconds(),
- (modifiers & NSControlKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
+ (modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
window,
GHOST_kKeyLeftControl));
}
- if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) {
+ if ((modifiers & NSEventModifierFlagOption) != (m_modifierMask & NSEventModifierFlagOption)) {
pushEvent(new GHOST_EventKey(getMilliSeconds(),
- (modifiers & NSAlternateKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
+ (modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
window,
GHOST_kKeyLeftAlt));
}
- if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
+ if ((modifiers & NSEventModifierFlagCommand) != (m_modifierMask & NSEventModifierFlagCommand)) {
pushEvent(new GHOST_EventKey(getMilliSeconds(),
- (modifiers & NSCommandKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
+ (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
window,
GHOST_kKeyOS));
}
@@ -1017,6 +1031,17 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
return GHOST_kSuccess;
}
+bool GHOST_SystemCocoa::hasDialogWindow()
+{
+ for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
+ GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow;
+ if (window->isDialog()) {
+ return true;
+ }
+ }
+ return false;
+}
+
void GHOST_SystemCocoa::notifyExternalEventProcessed()
{
m_outsideLoopEventProcessed = true;
@@ -1413,7 +1438,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
GHOST_TabletData &ct = ((GHOST_WindowCocoa *)window)->GetCocoaTabletData();
switch (eventType) {
- case NSTabletPoint:
+ case NSEventTypeTabletPoint:
// workaround 2 cornercases:
// 1. if [event isEnteringProximity] was not triggered since program-start
// 2. device is not sending [event pointingDeviceType], due no eraser
@@ -1425,21 +1450,21 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
ct.Ytilt = [event tilt].y;
break;
- case NSTabletProximity:
+ case NSEventTypeTabletProximity:
ct.Pressure = 0;
ct.Xtilt = 0;
ct.Ytilt = 0;
if ([event isEnteringProximity]) {
// pointer is entering tablet area proximity
switch ([event pointingDeviceType]) {
- case NSPenPointingDevice:
+ case NSPointingDeviceTypePen:
ct.Active = GHOST_kTabletModeStylus;
break;
- case NSEraserPointingDevice:
+ case NSPointingDeviceTypeEraser:
ct.Active = GHOST_kTabletModeEraser;
break;
- case NSCursorPointingDevice:
- case NSUnknownPointingDevice:
+ case NSPointingDeviceTypeCursor:
+ case NSPointingDeviceTypeUnknown:
default:
ct.Active = GHOST_kTabletModeNone;
break;
@@ -1464,11 +1489,11 @@ bool GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
NSEvent *event = (NSEvent *)eventPtr;
switch ([event subtype]) {
- case NSTabletPointEventSubtype:
- handleTabletEvent(eventPtr, NSTabletPoint);
+ case NSEventSubtypeTabletPoint:
+ handleTabletEvent(eventPtr, NSEventTypeTabletPoint);
return true;
- case NSTabletProximityEventSubtype:
- handleTabletEvent(eventPtr, NSTabletProximity);
+ case NSEventSubtypeTabletProximity:
+ handleTabletEvent(eventPtr, NSEventTypeTabletProximity);
return true;
default:
// No tablet event included : do nothing
@@ -1498,17 +1523,17 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
cocoawindow = (CocoaWindow *)window->getOSWindow();
switch ([event type]) {
- case NSLeftMouseDown:
+ case NSEventTypeLeftMouseDown:
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft));
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSRightMouseDown:
+ case NSEventTypeRightMouseDown:
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight));
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSOtherMouseDown:
+ case NSEventTypeOtherMouseDown:
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonDown,
window,
@@ -1516,17 +1541,17 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSLeftMouseUp:
+ case NSEventTypeLeftMouseUp:
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft));
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSRightMouseUp:
+ case NSEventTypeRightMouseUp:
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight));
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSOtherMouseUp:
+ case NSEventTypeOtherMouseUp:
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonUp,
window,
@@ -1534,13 +1559,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged:
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeOtherMouseDragged:
// Handle tablet events combined with mouse events
handleTabletEvent(event);
- case NSMouseMoved: {
+ case NSEventTypeMouseMoved: {
GHOST_TGrabCursorMode grab_mode = window->getCursorGrabMode();
/* TODO: CHECK IF THIS IS A TABLET EVENT */
@@ -1628,7 +1653,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
}
} break;
- case NSScrollWheel: {
+ case NSEventTypeScrollWheel: {
NSEventPhase momentumPhase = NSEventPhaseNone;
NSEventPhase phase = NSEventPhaseNone;
@@ -1750,17 +1775,20 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
switch ([event type]) {
- case NSKeyDown:
- case NSKeyUp:
+ case NSEventTypeKeyDown:
+ case NSEventTypeKeyUp:
charsIgnoringModifiers = [event charactersIgnoringModifiers];
if ([charsIgnoringModifiers length] > 0) {
keyCode = convertKey([event keyCode],
[charsIgnoringModifiers characterAtIndex:0],
- [event type] == NSKeyDown ? kUCKeyActionDown : kUCKeyActionUp);
+ [event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
+ kUCKeyActionUp);
}
else {
- keyCode = convertKey(
- [event keyCode], 0, [event type] == NSKeyDown ? kUCKeyActionDown : kUCKeyActionUp);
+ keyCode = convertKey([event keyCode],
+ 0,
+ [event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
+ kUCKeyActionUp);
}
/* handling both unicode or ascii */
@@ -1782,10 +1810,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
utf8_buf[0] = '\0';
/* no text with command key pressed */
- if (m_modifierMask & NSCommandKeyMask)
+ if (m_modifierMask & NSEventModifierFlagCommand)
utf8_buf[0] = '\0';
- if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSCommandKeyMask))
+ if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSEventModifierFlagCommand))
break; // Cmd-Q is directly handled by Cocoa
/* ascii is a subset of unicode */
@@ -1793,7 +1821,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
ascii = utf8_buf[0];
}
- if ([event type] == NSKeyDown) {
+ if ([event type] == NSEventTypeKeyDown) {
pushEvent(new GHOST_EventKey(
[event timestamp] * 1000, GHOST_kEventKeyDown, window, keyCode, ascii, utf8_buf));
#if 0
@@ -1824,36 +1852,39 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
m_ignoreMomentumScroll = true;
break;
- case NSFlagsChanged:
+ case NSEventTypeFlagsChanged:
modifiers = [event modifierFlags];
- if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
+ if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
pushEvent(new GHOST_EventKey([event timestamp] * 1000,
- (modifiers & NSShiftKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
+ (modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
+ GHOST_kEventKeyUp,
window,
GHOST_kKeyLeftShift));
}
- if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) {
- pushEvent(new GHOST_EventKey([event timestamp] * 1000,
- (modifiers & NSControlKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
- window,
- GHOST_kKeyLeftControl));
+ if ((modifiers & NSEventModifierFlagControl) !=
+ (m_modifierMask & NSEventModifierFlagControl)) {
+ pushEvent(new GHOST_EventKey(
+ [event timestamp] * 1000,
+ (modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
+ window,
+ GHOST_kKeyLeftControl));
}
- if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) {
- pushEvent(new GHOST_EventKey([event timestamp] * 1000,
- (modifiers & NSAlternateKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
- window,
- GHOST_kKeyLeftAlt));
+ if ((modifiers & NSEventModifierFlagOption) !=
+ (m_modifierMask & NSEventModifierFlagOption)) {
+ pushEvent(new GHOST_EventKey(
+ [event timestamp] * 1000,
+ (modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
+ window,
+ GHOST_kKeyLeftAlt));
}
- if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
- pushEvent(new GHOST_EventKey([event timestamp] * 1000,
- (modifiers & NSCommandKeyMask) ? GHOST_kEventKeyDown :
- GHOST_kEventKeyUp,
- window,
- GHOST_kKeyOS));
+ if ((modifiers & NSEventModifierFlagCommand) !=
+ (m_modifierMask & NSEventModifierFlagCommand)) {
+ pushEvent(new GHOST_EventKey(
+ [event timestamp] * 1000,
+ (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
+ window,
+ GHOST_kKeyOS));
}
m_modifierMask = modifiers;
diff --git a/intern/ghost/intern/GHOST_SystemNULL.h b/intern/ghost/intern/GHOST_SystemNULL.h
index 93aea87e9a6..10138bfc6eb 100644
--- a/intern/ghost/intern/GHOST_SystemNULL.h
+++ b/intern/ghost/intern/GHOST_SystemNULL.h
@@ -114,8 +114,9 @@ class GHOST_SystemNULL : public GHOST_System {
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
- bool exclusive,
- const GHOST_TEmbedderWindowID parentWindow)
+ const bool exclusive,
+ const bool is_dialog,
+ const GHOST_IWindow *parentWindow)
{
return new GHOST_WindowNULL(this,
title,
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index 520c62719f8..e3f6f4b6bb1 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -58,6 +58,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const STR_String &title,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
+ const bool /* is_dialog */,
const GHOST_TEmbedderWindowID parentWindow)
{
GHOST_WindowSDL *window = NULL;
diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h
index 7dbdc3ccec8..942b6297c22 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.h
+++ b/intern/ghost/intern/GHOST_SystemSDL.h
@@ -89,6 +89,7 @@ class GHOST_SystemSDL : public GHOST_System {
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
+ const bool is_dialog = false,
const GHOST_TEmbedderWindowID parentWindow = 0);
/* SDL specific */
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 9073ed9944b..c86accf4ede 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -28,12 +28,21 @@
# define _WIN32_IE 0x0501 /* shipped before XP, so doesn't impose additional requirements */
#endif
+/* clang-format off */
+#pragma comment(linker,"\"/manifestdependency:type='win32' \
+name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
+processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
+/* clang-format on */
+
+#include <commctrl.h>
#include <shlobj.h>
#include <tlhelp32.h>
#include <psapi.h>
+#include <shellapi.h>
#include <windowsx.h>
#include "utfconv.h"
+#include "utf_winfunc.h"
#include "GHOST_DisplayManagerWin32.h"
#include "GHOST_EventButton.h"
@@ -266,7 +275,8 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const STR_String &title,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
- const GHOST_TEmbedderWindowID parentWindow)
+ const bool is_dialog,
+ const GHOST_IWindow *parentWindow)
{
GHOST_WindowWin32 *window = new GHOST_WindowWin32(
this,
@@ -279,8 +289,9 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const STR_String &title,
type,
((glSettings.flags & GHOST_glStereoVisual) != 0),
((glSettings.flags & GHOST_glAlphaBackground) != 0),
- parentWindow,
- ((glSettings.flags & GHOST_glDebugContext) != 0));
+ (GHOST_WindowWin32 *)parentWindow,
+ ((glSettings.flags & GHOST_glDebugContext) != 0),
+ is_dialog);
if (window->getValid()) {
// Store the pointer to the window
@@ -356,14 +367,8 @@ GHOST_IContext *GHOST_SystemWin32::createOffscreenContext()
goto finished;
}
else {
- MessageBox(NULL,
- "A graphics card and driver with support for OpenGL 3.3 or higher is required.\n"
- "Installing the latest driver for your graphics card may resolve the issue.\n\n"
- "The program will now close.",
- "Blender - Unsupported Graphics Card or Driver",
- MB_OK | MB_ICONERROR);
delete context;
- exit();
+ return NULL;
}
#elif defined(WITH_GL_PROFILE_COMPAT)
@@ -514,6 +519,7 @@ GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons &buttons) const
GHOST_TSuccess GHOST_SystemWin32::init()
{
GHOST_TSuccess success = GHOST_System::init();
+ InitCommonControls();
/* Disable scaling on high DPI displays on Vista */
HMODULE
@@ -1774,6 +1780,57 @@ void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const
}
}
+/** \name Message Box
+ * \{ */
+GHOST_TSuccess GHOST_SystemWin32::showMessageBox(const char *title,
+ const char *message,
+ const char *help_label,
+ const char *continue_label,
+ const char *link,
+ GHOST_DialogOptions dialog_options) const
+{
+ const wchar_t *title_16 = alloc_utf16_from_8(title, 0);
+ const wchar_t *message_16 = alloc_utf16_from_8(message, 0);
+ const wchar_t *help_label_16 = alloc_utf16_from_8(help_label, 0);
+ const wchar_t *continue_label_16 = alloc_utf16_from_8(continue_label, 0);
+
+ int nButtonPressed = 0;
+ TASKDIALOGCONFIG config = {0};
+ const TASKDIALOG_BUTTON buttons[] = {{IDOK, help_label_16}, {IDCONTINUE, continue_label_16}};
+
+ config.cbSize = sizeof(config);
+ config.hInstance = 0;
+ config.dwCommonButtons = 0;
+ config.pszMainIcon = (dialog_options & GHOST_DialogError ?
+ TD_ERROR_ICON :
+ dialog_options & GHOST_DialogWarning ? TD_WARNING_ICON :
+ TD_INFORMATION_ICON);
+ config.pszWindowTitle = L"Blender";
+ config.pszMainInstruction = title_16;
+ config.pszContent = message_16;
+ config.pButtons = (link) ? buttons : buttons + 1;
+ config.cButtons = (link) ? 2 : 1;
+
+ TaskDialogIndirect(&config, &nButtonPressed, NULL, NULL);
+ switch (nButtonPressed) {
+ case IDOK:
+ ShellExecute(NULL, "open", link, NULL, NULL, SW_SHOWNORMAL);
+ break;
+ case IDCONTINUE:
+ break;
+ default:
+ break; // should never happen
+ }
+
+ free((void *)title_16);
+ free((void *)message_16);
+ free((void *)help_label_16);
+ free((void *)continue_label_16);
+
+ return GHOST_kSuccess;
+}
+/* \} */
+
static DWORD GetParentProcessID(void)
{
HANDLE snapshot;
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 7ac6a3e3e20..b069e6cf3b6 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -29,10 +29,6 @@
# error WIN32 only!
#endif // WIN32
-/* require Windows XP or newer */
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x501
-
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ole2.h> // for drag-n-drop
@@ -112,7 +108,7 @@ class GHOST_SystemWin32 : public GHOST_System {
* \param type The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window ontop and ignore others (used fullscreen).
- * \param parentWindow Parent (embedder) window
+ * \param parentWindow Parent window
* \return The new window (or 0 if creation failed).
*/
GHOST_IWindow *createWindow(const STR_String &title,
@@ -124,7 +120,8 @@ class GHOST_SystemWin32 : public GHOST_System {
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
- const GHOST_TEmbedderWindowID parentWindow = 0);
+ const bool is_dialog = false,
+ const GHOST_IWindow *parentWindow = 0);
/**
* Create a new offscreen context.
@@ -204,6 +201,22 @@ class GHOST_SystemWin32 : public GHOST_System {
void putClipboard(GHOST_TInt8 *buffer, bool selection) const;
/**
+ * Show a system message box
+ * \param title The title of the message box
+ * \param message The message to display
+ * \param help_label Help button label
+ * \param continue_label Continue button label
+ * \param link An optional hyperlink
+ * \param dialog_options Options how to display the message
+ */
+ GHOST_TSuccess showMessageBox(const char *title,
+ const char *message,
+ const char *help_label,
+ const char *continue_label,
+ const char *link,
+ GHOST_DialogOptions dialog_options) const;
+
+ /**
* Creates a drag'n'drop event and pushes it immediately onto the event queue.
* Called by GHOST_DropTargetWin32 class.
* \param eventType: The type of drag'n'drop event
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index e46edeeac9a..1ca412fbccc 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -324,7 +324,7 @@ void GHOST_SystemX11::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32
* \param type The type of drawing context installed in this window.
* \param glSettings: Misc OpenGL settings.
* \param exclusive: Use to show the window ontop and ignore others (used fullscreen).
- * \param parentWindow Parent (embedder) window
+ * \param parentWindow Parent window
* \return The new window (or 0 if creation failed).
*/
GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title,
@@ -336,7 +336,8 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title,
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive,
- const GHOST_TEmbedderWindowID parentWindow)
+ const bool is_dialog,
+ const GHOST_IWindow *parentWindow)
{
GHOST_WindowX11 *window = NULL;
@@ -351,8 +352,9 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title,
width,
height,
state,
- parentWindow,
+ (GHOST_WindowX11 *)parentWindow,
type,
+ is_dialog,
((glSettings.flags & GHOST_glStereoVisual) != 0),
exclusive,
((glSettings.flags & GHOST_glAlphaBackground) != 0),
@@ -2143,6 +2145,222 @@ void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
}
}
+/** \name Message Box
+ * \{ */
+class DialogData {
+ public:
+ /* Width of the dialog */
+ uint width;
+ /* Heigth of the dialog */
+ uint height;
+ /* Default padding (x direction) between controls and edge of dialog */
+ uint padding_x;
+ /* Default padding (y direction) between controls and edge of dialog */
+ uint padding_y;
+ /* Width of a single button */
+ uint button_width;
+ /* Height of a single button */
+ uint button_height;
+ /* Inset of a button to its text */
+ uint button_inset_x;
+ /* Size of the border of the button */
+ uint button_border_size;
+ /* Height of a line of text */
+ uint line_height;
+ /* offset of the text inside the button */
+ uint button_text_offset_y;
+
+ /* Construct a new DialogData with the default settings */
+ DialogData()
+ : width(640),
+ height(175),
+ padding_x(10),
+ padding_y(5),
+ button_width(130),
+ button_height(24),
+ button_inset_x(10),
+ button_border_size(1),
+ line_height(16)
+ {
+ button_text_offset_y = button_height - line_height;
+ }
+
+ void drawButton(Display *display,
+ Window &window,
+ GC &borderGC,
+ GC &buttonGC,
+ uint button_num,
+ const char *label)
+ {
+ XFillRectangle(display,
+ window,
+ borderGC,
+ width - (padding_x + button_width) * button_num,
+ height - padding_y - button_height,
+ button_width,
+ button_height);
+
+ XFillRectangle(display,
+ window,
+ buttonGC,
+ width - (padding_x + button_width) * button_num + button_border_size,
+ height - padding_y - button_height + button_border_size,
+ button_width - button_border_size * 2,
+ button_height - button_border_size * 2);
+
+ XDrawString(display,
+ window,
+ borderGC,
+ width - (padding_x + button_width) * button_num + button_inset_x,
+ height - padding_y - button_text_offset_y,
+ label,
+ strlen(label));
+ }
+
+ /* Is the mouse inside the given button */
+ bool isInsideButton(XEvent &e, uint button_num)
+ {
+ return ((e.xmotion.y > height - padding_y - button_height) &&
+ (e.xmotion.y < height - padding_y) &&
+ (e.xmotion.x > width - (padding_x + button_width) * button_num) &&
+ (e.xmotion.x < width - padding_x - (padding_x + button_width) * (button_num - 1)));
+ }
+};
+
+static void split(const char *text, const char *seps, char ***str, int *count)
+{
+ char *tok, *data;
+ int i;
+ *count = 0;
+
+ data = strdup(text);
+ for (tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps))
+ (*count)++;
+ free(data);
+
+ data = strdup(text);
+ *str = (char **)malloc((size_t)(*count) * sizeof(char *));
+ for (i = 0, tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps), i++)
+ (*str)[i] = strdup(tok);
+ free(data);
+}
+
+GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
+ const char *message,
+ const char *help_label,
+ const char *continue_label,
+ const char *link,
+ GHOST_DialogOptions) const
+{
+ char **text_splitted = NULL;
+ int textLines = 0;
+ split(message, "\n", &text_splitted, &textLines);
+
+ DialogData dialog_data;
+ XSizeHints hints;
+
+ Window window;
+ XEvent e;
+ int screen = DefaultScreen(m_display);
+ window = XCreateSimpleWindow(m_display,
+ RootWindow(m_display, screen),
+ 0,
+ 0,
+ dialog_data.width,
+ dialog_data.height,
+ 1,
+ BlackPixel(m_display, screen),
+ WhitePixel(m_display, screen));
+
+ /* Window Should not be resizable */
+ {
+ hints.flags = PSize | PMinSize | PMaxSize;
+ hints.min_width = hints.max_width = hints.base_width = dialog_data.width;
+ hints.min_height = hints.max_height = hints.base_height = dialog_data.height;
+ XSetWMNormalHints(m_display, window, &hints);
+ }
+
+ /* Set title */
+ {
+ Atom wm_Name = XInternAtom(m_display, "_NET_WM_NAME", False);
+ Atom utf8Str = XInternAtom(m_display, "UTF8_STRING", False);
+
+ Atom winType = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE", False);
+ Atom typeDialog = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+
+ XChangeProperty(m_display,
+ window,
+ wm_Name,
+ utf8Str,
+ 8,
+ PropModeReplace,
+ (const unsigned char *)title,
+ (int)strlen(title));
+
+ XChangeProperty(
+ m_display, window, winType, XA_ATOM, 32, PropModeReplace, (unsigned char *)&typeDialog, 1);
+ }
+
+ /* Create buttons GC */
+ XGCValues buttonBorderGCValues;
+ buttonBorderGCValues.foreground = BlackPixel(m_display, screen);
+ buttonBorderGCValues.background = WhitePixel(m_display, screen);
+ XGCValues buttonGCValues;
+ buttonGCValues.foreground = WhitePixel(m_display, screen);
+ buttonGCValues.background = BlackPixel(m_display, screen);
+
+ GC buttonBorderGC = XCreateGC(m_display, window, GCForeground, &buttonBorderGCValues);
+ GC buttonGC = XCreateGC(m_display, window, GCForeground, &buttonGCValues);
+
+ XSelectInput(m_display, window, ExposureMask | ButtonPressMask | ButtonReleaseMask);
+ XMapWindow(m_display, window);
+
+ while (1) {
+ XNextEvent(m_display, &e);
+ if (e.type == Expose) {
+ for (int i = 0; i < textLines; i++) {
+ XDrawString(m_display,
+ window,
+ DefaultGC(m_display, screen),
+ dialog_data.padding_x,
+ dialog_data.padding_x + (i + 1) * dialog_data.line_height,
+ text_splitted[i],
+ (int)strlen(text_splitted[i]));
+ }
+ dialog_data.drawButton(m_display, window, buttonBorderGC, buttonGC, 1, continue_label);
+ if (strlen(link)) {
+ dialog_data.drawButton(m_display, window, buttonBorderGC, buttonGC, 2, help_label);
+ }
+ }
+ else if (e.type == ButtonRelease) {
+ if (dialog_data.isInsideButton(e, 1)) {
+ break;
+ }
+ else if (dialog_data.isInsideButton(e, 2)) {
+ if (strlen(link)) {
+ string cmd = "xdg-open \"" + string(link) + "\"";
+ if (system(cmd.c_str()) != 0) {
+ GHOST_PRINTF("GHOST_SystemX11::showMessageBox: Unable to run system command [%s]",
+ cmd);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < textLines; i++) {
+ free(text_splitted[i]);
+ }
+ free(text_splitted);
+
+ XDestroyWindow(m_display, window);
+ XFreeGC(m_display, buttonBorderGC);
+ XFreeGC(m_display, buttonGC);
+ return GHOST_kSuccess;
+}
+/* \} */
+
#ifdef WITH_XDND
GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
GHOST_TDragnDropTypes draggedObjectType,
@@ -2303,26 +2521,30 @@ void GHOST_SystemX11::refreshXInputDevices()
/* Find how many pressure levels tablet has */
XAnyClassPtr ici = device_info[i].inputclassinfo;
- for (int j = 0; j < xtablet.Device->num_classes; ++j) {
- if (ici->c_class == ValuatorClass) {
- XValuatorInfo *xvi = (XValuatorInfo *)ici;
- xtablet.PressureLevels = xvi->axes[2].max_value;
-
- if (xvi->num_axes > 3) {
- /* this is assuming that the tablet has the same tilt resolution in both
- * positive and negative directions. It would be rather weird if it didn't.. */
- xtablet.XtiltLevels = xvi->axes[3].max_value;
- xtablet.YtiltLevels = xvi->axes[4].max_value;
- }
- else {
- xtablet.XtiltLevels = 0;
- xtablet.YtiltLevels = 0;
+ if (ici != NULL) {
+ for (int j = 0; j < xtablet.Device->num_classes; ++j) {
+ if (ici->c_class == ValuatorClass) {
+ XValuatorInfo *xvi = (XValuatorInfo *)ici;
+ if (xvi->axes != NULL) {
+ xtablet.PressureLevels = xvi->axes[2].max_value;
+
+ if (xvi->num_axes > 3) {
+ /* this is assuming that the tablet has the same tilt resolution in both
+ * positive and negative directions. It would be rather weird if it didn't.. */
+ xtablet.XtiltLevels = xvi->axes[3].max_value;
+ xtablet.YtiltLevels = xvi->axes[4].max_value;
+ }
+ else {
+ xtablet.XtiltLevels = 0;
+ xtablet.YtiltLevels = 0;
+ }
+
+ break;
+ }
}
- break;
+ ici = (XAnyClassPtr)(((char *)ici) + ici->length);
}
-
- ici = (XAnyClassPtr)(((char *)ici) + ici->length);
}
m_xtablets.push_back(xtablet);
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index 1fe94b40f17..67dd0789ac3 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -146,7 +146,8 @@ class GHOST_SystemX11 : public GHOST_System {
GHOST_TDrawingContextType type,
GHOST_GLSettings glSettings,
const bool exclusive = false,
- const GHOST_TEmbedderWindowID parentWindow = 0);
+ const bool is_dialog = false,
+ const GHOST_IWindow *parentWindow = 0);
/**
* Create a new offscreen context.
@@ -232,6 +233,21 @@ class GHOST_SystemX11 : public GHOST_System {
*/
void putClipboard(GHOST_TInt8 *buffer, bool selection) const;
+ /**
+ * Show a system message box
+ * \param title The title of the message box
+ * \param message The message to display
+ * \param help_label Help button label
+ * \param continue_label Continue button label
+ * \param link An optional hyperlink
+ * \param dialog_options Options how to display the message
+ */
+ GHOST_TSuccess showMessageBox(const char *title,
+ const char *message,
+ const char *help_label,
+ const char *continue_label,
+ const char *link,
+ GHOST_DialogOptions dialog_options) const;
#ifdef WITH_XDND
/**
* Creates a drag'n'drop event and pushes it immediately onto the event queue.
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 5f9e8ffdd5e..553a7d89df4 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -109,6 +109,11 @@ class GHOST_Window : public GHOST_IWindow {
*/
inline GHOST_TStandardCursor getCursorShape() const;
+ inline bool isDialog() const
+ {
+ return false;
+ }
+
/**
* Set the shape of the cursor.
* \param cursorShape: The new cursor shape type id.
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index 5e857c05a09..d260d0eacbc 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -66,7 +66,9 @@ class GHOST_WindowCocoa : public GHOST_Window {
GHOST_TWindowState state,
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
const bool stereoVisual = false,
- bool is_debug = false);
+ bool is_debug = false,
+ bool dialog = false,
+ GHOST_WindowCocoa *parentWindow = 0);
/**
* Destructor.
@@ -215,8 +217,11 @@ class GHOST_WindowCocoa : public GHOST_Window {
*/
GHOST_TSuccess setOrder(GHOST_TWindowOrder order);
+ NSCursor *getStandardCursor(GHOST_TStandardCursor cursor) const;
void loadCursor(bool visible, GHOST_TStandardCursor cursor) const;
+ bool isDialog() const;
+
const GHOST_TabletData *GetTabletData()
{
return &m_tablet;
@@ -296,6 +301,7 @@ class GHOST_WindowCocoa : public GHOST_Window {
* native window system calls.
*/
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor shape);
/**
* Sets the cursor shape on the window using
@@ -326,6 +332,7 @@ class GHOST_WindowCocoa : public GHOST_Window {
bool m_immediateDraw;
bool m_debug_context; // for debug messages during context setup
+ bool m_is_dialog;
};
#endif // __GHOST_WINDOWCOCOA_H__
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index cb4100c1188..1d89da90a32 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -166,7 +166,8 @@
- (BOOL)canBecomeKeyWindow
{
- return YES;
+ /* Don't make other windows active when a dialog window is open. */
+ return (associatedWindow->isDialog() || !systemCocoa->hasDialogWindow());
}
//The drag'n'drop dragging destination methods
@@ -290,7 +291,9 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
const bool stereoVisual,
- bool is_debug)
+ bool is_debug,
+ bool is_dialog,
+ GHOST_WindowCocoa *parentWindow)
: GHOST_Window(width, height, state, stereoVisual, false),
m_openGLView(nil),
m_metalView(nil),
@@ -298,7 +301,8 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
m_systemCocoa(systemCocoa),
m_customCursor(0),
m_immediateDraw(false),
- m_debug_context(is_debug)
+ m_debug_context(is_debug),
+ m_is_dialog(is_dialog)
{
m_fullScreen = false;
@@ -313,12 +317,16 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
rect.size.width = width;
rect.size.height = height;
- m_window = [[CocoaWindow alloc]
- initWithContentRect:rect
- styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask |
- NSMiniaturizableWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
+ NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskResizable;
+ if (!is_dialog) {
+ styleMask |= NSWindowStyleMaskMiniaturizable;
+ }
+
+ m_window = [[CocoaWindow alloc] initWithContentRect:rect
+ styleMask:styleMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
if (m_window == nil) {
[pool drain];
@@ -402,6 +410,10 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
if (state == GHOST_kWindowStateFullScreen)
setState(GHOST_kWindowStateFullScreen);
+ if (is_dialog && parentWindow) {
+ [parentWindow->getCocoaWindow() addChildWindow:m_window ordered:NSWindowAbove];
+ }
+
setNativePixelSize();
[pool drain];
@@ -548,10 +560,8 @@ void GHOST_WindowCocoa::getClientBounds(GHOST_Rect &bounds) const
NSRect screenSize = [[m_window screen] visibleFrame];
// Max window contents as screen size (excluding title bar...)
- NSRect contentRect = [CocoaWindow
- contentRectForFrameRect:screenSize
- styleMask:(NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSResizableWindowMask)];
+ NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize
+ styleMask:[m_window styleMask]];
rect = [m_window contentRectForFrameRect:[m_window frame]];
@@ -619,7 +629,7 @@ GHOST_TWindowState GHOST_WindowCocoa::getState() const
NSUInteger masks = [m_window styleMask];
- if (masks & NSFullScreenWindowMask) {
+ if (masks & NSWindowStyleMaskFullScreen) {
// Lion style fullscreen
if (!m_immediateDraw) {
state = GHOST_kWindowStateFullScreen;
@@ -748,7 +758,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
case GHOST_kWindowStateFullScreen: {
NSUInteger masks = [m_window styleMask];
- if (!(masks & NSFullScreenWindowMask)) {
+ if (!(masks & NSWindowStyleMaskFullScreen)) {
[m_window toggleFullScreen:nil];
}
break;
@@ -758,7 +768,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSUInteger masks = [m_window styleMask];
- if (masks & NSFullScreenWindowMask) {
+ if (masks & NSWindowStyleMaskFullScreen) {
// Lion style fullscreen
[m_window toggleFullScreen:nil];
}
@@ -851,7 +861,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress)
[[NSImage imageNamed:@"NSApplicationIcon"] drawAtPoint:NSZeroPoint
fromRect:NSZeroRect
- operation:NSCompositeSourceOver
+ operation:NSCompositingOperationSourceOver
fraction:1.0];
// Track & Outline
@@ -904,7 +914,7 @@ GHOST_TSuccess GHOST_WindowCocoa::endProgressBar()
[dockIcon lockFocus];
[[NSImage imageNamed:@"NSApplicationIcon"] drawAtPoint:NSZeroPoint
fromRect:NSZeroRect
- operation:NSCompositeSourceOver
+ operation:NSCompositingOperationSourceOver
fraction:1.0];
[dockIcon unlockFocus];
[NSApp setApplicationIconImage:dockIcon];
@@ -925,12 +935,107 @@ GHOST_TSuccess GHOST_WindowCocoa::endProgressBar()
#pragma mark Cursor handling
-void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
+static NSCursor *getImageCursor(GHOST_TStandardCursor shape, NSString *name, NSPoint hotspot)
{
- static bool systemCursorVisible = true;
+ static NSCursor *cursors[(int)GHOST_kStandardCursorNumCursors] = {0};
+ static bool loaded[(int)GHOST_kStandardCursorNumCursors] = {false};
+
+ const int index = (int)shape;
+ if (!loaded[index]) {
+ /* Load image from file in application Resources folder. */
+ @autoreleasepool {
+ NSImage *image = [NSImage imageNamed:name];
+ if (image != NULL) {
+ cursors[index] = [[NSCursor alloc] initWithImage:image hotSpot:hotspot];
+ }
+ }
+
+ loaded[index] = true;
+ }
+
+ return cursors[index];
+}
- NSCursor *tmpCursor = nil;
+NSCursor *GHOST_WindowCocoa::getStandardCursor(GHOST_TStandardCursor shape) const
+{
+ switch (shape) {
+ case GHOST_kStandardCursorCustom:
+ if (m_customCursor) {
+ return m_customCursor;
+ }
+ else {
+ return NULL;
+ }
+ case GHOST_kStandardCursorDestroy:
+ return [NSCursor disappearingItemCursor];
+ case GHOST_kStandardCursorText:
+ return [NSCursor IBeamCursor];
+ case GHOST_kStandardCursorCrosshair:
+ return [NSCursor crosshairCursor];
+ case GHOST_kStandardCursorUpDown:
+ return [NSCursor resizeUpDownCursor];
+ case GHOST_kStandardCursorLeftRight:
+ return [NSCursor resizeLeftRightCursor];
+ case GHOST_kStandardCursorTopSide:
+ return [NSCursor resizeUpCursor];
+ case GHOST_kStandardCursorBottomSide:
+ return [NSCursor resizeDownCursor];
+ case GHOST_kStandardCursorLeftSide:
+ return [NSCursor resizeLeftCursor];
+ case GHOST_kStandardCursorRightSide:
+ return [NSCursor resizeRightCursor];
+ case GHOST_kStandardCursorCopy:
+ return [NSCursor dragCopyCursor];
+ case GHOST_kStandardCursorStop:
+ return [NSCursor operationNotAllowedCursor];
+ case GHOST_kStandardCursorMove:
+ return [NSCursor pointingHandCursor];
+ case GHOST_kStandardCursorDefault:
+ return [NSCursor arrowCursor];
+ case GHOST_kStandardCursorKnife:
+ return getImageCursor(shape, @"knife.pdf", NSMakePoint(6, 24));
+ case GHOST_kStandardCursorEraser:
+ return getImageCursor(shape, @"eraser.pdf", NSMakePoint(6, 24));
+ case GHOST_kStandardCursorPencil:
+ return getImageCursor(shape, @"pen.pdf", NSMakePoint(6, 24));
+ case GHOST_kStandardCursorEyedropper:
+ return getImageCursor(shape, @"eyedropper.pdf", NSMakePoint(6, 24));
+ case GHOST_kStandardCursorZoomIn:
+ return getImageCursor(shape, @"zoomin.pdf", NSMakePoint(8, 7));
+ case GHOST_kStandardCursorZoomOut:
+ return getImageCursor(shape, @"zoomout.pdf", NSMakePoint(8, 7));
+ case GHOST_kStandardCursorNSEWScroll:
+ return getImageCursor(shape, @"scrollnsew.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorNSScroll:
+ return getImageCursor(shape, @"scrollns.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorEWScroll:
+ return getImageCursor(shape, @"scrollew.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorUpArrow:
+ return getImageCursor(shape, @"arrowup.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorDownArrow:
+ return getImageCursor(shape, @"arrowdown.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorLeftArrow:
+ return getImageCursor(shape, @"arrowleft.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorRightArrow:
+ return getImageCursor(shape, @"arrowright.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorVerticalSplit:
+ return getImageCursor(shape, @"splitv.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorHorizontalSplit:
+ return getImageCursor(shape, @"splith.pdf", NSMakePoint(16, 16));
+ case GHOST_kStandardCursorCrosshairA:
+ return getImageCursor(shape, @"paint_cursor_cross.pdf", NSMakePoint(16, 15));
+ case GHOST_kStandardCursorCrosshairB:
+ return getImageCursor(shape, @"paint_cursor_dot.pdf", NSMakePoint(16, 15));
+ case GHOST_kStandardCursorCrosshairC:
+ return getImageCursor(shape, @"crossc.pdf", NSMakePoint(16, 16));
+ default:
+ return NULL;
+ }
+}
+void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor shape) const
+{
+ static bool systemCursorVisible = true;
if (visible != systemCursorVisible) {
if (visible) {
[NSCursor unhide];
@@ -942,57 +1047,17 @@ void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) c
}
}
- if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
- tmpCursor = m_customCursor;
+ NSCursor *cursor = getStandardCursor(shape);
+ if (cursor == NULL) {
+ cursor = getStandardCursor(GHOST_kStandardCursorDefault);
}
- else {
- switch (cursor) {
- case GHOST_kStandardCursorDestroy:
- tmpCursor = [NSCursor disappearingItemCursor];
- break;
- case GHOST_kStandardCursorText:
- tmpCursor = [NSCursor IBeamCursor];
- break;
- case GHOST_kStandardCursorCrosshair:
- tmpCursor = [NSCursor crosshairCursor];
- break;
- case GHOST_kStandardCursorUpDown:
- tmpCursor = [NSCursor resizeUpDownCursor];
- break;
- case GHOST_kStandardCursorLeftRight:
- tmpCursor = [NSCursor resizeLeftRightCursor];
- break;
- case GHOST_kStandardCursorTopSide:
- tmpCursor = [NSCursor resizeUpCursor];
- break;
- case GHOST_kStandardCursorBottomSide:
- tmpCursor = [NSCursor resizeDownCursor];
- break;
- case GHOST_kStandardCursorLeftSide:
- tmpCursor = [NSCursor resizeLeftCursor];
- break;
- case GHOST_kStandardCursorRightSide:
- tmpCursor = [NSCursor resizeRightCursor];
- break;
- case GHOST_kStandardCursorRightArrow:
- case GHOST_kStandardCursorInfo:
- case GHOST_kStandardCursorLeftArrow:
- case GHOST_kStandardCursorHelp:
- case GHOST_kStandardCursorCycle:
- case GHOST_kStandardCursorSpray:
- case GHOST_kStandardCursorWait:
- case GHOST_kStandardCursorTopLeftCorner:
- case GHOST_kStandardCursorTopRightCorner:
- case GHOST_kStandardCursorBottomRightCorner:
- case GHOST_kStandardCursorBottomLeftCorner:
- case GHOST_kStandardCursorCopy:
- case GHOST_kStandardCursorDefault:
- default:
- tmpCursor = [NSCursor arrowCursor];
- break;
- };
- }
- [tmpCursor set];
+
+ [cursor set];
+}
+
+bool GHOST_WindowCocoa::isDialog() const
+{
+ return m_is_dialog;
}
GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
@@ -1047,11 +1112,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor sha
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- if (m_customCursor) {
- [m_customCursor release];
- m_customCursor = nil;
- }
-
if ([m_window isVisible]) {
loadCursor(getCursorVisibility(), shape);
}
@@ -1060,6 +1120,14 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor sha
return GHOST_kSuccess;
}
+GHOST_TSuccess GHOST_WindowCocoa::hasCursorShape(GHOST_TStandardCursor shape)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ GHOST_TSuccess success = (getStandardCursor(shape)) ? GHOST_kSuccess : GHOST_kFailure;
+ [pool drain];
+ return success;
+}
+
/** Reverse the bits in a GHOST_TUns8
static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
{
diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h
index 1d332a7dc3e..29f3eee7cce 100644
--- a/intern/ghost/intern/GHOST_WindowNULL.h
+++ b/intern/ghost/intern/GHOST_WindowNULL.h
@@ -36,6 +36,11 @@ class GHOST_WindowNULL : public GHOST_Window {
return NULL;
}
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor)
+ {
+ return GHOST_kSuccess;
+ }
+
GHOST_WindowNULL(GHOST_SystemNULL *system,
const STR_String &title,
GHOST_TInt32 left,
@@ -43,7 +48,7 @@ class GHOST_WindowNULL : public GHOST_Window {
GHOST_TUns32 width,
GHOST_TUns32 height,
GHOST_TWindowState state,
- const GHOST_TEmbedderWindowID parentWindow,
+ const GHOST_IWindow *parentWindow,
GHOST_TDrawingContextType type,
const bool stereoVisual)
: GHOST_Window(width, height, state, stereoVisual, false), m_system(system)
diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp
index cd9863d7e72..99988dd55cc 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.cpp
+++ b/intern/ghost/intern/GHOST_WindowSDL.cpp
@@ -301,19 +301,6 @@ static unsigned char sdl_std_cursor_top_left_corner[] = {
#define sdl_std_cursor_HOT_X_top_left_corner 0
#define sdl_std_cursor_HOT_Y_top_left_corner -14
-static unsigned char sdl_std_cursor_mask_spraycan[] = {
- 0x00, 0x0c, 0x18, 0x0d, 0x7c, 0x0d, 0x7c, 0x0d, 0x7e, 0x0d, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
- 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
-};
-static unsigned char sdl_std_cursor_spraycan[] = {
- 0x00, 0x06, 0x80, 0x00, 0x2c, 0x06, 0x9e, 0x00, 0x16, 0x06, 0x3f, 0x00, 0x21, 0x00, 0x27, 0x00,
- 0x25, 0x00, 0x27, 0x00, 0x25, 0x00, 0x27, 0x00, 0x27, 0x00, 0x21, 0x00, 0x21, 0x00, 0x3f, 0x00,
-};
-#define sdl_std_cursor_WIDTH_spraycan 12
-#define sdl_std_cursor_HEIGHT_spraycan 16
-#define sdl_std_cursor_HOT_X_spraycan -9
-#define sdl_std_cursor_HOT_Y_spraycan -14
-
static unsigned char sdl_std_cursor_mask_sb_v_double_arrow[] = {
0x38, 0x00, 0x7c, 0x00, 0xfe, 0x00, 0xff, 0x01, 0xff, 0x01, 0x7c, 0x00, 0x7c, 0x00, 0x7c,
0x00, 0x7c, 0x00, 0x7c, 0x00, 0xff, 0x01, 0xff, 0x01, 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00,
@@ -450,19 +437,6 @@ static unsigned char sdl_std_cursor_left_ptr[] = {
#define sdl_std_cursor_HOT_X_left_ptr -8
#define sdl_std_cursor_HOT_Y_left_ptr -14
-static unsigned char sdl_std_cursor_mask_exchange[] = {
- 0xe3, 0x07, 0xf7, 0x0f, 0xff, 0x1f, 0xff, 0x3f, 0x3f, 0x38, 0xff, 0x30, 0xff, 0x00, 0xff, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0x0c, 0xfe, 0x1c, 0xfc, 0xfc, 0xff, 0xf8, 0xff, 0xf0, 0xef, 0xe0, 0xc7,
-};
-static unsigned char sdl_std_cursor_exchange[] = {
- 0xf1, 0x03, 0xfb, 0x07, 0x1f, 0x0c, 0x09, 0x08, 0x19, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3f, 0x00, 0x26, 0x04, 0x24, 0x0c, 0x3e, 0xf8, 0x37, 0xf0, 0x23, 0x00, 0x00, 0x00, 0x00,
-};
-#define sdl_std_cursor_WIDTH_exchange 16
-#define sdl_std_cursor_HEIGHT_exchange 16
-#define sdl_std_cursor_HOT_X_exchange -6
-#define sdl_std_cursor_HOT_Y_exchange -8
-
static unsigned char sdl_std_cursor_mask_crosshair[] = {
0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
@@ -583,9 +557,9 @@ static SDL_Cursor *sdl_ghost_CreateCursor(
}
/* TODO, this is currently never freed but it wont leak either. */
-static void sdl_cursor_init(void)
+static void getStandardCursorShape(GHOST_TStandardCursor shape)
{
-
+ if (sdl_std_cursor_array[0] == NULL) {
#define DEF_CURSOR(name, ind) \
{ \
sdl_std_cursor_array[(int)ind] = sdl_ghost_CreateCursor( \
@@ -599,32 +573,32 @@ static void sdl_cursor_init(void)
} \
(void)0
- DEF_CURSOR(left_ptr, GHOST_kStandardCursorDefault);
- DEF_CURSOR(right_ptr, GHOST_kStandardCursorRightArrow);
- DEF_CURSOR(left_ptr, GHOST_kStandardCursorLeftArrow);
- DEF_CURSOR(umbrella, GHOST_kStandardCursorInfo); // TODO, replace this one.
- DEF_CURSOR(pirate, GHOST_kStandardCursorDestroy);
- DEF_CURSOR(question_arrow, GHOST_kStandardCursorHelp);
- DEF_CURSOR(exchange, GHOST_kStandardCursorCycle);
- DEF_CURSOR(spraycan, GHOST_kStandardCursorSpray);
- DEF_CURSOR(watch, GHOST_kStandardCursorWait);
- DEF_CURSOR(xterm, GHOST_kStandardCursorText);
- DEF_CURSOR(crosshair, GHOST_kStandardCursorCrosshair);
- DEF_CURSOR(sb_v_double_arrow, GHOST_kStandardCursorUpDown);
- DEF_CURSOR(sb_h_double_arrow, GHOST_kStandardCursorLeftRight);
- DEF_CURSOR(top_side, GHOST_kStandardCursorTopSide);
- DEF_CURSOR(bottom_side, GHOST_kStandardCursorBottomSide);
- DEF_CURSOR(left_side, GHOST_kStandardCursorLeftSide);
- DEF_CURSOR(right_side, GHOST_kStandardCursorRightSide);
- DEF_CURSOR(top_left_corner, GHOST_kStandardCursorTopLeftCorner);
- DEF_CURSOR(top_right_corner, GHOST_kStandardCursorTopRightCorner);
- DEF_CURSOR(bottom_right_corner, GHOST_kStandardCursorBottomRightCorner);
- DEF_CURSOR(bottom_left_corner, GHOST_kStandardCursorBottomLeftCorner);
- DEF_CURSOR(arrow, GHOST_kStandardCursorCopy);
- // DEF_CURSOR(arrow, GHOST_kStandardCursorCustom);
- DEF_CURSOR(arrow, GHOST_kStandardCursorPencil);
-
+ DEF_CURSOR(left_ptr, GHOST_kStandardCursorDefault);
+ DEF_CURSOR(right_ptr, GHOST_kStandardCursorRightArrow);
+ DEF_CURSOR(left_ptr, GHOST_kStandardCursorLeftArrow);
+ DEF_CURSOR(umbrella, GHOST_kStandardCursorInfo); // TODO, replace this one.
+ DEF_CURSOR(pirate, GHOST_kStandardCursorDestroy);
+ DEF_CURSOR(question_arrow, GHOST_kStandardCursorHelp);
+ DEF_CURSOR(watch, GHOST_kStandardCursorWait);
+ DEF_CURSOR(xterm, GHOST_kStandardCursorText);
+ DEF_CURSOR(crosshair, GHOST_kStandardCursorCrosshair);
+ DEF_CURSOR(sb_v_double_arrow, GHOST_kStandardCursorUpDown);
+ DEF_CURSOR(sb_h_double_arrow, GHOST_kStandardCursorLeftRight);
+ DEF_CURSOR(top_side, GHOST_kStandardCursorTopSide);
+ DEF_CURSOR(bottom_side, GHOST_kStandardCursorBottomSide);
+ DEF_CURSOR(left_side, GHOST_kStandardCursorLeftSide);
+ DEF_CURSOR(right_side, GHOST_kStandardCursorRightSide);
+ DEF_CURSOR(top_left_corner, GHOST_kStandardCursorTopLeftCorner);
+ DEF_CURSOR(top_right_corner, GHOST_kStandardCursorTopRightCorner);
+ DEF_CURSOR(bottom_right_corner, GHOST_kStandardCursorBottomRightCorner);
+ DEF_CURSOR(bottom_left_corner, GHOST_kStandardCursorBottomLeftCorner);
+ DEF_CURSOR(arrow, GHOST_kStandardCursorCopy);
+ // DEF_CURSOR(arrow, GHOST_kStandardCursorCustom);
+ DEF_CURSOR(arrow, GHOST_kStandardCursorPencil);
#undef DEF_CURSOR
+ }
+
+ return sdl_std_cursor_array[(int)shape];
}
GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
@@ -634,14 +608,20 @@ GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
GHOST_TSuccess GHOST_WindowSDL::setWindowCursorShape(GHOST_TStandardCursor shape)
{
- if (sdl_std_cursor_array[0] == NULL) {
- sdl_cursor_init();
+ SDL_Cursor *cursor = getStandardCursorShape(shape);
+ if (cursor == NULL) {
+ cursor = getStandardCursorShape(GHOST_kStandardCursorDefault);
}
- SDL_SetCursor(sdl_std_cursor_array[(int)shape]);
+ SDL_SetCursor(cursor);
return GHOST_kSuccess;
}
+GHOST_TSuccess GHOST_WindowSDL::hasCursorShape(GHOST_TStandardCursor shape)
+{
+ return (getStandardCursorShape(shape)) ? GHOST_kSuccess : GHOST_kFailure;
+}
+
GHOST_TSuccess GHOST_WindowSDL::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
GHOST_TUns8 *mask,
int sizex,
diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h
index bb19b62e06d..a5c2fa9b185 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.h
+++ b/intern/ghost/intern/GHOST_WindowSDL.h
@@ -100,6 +100,7 @@ class GHOST_WindowSDL : public GHOST_Window {
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode);
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor shape);
GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
GHOST_TUns8 *mask,
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index e8b36c59366..e1c6aa1109c 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -23,6 +23,7 @@
#define _USE_MATH_DEFINES
+#include "GHOST_WindowManager.h"
#include "GHOST_WindowWin32.h"
#include "GHOST_SystemWin32.h"
#include "GHOST_DropTargetWin32.h"
@@ -66,8 +67,9 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
GHOST_TDrawingContextType type,
bool wantStereoVisual,
bool alphaBackground,
- GHOST_TEmbedderWindowID parentwindowhwnd,
- bool is_debug)
+ GHOST_WindowWin32 *parentwindow,
+ bool is_debug,
+ bool dialog)
: GHOST_Window(width, height, state, wantStereoVisual, false),
m_inLiveResize(false),
m_system(system),
@@ -82,7 +84,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_fpGetPointerInfo(NULL),
m_fpGetPointerPenInfo(NULL),
m_fpGetPointerTouchInfo(NULL),
- m_parentWindowHwnd(parentwindowhwnd),
+ m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : NULL),
m_debug_context(is_debug)
{
// Initialize tablet variables
@@ -146,9 +148,9 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
top = monitor.rcWork.top;
int wintype = WS_OVERLAPPEDWINDOW;
- if (m_parentWindowHwnd != 0) {
+ if ((m_parentWindowHwnd != 0) && !dialog) {
wintype = WS_CHILD;
- GetWindowRect((HWND)m_parentWindowHwnd, &rect);
+ GetWindowRect(m_parentWindowHwnd, &rect);
left = 0;
top = 0;
width = rect.right - rect.left;
@@ -156,14 +158,14 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
}
wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
- m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name
- title_16, // pointer to window name
- wintype, // window style
- left, // horizontal position of window
- top, // vertical position of window
- width, // window width
- height, // window height
- (HWND)m_parentWindowHwnd, // handle to parent or owner window
+ m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name
+ title_16, // pointer to window name
+ wintype, // window style
+ left, // horizontal position of window
+ top, // vertical position of window
+ width, // window width
+ height, // window height
+ dialog ? 0 : m_parentWindowHwnd, // handle to parent or owner window
0, // handle to menu or child-window identifier
::GetModuleHandle(0), // handle to application instance
0); // pointer to window-creation data
@@ -267,7 +269,16 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
}
}
- if (parentwindowhwnd != 0) {
+ if (dialog && parentwindow) {
+ ::SetWindowLongPtr(m_hWnd,
+ GWL_STYLE,
+ WS_VISIBLE | WS_CHILD | WS_POPUPWINDOW | WS_CAPTION | WS_MAXIMIZEBOX |
+ WS_SIZEBOX);
+ ::SetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT, (LONG_PTR)m_parentWindowHwnd);
+ ::SetWindowPos(
+ m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ }
+ else if (parentwindow) {
RAWINPUTDEVICE device = {0};
device.usUsagePage = 0x01; /* usUsagePage & usUsage for keyboard*/
device.usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
@@ -386,6 +397,16 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
}
if (m_hWnd) {
+ /* If this window is referenced by others as parent, clear that relation or windows will free
+ * the handle while we still reference it. */
+ for (GHOST_IWindow *iter_win : m_system->getWindowManager()->getWindows()) {
+ GHOST_WindowWin32 *iter_winwin = (GHOST_WindowWin32 *)iter_win;
+ if (iter_winwin->m_parentWindowHwnd == m_hWnd) {
+ ::SetWindowLongPtr(iter_winwin->m_hWnd, GWLP_HWNDPARENT, NULL);
+ iter_winwin->m_parentWindowHwnd = 0;
+ }
+ }
+
if (m_dropTarget) {
// Disable DragDrop
RevokeDragDrop(m_hWnd);
@@ -528,7 +549,7 @@ GHOST_TWindowState GHOST_WindowWin32::getState() const
// we need to find a way to combine parented windows + resizing if we simply set the
// state as GHOST_kWindowStateEmbedded we will need to check for them somewhere else.
// It's also strange that in Windows is the only platform we need to make this separation.
- if (m_parentWindowHwnd != 0) {
+ if ((m_parentWindowHwnd != 0) && !isDialog()) {
state = GHOST_kWindowStateEmbedded;
return state;
}
@@ -574,6 +595,7 @@ void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX,
GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
{
GHOST_TWindowState curstate = getState();
+ LONG_PTR newstyle = -1;
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
::GetWindowPlacement(m_hWnd, &wp);
@@ -587,7 +609,7 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
break;
case GHOST_kWindowStateMaximized:
wp.showCmd = SW_SHOWMAXIMIZED;
- ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
+ newstyle = WS_OVERLAPPEDWINDOW;
break;
case GHOST_kWindowStateFullScreen:
if (curstate != state && curstate != GHOST_kWindowStateMinimized)
@@ -595,17 +617,21 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
wp.showCmd = SW_SHOWMAXIMIZED;
wp.ptMaxPosition.x = 0;
wp.ptMaxPosition.y = 0;
- ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_MAXIMIZE);
+ newstyle = WS_MAXIMIZE;
break;
case GHOST_kWindowStateEmbedded:
- ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD);
+ newstyle = WS_CHILD;
break;
case GHOST_kWindowStateNormal:
default:
wp.showCmd = SW_SHOWNORMAL;
- ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
+ newstyle = WS_OVERLAPPEDWINDOW;
break;
}
+ if ((newstyle >= 0) && !isDialog()) {
+ ::SetWindowLongPtr(m_hWnd, GWL_STYLE, newstyle);
+ }
+
/* Clears window cache for SetWindowLongPtr */
::SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
@@ -737,6 +763,14 @@ void GHOST_WindowWin32::lostMouseCapture()
}
}
+bool GHOST_WindowWin32::isDialog() const
+{
+ HWND parent = (HWND)::GetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT);
+ long int style = (long int)::GetWindowLongPtr(m_hWnd, GWL_STYLE);
+
+ return (parent != 0) && (style & WS_POPUPWINDOW);
+}
+
void GHOST_WindowWin32::registerMouseClickEvent(int press)
{
@@ -766,7 +800,133 @@ void GHOST_WindowWin32::registerMouseClickEvent(int press)
}
}
-void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
+HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const
+{
+ // Convert GHOST cursor to Windows OEM cursor
+ HANDLE cursor = NULL;
+ HMODULE module = ::GetModuleHandle(0);
+ GHOST_TUns32 flags = LR_SHARED | LR_DEFAULTSIZE;
+ int cx = 0, cy = 0;
+
+ switch (shape) {
+ case GHOST_kStandardCursorCustom:
+ if (m_customCursor) {
+ return m_customCursor;
+ }
+ else {
+ return NULL;
+ }
+ case GHOST_kStandardCursorRightArrow:
+ cursor = ::LoadImage(module, "arrowright_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorLeftArrow:
+ cursor = ::LoadImage(module, "arrowleft_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorUpArrow:
+ cursor = ::LoadImage(module, "arrowup_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorDownArrow:
+ cursor = ::LoadImage(module, "arrowdown_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorVerticalSplit:
+ cursor = ::LoadImage(module, "splitv_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorHorizontalSplit:
+ cursor = ::LoadImage(module, "splith_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorKnife:
+ cursor = ::LoadImage(module, "knife_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorEyedropper:
+ cursor = ::LoadImage(module, "eyedropper_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorZoomIn:
+ cursor = ::LoadImage(module, "zoomin_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorZoomOut:
+ cursor = ::LoadImage(module, "zoomout_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorMove:
+ cursor = ::LoadImage(module, "handopen_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorNSEWScroll:
+ cursor = ::LoadImage(module, "scrollnsew_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorNSScroll:
+ cursor = ::LoadImage(module, "scrollns_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorEWScroll:
+ cursor = ::LoadImage(module, "scrollew_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorHelp:
+ cursor = ::LoadImage(NULL, IDC_HELP, IMAGE_CURSOR, cx, cy, flags);
+ break; // Arrow and question mark
+ case GHOST_kStandardCursorWait:
+ cursor = ::LoadImage(NULL, IDC_WAIT, IMAGE_CURSOR, cx, cy, flags);
+ break; // Hourglass
+ case GHOST_kStandardCursorText:
+ cursor = ::LoadImage(NULL, IDC_IBEAM, IMAGE_CURSOR, cx, cy, flags);
+ break; // I-beam
+ case GHOST_kStandardCursorCrosshair:
+ cursor = ::LoadImage(module, "cross_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Standard Cross
+ case GHOST_kStandardCursorCrosshairA:
+ cursor = ::LoadImage(module, "crossA_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Crosshair A
+ case GHOST_kStandardCursorCrosshairB:
+ cursor = ::LoadImage(module, "crossB_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Diagonal Crosshair B
+ case GHOST_kStandardCursorCrosshairC:
+ cursor = ::LoadImage(module, "crossC_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Minimal Crosshair C
+ case GHOST_kStandardCursorBottomSide:
+ case GHOST_kStandardCursorUpDown:
+ cursor = ::LoadImage(module, "movens_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Double-pointed arrow pointing north and south
+ case GHOST_kStandardCursorLeftSide:
+ case GHOST_kStandardCursorLeftRight:
+ cursor = ::LoadImage(module, "moveew_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Double-pointed arrow pointing west and east
+ case GHOST_kStandardCursorTopSide:
+ cursor = ::LoadImage(NULL, IDC_UPARROW, IMAGE_CURSOR, cx, cy, flags);
+ break; // Vertical arrow
+ case GHOST_kStandardCursorTopLeftCorner:
+ cursor = ::LoadImage(NULL, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorTopRightCorner:
+ cursor = ::LoadImage(NULL, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorBottomRightCorner:
+ cursor = ::LoadImage(NULL, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorBottomLeftCorner:
+ cursor = ::LoadImage(NULL, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorPencil:
+ cursor = ::LoadImage(module, "pencil_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorEraser:
+ cursor = ::LoadImage(module, "eraser_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
+ case GHOST_kStandardCursorDestroy:
+ case GHOST_kStandardCursorStop:
+ cursor = ::LoadImage(module, "forbidden_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; // Slashed circle
+ case GHOST_kStandardCursorDefault:
+ cursor = NULL;
+ break;
+ default:
+ return NULL;
+ }
+
+ if (cursor == NULL) {
+ cursor = ::LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, cx, cy, flags);
+ }
+
+ return (HCURSOR)cursor;
+}
+
+void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor shape) const
{
if (!visible) {
while (::ShowCursor(FALSE) >= 0)
@@ -777,88 +937,11 @@ void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) c
;
}
- if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
- ::SetCursor(m_customCursor);
- }
- else {
- // Convert GHOST cursor to Windows OEM cursor
- bool success = true;
- LPCSTR id;
- switch (cursor) {
- case GHOST_kStandardCursorDefault:
- id = IDC_ARROW;
- break;
- case GHOST_kStandardCursorRightArrow:
- id = IDC_ARROW;
- break;
- case GHOST_kStandardCursorLeftArrow:
- id = IDC_ARROW;
- break;
- case GHOST_kStandardCursorInfo:
- id = IDC_SIZEALL;
- break; // Four-pointed arrow pointing north, south, east, and west
- case GHOST_kStandardCursorDestroy:
- id = IDC_NO;
- break; // Slashed circle
- case GHOST_kStandardCursorHelp:
- id = IDC_HELP;
- break; // Arrow and question mark
- case GHOST_kStandardCursorCycle:
- id = IDC_NO;
- break; // Slashed circle
- case GHOST_kStandardCursorSpray:
- id = IDC_SIZEALL;
- break; // Four-pointed arrow pointing north, south, east, and west
- case GHOST_kStandardCursorWait:
- id = IDC_WAIT;
- break; // Hourglass
- case GHOST_kStandardCursorText:
- id = IDC_IBEAM;
- break; // I-beam
- case GHOST_kStandardCursorCrosshair:
- id = IDC_CROSS;
- break; // Crosshair
- case GHOST_kStandardCursorUpDown:
- id = IDC_SIZENS;
- break; // Double-pointed arrow pointing north and south
- case GHOST_kStandardCursorLeftRight:
- id = IDC_SIZEWE;
- break; // Double-pointed arrow pointing west and east
- case GHOST_kStandardCursorTopSide:
- id = IDC_UPARROW;
- break; // Vertical arrow
- case GHOST_kStandardCursorBottomSide:
- id = IDC_SIZENS;
- break;
- case GHOST_kStandardCursorLeftSide:
- id = IDC_SIZEWE;
- break;
- case GHOST_kStandardCursorTopLeftCorner:
- id = IDC_SIZENWSE;
- break;
- case GHOST_kStandardCursorTopRightCorner:
- id = IDC_SIZENESW;
- break;
- case GHOST_kStandardCursorBottomRightCorner:
- id = IDC_SIZENWSE;
- break;
- case GHOST_kStandardCursorBottomLeftCorner:
- id = IDC_SIZENESW;
- break;
- case GHOST_kStandardCursorPencil:
- id = IDC_ARROW;
- break;
- case GHOST_kStandardCursorCopy:
- id = IDC_ARROW;
- break;
- default:
- success = false;
- }
-
- if (success) {
- ::SetCursor(::LoadCursor(0, id));
- }
+ HCURSOR cursor = getStandardCursor(shape);
+ if (cursor == NULL) {
+ cursor = getStandardCursor(GHOST_kStandardCursorDefault);
}
+ ::SetCursor(cursor);
}
GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
@@ -908,11 +991,6 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode
GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
{
- if (m_customCursor) {
- DestroyCursor(m_customCursor);
- m_customCursor = NULL;
- }
-
if (::GetForegroundWindow() == m_hWnd) {
loadCursor(getCursorVisibility(), cursorShape);
}
@@ -920,6 +998,11 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cur
return GHOST_kSuccess;
}
+GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorShape)
+{
+ return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure;
+}
+
GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo,
WPARAM wParam,
LPARAM lParam)
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index cf7177b0062..f72f03855fd 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -235,8 +235,9 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
bool wantStereoVisual = false,
bool alphaBackground = false,
- GHOST_TEmbedderWindowID parentWindowHwnd = 0,
- bool is_debug = false);
+ GHOST_WindowWin32 *parentWindow = 0,
+ bool is_debug = false,
+ bool dialog = false);
/**
* Destructor.
@@ -381,11 +382,14 @@ class GHOST_WindowWin32 : public GHOST_Window {
*/
void lostMouseCapture();
+ bool isDialog() const;
+
/**
* Loads the windows equivalent of a standard GHOST cursor.
* \param visible Flag for cursor visibility.
* \param cursorShape The cursor shape.
*/
+ HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const;
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
const GHOST_TabletData *GetTabletData()
@@ -456,6 +460,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
* native window system calls.
*/
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor shape);
/**
* Sets the cursor shape on the window using
@@ -526,8 +531,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_WIN32_GetPointerPenInfo m_fpGetPointerPenInfo;
GHOST_WIN32_GetPointerTouchInfo m_fpGetPointerTouchInfo;
- /** Hwnd to parent window */
- GHOST_TEmbedderWindowID m_parentWindowHwnd;
+ HWND m_parentWindowHwnd;
#ifdef WITH_INPUT_IME
/** Handle input method editors event */
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 166fea8a84b..ae8d705fe4a 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -72,7 +72,18 @@ typedef struct {
long input_mode;
} MotifWmHints;
-#define MWM_HINTS_DECORATIONS (1L << 1)
+enum {
+ MWM_HINTS_FUNCTIONS = (1L << 0),
+ MWM_HINTS_DECORATIONS = (1L << 1),
+};
+enum {
+ MWM_FUNCTION_ALL = (1L << 0),
+ MWM_FUNCTION_RESIZE = (1L << 1),
+ MWM_FUNCTION_MOVE = (1L << 2),
+ MWM_FUNCTION_MINIMIZE = (1L << 3),
+ MWM_FUNCTION_MAXIMIZE = (1L << 4),
+ MWM_FUNCTION_CLOSE = (1L << 5),
+};
#ifndef HOST_NAME_MAX
# define HOST_NAME_MAX 64
@@ -191,8 +202,9 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
GHOST_TUns32 width,
GHOST_TUns32 height,
GHOST_TWindowState state,
- const GHOST_TEmbedderWindowID parentWindow,
+ GHOST_WindowX11 *parentWindow,
GHOST_TDrawingContextType type,
+ const bool is_dialog,
const bool stereoVisual,
const bool exclusive,
const bool alphaBackground,
@@ -259,7 +271,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
m_display, RootWindow(m_display, m_visualInfo->screen), m_visualInfo->visual, AllocNone);
/* create the window! */
- if (parentWindow == 0) {
+ if ((parentWindow == 0) || is_dialog) {
m_window = XCreateWindow(m_display,
RootWindow(m_display, m_visualInfo->screen),
left,
@@ -279,7 +291,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
unsigned int w_return, h_return, border_w_return, depth_return;
XGetGeometry(m_display,
- parentWindow,
+ parentWindow->m_window,
&root_return,
&x_return,
&y_return,
@@ -294,7 +306,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
height = h_return;
m_window = XCreateWindow(m_display,
- parentWindow, /* reparent against embedder */
+ parentWindow->m_window, /* reparent against embedder */
left,
top,
width,
@@ -306,7 +318,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
xattributes_valuemask,
&xattributes);
- XSelectInput(m_display, parentWindow, SubstructureNotifyMask);
+ XSelectInput(m_display, parentWindow->m_window, SubstructureNotifyMask);
}
#ifdef WITH_XDND
@@ -356,6 +368,10 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
m_post_state = GHOST_kWindowStateNormal;
}
+ if (is_dialog && parentWindow) {
+ setDialogHints(parentWindow);
+ }
+
/* Create some hints for the window manager on how
* we want this window treated. */
{
@@ -701,6 +717,42 @@ void GHOST_WindowX11::clientToScreen(GHOST_TInt32 inX,
outY = ay;
}
+GHOST_TSuccess GHOST_WindowX11::setDialogHints(GHOST_WindowX11 *parentWindow)
+{
+
+ Atom atom_window_type = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE", False);
+ Atom atom_dialog = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+ MotifWmHints hints = {0};
+
+ XChangeProperty(m_display,
+ m_window,
+ atom_window_type,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char *)&atom_dialog,
+ 1);
+ XSetTransientForHint(m_display, m_window, parentWindow->m_window);
+
+ /* Disable minimizing of the window for now.
+ * Actually, most window managers disable minimizing and maximizing for dialogs, ignoring this.
+ * Leaving it here anyway in the hope it brings back maximizing on some window managers at least,
+ * we'd preferably have it even for dialog windows (e.g. file browser). */
+ hints.flags = MWM_HINTS_FUNCTIONS;
+ hints.functions = MWM_FUNCTION_RESIZE | MWM_FUNCTION_MOVE | MWM_FUNCTION_MAXIMIZE |
+ MWM_FUNCTION_CLOSE;
+ XChangeProperty(m_display,
+ m_window,
+ m_system->m_atom._MOTIF_WM_HINTS,
+ m_system->m_atom._MOTIF_WM_HINTS,
+ 32,
+ PropModeReplace,
+ (unsigned char *)&hints,
+ 4);
+
+ return GHOST_kSuccess;
+}
+
void GHOST_WindowX11::icccmSetState(int state)
{
XEvent xev;
@@ -1112,6 +1164,44 @@ GHOST_TSuccess GHOST_WindowX11::setOrder(GHOST_TWindowOrder order)
return GHOST_kSuccess;
}
+bool GHOST_WindowX11::isDialog() const
+{
+ Atom atom_window_type = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE", False);
+ Atom atom_dialog = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
+
+ Atom *prop_ret;
+ unsigned long bytes_after, num_ret;
+ Atom type_ret;
+ bool st;
+ int format_ret, ret;
+
+ prop_ret = NULL;
+ st = False;
+ ret = XGetWindowProperty(m_display,
+ m_window,
+ atom_window_type,
+ 0,
+ INT_MAX,
+ False,
+ XA_ATOM,
+ &type_ret,
+ &format_ret,
+ &num_ret,
+ &bytes_after,
+ (unsigned char **)&prop_ret);
+ if ((ret == Success) && (prop_ret) && (format_ret == 32)) {
+ if (prop_ret[0] == atom_dialog) {
+ st = True;
+ }
+ }
+
+ if (prop_ret) {
+ XFree(prop_ret);
+ }
+
+ return st;
+}
+
GHOST_TSuccess GHOST_WindowX11::invalidate()
{
/* So the idea of this function is to generate an expose event
@@ -1284,77 +1374,70 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
return NULL;
}
-Cursor GHOST_WindowX11::getStandardCursor(GHOST_TStandardCursor g_cursor)
+GHOST_TSuccess GHOST_WindowX11::getStandardCursor(GHOST_TStandardCursor g_cursor, Cursor &xcursor)
{
unsigned int xcursor_id;
-#define GtoX(gcurs, xcurs) \
- case gcurs: \
- xcursor_id = xcurs
switch (g_cursor) {
- GtoX(GHOST_kStandardCursorRightArrow, XC_arrow);
- break;
- GtoX(GHOST_kStandardCursorLeftArrow, XC_top_left_arrow);
- break;
- GtoX(GHOST_kStandardCursorInfo, XC_hand1);
- break;
- GtoX(GHOST_kStandardCursorDestroy, XC_pirate);
- break;
- GtoX(GHOST_kStandardCursorHelp, XC_question_arrow);
- break;
- GtoX(GHOST_kStandardCursorCycle, XC_exchange);
- break;
- GtoX(GHOST_kStandardCursorSpray, XC_spraycan);
- break;
- GtoX(GHOST_kStandardCursorWait, XC_watch);
- break;
- GtoX(GHOST_kStandardCursorText, XC_xterm);
- break;
- GtoX(GHOST_kStandardCursorCrosshair, XC_crosshair);
- break;
- GtoX(GHOST_kStandardCursorUpDown, XC_sb_v_double_arrow);
- break;
- GtoX(GHOST_kStandardCursorLeftRight, XC_sb_h_double_arrow);
- break;
- GtoX(GHOST_kStandardCursorTopSide, XC_top_side);
- break;
- GtoX(GHOST_kStandardCursorBottomSide, XC_bottom_side);
- break;
- GtoX(GHOST_kStandardCursorLeftSide, XC_left_side);
- break;
- GtoX(GHOST_kStandardCursorRightSide, XC_right_side);
- break;
- GtoX(GHOST_kStandardCursorTopLeftCorner, XC_top_left_corner);
- break;
- GtoX(GHOST_kStandardCursorTopRightCorner, XC_top_right_corner);
- break;
- GtoX(GHOST_kStandardCursorBottomRightCorner, XC_bottom_right_corner);
- break;
- GtoX(GHOST_kStandardCursorBottomLeftCorner, XC_bottom_left_corner);
- break;
- GtoX(GHOST_kStandardCursorPencil, XC_pencil);
- break;
- GtoX(GHOST_kStandardCursorCopy, XC_arrow);
- break;
+ case GHOST_kStandardCursorHelp:
+ xcursor_id = XC_question_arrow;
+ break;
+ case GHOST_kStandardCursorWait:
+ xcursor_id = XC_watch;
+ break;
+ case GHOST_kStandardCursorText:
+ xcursor_id = XC_xterm;
+ break;
+ case GHOST_kStandardCursorCrosshair:
+ xcursor_id = XC_crosshair;
+ break;
+ case GHOST_kStandardCursorUpDown:
+ xcursor_id = XC_sb_v_double_arrow;
+ break;
+ case GHOST_kStandardCursorLeftRight:
+ xcursor_id = XC_sb_h_double_arrow;
+ break;
+ case GHOST_kStandardCursorTopSide:
+ xcursor_id = XC_top_side;
+ break;
+ case GHOST_kStandardCursorBottomSide:
+ xcursor_id = XC_bottom_side;
+ break;
+ case GHOST_kStandardCursorLeftSide:
+ xcursor_id = XC_left_side;
+ break;
+ case GHOST_kStandardCursorRightSide:
+ xcursor_id = XC_right_side;
+ break;
+ case GHOST_kStandardCursorTopLeftCorner:
+ xcursor_id = XC_top_left_corner;
+ break;
+ case GHOST_kStandardCursorTopRightCorner:
+ xcursor_id = XC_top_right_corner;
+ break;
+ case GHOST_kStandardCursorBottomRightCorner:
+ xcursor_id = XC_bottom_right_corner;
+ break;
+ case GHOST_kStandardCursorBottomLeftCorner:
+ xcursor_id = XC_bottom_left_corner;
+ break;
+ case GHOST_kStandardCursorDefault:
+ xcursor = None;
+ return GHOST_kSuccess;
default:
- xcursor_id = 0;
+ xcursor = None;
+ return GHOST_kFailure;
}
-#undef GtoX
- if (xcursor_id) {
- Cursor xcursor = m_standard_cursors[xcursor_id];
+ xcursor = m_standard_cursors[xcursor_id];
- if (!xcursor) {
- xcursor = XCreateFontCursor(m_display, xcursor_id);
+ if (!xcursor) {
+ xcursor = XCreateFontCursor(m_display, xcursor_id);
- m_standard_cursors[xcursor_id] = xcursor;
- }
-
- return xcursor;
- }
- else {
- return None;
+ m_standard_cursors[xcursor_id] = xcursor;
}
+
+ return GHOST_kSuccess;
}
Cursor GHOST_WindowX11::getEmptyCursor()
@@ -1380,10 +1463,12 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorVisibility(bool visible)
Cursor xcursor;
if (visible) {
- if (m_visible_cursor)
+ if (m_visible_cursor) {
xcursor = m_visible_cursor;
- else
- xcursor = getStandardCursor(getCursorShape());
+ }
+ else if (getStandardCursor(getCursorShape(), xcursor) == GHOST_kFailure) {
+ getStandardCursor(getCursorShape(), xcursor);
+ }
}
else {
xcursor = getEmptyCursor();
@@ -1463,7 +1548,10 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
GHOST_TSuccess GHOST_WindowX11::setWindowCursorShape(GHOST_TStandardCursor shape)
{
- Cursor xcursor = getStandardCursor(shape);
+ Cursor xcursor;
+ if (getStandardCursor(shape, xcursor) == GHOST_kFailure) {
+ getStandardCursor(GHOST_kStandardCursorDefault, xcursor);
+ }
m_visible_cursor = xcursor;
@@ -1473,6 +1561,12 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorShape(GHOST_TStandardCursor shape
return GHOST_kSuccess;
}
+GHOST_TSuccess GHOST_WindowX11::hasCursorShape(GHOST_TStandardCursor shape)
+{
+ Cursor xcursor;
+ return getStandardCursor(shape, xcursor);
+}
+
GHOST_TSuccess GHOST_WindowX11::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
GHOST_TUns8 *mask,
int sizex,
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 83e0a2b59db..faf3acba234 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -75,8 +75,9 @@ class GHOST_WindowX11 : public GHOST_Window {
GHOST_TUns32 width,
GHOST_TUns32 height,
GHOST_TWindowState state,
- const GHOST_TEmbedderWindowID parentWindow,
+ GHOST_WindowX11 *parentWindow,
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
+ const bool is_dialog = false,
const bool stereoVisual = false,
const bool exclusive = false,
const bool alphaBackground = false,
@@ -92,6 +93,8 @@ class GHOST_WindowX11 : public GHOST_Window {
void getClientBounds(GHOST_Rect &bounds) const;
+ bool isDialog() const;
+
GHOST_TSuccess setClientWidth(GHOST_TUns32 width);
GHOST_TSuccess setClientHeight(GHOST_TUns32 height);
@@ -185,6 +188,8 @@ class GHOST_WindowX11 : public GHOST_Window {
GHOST_TSuccess endFullScreen() const;
+ GHOST_TSuccess setDialogHints(GHOST_WindowX11 *parentWindow);
+
GHOST_TUns16 getDPIHint();
protected:
@@ -213,6 +218,7 @@ class GHOST_WindowX11 : public GHOST_Window {
* native window system calls.
*/
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor shape);
/**
* Sets the cursor shape on the window using
@@ -233,7 +239,7 @@ class GHOST_WindowX11 : public GHOST_Window {
GHOST_WindowX11(const GHOST_WindowX11 &);
- Cursor getStandardCursor(GHOST_TStandardCursor g_cursor);
+ GHOST_TSuccess getStandardCursor(GHOST_TStandardCursor g_cursor, Cursor &xcursor);
Cursor getEmptyCursor();
diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt
index a5a41209603..f97397715bf 100644
--- a/intern/ghost/test/CMakeLists.txt
+++ b/intern/ghost/test/CMakeLists.txt
@@ -126,27 +126,27 @@ add_library(glewmx_lib ${SRC_NEW})
# grr, blenfont needs BLI
include_directories(
- "../../../source/blender/blenlib"
- )
+ "../../../source/blender/blenlib"
+)
add_library(bli_lib
- "../../../source/blender/blenlib/intern/fileops.c"
- "../../../source/blender/blenlib/intern/gsqueue.c"
- "../../../source/blender/blenlib/intern/rct.c"
- "../../../source/blender/blenlib/intern/string.c"
- "../../../source/blender/blenlib/intern/string_utf8.c"
- "../../../source/blender/blenlib/intern/listbase.c"
- "../../../source/blender/blenlib/intern/math_color.c"
- "../../../source/blender/blenlib/intern/storage.c"
- "../../../source/blender/blenlib/intern/task.c"
- "../../../source/blender/blenlib/intern/threads.c"
- "../../../source/blender/blenlib/intern/time.c"
- "../../../source/blender/blenlib/intern/path_util.c"
- "../../../source/blender/blenlib/intern/BLI_dynstr.c"
- "../../../source/blender/blenlib/intern/BLI_linklist.c"
- "../../../source/blender/blenlib/intern/BLI_memarena.c"
- "../../../source/blender/blenlib/intern/BLI_mempool.c"
- "../../../source/blender/blenlib/intern/system.c"
- )
+ "../../../source/blender/blenlib/intern/fileops.c"
+ "../../../source/blender/blenlib/intern/gsqueue.c"
+ "../../../source/blender/blenlib/intern/rct.c"
+ "../../../source/blender/blenlib/intern/string.c"
+ "../../../source/blender/blenlib/intern/string_utf8.c"
+ "../../../source/blender/blenlib/intern/listbase.c"
+ "../../../source/blender/blenlib/intern/math_color.c"
+ "../../../source/blender/blenlib/intern/storage.c"
+ "../../../source/blender/blenlib/intern/task.c"
+ "../../../source/blender/blenlib/intern/threads.c"
+ "../../../source/blender/blenlib/intern/time.c"
+ "../../../source/blender/blenlib/intern/path_util.c"
+ "../../../source/blender/blenlib/intern/BLI_dynstr.c"
+ "../../../source/blender/blenlib/intern/BLI_linklist.c"
+ "../../../source/blender/blenlib/intern/BLI_memarena.c"
+ "../../../source/blender/blenlib/intern/BLI_mempool.c"
+ "../../../source/blender/blenlib/intern/system.c"
+)
set(PLATFORM_CGLAGS)
diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c
index ac970a8c610..fa2d0d1e334 100644
--- a/intern/guardedalloc/intern/mallocn.c
+++ b/intern/guardedalloc/intern/mallocn.c
@@ -72,7 +72,7 @@ void *aligned_malloc(size_t size, size_t alignment)
{
#ifdef _WIN32
return _aligned_malloc(size, alignment);
-#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined (__APPLE__)
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
void *result;
if (posix_memalign(&result, alignment, size)) {
diff --git a/intern/libmv/libmv/autotrack/callbacks.h b/intern/libmv/libmv/autotrack/callbacks.h
index e65841de3ce..ee3d2eeb7c3 100644
--- a/intern/libmv/libmv/autotrack/callbacks.h
+++ b/intern/libmv/libmv/autotrack/callbacks.h
@@ -27,7 +27,7 @@ namespace mv {
struct OperationListener {
// All hooks return true to continue or false to indicate the operation
- // should abort. Hooks should be thread safe (reentrant).
+ // should abort. Hooks should be thread safe (re-entrant).
virtual bool Log(const string& message) = 0;
virtual bool Progress(double fraction) = 0;
virtual bool Cancelled() = 0;
diff --git a/intern/mikktspace/mikktspace.c b/intern/mikktspace/mikktspace.c
index ab58c8f48e4..4f120b7d83c 100644
--- a/intern/mikktspace/mikktspace.c
+++ b/intern/mikktspace/mikktspace.c
@@ -460,11 +460,6 @@ tbool genTangSpace(const SMikkTSpaceContext *pContext, const float fAngularThres
///////////////////////////////////////////////////////////////////////////////////////////////////
-typedef struct {
- float vert[3];
- int index;
-} STmpVert;
-
static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[],
const SMikkTSpaceContext *pContext,
const int iNrTrianglesIn);
diff --git a/intern/numaapi/README.blender b/intern/numaapi/README.blender
index 6f71d5f8807..0151be80e10 100644
--- a/intern/numaapi/README.blender
+++ b/intern/numaapi/README.blender
@@ -1,5 +1,5 @@
Project: LibNumaAPI
URL: https://github.com/Nazg-Gul/libNumaAPI
License: MIT
-Upstream version: 4e7206befce
+Upstream version: 1afdd28a08d
Local modifications: None
diff --git a/intern/numaapi/source/build_config.h b/intern/numaapi/source/build_config.h
index 444adcc0c71..b8af51a5dd7 100644
--- a/intern/numaapi/source/build_config.h
+++ b/intern/numaapi/source/build_config.h
@@ -307,6 +307,27 @@
# define ARCH_CPU_32_BITS 1
# define ARCH_CPU_BIG_ENDIAN 1
# endif
+#elif defined(__powerpc64__)
+# define ARCH_CPU_PPC_FAMILY 1
+# define ARCH_CPU_PPC 1
+# define ARCH_CPU_64_BITS 1
+# if defined(__BIG_ENDIAN__)
+# define ARCH_CPU_BIG_ENDIAN 1
+# elif defined(__LITTLE_ENDIAN)
+# define ARCH_CPU_LITTLE_ENDIAN 1
+# else
+# error Please define your endianness
+# endif
+#elif defined(__s390x__)
+# define ARCH_CPU_S390_FAMILY 1
+# define ARCH_CPU_S390X 1
+# define ARCH_CPU_64_BITS 1
+# define ARCH_CPU_BIG_ENDIAN 1
+#elif defined(__s390__)
+# define ARCH_CPU_S390_FAMILY 1
+# define ARCH_CPU_S390 1
+# define ARCH_CPU_31_BITS 1
+# define ARCH_CPU_BIG_ENDIAN 1
#else
# error Please add support for your architecture in build_config.h
#endif
@@ -337,6 +358,12 @@
#if !defined(ARCH_CPU_MIPS64_FAMILY)
# define ARCH_CPU_MIPS64_FAMILY 0
#endif
+#if !defined(ARCH_CPU_PPC_FAMILY)
+# define ARCH_CPU_PPC_FAMILY 0
+#endif
+#if !defined(ARCH_CPU_S390_FAMILY)
+# define ARCH_CPU_S390_FAMILY 0
+#endif
////////////////////////////////////////////////////////////////////////////////
// Sizes of platform-dependent types.
diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
index f4a1a82ca52..ac27cbdefdc 100644
--- a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
+++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
@@ -123,6 +123,21 @@ void getEdgeVertices(const OpenSubdiv_TopologyRefiner *topology_refiner,
edge_vertices_indices[1] = array[1];
}
+int getNumVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, const int vertex_index)
+{
+ const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner);
+ return base_level->GetVertexEdges(vertex_index).size();
+}
+
+void getVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner,
+ const int vertex_index,
+ int *vertex_edges_indices)
+{
+ const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner);
+ OpenSubdiv::Far::ConstIndexArray array = base_level->GetVertexEdges(vertex_index);
+ convertArrayToRaw(array, vertex_edges_indices);
+}
+
int getNumFacePtexFaces(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index)
{
const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index);
@@ -201,6 +216,8 @@ void assignFunctionPointers(OpenSubdiv_TopologyRefiner *topology_refiner)
topology_refiner->getNumFaceEdges = getNumFaceEdges;
topology_refiner->getFaceEdges = getFaceEdges;
topology_refiner->getEdgeVertices = getEdgeVertices;
+ topology_refiner->getNumVertexEdges = getNumVertexEdges;
+ topology_refiner->getVertexEdges = getVertexEdges;
// PTex face geometry.
topology_refiner->getNumFacePtexFaces = getNumFacePtexFaces;
topology_refiner->getNumPtexFaces = getNumPtexFaces;
@@ -389,7 +406,7 @@ bool compareCyclicBackward(const CyclicArray &array_a,
// vertices.
bool checkVerticesOfFacesMatch(const CyclicArray &indices_a, const CyclicArray &indices_b)
{
- if (indices_a.size() != indices_a.size()) {
+ if (indices_a.size() != indices_b.size()) {
return false;
}
// "Align" the arrays so we know first matched element.
diff --git a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h
index cf7f59adf2f..38d722ab572 100644
--- a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h
+++ b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h
@@ -58,11 +58,13 @@ typedef struct OpenSubdiv_TopologyRefiner {
int (*getNumVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumFaces)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
+
int (*getNumFaceVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index);
void (*getFaceVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
int *face_vertices_indices);
+
int (*getNumFaceEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index);
void (*getFaceEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
@@ -72,6 +74,12 @@ typedef struct OpenSubdiv_TopologyRefiner {
const int edge_index,
int edge_vertices_indices[2]);
+ int (*getNumVertexEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
+ const int vertex_index);
+ void (*getVertexEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
+ const int vertex_index,
+ int *vertex_edges_indices);
+
//////////////////////////////////////////////////////////////////////////////
// PTex face geometry queries.
diff --git a/intern/quadriflow/CMakeLists.txt b/intern/quadriflow/CMakeLists.txt
index 615d5a34ce6..35cfe22a018 100644
--- a/intern/quadriflow/CMakeLists.txt
+++ b/intern/quadriflow/CMakeLists.txt
@@ -38,7 +38,7 @@ set(LIB
extern_quadriflow
)
-if (WIN32)
+if(WIN32)
add_definitions(-D_USE_MATH_DEFINES)
endif()
diff --git a/release/darwin/Blender.app/Contents/Resources/arrowdown.pdf b/release/darwin/Blender.app/Contents/Resources/arrowdown.pdf
new file mode 100644
index 00000000000..8a262b21010
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/arrowdown.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/arrowleft.pdf b/release/darwin/Blender.app/Contents/Resources/arrowleft.pdf
new file mode 100644
index 00000000000..1ca740b6d70
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/arrowleft.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/arrowright.pdf b/release/darwin/Blender.app/Contents/Resources/arrowright.pdf
new file mode 100644
index 00000000000..c8c657f02a0
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/arrowright.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/arrowup.pdf b/release/darwin/Blender.app/Contents/Resources/arrowup.pdf
new file mode 100644
index 00000000000..2a74e8b293e
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/arrowup.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/crossc.pdf b/release/darwin/Blender.app/Contents/Resources/crossc.pdf
new file mode 100644
index 00000000000..a6bb7a4ef01
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/crossc.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/eraser.pdf b/release/darwin/Blender.app/Contents/Resources/eraser.pdf
new file mode 100644
index 00000000000..5a56be7006b
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/eraser.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/eyedropper.pdf b/release/darwin/Blender.app/Contents/Resources/eyedropper.pdf
new file mode 100644
index 00000000000..59b9fa936df
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/eyedropper.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/knife.pdf b/release/darwin/Blender.app/Contents/Resources/knife.pdf
new file mode 100644
index 00000000000..da4d48cde10
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/knife.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/paint_cursor_cross.pdf b/release/darwin/Blender.app/Contents/Resources/paint_cursor_cross.pdf
new file mode 100644
index 00000000000..4f658f3b722
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/paint_cursor_cross.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/paint_cursor_dot.pdf b/release/darwin/Blender.app/Contents/Resources/paint_cursor_dot.pdf
new file mode 100644
index 00000000000..a5eea954231
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/paint_cursor_dot.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/pen.pdf b/release/darwin/Blender.app/Contents/Resources/pen.pdf
new file mode 100644
index 00000000000..d98f9ee9c89
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/pen.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/scrollew.pdf b/release/darwin/Blender.app/Contents/Resources/scrollew.pdf
new file mode 100644
index 00000000000..35db18830e8
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/scrollew.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/scrollns.pdf b/release/darwin/Blender.app/Contents/Resources/scrollns.pdf
new file mode 100644
index 00000000000..b4046290d50
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/scrollns.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/scrollnsew.pdf b/release/darwin/Blender.app/Contents/Resources/scrollnsew.pdf
new file mode 100644
index 00000000000..f8c666b5347
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/scrollnsew.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/splith.pdf b/release/darwin/Blender.app/Contents/Resources/splith.pdf
new file mode 100644
index 00000000000..03265fd18aa
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/splith.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/splitv.pdf b/release/darwin/Blender.app/Contents/Resources/splitv.pdf
new file mode 100644
index 00000000000..95774f9c17d
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/splitv.pdf
Binary files differ
diff --git a/release/darwin/Blender.app/Contents/Resources/zoomin.pdf b/release/darwin/Blender.app/Contents/Resources/zoomin.pdf
new file mode 100644
index 00000000000..da20349c1aa
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/zoomin.pdf
@@ -0,0 +1,674 @@
+%PDF-1.5 %âãÏÓ
+1 0 obj <</Metadata 2 0 R/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 48624/Subtype/XML/Type/Metadata>>stream
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.2-c063 53.352624, 2008/07/30-18:05:41 ">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about=""
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <dc:format>application/pdf</dc:format>
+ <dc:title>
+ <rdf:Alt>
+ <rdf:li xml:lang="x-default">ZoominCursor</rdf:li>
+ </rdf:Alt>
+ </dc:title>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmp="http://ns.adobe.com/xap/1.0/"
+ xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
+ <xmp:CreatorTool>Adobe Illustrator CS4</xmp:CreatorTool>
+ <xmp:CreateDate>2011-08-25T16:21:20-07:00</xmp:CreateDate>
+ <xmp:ModifyDate>2011-08-25T16:21:20-07:00</xmp:ModifyDate>
+ <xmp:MetadataDate>2011-08-25T16:21:20-07:00</xmp:MetadataDate>
+ <xmp:Thumbnails>
+ <rdf:Alt>
+ <rdf:li rdf:parseType="Resource">
+ <xmpGImg:width>256</xmpGImg:width>
+ <xmpGImg:height>256</xmpGImg:height>
+ <xmpGImg:format>JPEG</xmpGImg:format>
+ <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYqx&#xA;Hzr+bP5eeSkb/EOtQWtyBUWKEzXRr0/cRBpAD4kAe+KvCvNv/ObdpGzw+UvL7TUqFvNTfgu3Q+hC&#xA;SSD/AMZBiryfX/8AnKT859XLKusppkDf7psIIoqfKRhJMP8Ag8VYPqf5h+ftUJ/SXmTU7wN1Wa8n&#xA;de+wUvQDc4qkU9xcTuHnleVwKBnYsaeFTiroLi4gcvBK8TkULIxU08KjFU90z8w/P2lkfo3zJqdm&#xA;F6LDeTovbYqHoRsMVZxoH/OUn5z6QVVtZTU4F/3TfwRS1+ciiOY/8Hir1jyn/wA5t2jlIfNvl5oT&#xA;sGvNMk5rv1/cTFSAP+MpxV7r5K/Nn8vPOqL/AIe1qC6uSKmxcmG6FOv7iULIQPEAj3xVl2KuxV2K&#xA;uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxViX5h/mn5L8gacLzzFfCKWQE2thF+8upyP&#xA;99xA9O3JqKO5xV8k/mX/AM5YeffM7TWXl8ny3ozVUfV2reyL/l3GxSvhGFp05HFXiMsss0ryzO0k&#xA;shLPI5LMzHckk7k4qsxV2KuxV2KuxV2KuxV2Kr4pZYZUlhdo5YyGSRCVZWG4II3BxV7d+Wn/ADlh&#xA;598sNDZeYGPmTRlop+sNS9jX/IuNy/ylDfMYq+tvy8/NPyX5/wBON55dvhLLGAbqwl/d3UBP+/Ii&#xA;enbktVPY4qy3FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXgP55/85Qab5Sa48veUjHqP&#xA;mVax3N4aPbWbdx4Syj+X7Kn7W4K4q+ONc13Wdd1OfVNZvJb/AFC4PKa5nYu7eAqegHYDYdsVQGKo&#xA;rTdM1LU72Ox021mvb2Y0itreNpZXP+SiAscVe3+SP+cPfzE1tY7nzBPB5cs23Mcv+k3dD/xTGQg/&#xA;2UgI8MVe2eWf+cQfym0pFbVEu9duBuxup2hiqP5Y7b0jT2ZmxV6NpP5WflrpKgaf5X0uBh/uwWkL&#xA;SfTIys5+/FWSW9naWylbaCOBTSqxqqDbp9kDFXXFnaXKhbmCOdRWiyKrjfr9oHFWN6t+Vn5a6spG&#xA;oeV9LnY/7sNpCsn0SKquPvxV5z5m/wCcQfym1VGbS0u9CuDuptZ2miqf5o7n1TT2VlxV4n53/wCc&#xA;PfzE0RZLny/PB5js13EcX+jXdB/xTISh/wBjISfDFXiGpaZqWmXsljqVrNZXsJpLbXEbRSof8pHA&#xA;YYqhcVR+h67rOhanBqmjXkthqFueUNzAxR18RUdQe4Ox74q+x/yM/wCcoNN82tb+XvNpj07zK1I7&#xA;a8FEtrxuw8IpT/L9lj9nchcVe/Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq+X/8AnJH/AJyR&#xA;msZrryV5KuuF2lYtZ1mI7xno1vbsOjjo7j7PQb1IVfJhJJqdycVaxV7j+T//ADi35o85xwax5gaT&#xA;QvLklHjLL/plwh3BhjcURGHR3+YVhir698j/AJb+S/I+n/UvLemRWfIUnuqc7ibvWWZqu2/atB2A&#xA;xVk2KuxV2KuxV2KuxV2KuxVjPnj8t/JfnjT/AKl5k0yK84ikF1ThcQ96xTLR137Voe4OKvkP84f+&#xA;cW/M/k2OfWPLzSa75cjq8nFf9MtkG5Msaijoo6unzKqMVeG4q2CQajYjFX1n/wA43f8AOSM19Na+&#xA;SvOt1zu3pFo2syneQ9Ft7hj1c9Ec/a6HehKr6gxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV4D/wA5&#xA;Qfnm3lLTT5S8vXHHzLqMdby5jPxWds47HtLKPs91X4tjxOKviokk1O5OKroopZZUiiRpJZGCxxqC&#xA;zMzGgAA3JJxV9gfkD/zjBZ6RDa+afPNstxrLUlsdFlAaK17q86moeXuFOye7fZVfSOKuxV2KuxV2&#xA;KuxV2KuxV2KuxV2KuxV83fn9/wA4wWesRXPmjyNbLb6ytZb7RogFiuu7PAooEl7lej+zfaVfIE8E&#xA;1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVWAkGo2IxV9q/84v8A55t5t00eUvMNxy8y6dHWzuZD8V5b&#xA;IO57yxD7Xdl+Lc8jir37FXYq7FXYq7FXYq7FXYq7FXYq7FWJfmn+YeneQPJd95ivAJJYh6Vhak0M&#xA;91JURR/L9pqdFBOKvzn13XNT13WbzWdUnNxqF/K09zM37Tuamg7AdAOw2xVAYq+w/wDnGD8gYdIs&#xA;7bzz5pteWs3CiXRbGUf7yxMKrO6n/drg1UH7A/yj8Kr6RxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2Kvm7/nJ/8AIGHV7O588+VrXjrNupl1qxiH+9USirToo/3agFWA+2P8ofEq+PMVR+ha5qehazZ6&#xA;zpc5t9QsJVntpl/ZdDUVHcHoR3G2Kv0Y/Kz8w9O8/wDkux8xWYEcso9K/tQamC6joJY/l+0teqkH&#xA;FWW4q7FXYq7FXYq7FXYq7FXYq7FXw5/zlh+ZbeZ/Pp8v2U3LRvLZa3op+GS9P+9D+/AgRjw4tTri&#xA;rw7FXuP/ADi3+T8fnPzQ3mDWIPU8uaFIrGNxVLi82eOEg7MiD43H+qDs2KvuPFXYq7FXYq7FXYq/&#xA;KvFXYq7FXYq/VTFXYq7FXYq7FXYq+Hf+cpPyej8m+Z18w6PB6flzXZGb00FEtrzdpIgBsqOPjQf6&#xA;wGy4q8NxV7j/AM4n/mW3ljz6vl+9m46N5kK29GPwx3o/3nf/AGZJiP8ArDwxV9x4q7FXYq7FXYq7&#xA;FXYq7FXYqxH82fOqeSvy81rzDyAubWApYg71upiIoNu4EjAn2BxV+bksss0rzSuZJZGLyOxqzMxq&#xA;SSe5OKq+mabe6nqVrptjGZr29mjt7aIdXllYIi/SxxV+kn5b+R9P8j+S9M8t2VG+pxD61OP93XD/&#xA;ABTSmu/xOTTwFB2xVk2KuxV2KuxV2KuxV+VeKuxV2KuxV+qmKuxV2KuxV2KuxVjP5keR9P8APHkv&#xA;U/Ld7RfrkR+qzn/dNwnxQyim/wALgV8RUd8Vfm3qem3umaldabfRmG9sppLe5iPVJYmKOv0MMVUI&#xA;pZYZUmicxyxsHjdTRlZTUEEdwcVfpH+U3nVPOv5eaL5h5A3N1AEvgNqXUJMU+3YGRSR7EYqy7FXY&#xA;q7FXYq7FXYq7FXYq+XP+c2/NhS08veUoX3maTU7xQafClYYNu4JaX7sVfJ2Kvef+cPfJC63+Yk/m&#xA;C5j5WflyD1Yydx9buaxw/cgkb2IGKvtvFXYq7FXYq7FXYq7FX5V4q7FXYq7FX6qYq7FXYq7FXYq7&#xA;FXYq+JP+cwvJC6J+YkHmC2j42fmOD1ZCNh9btqRzfehjb3JOKvBsVfWH/OEnmwva+YfKcz19Fo9T&#xA;s0Jr8L0hnp4AFYvvxV9SYq7FXYq7FXYq7FXYq7FXwJ/zlJr51f8AOfWVVuUGmJBYQ+3pRBpB9E0j&#xA;4q8mxV9y/wDOIPllNK/KZNUZaXGu3c90WOx9KFvq0a/KsTMP9bFXt+KuxV2KuxV2KuxV2KvyrxV2&#xA;KuxV2Kv1UxV2KuxV2KuxV2KuxV4h/wA5feWU1X8pn1RVrcaFdwXQYbn0pm+rSL8qyqx/1cVfDWKv&#xA;Wf8AnFvXzpH5z6MrNxg1NJ7Cb39WItGPpmjTFX33irsVdirsVdirsVdirsVfmZ+YepnVPP3mTUq8&#xA;heaneTKf8l53KgbnYD3xVj2Kv0r/ACr0kaT+WvlfT6cWg0u0Eo/4saFWk/4djirKcVdirsVflXir&#xA;sVdirsVdirsVdirsVdirsVdirsVfqpirsVdirFvzT0ldW/LXzRp5FWn0u7Ef/GRYWaM/Q6jFX5qY&#xA;qyD8vdTbS/PnlzUVbj9U1OzmJ6fCk6FgemxGKv00xV2KuxV2KuxV2KuxV2KvyvuJ3nuJZ3ADyuzs&#xA;B0qxqaYqp4q/U+zt1trSC2U1WCNY1NKbIoXp9GKquKuxV2KvyrxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2Kv1UxV2KuxVSvLdbm0ntmNFnjaNjSuzqV6fTir8sMVVLed4LiKdAC8Tq6g9KqaiuKv1QxV2Kux&#xA;V2KuxV2KuxV2KvyvuIHguJYHILxOyMR0qpoaYqp4q/U+zuFubSC5UUWeNZFFa7Oobr9OKquKuxV2&#xA;KvyrxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kv1UxV2KuxVSvLhba0nuWFVgjaRhWmyKW6/Rir8sMVVL&#xA;eB57iKBCA8rqik9KsaCuKv1QxV2KuxV2KuxV2KuxV2KvzM/MPTDpfn7zJptOIs9TvIVH+Sk7hSNh&#xA;sR7Yqx7FX6V/lZqy6t+WvlfUAatPpdoZP+Miwqsg+h1OKspxV2KuxV+W36J1X/ljn/5Fv/TFXfon&#xA;Vf8Aljn/AORb/wBMVd+idV/5Y5/+Rb/0xV36J1X/AJY5/wDkW/8ATFUJirsVdirsVRf6J1X/AJY5&#xA;/wDkW/8ATFXfonVf+WOf/kW/9MVd+idV/wCWOf8A5Fv/AExV36J1X/ljn/5Fv/TFX6k4q7FXYqxb&#xA;809WXSfy180agTRoNLuzH/xkaFljH0uwxV+amKsg/L3TG1Tz55c05V5fW9Ts4SOvwvOgYnrsBir9&#xA;NMVdirsVdirsVdirsVdir4E/5yk0A6R+c+ssq8YNTSC/h9/ViCyH6Zo3xV5Nir7l/wCcQfMyar+U&#xA;yaWzVuNCu57Uqdz6UzfWY2+VZWUf6uKvb8VdirsVdirsVdirsVflXirsVdirsVfqpirsVdirsVdi&#xA;rsVdirxD/nL7zMmlflM+lq1LjXbuC1CjY+lC31mRvlWJVP8ArYq+GsVes/8AOLegHV/zn0ZmXlBp&#xA;iT383t6URWM/RNImKvvvFXYq7FXYq7FXYq7FXYq+XP8AnNvymXtPL3m2FN4Wk0y8YCvwvWaDfsAV&#xA;l+/FXydir3n/AJw987ron5iT+X7mTjZ+Y4PSjB2H1u2rJD96GRfckYq+28VdirsVdirsVdirsVfl&#xA;XirsVdirsVfqpirsVdirsVdirsVdir4k/wCcwvO663+YkHl+2k5WflyD0pANx9buaSTfcgjX2IOK&#xA;vBsVfWH/ADhJ5TKWvmHzZMlPWaPTLNyKfClJp6eIJaL7sVfUmKuxV2KuxV2KuxV2KuxViP5s+Sk8&#xA;6/l5rXl7iDc3UBexJ2pdQkSwb9gZFAPsTir83JYpYZXhlQxyxsUkRhRlZTQgg9wcVV9M1K90zUrX&#xA;UrGQw3tlNHcW0o6pLEwdG+hhir9JPy388af548l6Z5ksqL9ciH1qAf7puE+GaI13+FwaeIoe+Ksm&#xA;xV2KuxV2KuxV2KvyrxV2KuxV2Kv1UxV2KuxV2KuxV2KsZ/Mjzxp/kfyXqfmS9o31OI/VYD/u64f4&#xA;YYhTf4nIr4Cp7Yq/NvU9SvdT1K61K+kM17ezSXFzKeryysXdvpY4qoRRSSyJFEpeSRgqIoqSxNAA&#xA;PfFX6R/lN5KTyV+Xmi+XuIFzawB74jet1MTLPv3AkYgewGKsuxV2KuxV2KuxV2KuxV2KuxV8Of8A&#xA;OWH5aN5Y8+t5gsoeOjeZC1xVR8Md6P8AehP9mSJR/rHwxV4dir3L/nFv84Y/JvmdvL2sT+n5c12R&#xA;V9RzRLa82WOUk7Kjj4HP+qTsuKvuLFXYq7FXYq7FXYq/KvFXYq7FXYq/VTFXYq7FXYq7FXYq+Hf+&#xA;cpPzhj85eZ18vaPP6nlzQpGX1ENUubzdZJQRsyIPgQ/6xGzYq8NxV7j/AM4n/lo3mfz6vmC9h5aN&#xA;5bK3FWHwyXp/3nT/AGBBlP8AqjxxV9x4q7FXYq7FXYq7FXYq7FXYq7FWJfmn+Xmnef8AyXfeXbwi&#xA;OWUerYXRFTBdR1MUny/ZanVSRir859d0PU9C1m80bVIDb6hYStBcwt+y6Ghoe4PUHuN8VQGKvsP/&#xA;AJxg/P6HV7O28jeabrjrNuoi0W+lP+9USiiwOx/3agFFJ+2P8ofEq+kcVdirsVdirsVdirsVdirs&#xA;VdirsVdirsVdir5u/wCcn/z+i0ezufI3le55azcqYtZvoj/vLEw+KBGH+7XBox/YH+UfhVfHmKo7&#xA;RNG1HW9YstH02Iz39/MlvaxDblJIwVak7Ab7nFX6M/lZ+XmneQPJdj5dsyJJYh6t/dAUM91JQyyf&#xA;L9la9FAGKstxV2KuxV2KuxV2KuxV2KuxV2KuxV4D/wA5QfkY3m3TT5t8vW/LzLp0dLy2jHxXlsg7&#xA;DvLEPs92X4dzxGKviogg0OxGKr4J5reaOeCRop4mDxSoSrq6mqsrDcEHcEYq+v8A8gf+cn7PWIrb&#xA;yv55uVt9ZWkVjrMpCxXXZUnY0CS9g3R/ZvtKvpHFXYq7FXYq7FXYq7FXYq7FXYq7FXYq+bvz+/5y&#xA;fs9HiufK/ka5W51lqxX2sxENFa9mSBtw8viw2T3b7Kr5AnnmuJpJ55GlnlYvLK5LOzsaszMdySdy&#xA;TiqniqpBPNbzRzwSNFPEweKVCVdXU1VlYbgg7gjFX2n/AM46/wDORUPm+GHyt5pmWLzTEvG0u2oq&#xA;X6KPuE4H2l/a6juAq99xV2KuxV2KuxV2KuxV2KuxV2KuxV2Kvl//AJyR/wCcbpr6a686+SrXndvW&#xA;XWdGiG8h6tcW6jq56ug+11G9QVXyYQQaHYjFWsVe5fk9/wA5SeZ/JscGj+YVk13y5HRI+Tf6ZbIN&#xA;gIpGNHRR0R/kGUYq+vPI/wCZHkvzxp/13y3qcV5xFZ7WvC4h7Ulhajrv3pQ9icVZNirsVdirsVdi&#xA;rsVdirsVYz54/MjyX5H0/wCu+ZNTis+QrBa153E3akUK1dt+9KDuRir5D/OH/nKTzP5yjn0fy8sm&#xA;heXJKpJxb/TLlDsRLIpoiMOqJ8izDFXhuKuxV2KuxVUgnmt5o54JGiniYPFKhKurqaqysNwQdwRi&#xA;r7T/AOcdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsVdirsVdirsVdirsVdir&#xA;sVdirsVeA/nn/wA4v6b5ta48w+UhHp3mVqyXNmaJbXjdz4RSn+b7LH7W5LYq+ONc0LWdC1OfS9Zs&#xA;5bDULc8ZradSjr4Gh6g9iNj2xVAYqitN1PUtMvY77TbqayvYTWK5t5GilQ/5LoQwxV7f5I/5zC/M&#xA;TRFjtvMEEHmOzXYyS/6Nd0H/ABdGCh/2UZJ8cVe2eWf+cvvym1VFXVHu9CuDswuoGmiqf5ZLb1TT&#xA;3ZVxV6NpP5p/lrqyg6f5o0udj/usXcKyfTGzK4+7FWSW95aXKlraeOdRSrRsrjfp9knFXXF5aWyh&#xA;rmeOBTWjSMqDbr9ojFWOar+af5baSpOoeaNLgYdYzdwtJ47Rqxc/dirzjzN/zl9+U2lI66XJd67c&#xA;DZVtYGhir/lSXHpGnuqtirxPzv8A85hfmJrayW3l+CDy5ZtsJIv9Ju6H/i6QBB/sYwR44q8Q1LU9&#xA;S1O9kvtSupr29mNZbm4kaWVz/lO5LHFULiqO0bRNY1vUYtN0eymv7+c0itbdGkkam5PFQdgOpxVC&#xA;zwTW80kE8bRTxMUlicFXV1NGVlO4IOxBxVTxV2KuxVUgnmt5o54JGiniYPFKhKurqaqysNwQdwRi&#xA;r7T/AOcdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsVdirsVdirsVdirsVdir&#xA;sVdirsVYl+Yf5WeS/P8Apws/MViJZYwRa38X7u6gJ/33KB078Wqp7jFXyT+Zf/OJ/n3yw0175fU+&#xA;ZNGWrD6utL2Nf8u33L/OIt8hirxGWKWGV4pkaOWMlXjcFWVhsQQdwcVWYq7FXYq7FXYq7FXYq7FV&#xA;8UUksixRI0kjkKiKCWJPQADrir278tP+cT/Pvmdob3zAp8t6M1GP1ha3si/5FvsU+cpX5HFX1t+X&#xA;n5WeS/IGnGz8u2IilkAF1fy/vLqcj/fkpHTvxWijsMVeX/8AORX/ADjrD5vhm80+VoVi80xLyu7R&#xA;aKl+ij7hOB9lv2uh7EKviyeCa3mkgnjaKeJiksTgq6upoysp3BB2IOKqeKuxV2KqkE81vNHPBI0U&#xA;8TB4pUJV1dTVWVhuCDuCMVfaf/OOv/ORUPm+GHyt5pmWLzTEvG0u2oqX6KPuE4H2l/a6juAq99xV&#xA;2KuxV2KuxV2KuxV2KuxV2KuxV2KuxViPnX8pvy886o3+IdFgurkigvkBhuhTp+/iKyEDwJI9sVeE&#xA;+bP+cJLVy83lPzC0NalLPU4+a79vXhCkAf8AGI4q8o1//nFv859ILMujJqcC/wC7rCeKWvyjYxzH&#xA;/gMVYNqf5e+fNLZl1Hy5qdpx6maznRdu4YpQjbFUjnt7iBwk8TxORUK6lTTxocVdBb3E7lIInlcC&#xA;pVFLGnjQYqnmmfl7581RlXTvLmp3fLoYbOd137lglAN8VZzoH/OLf5z6uVZtGTTIG/3dfzxRU+ca&#xA;mSYf8Bir1fyn/wA4SWqFJvNnmFpqUL2emR8F27evMGJB/wCMQxV7t5K/Kb8vPJSL/h7RYLW5Aob5&#xA;wZro16/v5S0gB8AQPbFWXYq7FXYq8C/5yK/5x1h83wzeafK0KxeaYl5XdotFS/RR9wnA+y37XQ9i&#xA;FXxZPBNbzSQTxtFPExSWJwVdXU0ZWU7gg7EHFVPFXYq7FVSCea3mjngkaKeJg8UqEq6upqrKw3BB&#xA;3BGKvtP/AJx1/wCciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsVdirsVdirsVdir&#xA;sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeBf8AORX/ADjrD5vhm80+VoVi80xL&#xA;yu7RaKl+ij7hOB9lv2uh7EKviyeCa3mkgnjaKeJiksTgq6upoysp3BB2IOKqeKuxV2KqkE81vNHP&#xA;BI0U8TB4pUJV1dTVWVhuCDuCMVfaf/OOv/ORUPm+GHyt5pmWLzTEvG0u2oqX6KPuE4H2l/a6juAq&#xA;99xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvAv+civ+cd&#xA;YfN8M3mnytCsXmmJeV3aLRUv0UfcJwPst+10PYhV8WTwTW80kE8bRTxMUlicFXV1NGVlO4IOxBxV&#xA;TxV2KuxVUgnmt5o54JGiniYPFKhKurqaqysNwQdwRir7T/5x1/5yKh83ww+VvNMyxeaYl42l21FS&#xA;/RR9wnA+0v7XUdwFXvuKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV4F/zkV/zjrD5vhm80+VoVi80xLyu7RaKl+ij7hOB9lv2uh7EKviyeCa3mkgnjaKeJiksT&#xA;gq6upoysp3BB2IOKqeKuxV2KqkE81vNHPBI0U8TB4pUJV1dTVWVhuCDuCMVfaf8Azjr/AM5FQ+b4&#xA;YfK3mmZYvNMS8bS7aipfoo+4TgfaX9rqO4Cr33FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq8C/wCciv8AnHWHzfDN5p8rQrF5piXld2i0VL9FH3CcD7LftdD2&#xA;IVfFk8E1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVU8VdirsVVIJ5reaOeCRop4mDxSoSrq6mqsrDcE&#xA;HcEYq+0/+cdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsVdirsVdirsVdirsV&#xA;dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeBf85Ff846w+b4ZvNPlaFYvNMS8ru0W&#xA;ipfoo+4TgfZb9roexCr4sngmt5pIJ42iniYpLE4KurqaMrKdwQdiDiqnirsVdiqpBPNbzRzwSNFP&#xA;EweKVCVdXU1VlYbgg7gjFX2n/wA46/8AORUPm+GHyt5pmWLzTEvG0u2oqX6KPuE4H2l/a6juAq99&#xA;xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvAv+civ+cdYf&#xA;N8M3mnytCsXmmJeV3aLRUv0UfcJwPst+10PYhV8WTwTW80kE8bRTxMUlicFXV1NGVlO4IOxBxVTx&#xA;V2KuxV7f/wA46/kHqfnbU4PMmrGaw8rWEweOaNmimu5omrwgdaMqKw+OQfJfiqVVfcuKuxV2KuxV&#xA;2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvAv+civ+cdYfN8M3mny&#xA;tCsXmmJeV3aLRUv0UfcJwPst+10PYhV8WTwTW80kE8bRTxMUlicFXV1NGVlO4IOxBxVTxV7Z/wA4&#xA;+f8AOPl759vU13XUe28oWz7ndHvXQ7xRHqIwdncf6q71KqvuGxsbKwsoLGxgS2s7ZFit7eJQiIiC&#xA;iqqjYADFVfFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq8C/5yK/5x1h83wzeafK0KxeaYl5XdotFS/RR9wnA+y37XQ9iFXi/5B/8AOOup+dtTOreZIJrD&#xA;ytYTNHNG4aKa7mibi8CVoyorCkj/AOxHxVKqvt6xsbKwsoLGxgS2s7ZFit7eJQiIiCiqqjYADFVf&#xA;FX//2Q==</xmpGImg:image>
+ </rdf:li>
+ </rdf:Alt>
+ </xmp:Thumbnails>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
+ xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
+ xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#">
+ <xmpMM:OriginalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</xmpMM:OriginalDocumentID>
+ <xmpMM:DocumentID>xmp.did:FF7F11740720681197A58AA60A3A792E</xmpMM:DocumentID>
+ <xmpMM:InstanceID>uuid:290e4a2c-d2d5-214f-ac9a-91dbf5b74460</xmpMM:InstanceID>
+ <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
+ <xmpMM:History>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/pdf to &lt;unknown&gt;</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:D07F11740720681191099C3B601C4548</stEvt:instanceID>
+ <stEvt:when>2008-04-17T14:19:10+05:30</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/pdf to &lt;unknown&gt;</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FC7F117407206811B628E3BF27C8C41B</stEvt:instanceID>
+ <stEvt:when>2008-05-22T14:51:08-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FD7F117407206811B628E3BF27C8C41B</stEvt:instanceID>
+ <stEvt:when>2008-05-22T15:15:38-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:0CC3BD25102DDD1181B594070CEB88D9</stEvt:instanceID>
+ <stEvt:when>2008-05-28T17:07:17-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:F77F117407206811ACFEA91EFF4B1542</stEvt:instanceID>
+ <stEvt:when>2011-08-23T17:31:58-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FD7F11740720681197A58AA60A3A792E</stEvt:instanceID>
+ <stEvt:when>2011-08-25T16:11:20-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FE7F11740720681197A58AA60A3A792E</stEvt:instanceID>
+ <stEvt:when>2011-08-25T16:20:54-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FF7F11740720681197A58AA60A3A792E</stEvt:instanceID>
+ <stEvt:when>2011-08-25T16:21:13-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpMM:History>
+ <xmpMM:DerivedFrom rdf:parseType="Resource">
+ <stRef:instanceID>xmp.iid:FE7F11740720681197A58AA60A3A792E</stRef:instanceID>
+ <stRef:documentID>xmp.did:FE7F11740720681197A58AA60A3A792E</stRef:documentID>
+ <stRef:originalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</stRef:originalDocumentID>
+ <stRef:renditionClass>proof:pdf</stRef:renditionClass>
+ </xmpMM:DerivedFrom>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
+ <illustrator:StartupProfile>Basic RGB</illustrator:StartupProfile>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+ xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+ xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
+ <xmpTPg:NPages>1</xmpTPg:NPages>
+ <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
+ <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
+ <xmpTPg:MaxPageSize rdf:parseType="Resource">
+ <stDim:w>20.000000</stDim:w>
+ <stDim:h>20.000000</stDim:h>
+ <stDim:unit>Pixels</stDim:unit>
+ </xmpTPg:MaxPageSize>
+ <xmpTPg:PlateNames>
+ <rdf:Seq>
+ <rdf:li>Cyan</rdf:li>
+ <rdf:li>Magenta</rdf:li>
+ <rdf:li>Yellow</rdf:li>
+ <rdf:li>Black</rdf:li>
+ </rdf:Seq>
+ </xmpTPg:PlateNames>
+ <xmpTPg:SwatchGroups>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Default Swatch Group</xmpG:groupName>
+ <xmpG:groupType>0</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>White</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>Black</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Red</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Yellow</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Green</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Cyan</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Blue</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Magenta</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>193</xmpG:red>
+ <xmpG:green>39</xmpG:green>
+ <xmpG:blue>45</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>237</xmpG:red>
+ <xmpG:green>28</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>241</xmpG:red>
+ <xmpG:green>90</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>247</xmpG:red>
+ <xmpG:green>147</xmpG:green>
+ <xmpG:blue>30</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>251</xmpG:red>
+ <xmpG:green>176</xmpG:green>
+ <xmpG:blue>59</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>252</xmpG:red>
+ <xmpG:green>238</xmpG:green>
+ <xmpG:blue>33</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>217</xmpG:red>
+ <xmpG:green>224</xmpG:green>
+ <xmpG:blue>33</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>140</xmpG:red>
+ <xmpG:green>198</xmpG:green>
+ <xmpG:blue>63</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>57</xmpG:red>
+ <xmpG:green>181</xmpG:green>
+ <xmpG:blue>74</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>146</xmpG:green>
+ <xmpG:blue>69</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>104</xmpG:green>
+ <xmpG:blue>55</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>34</xmpG:red>
+ <xmpG:green>181</xmpG:green>
+ <xmpG:blue>115</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>169</xmpG:green>
+ <xmpG:blue>157</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>41</xmpG:red>
+ <xmpG:green>171</xmpG:green>
+ <xmpG:blue>226</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>113</xmpG:green>
+ <xmpG:blue>188</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>46</xmpG:red>
+ <xmpG:green>49</xmpG:green>
+ <xmpG:blue>146</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>27</xmpG:red>
+ <xmpG:green>20</xmpG:green>
+ <xmpG:blue>100</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>102</xmpG:red>
+ <xmpG:green>45</xmpG:green>
+ <xmpG:blue>145</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>147</xmpG:red>
+ <xmpG:green>39</xmpG:green>
+ <xmpG:blue>143</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>158</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>93</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>212</xmpG:red>
+ <xmpG:green>20</xmpG:green>
+ <xmpG:blue>90</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>237</xmpG:red>
+ <xmpG:green>30</xmpG:green>
+ <xmpG:blue>121</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>199</xmpG:red>
+ <xmpG:green>178</xmpG:green>
+ <xmpG:blue>153</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>153</xmpG:red>
+ <xmpG:green>134</xmpG:green>
+ <xmpG:blue>117</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>115</xmpG:red>
+ <xmpG:green>99</xmpG:green>
+ <xmpG:blue>87</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>83</xmpG:red>
+ <xmpG:green>71</xmpG:green>
+ <xmpG:blue>65</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>198</xmpG:red>
+ <xmpG:green>156</xmpG:green>
+ <xmpG:blue>109</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>166</xmpG:red>
+ <xmpG:green>124</xmpG:green>
+ <xmpG:blue>82</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>140</xmpG:red>
+ <xmpG:green>98</xmpG:green>
+ <xmpG:blue>57</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>117</xmpG:red>
+ <xmpG:green>76</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>96</xmpG:red>
+ <xmpG:green>56</xmpG:green>
+ <xmpG:blue>19</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>66</xmpG:red>
+ <xmpG:green>33</xmpG:green>
+ <xmpG:blue>11</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Grays</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>26</xmpG:red>
+ <xmpG:green>26</xmpG:green>
+ <xmpG:blue>26</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>51</xmpG:red>
+ <xmpG:green>51</xmpG:green>
+ <xmpG:blue>51</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>77</xmpG:red>
+ <xmpG:green>77</xmpG:green>
+ <xmpG:blue>77</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>102</xmpG:red>
+ <xmpG:green>102</xmpG:green>
+ <xmpG:blue>102</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>128</xmpG:red>
+ <xmpG:green>128</xmpG:green>
+ <xmpG:blue>128</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>153</xmpG:red>
+ <xmpG:green>153</xmpG:green>
+ <xmpG:blue>153</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>179</xmpG:red>
+ <xmpG:green>179</xmpG:green>
+ <xmpG:blue>179</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>204</xmpG:red>
+ <xmpG:green>204</xmpG:green>
+ <xmpG:blue>204</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>230</xmpG:red>
+ <xmpG:green>230</xmpG:green>
+ <xmpG:blue>230</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>242</xmpG:red>
+ <xmpG:green>242</xmpG:green>
+ <xmpG:blue>242</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Splash</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=214 G=149 B=68</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>214</xmpG:red>
+ <xmpG:green>149</xmpG:green>
+ <xmpG:blue>68</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=71 G=152 B=237</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>71</xmpG:red>
+ <xmpG:green>152</xmpG:green>
+ <xmpG:blue>237</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=42 G=81 B=224</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>42</xmpG:red>
+ <xmpG:green>81</xmpG:green>
+ <xmpG:blue>224</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=180 G=58 B=228</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>180</xmpG:red>
+ <xmpG:green>58</xmpG:green>
+ <xmpG:blue>228</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpTPg:SwatchGroups>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
+ <pdf:Producer>Adobe PDF library 9.00</pdf:Producer>
+ </rdf:Description>
+ </rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end="w"?> endstream endobj 3 0 obj <</Count 1/Kids[5 0 R]/Type/Pages>> endobj 5 0 obj <</ArtBox[2.0 3.0 18.0 19.0]/BleedBox[0.0 0.0 20.0 20.0]/Contents 6 0 R/MediaBox[0.0 0.0 20.0 20.0]/Parent 3 0 R/Resources<</ExtGState<</GS0 7 0 R>>/Properties<</MC0<</Color[65535 20224 20224]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 2)/Visible true>>/MC1<</Color[20224 20224 65535]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 4)/Visible true>>/MC2<</Color[0 21845 0]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 5)/Visible true>>>>>>/TrimBox[0.0 0.0 20.0 20.0]/Type/Page>> endobj 6 0 obj <</Filter/FlateDecode/Length 238>>stream
+H‰ÌR;®Â0ì÷{oÖŽm9-Ñ(^ý„øï!*nÏ®˜
+0000000016 00000 n
+0000000076 00000 n
+0000048777 00000 n
+0000000000 00000 f
+0000048828 00000 n
+0000049382 00000 n
+0000049688 00000 n
+0000049800 00000 n
+trailer <</Size 9/Root 1 0 R/Info 8 0 R/ID[<3661EF74478645EC8F1B98E18A5E6001><1DA54DD892824505A9E35B2A0D648A58>]>> startxref 49975 %%EOF \ No newline at end of file
diff --git a/release/darwin/Blender.app/Contents/Resources/zoomout.pdf b/release/darwin/Blender.app/Contents/Resources/zoomout.pdf
new file mode 100644
index 00000000000..6ded60dbc0f
--- /dev/null
+++ b/release/darwin/Blender.app/Contents/Resources/zoomout.pdf
@@ -0,0 +1,676 @@
+%PDF-1.5 %âãÏÓ
+1 0 obj <</Metadata 2 0 R/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 48694/Subtype/XML/Type/Metadata>>stream
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.2-c063 53.352624, 2008/07/30-18:05:41 ">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about=""
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <dc:format>application/pdf</dc:format>
+ <dc:title>
+ <rdf:Alt>
+ <rdf:li xml:lang="x-default">ZoomoutCursor</rdf:li>
+ </rdf:Alt>
+ </dc:title>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmp="http://ns.adobe.com/xap/1.0/"
+ xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
+ <xmp:CreatorTool>Adobe Illustrator CS4</xmp:CreatorTool>
+ <xmp:CreateDate>2011-08-25T16:23:51-07:00</xmp:CreateDate>
+ <xmp:ModifyDate>2011-08-25T16:23:51-07:00</xmp:ModifyDate>
+ <xmp:MetadataDate>2011-08-25T16:23:51-07:00</xmp:MetadataDate>
+ <xmp:Thumbnails>
+ <rdf:Alt>
+ <rdf:li rdf:parseType="Resource">
+ <xmpGImg:width>256</xmpGImg:width>
+ <xmpGImg:height>256</xmpGImg:height>
+ <xmpGImg:format>JPEG</xmpGImg:format>
+ <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYqx&#xA;Hzr+bP5eeSkb/EOtQWtyBUWKEzXRr0/cRBpAD4kAe+KvCvNv/ObdpGzw+UvL7TUqFvNTfgu3Q+hC&#xA;SSD/AMZBiryfX/8AnKT859XLKusppkDf7psIIoqfKRhJMP8Ag8VYPqf5h+ftUJ/SXmTU7wN1Wa8n&#xA;de+wUvQDc4qkU9xcTuHnleVwKBnYsaeFTiroLi4gcvBK8TkULIxU08KjFU90z8w/P2lkfo3zJqdm&#xA;F6LDeTovbYqHoRsMVZxoH/OUn5z6QVVtZTU4F/3TfwRS1+ciiOY/8Hir1jyn/wA5t2jlIfNvl5oT&#xA;sGvNMk5rv1/cTFSAP+MpxV7r5K/Nn8vPOqL/AIe1qC6uSKmxcmG6FOv7iULIQPEAj3xVl2KuxV2K&#xA;uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxViX5h/mn5L8gacLzzFfCKWQE2thF+8upyP&#xA;99xA9O3JqKO5xV8k/mX/AM5YeffM7TWXl8ny3ozVUfV2reyL/l3GxSvhGFp05HFXiMsss0ryzO0k&#xA;shLPI5LMzHckk7k4qsxV2KuxV2KuxV2KuxV2Kr4pZYZUlhdo5YyGSRCVZWG4II3BxV7d+Wn/ADlh&#xA;598sNDZeYGPmTRlop+sNS9jX/IuNy/ylDfMYq+tvy8/NPyX5/wBON55dvhLLGAbqwl/d3UBP+/Ii&#xA;enbktVPY4qy3FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXgP55/85Qab5Sa48veUjHqP&#xA;mVax3N4aPbWbdx4Syj+X7Kn7W4K4q+ONc13Wdd1OfVNZvJb/AFC4PKa5nYu7eAqegHYDYdsVQGKo&#xA;rTdM1LU72Ox021mvb2Y0itreNpZXP+SiAscVe3+SP+cPfzE1tY7nzBPB5cs23Mcv+k3dD/xTGQg/&#xA;2UgI8MVe2eWf+cQfym0pFbVEu9duBuxup2hiqP5Y7b0jT2ZmxV6NpP5WflrpKgaf5X0uBh/uwWkL&#xA;SfTIys5+/FWSW9naWylbaCOBTSqxqqDbp9kDFXXFnaXKhbmCOdRWiyKrjfr9oHFWN6t+Vn5a6spG&#xA;oeV9LnY/7sNpCsn0SKquPvxV5z5m/wCcQfym1VGbS0u9CuDuptZ2miqf5o7n1TT2VlxV4n53/wCc&#xA;PfzE0RZLny/PB5js13EcX+jXdB/xTISh/wBjISfDFXiGpaZqWmXsljqVrNZXsJpLbXEbRSof8pHA&#xA;YYqhcVR+h67rOhanBqmjXkthqFueUNzAxR18RUdQe4Ox74q+x/yM/wCcoNN82tb+XvNpj07zK1I7&#xA;a8FEtrxuw8IpT/L9lj9nchcVe/Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq+X/8AnJH/AJyR&#xA;msZrryV5KuuF2lYtZ1mI7xno1vbsOjjo7j7PQb1IVfJhJJqdycVaxV7j+T//ADi35o85xwax5gaT&#xA;QvLklHjLL/plwh3BhjcURGHR3+YVhir698j/AJb+S/I+n/UvLemRWfIUnuqc7ibvWWZqu2/atB2A&#xA;xVk2KuxV2KuxV2KuxV2KuxVjPnj8t/JfnjT/AKl5k0yK84ikF1ThcQ96xTLR137Voe4OKvkP84f+&#xA;cW/M/k2OfWPLzSa75cjq8nFf9MtkG5Msaijoo6unzKqMVeG4q2CQajYjFX1n/wA43f8AOSM19Na+&#xA;SvOt1zu3pFo2syneQ9Ft7hj1c9Ec/a6HehKr6gxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV4D/wA5&#xA;Qfnm3lLTT5S8vXHHzLqMdby5jPxWds47HtLKPs91X4tjxOKviokk1O5OKroopZZUiiRpJZGCxxqC&#xA;zMzGgAA3JJxV9gfkD/zjBZ6RDa+afPNstxrLUlsdFlAaK17q86moeXuFOye7fZVfSOKuxV2KuxV2&#xA;KuxV2KuxV2KuxV2KuxV83fn9/wA4wWesRXPmjyNbLb6ytZb7RogFiuu7PAooEl7lej+zfaVfIE8E&#xA;1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVWAkGo2IxV9q/84v8A55t5t00eUvMNxy8y6dHWzuZD8V5b&#xA;IO57yxD7Xdl+Lc8jir37FXYq7FXYq7FXYq7FXYq7FXYq7FWJfmn+YeneQPJd95ivAJJYh6Vhak0M&#xA;91JURR/L9pqdFBOKvzn13XNT13WbzWdUnNxqF/K09zM37Tuamg7AdAOw2xVAYq+w/wDnGD8gYdIs&#xA;7bzz5pteWs3CiXRbGUf7yxMKrO6n/drg1UH7A/yj8Kr6RxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2Kvm7/nJ/8AIGHV7O588+VrXjrNupl1qxiH+9USirToo/3agFWA+2P8ofEq+PMVR+ha5qehazZ6&#xA;zpc5t9QsJVntpl/ZdDUVHcHoR3G2Kv0Y/Kz8w9O8/wDkux8xWYEcso9K/tQamC6joJY/l+0teqkH&#xA;FWW4q7FXYq7FXYq7FXYq7FXYq7FXw5/zlh+ZbeZ/Pp8v2U3LRvLZa3op+GS9P+9D+/AgRjw4tTri&#xA;rw7FXuP/ADi3+T8fnPzQ3mDWIPU8uaFIrGNxVLi82eOEg7MiD43H+qDs2KvuPFXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq+Hf+cpPyej8m+Z18w6PB6flzXZGb00FEtrzdpIgBsqOPjQf6wGy4&#xA;q8NxV7j/AM4n/mW3ljz6vl+9m46N5kK29GPwx3o/3nf/AGZJiP8ArDwxV9x4q7FXYq7FXYq7FXYq&#xA;7FXYqxH82fOqeSvy81rzDyAubWApYg71upiIoNu4EjAn2BxV+bksss0rzSuZJZGLyOxqzMxqSSe5&#xA;OKq+mabe6nqVrptjGZr29mjt7aIdXllYIi/SxxV+kn5b+R9P8j+S9M8t2VG+pxD61OP93XD/ABTS&#xA;mu/xOTTwFB2xVk2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVjP5keR9P8APHkvU/Ld7Rfr&#xA;kR+qzn/dNwnxQyim/wALgV8RUd8Vfm3qem3umaldabfRmG9sppLe5iPVJYmKOv0MMVUIpZYZUmic&#xA;xyxsHjdTRlZTUEEdwcVfpH+U3nVPOv5eaL5h5A3N1AEvgNqXUJMU+3YGRSR7EYqy7FXYq7FXYq7F&#xA;XYq7FXYq+XP+c2/NhS08veUoX3maTU7xQafClYYNu4JaX7sVfJ2Kvef+cPfJC63+Yk/mC5j5Wfly&#xA;D1Yydx9buaxw/cgkb2IGKvtvFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq+JP+cwvJ&#xA;C6J+YkHmC2j42fmOD1ZCNh9btqRzfehjb3JOKvBsVfWH/OEnmwva+YfKcz19Fo9Ts0Jr8L0hnp4A&#xA;FYvvxV9SYq7FXYq7FXYq7FXYq7FXwJ/zlJr51f8AOfWVVuUGmJBYQ+3pRBpB9E0j4q8mxV9y/wDO&#xA;IPllNK/KZNUZaXGu3c90WOx9KFvq0a/KsTMP9bFXt+KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV&#xA;2KuxV2KuxV4h/wA5feWU1X8pn1RVrcaFdwXQYbn0pm+rSL8qyqx/1cVfDWKvWf8AnFvXzpH5z6Mr&#xA;Nxg1NJ7Cb39WItGPpmjTFX33irsVdirsVdirsVdirsVfmZ+YepnVPP3mTUq8heaneTKf8l53Kgbn&#xA;YD3xVj2Kv0r/ACr0kaT+WvlfT6cWg0u0Eo/4saFWk/4djirKcVdirsVfmBquq6oNUvALycATyf7s&#xA;f+c++KoX9Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/64q79Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/&#xA;64q79Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/64q79Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/64q7&#xA;9Lar/wAtk/8AyMf+uKu/S2q/8tk//Ix/64q79Lar/wAtk/8AyMf+uKv1JxV2KuxVi35p6Surflr5&#xA;o08irT6XdiP/AIyLCzRn6HUYq/NTFWQfl7qbaX588uaircfqmp2cxPT4UnQsD02IxV+mmKuxV2Ku&#xA;xV2KuxV2KuxV+V9xO89xLO4AeV2dgOlWNTTFVPFX6n2duttaQWymqwRrGppTZFC9PoxVVxV2KuxV&#xA;+W2rf8dW8/4zyf8AEziqExV2KuxV2KuxV2KuxV2KuxV2KuxV+qmKuxV2KqV5brc2k9sxos8bRsaV&#xA;2dSvT6cVflhiqpbzvBcRToAXidXUHpVTUVxV+qGKuxV2KuxV2KuxV2KuxV+V9xA8FxLA5BeJ2RiO&#xA;lVNDTFVPFX6n2dwtzaQXKiizxrIorXZ1DdfpxVVxV2KuxV+W2rf8dW8/4zyf8TOKoTFXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FX6qYq7FXYqpXlwttaT3LCqwRtIwrTZFLdfoxV+WGKqlvA89xFAhAeV1RSelW&#xA;NBXFX6oYq7FXYq7FXYq7FXYq7FX5mfmHph0vz95k02nEWep3kKj/ACUncKRsNiPbFWPYq/Sv8rNW&#xA;XVvy18r6gDVp9LtDJ/xkWFVkH0OpxVlOKuxV2Kvy21b/AI6t5/xnk/4mcVQmKuxV2KuxV2KuxV2K&#xA;uxV2KuxV2Kv1UxV2KuxVi35p6suk/lr5o1AmjQaXdmP/AIyNCyxj6XYYq/NTFWQfl7pjap588uac&#xA;q8vrep2cJHX4XnQMT12AxV+mmKuxV2KuxV2KuxV2KuxV8Cf85SaAdI/OfWWVeMGppBfw+/qxBZD9&#xA;M0b4q8mxV9y/84g+Zk1X8pk0tmrcaFdz2pU7n0pm+sxt8qyso/1cVe34q7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXiH/OX3mZNK/KZ9LVqXGu3cFqFGx9KFvrMjfKsSqf9bFXw1ir1n/n&#xA;FvQDq/5z6MzLyg0xJ7+b29KIrGfomkTFX33irsVdirsVdirsVdirsVfLn/ObflMvaeXvNsKbwtJp&#xA;l4wFfhes0G/YArL9+Kvk7FXvP/OHvnddE/MSfy/cycbPzHB6UYOw+t21ZIfvQyL7kjFX23irsVdi&#xA;rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVfEn/OYXnddb/MSDy/bScrPy5B6UgG4+t3NJJvu&#xA;QRr7EHFXg2KvrD/nCTymUtfMPmyZKes0emWbkU+FKTT08QS0X3Yq+pMVdirsVdirsVdirsVdirEf&#xA;zZ8lJ51/LzWvL3EG5uoC9iTtS6hIlg37AyKAfYnFX5uSxSwyvDKhjljYpIjCjKymhBB7g4qr6ZqV&#xA;7pmpWupWMhhvbKaO4tpR1SWJg6N9DDFX6Sflv540/wA8eS9M8yWVF+uRD61AP903CfDNEa7/AAuD&#xA;TxFD3xVk2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVjP5keeNP8j+S9T8yXtG+pxH6rAf9&#xA;3XD/AAwxCm/xORXwFT2xV+bep6le6nqV1qV9IZr29mkuLmU9XllYu7fSxxVQiiklkSKJS8kjBURR&#xA;UliaAAe+Kv0j/KbyUnkr8vNF8vcQLm1gD3xG9bqYmWffuBIxA9gMVZdirsVdirsVdirsVdirsVdi&#xA;r4c/5yw/LRvLHn1vMFlDx0bzIWuKqPhjvR/vQn+zJEo/1j4Yq8OxV7l/zi3+cMfk3zO3l7WJ/T8u&#xA;a7Iq+o5oltebLHKSdlRx8Dn/AFSdlxV9xYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXw7/&#xA;AM5SfnDH5y8zr5e0ef1PLmhSMvqIapc3m6ySgjZkQfAh/wBYjZsVeG4q9x/5xP8Ay0bzP59XzBew&#xA;8tG8tlbirD4ZL0/7zp/sCDKf9UeOKvuPFXYq7FXYq7FXYq7FXYq7FXYqxL80/wAvNO8/+S77y7eE&#xA;Ryyj1bC6IqYLqOpik+X7LU6qSMVfnPruh6noWs3mjapAbfULCVoLmFv2XQ0ND3B6g9xviqAxV9h/&#xA;84wfn9Dq9nbeRvNN1x1m3URaLfSn/eqJRRYHY/7tQCik/bH+UPiVfSOKuxV2KuxV2KuxV2KuxV2K&#xA;uxV2KuxV2KuxV83f85P/AJ/RaPZ3Pkbyvc8tZuVMWs30R/3liYfFAjD/AHa4NGP7A/yj8Kr48xVH&#xA;aJo2o63rFlo+mxGe/v5kt7WIbcpJGCrUnYDfc4q/Rn8rPy807yB5LsfLtmRJLEPVv7oChnupKGWT&#xA;5fsrXooAxVluKuxV2KuxV2KuxV2KuxV2KuxV2KvAf+coPyMbzbpp82+Xrfl5l06Ol5bRj4ry2Qdh&#xA;3liH2e7L8O54jFXxUQQaHYjFV8E81vNHPBI0U8TB4pUJV1dTVWVhuCDuCMVfX/5A/wDOT9nrEVt5&#xA;X883K2+srSKx1mUhYrrsqTsaBJewbo/s32lX0jirsVdirsVdirsVdirsVdirsVdirsVfN35/f85P&#xA;2ejxXPlfyNcrc6y1Yr7WYiGitezJA24eXxYbJ7t9lV8gTzzXE0k88jSzysXllclnZ2NWZmO5JO5J&#xA;xVTxVUgnmt5o54JGiniYPFKhKurqaqysNwQdwRir7T/5x1/5yKh83ww+VvNMyxeaYl42l21FS/RR&#xA;9wnA+0v7XUdwFXvuKuxV2KuxV2KuxV2KuxV2KuxV2KuxV8v/APOSP/ON019NdedfJVrzu3rLrOjR&#xA;DeQ9WuLdR1c9XQfa6jeoKr5MIINDsRirWKvcvye/5yk8z+TY4NH8wrJrvlyOiR8m/wBMtkGwEUjG&#xA;joo6I/yDKMVfXnkf8yPJfnjT/rvlvU4rziKz2teFxD2pLC1HXfvSh7E4qybFXYq7FXYq7FXYq7FX&#xA;Yqxnzx+ZHkvyPp/13zJqcVnyFYLWvO4m7UihWrtv3pQdyMVfIf5w/wDOUnmfzlHPo/l5ZNC8uSVS&#xA;Ti3+mXKHYiWRTREYdUT5FmGKvDcVdirsVdiqpBPNbzRzwSNFPEweKVCVdXU1VlYbgg7gjFX2n/zj&#xA;r/zkVD5vhh8reaZli80xLxtLtqKl+ij7hOB9pf2uo7gKvfcVdirsVdirsVdirsVdirsVdirsVdir&#xA;wH88/wDnF/TfNrXHmHykI9O8ytWS5szRLa8bufCKU/zfZY/a3JbFXxxrmhazoWpz6XrNnLYahbnj&#xA;NbTqUdfA0PUHsRse2KoDFUVpup6lpl7HfabdTWV7CaxXNvI0UqH/ACXQhhir2/yR/wA5hfmJoix2&#xA;3mCCDzHZrsZJf9Gu6D/i6MFD/soyT44q9s8s/wDOX35Taqirqj3ehXB2YXUDTRVP8slt6pp7sq4q&#xA;9G0n80/y11ZQdP8ANGlzsf8AdYu4Vk+mNmVx92Kskt7y0uVLW08c6ilWjZXG/T7JOKuuLy0tlDXM&#xA;8cCmtGkZUG3X7RGKsc1X80/y20lSdQ80aXAw6xm7haTx2jVi5+7FXnHmb/nL78ptKR10uS7124Gy&#xA;rawNDFX/ACpLj0jT3VWxV4n53/5zC/MTW1ktvL8EHlyzbYSRf6Td0P8AxdIAg/2MYI8cVeIalqep&#xA;aneyX2pXU17ezGstzcSNLK5/yncljiqFxVHaNomsa3qMWm6PZTX9/OaRWtujSSNTcnioOwHU4qhZ&#xA;4JreaSCeNop4mKSxOCrq6mjKyncEHYg4qp4q7FXYqqQTzW80c8EjRTxMHilQlXV1NVZWG4IO4IxV&#xA;9p/846/85FQ+b4YfK3mmZYvNMS8bS7aipfoo+4TgfaX9rqO4Cr33FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYqxL8w/ys8l+f9OFn5isRLLGCLW/i/d3UBP8AvuUDp34tVT3GKvkn8y/+cT/Pvlhpr3y+p8ya&#xA;MtWH1daXsa/5dvuX+cRb5DFXiMsUsMrxTI0csZKvG4KsrDYgg7g4qsxV2KuxV2KuxV2KuxV2Kr4o&#xA;pJZFiiRpJHIVEUEsSegAHXFXt35af84n+ffM7Q3vmBT5b0ZqMfrC1vZF/wAi32KfOUr8jir62/Lz&#xA;8rPJfkDTjZ+XbERSyAC6v5f3l1OR/vyUjp34rRR2GKvL/wDnIr/nHWHzfDN5p8rQrF5piXld2i0V&#xA;L9FH3CcD7LftdD2IVfFk8E1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVU8VdirsVVIJ5reaOeCRop4m&#xA;DxSoSrq6mqsrDcEHcEYq+0/+cdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsV&#xA;dirsVdirsVdirsVdirsVdirsVdirEfOv5Tfl551Rv8Q6LBdXJFBfIDDdCnT9/EVkIHgSR7Yq8J82&#xA;f84SWrl5vKfmFoa1KWepx8137evCFIA/4xHFXlGv/wDOLf5z6QWZdGTU4F/3dYTxS1+UbGOY/wDA&#xA;YqwbU/y98+aWzLqPlzU7Tj1M1nOi7dwxShG2KpHPb3EDhJ4nicioV1KmnjQ4q6C3uJ3KQRPK4FSq&#xA;KWNPGgxVPNM/L3z5qjKuneXNTu+XQw2c7rv3LBKAb4qznQP+cW/zn1cqzaMmmQN/u6/niip841Mk&#xA;w/4DFXq/lP8A5wktUKTebPMLTUoXs9Mj4Lt29eYMSD/xiGKvdvJX5Tfl55KRf8PaLBa3IFDfODNd&#xA;GvX9/KWkAPgCB7Yqy7FXYq7FXgX/ADkV/wA46w+b4ZvNPlaFYvNMS8ru0Wipfoo+4TgfZb9roexC&#xA;r4sngmt5pIJ42iniYpLE4KurqaMrKdwQdiDiqnirsVdiqpBPNbzRzwSNFPEweKVCVdXU1VlYbgg7&#xA;gjFX2n/zjr/zkVD5vhh8reaZli80xLxtLtqKl+ij7hOB9pf2uo7gKvfcVdirsVdirsVdirsVdirs&#xA;VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirwL/nIr/nHWHzfDN5p8rQrF5piXld2i0V&#xA;L9FH3CcD7LftdD2IVfFk8E1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVU8VdirsVVIJ5reaOeCRop4m&#xA;DxSoSrq6mqsrDcEHcEYq+0/+cdf+ciofN8MPlbzTMsXmmJeNpdtRUv0UfcJwPtL+11HcBV77irsV&#xA;dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeBf85Ff846w+b4Zv&#xA;NPlaFYvNMS8ru0Wipfoo+4TgfZb9roexCr4sngmt5pIJ42iniYpLE4KurqaMrKdwQdiDiqnirsVd&#xA;iqpBPNbzRzwSNFPEweKVCVdXU1VlYbgg7gjFX2n/AM46/wDORUPm+GHyt5pmWLzTEvG0u2oqX6KP&#xA;uE4H2l/a6juAq99xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2KvAv8AnIr/AJx1h83wzeafK0KxeaYl5XdotFS/RR9wnA+y37XQ9iFXxZPBNbzSQTxtFPExSWJw&#xA;VdXU0ZWU7gg7EHFVPFXYq7FVSCea3mjngkaKeJg8UqEq6upqrKw3BB3BGKvtP/nHX/nIqHzfDD5W&#xA;80zLF5piXjaXbUVL9FH3CcD7S/tdR3AVe+4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXgX/ORX/OOsPm+GbzT5WhWLzTEvK7tFoqX6KPuE4H2W/a6HsQq+LJ4&#xA;JreaSCeNop4mKSxOCrq6mjKyncEHYg4qp4q7FXYqqQTzW80c8EjRTxMHilQlXV1NVZWG4IO4IxV9&#xA;p/8AOOv/ADkVD5vhh8reaZli80xLxtLtqKl+ij7hOB9pf2uo7gKvfcVdirsVdirsVdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirwL/nIr/nHWHzfDN5p8rQrF5piXld2i0VL9&#xA;FH3CcD7LftdD2IVfFk8E1vNJBPG0U8TFJYnBV1dTRlZTuCDsQcVU8VdirsVVIJ5reaOeCRop4mDx&#xA;SoSrq6mqsrDcEHcEYq+0/wDnHX/nIqHzfDD5W80zLF5piXjaXbUVL9FH3CcD7S/tdR3AVe+4q7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXgX/ORX/OOsPm+Gbz&#xA;T5WhWLzTEvK7tFoqX6KPuE4H2W/a6HsQq+LJ4JreaSCeNop4mKSxOCrq6mjKyncEHYg4qp4q7FXY&#xA;q9v/AOcdfyD1PztqcHmTVjNYeVrCYPHNGzRTXc0TV4QOtGVFYfHIPkvxVKqvuXFXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXgX/ADkV/wA46w+b4ZvNPlaF&#xA;YvNMS8ru0Wipfoo+4TgfZb9roexCr4sngmt5pIJ42iniYpLE4KurqaMrKdwQdiDiqnir2z/nHz/n&#xA;Hy98+3qa7rqPbeULZ9zuj3rod4oj1EYOzuP9Vd6lVX3DY2NlYWUFjYwJbWdsixW9vEoRERBRVVRs&#xA;ABiqvirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeB&#xA;f85Ff846w+b4ZvNPlaFYvNMS8ru0Wipfoo+4TgfZb9roexCrxf8AIP8A5x11PztqZ1bzJBNYeVrC&#xA;Zo5o3DRTXc0TcXgStGVFYUkf/Yj4qlVX29Y2NlYWUFjYwJbWdsixW9vEoRERBRVVRsABiqvir//Z</xmpGImg:image>
+ </rdf:li>
+ </rdf:Alt>
+ </xmp:Thumbnails>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
+ xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
+ xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#">
+ <xmpMM:OriginalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</xmpMM:OriginalDocumentID>
+ <xmpMM:DocumentID>xmp.did:008011740720681197A58AA60A3A792E</xmpMM:DocumentID>
+ <xmpMM:InstanceID>uuid:d89cf8d7-60ea-364a-bd79-1b730e3e758c</xmpMM:InstanceID>
+ <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
+ <xmpMM:History>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/pdf to &lt;unknown&gt;</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:D07F11740720681191099C3B601C4548</stEvt:instanceID>
+ <stEvt:when>2008-04-17T14:19:10+05:30</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/pdf to &lt;unknown&gt;</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FC7F117407206811B628E3BF27C8C41B</stEvt:instanceID>
+ <stEvt:when>2008-05-22T14:51:08-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:FD7F117407206811B628E3BF27C8C41B</stEvt:instanceID>
+ <stEvt:when>2008-05-22T15:15:38-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>converted</stEvt:action>
+ <stEvt:params>from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator</stEvt:params>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:0CC3BD25102DDD1181B594070CEB88D9</stEvt:instanceID>
+ <stEvt:when>2008-05-28T17:07:17-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>
+ <rdf:Bag>
+ <rdf:li>/</rdf:li>
+ </rdf:Bag>
+ </stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:F77F117407206811ACFEA91EFF4B1542</stEvt:instanceID>
+ <stEvt:when>2011-08-23T17:31:58-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:F87F117407206811ACFEA91EFF4B1542</stEvt:instanceID>
+ <stEvt:when>2011-08-23T19:05:46-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:F97F117407206811ACFEA91EFF4B1542</stEvt:instanceID>
+ <stEvt:when>2011-08-23T19:07:15-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:008011740720681197A58AA60A3A792E</stEvt:instanceID>
+ <stEvt:when>2011-08-25T16:23:44-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS4</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpMM:History>
+ <xmpMM:DerivedFrom rdf:parseType="Resource">
+ <stRef:instanceID>uuid:4c3886fe-eb3e-c245-b671-dca17624cd71</stRef:instanceID>
+ <stRef:documentID>xmp.did:F97F117407206811ACFEA91EFF4B1542</stRef:documentID>
+ <stRef:originalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</stRef:originalDocumentID>
+ <stRef:renditionClass>proof:pdf</stRef:renditionClass>
+ </xmpMM:DerivedFrom>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
+ <illustrator:StartupProfile>Basic RGB</illustrator:StartupProfile>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+ xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+ xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
+ <xmpTPg:NPages>1</xmpTPg:NPages>
+ <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
+ <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
+ <xmpTPg:MaxPageSize rdf:parseType="Resource">
+ <stDim:w>20.000000</stDim:w>
+ <stDim:h>20.000000</stDim:h>
+ <stDim:unit>Pixels</stDim:unit>
+ </xmpTPg:MaxPageSize>
+ <xmpTPg:PlateNames>
+ <rdf:Seq>
+ <rdf:li>Cyan</rdf:li>
+ <rdf:li>Magenta</rdf:li>
+ <rdf:li>Yellow</rdf:li>
+ <rdf:li>Black</rdf:li>
+ </rdf:Seq>
+ </xmpTPg:PlateNames>
+ <xmpTPg:SwatchGroups>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Default Swatch Group</xmpG:groupName>
+ <xmpG:groupType>0</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>White</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>Black</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Red</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Yellow</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Green</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Cyan</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>255</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Blue</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Magenta</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>255</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>255</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>193</xmpG:red>
+ <xmpG:green>39</xmpG:green>
+ <xmpG:blue>45</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>237</xmpG:red>
+ <xmpG:green>28</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>241</xmpG:red>
+ <xmpG:green>90</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>247</xmpG:red>
+ <xmpG:green>147</xmpG:green>
+ <xmpG:blue>30</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>251</xmpG:red>
+ <xmpG:green>176</xmpG:green>
+ <xmpG:blue>59</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>252</xmpG:red>
+ <xmpG:green>238</xmpG:green>
+ <xmpG:blue>33</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>217</xmpG:red>
+ <xmpG:green>224</xmpG:green>
+ <xmpG:blue>33</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>140</xmpG:red>
+ <xmpG:green>198</xmpG:green>
+ <xmpG:blue>63</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>57</xmpG:red>
+ <xmpG:green>181</xmpG:green>
+ <xmpG:blue>74</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>146</xmpG:green>
+ <xmpG:blue>69</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>104</xmpG:green>
+ <xmpG:blue>55</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>34</xmpG:red>
+ <xmpG:green>181</xmpG:green>
+ <xmpG:blue>115</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>169</xmpG:green>
+ <xmpG:blue>157</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>41</xmpG:red>
+ <xmpG:green>171</xmpG:green>
+ <xmpG:blue>226</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>113</xmpG:green>
+ <xmpG:blue>188</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>46</xmpG:red>
+ <xmpG:green>49</xmpG:green>
+ <xmpG:blue>146</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>27</xmpG:red>
+ <xmpG:green>20</xmpG:green>
+ <xmpG:blue>100</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>102</xmpG:red>
+ <xmpG:green>45</xmpG:green>
+ <xmpG:blue>145</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>147</xmpG:red>
+ <xmpG:green>39</xmpG:green>
+ <xmpG:blue>143</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>158</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>93</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>212</xmpG:red>
+ <xmpG:green>20</xmpG:green>
+ <xmpG:blue>90</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>237</xmpG:red>
+ <xmpG:green>30</xmpG:green>
+ <xmpG:blue>121</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>199</xmpG:red>
+ <xmpG:green>178</xmpG:green>
+ <xmpG:blue>153</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>153</xmpG:red>
+ <xmpG:green>134</xmpG:green>
+ <xmpG:blue>117</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>115</xmpG:red>
+ <xmpG:green>99</xmpG:green>
+ <xmpG:blue>87</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>83</xmpG:red>
+ <xmpG:green>71</xmpG:green>
+ <xmpG:blue>65</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>198</xmpG:red>
+ <xmpG:green>156</xmpG:green>
+ <xmpG:blue>109</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>166</xmpG:red>
+ <xmpG:green>124</xmpG:green>
+ <xmpG:blue>82</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>140</xmpG:red>
+ <xmpG:green>98</xmpG:green>
+ <xmpG:blue>57</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>117</xmpG:red>
+ <xmpG:green>76</xmpG:green>
+ <xmpG:blue>36</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>96</xmpG:red>
+ <xmpG:green>56</xmpG:green>
+ <xmpG:blue>19</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>66</xmpG:red>
+ <xmpG:green>33</xmpG:green>
+ <xmpG:blue>11</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Grays</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>0</xmpG:red>
+ <xmpG:green>0</xmpG:green>
+ <xmpG:blue>0</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>26</xmpG:red>
+ <xmpG:green>26</xmpG:green>
+ <xmpG:blue>26</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>51</xmpG:red>
+ <xmpG:green>51</xmpG:green>
+ <xmpG:blue>51</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>77</xmpG:red>
+ <xmpG:green>77</xmpG:green>
+ <xmpG:blue>77</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>102</xmpG:red>
+ <xmpG:green>102</xmpG:green>
+ <xmpG:blue>102</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>128</xmpG:red>
+ <xmpG:green>128</xmpG:green>
+ <xmpG:blue>128</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>153</xmpG:red>
+ <xmpG:green>153</xmpG:green>
+ <xmpG:blue>153</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>179</xmpG:red>
+ <xmpG:green>179</xmpG:green>
+ <xmpG:blue>179</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>204</xmpG:red>
+ <xmpG:green>204</xmpG:green>
+ <xmpG:blue>204</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>230</xmpG:red>
+ <xmpG:green>230</xmpG:green>
+ <xmpG:blue>230</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>242</xmpG:red>
+ <xmpG:green>242</xmpG:green>
+ <xmpG:blue>242</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Splash</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=214 G=149 B=68</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>214</xmpG:red>
+ <xmpG:green>149</xmpG:green>
+ <xmpG:blue>68</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=71 G=152 B=237</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>71</xmpG:red>
+ <xmpG:green>152</xmpG:green>
+ <xmpG:blue>237</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=42 G=81 B=224</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>42</xmpG:red>
+ <xmpG:green>81</xmpG:green>
+ <xmpG:blue>224</xmpG:blue>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=180 G=58 B=228</xmpG:swatchName>
+ <xmpG:mode>RGB</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:red>180</xmpG:red>
+ <xmpG:green>58</xmpG:green>
+ <xmpG:blue>228</xmpG:blue>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpTPg:SwatchGroups>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
+ <pdf:Producer>Adobe PDF library 9.00</pdf:Producer>
+ </rdf:Description>
+ </rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end="w"?> endstream endobj 3 0 obj <</Count 1/Kids[5 0 R]/Type/Pages>> endobj 5 0 obj <</ArtBox[2.0 3.0 18.0 19.0]/BleedBox[0.0 0.0 20.0 20.0]/Contents 6 0 R/MediaBox[0.0 0.0 20.0 20.0]/Parent 3 0 R/Resources<</ExtGState<</GS0 7 0 R>>/Properties<</MC0<</Color[65535 20224 20224]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 2)/Visible true>>/MC1<</Color[20224 65535 65535]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 7)/Visible true>>/MC2<</Color[0 21845 0]/Dimmed false/Editable true/Preview true/Printed true/Title(Layer 5)/Visible true>>>>>>/TrimBox[0.0 0.0 20.0 20.0]/Type/Page>> endobj 6 0 obj <</Filter/FlateDecode/Length 214>>stream
+H‰ÌQ;Â0 Ý}Šw¤q›TéÊG]èP˜â3$ÊÄí±“ª0p
+ÏÔ' Û–<:ü¥Ê+íf²PiÃizÁ
+²ñó·ðÚ†|IgëÙ#ã@ÆKó€ÚƺR7Xïddšn%ýtOo
+0000000016 00000 n
+0000000076 00000 n
+0000048847 00000 n
+0000000000 00000 f
+0000048898 00000 n
+0000049452 00000 n
+0000049734 00000 n
+0000049846 00000 n
+trailer <</Size 9/Root 1 0 R/Info 8 0 R/ID[<6E648B55580B4616AD8999C45B44F5EC><51E6FA2ED7984AA4AE5261DEE0025340>]>> startxref 50022 %%EOF \ No newline at end of file
diff --git a/release/datafiles/blender_icons16/icon16_desktop.dat b/release/datafiles/blender_icons16/icon16_desktop.dat
new file mode 100644
index 00000000000..4a08daed9a9
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_desktop.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_external_drive.dat b/release/datafiles/blender_icons16/icon16_external_drive.dat
new file mode 100644
index 00000000000..3996681d0af
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_external_drive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_network_drive.dat b/release/datafiles/blender_icons16/icon16_network_drive.dat
new file mode 100644
index 00000000000..8570bbc3634
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_network_drive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_desktop.dat b/release/datafiles/blender_icons32/icon32_desktop.dat
new file mode 100644
index 00000000000..1400d07381d
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_desktop.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_external_drive.dat b/release/datafiles/blender_icons32/icon32_external_drive.dat
new file mode 100644
index 00000000000..cd16d0e1735
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_external_drive.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_network_drive.dat b/release/datafiles/blender_icons32/icon32_network_drive.dat
new file mode 100644
index 00000000000..36a18f0882c
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_network_drive.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.draw_sharp.dat b/release/datafiles/icons/brush.sculpt.draw_sharp.dat
new file mode 100644
index 00000000000..c3e0c7a7536
--- /dev/null
+++ b/release/datafiles/icons/brush.sculpt.draw_sharp.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.elastic_deform.dat b/release/datafiles/icons/brush.sculpt.elastic_deform.dat
new file mode 100644
index 00000000000..6d0ea25c1fe
--- /dev/null
+++ b/release/datafiles/icons/brush.sculpt.elastic_deform.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.mask.dat b/release/datafiles/icons/brush.sculpt.mask.dat
index a0ae683193d..02efb60857f 100644
--- a/release/datafiles/icons/brush.sculpt.mask.dat
+++ b/release/datafiles/icons/brush.sculpt.mask.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.pinch.dat b/release/datafiles/icons/brush.sculpt.pinch.dat
index d81c885e144..4a76c725561 100644
--- a/release/datafiles/icons/brush.sculpt.pinch.dat
+++ b/release/datafiles/icons/brush.sculpt.pinch.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.pose.dat b/release/datafiles/icons/brush.sculpt.pose.dat
new file mode 100644
index 00000000000..6183583ea27
--- /dev/null
+++ b/release/datafiles/icons/brush.sculpt.pose.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.simplify.dat b/release/datafiles/icons/brush.sculpt.simplify.dat
index a7f6ef47c36..f7de2f97aa1 100644
--- a/release/datafiles/icons/brush.sculpt.simplify.dat
+++ b/release/datafiles/icons/brush.sculpt.simplify.dat
Binary files differ
diff --git a/release/datafiles/icons/brush.sculpt.snake_hook.dat b/release/datafiles/icons/brush.sculpt.snake_hook.dat
index 3b0a8b47bd8..64256d93702 100644
--- a/release/datafiles/icons/brush.sculpt.snake_hook.dat
+++ b/release/datafiles/icons/brush.sculpt.snake_hook.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.border_hide.dat b/release/datafiles/icons/ops.sculpt.border_hide.dat
index c95e81a3099..67cd306805c 100644
--- a/release/datafiles/icons/ops.sculpt.border_hide.dat
+++ b/release/datafiles/icons/ops.sculpt.border_hide.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.border_mask.dat b/release/datafiles/icons/ops.sculpt.border_mask.dat
index aa4ba9165a3..701b96e31d9 100644
--- a/release/datafiles/icons/ops.sculpt.border_mask.dat
+++ b/release/datafiles/icons/ops.sculpt.border_mask.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.sculpt.mesh_filter.dat b/release/datafiles/icons/ops.sculpt.mesh_filter.dat
new file mode 100644
index 00000000000..164e08b78be
--- /dev/null
+++ b/release/datafiles/icons/ops.sculpt.mesh_filter.dat
Binary files differ
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index da8d1884851..d8b87480f29 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -21,6 +21,8 @@
#include "DNA_userdef_types.h"
#include "DNA_curve_types.h"
+#include "DNA_space_types.h"
+#include "DNA_anim_types.h"
#include "BLI_math_rotation.h"
@@ -137,6 +139,7 @@ const UserDef U_default = {
.glreslimit = 0,
.curssize = 0,
.color_picker_type = USER_CP_CIRCLE_HSV,
+ .auto_smoothing_new = FCURVE_SMOOTH_CONT_ACCEL,
.ipo_new = BEZT_IPO_BEZ,
.keyhandles_new = HD_AUTO_ANIM,
.view_frame_type = ZOOM_FRAME_MODE_KEEP_RANGE,
@@ -183,6 +186,8 @@ const UserDef U_default = {
.opensubdiv_compute_type = 0,
.gpencil_multisamples = 4,
.factor_display_type = USER_FACTOR_AS_FACTOR,
+ .render_display_type = USER_RENDER_DISPLAY_WINDOW,
+ .filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW,
.viewport_aa = 8,
.walk_navigation =
@@ -201,6 +206,19 @@ const UserDef U_default = {
.section_active = USER_SECTION_INTERFACE,
},
+ .file_space_data =
+ {
+ .display_type = FILE_VERTICALDISPLAY,
+ .thumbnail_size = 128,
+ .sort_type = FILE_SORT_ALPHA,
+ .details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME,
+ .flag = FILE_HIDE_DOT,
+ .filter_id = FILTER_ID_ALL,
+
+ .temp_win_sizex = 1020,
+ .temp_win_sizey = 600,
+ },
+
.runtime =
{
.is_dirty = 0,
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index ff2a5ae2739..0b9e8beccc1 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -585,6 +585,7 @@ const bTheme U_theme_default = {
.anim_preview_range = RGBA(0xa14d0066),
.nla_tweaking = RGBA(0x4df31a4d),
.nla_tweakdupli = RGBA(0xd90000ff),
+ .nla_track = RGBA(0x424242ff),
.nla_transition = RGBA(0x1c2630ff),
.nla_transition_sel = RGBA(0x2e75dbff),
.nla_meta = RGBA(0x332642ff),
@@ -746,12 +747,12 @@ const bTheme U_theme_default = {
.back = RGBA(0x333333b3),
.sub_back = RGBA(0x0000003e),
},
+ .active = RGBA(0x3b5689ff),
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
.match = RGBA(0x337f334c),
.selected_highlight = RGBA(0x223a5bff),
- .active = RGBA(0x3b5689ff),
.selected_object = RGBA(0xe96a00ff),
.active_object = RGBA(0xffaf29ff),
.edited_object = RGBA(0x00806266),
@@ -914,6 +915,8 @@ const bTheme U_theme_default = {
.lock_marker = RGBA(0x7f7f7fff),
.path_before = RGBA(0xff0000ff),
.path_after = RGBA(0x0000ffff),
+ .path_keyframe_before = RGBA(0xffc4c4ff),
+ .path_keyframe_after = RGBA(0xc4c4ffff),
.gp_vertex_size = 1,
.metadatatext = RGBA(0xffffffff),
},
diff --git a/release/freedesktop/org.blender.Blender.appdata.xml b/release/freedesktop/org.blender.Blender.appdata.xml
index 1287c9eea5d..984b5b3b15e 100644
--- a/release/freedesktop/org.blender.Blender.appdata.xml
+++ b/release/freedesktop/org.blender.Blender.appdata.xml
@@ -40,6 +40,27 @@
</screenshot>
</screenshots>
<releases>
+ <release version="2.81" date="2019-11-14">
+ <description>
+ <p>New features:</p>
+ <ul>
+ <li>Many sculpt tools and poly build tool for retopology</li>
+ <li>Voxel remesh and quad remesh</li>
+ <li>Transform origins, new snapping, mirroring and auto merge options</li>
+ <li>Revamped shaders for texturing</li>
+ <li>Cycles denoising with OpenImageDenoise and NVIDIA RTX support</li>
+ <li>Library overrides to make local overrides to linked characters and other data</li>
+ <li>
+ </ul>
+ <ul>
+ <p>Enhancements:</p>
+ <li>Eevee shadows, transparency and bump mapping redesigned</li>
+ <li>Viewport options for look development with Cycles and Eevee</li>
+ <li>Finer control over rotations and scale in bones, constraints and drivers</li>
+ <li>Outliner improvements, new file browser and batch rename</li>
+ </ul>
+ </description>
+ </release>
<release version="2.80" date="2019-07-30">
<description>
<p>New features:</p>
diff --git a/release/scripts/modules/bl_app_override/__init__.py b/release/scripts/modules/bl_app_override/__init__.py
index 2104b10bf85..112fe040f0c 100644
--- a/release/scripts/modules/bl_app_override/__init__.py
+++ b/release/scripts/modules/bl_app_override/__init__.py
@@ -90,7 +90,7 @@ def ui_draw_filter_register(
ret = real_func(*args, **kw)
else:
if ui_test is None:
- UILayout.__getattribute__(self, "label")("")
+ UILayout.__getattribute__(self, "label")(text="")
else:
assert(ui_test is True)
# may need to be set
@@ -111,7 +111,7 @@ def ui_draw_filter_register(
ret = real_func(*args, **kw)
else:
if ui_test is None:
- UILayout.__getattribute__(self, "label")("")
+ UILayout.__getattribute__(self, "label")(text="")
else:
assert(ui_test is True)
ret = None
@@ -131,7 +131,7 @@ def ui_draw_filter_register(
ret = real_func(*args, **kw)
else:
if ui_test is None:
- UILayout.__getattribute__(self, "label")("")
+ UILayout.__getattribute__(self, "label")(text="")
else:
assert(ui_test is True)
ret = None
@@ -151,7 +151,7 @@ def ui_draw_filter_register(
ret = real_func(*args, **kw)
else:
if ui_test is None:
- real_func("")
+ real_func(text="")
else:
assert(ui_test is True)
ret = None
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index a6c7940f5c8..c81558db587 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -94,6 +94,7 @@ LANGUAGES = (
(44, "Kazakh (қазақша)", "kk_KZ"),
(45, "Abkhaz (ÐÔ¥Ñуа бызшәа)", "ab"),
(46, "Thai (ภาษาไทย)", "th_TH"),
+ (47, "Slovak (SlovenÄina)", "sk_SK"),
)
# Default context, in py!
diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py
index 03864d652e4..f4d34de5037 100644
--- a/release/scripts/modules/bpy_extras/image_utils.py
+++ b/release/scripts/modules/bpy_extras/image_utils.py
@@ -24,17 +24,18 @@ __all__ = (
# limited replacement for BPyImage.comprehensiveImageLoad
-def load_image(imagepath,
- dirname="",
- place_holder=False,
- recursive=False,
- ncase_cmp=True,
- convert_callback=None,
- verbose=False,
- relpath=None,
- check_existing=False,
- force_reload=False,
- ):
+def load_image(
+ imagepath,
+ dirname="",
+ place_holder=False,
+ recursive=False,
+ ncase_cmp=True,
+ convert_callback=None,
+ verbose=False,
+ relpath=None,
+ check_existing=False,
+ force_reload=False,
+):
"""
Return an image from the file path with options to search multiple paths
and return a placeholder if its not found.
@@ -161,15 +162,17 @@ def load_image(imagepath,
variants = [imagepath]
if dirname:
- variants += [os.path.join(dirname, imagepath),
- os.path.join(dirname, bpy.path.basename(imagepath)),
- ]
+ variants += [
+ os.path.join(dirname, imagepath),
+ os.path.join(dirname, bpy.path.basename(imagepath)),
+ ]
for filepath_test in variants:
if ncase_cmp:
- ncase_variants = (filepath_test,
- bpy.path.resolve_ncase(filepath_test),
- )
+ ncase_variants = (
+ filepath_test,
+ bpy.path.resolve_ncase(filepath_test),
+ )
else:
ncase_variants = (filepath_test, )
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 96b9596a57d..380b63066ef 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -44,10 +44,11 @@ from bpy.props import (
def _check_axis_conversion(op):
if hasattr(op, "axis_forward") and hasattr(op, "axis_up"):
- return axis_conversion_ensure(op,
- "axis_forward",
- "axis_up",
- )
+ return axis_conversion_ensure(
+ op,
+ "axis_forward",
+ "axis_up",
+ )
return False
@@ -93,10 +94,12 @@ class ExportHelper:
if check_extension is not None:
filepath = self.filepath
if os.path.basename(filepath):
- filepath = bpy.path.ensure_ext(filepath,
- self.filename_ext
- if check_extension
- else "")
+ filepath = bpy.path.ensure_ext(
+ filepath,
+ self.filename_ext
+ if check_extension
+ else "",
+ )
if filepath != self.filepath:
self.filepath = filepath
@@ -134,8 +137,10 @@ def orientation_helper(axis_forward='Y', axis_up='Z'):
def _update_axis_forward(self, _context):
if self.axis_forward[-1] == self.axis_up[-1]:
- self.axis_up = (self.axis_up[0:-1] +
- 'XYZ'[('XYZ'.index(self.axis_up[-1]) + 1) % 3])
+ self.axis_up = (
+ self.axis_up[0:-1] +
+ 'XYZ'[('XYZ'.index(self.axis_up[-1]) + 1) % 3]
+ )
cls.__annotations__['axis_forward'] = EnumProperty(
name="Forward",
@@ -153,8 +158,10 @@ def orientation_helper(axis_forward='Y', axis_up='Z'):
def _update_axis_up(self, _context):
if self.axis_up[-1] == self.axis_forward[-1]:
- self.axis_forward = (self.axis_forward[0:-1] +
- 'XYZ'[('XYZ'.index(self.axis_forward[-1]) + 1) % 3])
+ self.axis_forward = (
+ self.axis_forward[0:-1] +
+ 'XYZ'[('XYZ'.index(self.axis_forward[-1]) + 1) % 3]
+ )
cls.__annotations__['axis_up'] = EnumProperty(
name="Up",
@@ -405,14 +412,15 @@ path_reference_mode = EnumProperty(
)
-def path_reference(filepath,
- base_src,
- base_dst,
- mode='AUTO',
- copy_subdir="",
- copy_set=None,
- library=None,
- ):
+def path_reference(
+ filepath,
+ base_src,
+ base_dst,
+ mode='AUTO',
+ copy_subdir="",
+ copy_set=None,
+ library=None,
+):
"""
Return a filepath relative to a destination directory, for use with
exporters.
@@ -540,22 +548,29 @@ def unique_name(key, name, name_dict, name_max=-1, clean_func=None, sep="."):
if name_new is None:
count = 1
name_dict_values = name_dict.values()
- name_new = name_new_orig = (name if clean_func is None
- else clean_func(name))
+ name_new = name_new_orig = (
+ name if clean_func is None
+ else clean_func(name)
+ )
if name_max == -1:
while name_new in name_dict_values:
- name_new = "%s%s%03d" % (name_new_orig, sep, count)
+ name_new = "%s%s%03d" % (
+ name_new_orig,
+ sep,
+ count,
+ )
count += 1
else:
name_new = name_new[:name_max]
while name_new in name_dict_values:
count_str = "%03d" % count
- name_new = "%.*s%s%s" % (name_max - (len(count_str) + 1),
- name_new_orig,
- sep,
- count_str,
- )
+ name_new = "%.*s%s%s" % (
+ name_max - (len(count_str) + 1),
+ name_new_orig,
+ sep,
+ count_str,
+ )
count += 1
name_dict[key] = name_new
diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py
index 1576947b8b4..f70f1eacead 100644
--- a/release/scripts/modules/bpy_extras/mesh_utils.py
+++ b/release/scripts/modules/bpy_extras/mesh_utils.py
@@ -265,7 +265,7 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True):
return []
def mlen(co):
- # manhatten length of a vector, faster then length
+ # Manhatten length of a vector, faster then length.
return abs(co[0]) + abs(co[1]) + abs(co[2])
def vert_treplet(v, i):
@@ -278,9 +278,8 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True):
return v1[1], v2[1]
if not fix_loops:
- """
- Normal single concave loop filling
- """
+ # Normal single concave loop filling.
+
if type(from_data) in {tuple, list}:
verts = [Vector(from_data[i]) for ii, i in enumerate(indices)]
else:
@@ -294,17 +293,19 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True):
fill = tessellate_polygon([verts])
else:
- """
- Separate this loop into multiple loops be finding edges that are
- used twice. This is used by lightwave LWO files a lot
- """
+ # Separate this loop into multiple loops be finding edges that are
+ # used twice. This is used by Light-Wave LWO files a lot.
if type(from_data) in {tuple, list}:
- verts = [vert_treplet(Vector(from_data[i]), ii)
- for ii, i in enumerate(indices)]
+ verts = [
+ vert_treplet(Vector(from_data[i]), ii)
+ for ii, i in enumerate(indices)
+ ]
else:
- verts = [vert_treplet(from_data.vertices[i].co, ii)
- for ii, i in enumerate(indices)]
+ verts = [
+ vert_treplet(from_data.vertices[i].co, ii)
+ for ii, i in enumerate(indices)
+ ]
edges = [(i, i - 1) for i in range(len(verts))]
if edges:
@@ -354,7 +355,7 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True):
else:
return False
- # If were stuill here s1 and s2 are 2 segments in the same polyline
+ # If were still here s1 and s2 are 2 segments in the same poly-line.
s1.pop() # remove the last vert from s1
s1.extend(s2) # add segment 2 to segment 1
@@ -402,14 +403,14 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True):
# draw_loops(loop_list)
#raise Exception("done loop")
# map to original indices
- fill = [[vert_map[i] for i in reversed(f)] for f in fill]
+ fill = [[vert_map[i] for i in f] for f in fill]
if not fill:
if debug_print:
print('Warning Cannot scanfill, fallback on a triangle fan.')
fill = [[0, i - 1, i] for i in range(2, len(indices))]
else:
- # Use real scanfill.
+ # Use real scan-fill.
# See if its flipped the wrong way.
flip = None
for fi in fill:
diff --git a/release/scripts/modules/bpy_extras/node_shader_utils.py b/release/scripts/modules/bpy_extras/node_shader_utils.py
index 4ca3e675c37..ce5edde5adf 100644
--- a/release/scripts/modules/bpy_extras/node_shader_utils.py
+++ b/release/scripts/modules/bpy_extras/node_shader_utils.py
@@ -336,6 +336,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
self, self.node_principled_bsdf,
self.node_principled_bsdf.inputs["Specular"],
grid_row_diff=0,
+ colorspace_name='Non-Color',
)
specular_texture = property(specular_texture_get)
@@ -367,6 +368,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
self, self.node_principled_bsdf,
self.node_principled_bsdf.inputs["Roughness"],
grid_row_diff=0,
+ colorspace_name='Non-Color',
)
roughness_texture = property(roughness_texture_get)
@@ -398,6 +400,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
self, self.node_principled_bsdf,
self.node_principled_bsdf.inputs["Metallic"],
grid_row_diff=0,
+ colorspace_name='Non-Color',
)
metallic_texture = property(metallic_texture_get)
@@ -428,6 +431,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
self, self.node_principled_bsdf,
self.node_principled_bsdf.inputs["IOR"],
grid_row_diff=-1,
+ colorspace_name='Non-Color',
)
ior_texture = property(ior_texture_get)
@@ -455,6 +459,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
self, self.node_principled_bsdf,
self.node_principled_bsdf.inputs["Transmission"],
grid_row_diff=-1,
+ colorspace_name='Non-Color',
)
transmission_texture = property(transmission_texture_get)
@@ -482,11 +487,41 @@ class PrincipledBSDFWrapper(ShaderWrapper):
self, self.node_principled_bsdf,
self.node_principled_bsdf.inputs["Alpha"],
grid_row_diff=-1,
+ colorspace_name='Non-Color',
)
alpha_texture = property(alpha_texture_get)
+ # --------------------------------------------------------------------
+ # Emission color.
+
+ def emission_color_get(self):
+ if not self.use_nodes or self.node_principled_bsdf is None:
+ return Color((0.0, 0.0, 0.0))
+ return rgba_to_rgb(self.node_principled_bsdf.inputs["Emission"].default_value)
+
+ @_set_check
+ def emission_color_set(self, color):
+ if self.use_nodes and self.node_principled_bsdf is not None:
+ color = values_clamp(color, 0.0, 1.0)
+ color = rgb_to_rgba(color)
+ self.node_principled_bsdf.inputs["Emission"].default_value = color
+
+ emission_color = property(emission_color_get, emission_color_set)
+
+
+ def emission_color_texture_get(self):
+ if not self.use_nodes or self.node_principled_bsdf is None:
+ return None
+ return ShaderImageTextureWrapper(
+ self, self.node_principled_bsdf,
+ self.node_principled_bsdf.inputs["Emission"],
+ grid_row_diff=1,
+ )
+
+ emission_color_texture = property(emission_color_texture_get)
+
# --------------------------------------------------------------------
# Normal map.
@@ -539,6 +574,7 @@ class ShaderImageTextureWrapper():
"grid_row_diff",
"use_alpha",
"colorspace_is_data",
+ "colorspace_name",
*NODES_LIST,
)
@@ -551,7 +587,7 @@ class ShaderImageTextureWrapper():
return instance
def __init__(self, owner_shader: ShaderWrapper, node_dst, socket_dst, grid_row_diff=0,
- use_alpha=False, colorspace_is_data=...):
+ use_alpha=False, colorspace_is_data=..., colorspace_name=...):
self.owner_shader = owner_shader
self.is_readonly = owner_shader.is_readonly
self.node_dst = node_dst
@@ -559,6 +595,7 @@ class ShaderImageTextureWrapper():
self.grid_row_diff = grid_row_diff
self.use_alpha = use_alpha
self.colorspace_is_data = colorspace_is_data
+ self.colorspace_name = colorspace_name
self._node_image = ...
self._node_mapping = ...
@@ -656,7 +693,13 @@ class ShaderImageTextureWrapper():
@_set_check
def image_set(self, image):
if self.colorspace_is_data is not ...:
+ if image.colorspace_settings.is_data != self.colorspace_is_data and image.users >= 1:
+ image = image.copy()
image.colorspace_settings.is_data = self.colorspace_is_data
+ if self.colorspace_name is not ...:
+ if image.colorspace_settings.is_data != self.colorspace_is_data and image.users >= 1:
+ image = image.copy()
+ image.colorspace_settings.name = self.colorspace_name
self.node_image.image = image
image = property(image_get, image_set)
@@ -771,7 +814,7 @@ class ShaderImageTextureWrapper():
def scale_get(self):
if self.node_mapping is None:
- return Vector((0.0, 0.0, 0.0))
+ return Vector((1.0, 1.0, 1.0))
return self.node_mapping.inputs['Scale'].default_value
@_set_check
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index a3787506da4..43ee785438b 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -60,12 +60,14 @@ class Library(bpy_types.ID):
# See: readblenentry.c, IDTYPE_FLAGS_ISLINKABLE,
# we could make this an attribute in rna.
- attr_links = ("actions", "armatures", "brushes", "cameras",
- "curves", "grease_pencils", "collections", "images",
- "lights", "lattices", "materials", "metaballs",
- "meshes", "node_groups", "objects", "scenes",
- "sounds", "speakers", "textures", "texts",
- "fonts", "worlds")
+ attr_links = (
+ "actions", "armatures", "brushes", "cameras",
+ "curves", "grease_pencils", "collections", "images",
+ "lights", "lattices", "materials", "metaballs",
+ "meshes", "node_groups", "objects", "scenes",
+ "sounds", "speakers", "textures", "texts",
+ "fonts", "worlds",
+ )
return tuple(id_block
for attr in attr_links
@@ -90,11 +92,13 @@ class Texture(bpy_types.ID):
def users_object_modifier(self):
"""Object modifiers that use this texture"""
import bpy
- return tuple(obj for obj in bpy.data.objects if
- self in [mod.texture
- for mod in obj.modifiers
- if mod.type == 'DISPLACE']
- )
+ return tuple(
+ obj for obj in bpy.data.objects if
+ self in [
+ mod.texture
+ for mod in obj.modifiers
+ if mod.type == 'DISPLACE']
+ )
class Collection(bpy_types.ID):
@@ -122,10 +126,15 @@ class Object(bpy_types.ID):
def users_collection(self):
"""The collections this object is in. Warning: takes O(len(bpy.data.collections) + len(bpy.data.scenes)) time."""
import bpy
- return tuple(collection for collection in bpy.data.collections
- if self in collection.objects[:]) + \
- tuple(scene.collection for scene in bpy.data.scenes
- if self in scene.collection.objects[:])
+ return (
+ tuple(
+ collection for collection in bpy.data.collections
+ if self in collection.objects[:]
+ ) + tuple(
+ scene.collection for scene in bpy.data.scenes
+ if self in scene.collection.objects[:]
+ )
+ )
@property
def users_scene(self):
@@ -175,6 +184,27 @@ class WindowManager(bpy_types.ID):
self.piemenu_end__internal(pie)
+class WorkSpace(bpy_types.ID):
+ __slots__ = ()
+
+ def status_text_set(self, text):
+ """
+ Set the status text or None to clear,
+ When text is a function, this will be called with the (header, context) arguments.
+ """
+ from bl_ui.space_statusbar import STATUSBAR_HT_header
+ draw_fn = getattr(STATUSBAR_HT_header, "_draw_orig", None)
+ if draw_fn is None:
+ draw_fn = STATUSBAR_HT_header._draw_orig = STATUSBAR_HT_header.draw
+
+ if not (text is None or isinstance(text, str)):
+ draw_fn = text
+ text = None
+
+ self.status_text_set_internal(text)
+ STATUSBAR_HT_header.draw = draw_fn
+
+
class _GenericBone:
"""
functions for bones, common between Armature/Pose/Edit bones.
@@ -409,6 +439,8 @@ class Mesh(bpy_types.ID):
int pairs, each pair contains two indices to the
*vertices* argument. eg: [(1, 2), ...]
+ When an empty iterable is passed in, the edges are inferred from the polygons.
+
:type edges: iterable object
:arg faces:
@@ -444,11 +476,15 @@ class Mesh(bpy_types.ID):
self.polygons.foreach_set("loop_start", loop_starts)
self.polygons.foreach_set("vertices", vertex_indices)
- # if no edges - calculate them
- if faces and (not edges):
- self.update(calc_edges=True)
- elif edges:
- self.update(calc_edges_loose=True)
+ if edges or faces:
+ self.update(
+ # Needed to either:
+ # - Calculate edges that don't exist for polygons.
+ # - Assign edges to polygon loops.
+ calc_edges=bool(faces),
+ # Flag loose edges.
+ calc_edges_loose=bool(edges),
+ )
@property
def edge_keys(self):
@@ -471,18 +507,20 @@ class MeshLoopTriangle(StructRNA):
"""The midpoint of the face."""
face_verts = self.vertices[:]
mesh_verts = self.id_data.vertices
- return (mesh_verts[face_verts[0]].co +
- mesh_verts[face_verts[1]].co +
- mesh_verts[face_verts[2]].co
- ) / 3.0
+ return (
+ mesh_verts[face_verts[0]].co +
+ mesh_verts[face_verts[1]].co +
+ mesh_verts[face_verts[2]].co
+ ) / 3.0
@property
def edge_keys(self):
verts = self.vertices[:]
- return (ord_ind(verts[0], verts[1]),
- ord_ind(verts[1], verts[2]),
- ord_ind(verts[2], verts[0]),
- )
+ return (
+ ord_ind(verts[0], verts[1]),
+ ord_ind(verts[1], verts[2]),
+ ord_ind(verts[2], verts[0]),
+ )
class MeshPolygon(StructRNA):
@@ -601,17 +639,27 @@ class Gizmo(StructRNA):
if select_id is not None:
gpu.select.load_id(select_id)
+ use_blend = False
else:
if self.is_highlight:
color = (*self.color_highlight, self.alpha_highlight)
else:
color = (*self.color, self.alpha)
shader.uniform_float("color", color)
+ use_blend = color[3] < 1.0
+
+ if use_blend:
+ # TODO: wrap GPU_blend from GPU state.
+ from bgl import glEnable, glDisable, GL_BLEND
+ glEnable(GL_BLEND)
with gpu.matrix.push_pop():
gpu.matrix.multiply_matrix(matrix)
batch.draw()
+ if use_blend:
+ glDisable(GL_BLEND)
+
@staticmethod
def new_custom_shape(type, verts):
"""
@@ -850,15 +898,15 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
# collect paths
files = []
for directory in searchpaths:
- files.extend(
- [(f, os.path.join(directory, f))
+ files.extend([
+ (f, os.path.join(directory, f))
for f in os.listdir(directory)
if (not f.startswith("."))
if ((filter_ext is None) or
(filter_ext(os.path.splitext(f)[1])))
if ((filter_path is None) or
(filter_path(f)))
- ])
+ ])
files.sort()
@@ -916,11 +964,13 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
ext_valid = getattr(self, "preset_extensions", {".py", ".xml"})
props_default = getattr(self, "preset_operator_defaults", None)
add_operator = getattr(self, "preset_add_operator", None)
- self.path_menu(bpy.utils.preset_paths(self.preset_subdir),
- self.preset_operator,
- props_default=props_default,
- filter_ext=lambda ext: ext.lower() in ext_valid,
- add_operator=add_operator)
+ self.path_menu(
+ bpy.utils.preset_paths(self.preset_subdir),
+ self.preset_operator,
+ props_default=props_default,
+ filter_ext=lambda ext: ext.lower() in ext_valid,
+ add_operator=add_operator,
+ )
@classmethod
def draw_collapsible(cls, context, layout):
@@ -955,9 +1005,10 @@ class NodeSocket(StructRNA, metaclass=RNAMetaPropGroup):
@property
def links(self):
"""List of node links from or to this socket. Warning: takes O(len(nodetree.links)) time."""
- return tuple(link for link in self.id_data.links
- if (link.from_socket == self or
- link.to_socket == self))
+ return tuple(
+ link for link in self.id_data.links
+ if (link.from_socket == self or
+ link.to_socket == self))
class NodeSocketInterface(StructRNA, metaclass=RNAMetaPropGroup):
diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py
index e2f5c2c240a..1f01523534f 100644
--- a/release/scripts/modules/rna_manual_reference.py
+++ b/release/scripts/modules/rna_manual_reference.py
@@ -37,15 +37,19 @@ if LANG is not None:
url_manual_mapping = (
("bpy.types.cyclesobjectsettings.use_adaptive_subdivision*", "render/cycles/object_settings/adaptive_subdiv.html#bpy-types-cyclesobjectsettings-use-adaptive-subdivision"),
+ ("bpy.types.rendersettings_simplify_gpencil_view_modifier*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-modifier"),
("bpy.types.brushgpencilsettings.use_settings_stabilizer*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-use-settings-stabilizer"),
("bpy.types.gpencilsculptsettings.use_multiframe_falloff*", "grease_pencil/multiframe.html#bpy-types-gpencilsculptsettings-use-multiframe-falloff"),
- ("bpy.types.toolsettings.use_transform_pivot_point_align*", "scene_layout/object/editing/transform/control/pivot_point/index.html#bpy-types-toolsettings-use-transform-pivot-point-align"),
+ ("bpy.types.rendersettings_simplify_gpencil_remove_lines*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-remove-lines"),
+ ("bpy.types.toolsettings.use_transform_pivot_point_align*", "scene_layout/object/editing/transform/control/options.html#bpy-types-toolsettings-use-transform-pivot-point-align"),
("bpy.types.cyclesrendersettings.offscreen_dicing_scale*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-offscreen-dicing-scale"),
("bpy.types.linestylegeometrymodifier_backbonestretcher*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/backbone_stretcher.html#bpy-types-linestylegeometrymodifier-backbonestretcher"),
("bpy.types.linestylegeometrymodifier_sinusdisplacement*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/sinus_displacement.html#bpy-types-linestylegeometrymodifier-sinusdisplacement"),
("bpy.types.linestylegeometrymodifier_polygonalization*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/polygonization.html#bpy-types-linestylegeometrymodifier-polygonalization"),
("bpy.types.cyclesrendersettings.distance_cull_margin*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-distance-cull-margin"),
("bpy.types.materialgpencilstyle.use_fill_texture_mix*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-use-fill-texture-mix"),
+ ("bpy.types.rendersettings_simplify_gpencil_shader_fx*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-shader-fx"),
+ ("bpy.types.rendersettings_simplify_gpencil_view_fill*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-fill"),
("bpy.types.brushgpencilsettings.use_jitter_pressure*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-use-jitter-pressure"),
("bpy.types.brushgpencilsettings.use_settings_random*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-use-settings-random"),
("bpy.types.linestylegeometrymodifier_simplification*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/simplification.html#bpy-types-linestylegeometrymodifier-simplification"),
@@ -59,16 +63,19 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_guidinglines*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/guiding_lines.html#bpy-types-linestylegeometrymodifier-guidinglines"),
("bpy.types.linestylegeometrymodifier_spatialnoise*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/spatial_noise.html#bpy-types-linestylegeometrymodifier-spatialnoise"),
("bpy.types.linestylethicknessmodifier_calligraphy*", "render/freestyle/parameter_editor/line_style/modifiers/thickness/calligraphy.html#bpy-types-linestylethicknessmodifier-calligraphy"),
+ ("bpy.types.rendersettings_simplify_gpencil_onplay*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-onplay"),
("bpy.types.toolsettings.use_gpencil_draw_additive*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-additive"),
- ("bpy.types.toolsettings.use_transform_data_origin*", "scene_layout/object/editing/transform/control/pivot_point/index.html#bpy-types-toolsettings-use-transform-data-origin"),
+ ("bpy.types.toolsettings.use_transform_data_origin*", "scene_layout/object/editing/transform/control/options.html#bpy-types-toolsettings-use-transform-data-origin"),
("bpy.types.cyclesrendersettings.max_subdivisions*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-max-subdivisions"),
("bpy.types.linestyle*modifier_distancefromcamera*", "render/freestyle/parameter_editor/line_style/modifiers/color/distance_from_camera.html#bpy-types-linestyle-modifier-distancefromcamera"),
("bpy.types.linestyle*modifier_distancefromobject*", "render/freestyle/parameter_editor/line_style/modifiers/color/distance_from_object.html#bpy-types-linestyle-modifier-distancefromobject"),
("bpy.types.linestylegeometrymodifier_2dtransform*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/2d_transform.html#bpy-types-linestylegeometrymodifier-2dtransform"),
("bpy.types.linestylegeometrymodifier_beziercurve*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/bezier_curve.html#bpy-types-linestylegeometrymodifier-beziercurve"),
+ ("bpy.types.rendersettings_simplify_gpencil_blend*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-blend"),
("bpy.types.toolsettings.gpencil_stroke_placement*", "grease_pencil/modes/draw/stroke_placement.html#bpy-types-toolsettings-gpencil-stroke-placement"),
("bpy.types.cyclesrendersettings.use_camera_cull*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-use-camera-cull"),
("bpy.types.linestylegeometrymodifier_tipremover*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/tip_remover.html#bpy-types-linestylegeometrymodifier-tipremover"),
+ ("bpy.types.rendersettings_simplify_gpencil_tint*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-tint"),
("bpy.types.toolsettings.use_gpencil_draw_onback*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-onback"),
("bpy.types.cyclesmaterialsettings.displacement*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-displacement"),
("bpy.types.linestylegeometrymodifier_blueprint*", "render/freestyle/parameter_editor/line_style/modifiers/geometry/blueprint.html#bpy-types-linestylegeometrymodifier-blueprint"),
@@ -101,11 +108,12 @@ url_manual_mapping = (
("bpy.types.materialgpencilstyle.fill_style*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-fill-style"),
("bpy.types.materialgpencilstyle.mix_factor*", "grease_pencil/materials/grease_pencil_shader.html#bpy-types-materialgpencilstyle-mix-factor"),
("bpy.types.rendersettings.use_render_cache*", "render/output/settings.html#bpy-types-rendersettings-use-render-cache"),
+ ("bpy.types.rendersettings_simplify_gpencil*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil"),
("bpy.types.sceneeevee.use_taa_reprojection*", "render/eevee/render_settings/sampling.html#bpy-types-sceneeevee-use-taa-reprojection"),
("bpy.types.sequenceeditor.use_overlay_lock*", "video_editing/preview/properties.html#bpy-types-sequenceeditor-use-overlay-lock"),
("bpy.types.toolsettings.gpencil_selectmode*", "grease_pencil/selecting.html#bpy-types-toolsettings-gpencil-selectmode"),
- ("bpy.ops.gpencil.active_frames_delete_all*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-active-frames-delete-all"),
- ("bpy.ops.gpencil.stroke_merge_by_distance*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-stroke-merge-by-distance"),
+ ("bpy.ops.gpencil.active_frames_delete_all*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-active-frames-delete-all"),
+ ("bpy.ops.gpencil.stroke_merge_by_distance*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-merge-by-distance"),
("bpy.ops.object.anim_transforms_to_deltas*", "scene_layout/object/editing/transform/clear_apply.html#bpy-ops-object-anim-transforms-to-deltas"),
("bpy.types.brushgpencilsettings.uv_random*", "grease_pencil/modes/draw/tool_settings/brushes/draw_brush.html#bpy-types-brushgpencilsettings-uv-random"),
("bpy.types.compositornodeplanetrackdeform*", "compositing/types/distort/plane_track_deform.html#bpy-types-compositornodeplanetrackdeform"),
@@ -177,6 +185,7 @@ url_manual_mapping = (
("bpy.types.shadernodevolumeprincipled*", "render/shader_nodes/shader/volume_principled.html#bpy-types-shadernodevolumeprincipled"),
("bpy.types.toolsettings.use_uv_sculpt*", "modeling/meshes/editing/uv/uv_sculpt.html#bpy-types-toolsettings-use-uv-sculpt"),
("bpy.ops.gpencil.interpolate_reverse*", "grease_pencil/animation/interpolation.html#bpy-ops-gpencil-interpolate-reverse"),
+ ("bpy.ops.gpencil.set_active_material*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-set-active-material"),
("bpy.ops.gpencil.stroke_change_color*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-change-color"),
("bpy.ops.gpencil.stroke_cyclical_set*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-cyclical-set"),
("bpy.ops.mesh.set_normals_from_faces*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-set-normals-from-faces"),
@@ -240,7 +249,7 @@ url_manual_mapping = (
("bpy.types.vertexweighteditmodifier*", "modeling/modifiers/modify/weight_edit.html#bpy-types-vertexweighteditmodifier"),
("bpy.ops.curve.match_texture_space*", "editors/uv/generated_uvs.html#bpy-ops-curve-match-texture-space"),
("bpy.ops.font.text_paste_from_file*", "modeling/texts/selecting_editing.html#bpy-ops-font-text-paste-from-file"),
- ("bpy.ops.gpencil.frame_clean_loose*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-frame-clean-loose"),
+ ("bpy.ops.gpencil.frame_clean_loose*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-frame-clean-loose"),
("bpy.ops.object.vertex_group_clean*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-clean"),
("bpy.ops.render.play-rendered-anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"),
("bpy.types.armaturegpencilmodifier*", "grease_pencil/modifiers/deform/armature.html#bpy-types-armaturegpencilmodifier"),
@@ -275,7 +284,7 @@ url_manual_mapping = (
("bpy.types.simplifygpencilmodifier*", "grease_pencil/modifiers/generate/simplify.html#bpy-types-simplifygpencilmodifier"),
("bpy.types.spacegrapheditor.cursor*", "editors/graph_editor/introduction.html#bpy-types-spacegrapheditor-cursor"),
("bpy.types.vertexweightmixmodifier*", "modeling/modifiers/modify/weight_mix.html#bpy-types-vertexweightmixmodifier"),
- ("bpy.ops.gpencil.frame_clean_fill*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-frame-clean-fill"),
+ ("bpy.ops.gpencil.frame_clean_fill*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-frame-clean-fill"),
("bpy.ops.gpencil.stroke_subdivide*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-subdivide"),
("bpy.ops.object.constraints_clear*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraints-clear"),
("bpy.ops.object.vertex_group_copy*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy"),
@@ -319,7 +328,7 @@ url_manual_mapping = (
("bpy.ops.gpencil.blank_frame_add*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-blank-frame-add"),
("bpy.ops.gpencil.frame_duplicate*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-frame-duplicate"),
("bpy.ops.gpencil.stroke_caps_set*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-caps-set"),
- ("bpy.ops.gpencil.stroke_separate*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-stroke-separate"),
+ ("bpy.ops.gpencil.stroke_separate*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-separate"),
("bpy.ops.gpencil.stroke_simplify*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-simplify"),
("bpy.ops.object.constraints_copy*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraints-copy"),
("bpy.ops.object.gpencil_modifier*", "grease_pencil/modifiers/index.html#bpy-ops-object-gpencil-modifier"),
@@ -365,7 +374,7 @@ url_manual_mapping = (
("bpy.types.spline.use_endpoint_u*", "modeling/curves/properties/active_spline.html#bpy-types-spline-use-endpoint-u"),
("bpy.types.userpreferencessystem*", "editors/preferences/system.html#bpy-types-userpreferencessystem"),
("bpy.ops.curve.switch_direction*", "modeling/curves/editing/segments.html#bpy-ops-curve-switch-direction"),
- ("bpy.ops.gpencil.duplicate_move*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-duplicate-move"),
+ ("bpy.ops.gpencil.duplicate_move*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-duplicate-move"),
("bpy.ops.gpencil.stroke_arrange*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-arrange"),
("bpy.ops.mesh.bridge-edge-loops*", "modeling/meshes/editing/edges.html#bpy-ops-mesh-bridge-edge-loops"),
("bpy.ops.object.paths_calculate*", "animation/motion_paths.html#bpy-ops-object-paths-calculate"),
@@ -424,7 +433,7 @@ url_manual_mapping = (
("bpy.ops.curve.spline_type_set*", "modeling/curves/editing/curve.html#bpy-ops-curve-spline-type-set"),
("bpy.ops.gpencil.move_to_layer*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-move-to-layer"),
("bpy.ops.gpencil.stroke_sample*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-sample"),
- ("bpy.ops.gpencil.stroke_smooth*", "grease_pencil/modes/edit/point.html#bpy-ops-gpencil-stroke-smooth"),
+ ("bpy.ops.gpencil.stroke_smooth*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-stroke-smooth"),
("bpy.ops.mesh.smoothen_normals*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-smoothen-normals"),
("bpy.ops.object.duplicate_move*", "scene_layout/object/editing/duplication.html#bpy-ops-object-duplicate-move"),
("bpy.ops.object.hook_add_selob*", "modeling/meshes/editing/vertices.html#bpy-ops-object-hook-add-selob"),
@@ -489,9 +498,9 @@ url_manual_mapping = (
("bpy.ops.console.autocomplete*", "editors/python_console.html#bpy-ops-console-autocomplete"),
("bpy.ops.curve.dissolve_verts*", "modeling/curves/editing/curve.html#bpy-ops-curve-dissolve-verts"),
("bpy.ops.curve.duplicate_move*", "modeling/curves/editing/curve.html#bpy-ops-curve-duplicate-move"),
- ("bpy.ops.gpencil.extrude_move*", "grease_pencil/modes/edit/point.html#bpy-ops-gpencil-extrude-move"),
- ("bpy.ops.gpencil.stroke_merge*", "grease_pencil/modes/edit/point.html#bpy-ops-gpencil-stroke-merge"),
- ("bpy.ops.gpencil.stroke_split*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-stroke-split"),
+ ("bpy.ops.gpencil.extrude_move*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-extrude-move"),
+ ("bpy.ops.gpencil.stroke_merge*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-stroke-merge"),
+ ("bpy.ops.gpencil.stroke_split*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-split"),
("bpy.ops.mesh.average_normals*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-average-normals"),
("bpy.ops.mesh.vertices_smooth*", "modeling/meshes/editing/transform/smooth.html#bpy-ops-mesh-vertices-smooth"),
("bpy.ops.node.read_viewlayers*", "interface/controls/nodes/editing.html#bpy-ops-node-read-viewlayers"),
@@ -536,6 +545,7 @@ url_manual_mapping = (
("bpy.types.shadernodeemission*", "render/shader_nodes/shader/emission.html#bpy-types-shadernodeemission"),
("bpy.types.shadernodegeometry*", "render/shader_nodes/input/geometry.html#bpy-types-shadernodegeometry"),
("bpy.types.shadernodehairinfo*", "render/shader_nodes/input/hair_info.html#bpy-types-shadernodehairinfo"),
+ ("bpy.types.shadernodemaprange*", "render/shader_nodes/converter/map_range.html#bpy-types-shadernodemaprange"),
("bpy.types.shadernodergbcurve*", "render/shader_nodes/color/rgb_curves.html#bpy-types-shadernodergbcurve"),
("bpy.types.shadernodeseparate*", "render/shader_nodes/converter/combine_separate.html#bpy-types-shadernodeseparate"),
("bpy.types.shadernodetexbrick*", "render/shader_nodes/textures/brick.html#bpy-types-shadernodetexbrick"),
@@ -660,7 +670,7 @@ url_manual_mapping = (
("bpy.types.texturenodegroup*", "editors/texture_node/types/groups.html#bpy-types-texturenodegroup"),
("bpy.types.texturenodeimage*", "editors/texture_node/types/input/image.html#bpy-types-texturenodeimage"),
("bpy.ops.curve.smooth_tilt*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-tilt"),
- ("bpy.ops.gpencil.reproject*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-reproject"),
+ ("bpy.ops.gpencil.reproject*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-reproject"),
("bpy.ops.mesh.flip_normals*", "modeling/meshes/editing/normals.html#bpy-ops-mesh-flip-normals"),
("bpy.ops.object.lightprobe*", "render/eevee/lightprobes/index.html#bpy-ops-object-lightprobe"),
("bpy.ops.object.make_links*", "scene_layout/object/editing/duplication.html#bpy-ops-object-make-links"),
@@ -694,6 +704,7 @@ url_manual_mapping = (
("bpy.types.rigidbodyobject*", "physics/rigid_body/index.html#bpy-types-rigidbodyobject"),
("bpy.types.sceneeevee.gtao*", "render/eevee/render_settings/ambient_occlusion.html#bpy-types-sceneeevee-gtao"),
("bpy.types.shadernodebevel*", "render/shader_nodes/input/bevel.html#bpy-types-shadernodebevel"),
+ ("bpy.types.shadernodeclamp*", "render/shader_nodes/converter/clamp.html#bpy-types-shadernodeclamp"),
("bpy.types.shadernodegamma*", "render/shader_nodes/color/gamma.html#bpy-types-shadernodegamma"),
("bpy.types.shadernodegroup*", "render/shader_nodes/groups.html#bpy-types-shadernodegroup"),
("bpy.types.shadernodeuvmap*", "render/shader_nodes/input/uv_map.html#bpy-types-shadernodeuvmap"),
@@ -707,7 +718,7 @@ url_manual_mapping = (
("bpy.ops.curve.select_row*", "modeling/surfaces/selecting.html#bpy-ops-curve-select-row"),
("bpy.ops.curve.tilt_clear*", "modeling/curves/editing/control_points.html#bpy-ops-curve-tilt-clear"),
("bpy.ops.curve.vertex_add*", "modeling/curves/editing/other.html#bpy-ops-curve-vertex-add"),
- ("bpy.ops.gpencil.dissolve*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-dissolve"),
+ ("bpy.ops.gpencil.dissolve*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-dissolve"),
("bpy.ops.graph.frame_jump*", "editors/graph_editor/fcurves/properties.html#bpy-ops-graph-frame-jump"),
("bpy.ops.mesh.edge_rotate*", "modeling/meshes/editing/edges.html#bpy-ops-mesh-edge-rotate"),
("bpy.ops.object.hide_view*", "scene_layout/object/editing/introduction.html#bpy-ops-object-hide-view"),
@@ -755,6 +766,7 @@ url_manual_mapping = (
("bpy.ops.uv.cube_project*", "modeling/meshes/editing/uv/unwrapping/mapping_types.html#bpy-ops-uv-cube-project"),
("bpy.ops.uv.pack_islands*", "modeling/meshes/editing/uv/layout.html#bpy-ops-uv-pack-islands"),
("bpy.ops.wm.app_template*", "advanced/app_templates.html#bpy-ops-wm-app-template"),
+ ("bpy.ops.wm.batch_rename*", "files/blend/rename.html#bpy-ops-wm-batch-rename"),
("bpy.ops.wm.redraw_timer*", "advanced/operators.html#bpy-ops-wm-redraw-timer"),
("bpy.types.*light.shadow*", "render/eevee/lighting.html#bpy-types-light-shadow"),
("bpy.types.armaturebones*", "animation/armatures/bones/index.html#bpy-types-armaturebones"),
@@ -795,7 +807,7 @@ url_manual_mapping = (
("bpy.ops.*.select_lasso*", "interface/selecting.html#bpy-ops-select-lasso"),
("bpy.ops.curve.decimate*", "modeling/curves/editing/curve.html#bpy-ops-curve-decimate"),
("bpy.ops.curve.separate*", "modeling/curves/editing/curve.html#bpy-ops-curve-separate"),
- ("bpy.ops.gpencil.delete*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-delete"),
+ ("bpy.ops.gpencil.delete*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-delete"),
("bpy.ops.gpencil.select*", "grease_pencil/selecting.html#bpy-ops-gpencil-select"),
("bpy.ops.mesh.mark_seam*", "modeling/meshes/editing/edges.html#bpy-ops-mesh-mark-seam"),
("bpy.ops.mesh.subdivide*", "modeling/meshes/editing/subdividing/subdivide.html#bpy-ops-mesh-subdivide"),
@@ -836,7 +848,7 @@ url_manual_mapping = (
("bpy.types.warpmodifier*", "modeling/modifiers/deform/warp.html#bpy-types-warpmodifier"),
("bpy.types.wavemodifier*", "modeling/modifiers/deform/wave.html#bpy-types-wavemodifier"),
("bpy.types.wipesequence*", "video_editing/sequencer/strips/transitions/wipe.html#bpy-types-wipesequence"),
- ("bpy.ops.gpencil.paste*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-paste"),
+ ("bpy.ops.gpencil.paste*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-paste"),
("bpy.ops.image.project*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-ops-image-project"),
("bpy.ops.mesh.decimate*", "modeling/meshes/editing/cleanup.html#bpy-ops-mesh-decimate"),
("bpy.ops.object.*clear*", "scene_layout/object/editing/transform/clear_apply.html#bpy-ops-object-clear"),
@@ -864,7 +876,7 @@ url_manual_mapping = (
("bpy.ops.curve.delete*", "modeling/curves/editing/curve.html#bpy-ops-curve-delete"),
("bpy.ops.curve.reveal*", "modeling/curves/editing/curve.html#bpy-ops-curve-reveal"),
("bpy.ops.curve.smooth*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth"),
- ("bpy.ops.gpencil.copy*", "grease_pencil/modes/edit/grease_pencil.html#bpy-ops-gpencil-copy"),
+ ("bpy.ops.gpencil.copy*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-copy"),
("bpy.ops.object.align*", "scene_layout/object/editing/transform/tools.html#bpy-ops-object-align"),
("bpy.ops.object.empty*", "modeling/empties.html#bpy-ops-object-empty"),
("bpy.ops.object.quick*", "physics/introduction.html#bpy-ops-object-quick"),
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 2ff6c3fc1b0..202fd865723 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -231,13 +231,15 @@ def draw(layout, context, context_member, property_type, use_edit=True):
if rna_item.id_data.library is not None:
use_edit = False
+ is_lib_override = rna_item.id_data.override_library and rna_item.id_data.override_library.reference
assert(isinstance(rna_item, property_type))
items = rna_item.items()
items.sort()
- if use_edit:
+ # TODO: Allow/support adding new custom props to overrides.
+ if use_edit and not is_lib_override:
row = layout.row()
props = row.operator("wm.properties_add", text="Add")
props.data_path = context_member
@@ -303,6 +305,9 @@ def draw(layout, context, context_member, property_type, use_edit=True):
if use_edit:
row = split.row(align=True)
+ # Do not allow editing of overridden properties (we cannot use a poll function of the operators here
+ # since they's have no access to the specific property...).
+ row.enabled = not(is_lib_override and key in rna_item.id_data.override_library.reference)
if not is_rna:
props = row.operator("wm.properties_edit", text="Edit")
assign_props(props, val_draw, key)
diff --git a/release/scripts/presets/keyconfig/blender.py b/release/scripts/presets/keyconfig/blender.py
index 60684be9163..596b17d734f 100644
--- a/release/scripts/presets/keyconfig/blender.py
+++ b/release/scripts/presets/keyconfig/blender.py
@@ -5,15 +5,15 @@ from bpy.props import (
EnumProperty,
)
-dirname, filename = os.path.split(__file__)
-idname = os.path.splitext(filename)[0]
+DIRNAME, FILENAME = os.path.split(__file__)
+IDNAME = os.path.splitext(FILENAME)[0]
def update_fn(_self, _context):
load()
class Prefs(bpy.types.KeyConfigPreferences):
- bl_idname = idname
+ bl_idname = IDNAME
select_mouse: EnumProperty(
name="Select Mouse",
@@ -154,7 +154,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
col.prop(self, "use_v3d_shade_ex_pie")
-blender_default = bpy.utils.execfile(os.path.join(dirname, "keymap_data", "blender_default.py"))
+blender_default = bpy.utils.execfile(os.path.join(DIRNAME, "keymap_data", "blender_default.py"))
def load():
@@ -163,13 +163,16 @@ def load():
from bl_keymap_utils.io import keyconfig_init_from_data
prefs = context.preferences
- kc = context.window_manager.keyconfigs.new(idname)
+ kc = context.window_manager.keyconfigs.new(IDNAME)
kc_prefs = kc.preferences
keyconfig_data = blender_default.generate_keymaps(
blender_default.Params(
select_mouse=kc_prefs.select_mouse,
- use_mouse_emulate_3_button=prefs.inputs.use_mouse_emulate_3_button,
+ use_mouse_emulate_3_button=(
+ prefs.inputs.use_mouse_emulate_3_button and
+ prefs.inputs.mouse_emulate_3_button_modifier == 'ALT'
+ ),
spacebar_action=kc_prefs.spacebar_action,
v3d_tilde_action=kc_prefs.v3d_tilde_action,
use_select_all_toggle=kc_prefs.use_select_all_toggle,
diff --git a/release/scripts/presets/keyconfig/blender_27x.py b/release/scripts/presets/keyconfig/blender_27x.py
index 052f5dd706a..8d50d449494 100644
--- a/release/scripts/presets/keyconfig/blender_27x.py
+++ b/release/scripts/presets/keyconfig/blender_27x.py
@@ -4,15 +4,15 @@ from bpy.props import (
EnumProperty,
)
-dirname, filename = os.path.split(__file__)
-idname = os.path.splitext(filename)[0]
+DIRNAME, FILENAME = os.path.split(__file__)
+IDNAME = os.path.splitext(FILENAME)[0]
def update_fn(_self, _context):
load()
class Prefs(bpy.types.KeyConfigPreferences):
- bl_idname = idname
+ bl_idname = IDNAME
select_mouse: EnumProperty(
name="Select Mouse",
@@ -39,7 +39,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
split.column()
-blender_default = bpy.utils.execfile(os.path.join(dirname, "keymap_data", "blender_default.py"))
+blender_default = bpy.utils.execfile(os.path.join(DIRNAME, "keymap_data", "blender_default.py"))
def load():
from sys import platform
@@ -47,13 +47,16 @@ def load():
from bl_keymap_utils.io import keyconfig_init_from_data
prefs = context.preferences
- kc = context.window_manager.keyconfigs.new(idname)
+ kc = context.window_manager.keyconfigs.new(IDNAME)
kc_prefs = kc.preferences
keyconfig_data = blender_default.generate_keymaps(
blender_default.Params(
select_mouse=kc_prefs.select_mouse,
- use_mouse_emulate_3_button=prefs.inputs.use_mouse_emulate_3_button,
+ use_mouse_emulate_3_button=(
+ prefs.inputs.use_mouse_emulate_3_button and
+ prefs.inputs.mouse_emulate_3_button_modifier == 'ALT'
+ ),
spacebar_action='SEARCH',
use_select_all_toggle=True,
use_gizmo_drag=False,
diff --git a/release/scripts/presets/keyconfig/industry_compatible.py b/release/scripts/presets/keyconfig/industry_compatible.py
index b7f069c7418..09a43452e93 100644
--- a/release/scripts/presets/keyconfig/industry_compatible.py
+++ b/release/scripts/presets/keyconfig/industry_compatible.py
@@ -5,14 +5,14 @@ import bpy
# ------------------------------------------------------------------------------
# Keymap
-dirname, filename = os.path.split(__file__)
-idname = os.path.splitext(filename)[0]
+DIRNAME, FILENAME = os.path.split(__file__)
+IDNAME = os.path.splitext(FILENAME)[0]
def update_fn(_self, _context):
load()
-industry_compatible = bpy.utils.execfile(os.path.join(dirname, "keymap_data", "industry_compatible_data.py"))
+industry_compatible = bpy.utils.execfile(os.path.join(DIRNAME, "keymap_data", "industry_compatible_data.py"))
def load():
@@ -21,7 +21,7 @@ def load():
prefs = bpy.context.preferences
- kc = bpy.context.window_manager.keyconfigs.new(idname)
+ kc = bpy.context.window_manager.keyconfigs.new(IDNAME)
params = industry_compatible.Params(use_mouse_emulate_3_button=prefs.inputs.use_mouse_emulate_3_button)
keyconfig_data = industry_compatible.generate_keymaps(params)
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index a4ae34b445c..25359510de2 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -1059,9 +1059,10 @@ def km_view3d(params):
("view3d.view_axis", {"type": 'NDOF_BUTTON_TOP', "value": 'PRESS', "shift": True},
{"properties": [("type", 'TOP'), ("align_active", True)]}),
# Selection.
- *(("view3d.select",
- {"type": params.select_mouse, "value": params.select_mouse_value, **{m: True for m in mods}},
- {"properties": [(c, True) for c in props]},
+ *((
+ "view3d.select",
+ {"type": params.select_mouse, "value": params.select_mouse_value, **{m: True for m in mods}},
+ {"properties": [(c, True) for c in props]},
) for props, mods in (
(("deselect_all",) if not params.legacy else (), ()),
(("toggle",), ("shift",)),
@@ -1447,7 +1448,6 @@ def km_graph_editor(params):
("graph.bake", {"type": 'C', "value": 'PRESS', "alt": True}, None),
op_menu("GRAPH_MT_delete", {"type": 'X', "value": 'PRESS'}),
op_menu("GRAPH_MT_delete", {"type": 'DEL', "value": 'PRESS'}),
- op_menu("GRAPH_MT_context_menu", params.context_menu_event),
("graph.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
("graph.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
("graph.click_insert", {"type": params.action_mouse, "value": 'CLICK', "ctrl": True},
@@ -1478,6 +1478,7 @@ def km_graph_editor(params):
op_menu_pie("GRAPH_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
+ op_menu("GRAPH_MT_context_menu", params.context_menu_event),
])
if params.select_mouse == 'LEFTMOUSE' and not params.legacy:
@@ -1581,11 +1582,16 @@ def km_image(params):
)
),
op_menu_pie("IMAGE_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
- op_menu("IMAGE_MT_mask_context_menu", params.context_menu_event),
("image.render_border", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
("image.clear_render_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None),
+ op_menu("IMAGE_MT_mask_context_menu", params.context_menu_event),
])
+ if params.legacy:
+ items.extend([
+ ("image.view_center_cursor", {"type": 'HOME', "value": 'PRESS', "alt": True}, None),
+ ])
+
return keymap
@@ -1665,7 +1671,6 @@ def km_node_editor(params):
{"properties": [("factor", 1.2)]}),
("node.backimage_fit", {"type": 'HOME', "value": 'PRESS', "alt": True}, None),
("node.backimage_sample", {"type": params.action_mouse, "value": 'PRESS', "alt": True}, None),
- op_menu("NODE_MT_context_menu", params.context_menu_event),
("node.link_make", {"type": 'F', "value": 'PRESS'},
{"properties": [("replace", False)]}),
("node.link_make", {"type": 'F', "value": 'PRESS', "shift": True},
@@ -1731,6 +1736,7 @@ def km_node_editor(params):
{"properties": [("data_path", 'tool_settings.use_snap')]}),
("wm.context_menu_enum", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("data_path", 'tool_settings.snap_node_element')]}),
+ op_menu("NODE_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -1785,7 +1791,11 @@ def km_file_browser(params):
("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.params.show_hidden')]}),
- ("file.directory_new", {"type": 'I', "value": 'PRESS'}, None),
+ ("file.directory_new", {"type": 'I', "value": 'PRESS'},
+ {"properties": [("confirm", False)]}),
+ ("file.rename", {"type": 'F2', "value": 'PRESS'}, None),
+ ("file.delete", {"type": 'X', "value": 'PRESS'}, None),
+ ("file.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None),
("file.bookmark_add", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS'},
@@ -1824,7 +1834,7 @@ def km_file_browser_main(params):
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
{"properties": [("extend", True)]}),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
- {"properties": [("extend", True), ("fill", True)]}),
+ {"properties": [("extend", True), ("fill", True), ("open", False)]}),
("file.select_walk", {"type": 'UP_ARROW', "value": 'PRESS'},
{"properties": [("direction", 'UP')]}),
("file.select_walk", {"type": 'UP_ARROW', "value": 'PRESS', "shift": True},
@@ -1976,7 +1986,6 @@ def km_dopesheet(params):
("action.interpolation_type", {"type": 'T', "value": 'PRESS'}, None),
("action.extrapolation_type", {"type": 'E', "value": 'PRESS', "shift": True}, None),
("action.keyframe_type", {"type": 'R', "value": 'PRESS'}, None),
- op_menu("DOPESHEET_MT_context_menu", params.context_menu_event),
("action.sample", {"type": 'O', "value": 'PRESS', "shift": True, "alt": True}, None),
op_menu("DOPESHEET_MT_delete", {"type": 'X', "value": 'PRESS'}),
op_menu("DOPESHEET_MT_delete", {"type": 'DEL', "value": 'PRESS'}),
@@ -2008,6 +2017,7 @@ def km_dopesheet(params):
op_menu_pie("VIEW3D_MT_proportional_editing_falloff_pie", {"type": 'O', "value": 'PRESS', "shift": True}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
+ op_menu("DOPESHEET_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -2121,7 +2131,6 @@ def km_nla_editor(params):
("nla.apply_scale", {"type": 'A', "value": 'PRESS', "ctrl": True}, None),
("nla.clear_scale", {"type": 'S', "value": 'PRESS', "alt": True}, None),
op_menu_pie("NLA_MT_snap_pie", {"type": 'S', "value": 'PRESS', "shift": True}),
- op_menu("NLA_MT_context_menu", params.context_menu_event),
("nla.fmodifier_add", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("transform.transform", {"type": 'G', "value": 'PRESS'},
{"properties": [("mode", 'TRANSLATION')]}),
@@ -2133,6 +2142,7 @@ def km_nla_editor(params):
{"properties": [("mode", 'TIME_SCALE')]}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
+ op_menu("NLA_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -2292,9 +2302,9 @@ def km_text(params):
{"properties": [("lines", 1)]}),
("text.line_break", {"type": 'RET', "value": 'PRESS'}, None),
("text.line_break", {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, None),
- op_menu("TEXT_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("text.autocomplete", {"type": 'SPACE', "value": 'PRESS', "ctrl": True}, None),
("text.line_number", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None),
+ op_menu("TEXT_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("text.insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None),
])
@@ -2422,7 +2432,6 @@ def km_sequencer(params):
("sequencer.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None),
op_menu("SEQUENCER_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}),
op_menu("SEQUENCER_MT_change", {"type": 'C', "value": 'PRESS'}),
- op_menu("SEQUENCER_MT_context_menu", params.context_menu_event),
("sequencer.slip", {"type": 'S', "value": 'PRESS'}, None),
("wm.context_set_int", {"type": 'O', "value": 'PRESS'},
{"properties": [("data_path", 'scene.sequence_editor.overlay_frame'), ("value", 0)]}),
@@ -2432,10 +2441,11 @@ def km_sequencer(params):
{"properties": [("mode", 'TIME_EXTEND')]}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
- ("sequencer.select",{"type": 'LEFT_BRACKET', "value": 'PRESS'},
- {"properties": [("left_right", 'LEFT'), ("linked_time", True)]}),
- ("sequencer.select",{"type": 'RIGHT_BRACKET', "value": 'PRESS'},
- {"properties": [("left_right", 'RIGHT'), ("linked_time", True)]}),
+ ("sequencer.select", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
+ {"properties": [("left_right", 'LEFT'), ("linked_time", True)]}),
+ ("sequencer.select", {"type": 'RIGHT_BRACKET', "value": 'PRESS'},
+ {"properties": [("left_right", 'RIGHT'), ("linked_time", True)]}),
+ op_menu("SEQUENCER_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -2532,8 +2542,8 @@ def km_console(params):
{"properties": [("text", '\t')]}),
("console.indent", {"type": 'TAB', "value": 'PRESS'}, None),
("console.unindent", {"type": 'TAB', "value": 'PRESS', "shift": True}, None),
+ op_menu("CONSOLE_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
("console.insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None),
- op_menu("CONSOLE_MT_context_menu", params.context_menu_event),
])
return keymap
@@ -2656,11 +2666,10 @@ def km_clip_editor(params):
("clip.hide_tracks", {"type": 'H', "value": 'PRESS', "shift": True},
{"properties": [("unselected", True)]}),
("clip.hide_tracks_clear", {"type": 'H', "value": 'PRESS', "alt": True}, None),
- ("clip.slide_plane_marker", {"type": params.action_mouse, "value": 'PRESS'}, None),
+ ("clip.slide_plane_marker", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'}, None),
("clip.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
("clip.keyframe_delete", {"type": 'I', "value": 'PRESS', "alt": True}, None),
("clip.join_tracks", {"type": 'J', "value": 'PRESS', "ctrl": True}, None),
- op_menu("CLIP_MT_tracking_context_menu", params.context_menu_event),
("clip.lock_selection_toggle", {"type": 'L', "value": 'PRESS'}, None),
("wm.context_toggle", {"type": 'D', "value": 'PRESS', "alt": True},
{"properties": [("data_path", 'space_data.show_disabled')]}),
@@ -2682,8 +2691,14 @@ def km_clip_editor(params):
op_menu_pie("CLIP_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
("clip.copy_tracks", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("clip.paste_tracks", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
+ op_menu("CLIP_MT_tracking_context_menu", params.context_menu_event),
])
+ if params.legacy:
+ items.extend([
+ ("clip.view_center_cursor", {"type": 'HOME', "value": 'PRESS', "alt": True}, None),
+ ])
+
return keymap
@@ -3037,8 +3052,6 @@ def km_grease_pencil_stroke_edit_mode(params):
("gpencil.blank_frame_add", {"type": 'I', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "shift": True}, None),
- # Context menu
- op_menu("VIEW3D_MT_gpencil_edit_context_menu", params.context_menu_event),
# Separate
("gpencil.stroke_separate", {"type": 'P', "value": 'PRESS'}, None),
# Split and joint strokes
@@ -3093,6 +3106,8 @@ def km_grease_pencil_stroke_edit_mode(params):
{"properties": [("mode", 1)]}),
("gpencil.selectmode_toggle", {"type": 'THREE', "value": 'PRESS'},
{"properties": [("mode", 2)]}),
+ # Context menu
+ op_menu("VIEW3D_MT_gpencil_edit_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -3119,8 +3134,6 @@ def km_grease_pencil_stroke_paint_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_paint.brush.size')]}),
- # Draw context menu
- op_panel("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event),
# Draw delete menu
op_menu("GPENCIL_MT_gpencil_draw_delete", {"type": 'X', "value": 'PRESS'}),
# Animation menu
@@ -3136,6 +3149,8 @@ def km_grease_pencil_stroke_paint_mode(params):
{"properties": [("unselected", False)]}),
("gpencil.hide", {"type": 'H', "value": 'PRESS', "shift": True},
{"properties": [("unselected", True)]}),
+ # Draw context menu
+ op_panel("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event),
])
return keymap
@@ -3158,9 +3173,6 @@ def km_grease_pencil_stroke_paint_draw_brush(params):
# Draw - straight lines
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
{"properties": [("mode", 'DRAW_STRAIGHT'), ("wait_for_input", False)]}),
- # Draw - poly lines
- ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "alt": True},
- {"properties": [("mode", 'DRAW_POLY'), ("wait_for_input", False)]}),
# Erase
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}),
@@ -3266,18 +3278,18 @@ def km_grease_pencil_stroke_sculpt_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.size')]}),
- # Context menu
- op_panel("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event),
# Copy
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
# Display
*_grease_pencil_display(),
+ # Context menu
+ op_panel("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event),
])
return keymap
-def km_grease_pencil_stroke_weight_mode(params):
+def km_grease_pencil_stroke_weight_mode(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight Mode",
@@ -3413,7 +3425,6 @@ def km_pose(params):
("pose.push", {"type": 'E', "value": 'PRESS', "ctrl": True}, None),
("pose.relax", {"type": 'E', "value": 'PRESS', "alt": True}, None),
("pose.breakdown", {"type": 'E', "value": 'PRESS', "shift": True}, None),
- op_menu("VIEW3D_MT_pose_context_menu", params.context_menu_event),
op_menu("VIEW3D_MT_pose_propagate", {"type": 'P', "value": 'PRESS', "alt": True}),
*(
(("object.hide_collection",
@@ -3422,6 +3433,7 @@ def km_pose(params):
for i in range(10)
)
),
+ op_menu("VIEW3D_MT_pose_context_menu", params.context_menu_event),
])
return keymap
@@ -3484,7 +3496,6 @@ def km_object_mode(params):
("collection.objects_remove_all", {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None),
("collection.objects_add_active", {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("collection.objects_remove_active", {"type": 'G', "value": 'PRESS', "shift": True, "alt": True}, None),
- op_menu("VIEW3D_MT_object_context_menu", params.context_menu_event),
*_template_items_object_subdivision_set(),
("object.move_to_collection", {"type": 'M', "value": 'PRESS'}, None),
("object.link_to_collection", {"type": 'M', "value": 'PRESS', "shift": True}, None),
@@ -3501,6 +3512,7 @@ def km_object_mode(params):
for i in range(10)
)
),
+ op_menu("VIEW3D_MT_object_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -3601,9 +3613,9 @@ def km_curve(params):
{"properties": [("unselected", True)]}),
("curve.normals_make_consistent", {"type": 'N', "value": 'PRESS', "ctrl" if params.legacy else "shift": True}, None),
("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
- op_menu("VIEW3D_MT_edit_curve_context_menu", params.context_menu_event),
op_menu("VIEW3D_MT_hook", {"type": 'H', "value": 'PRESS', "ctrl": True}),
*_template_items_proportional_editing(connected=True),
+ op_menu("VIEW3D_MT_edit_curve_context_menu", params.context_menu_event),
])
return keymap
@@ -3854,6 +3866,9 @@ def km_sculpt(params):
# Dynamic topology
("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ # Remesh
+ ("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None),
# Brush properties
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
{"properties": [("scalar", 0.9)]}),
@@ -3902,8 +3917,8 @@ def km_sculpt(params):
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.sculpt.brush.use_smooth_stroke')]}),
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
+ op_menu_pie("VIEW3D_MT_sculpt_mask_edit_pie", {"type" : 'A', "value": 'PRESS'}),
op_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event),
- op_menu_pie("VIEW3D_MT_sculpt_mask_edit_pie", {"type" : 'A', "value": 'PRESS'})
])
if params.legacy:
@@ -4007,7 +4022,6 @@ def km_mesh(params):
{"properties": [("use_occlude_geometry", True), ("only_selected", False)]}),
("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
# Menus.
- op_menu("VIEW3D_MT_edit_mesh_context_menu", params.context_menu_event),
op_menu("VIEW3D_MT_edit_mesh_faces", {"type": 'F', "value": 'PRESS', "ctrl": True}),
op_menu("VIEW3D_MT_edit_mesh_edges", {"type": 'E', "value": 'PRESS', "ctrl": True}),
op_menu("VIEW3D_MT_edit_mesh_vertices", {"type": 'V', "value": 'PRESS', "ctrl": True}),
@@ -4017,6 +4031,7 @@ def km_mesh(params):
op_menu("VIEW3D_MT_edit_mesh_normals", {"type": 'N', "value": 'PRESS', "alt" : True}),
("object.vertex_group_remove_from", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None),
*_template_items_proportional_editing(connected=True),
+ op_menu("VIEW3D_MT_edit_mesh_context_menu", params.context_menu_event),
])
if params.use_mouse_emulate_3_button and params.select_mouse == 'LEFTMOUSE':
@@ -4173,8 +4188,8 @@ def km_lattice(params):
("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
("lattice.flip", {"type": 'F', "value": 'PRESS', "alt": True}, None),
op_menu("VIEW3D_MT_hook", {"type": 'H', "value": 'PRESS', "ctrl": True}),
- op_menu("VIEW3D_MT_edit_lattice_context_menu", params.context_menu_event),
*_template_items_proportional_editing(connected=False),
+ op_menu("VIEW3D_MT_edit_lattice_context_menu", params.context_menu_event),
])
return keymap
@@ -4210,7 +4225,6 @@ def km_particle(params):
{"properties": [("data_path_primary", 'tool_settings.particle_edit.brush.size')]}),
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.particle_edit.brush.strength')]}),
- op_menu("VIEW3D_MT_particle_context_menu", params.context_menu_event),
("particle.weight_set", {"type": 'K', "value": 'PRESS', "shift": True}, None),
*(
(("wm.context_set_enum",
@@ -4220,6 +4234,7 @@ def km_particle(params):
)
),
*_template_items_proportional_editing(connected=False),
+ op_menu("VIEW3D_MT_particle_context_menu", params.context_menu_event),
])
return keymap
@@ -5778,6 +5793,19 @@ def km_3d_view_tool_paint_gpencil_line(params):
]},
)
+def km_3d_view_tool_paint_gpencil_polyline(params):
+ return (
+ "3D View Tool: Paint Gpencil, Polyline",
+ {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+ {"items": [
+ ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'},
+ {"properties": [("type", 'POLYLINE'), ("wait_for_input", False)]}),
+ ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+ {"properties": [("type", 'POLYLINE'), ("wait_for_input", False)]}),
+ # Lasso select
+ ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None),
+ ]},
+ )
def km_3d_view_tool_paint_gpencil_box(params):
return (
@@ -5855,6 +5883,18 @@ def km_3d_view_tool_paint_gpencil_cutter(params):
)
+def km_3d_view_tool_paint_gpencil_eyedropper(params):
+ return (
+ "3D View Tool: Paint Gpencil, Eyedropper",
+ {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+ {"items": [
+ ("ui.eyedropper_gpencil_color", {"type": params.tool_mouse, "value": 'PRESS'}, None),
+ ("ui.eyedropper_gpencil_color", {"type": params.tool_mouse, "value": 'PRESS', "shift": True}, None),
+ ("ui.eyedropper_gpencil_color", {"type": params.tool_mouse, "value": 'PRESS', "shift": True, "ctrl": True}, None),
+ ]},
+ )
+
+
def km_3d_view_tool_edit_gpencil_select(params):
return (
"3D View Tool: Edit Gpencil, Tweak",
@@ -5890,6 +5930,16 @@ def km_3d_view_tool_edit_gpencil_select_lasso(params):
)
+def km_3d_view_tool_edit_gpencil_extrude(params):
+ return (
+ "3D View Tool: Edit Gpencil, Extrude",
+ {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+ {"items": [
+ ("gpencil.extrude_move", {"type": params.tool_tweak, "value": 'ANY'}, None),
+ ]},
+ )
+
+
def km_3d_view_tool_edit_gpencil_radius(params):
return (
"3D View Tool: Edit Gpencil, Radius",
@@ -6177,15 +6227,18 @@ def generate_keymaps(params=None):
km_3d_view_tool_paint_weight_sample_vertex_group(params),
km_3d_view_tool_paint_weight_gradient(params),
km_3d_view_tool_paint_gpencil_line(params),
+ km_3d_view_tool_paint_gpencil_polyline(params),
km_3d_view_tool_paint_gpencil_box(params),
km_3d_view_tool_paint_gpencil_circle(params),
km_3d_view_tool_paint_gpencil_arc(params),
km_3d_view_tool_paint_gpencil_curve(params),
km_3d_view_tool_paint_gpencil_cutter(params),
+ km_3d_view_tool_paint_gpencil_eyedropper(params),
km_3d_view_tool_edit_gpencil_select(params),
km_3d_view_tool_edit_gpencil_select_box(params),
km_3d_view_tool_edit_gpencil_select_circle(params),
km_3d_view_tool_edit_gpencil_select_lasso(params),
+ km_3d_view_tool_edit_gpencil_extrude(params),
km_3d_view_tool_edit_gpencil_radius(params),
km_3d_view_tool_edit_gpencil_bend(params),
km_3d_view_tool_edit_gpencil_shear(params),
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index 29a002b2754..49a394b478d 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -1171,15 +1171,23 @@ def km_file_browser(params):
items.extend([
("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "alt": True}, None),
+ ("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "ctrl": True}, None),
("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, None),
+ ("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "ctrl": True}, None),
("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, None),
- ("file.refresh", {"type": 'R', "value": 'PRESS'}, None),
- ("file.parent", {"type": 'P', "value": 'PRESS'}, None),
+ ("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, None),
+ ("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("file.previous", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
+ ("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None),
("wm.context_toggle", {"type": 'H', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.params.show_hidden')]}),
- ("file.directory_new", {"type": 'I', "value": 'PRESS'}, None),
+ ("file.directory_new", {"type": 'I', "value": 'PRESS'},
+ {"properties": [("confirm", False)]}),
+ ("file.rename", {"type": 'F2', "value": 'PRESS'}, None),
+ ("file.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None),
- ("file.bookmark_toggle", {"type": 'T', "value": 'PRESS'}, None),
+ ("wm.context_toggle", {"type": 'T', "value": 'PRESS'},
+ {"properties": [("data_path", 'space_data.show_region_toolbar')]}),
("file.bookmark_add", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS'},
{"properties": [("increment", 1)]}),
@@ -1217,7 +1225,7 @@ def km_file_browser_main(params):
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
{"properties": [("extend", True)]}),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True,},
- {"properties": [("extend", True), ("fill", True)]}),
+ {"properties": [("extend", True), ("fill", True), ("open", False)]}),
("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("extend", True), ("open", False)]}),
("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "alt": True},
diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py
index 316ad152a32..0f95371d4c5 100644
--- a/release/scripts/startup/bl_operators/add_mesh_torus.py
+++ b/release/scripts/startup/bl_operators/add_mesh_torus.py
@@ -125,7 +125,7 @@ def add_uvs(mesh, minor_seg, major_seg):
class AddTorus(Operator, object_utils.AddObjectHelper):
- """Add a torus mesh"""
+ """Construct a torus mesh"""
bl_idname = "mesh.primitive_torus_add"
bl_label = "Add Torus"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index f16f97ab156..4c014ff7ac4 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -89,7 +89,7 @@ class CopyRigidbodySettings(Operator):
class BakeToKeyframes(Operator):
'''Bake rigid body transformations of selected objects to keyframes'''
bl_idname = "rigidbody.bake_to_keyframes"
- bl_label = "Bake To Keyframes"
+ bl_label = "Bake to Keyframes"
bl_options = {'REGISTER', 'UNDO'}
frame_start: IntProperty(
diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py
index 1da96834a5a..ab87dc47075 100644
--- a/release/scripts/startup/bl_operators/sequencer.py
+++ b/release/scripts/startup/bl_operators/sequencer.py
@@ -20,8 +20,6 @@
import bpy
from bpy.types import Operator
-from mathutils import Vector
-from math import floor
from bpy.props import IntProperty
@@ -139,13 +137,9 @@ class SequencerDeinterlaceSelectedMovies(Operator):
class SequencerFadesClear(Operator):
- """Removes fade animation from selected sequences.
- Removes opacity or volume animation on selected sequences and resets the
- property to a value of 1.0. Works on all types of sequences.
- """
+ """Removes fade animation from selected sequences"""
bl_idname = "sequencer.fades_clear"
bl_label = "Clear Fades"
- bl_description = "Removes fade animation from selected sequences."
bl_options = {'REGISTER', 'UNDO'}
@classmethod
@@ -154,31 +148,26 @@ class SequencerFadesClear(Operator):
def execute(self, context):
fcurves = context.scene.animation_data.action.fcurves
-
+ fcurve_map = {
+ curve.data_path: curve
+ for curve in fcurves
+ if curve.data_path.startswith("sequence_editor.sequences_all")
+ }
for sequence in context.selected_sequences:
- animated_property = 'volume' if hasattr(sequence, 'volume') else 'blend_alpha'
- for curve in fcurves:
- if not curve.data_path.endswith(animated_property):
- continue
- # Ensure the fcurve corresponds to the selected sequence
- if sequence == eval("bpy.context.scene." + curve.data_path.replace('.' + animated_property, '')):
- fcurves.remove(curve)
+ animated_property = "volume" if hasattr(sequence, "volume") else "blend_alpha"
+ data_path = sequence.path_from_id() + "." + animated_property
+ curve = fcurve_map.get(data_path)
+ if curve:
+ fcurves.remove(curve)
setattr(sequence, animated_property, 1.0)
+
return {'FINISHED'}
class SequencerFadesAdd(Operator):
- """Adds or updates a fade animation for either visual or audio strips.
- Fade options:
- - In, Out, In and Out create a fade animation of the given duration from
- the start of the sequence, to the end of the sequence, or on boths sides
- - From playhead: the fade animation goes from the start of sequences under the playhead to the playhead
- - To playhead: the fade animation goes from the playhead to the end of sequences under the playhead
- By default, the duration of the fade is 1 second.
- """
+ """Adds or updates a fade animation for either visual or audio strips"""
bl_idname = "sequencer.fades_add"
bl_label = "Add Fades"
- bl_description = "Adds or updates a fade animation for either visual or audio strips."
bl_options = {'REGISTER', 'UNDO'}
duration_seconds: bpy.props.FloatProperty(
@@ -187,13 +176,15 @@ class SequencerFadesAdd(Operator):
default=1.0,
min=0.01)
type: bpy.props.EnumProperty(
- items=[('IN_OUT', 'Fade In And Out', 'Fade selected strips in and out'),
- ('IN', 'Fade In', 'Fade in selected strips'),
- ('OUT', 'Fade Out', 'Fade out selected strips'),
- ('CURSOR_FROM', 'From Playhead', 'Fade from the time cursor to the end of overlapping sequences'),
- ('CURSOR_TO', 'To Playhead', 'Fade from the start of sequences under the time cursor to the current frame')],
+ items=(
+ ('IN_OUT', 'Fade In And Out', 'Fade selected strips in and out'),
+ ('IN', 'Fade In', 'Fade in selected strips'),
+ ('OUT', 'Fade Out', 'Fade out selected strips'),
+ ('CURSOR_FROM', 'From Playhead', 'Fade from the time cursor to the end of overlapping sequences'),
+ ('CURSOR_TO', 'To Playhead', 'Fade from the start of sequences under the time cursor to the current frame'),
+ ),
name="Fade type",
- description="Fade in, out, both in and out, to, or from the playhead. Default is both in and out.",
+ description="Fade in, out, both in and out, to, or from the playhead. Default is both in and out",
default='IN_OUT')
@classmethod
@@ -202,6 +193,8 @@ class SequencerFadesAdd(Operator):
return context.scene and context.scene.sequence_editor and context.scene.sequence_editor.active_strip
def execute(self, context):
+ from math import floor
+
# We must create a scene action first if there's none
scene = context.scene
if not scene.animation_data:
@@ -211,9 +204,11 @@ class SequencerFadesAdd(Operator):
scene.animation_data.action = action
sequences = context.selected_sequences
- if self.type in ['CURSOR_TO', 'CURSOR_FROM']:
- sequences = [s for s in sequences
- if s.frame_final_start < context.scene.frame_current < s.frame_final_end]
+ if self.type in {'CURSOR_TO', 'CURSOR_FROM'}:
+ sequences = [
+ s for s in sequences
+ if s.frame_final_start < context.scene.frame_current < s.frame_final_end
+ ]
max_duration = min(sequences, key=lambda s: s.frame_final_duration).frame_final_duration
max_duration = floor(max_duration / 2.0) if self.type == 'IN_OUT' else max_duration
@@ -228,13 +223,13 @@ class SequencerFadesAdd(Operator):
animated_property = 'volume' if hasattr(sequence, 'volume') else 'blend_alpha'
fade_fcurve = self.fade_find_or_create_fcurve(context, sequence, animated_property)
fades = self.calculate_fades(sequence, fade_fcurve, animated_property, duration)
- self.fade_animation_clear(context, fade_fcurve, fades)
+ self.fade_animation_clear(fade_fcurve, fades)
self.fade_animation_create(fade_fcurve, fades)
faded_sequences.append(sequence)
sequence_string = "sequence" if len(faded_sequences) == 1 else "sequences"
- self.report({"INFO"}, "Added fade animation to {} {}.".format(len(faded_sequences), sequence_string))
- return {"FINISHED"}
+ self.report({'INFO'}, "Added fade animation to {} {}.".format(len(faded_sequences), sequence_string))
+ return {'FINISHED'}
def calculate_fade_duration(self, context, sequence):
frame_current = context.scene.frame_current
@@ -248,9 +243,7 @@ class SequencerFadesAdd(Operator):
return max(1, duration)
def is_long_enough(self, sequence, duration=0.0):
- minimum_duration = (duration * 2
- if self.type == 'IN_OUT' else
- duration)
+ minimum_duration = duration * 2 if self.type == 'IN_OUT' else duration
return sequence.frame_final_duration >= minimum_duration
def calculate_fades(self, sequence, fade_fcurve, animated_property, duration):
@@ -258,10 +251,10 @@ class SequencerFadesAdd(Operator):
Returns a list of Fade objects
"""
fades = []
- if self.type in ['IN', 'IN_OUT', 'CURSOR_TO']:
+ if self.type in {'IN', 'IN_OUT', 'CURSOR_TO'}:
fade = Fade(sequence, fade_fcurve, 'IN', animated_property, duration)
fades.append(fade)
- if self.type in ['OUT', 'IN_OUT', 'CURSOR_FROM']:
+ if self.type in {'OUT', 'IN_OUT', 'CURSOR_FROM'}:
fade = Fade(sequence, fade_fcurve, 'OUT', animated_property, duration)
fades.append(fade)
return fades
@@ -283,7 +276,7 @@ class SequencerFadesAdd(Operator):
fade_fcurve = fcurves.new(data_path=searched_data_path)
return fade_fcurve
- def fade_animation_clear(self, context, fade_fcurve, fades):
+ def fade_animation_clear(self, fade_fcurve, fades):
"""
Removes existing keyframes in the fades' time range, in fast mode, without
updating the fcurve
@@ -295,7 +288,7 @@ class SequencerFadesAdd(Operator):
# operator re-runs Leading to trying to remove nonexistent keyframes
try:
if fade.start.x < keyframe.co[0] <= fade.end.x:
- keyframe_points.remove(keyframe, fast=True)
+ keyframe_points.remove(keyframe, fast=True)
except Exception:
pass
fade_fcurve.update()
@@ -315,16 +308,18 @@ class SequencerFadesAdd(Operator):
class Fade:
- """
- Data structure to represent fades
- """
- type = ''
- animated_property = ''
- duration = -1
- max_value = 1.0
- start, end = Vector((0, 0)), Vector((0, 0))
+ # Data structure to represent fades.
+ __slots__ = (
+ "type",
+ "animated_property",
+ "duration",
+ "max_value",
+ "start",
+ "end",
+ )
def __init__(self, sequence, fade_fcurve, type, animated_property, duration):
+ from mathutils import Vector
self.type = type
self.animated_property = animated_property
self.duration = duration
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index 6311bcade7a..0cd90610cdc 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -114,7 +114,8 @@ class PREFERENCES_OT_copy_prev(Operator):
shutil.copytree(self._old_path(), self._new_path(), symlinks=True)
- # reload recent-files.txt
+ # reload preferences and recent-files.txt
+ bpy.ops.wm.read_userpref()
bpy.ops.wm.read_history()
# don't loose users work if they open the splash later.
@@ -537,7 +538,7 @@ class PREFERENCES_OT_addon_refresh(Operator):
class PREFERENCES_OT_addon_install(Operator):
"""Install an add-on"""
bl_idname = "preferences.addon_install"
- bl_label = "Install"
+ bl_label = "Install Add-on"
overwrite: BoolProperty(
name="Overwrite",
diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
index 2b20754a995..2befb7c73e2 100644
--- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py
+++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
@@ -565,7 +565,12 @@ def unwrap(operator, context, **kwargs):
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
# define list of meshes
- meshes = list({me for obj in context.selected_objects if obj.type == 'MESH' for me in (obj.data,) if me.polygons and me.library is None})
+ meshes = list({
+ me for obj in context.selected_objects
+ if obj.type == 'MESH'
+ for me in (obj.data,)
+ if me.polygons and me.library is None
+ })
if not meshes:
operator.report({'ERROR'}, "No mesh object")
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index d2e2a61826f..0dad29ce683 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1103,7 +1103,7 @@ class WM_OT_doc_view(Operator):
bl_label = "View Documentation"
doc_id: doc_id
- if bpy.app.version_cycle in {"release", "rc"}:
+ if bpy.app.version_cycle in {"release", "rc", "beta"}:
_prefix = ("https://docs.blender.org/api/%d.%d%s" %
(bpy.app.version[0], bpy.app.version[1], bpy.app.version_char))
else:
@@ -1995,7 +1995,6 @@ class WM_OT_batch_rename(Operator):
descr,
)
-
return data
@staticmethod
@@ -2038,7 +2037,7 @@ class WM_OT_batch_rename(Operator):
if action.use_replace_regex_dst:
replace_dst = action.replace_dst
else:
- replace_dst = re.escape(action.replace_dst)
+ replace_dst = action.replace_dst.replace("\\", "\\\\")
else:
replace_src = re.escape(action.replace_src)
replace_dst = re.escape(action.replace_dst)
@@ -2201,7 +2200,7 @@ class WM_OT_batch_rename(Operator):
change_len += 1
total_len += 1
- self.report({'INFO'}, "Renamed {:d} of {:d} {:s}".format(total_len, change_len, descr))
+ self.report({'INFO'}, "Renamed {:d} of {:d} {:s}".format(change_len, total_len, descr))
return {'FINISHED'}
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index c090b27d80f..6cf448d4fe8 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -332,7 +332,8 @@ class DATA_PT_font(CurveButtonsPanelText, Panel):
layout = self.layout
text = context.curve
- char = context.curve.edit_format
+ char = text.edit_format
+ mode = context.mode
row = layout.split(factor=0.25)
row.label(text="Regular")
@@ -347,13 +348,14 @@ class DATA_PT_font(CurveButtonsPanelText, Panel):
row.label(text="Bold & Italic")
row.template_ID(text, "font_bold_italic", open="font.open", unlink="font.unlink")
- layout.separator()
+ if mode == 'EDIT_TEXT':
+ layout.separator()
- row = layout.row(align=True)
- row.prop(char, "use_bold", toggle=True)
- row.prop(char, "use_italic", toggle=True)
- row.prop(char, "use_underline", toggle=True)
- row.prop(char, "use_small_caps", toggle=True)
+ row = layout.row(align=True)
+ row.prop(char, "use_bold", toggle=True)
+ row.prop(char, "use_italic", toggle=True)
+ row.prop(char, "use_underline", toggle=True)
+ row.prop(char, "use_small_caps", toggle=True)
class DATA_PT_font_transform(CurveButtonsPanelText, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_lattice.py b/release/scripts/startup/bl_ui/properties_data_lattice.py
index d9bcdeed5a4..60c46f1c0dd 100644
--- a/release/scripts/startup/bl_ui/properties_data_lattice.py
+++ b/release/scripts/startup/bl_ui/properties_data_lattice.py
@@ -43,13 +43,10 @@ class DATA_PT_context_lattice(DataButtonsPanel, Panel):
lat = context.lattice
space = context.space_data
- split = layout.split(factor=0.65)
if ob:
- split.template_ID(ob, "data")
- split.separator()
+ layout.template_ID(ob, "data")
elif lat:
- split.template_ID(space, "pin_id")
- split.separator()
+ layout.template_ID(space, "pin_id")
class DATA_PT_lattice(DataButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index e7cdc221c0a..a4920568198 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -72,8 +72,8 @@ class MESH_MT_shape_key_context_menu(Menu):
layout.separator()
layout.operator("object.shape_key_remove", icon='X', text="Delete All Shape Keys").all = True
layout.separator()
- layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move To Top").type = 'TOP'
- layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move To Bottom").type = 'BOTTOM'
+ layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move to Top").type = 'TOP'
+ layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM'
class MESH_UL_vgroups(UIList):
@@ -476,12 +476,16 @@ class DATA_PT_remesh(MeshButtonsPanel, Panel):
col = layout.column()
if (mesh.remesh_mode == 'VOXEL'):
col.prop(mesh, "remesh_voxel_size")
+ col.prop(mesh, "remesh_voxel_adaptivity")
+ col.prop(mesh, "remesh_fix_poles")
col.prop(mesh, "remesh_smooth_normals")
+ col.prop(mesh, "remesh_preserve_volume")
col.prop(mesh, "remesh_preserve_paint_mask")
col.operator("object.voxel_remesh", text="Voxel Remesh")
else:
col.operator("object.quadriflow_remesh", text="QuadriFlow Remesh")
+
class DATA_PT_customdata(MeshButtonsPanel, Panel):
bl_label = "Geometry Data"
bl_options = {'DEFAULT_CLOSED'}
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 ca9c518f443..e545ee971d8 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -950,6 +950,7 @@ class GPENCIL_UL_layer(UIList):
icon_value=icon,
)
+
class GreasePencilSimplifyPanel:
def draw_header(self, context):
@@ -977,6 +978,7 @@ class GreasePencilSimplifyPanel:
sub.active = rd.simplify_gpencil_view_fill
sub.prop(rd, "simplify_gpencil_remove_lines", text="Lines")
+
classes = (
GPENCIL_MT_pie_tool_palette,
GPENCIL_MT_pie_settings_palette,
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 23b2556eddb..dc0ad1dcac3 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -367,7 +367,7 @@ def brush_basic_sculpt_settings(layout, context, brush, *, compact=False):
layout.row().prop(brush, "direction", expand=True, **({"text": ""} if compact else {}))
-def brush_basic_gpencil_paint_settings(layout, _context, brush, *, compact=True):
+def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact=True, is_toolbar=False):
gp_settings = brush.gpencil_settings
# Brush details
@@ -395,6 +395,23 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, *, compact=True)
row = layout.row(align=True)
row.prop(gp_settings, "fill_draw_mode", text="Boundary")
row.prop(gp_settings, "show_fill_boundary", text="", icon='GRID')
+ # Fill options
+ if is_toolbar:
+ settings = _context.tool_settings.gpencil_sculpt
+ row = layout.row(align=True)
+ sub = row.row(align=True)
+ sub.popover(
+ panel="TOPBAR_PT_gpencil_fill",
+ text="Fill Options",
+ )
+ else:
+ row = layout.row(align=True)
+ row.prop(gp_settings, "fill_factor", text="Resolution")
+ if gp_settings.fill_draw_mode != 'STROKE':
+ row = layout.row(align=True)
+ row.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes")
+ row = layout.row(align=True)
+ row.prop(gp_settings, "fill_threshold", text="Threshold")
else: # brush.gpencil_tool == 'DRAW':
row = layout.row(align=True)
row.prop(brush, "size", text="Radius")
@@ -403,6 +420,25 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, *, compact=True)
row.prop(gp_settings, "pen_strength", slider=True)
row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
+ if tool.idname in {"builtin.arc", "builtin.curve", "builtin.line", "builtin.box", "builtin.circle", "builtin.polyline"}:
+ settings = _context.tool_settings.gpencil_sculpt
+ if is_toolbar:
+ row = layout.row(align=True)
+ row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA')
+ sub = row.row(align=True)
+ sub.active = settings.use_thickness_curve
+ sub.popover(
+ panel="TOPBAR_PT_gpencil_primitive",
+ text="Thickness Profile",
+ )
+ else:
+ row = layout.row(align=True)
+ row.prop(settings, "use_thickness_curve", text="Use Thickness Profile")
+ sub = row.row(align=True)
+ if settings.use_thickness_curve:
+ # Curve
+ layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True)
+
def brush_basic_gpencil_sculpt_settings(layout, context, brush, *, compact=False):
tool_settings = context.tool_settings
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 48e6eb06076..2bdbbb96e51 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -1091,14 +1091,13 @@ class PARTICLE_PT_physics_integration(ParticleButtonsPanel, Panel):
col.prop(part, "integrator")
col.prop(part, "timestep")
- sub = col.row()
- sub.prop(part, "subframes")
- supports_courant = part.physics_type == 'FLUID'
- subsub = sub.row()
- subsub.enabled = supports_courant
- subsub.prop(part, "use_adaptive_subframes", text="")
- if supports_courant and part.use_adaptive_subframes:
- col.prop(part, "courant_target", text="Threshold")
+ col.prop(part, "subframes")
+
+ if part.physics_type == 'FLUID':
+ col.prop(part, "use_adaptive_subframes", text="Adaptive")
+ sub = col.row()
+ sub.enabled = part.use_adaptive_subframes
+ sub.prop(part, "courant_target", text="Threshold")
class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
@@ -1122,33 +1121,28 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
boids = particle_get_settings(context).boids
layout.enabled = particle_panel_enabled(context, context.particle_system)
# Currently boids can only use the first state so these are commented out for now.
- #row = layout.row()
+ # row = layout.row()
# row.template_list("UI_UL_list", "particle_boids", boids, "states",
- # boids, "active_boid_state_index", compact="True")
- #col = row.row()
- #sub = col.row(align=True)
- #sub.operator("boid.state_add", icon='ADD', text="")
- #sub.operator("boid.state_del", icon='REMOVE', text="")
- #sub = row.row(align=True)
- #sub.operator("boid.state_move_up", icon='TRIA_UP', text="")
- #sub.operator("boid.state_move_down", icon='TRIA_DOWN', text="")
+ # boids, "active_boid_state_index", compact="True")
+ # col = row.row()
+ # sub = col.row(align=True)
+ # sub.operator("boid.state_add", icon='ADD', text="")
+ # sub.operator("boid.state_del", icon='REMOVE', text="")
+ # sub = row.row(align=True)
+ # sub.operator("boid.state_move_up", icon='TRIA_UP', text="")
+ # sub.operator("boid.state_move_down", icon='TRIA_DOWN', text="")
state = boids.active_boid_state
- #layout.prop(state, "name", text="State name")
-
- row = layout.row()
- row.prop(state, "ruleset_type")
- if state.ruleset_type == 'FUZZY':
- row.prop(state, "rule_fuzzy", slider=True)
- else:
- row.label(text="")
+ # layout.prop(state, "name", text="State name")
row = layout.row()
row.template_list("UI_UL_list", "particle_boids_rules", state,
@@ -1164,47 +1158,46 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
subsub.operator("boid.rule_move_up", icon='TRIA_UP', text="")
subsub.operator("boid.rule_move_down", icon='TRIA_DOWN', text="")
+ layout.prop(state, "ruleset_type")
+ if state.ruleset_type == 'FUZZY':
+ layout.prop(state, "rule_fuzzy", slider=True)
+
rule = state.active_boid_rule
if rule:
- row = layout.row()
- row.prop(rule, "name", text="")
- # somebody make nice icons for boids here please! -jahka
- row.prop(rule, "use_in_air", icon='TRIA_UP', text="")
- row.prop(rule, "use_on_land", icon='TRIA_DOWN', text="")
+ col = layout.column(align=True)
+ col.prop(rule, "use_in_air")
+ col.prop(rule, "use_on_land")
- row = layout.row()
+ col = layout.column()
if rule.type == 'GOAL':
- row.prop(rule, "object")
- row = layout.row()
- row.prop(rule, "use_predict")
+ col.prop(rule, "object")
+ col.prop(rule, "use_predict")
elif rule.type == 'AVOID':
- row.prop(rule, "object")
- row = layout.row()
- row.prop(rule, "use_predict")
- row.prop(rule, "fear_factor")
+ col.prop(rule, "object")
+ col.prop(rule, "use_predict")
+ col.prop(rule, "fear_factor")
elif rule.type == 'FOLLOW_PATH':
- row.label(text="Not yet functional")
+ col.label(text="Not yet functional")
elif rule.type == 'AVOID_COLLISION':
- row.prop(rule, "use_avoid")
- row.prop(rule, "use_avoid_collision")
- row.prop(rule, "look_ahead")
+ col.prop(rule, "use_avoid")
+ col.prop(rule, "use_avoid_collision")
+ col.prop(rule, "look_ahead")
elif rule.type == 'FOLLOW_LEADER':
- row.prop(rule, "object", text="")
- row.prop(rule, "distance")
- row = layout.row()
- row.prop(rule, "use_line")
- sub = row.row()
+ col.prop(rule, "object")
+ col.prop(rule, "distance")
+ col.prop(rule, "use_line")
+ sub = col.row()
sub.active = rule.use_line
sub.prop(rule, "queue_count")
elif rule.type == 'AVERAGE_SPEED':
- row.prop(rule, "speed", slider=True)
- row.prop(rule, "wander", slider=True)
- row.prop(rule, "level", slider=True)
+ col.prop(rule, "speed", slider=True)
+ col.prop(rule, "wander", slider=True)
+ col.prop(rule, "level", slider=True)
elif rule.type == 'FIGHT':
- row.prop(rule, "distance")
- row.prop(rule, "flee_distance")
+ col.prop(rule, "distance")
+ col.prop(rule, "flee_distance")
class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 6bd2dea3e7b..b5154e72de6 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -1221,7 +1221,7 @@ class CLIP_PT_tools_grease_pencil_draw(AnnotationDrawingToolsPanel, Panel):
class CLIP_MT_view_zoom(Menu):
bl_label = "Fractional Zoom"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
@@ -1255,6 +1255,7 @@ class CLIP_MT_view(Menu):
layout.operator("clip.view_selected")
layout.operator("clip.view_all")
layout.operator("clip.view_all", text="View Fit").fit_view = True
+ layout.operator("clip.view_center_cursor")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py
index a56928a0589..54a72cf59d0 100644
--- a/release/scripts/startup/bl_ui/space_console.py
+++ b/release/scripts/startup/bl_ui/space_console.py
@@ -129,7 +129,7 @@ class CONSOLE_MT_console(Menu):
class CONSOLE_MT_context_menu(Menu):
bl_label = "Console Context Menu"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("console.clear")
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 948a797e7fe..181032e4d96 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -158,7 +158,8 @@ class FILEBROWSER_PT_filter(Panel):
def panel_poll_is_upper_region(region):
- # The upper region is left-aligned, the lower is split into it then. Note that after "Flip Regions" it's right-aligned.
+ # The upper region is left-aligned, the lower is split into it then.
+ # Note that after "Flip Regions" it's right-aligned.
return region.alignment in {'LEFT', 'RIGHT'}
@@ -239,9 +240,9 @@ class FILEBROWSER_MT_bookmarks_context_menu(Menu):
layout.separator()
layout.operator("file.bookmark_move", icon='TRIA_UP_BAR',
- text="Move To Top").direction = 'TOP'
+ text="Move to Top").direction = 'TOP'
layout.operator("file.bookmark_move", icon='TRIA_DOWN_BAR',
- text="Move To Bottom").direction = 'BOTTOM'
+ text="Move to Bottom").direction = 'BOTTOM'
class FILEBROWSER_PT_bookmarks_favorites(Panel):
@@ -328,36 +329,6 @@ class FILEBROWSER_PT_advanced_filter(Panel):
col.prop(params, "filter_id")
-class FILEBROWSER_PT_options_toggle(Panel):
- bl_space_type = 'FILE_BROWSER'
- bl_region_type = 'TOOLS'
- bl_label = "Options Toggle"
- bl_options = {'HIDE_HEADER'}
-
- @classmethod
- def poll(cls, context):
- sfile = context.space_data
- return context.region.alignment == 'BOTTOM' and sfile.active_operator
-
- def is_option_region_visible(self, context):
- for region in context.area.regions:
- if region.type == 'TOOL_PROPS' and region.width <= 1:
- return False
-
- return True
-
- def draw(self, context):
- layout = self.layout
- label = "Hide Options" if self.is_option_region_visible(
- context) else "Options"
-
- layout.scale_x = 1.3
- layout.scale_y = 1.3
-
- layout.operator("screen.region_toggle",
- text=label).region_type = 'TOOL_PROPS'
-
-
class FILEBROWSER_PT_directory_path(Panel):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'UI'
@@ -372,6 +343,16 @@ class FILEBROWSER_PT_directory_path(Panel):
return True
+ def is_option_region_visible(self, context, space):
+ if not space.active_operator:
+ return False
+
+ for region in context.area.regions:
+ if region.type == 'TOOL_PROPS' and region.width <= 1:
+ return False
+
+ return True
+
def draw(self, context):
layout = self.layout
space = context.space_data
@@ -381,31 +362,37 @@ class FILEBROWSER_PT_directory_path(Panel):
layout.scale_y = 1.3
row = layout.row()
+ flow = row.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=False)
+
+ subrow = flow.row()
- subrow = row.row(align=True)
- subrow.operator("file.previous", text="", icon='BACK')
- subrow.operator("file.next", text="", icon='FORWARD')
- subrow.operator("file.parent", text="", icon='FILE_PARENT')
- subrow.operator("file.refresh", text="", icon='FILE_REFRESH')
+ subsubrow = subrow.row(align=True)
+ subsubrow.operator("file.previous", text="", icon='BACK')
+ subsubrow.operator("file.next", text="", icon='FORWARD')
+ subsubrow.operator("file.parent", text="", icon='FILE_PARENT')
+ subsubrow.operator("file.refresh", text="", icon='FILE_REFRESH')
- row.operator("file.directory_new", icon='NEWFOLDER', text="")
+ subsubrow = subrow.row()
+ subsubrow.operator_context = 'EXEC_DEFAULT'
+ subsubrow.operator("file.directory_new", icon='NEWFOLDER', text="")
- subrow = row.row()
subrow.template_file_select_path(params)
- subrow = row.row()
- subrow.scale_x = 0.5
- subrow.prop(params, "filter_search", text="", icon='VIEWZOOM')
+ subrow = flow.row()
+
+ subsubrow = subrow.row()
+ subsubrow.scale_x = 0.6
+ subsubrow.prop(params, "filter_search", text="", icon='VIEWZOOM')
# Uses prop_with_popover() as popover() only adds the triangle icon in headers.
- row.prop_with_popover(
+ subrow.prop_with_popover(
params,
"display_type",
panel="FILEBROWSER_PT_display",
text="",
icon_only=True,
)
- row.prop_with_popover(
+ subrow.prop_with_popover(
params,
"display_type",
panel="FILEBROWSER_PT_filter",
@@ -414,6 +401,14 @@ class FILEBROWSER_PT_directory_path(Panel):
icon_only=True,
)
+ if space.active_operator:
+ subrow.operator(
+ "screen.region_toggle",
+ text="",
+ icon='PREFERENCES',
+ depress=self.is_option_region_visible(context, space)
+ ).region_type = 'TOOL_PROPS'
+
class FILEBROWSER_MT_view(Menu):
bl_label = "View"
@@ -475,8 +470,15 @@ class FILEBROWSER_MT_context_menu(Menu):
layout.separator()
layout.operator("file.rename", text="Rename")
- # layout.operator("file.delete")
- layout.operator("file.directory_new", text="New Folder")
+ sub = layout.row()
+ sub.operator_context = 'EXEC_DEFAULT'
+ sub.operator("file.delete", text="Delete")
+
+ layout.separator()
+
+ sub = layout.row()
+ sub.operator_context = 'EXEC_DEFAULT'
+ sub.operator("file.directory_new", text="New Folder")
layout.operator("file.bookmark_add", text="Add Bookmark")
layout.separator()
@@ -500,7 +502,6 @@ classes = (
FILEBROWSER_PT_bookmarks_recents,
FILEBROWSER_PT_advanced_filter,
FILEBROWSER_PT_directory_path,
- FILEBROWSER_PT_options_toggle,
FILEBROWSER_MT_view,
FILEBROWSER_MT_select,
FILEBROWSER_MT_context_menu,
@@ -508,5 +509,6 @@ classes = (
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
+
for cls in classes:
register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 5e05c49b567..aaa73b2c864 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -113,6 +113,8 @@ class IMAGE_MT_view(Menu):
layout.operator("image.view_all", text="Frame All")
layout.operator("image.view_all", text="Frame All Fit").fit_view = True
+ layout.operator("image.view_center_cursor", text="Center View to Cursor")
+
layout.separator()
if show_render:
@@ -238,6 +240,7 @@ class IMAGE_MT_image(Menu):
layout.separator()
layout.menu("IMAGE_MT_image_invert")
+ layout.operator("image.resize", text="Resize")
if ima and not show_render:
if ima.packed_file:
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index b7b0326106e..82ed701aa4c 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -34,7 +34,7 @@ class INFO_MT_editor_menus(Menu):
bl_idname = "INFO_MT_editor_menus"
bl_label = ""
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.menu("INFO_MT_view")
layout.menu("INFO_MT_info")
@@ -43,7 +43,7 @@ class INFO_MT_editor_menus(Menu):
class INFO_MT_view(Menu):
bl_label = "View"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.menu("INFO_MT_area")
@@ -52,7 +52,7 @@ class INFO_MT_view(Menu):
class INFO_MT_info(Menu):
bl_label = "Info"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("info.select_all", text="Select All").action = 'SELECT'
@@ -107,7 +107,7 @@ class INFO_MT_area(Menu):
class INFO_MT_context_menu(Menu):
bl_label = "Info Context Menu"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("info.report_copy", text="Copy")
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 0f926e596de..2ce81ba8359 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -373,6 +373,12 @@ class NODE_PT_material_slots(Panel):
col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+ if ob.mode == 'EDIT':
+ row = layout.row(align=True)
+ row.operator("object.material_slot_assign", text="Assign")
+ row.operator("object.material_slot_select", text="Select")
+ row.operator("object.material_slot_deselect", text="Deselect")
+
class NODE_PT_node_color_presets(PresetPanel, Panel):
"""Predefined node color"""
@@ -412,6 +418,9 @@ class NODE_MT_context_menu(Menu):
# If something is selected
layout.operator_context = 'INVOKE_DEFAULT'
layout.operator("node.duplicate_move")
+ props = layout.operator("wm.call_panel", text="Rename...")
+ props.name = "TOPBAR_PT_name"
+ props.keep_open = False
layout.operator("node.delete")
layout.operator("node.clipboard_copy", text="Copy")
layout.operator("node.clipboard_paste", text="Paste")
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index e6ab9d1e9de..cdac91b8014 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -187,7 +187,7 @@ class SEQUENCER_MT_range(Menu):
class SEQUENCER_MT_preview_zoom(Menu):
bl_label = "Fractional Zoom"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_PREVIEW'
@@ -741,6 +741,9 @@ class SEQUENCER_MT_context_menu(Menu):
layout.operator("sequencer.copy", text="Copy", icon='COPYDOWN')
layout.operator("sequencer.paste", text="Paste", icon='PASTEDOWN')
layout.operator("sequencer.duplicate_move")
+ props = layout.operator("wm.call_panel", text="Rename...")
+ props.name = "TOPBAR_PT_name"
+ props.keep_open = False
layout.operator("sequencer.delete", text="Delete...")
layout.separator()
@@ -761,7 +764,7 @@ class SEQUENCER_MT_context_menu(Menu):
strip_type = strip.type
selected_sequences_count = selected_sequences_len(context)
- if strip_type != "SOUND":
+ if strip_type != 'SOUND':
layout.separator()
layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
@@ -778,7 +781,6 @@ class SEQUENCER_MT_context_menu(Menu):
if selected_sequences_count >= 1:
col = layout.column()
col.operator_menu_enum("sequencer.fades_add", "type", text="Fade")
- col.enabled = selected_sequences_len(context) >= 1
layout.operator("sequencer.fades_clear", text="Clear Fade")
if strip_type in {
@@ -1572,10 +1574,13 @@ class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel):
col.prop(strip, "volume", text="Volume")
col.prop(strip, "pitch")
+
+ col = layout.column()
col.prop(strip, "pan")
+ col.enabled = sound is not None and sound.use_mono
if sound is not None:
-
+ col = layout.column()
if st.waveform_display_type == 'DEFAULT_WAVEFORMS':
col.prop(strip, "show_waveform")
col.prop(sound, "use_mono")
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index de05a357211..ff5d2565c26 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -48,6 +48,7 @@ def generate_from_enum_ex(
icon_prefix,
type,
attr,
+ cursor='DEFAULT',
tooldef_keywords={},
):
tool_defs = []
@@ -60,6 +61,7 @@ def generate_from_enum_ex(
idname=idname_prefix + name,
label=name,
icon=icon_prefix + idname.lower(),
+ cursor=cursor,
data_block=idname,
**tooldef_keywords,
)
@@ -199,7 +201,7 @@ class _defs_annotate:
idname="builtin.annotate_line",
label="Annotate Line",
icon="ops.gpencil.draw.line",
- cursor='CROSSHAIR',
+ cursor='PAINT_BRUSH',
keymap="Generic Tool: Annotate Line",
draw_settings=draw_settings,
)
@@ -210,7 +212,7 @@ class _defs_annotate:
idname="builtin.annotate_polygon",
label="Annotate Polygon",
icon="ops.gpencil.draw.poly",
- cursor='CROSSHAIR',
+ cursor='PAINT_BRUSH',
keymap="Generic Tool: Annotate Polygon",
draw_settings=draw_settings,
)
@@ -225,7 +227,7 @@ class _defs_annotate:
idname="builtin.annotate_eraser",
label="Annotate Eraser",
icon="ops.gpencil.draw.eraser",
- cursor='CROSSHAIR', # XXX: Always show brush circle when enabled
+ cursor='ERASER',
keymap="Generic Tool: Annotate Eraser",
draw_settings=draw_settings,
)
@@ -490,7 +492,7 @@ class _defs_edit_mesh:
@ToolDef.from_fn
def poly_build():
- def draw_settings(context, layout, tool):
+ def draw_settings(_context, layout, tool):
props = tool.operator_properties("mesh.polybuild_face_at_cursor_move")
props_macro = props.MESH_OT_polybuild_face_at_cursor
layout.prop(props_macro, "create_quads")
@@ -987,7 +989,7 @@ class _defs_sculpt:
@ToolDef.from_fn
def mesh_filter():
- def draw_settings(context, layout, tool):
+ def draw_settings(_context, layout, tool):
props = tool.operator_properties("sculpt.mesh_filter")
layout.prop(props, "type", expand=False)
layout.prop(props, "strength")
@@ -1318,6 +1320,7 @@ class _defs_gpencil_paint:
icon_prefix="brush.gpencil_draw.",
type=bpy.types.Brush,
attr="gpencil_tool",
+ cursor='DOT',
tooldef_keywords=dict(
operator="gpencil.draw",
),
@@ -1346,6 +1349,17 @@ class _defs_gpencil_paint:
)
@ToolDef.from_fn
+ def polyline():
+ return dict(
+ idname="builtin.polyline",
+ label="Polyline",
+ icon="ops.gpencil.primitive_polyline",
+ cursor='CROSSHAIR',
+ widget=None,
+ keymap=(),
+ )
+
+ @ToolDef.from_fn
def box():
return dict(
idname="builtin.box",
@@ -1387,6 +1401,17 @@ class _defs_gpencil_paint:
cursor='CROSSHAIR',
widget=None,
keymap=(),
+ )
+
+ @ToolDef.from_fn
+ def eyedropper():
+ return dict(
+ idname="builtin.eyedropper",
+ label="Eyedropper",
+ icon="ops.paint.weight_sample",
+ cursor='EYEDROPPER',
+ widget=None,
+ keymap=(),
)
@@ -2041,7 +2066,10 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_gpencil_paint.generate_from_brushes,
_defs_gpencil_paint.cutter,
None,
+ _defs_gpencil_paint.eyedropper,
+ None,
_defs_gpencil_paint.line,
+ _defs_gpencil_paint.polyline,
_defs_gpencil_paint.arc,
_defs_gpencil_paint.curve,
_defs_gpencil_paint.box,
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 0374a563532..fef0e095099 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -465,7 +465,6 @@ class TOPBAR_MT_render(Menu):
layout.operator("render.view_show", text="View Render")
layout.operator("render.play_rendered_anim", text="View Animation")
- layout.prop_menu_enum(rd, "display_mode", text="Display Mode")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 24586745c4f..4c90f987c50 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -265,6 +265,26 @@ class USERPREF_PT_interface_editors(PreferencePanel, Panel):
flow.prop(view, "factor_display_type")
+class USERPREF_PT_interface_temporary_windows(PreferencePanel, Panel):
+ bl_label = "Temporary Windows"
+ bl_parent_id = "USERPREF_PT_interface_editors"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ prefs = context.preferences
+ return (prefs.active_section == 'INTERFACE')
+
+ def draw_props(self, context, layout):
+ prefs = context.preferences
+ view = prefs.view
+
+ flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
+
+ flow.prop(view, "render_display_type", text="Render in")
+ flow.prop(view, "filebrowser_display_type", text="File Browser")
+
+
class USERPREF_PT_interface_menus(Panel):
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
@@ -549,6 +569,7 @@ class USERPREF_PT_animation_fcurves(PreferencePanel, Panel):
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
flow.prop(edit, "fcurve_unselected_alpha", text="F-Curve Visibility")
+ flow.prop(edit, "fcurve_new_auto_smoothing", text="Default Smoothing Mode")
flow.prop(edit, "keyframe_new_interpolation_type", text="Default Interpolation")
flow.prop(edit, "keyframe_new_handle_type", text="Default Handles")
flow.prop(edit, "use_insertkey_xyz_to_rgb", text="XYZ to RGB")
@@ -1385,7 +1406,6 @@ class USERPREF_PT_saveload_file_browser(PreferencePanel, Panel):
flow.prop(paths, "show_hidden_files_datablocks")
flow.prop(paths, "hide_recent_locations")
flow.prop(paths, "hide_system_bookmarks")
- flow.prop(paths, "show_thumbnails")
class USERPREF_MT_ndof_settings(Menu):
@@ -1460,12 +1480,17 @@ class USERPREF_PT_input_mouse(PreferencePanel, Panel):
return (prefs.active_section == 'INPUT')
def draw_props(self, context, layout):
+ import sys
prefs = context.preferences
inputs = prefs.inputs
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
flow.prop(inputs, "use_mouse_emulate_3_button")
+ if sys.platform[:3] != "win":
+ rowsub = flow.row()
+ rowsub.active = inputs.use_mouse_emulate_3_button
+ rowsub.prop(inputs, "mouse_emulate_3_button_modifier")
flow.prop(inputs, "use_mouse_continuous")
flow.prop(inputs, "use_drag_immediately")
flow.prop(inputs, "mouse_double_click_time", text="Double Click Speed")
@@ -2119,6 +2144,7 @@ classes = (
USERPREF_PT_interface_display,
USERPREF_PT_interface_editors,
+ USERPREF_PT_interface_temporary_windows,
USERPREF_PT_interface_translation,
USERPREF_PT_interface_text,
USERPREF_PT_interface_menus,
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 4853d280fe6..ba46f3abf4a 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -129,6 +129,8 @@ class VIEW3D_HT_tool_header(Header):
if mode_string == 'EDIT_MESH':
_row, sub = row_for_mirror()
sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
+ sub.prop(context.object.data, "use_mirror_y", text="Y", toggle=True)
+ sub.prop(context.object.data, "use_mirror_z", text="Z", toggle=True)
tool_settings = context.tool_settings
layout.prop(tool_settings, "use_mesh_automerge", text="")
elif mode_string == 'EDIT_ARMATURE':
@@ -139,7 +141,10 @@ class VIEW3D_HT_tool_header(Header):
sub.prop(context.object.pose, "use_mirror_x", text="X", toggle=True)
elif mode_string == 'PAINT_WEIGHT':
row, sub = row_for_mirror()
- sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
+ wpaint = context.tool_settings.weight_paint
+ sub.prop(wpaint, "use_symmetry_x", text="X", toggle=True)
+ sub.prop(wpaint, "use_symmetry_y", text="Y", toggle=True)
+ sub.prop(wpaint, "use_symmetry_z", text="Z", toggle=True)
row.popover(panel="VIEW3D_PT_tools_weightpaint_symmetry_for_topbar", text="")
elif mode_string == 'SCULPT':
row, sub = row_for_mirror()
@@ -293,7 +298,7 @@ class _draw_tool_settings_context_mode:
# is_paint = True
# FIXME: tools must use their own UI drawing!
- if tool.idname in {"builtin.line", "builtin.box", "builtin.circle", "builtin.arc", "builtin.curve"}:
+ if tool.idname in {"builtin.line", "builtin.box", "builtin.circle", "builtin.arc", "builtin.curve","builtin.polyline"}:
# is_paint = False
pass
elif tool.idname == "Cutter":
@@ -346,28 +351,7 @@ class _draw_tool_settings_context_mode:
from bl_ui.properties_paint_common import (
brush_basic_gpencil_paint_settings,
)
- brush_basic_gpencil_paint_settings(layout, context, brush, compact=True)
-
- # FIXME: tools must use their own UI drawing!
- if tool.idname in {"builtin.arc", "builtin.curve", "builtin.line", "builtin.box", "builtin.circle"}:
- settings = context.tool_settings.gpencil_sculpt
- row = layout.row(align=True)
- row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA')
- sub = row.row(align=True)
- sub.active = settings.use_thickness_curve
- sub.popover(
- panel="TOPBAR_PT_gpencil_primitive",
- text="Thickness Profile",
- )
-
- if brush.gpencil_tool == 'FILL':
- settings = context.tool_settings.gpencil_sculpt
- row = layout.row(align=True)
- sub = row.row(align=True)
- sub.popover(
- panel="TOPBAR_PT_gpencil_fill",
- text="Fill Options",
- )
+ brush_basic_gpencil_paint_settings(layout, context, brush, tool, compact=True, is_toolbar=True)
@staticmethod
def SCULPT_GPENCIL(context, layout, tool):
@@ -702,10 +686,18 @@ class VIEW3D_HT_header(Header):
row = layout.row()
row.active = (object_mode == 'EDIT') or (shading.type in {'WIREFRAME', 'SOLID'})
- if shading.type == 'WIREFRAME':
- row.prop(shading, "show_xray_wireframe", text="", icon='XRAY')
- else:
- row.prop(shading, "show_xray", text="", icon='XRAY')
+ # While exposing 'shading.show_xray(_wireframe)' is correct.
+ # this hides the key shortcut from users: T70433.
+ row.operator(
+ "view3d.toggle_xray",
+ text="",
+ icon='XRAY',
+ depress=getattr(
+ shading,
+ "show_xray_wireframe" if shading.type == 'WIREFRAME' else
+ "show_xray"
+ ),
+ )
row = layout.row(align=True)
row.prop(shading, "type", text="", expand=True)
@@ -789,6 +781,8 @@ class VIEW3D_MT_editor_menus(Menu):
elif obj:
if mode_string != 'PAINT_TEXTURE':
layout.menu("VIEW3D_MT_%s" % mode_string.lower())
+ if mode_string == 'SCULPT':
+ layout.menu("VIEW3D_MT_mask")
else:
layout.menu("VIEW3D_MT_object")
@@ -2218,7 +2212,7 @@ class VIEW3D_MT_object_rigid_body(Menu):
layout.operator("rigidbody.mass_calculate", text="Calculate Mass")
layout.operator("rigidbody.object_settings_copy", text="Copy from Active")
layout.operator("object.visual_transform_apply", text="Apply Transformation")
- layout.operator("rigidbody.bake_to_keyframes", text="Bake To Keyframes")
+ layout.operator("rigidbody.bake_to_keyframes", text="Bake to Keyframes")
layout.separator()
@@ -2810,26 +2804,36 @@ class VIEW3D_MT_paint_weight(Menu):
class VIEW3D_MT_sculpt(Menu):
bl_label = "Sculpt"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
props = layout.operator("paint.hide_show", text="Show All")
props.action = 'SHOW'
props.area = 'ALL'
- props = layout.operator("paint.hide_show", text="Hide Bounding Box")
- props.action = 'HIDE'
- props.area = 'INSIDE'
-
props = layout.operator("paint.hide_show", text="Show Bounding Box")
props.action = 'SHOW'
props.area = 'INSIDE'
+ props = layout.operator("paint.hide_show", text="Hide Bounding Box")
+ props.action = 'HIDE'
+ props.area = 'INSIDE'
+
props = layout.operator("paint.hide_show", text="Hide Masked")
+ props.action = 'HIDE'
props.area = 'MASKED'
layout.separator()
+ layout.menu("VIEW3D_MT_sculpt_set_pivot", text="Set Pivot")
+
+
+class VIEW3D_MT_mask(Menu):
+ bl_label = "Mask"
+
+ def draw(self, _context):
+ layout = self.layout
+
props = layout.operator("paint.mask_flood_fill", text="Invert Mask")
props.mode = 'INVERT'
@@ -2893,6 +2897,28 @@ class VIEW3D_MT_sculpt(Menu):
props = layout.operator("sculpt.dirty_mask", text='Dirty Mask')
+class VIEW3D_MT_sculpt_set_pivot(Menu):
+ bl_label = "Sculpt Set Pivot"
+
+ def draw(self, context):
+ layout = self.layout
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Origin")
+ props.mode = 'ORIGIN'
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Unmasked")
+ props.mode = 'UNMASKED'
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Mask Border")
+ props.mode = 'BORDER'
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Active Vertex")
+ props.mode = 'ACTIVE'
+
+ props = layout.operator("sculpt.set_pivot_position", text="Pivot to Surface Under Cursor")
+ props.mode = 'SURFACE'
+
+
class VIEW3D_MT_particle(Menu):
bl_label = "Particle"
@@ -3435,9 +3461,11 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu):
col.operator("mesh.loopcut_slide")
col.operator("mesh.offset_edge_loops_slide")
+
+ col.separator()
+
col.operator("mesh.knife_tool")
col.operator("mesh.bisect")
- col.operator("mesh.bridge_edge_loops", text="Bridge Edge Loops")
col.separator()
@@ -5037,11 +5065,8 @@ class VIEW3D_PT_collections(Panel):
if not use_local_collections:
subrow.active = collection.is_visible # Parent collection runtime visibility
subrow.prop(child, "hide_viewport", text="", emboss=False)
- elif not child.is_visible:
- subrow.active = False
- subrow.label(text="", icon='REMOVE')
else:
- subrow.active = collection.visible_get() # Parent collection runtime visibility
+ subrow.active = collection.visible_get() # Parent collection runtime visibility
icon = 'HIDE_OFF' if child.visible_get() else 'HIDE_ON'
props = subrow.operator("object.hide_collection", text="", icon=icon, emboss=False)
props.collection_index = index
@@ -6774,6 +6799,8 @@ classes = (
VIEW3D_MT_gpencil_vertex_group,
VIEW3D_MT_paint_weight,
VIEW3D_MT_sculpt,
+ VIEW3D_MT_sculpt_set_pivot,
+ VIEW3D_MT_mask,
VIEW3D_MT_particle,
VIEW3D_MT_particle_context_menu,
VIEW3D_MT_particle_showhide,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index ac74c7b66fe..38208f5e426 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -424,12 +424,10 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
row.prop(brush, "elastic_deform_type")
row = col.row()
row.prop(brush, "elastic_deform_volume_preservation", slider=True)
-
- col.separator()
- row = col.row()
- row.prop(brush, "use_automasking_topology")
-
- if brush.sculpt_tool == 'GRAB':
+ elif brush.sculpt_tool == 'POSE':
+ row = col.row()
+ row.prop(brush, "pose_offset")
+ elif brush.sculpt_tool == 'GRAB':
col.separator()
row = col.row()
row.prop(brush, "use_grab_active_vertex")
@@ -456,7 +454,10 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
# crease_pinch_factor
if capabilities.has_pinch_factor:
row = col.row(align=True)
- row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
+ if (brush.sculpt_tool in ('BLOB', 'SNAKE_HOOK')):
+ row.prop(brush, "crease_pinch_factor", slider=True, text="Magnify")
+ else:
+ row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
# rake_factor
if capabilities.has_rake_factor:
@@ -638,6 +639,7 @@ class VIEW3D_PT_tools_brush_options(Panel, View3DPaintPanel):
brush_texpaint_common_options(self, context, layout, brush, settings, True)
elif context.sculpt_object and brush:
+ col.prop(brush, "use_automasking_topology")
if capabilities.has_accumulate:
col.prop(brush, "use_accumulate")
@@ -646,6 +648,7 @@ class VIEW3D_PT_tools_brush_options(Panel, View3DPaintPanel):
if capabilities.has_sculpt_plane:
col.prop(brush, "sculpt_plane")
col.prop(brush, "use_original_normal")
+ col.prop(brush, "use_original_plane")
col.prop(brush, "use_frontface", text="Front Faces Only")
col.prop(brush, "use_projected")
@@ -1224,15 +1227,6 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
def poll(cls, context):
return (context.sculpt_object and context.tool_settings.sculpt)
- def draw_header(self, context):
- is_popover = self.is_popover
- layout = self.layout
- layout.operator(
- "object.voxel_remesh",
- text="",
- emboss=is_popover,
- )
-
def draw(self, context):
layout = self.layout
layout.use_property_split = True
@@ -1241,7 +1235,10 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
col = layout.column()
mesh = context.active_object.data
col.prop(mesh, "remesh_voxel_size")
+ col.prop(mesh, "remesh_voxel_adaptivity")
+ col.prop(mesh, "remesh_fix_poles")
col.prop(mesh, "remesh_smooth_normals")
+ col.prop(mesh, "remesh_preserve_volume")
col.prop(mesh, "remesh_preserve_paint_mask")
col.operator("object.voxel_remesh", text="Remesh")
@@ -1856,7 +1853,7 @@ class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
brush = gpencil_paint.brush
sub = col.column(align=True)
- sub.operator("gpencil.brush_presets_create", icon='HELP', text="")
+ sub.operator("gpencil.brush_presets_create", icon='PRESET_NEW', text="")
if brush is not None:
gp_settings = brush.gpencil_settings
@@ -1876,7 +1873,8 @@ class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
from bl_ui.properties_paint_common import (
brush_basic_gpencil_paint_settings,
)
- brush_basic_gpencil_paint_settings(layout, context, brush, compact=True)
+ tool = context.workspace.tools.from_space_view3d_mode(context.mode, create=False)
+ brush_basic_gpencil_paint_settings(layout, context, brush, tool, compact=True, is_toolbar=False)
# Grease Pencil drawing brushes options
@@ -1884,7 +1882,6 @@ class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_label = "Options"
bl_category = "Tool"
- bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
@@ -1964,7 +1961,6 @@ class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
bl_label = "Post-Processing"
bl_category = "Tool"
- bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
@@ -2258,12 +2254,12 @@ classes = (
VIEW3D_PT_tools_brush_display_custom_icon,
VIEW3D_PT_sculpt_dyntopo,
VIEW3D_PT_sculpt_dyntopo_remesh,
+ VIEW3D_PT_sculpt_voxel_remesh,
VIEW3D_PT_sculpt_symmetry,
VIEW3D_PT_sculpt_symmetry_for_topbar,
VIEW3D_PT_sculpt_options,
VIEW3D_PT_sculpt_options_unified,
VIEW3D_PT_sculpt_options_gravity,
- VIEW3D_PT_sculpt_voxel_remesh,
VIEW3D_PT_tools_weightpaint_symmetry,
VIEW3D_PT_tools_weightpaint_symmetry_for_topbar,
VIEW3D_PT_tools_weightpaint_options,
diff --git a/release/scripts/templates_py/operator_mesh_add.py b/release/scripts/templates_py/operator_mesh_add.py
index d3df64a5501..01a9ad6160e 100644
--- a/release/scripts/templates_py/operator_mesh_add.py
+++ b/release/scripts/templates_py/operator_mesh_add.py
@@ -2,6 +2,7 @@ import bpy
import bmesh
from bpy_extras.object_utils import AddObjectHelper
+
def add_box(width, height, depth):
"""
This function takes inputs and returns vertex and face arrays.
@@ -77,16 +78,16 @@ class AddBox(bpy.types.Operator):
# generic transform props
align_items = (
- ('WORLD', "World", "Align the new object to the world"),
- ('VIEW', "View", "Align the new object to the view"),
- ('CURSOR', "3D Cursor", "Use the 3D cursor orientation for the new object")
+ ('WORLD', "World", "Align the new object to the world"),
+ ('VIEW', "View", "Align the new object to the view"),
+ ('CURSOR', "3D Cursor", "Use the 3D cursor orientation for the new object")
)
align: EnumProperty(
- name="Align",
- items=align_items,
- default='WORLD',
- update=AddObjectHelper.align_update_callback,
- )
+ name="Align",
+ items=align_items,
+ default='WORLD',
+ update=AddObjectHelper.align_update_callback,
+ )
location: FloatVectorProperty(
name="Location",
subtype='TRANSLATION',
diff --git a/release/scripts/templates_py/operator_modal_draw.py b/release/scripts/templates_py/operator_modal_draw.py
index 5dc72c36a8f..1e185ecfe2b 100644
--- a/release/scripts/templates_py/operator_modal_draw.py
+++ b/release/scripts/templates_py/operator_modal_draw.py
@@ -4,6 +4,7 @@ import blf
import gpu
from gpu_extras.batch import batch_for_shader
+
def draw_callback_px(self, context):
print("mouse points", len(self.mouse_path))
diff --git a/release/scripts/templates_py/ui_tool_simple.py b/release/scripts/templates_py/ui_tool_simple.py
index afda5088e69..fc239093b9c 100644
--- a/release/scripts/templates_py/ui_tool_simple.py
+++ b/release/scripts/templates_py/ui_tool_simple.py
@@ -3,9 +3,10 @@
import bpy
from bpy.types import WorkSpaceTool
+
class MyTool(WorkSpaceTool):
- bl_space_type='VIEW_3D'
- bl_context_mode='OBJECT'
+ bl_space_type = 'VIEW_3D'
+ bl_context_mode = 'OBJECT'
# The prefix of the idname should be your add-on name.
bl_idname = "my_template.my_circle_select"
@@ -30,8 +31,8 @@ class MyTool(WorkSpaceTool):
class MyOtherTool(WorkSpaceTool):
- bl_space_type='VIEW_3D'
- bl_context_mode='OBJECT'
+ bl_space_type = 'VIEW_3D'
+ bl_context_mode = 'OBJECT'
bl_idname = "my_template.my_other_select"
bl_label = "My Lasso Tool Select"
@@ -56,9 +57,11 @@ def register():
bpy.utils.register_tool(MyTool, after={"builtin.scale_cage"}, separator=True, group=True)
bpy.utils.register_tool(MyOtherTool, after={MyTool.bl_idname})
+
def unregister():
bpy.utils.unregister_tool(MyTool)
bpy.utils.unregister_tool(MyOtherTool)
+
if __name__ == "__main__":
register()
diff --git a/release/windows/icons/cursors/arrowdown.cur b/release/windows/icons/cursors/arrowdown.cur
new file mode 100644
index 00000000000..251f3453e63
--- /dev/null
+++ b/release/windows/icons/cursors/arrowdown.cur
Binary files differ
diff --git a/release/windows/icons/cursors/arrowleft.cur b/release/windows/icons/cursors/arrowleft.cur
new file mode 100644
index 00000000000..6935e461a05
--- /dev/null
+++ b/release/windows/icons/cursors/arrowleft.cur
Binary files differ
diff --git a/release/windows/icons/cursors/arrowright.cur b/release/windows/icons/cursors/arrowright.cur
new file mode 100644
index 00000000000..ae561a54d04
--- /dev/null
+++ b/release/windows/icons/cursors/arrowright.cur
Binary files differ
diff --git a/release/windows/icons/cursors/arrowup.cur b/release/windows/icons/cursors/arrowup.cur
new file mode 100644
index 00000000000..5c29145f16b
--- /dev/null
+++ b/release/windows/icons/cursors/arrowup.cur
Binary files differ
diff --git a/release/windows/icons/cursors/cross.cur b/release/windows/icons/cursors/cross.cur
new file mode 100644
index 00000000000..62c5c322cfb
--- /dev/null
+++ b/release/windows/icons/cursors/cross.cur
Binary files differ
diff --git a/release/windows/icons/cursors/crossa.cur b/release/windows/icons/cursors/crossa.cur
new file mode 100644
index 00000000000..7a2bfa7f406
--- /dev/null
+++ b/release/windows/icons/cursors/crossa.cur
Binary files differ
diff --git a/release/windows/icons/cursors/crossb.cur b/release/windows/icons/cursors/crossb.cur
new file mode 100644
index 00000000000..78bb1a3574b
--- /dev/null
+++ b/release/windows/icons/cursors/crossb.cur
Binary files differ
diff --git a/release/windows/icons/cursors/crossc.cur b/release/windows/icons/cursors/crossc.cur
new file mode 100644
index 00000000000..5c54525b2dc
--- /dev/null
+++ b/release/windows/icons/cursors/crossc.cur
Binary files differ
diff --git a/release/windows/icons/cursors/eraser.cur b/release/windows/icons/cursors/eraser.cur
new file mode 100644
index 00000000000..c1e14ef3bae
--- /dev/null
+++ b/release/windows/icons/cursors/eraser.cur
Binary files differ
diff --git a/release/windows/icons/cursors/eyedropper.cur b/release/windows/icons/cursors/eyedropper.cur
new file mode 100644
index 00000000000..2294297b210
--- /dev/null
+++ b/release/windows/icons/cursors/eyedropper.cur
Binary files differ
diff --git a/release/windows/icons/cursors/forbidden.cur b/release/windows/icons/cursors/forbidden.cur
new file mode 100644
index 00000000000..2e45bad168b
--- /dev/null
+++ b/release/windows/icons/cursors/forbidden.cur
Binary files differ
diff --git a/release/windows/icons/cursors/handopen.cur b/release/windows/icons/cursors/handopen.cur
new file mode 100644
index 00000000000..cba18448873
--- /dev/null
+++ b/release/windows/icons/cursors/handopen.cur
Binary files differ
diff --git a/release/windows/icons/cursors/knife.cur b/release/windows/icons/cursors/knife.cur
new file mode 100644
index 00000000000..edc97d9e9f2
--- /dev/null
+++ b/release/windows/icons/cursors/knife.cur
Binary files differ
diff --git a/release/windows/icons/cursors/moveew.cur b/release/windows/icons/cursors/moveew.cur
new file mode 100644
index 00000000000..c2bef134cca
--- /dev/null
+++ b/release/windows/icons/cursors/moveew.cur
Binary files differ
diff --git a/release/windows/icons/cursors/movens.cur b/release/windows/icons/cursors/movens.cur
new file mode 100644
index 00000000000..409176a23f9
--- /dev/null
+++ b/release/windows/icons/cursors/movens.cur
Binary files differ
diff --git a/release/windows/icons/cursors/pencil.cur b/release/windows/icons/cursors/pencil.cur
new file mode 100644
index 00000000000..ac76b367d25
--- /dev/null
+++ b/release/windows/icons/cursors/pencil.cur
Binary files differ
diff --git a/release/windows/icons/cursors/pointer.cur b/release/windows/icons/cursors/pointer.cur
new file mode 100644
index 00000000000..d9b1ee8a60b
--- /dev/null
+++ b/release/windows/icons/cursors/pointer.cur
Binary files differ
diff --git a/release/windows/icons/cursors/scrollew.cur b/release/windows/icons/cursors/scrollew.cur
new file mode 100644
index 00000000000..c5eab1b9890
--- /dev/null
+++ b/release/windows/icons/cursors/scrollew.cur
Binary files differ
diff --git a/release/windows/icons/cursors/scrollns.cur b/release/windows/icons/cursors/scrollns.cur
new file mode 100644
index 00000000000..4b443220da8
--- /dev/null
+++ b/release/windows/icons/cursors/scrollns.cur
Binary files differ
diff --git a/release/windows/icons/cursors/scrollnsew.cur b/release/windows/icons/cursors/scrollnsew.cur
new file mode 100644
index 00000000000..fd0cad49c42
--- /dev/null
+++ b/release/windows/icons/cursors/scrollnsew.cur
Binary files differ
diff --git a/release/windows/icons/cursors/splith.cur b/release/windows/icons/cursors/splith.cur
new file mode 100644
index 00000000000..9b74fca7c6f
--- /dev/null
+++ b/release/windows/icons/cursors/splith.cur
Binary files differ
diff --git a/release/windows/icons/cursors/splitv.cur b/release/windows/icons/cursors/splitv.cur
new file mode 100644
index 00000000000..68a739eb11b
--- /dev/null
+++ b/release/windows/icons/cursors/splitv.cur
Binary files differ
diff --git a/release/windows/icons/cursors/zoomin.cur b/release/windows/icons/cursors/zoomin.cur
new file mode 100644
index 00000000000..8e6930b465a
--- /dev/null
+++ b/release/windows/icons/cursors/zoomin.cur
Binary files differ
diff --git a/release/windows/icons/cursors/zoomout.cur b/release/windows/icons/cursors/zoomout.cur
new file mode 100644
index 00000000000..834686c7ec0
--- /dev/null
+++ b/release/windows/icons/cursors/zoomout.cur
Binary files differ
diff --git a/release/windows/icons/winblender.rc b/release/windows/icons/winblender.rc
index 244c2cb2e2c..ba3363aacc5 100644
--- a/release/windows/icons/winblender.rc
+++ b/release/windows/icons/winblender.rc
@@ -13,6 +13,31 @@
APPICON ICON DISCARDABLE "winblender.ico"
BLENDERFILE ICON DISCARDABLE "winblenderfile.ico"
+pointer_cursor CURSOR "cursors/pointer.cur"
+moveew_cursor CURSOR "cursors/moveew.cur"
+movens_cursor CURSOR "cursors/movens.cur"
+arrowdown_cursor CURSOR "cursors/arrowdown.cur"
+arrowleft_cursor CURSOR "cursors/arrowleft.cur"
+arrowright_cursor CURSOR "cursors/arrowright.cur"
+arrowup_cursor CURSOR "cursors/arrowup.cur"
+cross_cursor CURSOR "cursors/cross.cur"
+crossA_cursor CURSOR "cursors/crossa.cur"
+crossB_cursor CURSOR "cursors/crossb.cur"
+crossC_cursor CURSOR "cursors/crossc.cur"
+eraser_cursor CURSOR "cursors/eraser.cur"
+eyedropper_cursor CURSOR "cursors/eyedropper.cur"
+handopen_cursor CURSOR "cursors/handopen.cur"
+knife_cursor CURSOR "cursors/knife.cur"
+pencil_cursor CURSOR "cursors/pencil.cur"
+scrollew_cursor CURSOR "cursors/scrollew.cur"
+scrollns_cursor CURSOR "cursors/scrollns.cur"
+scrollnsew_cursor CURSOR "cursors/scrollnsew.cur"
+splith_cursor CURSOR "cursors/splith.cur"
+splitv_cursor CURSOR "cursors/splitv.cur"
+zoomin_cursor CURSOR "cursors/zoomin.cur"
+zoomout_cursor CURSOR "cursors/zoomout.cur"
+forbidden_cursor CURSOR "cursors/forbidden.cur"
+
IDR_VERSION1 VERSIONINFO
FILEVERSION BLEN_VER_RC_1, BLEN_VER_RC_2, BLEN_VER_RC_3, BLEN_VER_RC_4
PRODUCTVERSION BLEN_VER_RC_1, BLEN_VER_RC_2, BLEN_VER_RC_3, BLEN_VER_RC_4
@@ -27,7 +52,7 @@ BEGIN
VALUE "ProductVersion", BLEN_VER_RC_STR
VALUE "CompanyName", "Blender Foundation"
VALUE "FileDescription", "Blender"
- VALUE "LegalCopyright", "GPLv2 (Blender Foundation)"
+ VALUE "LegalCopyright", "GPLv3 (Blender Foundation)"
VALUE "OriginalFilename", "blender.exe"
VALUE "ProductName", "Blender"
END
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index 696e0ff1810..7c5efaf309d 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -27,6 +27,7 @@ extern "C" {
struct CacheReader;
struct ListBase;
+struct Main;
struct Mesh;
struct Object;
struct Scene;
@@ -103,7 +104,9 @@ bool ABC_import(struct bContext *C,
bool validate_meshes,
bool as_background_job);
-AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
+AbcArchiveHandle *ABC_create_handle(struct Main *bmain,
+ const char *filename,
+ struct ListBase *object_paths);
void ABC_free_handle(AbcArchiveHandle *handle);
diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_archive.cc
index c4252d20d48..bb527c23b20 100644
--- a/source/blender/alembic/intern/abc_archive.cc
+++ b/source/blender/alembic/intern/abc_archive.cc
@@ -24,6 +24,10 @@
#include "abc_archive.h"
extern "C" {
#include "BKE_blender_version.h"
+#include "BKE_main.h"
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
}
#ifdef WIN32
@@ -95,20 +99,24 @@ static IArchive open_archive(const std::string &filename,
return IArchive();
}
-ArchiveReader::ArchiveReader(const char *filename)
+ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename)
{
+ char abs_filename[FILE_MAX];
+ BLI_strncpy(abs_filename, filename, FILE_MAX);
+ BLI_path_abs(abs_filename, BKE_main_blendfile_path(bmain));
+
#ifdef WIN32
- UTF16_ENCODE(filename);
- std::wstring wstr(filename_16);
+ UTF16_ENCODE(abs_filename);
+ std::wstring wstr(abs_filename_16);
m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary);
- UTF16_UN_ENCODE(filename);
+ UTF16_UN_ENCODE(abs_filename);
#else
- m_infile.open(filename, std::ios::in | std::ios::binary);
+ m_infile.open(abs_filename, std::ios::in | std::ios::binary);
#endif
m_streams.push_back(&m_infile);
- m_archive = open_archive(filename, m_streams, m_is_hdf5);
+ m_archive = open_archive(abs_filename, m_streams, m_is_hdf5);
/* We can't open an HDF5 file from a stream, so close it. */
if (m_is_hdf5) {
diff --git a/source/blender/alembic/intern/abc_archive.h b/source/blender/alembic/intern/abc_archive.h
index 343a8112aa2..a64de742cdf 100644
--- a/source/blender/alembic/intern/abc_archive.h
+++ b/source/blender/alembic/intern/abc_archive.h
@@ -34,6 +34,8 @@
#include <fstream>
+struct Main;
+
/* Wrappers around input and output archives. The goal is to be able to use
* streams so that unicode paths work on Windows (T49112), and to make sure that
* the stream objects remain valid as long as the archives are open.
@@ -46,7 +48,7 @@ class ArchiveReader {
bool m_is_hdf5;
public:
- explicit ArchiveReader(const char *filename);
+ ArchiveReader(struct Main *bmain, const char *filename);
bool valid() const;
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index a7549cc1f47..a69178281ff 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -53,6 +53,7 @@ extern "C" {
#include "BKE_anim.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
@@ -263,7 +264,7 @@ void AbcExporter::getFrameSet(unsigned int nr_of_samples, std::set<double> &fram
}
}
-void AbcExporter::operator()(float &progress, bool &was_canceled)
+void AbcExporter::operator()(short *do_update, float *progress, bool *was_canceled)
{
std::string scene_name;
@@ -332,10 +333,11 @@ void AbcExporter::operator()(float &progress, bool &was_canceled)
size_t i = 0;
for (; begin != end; ++begin) {
- progress = (++i / size);
+ *progress = (++i / size);
+ *do_update = 1;
if (G.is_break) {
- was_canceled = true;
+ *was_canceled = true;
break;
}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index e6a7a3fc7f4..a73289fcf95 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -104,7 +104,7 @@ class AbcExporter {
AbcExporter(Main *bmain, const char *filename, ExportSettings &settings);
~AbcExporter();
- void operator()(float &progress, bool &was_canceled);
+ void operator()(short *do_update, float *progress, bool *was_canceled);
protected:
void getShutterSamples(unsigned int nr_of_samples,
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
index 38042bc7286..98387be2e61 100644
--- a/source/blender/alembic/intern/abc_hair.cc
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -79,10 +79,14 @@ void AbcHairWriter::do_write()
if (m_psys->pathcache) {
ParticleSettings *part = m_psys->part;
+ bool export_children = m_settings.export_child_hairs && m_psys->childcache &&
+ part->childtype != 0;
- write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices);
+ if (!export_children || part->draw & PART_DRAW_PARENT) {
+ write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices);
+ }
- if (m_settings.export_child_hairs && m_psys->childcache) {
+ if (export_children) {
write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices);
}
}
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index 5de21075a23..651f32e6ab0 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -561,7 +561,7 @@ Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree)
BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, NULL, NULL, NULL);
- Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
if (r_needsfree) {
@@ -885,7 +885,8 @@ static void process_normals(CDStreamConfig &config, const AbcMeshData &mesh_data
if (!mesh_data.loop_normals) {
BKE_mesh_calc_normals(config.mesh);
- config.mesh->flag &= ~ME_AUTOSMOOTH;
+ /* Don't touch the ME_AUTOSMOOTH flag in this case. It can be used by artists to toggle between
+ * flat/smooth shaded when the Alembic mesh doesn't contain loop normals. */
return;
}
@@ -1018,7 +1019,10 @@ static void read_mesh_sample(const std::string &iobject_full_name,
abc_mesh_data.face_counts = sample.getFaceCounts();
abc_mesh_data.face_indices = sample.getFaceIndices();
abc_mesh_data.positions = sample.getPositions();
- abc_mesh_data.poly_flag_smooth = false;
+
+ /* The auto-smoothing flag can be used by artists when the Alembic file does not contain custom
+ * loop normals. Auto-smoothing only works when polys are marked as smooth. */
+ abc_mesh_data.poly_flag_smooth = (config.mesh->flag & ME_AUTOSMOOTH);
read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
@@ -1192,8 +1196,6 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size());
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
- /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_new_nomain_from_template() */
- new_mesh->flag |= (existing_mesh->flag & ME_AUTOSMOOTH);
}
else {
/* If the face count changed (e.g. by triangulation), only read points.
@@ -1416,11 +1418,24 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
Int32ArraySamplePtr indices = sample.getCreaseIndices();
Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
- MEdge *edges = mesh->medge;
-
if (indices && sharpnesses) {
+ MEdge *edges = mesh->medge;
+ int totedge = mesh->totedge;
+
for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
- MEdge *edge = find_edge(edges, mesh->totedge, (*indices)[i], (*indices)[i + 1]);
+ int v1 = (*indices)[i];
+ int v2 = (*indices)[i + 1];
+
+ if (v2 < v1) {
+ /* It appears to be common to store edges with the smallest index first, in which case this
+ * prevents us from doing the second search below. */
+ std::swap(v1, v2);
+ }
+
+ MEdge *edge = find_edge(edges, totedge, v1, v2);
+ if (edge == NULL) {
+ edge = find_edge(edges, totedge, v2, v1);
+ }
if (edge) {
edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index 9ace0a8faa9..1034c5b319f 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -173,9 +173,11 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
return parent_is_part_of_this_object;
}
-AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
+AbcArchiveHandle *ABC_create_handle(struct Main *bmain,
+ const char *filename,
+ ListBase *object_paths)
{
- ArchiveReader *archive = new ArchiveReader(filename);
+ ArchiveReader *archive = new ArchiveReader(bmain, filename);
if (!archive->valid()) {
delete archive;
@@ -222,6 +224,7 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string
struct ExportJobData {
ViewLayer *view_layer;
Main *bmain;
+ wmWindowManager *wm;
char filename[1024];
ExportSettings settings;
@@ -246,8 +249,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
* scene frame in separate threads
*/
G.is_rendering = true;
- BKE_spacedata_draw_locks(true);
-
+ WM_set_locked_interface(data->wm, true);
G.is_break = false;
DEG_graph_build_from_view_layer(
@@ -261,7 +263,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
const int orig_frame = CFRA;
data->was_canceled = false;
- exporter(*data->progress, data->was_canceled);
+ exporter(do_update, progress, &data->was_canceled);
if (CFRA != orig_frame) {
CFRA = orig_frame;
@@ -296,7 +298,7 @@ static void export_endjob(void *customdata)
}
G.is_rendering = false;
- BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(data->wm, false);
}
bool ABC_export(Scene *scene,
@@ -310,6 +312,7 @@ bool ABC_export(Scene *scene,
job->view_layer = CTX_data_view_layer(C);
job->bmain = CTX_data_main(C);
+ job->wm = CTX_wm_manager(C);
job->export_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
@@ -649,7 +652,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
WM_set_locked_interface(data->wm, true);
- ArchiveReader *archive = new ArchiveReader(data->filename);
+ ArchiveReader *archive = new ArchiveReader(data->bmain, data->filename);
if (!archive->valid()) {
#ifndef WITH_ALEMBIC_HDF5
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 0294a6219b9..45086de0f61 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -80,9 +80,8 @@ typedef struct GlyphCacheBLF {
/* and the last texture, aka. the current texture. */
unsigned int texture_current;
- /* like bftgl, we draw every glyph in a big texture, so this is the
- * current position inside the texture.
- */
+ /* We draw every glyph in a big texture, so this is the
+ * current position inside the texture. */
int offset_x;
int offset_y;
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 868c5a69593..b7139d5bbf6 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -212,8 +212,8 @@ void what_does_obaction(struct Object *ob,
float cframe);
/* for proxy */
-void BKE_pose_copyesult_pchan_result(struct bPoseChannel *pchanto,
- const struct bPoseChannel *pchanfrom);
+void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto,
+ const struct bPoseChannel *pchanfrom);
bool BKE_pose_copy_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void BKE_pose_rest(struct bPose *pose);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index a2a14011595..4e4528ff92b 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -25,7 +25,6 @@
*/
struct AnimData;
-struct ChannelDriver;
struct Depsgraph;
struct FCurve;
struct ID;
@@ -289,7 +288,7 @@ void BKE_animsys_eval_animdata(struct Depsgraph *depsgraph, struct ID *id);
void BKE_animsys_eval_driver(struct Depsgraph *depsgraph,
struct ID *id,
int driver_index,
- struct ChannelDriver *driver_orig);
+ struct FCurve *fcu_orig);
void BKE_animsys_update_driver_array(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index e55cb69a5c6..b35abb1ecef 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -91,5 +91,6 @@ enum {
#define BLENDER_QUIT_FILE "quit.blend"
#define BLENDER_BOOKMARK_FILE "bookmarks.txt"
#define BLENDER_HISTORY_FILE "recent-files.txt"
+#define BLENDER_PLATFORM_SUPPORT_FILE "platform_support.txt"
#endif /* __BKE_APPDIR_H__ */
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 89f83c44c11..dfa1b311eb0 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -26,8 +26,8 @@
*
* \note Use #STRINGIFY() rather than defining with quotes.
*/
-#define BLENDER_VERSION 281
-#define BLENDER_SUBVERSION 11
+#define BLENDER_VERSION 282
+#define BLENDER_SUBVERSION 1
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 26ab7f8ba0c..70741831727 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -31,7 +31,6 @@ struct Main;
struct Scene;
struct ToolSettings;
struct UnifiedPaintSettings;
-struct bContext;
// enum eCurveMappingPreset;
@@ -56,7 +55,7 @@ void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool li
void BKE_brush_free(struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
-void BKE_brush_gpencil_presets(struct bContext *C);
+void BKE_brush_gpencil_presets(struct Main *bmain, struct ToolSettings *ts);
/* image icon function */
struct ImBuf *get_brush_icon(struct Brush *brush);
@@ -90,7 +89,9 @@ float BKE_brush_sample_masktex(const struct Scene *scene,
unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary);
/* radial control */
-struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondary);
+struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br,
+ bool secondary,
+ bool display_gradient);
/* unified strength size and color */
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index aeff6007292..630c5fa1856 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -86,11 +86,10 @@ void BKE_curve_curve_dimension_update(struct Curve *cu);
void BKE_curve_boundbox_calc(struct Curve *cu, float r_loc[3], float r_size[3]);
struct BoundBox *BKE_curve_boundbox_get(struct Object *ob);
+
void BKE_curve_texspace_calc(struct Curve *cu);
-struct BoundBox *BKE_curve_texspace_get(struct Curve *cu,
- float r_loc[3],
- float r_rot[3],
- float r_size[3]);
+void BKE_curve_texspace_ensure(struct Curve *cu);
+void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_size[3]);
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 062968eddfc..47c8f31ead3 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -30,6 +30,7 @@
struct BMLoop;
struct BMesh;
+struct BoundBox;
struct Depsgraph;
struct EditMeshData;
struct Mesh;
@@ -59,6 +60,9 @@ typedef struct BMEditMesh {
struct Mesh *mesh_eval_final, *mesh_eval_cage;
+ /** Cached cage bounding box for selection. */
+ struct BoundBox *bb_cage;
+
/*derivedmesh stuff*/
CustomData_MeshMasks lastDataMask;
unsigned char (*derivedVertColor)[4];
@@ -90,6 +94,7 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3];
void BKE_editmesh_lnorspace_update(BMEditMesh *em);
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em);
+struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
/* editderivedmesh.c */
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index e86408076cd..7c8a9452023 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -72,8 +72,8 @@ struct BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *tree,
float *r_dist,
float r_hitout[3],
float r_cagehit[3],
- BMBVHTree_FaceFilter filter,
- void *filter_cb);
+ BMBVHTree_FaceFilter filter_cb,
+ void *filter_userdata);
/* find a vert closest to co in a sphere of radius dist_max */
struct BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *tree,
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 369cffedb9d..7f227650f61 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -32,6 +32,7 @@ struct ListBase;
struct Main;
struct Material;
struct Object;
+struct Scene;
struct ToolSettings;
struct bDeformGroup;
struct bGPDframe;
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index ba2e1e85d23..9cbc7d05ac2 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -31,7 +31,7 @@ struct ModifierUpdateDepsgraphContext;
struct Object;
struct Scene;
/* NOTE: bakeModifier() called from UI:
- * needs to create new databloc-ks, hence the need for this. */
+ * needs to create new data-blocks, hence the need for this. */
struct bGPDframe;
struct bGPDlayer;
struct bGPDstroke;
@@ -261,12 +261,6 @@ typedef struct GpencilModifierTypeInfo {
struct Object *ob,
GreasePencilTexWalkFunc walk,
void *userData);
-
- /**
- * Get the number of times the strokes are duplicated in this modifier.
- * This is used to calculate the size of the GPU VBOs
- */
- int (*getDuplicationFactor)(struct GpencilModifierData *md);
} GpencilModifierTypeInfo;
/* Initialize modifier's global data (type info and some common global storages). */
@@ -297,6 +291,7 @@ void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob,
bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
bool BKE_gpencil_has_time_modifiers(struct Object *ob);
+bool BKE_gpencil_has_transform_modifiers(struct Object *ob);
void BKE_gpencil_stroke_modifiers(struct Depsgraph *depsgraph,
struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 234b74eece3..82c831ae8e0 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -309,11 +309,11 @@ void BKE_image_get_aspect(struct Image *image, float *aspx, float *aspy);
/* image_gen.c */
void BKE_image_buf_fill_color(
unsigned char *rect, float *rect_float, int width, int height, const float color[4]);
-void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int height, int width);
+void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height);
void BKE_image_buf_fill_checker_color(unsigned char *rect,
float *rect_float,
- int height,
- int width);
+ int width,
+ int height);
/* Cycles hookup */
unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame);
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index 535980840c1..19eb40debe6 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -114,11 +114,13 @@ void BKE_base_set_visible(struct Scene *scene,
struct ViewLayer *view_layer,
struct Base *base,
bool extend);
-void BKE_layer_collection_isolate(struct Scene *scene,
- struct ViewLayer *view_layer,
- struct LayerCollection *lc,
- bool extend);
-void BKE_layer_collection_local_isolate(struct ViewLayer *view_layer,
+bool BKE_base_is_visible(const struct View3D *v3d, const struct Base *base);
+bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Object *ob);
+void BKE_layer_collection_isolate_global(struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct LayerCollection *lc,
+ bool extend);
+void BKE_layer_collection_isolate_local(struct ViewLayer *view_layer,
struct View3D *v3d,
struct LayerCollection *lc,
bool extend);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 261416dc025..71799bf74f6 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -114,7 +114,10 @@ enum {
LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_CACHES,
};
-void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, int flag);
+void BKE_libblock_copy_ex(struct Main *bmain,
+ const struct ID *id,
+ struct ID **r_newid,
+ const int orig_flag);
void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/* Special version. sued by datablock localization. */
@@ -172,6 +175,7 @@ void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv);
void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
void id_lib_extern(struct ID *id);
+void id_lib_indirect_weak_link(struct ID *id);
void BKE_library_filepath_set(struct Main *bmain, struct Library *lib, const char *filepath);
void id_us_ensure_real(struct ID *id);
void id_us_clear_real(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index af40eef6ab5..90afec54561 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -78,12 +78,18 @@ struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me,
const bool add_key_index,
const struct BMeshCreateParams *params);
-struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm, const struct BMeshToMeshParams *params);
+struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm,
+ const struct BMeshToMeshParams *params,
+ const struct Mesh *me_settings);
struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
- const struct CustomData_MeshMasks *cd_mask_extra);
+ const struct CustomData_MeshMasks *cd_mask_extra,
+ const struct Mesh *me_settings);
struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
- struct BMEditMesh *em, const struct CustomData_MeshMasks *data_mask, float (*vertexCos)[3]);
+ struct BMEditMesh *em,
+ const struct CustomData_MeshMasks *data_mask,
+ float (*vertexCos)[3],
+ const struct Mesh *me_settings);
int poly_find_loop_from_vert(const struct MPoly *poly,
const struct MLoop *loopstart,
@@ -107,6 +113,7 @@ void BKE_mesh_copy_data(struct Main *bmain,
const struct Mesh *me_src,
const int flag);
struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me);
+void BKE_mesh_copy_settings(struct Mesh *me_dst, const struct Mesh *me_src);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
@@ -141,8 +148,6 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me);
bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool lib_local);
-void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]);
-void BKE_mesh_texspace_calc(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr);
@@ -192,12 +197,14 @@ void BKE_mesh_smooth_flag_set(struct Mesh *me, const bool use_smooth);
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob);
-struct BoundBox *BKE_mesh_texspace_get(struct Mesh *me,
- float r_loc[3],
- float r_rot[3],
- float r_size[3]);
-void BKE_mesh_texspace_get_reference(
- struct Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size);
+
+void BKE_mesh_texspace_calc(struct Mesh *me);
+void BKE_mesh_texspace_ensure(struct Mesh *me);
+void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_size[3]);
+void BKE_mesh_texspace_get_reference(struct Mesh *me,
+ short **r_texflag,
+ float **r_loc,
+ float **r_size);
void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob);
void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
index a1bcd515c17..86c094b8a6d 100644
--- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
+++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
@@ -39,7 +39,12 @@ struct Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLeve
double adaptivity,
bool relax_disoriented_triangles);
#endif
-struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size);
+
+struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh);
+struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh,
+ float voxel_size,
+ float adaptivity,
+ float isovalue);
struct Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh,
int target_faces,
int seed,
diff --git a/source/blender/blenkernel/BKE_mirror.h b/source/blender/blenkernel/BKE_mirror.h
new file mode 100644
index 00000000000..20eb8a920fc
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mirror.h
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+#ifndef __BKE_MIRROR_H__
+#define __BKE_MIRROR_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_utildefines.h"
+
+struct MirrorModifierData;
+struct ModifierEvalContext;
+struct Object;
+
+struct Mesh *BKE_mirror_bisect_on_mirror_plane(struct MirrorModifierData *mmd,
+ const struct Mesh *mesh,
+ int axis,
+ const float plane_co[3],
+ float plane_no[3]);
+
+struct Mesh *BKE_mirror_apply_mirror_on_axis(struct MirrorModifierData *mmd,
+ const struct ModifierEvalContext *UNUSED(ctx),
+ struct Object *ob,
+ const struct Mesh *mesh,
+ int axis);
+
+#endif /* __BKE_MIRROR_H__ */
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index b2bc30c107c..0977a406aa0 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -48,7 +48,9 @@ typedef enum {
*/
eModifierTypeType_OnlyDeform,
+ /* Modifier adds geometry. */
eModifierTypeType_Constructive,
+ /* Modifier can add and remove geometry. */
eModifierTypeType_Nonconstructive,
/* both deformVerts & applyModifier are valid calls
@@ -380,6 +382,7 @@ struct Object *modifiers_isDeformedByArmature(struct Object *ob);
struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob);
struct Object *modifiers_isDeformedByLattice(struct Object *ob);
struct Object *modifiers_isDeformedByCurve(struct Object *ob);
+bool modifiers_usesMultires(struct Object *ob);
bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
bool modifiers_usesSubsurfFacedots(struct Scene *scene, struct Object *ob);
bool modifiers_isCorrectableDeformed(struct Scene *scene, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index c5955a9af8d..7513717df41 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -53,8 +53,8 @@ void multires_mark_as_modified(struct Depsgraph *depsgraph,
struct Object *object,
enum MultiresModifiedFlags flags);
-void multires_force_update(struct Object *ob);
-void multires_force_render_update(struct Object *ob);
+void multires_flush_sculpt_updates(struct Object *ob);
+void multires_force_sculpt_rebuild(struct Object *ob);
void multires_force_external_reload(struct Object *ob);
/* internal, only called in subsurf_ccg.c */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index f88aebd312c..a5b9b1e5148 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -591,6 +591,11 @@ void nodeChainIter(const bNodeTree *ntree,
bool (*callback)(bNode *, bNode *, void *, const bool),
void *userdata,
const bool reversed);
+void nodeChainIterBackwards(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *),
+ void *userdata,
+ int recursion_lvl);
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index dcd926e9e19..ffdcb9cd2c0 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -321,8 +321,10 @@ void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
void BKE_object_sculpt_data_create(struct Object *ob);
-int BKE_object_obdata_texspace_get(
- struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot);
+int BKE_object_obdata_texspace_get(struct Object *ob,
+ short **r_texflag,
+ float **r_loc,
+ float **r_size);
struct Mesh *BKE_object_get_evaluated_mesh(const struct Depsgraph *depsgraph, struct Object *ob);
struct Mesh *BKE_object_get_final_mesh(struct Object *object);
diff --git a/source/blender/blenkernel/BKE_object_facemap.h b/source/blender/blenkernel/BKE_object_facemap.h
index ef0cbaa2ae6..83780d8fad5 100644
--- a/source/blender/blenkernel/BKE_object_facemap.h
+++ b/source/blender/blenkernel/BKE_object_facemap.h
@@ -40,6 +40,11 @@ void BKE_object_facemap_unique_name(struct Object *ob, struct bFaceMap *fmap);
struct bFaceMap *BKE_object_facemap_find_name(struct Object *ob, const char *name);
void BKE_object_facemap_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
+int *BKE_object_facemap_index_map_create(struct Object *ob_src,
+ struct Object *ob_dst,
+ int *r_map_len);
+void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 5ce16e8b906..4413ad2a70f 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -220,7 +220,7 @@ typedef struct SculptSession {
struct MPoly *mpoly;
struct MLoop *mloop;
int totvert, totpoly;
- struct KeyBlock *kb;
+ struct KeyBlock *shapekey_active;
float *vmask;
/* Mesh connectivity */
@@ -243,10 +243,10 @@ typedef struct SculptSession {
bool show_mask;
/* Painting on deformed mesh */
- bool modifiers_active; /* object is deformed with some modifiers */
- float (*orig_cos)[3]; /* coords of undeformed mesh */
- float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */
- float (*deform_imats)[3][3]; /* crazyspace deformation matrices */
+ bool deform_modifiers_active; /* object is deformed with some modifiers */
+ float (*orig_cos)[3]; /* coords of undeformed mesh */
+ float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */
+ float (*deform_imats)[3][3]; /* crazyspace deformation matrices */
/* Used to cache the render of the active texture */
unsigned int texcache_side, *texcache, texcache_actual;
@@ -270,6 +270,7 @@ typedef struct SculptSession {
/* Dynamic mesh preview */
int *preview_vert_index_list;
int preview_vert_index_count;
+ float pose_origin[3];
/* Transform operator */
float pivot_pos[3];
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 899dddf31e8..13adb868c01 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -25,6 +25,13 @@
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
+/* For embedding CCGKey in iterator. */
+#include "BKE_ccg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BMLog;
struct BMesh;
struct CCGElem;
@@ -33,6 +40,7 @@ struct CustomData;
struct DMFlagMat;
struct GPU_PBVH_Buffers;
struct IsectRayPrecalc;
+struct Mesh;
struct MLoop;
struct MLoopTri;
struct MPoly;
@@ -40,6 +48,8 @@ struct MVert;
struct PBVH;
struct PBVHNode;
struct SubdivCCG;
+struct TaskParallelSettings;
+struct TaskParallelTLS;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
@@ -49,20 +59,28 @@ typedef struct {
} PBVHProxyNode;
typedef enum {
- PBVH_Leaf = 1,
+ PBVH_Leaf = 1 << 0,
- PBVH_UpdateNormals = 2,
- PBVH_UpdateBB = 4,
- PBVH_UpdateOriginalBB = 8,
- PBVH_UpdateDrawBuffers = 16,
- PBVH_UpdateRedraw = 32,
+ PBVH_UpdateNormals = 1 << 1,
+ PBVH_UpdateBB = 1 << 2,
+ PBVH_UpdateOriginalBB = 1 << 3,
+ PBVH_UpdateDrawBuffers = 1 << 4,
+ PBVH_UpdateRedraw = 1 << 5,
+ PBVH_UpdateMask = 1 << 6,
- PBVH_RebuildDrawBuffers = 64,
- PBVH_FullyHidden = 128,
+ PBVH_RebuildDrawBuffers = 1 << 7,
+ PBVH_FullyHidden = 1 << 8,
+ PBVH_FullyMasked = 1 << 9,
+ PBVH_FullyUnmasked = 1 << 10,
- PBVH_UpdateTopology = 256,
+ PBVH_UpdateTopology = 1 << 11,
} PBVHNodeFlags;
+typedef struct PBVHFrustumPlanes {
+ float (*planes)[4];
+ int num_planes;
+} PBVHFrustumPlanes;
+
/* Callbacks */
/* returns 1 if the search should continue from this node, 0 otherwise */
@@ -77,6 +95,7 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float
PBVH *BKE_pbvh_new(void);
void BKE_pbvh_build_mesh(PBVH *bvh,
+ const struct Mesh *mesh,
const struct MPoly *mpoly,
const struct MLoop *mloop,
struct MVert *verts,
@@ -167,7 +186,9 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
/* Drawing */
void BKE_pbvh_draw_cb(PBVH *bvh,
- float (*planes)[4],
+ bool show_vcol,
+ bool update_only_visible,
+ PBVHFrustumPlanes *frustum,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
void *user_data);
@@ -198,9 +219,10 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
int gridsize);
/* multires level, only valid for type == PBVH_GRIDS */
-void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key);
+const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh);
-struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh, int *num_grids);
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh);
+int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh);
/* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
@@ -221,11 +243,16 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
/* Node Access */
void BKE_pbvh_node_mark_update(PBVHNode *node);
+void BKE_pbvh_node_mark_update_mask(PBVHNode *node);
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node);
void BKE_pbvh_node_mark_redraw(PBVHNode *node);
void BKE_pbvh_node_mark_normals_update(PBVHNode *node);
void BKE_pbvh_node_mark_topology_update(PBVHNode *node);
void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden);
+void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked);
+bool BKE_pbvh_node_fully_masked_get(PBVHNode *node);
+void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked);
+bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node);
void BKE_pbvh_node_get_grids(PBVH *bvh,
PBVHNode *node,
@@ -245,10 +272,10 @@ void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
float BKE_pbvh_node_get_tmin(PBVHNode *node);
-/* test if AABB is at least partially inside the planes' volume */
-bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data);
-/* test if AABB is at least partially outside the planes' volume */
-bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data);
+/* test if AABB is at least partially inside the PBVHFrustumPlanes volume */
+bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum);
+/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */
+bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
@@ -259,8 +286,8 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *bvh);
/* Update Bounding Box/Redraw and clear flags */
void BKE_pbvh_update_bounds(PBVH *bvh, int flags);
+void BKE_pbvh_update_vertex_data(PBVH *bvh, int flags);
void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg);
-void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol);
void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface);
void BKE_pbvh_grids_update(PBVH *bvh,
@@ -304,9 +331,9 @@ typedef struct PBVHVertexIter {
int index;
/* grid */
+ struct CCGKey key;
struct CCGElem **grids;
struct CCGElem *grid;
- struct CCGKey *key;
BLI_bitmap **grid_hidden, *gh;
int *grid_indices;
int totgrid;
@@ -343,6 +370,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
if (vi.grids) { \
vi.width = vi.gridsize; \
vi.height = vi.gridsize; \
+ vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
vi.grid = vi.grids[vi.grid_indices[vi.g]]; \
if (mode == PBVH_ITER_UNIQUE) \
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
@@ -355,10 +383,11 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
for (vi.gy = 0; vi.gy < vi.height; vi.gy++) { \
for (vi.gx = 0; vi.gx < vi.width; vi.gx++, vi.i++) { \
if (vi.grid) { \
- vi.co = CCG_elem_co(vi.key, vi.grid); \
- vi.fno = CCG_elem_no(vi.key, vi.grid); \
- vi.mask = vi.key->has_mask ? CCG_elem_mask(vi.key, vi.grid) : NULL; \
- vi.grid = CCG_elem_next(vi.key, vi.grid); \
+ vi.co = CCG_elem_co(&vi.key, vi.grid); \
+ vi.fno = CCG_elem_no(&vi.key, vi.grid); \
+ vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \
+ vi.grid = CCG_elem_next(&vi.key, vi.grid); \
+ vi.index++; \
if (vi.gh) { \
if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) \
continue; \
@@ -414,4 +443,33 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
bool pbvh_has_mask(PBVH *bvh);
void pbvh_show_mask_set(PBVH *bvh, bool show_mask);
+/* Parallelization */
+typedef void (*PBVHParallelRangeFunc)(void *__restrict userdata,
+ const int iter,
+ const struct TaskParallelTLS *__restrict tls);
+typedef void (*PBVHParallelReduceFunc)(const void *__restrict userdata,
+ void *__restrict chunk_join,
+ void *__restrict chunk);
+
+typedef struct PBVHParallelSettings {
+ bool use_threading;
+ void *userdata_chunk;
+ size_t userdata_chunk_size;
+ PBVHParallelReduceFunc func_reduce;
+} PBVHParallelSettings;
+
+void BKE_pbvh_parallel_range_settings(struct PBVHParallelSettings *settings,
+ bool use_threading,
+ int totnode);
+
+void BKE_pbvh_parallel_range(const int start,
+ const int stop,
+ void *userdata,
+ PBVHParallelRangeFunc func,
+ const struct PBVHParallelSettings *settings);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BKE_PBVH_H__ */
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 4c023f54e04..b4c440d54a6 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -103,8 +103,14 @@ bool BKE_rigidbody_add_object(struct Main *bmain,
int type,
struct ReportList *reports);
void BKE_rigidbody_ensure_local_object(struct Main *bmain, struct Object *ob);
-void BKE_rigidbody_remove_object(struct Main *bmain, struct Scene *scene, struct Object *ob);
-void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob);
+void BKE_rigidbody_remove_object(struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob,
+ const bool free_us);
+void BKE_rigidbody_remove_constraint(struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob,
+ const bool free_us);
/* -------------- */
/* Utility Macros */
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 2986d19edfb..006915d6c45 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -75,7 +75,10 @@ void BKE_scene_free(struct Scene *sce);
void BKE_scene_init(struct Scene *sce);
struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
-void BKE_scene_remove_rigidbody_object(struct Main *bmain, struct Scene *scene, struct Object *ob);
+void BKE_scene_remove_rigidbody_object(struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob,
+ const bool free_us);
bool BKE_scene_object_find(struct Scene *scene, struct Object *ob);
struct Object *BKE_scene_object_find_by_name(struct Scene *scene, const char *name);
@@ -122,7 +125,7 @@ struct Scene *BKE_scene_find_from_collection(const struct Main *bmain,
#ifdef DURIAN_CAMERA_SWITCH
struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH
#endif
-int BKE_scene_camera_switch_update(struct Scene *scene);
+bool BKE_scene_camera_switch_update(struct Scene *scene);
char *BKE_scene_find_marker_name(struct Scene *scene, int frame);
char *BKE_scene_find_last_marker_name(struct Scene *scene, int frame);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 16f766ae8bb..a5b223a73f2 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -351,6 +351,7 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, floa
void BKE_sequencer_prefetch_stop(struct Scene *scene);
void BKE_sequencer_prefetch_free(struct Scene *scene);
bool BKE_sequencer_prefetch_need_redraw(struct Main *bmain, struct Scene *scene);
+bool BKE_sequencer_prefetch_job_is_running(struct Scene *scene);
void BKE_sequencer_prefetch_get_time_range(struct Scene *scene, int *start, int *end);
SeqRenderData *BKE_sequencer_prefetch_get_original_context(const SeqRenderData *context);
struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *seq,
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index e3d19a3d807..e90b1429c9d 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -115,6 +115,11 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
struct Object *ob_source,
struct Object *ob_target);
+/* Used in object_remesh.c to preserve the details and volume in the voxel remesher */
+void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me,
+ struct Mesh *target_me,
+ struct Object *ob_target);
+
/*
* This function casts a ray in the given BVHTree.
* but it takes into consideration the space_transform, that is:
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 700bf5139e0..267a03da25c 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -140,7 +140,7 @@ typedef struct SubdivDisplacement {
/* This structure contains everything needed to construct subdivided surface.
* It does not specify storage, memory layout or anything else.
- * It is possible to create different storages (like, grid based CPU side
+ * It is possible to create different storage's (like, grid based CPU side
* buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same
* Subdiv structure. */
typedef struct Subdiv {
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index 2e9ccb8b39d..409a0d1232b 100644
--- a/source/blender/blenkernel/BKE_subdiv_ccg.h
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -92,6 +92,14 @@ typedef struct SubdivToCCGSettings {
bool need_mask;
} SubdivToCCGSettings;
+typedef struct SubdivCCGCoord {
+ /* Index of the grid within SubdivCCG::grids array. */
+ int grid_index;
+
+ /* Coordinate within the grid. */
+ short x, y;
+} SubdivCCGCoord;
+
/* This is actually a coarse face, which consists of multiple CCG grids. */
typedef struct SubdivCCGFace {
/* Total number of grids in this face.
@@ -106,20 +114,16 @@ typedef struct SubdivCCGFace {
/* Definition of an edge which is adjacent to at least one of the faces. */
typedef struct SubdivCCGAdjacentEdge {
int num_adjacent_faces;
- /* Indexed by adjacent face index. */
- SubdivCCGFace **faces;
/* Indexed by adjacent face index, then by point index on the edge.
- * points to a grid element. */
- struct CCGElem ***boundary_elements;
+ * points to a coordinate into the grids. */
+ struct SubdivCCGCoord **boundary_coords;
} SubdivCCGAdjacentEdge;
/* Definition of a vertex which is adjacent to at least one of the faces. */
typedef struct SubdivCCGAdjacentVertex {
int num_adjacent_faces;
- /* Indexed by adjacent face index. */
- SubdivCCGFace **faces;
- /* Indexed by adjacent face index, points to a grid element. */
- struct CCGElem **corner_elements;
+ /* Indexed by adjacent face index, points to a coordinate in the grids. */
+ struct SubdivCCGCoord *corner_coords;
} SubdivCCGAdjacentVertex;
/* Representation of subdivision surface which uses CCG grids. */
@@ -135,6 +139,9 @@ typedef struct SubdivCCG {
/* Resolution of grid. All grids have matching resolution, and resolution
* is same as ptex created for non-quad polygons. */
int grid_size;
+ /* Size of a single element of a grid (including coordinate and all the other layers).
+ * Measured in bytes. */
+ int grid_element_size;
/* Grids represent limit surface, with displacement applied. Grids are
* corresponding to face-corners of coarse mesh, each grid has
* grid_size^2 elements.
@@ -150,7 +157,7 @@ typedef struct SubdivCCG {
struct CCGElem **edges;
int num_edges;
/* Loose vertices. Every element corresponds to a loose vertex from a coarse
- * mesh, every coarse loose vertex corresponds to a single sundivided
+ * mesh, every coarse loose vertex corresponds to a single subdivided
* element. */
struct CCGElem *vertices;
int num_vertices;
@@ -255,4 +262,40 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg,
int *r_num_faces,
int *r_num_loops);
+typedef struct SubdivCCGNeighbors {
+ SubdivCCGCoord *coords;
+ int size;
+ int num_duplicates;
+
+ SubdivCCGCoord coords_fixed[256];
+} SubdivCCGNeighbors;
+
+void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord);
+bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord);
+
+/* CCG element neighbors.
+ *
+ * Neighbors are considered:
+ *
+ * - For an inner elements of a grid other elements which are sharing same row or column (4
+ * neighbor elements in total).
+ *
+ * - For the corner element a single neighboring element on every adjacent edge, single from
+ * every gird.
+ *
+ * - For the boundary element two neighbor elements on the boundary (from same grid) and one
+ * element inside of every neighboring grid. */
+
+/* Get actual neighbors of the given coordinate.
+ *
+ * SubdivCCGNeighbors.neighbors must be freed if it is not equal to
+ * SubdivCCGNeighbors.fixed_neighbors.
+ *
+ * If include_duplicates is true, vertices in other grids that match
+ * the current vertex are added at the end of the coords array. */
+void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors);
+
#endif /* __BKE_SUBDIV_CCG_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_deform.h b/source/blender/blenkernel/BKE_subdiv_deform.h
new file mode 100644
index 00000000000..f1a56aa9cde
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_deform.h
@@ -0,0 +1,40 @@
+/*
+ * 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) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifndef __BKE_SUBDIV_DEFORM_H__
+#define __BKE_SUBDIV_DEFORM_H__
+
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct Subdiv;
+
+/* Special version of subdivision surface which calculates final positions for coarse vertices.
+ *
+ * vertex_cos are supposed to hold coordinates of the coarse mesh. */
+void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
+ const struct Mesh *coarse_mesh,
+ float (*vertex_cos)[3],
+ int num_verts);
+
+#endif /* __BKE_SUBDIV_DEFORM_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index 1d794e4d61a..c8d672c2524 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -31,7 +31,12 @@ struct Subdiv;
/* Returns true if evaluator is ready for use. */
bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
-bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv, const struct Mesh *mesh);
+
+/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
+ * mesh. */
+bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv,
+ const struct Mesh *mesh,
+ const float (*coarse_vertex_cos)[3]);
/* Makes sure displacement evaluator is initialized.
*
diff --git a/source/blender/blenkernel/BKE_subdiv_topology.h b/source/blender/blenkernel/BKE_subdiv_topology.h
new file mode 100644
index 00000000000..dd057d88fb6
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_topology.h
@@ -0,0 +1,31 @@
+/*
+ * 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) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifndef __BKE_SUBDIV_TOPOLOGY_H__
+#define __BKE_SUBDIV_TOPOLOGY_H__
+
+struct Subdiv;
+
+int BKE_subdiv_topology_num_fvar_layers_get(const struct Subdiv *subdiv);
+
+#endif /* __BKE_SUBDIV_TOPOLOGY_H__ */
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index 65aa43ced7c..98a94c5f689 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -78,6 +78,7 @@ void txt_delete_selected(struct Text *text);
void txt_sel_all(struct Text *text);
void txt_sel_clear(struct Text *text);
void txt_sel_line(struct Text *text);
+void txt_sel_set(struct Text *text, int startl, int startc, int endl, int endc);
char *txt_sel_to_buf(struct Text *text, int *r_buf_strlen);
void txt_insert_buf(struct Text *text, const char *in_buffer);
void txt_split_curline(struct Text *text);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 16074cd3e37..ec4246f5dba 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -159,6 +159,7 @@ set(SRC
intern/mesh_runtime.c
intern/mesh_tangent.c
intern/mesh_validate.c
+ intern/mirror.c
intern/modifier.c
intern/movieclip.c
intern/multires.c
@@ -182,15 +183,16 @@ set(SRC
intern/particle_system.c
intern/pbvh.c
intern/pbvh_bmesh.c
+ intern/pbvh_parallel.cc
intern/pointcache.c
intern/report.c
intern/rigidbody.c
intern/scene.c
intern/screen.c
intern/seqcache.c
- intern/seqprefetch.c
intern/seqeffects.c
intern/seqmodifier.c
+ intern/seqprefetch.c
intern/sequencer.c
intern/shader_fx.c
intern/shrinkwrap.c
@@ -205,12 +207,14 @@ set(SRC
intern/subdiv_ccg_material.c
intern/subdiv_converter.c
intern/subdiv_converter_mesh.c
+ intern/subdiv_deform.c
intern/subdiv_displacement.c
intern/subdiv_displacement_multires.c
intern/subdiv_eval.c
intern/subdiv_foreach.c
intern/subdiv_mesh.c
intern/subdiv_stats.c
+ intern/subdiv_topology.c
intern/subsurf_ccg.c
intern/suggestions.c
intern/text.c
@@ -310,6 +314,7 @@ set(SRC
BKE_mesh_remesh_voxel.h
BKE_mesh_runtime.h
BKE_mesh_tangent.h
+ BKE_mirror.h
BKE_modifier.h
BKE_movieclip.h
BKE_multires.h
@@ -339,9 +344,11 @@ set(SRC
BKE_studiolight.h
BKE_subdiv.h
BKE_subdiv_ccg.h
+ BKE_subdiv_deform.h
BKE_subdiv_eval.h
BKE_subdiv_foreach.h
BKE_subdiv_mesh.h
+ BKE_subdiv_topology.h
BKE_subsurf.h
BKE_suggestions.h
BKE_text.h
@@ -631,6 +638,14 @@ if(WITH_QUADRIFLOW)
add_definitions(-DWITH_QUADRIFLOW)
endif()
+if(WITH_TBB)
+ add_definitions(-DWITH_TBB)
+
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+endif()
+
## Warnings as errors, this is too strict!
#if(MSVC)
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 010e162f49d..2f61cfcbc15 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -729,7 +729,7 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
int free;
if (em) {
- mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, me);
}
else {
mesh = BKE_mesh_copy_for_eval(me, true);
@@ -797,14 +797,6 @@ static void editmesh_update_statvis_color(const Scene *scene, Object *ob)
BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
}
-static void mesh_copy_autosmooth(Mesh *me, Mesh *me_orig)
-{
- if (me_orig->flag & ME_AUTOSMOOTH) {
- me->flag |= ME_AUTOSMOOTH;
- me->smoothresh = me_orig->smoothresh;
- }
-}
-
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
const CustomData_MeshMasks *final_datamask,
const bool sculpt_dyntopo,
@@ -881,18 +873,8 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
/* Make sure the name is the same. This is because mesh allocation from template does not
* take care of naming. */
BLI_strncpy(mesh_eval->id.name, mesh_input->id.name, sizeof(mesh_eval->id.name));
- /* Make sure materials are preserved from the input. */
- if (mesh_eval->mat != NULL) {
- MEM_freeN(mesh_eval->mat);
- }
- mesh_eval->mat = MEM_dupallocN(mesh_input->mat);
- mesh_eval->totcol = mesh_input->totcol;
/* Make evaluated mesh to share same edit mesh pointer as original and copied meshes. */
mesh_eval->edit_mesh = mesh_input->edit_mesh;
- /* Copy auth-smooth settings which are also not taken care about by mesh allocation from a
- * template. */
- mesh_eval->flag |= (mesh_input->flag & ME_AUTOSMOOTH);
- mesh_eval->smoothresh = mesh_input->smoothresh;
}
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
@@ -1220,8 +1202,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
MEM_freeN(deformed_verts);
deformed_verts = NULL;
}
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
}
/* create an orco mesh in parallel */
@@ -1533,8 +1513,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Evaluate modifiers up to certain index to get the mesh cage. */
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
if (r_cage && cageIndex == -1) {
- mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, &final_datamask, NULL);
- mesh_copy_autosmooth(mesh_cage, mesh_input);
+ mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ em_input, &final_datamask, NULL, mesh_input);
}
/* Clear errors before evaluation. */
@@ -1574,9 +1554,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
if (mesh_final == NULL) {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
+ mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
- mesh_copy_autosmooth(mesh_final, mesh_input);
}
BLI_assert(deformed_verts != NULL);
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
@@ -1607,11 +1586,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
else {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
+ mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
- mesh_copy_autosmooth(mesh_final, mesh_input);
-
if (deformed_verts) {
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
@@ -1674,8 +1651,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
MEM_freeN(deformed_verts);
deformed_verts = NULL;
}
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
}
mesh_final->runtime.deformed_only = false;
}
@@ -1695,8 +1670,10 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
}
mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
- em_input, &final_datamask, deformed_verts ? MEM_dupallocN(deformed_verts) : NULL);
- mesh_copy_autosmooth(mesh_cage, mesh_input);
+ em_input,
+ &final_datamask,
+ deformed_verts ? MEM_dupallocN(deformed_verts) : NULL,
+ mesh_input);
}
}
@@ -1730,11 +1707,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
else {
/* this is just a copy of the editmesh, no need to calc normals */
mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(
- em_input, &final_datamask, deformed_verts);
+ em_input, &final_datamask, deformed_verts, mesh_input);
deformed_verts = NULL;
- mesh_copy_autosmooth(mesh_final, mesh_input);
-
/* In this case, we should never have weight-modifying modifiers in stack... */
if (do_init_statvis) {
editmesh_update_statvis_color(scene, ob);
@@ -1854,11 +1829,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
&ob->runtime.mesh_eval);
BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
- /* Only copy texspace from orig mesh if some modifier (hint: smoke sim, see T58492)
- * did not re-enable that flag (which always get disabled for eval mesh as a start). */
- if (!(ob->runtime.mesh_eval->texflag & ME_AUTOSPACE)) {
- BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
- }
assign_object_mesh_eval(ob);
@@ -1982,7 +1952,7 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
const CustomData_MeshMasks *dataMask)
{
/* This function isn't thread-safe and can't be used during evaluation. */
- BLI_assert(DEG_debug_is_evaluating(depsgraph) == false);
+ BLI_assert(DEG_is_evaluating(depsgraph) == false);
/* Evaluated meshes aren't supposed to be created on original instances. If you do,
* they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
@@ -2015,7 +1985,7 @@ Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
const CustomData_MeshMasks *dataMask)
{
/* This function isn't thread-safe and can't be used during evaluation. */
- BLI_assert(DEG_debug_is_evaluating(depsgraph) == false);
+ BLI_assert(DEG_is_evaluating(depsgraph) == false);
/* Evaluated meshes aren't supposed to be created on original instances. If you do,
* they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index d072a0aa599..de1cbd236fb 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -1472,7 +1472,7 @@ void BKE_pose_rest(bPose *pose)
}
}
-void BKE_pose_copyesult_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom)
+void BKE_pose_copy_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom)
{
copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
@@ -1523,7 +1523,7 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) {
pchanto = BKE_pose_channel_find_name(to, pchanfrom->name);
if (pchanto != NULL) {
- BKE_pose_copyesult_pchan_result(pchanto, pchanfrom);
+ BKE_pose_copy_pchan_result(pchanto, pchanfrom);
}
}
return true;
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index ab8ea37377d..2e655452a21 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -305,8 +305,9 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
/* make a copy of action - at worst, user has to delete copies... */
if (do_action) {
BLI_assert(bmain != NULL);
- BKE_id_copy(bmain, (ID *)dadt->action, (ID **)&dadt->action);
- BKE_id_copy(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact);
+ BLI_assert(dadt->action == NULL || dadt->action != dadt->tmpact);
+ BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, flag);
+ BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, flag);
}
else if (do_id_user) {
id_us_plus((ID *)dadt->action);
@@ -4081,11 +4082,10 @@ void BKE_animsys_update_driver_array(ID *id)
}
}
-void BKE_animsys_eval_driver(Depsgraph *depsgraph,
- ID *id,
- int driver_index,
- ChannelDriver *driver_orig)
+void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCurve *fcu_orig)
{
+ BLI_assert(fcu_orig != NULL);
+
/* TODO(sergey): De-duplicate with BKE animsys. */
PointerRNA id_ptr;
bool ok = false;
@@ -4110,6 +4110,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
/* check if driver itself is tagged for recalculation */
/* XXX driver recalc flag is not set yet by depsgraph! */
+ ChannelDriver *driver_orig = fcu_orig->driver;
if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID)) {
/* evaluate this using values set already in other places
* NOTE: for 'layering' option later on, we should check if we should remove old value before
@@ -4120,7 +4121,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
/* Evaluate driver, and write results to COW-domain destination */
const float ctime = DEG_get_ctime(depsgraph);
- const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime);
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
ok = animsys_write_rna_setting(&anim_rna, curval);
/* Flush results & status codes to original data for UI (T59984) */
@@ -4128,6 +4129,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval);
/* curval is displayed in the UI, and flag contains error-status codes */
+ fcu_orig->curval = fcu->curval;
driver_orig->curval = fcu->driver->curval;
driver_orig->flag = fcu->driver->flag;
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 3b64a9520ca..fbac9e6b773 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -110,7 +110,7 @@ const char *BKE_appdir_folder_default(void)
// #define PATH_DEBUG
-/* returns a formatted representation of the specified version number. Non-reentrant! */
+/* returns a formatted representation of the specified version number. Non-re-entrant! */
static char *blender_version_decimal(const int ver)
{
static char version_str[5];
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index d74c8e6d258..3215b3d7b40 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1257,9 +1257,9 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
float pre_blend = pos * (float)segments;
int index = (int)floorf(pre_blend);
- float blend = pre_blend - index;
+ CLAMP(index, 0, segments - 1);
- CLAMP(index, 0, segments);
+ float blend = pre_blend - index;
CLAMP(blend, 0.0f, 1.0f);
*r_index = index;
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 00975976130..e30accf6279 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -643,6 +643,10 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec
}
BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase));
+
+ if (object->proxy != NULL) {
+ object->proxy->proxy_from = object;
+ }
}
void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, Scene *scene, Object *object)
@@ -724,6 +728,26 @@ void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph,
}
}
+static void pose_channel_flush_to_orig_if_needed(struct Depsgraph *depsgraph,
+ struct Object *object,
+ bPoseChannel *pchan)
+{
+ if (!DEG_is_active(depsgraph)) {
+ return;
+ }
+ const bArmature *armature = (bArmature *)object->data;
+ if (armature->edbo != NULL) {
+ return;
+ }
+ bPoseChannel *pchan_orig = pchan->orig_pchan;
+ /* TODO(sergey): Using BKE_pose_copy_pchan_result() introduces T70901, but why? */
+ copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat);
+ copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat);
+ copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]);
+ copy_m4_m4(pchan_orig->constinv, pchan->constinv);
+ copy_v3_v3(pchan_orig->pose_tail, pchan->pose_tail);
+}
+
void BKE_pose_bone_done(struct Depsgraph *depsgraph, struct Object *object, int pchan_index)
{
const bArmature *armature = (bArmature *)object->data;
@@ -741,13 +765,9 @@ void BKE_pose_bone_done(struct Depsgraph *depsgraph, struct Object *object, int
mat4_to_dquat(&pchan->runtime.deform_dual_quat, pchan->bone->arm_mat, pchan->chan_mat);
}
}
- if (DEG_is_active(depsgraph) && armature->edbo == NULL) {
+ pose_channel_flush_to_orig_if_needed(depsgraph, object, pchan);
+ if (DEG_is_active(depsgraph)) {
bPoseChannel *pchan_orig = pchan->orig_pchan;
- copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat);
- copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat);
- copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]);
- copy_m4_m4(pchan_orig->constinv, pchan->constinv);
- BKE_pose_where_is_bone_tail(pchan_orig);
if (pchan->bone == NULL || pchan->bone->segments <= 1) {
BKE_pose_channel_free_bbone_cache(&pchan_orig->runtime);
}
@@ -905,7 +925,9 @@ void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, Object *object,
pchan->name);
return;
}
- BKE_pose_copyesult_pchan_result(pchan, pchan_from);
+ BKE_pose_copy_pchan_result(pchan, pchan_from);
copy_dq_dq(&pchan->runtime.deform_dual_quat, &pchan_from->runtime.deform_dual_quat);
BKE_pchan_bbone_segments_cache_copy(pchan, pchan_from);
+
+ pose_channel_flush_to_orig_if_needed(depsgraph, object, pchan);
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 29c4ae624e9..fe740f4898e 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -26,6 +26,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_defaults.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rand.h"
@@ -36,6 +37,7 @@
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
#include "BKE_icons.h"
@@ -239,307 +241,390 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
}
}
-/* create a set of grease pencil presets */
-void BKE_brush_gpencil_presets(bContext *C)
+/* create a set of grease pencil presets. */
+void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts)
{
#define SMOOTH_STROKE_RADIUS 40
#define SMOOTH_STROKE_FACTOR 0.9f
- ToolSettings *ts = CTX_data_tool_settings(C);
Paint *paint = &ts->gp_paint->paint;
- Main *bmain = CTX_data_main(C);
Brush *brush, *deft;
CurveMapping *custom_curve;
- /* Pencil brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
- brush->size = 25.0f;
+ /* Airbrush brush. */
+ brush = BLI_findstring(&bmain->brushes, "Airbrush", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Airbrush");
+ }
+
+ brush->size = 300.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->draw_strength = 0.4f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
- brush->gpencil_settings->draw_random_press = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.98f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 0.211f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_AIRBRUSH;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Pen brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
- deft = brush; /* save default brush */
- brush->size = 30.0f;
+ /* Create and link Black Dots material to brush.
+ * This material is required because the brush uses the material to define how the stroke is
+ * drawn. */
+ Material *ma = BLI_findstring(&bmain->materials, "Black Dots", offsetof(ID, name) + 2);
+ if (ma == NULL) {
+ ma = BKE_material_add_gpencil(bmain, "Black Dots");
+ }
+ brush->gpencil_settings->material = ma;
+ /* Pin the matterial to the brush. */
+ brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED;
+
+ /* Ink Pen brush. */
+ brush = BLI_findstring(&bmain->brushes, "Ink Pen", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen");
+ }
+ brush->size = 60.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->gpencil_settings->draw_random_press = 0.0f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.7f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Ink brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
- brush->size = 60.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.6f;
-
- brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->simplify_f = 0.002f;
brush->gpencil_settings->draw_random_press = 0.0f;
-
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_angle = 0.0f;
- brush->gpencil_settings->draw_angle_factor = 0.0f;
+ /* Curve. */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ BKE_curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Curve */
- custom_curve = brush->gpencil_settings->curve_sensitivity;
- BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
- BKE_curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
+ /* Ink Pen Rough brush. */
+ brush = BLI_findstring(&bmain->brushes, "Ink Pen Rough", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen Rough");
+ }
- /* Ink Noise brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
brush->size = 60.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 0.7f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.5f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 2;
- brush->gpencil_settings->thick_smoothfac = 0.5f;
+ brush->gpencil_settings->thick_smoothfac = 0.0f;
brush->gpencil_settings->thick_smoothlvl = 2;
- brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ brush->gpencil_settings->simplify_f = 0.000f;
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 1.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- /* Curve */
+ /* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_initialize(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE);
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Block Basic brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
- brush->size = 150.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
- brush->gpencil_settings->draw_strength = 1.0f;
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->draw_random_press = 0.0f;
+ /* Marker Bold brush. */
+ brush = BLI_findstring(&bmain->brushes, "Marker Bold", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Marker Bold");
+ }
+ brush->size = 150.0f;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE;
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_strength = 0.3f;
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.6f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 0;
- brush->gpencil_settings->draw_random_sub = 0;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ /* Curve. */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ BKE_curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Marker brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
+ /* Marker Chisel brush. */
+ brush = BLI_findstring(&bmain->brushes, "Marker Chisel", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Marker Chisel");
+ }
brush->size = 80.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 0.374f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.5f;
brush->gpencil_settings->draw_angle = DEG2RAD(20.0f);
brush->gpencil_settings->draw_angle_factor = 1.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- /* Curve */
- custom_curve = brush->gpencil_settings->curve_sensitivity;
- BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
- BKE_curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
+ /* Pen brush. */
+ brush = BLI_findstring(&bmain->brushes, "Pen", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Pen");
+ }
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.3f;
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
brush->gpencil_settings->gradient_f = 1.0f;
brush->gpencil_settings->gradient_s[0] = 1.0f;
brush->gpencil_settings->gradient_s[1] = 1.0f;
- /* Soft brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Soft");
- deft = brush; /* save default brush */
- brush->size = 300.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 1;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pencil Soft brush. */
+ brush = BLI_findstring(&bmain->brushes, "Pencil Soft", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Pencil Soft");
+ }
+
+ brush->size = 80.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+
brush->gpencil_settings->draw_strength = 0.4f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.64f;
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 0.8f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->simplify_f = 0.000f;
+
brush->gpencil_settings->draw_random_press = 0.0f;
brush->gpencil_settings->draw_random_strength = 0.0f;
-
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pencil brush. */
+ brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Pencil");
+ }
+ deft = brush; /* save default brush. */
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+
+ brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->input_samples = 10;
+ brush->gpencil_settings->active_smooth = 0.55f;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
- brush->gpencil_settings->input_samples = 10;
- brush->gpencil_settings->active_smooth = 0.98f;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_settings->simplify_f = 0.002f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- brush->gpencil_settings->gradient_f = 0.211f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 0.91f;
-
- /* Fill brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
+ /* Fill brush. */
+ brush = BLI_findstring(&bmain->brushes, "Fill Area", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
+ }
brush->size = 20.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
- brush->gpencil_settings->draw_sensitivity = 1.0f;
+
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->icon_id = GP_BRUSH_ICON_FILL;
- brush->gpencil_tool = GPAINT_TOOL_FILL;
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
brush->gpencil_settings->draw_smoothfac = 0.1f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 1;
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
+ brush->gpencil_tool = GPAINT_TOOL_FILL;
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- /* Soft Eraser brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
+ /* Soft Eraser brush. */
+ brush = BLI_findstring(&bmain->brushes, "Eraser Soft", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
+ }
brush->size = 30.0f;
brush->gpencil_settings->draw_strength = 0.5f;
brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
@@ -551,34 +636,46 @@ void BKE_brush_gpencil_presets(bContext *C)
brush->gpencil_settings->era_strength_f = 100.0f;
brush->gpencil_settings->era_thickness_f = 10.0f;
- /* Hard Eraser brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
+ /* Hard Eraser brush. */
+ brush = BLI_findstring(&bmain->brushes, "Eraser Hard", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
+ }
brush->size = 30.0f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
- brush->gpencil_tool = GPAINT_TOOL_ERASE;
brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
brush->gpencil_settings->era_strength_f = 100.0f;
brush->gpencil_settings->era_thickness_f = 50.0f;
- /* Point Eraser brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point");
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+
+ /* Point Eraser brush. */
+ brush = BLI_findstring(&bmain->brushes, "Eraser Point", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point");
+ }
brush->size = 30.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
+
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
- /* Stroke Eraser brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
+ /* Stroke Eraser brush. */
+ brush = BLI_findstring(&bmain->brushes, "Eraser Stroke", offsetof(ID, name) + 2);
+ if (brush == NULL) {
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
+ }
brush->size = 30.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
+
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
- /* set default brush */
+ /* set default brush. */
BKE_paint_brush_set(paint, deft);
}
@@ -812,53 +909,36 @@ void BKE_brush_sculpt_reset(Brush *br)
/* Use the curve presets by default */
br->curve_preset = BRUSH_CURVE_SMOOTH;
- if (br->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
- br->curve_preset = BRUSH_CURVE_POW4;
- }
+ /* Note that sculpt defaults where set when 0.5 was the default (now it's 1.0)
+ * assign this so logic below can remain the same. */
+ br->alpha = 0.5f;
+
+ /* Brush settings */
switch (br->sculpt_tool) {
+ case SCULPT_TOOL_DRAW_SHARP:
+ br->flag |= BRUSH_DIR_IN;
+ br->curve_preset = BRUSH_CURVE_POW4;
+ br->spacing = 5;
+ break;
case SCULPT_TOOL_CLAY:
br->flag |= BRUSH_FRONTFACE;
break;
+ case SCULPT_TOOL_CLAY_STRIPS:
+ br->flag |= BRUSH_ACCUMULATE;
+ br->alpha = 0.7f;
+ br->normal_radius_factor = 1.7f;
+ br->curve_preset = BRUSH_CURVE_SPHERE;
+ br->spacing = 6;
+ break;
case SCULPT_TOOL_CREASE:
br->flag |= BRUSH_DIR_IN;
br->alpha = 0.25;
break;
- case SCULPT_TOOL_FILL:
- br->add_col[1] = 1;
- br->sub_col[0] = 0.25;
- br->sub_col[1] = 1;
- break;
- case SCULPT_TOOL_FLATTEN:
- br->add_col[1] = 1;
- br->sub_col[0] = 0.25;
- br->sub_col[1] = 1;
- break;
- case SCULPT_TOOL_INFLATE:
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 0.250000;
- br->sub_col[2] = 0.250000;
- break;
- case SCULPT_TOOL_NUDGE:
- br->add_col[0] = 0.250000;
- br->add_col[1] = 1.000000;
- br->add_col[2] = 0.250000;
- break;
- case SCULPT_TOOL_PINCH:
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 0.250000;
- br->sub_col[2] = 0.250000;
- break;
case SCULPT_TOOL_SCRAPE:
- br->add_col[1] = 1.000000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 1.000000;
+ br->alpha = 1.0f;
+ br->spacing = 7;
+ br->flag |= BRUSH_ACCUMULATE;
break;
case SCULPT_TOOL_ROTATE:
br->alpha = 1.0;
@@ -866,22 +946,95 @@ void BKE_brush_sculpt_reset(Brush *br)
case SCULPT_TOOL_SMOOTH:
br->flag &= ~BRUSH_SPACE_ATTEN;
br->spacing = 5;
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
+ br->alpha = 0.7f;
break;
- case SCULPT_TOOL_GRAB:
- case SCULPT_TOOL_ELASTIC_DEFORM:
- case SCULPT_TOOL_POSE:
case SCULPT_TOOL_SNAKE_HOOK:
+ br->alpha = 1.0f;
+ br->rake_factor = 1.0f;
+ break;
case SCULPT_TOOL_THUMB:
br->size = 75;
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
- br->add_col[0] = 0.250000;
- br->add_col[1] = 1.000000;
- br->add_col[2] = 0.250000;
+ break;
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ br->elastic_deform_volume_preservation = 0.4f;
+ br->elastic_deform_type = BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ break;
+ case SCULPT_TOOL_POSE:
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ break;
+ case SCULPT_TOOL_GRAB:
+ br->alpha = 0.4f;
+ br->size = 75;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ break;
+ default:
+ break;
+ }
+
+ /* Cursor colors */
+ switch (br->sculpt_tool) {
+ case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_DRAW_SHARP:
+ case SCULPT_TOOL_CLAY:
+ case SCULPT_TOOL_CLAY_STRIPS:
+ case SCULPT_TOOL_LAYER:
+ case SCULPT_TOOL_INFLATE:
+ case SCULPT_TOOL_BLOB:
+ case SCULPT_TOOL_CREASE:
+ br->add_col[0] = 0.5f;
+ br->add_col[1] = 0.7f;
+ br->add_col[2] = 0.875f;
+ br->sub_col[0] = 0.5f;
+ br->sub_col[1] = 0.7f;
+ br->sub_col[2] = 0.875f;
+ break;
+
+ case SCULPT_TOOL_SMOOTH:
+ case SCULPT_TOOL_FLATTEN:
+ case SCULPT_TOOL_FILL:
+ case SCULPT_TOOL_SCRAPE:
+ br->add_col[0] = 1.0f;
+ br->add_col[1] = 0.39f;
+ br->add_col[2] = 0.39f;
+ br->sub_col[0] = 1.0f;
+ br->sub_col[1] = 0.39f;
+ br->sub_col[2] = 0.39f;
+ break;
+
+ case SCULPT_TOOL_PINCH:
+ case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_SNAKE_HOOK:
+ case SCULPT_TOOL_THUMB:
+ case SCULPT_TOOL_NUDGE:
+ case SCULPT_TOOL_ROTATE:
+ case SCULPT_TOOL_ELASTIC_DEFORM:
+ case SCULPT_TOOL_POSE:
+ br->add_col[0] = 1.0f;
+ br->add_col[1] = 1.0f;
+ br->add_col[2] = 0.39f;
+ br->sub_col[0] = 1.0f;
+ br->sub_col[1] = 1.0f;
+ br->sub_col[2] = 0.39f;
+ break;
+
+ case SCULPT_TOOL_SIMPLIFY:
+ case SCULPT_TOOL_MASK:
+ br->add_col[0] = 0.750000;
+ br->add_col[1] = 0.750000;
+ br->add_col[2] = 0.750000;
+ br->sub_col[0] = 0.750000;
+ br->sub_col[1] = 0.750000;
+ br->sub_col[2] = 0.750000;
break;
default:
break;
@@ -1470,11 +1623,11 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
}
/**** Radial Control ****/
-struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
+struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool display_gradient)
{
ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture");
unsigned int *texcache;
- int side = 128;
+ int side = 512;
int half = side / 2;
int i, j;
@@ -1483,15 +1636,17 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect");
im->x = im->y = side;
- for (i = 0; i < side; i++) {
- for (j = 0; j < side; j++) {
- float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
- im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
+ if (display_gradient || texcache) {
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
+ float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
+ im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
+ }
}
}
- /* Modulate curve with texture */
if (texcache) {
+ /* Modulate curve with texture */
for (i = 0; i < side; i++) {
for (j = 0; j < side; j++) {
const int col = texcache[i * side + j];
@@ -1500,7 +1655,6 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
3.0f / 255.0f;
}
}
-
MEM_freeN(texcache);
}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 85a12027bf2..0a5952e1b47 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -1395,7 +1395,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
else {
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_edges_setup_data(
- data, tree, false, mesh->mvert, false, mesh->medge, false);
+ data, tree, true, mesh->mvert, false, mesh->medge, false);
}
break;
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 2d6256f12e2..3b0f4d9c2aa 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -246,7 +246,7 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file
BLI_freelistN(&cache_file->object_paths);
#ifdef WITH_ALEMBIC
- cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
+ cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths);
BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
#endif
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 63d58f7e32e..463cbd4f378 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -772,7 +772,7 @@ static int cloth_from_object(
clmd->clothObject->old_solver_type = 255;
clmd->clothObject->edgeset = NULL;
}
- else if (!clmd->clothObject) {
+ else {
modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject");
return 0;
}
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index f2098cc2430..68a38c94ff7 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -773,7 +773,7 @@ static bool scene_collections_object_remove(
bool removed = false;
if (collection_skip == NULL) {
- BKE_scene_remove_rigidbody_object(bmain, scene, ob);
+ BKE_scene_remove_rigidbody_object(bmain, scene, ob, free_us);
}
FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
@@ -1305,6 +1305,9 @@ bool BKE_collection_move(Main *bmain,
BLI_ghash_free(view_layer_hash, NULL, NULL);
+ /* We need to sync it again to pass the correct flags to the collections objects. */
+ BKE_main_collection_sync(bmain);
+
return true;
}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index fcbebd24b4a..fe834658689 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -261,7 +261,8 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
float (**deformcos)[3])
{
ModifierData *md;
- Mesh *me;
+ Mesh *me_input = ob->data;
+ Mesh *me = NULL;
int i, a, numleft = 0, numVerts = 0;
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
@@ -270,7 +271,6 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
modifiers_clearErrors(ob);
- me = NULL;
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* compute the deformation matrices and coordinates for the first
@@ -292,7 +292,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
data_mask = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, NULL);
- me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL);
+ me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL, me_input);
deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
@@ -342,6 +342,34 @@ static void crazyspace_init_object_for_eval(struct Depsgraph *depsgraph,
}
}
+static void crazyspace_init_verts_and_matrices(const Mesh *mesh,
+ float (**deformmats)[3][3],
+ float (**deformcos)[3])
+{
+ int num_verts;
+ *deformcos = BKE_mesh_vert_coords_alloc(mesh, &num_verts);
+ *deformmats = MEM_callocN(sizeof(**deformmats) * num_verts, "defmats");
+ for (int a = 0; a < num_verts; a++) {
+ unit_m3((*deformmats)[a]);
+ }
+ BLI_assert(num_verts == mesh->totvert);
+}
+
+static bool crazyspace_modifier_supports_deform_matrices(ModifierData *md)
+{
+ if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) {
+ return true;
+ }
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ return (mti->type == eModifierTypeType_OnlyDeform);
+}
+
+static bool crazyspace_modifier_supports_deform(ModifierData *md)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ return (mti->type == eModifierTypeType_OnlyDeform);
+}
+
int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
Scene *scene,
Object *object,
@@ -349,70 +377,63 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
float (**deformcos)[3])
{
ModifierData *md;
- Mesh *me_eval;
- int a, numVerts = 0;
+ Mesh *me_eval = NULL;
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
int numleft = 0;
VirtualModifierData virtualModifierData;
Object object_eval;
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0);
+ const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0;
const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
- if (has_multires) {
+ if (is_sculpt_mode && has_multires) {
*deformmats = NULL;
*deformcos = NULL;
return numleft;
}
- me_eval = NULL;
-
md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (mti->type == eModifierTypeType_OnlyDeform) {
- if (!defmats) {
+ if (crazyspace_modifier_supports_deform_matrices(md)) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ if (defmats == NULL) {
/* NOTE: Evaluated object si re-set to its original undeformed
* state. */
Mesh *me = object_eval.data;
me_eval = BKE_mesh_copy_for_eval(me, true);
- deformedVerts = BKE_mesh_vert_coords_alloc(me, &numVerts);
- defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats");
-
- for (a = 0; a < numVerts; a++) {
- unit_m3(defmats[a]);
- }
+ crazyspace_init_verts_and_matrices(me_eval, &defmats, &deformedVerts);
}
if (mti->deformMatrices) {
- mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts);
+ mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, me_eval->totvert);
}
else {
break;
}
}
+ else {
+ break;
+ }
}
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (mti->type == eModifierTypeType_OnlyDeform) {
+ if (crazyspace_modifier_supports_deform(md)) {
numleft++;
}
}
- if (me_eval) {
+ if (me_eval != NULL) {
BKE_id_free(NULL, me_eval);
}
@@ -435,6 +456,13 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
/* there are deformation modifier which doesn't support deformation matrices
* calculation. Need additional crazyspace correction */
+ Mesh *mesh = (Mesh *)object->data;
+ Mesh *mesh_eval = NULL;
+
+ if (*deformcos == NULL) {
+ crazyspace_init_verts_and_matrices(mesh, deformmats, deformcos);
+ }
+
float(*deformedVerts)[3] = *deformcos;
float(*origVerts)[3] = MEM_dupallocN(deformedVerts);
float(*quats)[4];
@@ -444,23 +472,26 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
- Mesh *mesh = (Mesh *)object->data;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (mti->type == eModifierTypeType_OnlyDeform) {
+ if (crazyspace_modifier_supports_deform(md)) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
/* skip leading modifiers which have been already
* handled in sculpt_get_first_deform_matrices */
if (mti->deformMatrices && !deformed) {
continue;
}
- mti->deformVerts(md, &mectx, NULL, deformedVerts, mesh->totvert);
+ if (mesh_eval == NULL) {
+ mesh_eval = BKE_mesh_copy_for_eval(mesh, true);
+ }
+
+ mti->deformVerts(md, &mectx, mesh_eval, deformedVerts, mesh_eval->totvert);
deformed = 1;
}
}
@@ -479,6 +510,10 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
MEM_freeN(origVerts);
MEM_freeN(quats);
+
+ if (mesh_eval != NULL) {
+ BKE_id_free(NULL, mesh_eval);
+ }
}
if (*deformmats == NULL) {
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 67b0aaffc4a..d81d250a305 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -142,7 +142,6 @@ void BKE_curve_free(Curve *cu)
MEM_SAFE_FREE(cu->mat);
MEM_SAFE_FREE(cu->str);
MEM_SAFE_FREE(cu->strinfo);
- MEM_SAFE_FREE(cu->bb);
MEM_SAFE_FREE(cu->tb);
}
@@ -154,8 +153,6 @@ void BKE_curve_init(Curve *cu, const short curve_type)
cu->type = curve_type;
- cu->bb = BKE_boundbox_alloc_unit();
-
if (cu->type == OB_FONT) {
cu->flag |= CU_FRONT | CU_BACK;
cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
@@ -204,7 +201,6 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const
cu_dst->str = MEM_dupallocN(cu_src->str);
cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
cu_dst->tb = MEM_dupallocN(cu_src->tb);
- cu_dst->bb = MEM_dupallocN(cu_src->bb);
cu_dst->batch_cache = NULL;
if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
@@ -291,41 +287,6 @@ void BKE_curve_type_test(Object *ob)
}
}
-void BKE_curve_boundbox_calc(Curve *cu, float r_loc[3], float r_size[3])
-{
- BoundBox *bb;
- float min[3], max[3];
- float mloc[3], msize[3];
-
- if (cu->bb == NULL) {
- cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- }
- bb = cu->bb;
-
- if (!r_loc) {
- r_loc = mloc;
- }
- if (!r_size) {
- r_size = msize;
- }
-
- INIT_MINMAX(min, max);
- if (!BKE_curve_minmax(cu, true, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
-
- mid_v3_v3v3(r_loc, min, max);
-
- r_size[0] = (max[0] - min[0]) / 2.0f;
- r_size[1] = (max[1] - min[1]) / 2.0f;
- r_size[2] = (max[2] - min[2]) / 2.0f;
-
- BKE_boundbox_init_from_minmax(bb, min, max);
-
- bb->flag &= ~BOUNDBOX_DIRTY;
-}
-
BoundBox *BKE_curve_boundbox_get(Object *ob)
{
/* This is Object-level data access,
@@ -349,13 +310,23 @@ BoundBox *BKE_curve_boundbox_get(Object *ob)
void BKE_curve_texspace_calc(Curve *cu)
{
- float loc[3], size[3];
- int a;
+ if (cu->texflag & CU_AUTOSPACE) {
+ float min[3], max[3];
- BKE_curve_boundbox_calc(cu, loc, size);
+ INIT_MINMAX(min, max);
+ if (!BKE_curve_minmax(cu, true, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- if (cu->texflag & CU_AUTOSPACE) {
- for (a = 0; a < 3; a++) {
+ float loc[3], size[3];
+ mid_v3_v3v3(loc, min, max);
+
+ size[0] = (max[0] - min[0]) / 2.0f;
+ size[1] = (max[1] - min[1]) / 2.0f;
+ size[2] = (max[2] - min[2]) / 2.0f;
+
+ for (int a = 0; a < 3; a++) {
if (size[a] == 0.0f) {
size[a] = 1.0f;
}
@@ -369,27 +340,28 @@ void BKE_curve_texspace_calc(Curve *cu)
copy_v3_v3(cu->loc, loc);
copy_v3_v3(cu->size, size);
- zero_v3(cu->rot);
+
+ cu->texflag |= CU_AUTOSPACE_EVALUATED;
}
}
-BoundBox *BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_size[3])
+void BKE_curve_texspace_ensure(Curve *cu)
{
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ if ((cu->texflag & CU_AUTOSPACE) && !(cu->texflag & CU_AUTOSPACE_EVALUATED)) {
BKE_curve_texspace_calc(cu);
}
+}
+
+void BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_size[3])
+{
+ BKE_curve_texspace_ensure(cu);
if (r_loc) {
copy_v3_v3(r_loc, cu->loc);
}
- if (r_rot) {
- copy_v3_v3(r_rot, cu->rot);
- }
if (r_size) {
copy_v3_v3(r_size, cu->size);
}
-
- return cu->bb;
}
bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
@@ -5501,15 +5473,10 @@ void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
BKE_curve_texspace_calc(curve);
if (DEG_is_active(depsgraph)) {
Curve *curve_orig = (Curve *)DEG_get_original_id(&curve->id);
- BoundBox *bb = curve->bb;
- if (bb != NULL) {
- if (curve_orig->bb == NULL) {
- curve_orig->bb = MEM_mallocN(sizeof(*curve_orig->bb), __func__);
- }
- *curve_orig->bb = *bb;
+ if (curve->texflag & CU_AUTOSPACE_EVALUATED) {
+ curve_orig->texflag |= CU_AUTOSPACE_EVALUATED;
copy_v3_v3(curve_orig->loc, curve->loc);
copy_v3_v3(curve_orig->size, curve->size);
- copy_v3_v3(curve_orig->rot, curve->rot);
}
}
}
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index cbd3c91acc7..46f6a604eaa 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -624,7 +624,7 @@ void BKE_displist_fill(ListBase *dispbase,
static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase)
{
- const float z_up[3] = {0.0f, 0.0f, 1.0f};
+ const float z_up[3] = {0.0f, 0.0f, -1.0f};
ListBase front, back;
DispList *dl, *dlnew;
float *fp, *fp1;
@@ -703,7 +703,7 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis
bevels_to_filledpoly(cu, dispbase);
}
else {
- const float z_up[3] = {0.0f, 0.0f, 1.0f};
+ const float z_up[3] = {0.0f, 0.0f, -1.0f};
BKE_displist_fill(dispbase, dispbase, z_up, false);
}
}
@@ -1730,11 +1730,11 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
if (cu->bevobj && (cu->flag & CU_FILL_CAPS) && !(nu->flagu & CU_NURB_CYCLIC)) {
if (a == 1) {
fillBevelCap(nu, dlb, cur_data - 3 * dlb->nr, &bottom_capbase);
- negate_v3_v3(bottom_no, bevp->dir);
+ copy_v3_v3(bottom_no, bevp->dir);
}
if (a == steps - 1) {
fillBevelCap(nu, dlb, cur_data, &top_capbase);
- copy_v3_v3(top_no, bevp->dir);
+ negate_v3_v3(top_no, bevp->dir);
}
}
}
diff --git a/source/blender/blenkernel/intern/editlattice.c b/source/blender/blenkernel/intern/editlattice.c
index 12e737bbaa8..2d71b847b5b 100644
--- a/source/blender/blenkernel/intern/editlattice.c
+++ b/source/blender/blenkernel/intern/editlattice.c
@@ -92,6 +92,21 @@ void BKE_editlattice_load(Object *obedit)
lt = obedit->data;
editlt = lt->editlatt->latt;
+ MEM_freeN(lt->def);
+
+ lt->def = MEM_dupallocN(editlt->def);
+
+ lt->flag = editlt->flag;
+
+ lt->pntsu = editlt->pntsu;
+ lt->pntsv = editlt->pntsv;
+ lt->pntsw = editlt->pntsw;
+
+ lt->typeu = editlt->typeu;
+ lt->typev = editlt->typev;
+ lt->typew = editlt->typew;
+ lt->actbp = editlt->actbp;
+
if (lt->editlatt->shapenr) {
actkey = BLI_findlink(&lt->key->block, lt->editlatt->shapenr - 1);
@@ -112,22 +127,6 @@ void BKE_editlattice_load(Object *obedit)
bp++;
}
}
- else {
- MEM_freeN(lt->def);
-
- lt->def = MEM_dupallocN(editlt->def);
-
- lt->flag = editlt->flag;
-
- lt->pntsu = editlt->pntsu;
- lt->pntsv = editlt->pntsv;
- lt->pntsw = editlt->pntsw;
-
- lt->typeu = editlt->typeu;
- lt->typev = editlt->typev;
- lt->typew = editlt->typew;
- lt->actbp = editlt->actbp;
- }
if (lt->dvert) {
BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 866c494d354..d929c953b89 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -32,6 +32,8 @@
#include "BKE_editmesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
{
@@ -51,6 +53,7 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
*em_copy = *em;
em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
+ em_copy->bb_cage = NULL;
em_copy->derivedVertColor = NULL;
em_copy->derivedVertColorLen = 0;
@@ -151,6 +154,8 @@ void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
BKE_id_free(NULL, em->mesh_eval_final);
}
em->mesh_eval_cage = em->mesh_eval_final = NULL;
+
+ MEM_SAFE_FREE(em->bb_cage);
}
/*does not free the BMEditMesh struct itself*/
@@ -257,3 +262,19 @@ void BKE_editmesh_ensure_autosmooth(BMEditMesh *em)
BKE_editmesh_lnorspace_update(em);
}
}
+
+BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em)
+{
+ if (em->bb_cage == NULL) {
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ if (em->mesh_eval_cage) {
+ BKE_mesh_minmax(em->mesh_eval_cage, min, max);
+ }
+
+ em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
+ BKE_boundbox_init_from_minmax(em->bb_cage, min, max);
+ }
+
+ return em->bb_cage;
+}
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 48c0258bf47..10499ae0b5c 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -821,7 +821,7 @@ static void fcm_noise_evaluate(
FMod_Noise *data = (FMod_Noise *)fcm->data;
float noise;
- /* generate noise using good ol' Blender Noise
+ /* generate noise using good old Blender Noise
* - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1
* with evaltime being an integer (which happens when evaluating on frame by frame basis)
*/
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index b55635560be..250e6ff6a7b 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -397,6 +397,9 @@ static void build_underline(Curve *cu,
copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f);
copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f);
+ /* Used by curve extrusion. */
+ bp[0].radius = bp[1].radius = bp[2].radius = bp[3].radius = 1.0f;
+
nu2->bp = bp;
BLI_addtail(nubase, nu2);
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index bcac531a72b..9e1d6b6c428 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -427,9 +427,9 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
/* grid settings */
- ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); /* Color */
- ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */
- gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */
+ ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); /* Color */
+ ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */
+ gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */
/* onion-skinning settings (datablock level) */
gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
@@ -664,7 +664,7 @@ bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
}
/* make a copy of a given gpencil datablock */
-/* XXX: Should this be deprecated? */
+/* XXX: Should this be deprecated? */
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
bGPdata *gpd_dst;
@@ -1422,6 +1422,7 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
bGPdata *gpd = ob->data;
MDeformVert *dvert = NULL;
const int def_nr = BLI_findindex(&ob->defbase, defgroup);
+ const int totgrp = BLI_listbase_count(&ob->defbase);
/* Remove points data */
if (gpd) {
@@ -1436,9 +1437,9 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
defvert_remove_group(dvert, dw);
}
else {
- /* reorganize weights in other strokes */
- for (int g = 0; g < gps->dvert->totweight; g++) {
- dw = &dvert->dw[g];
+ /* Reorganize weights for other groups after deleted one. */
+ for (int g = 0; g < totgrp; g++) {
+ dw = defvert_find_index(dvert, g);
if ((dw != NULL) && (dw->def_nr > def_nr)) {
dw->def_nr--;
}
@@ -2020,7 +2021,10 @@ bool BKE_gpencil_shrink_stroke(bGPDstroke *gps, const float dist)
bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf)
{
bGPDspoint *pt = &gps->points[i];
+<<<<<<< HEAD
/* float pressure = 0.0f; */
+=======
+>>>>>>> origin/master
float sco[3] = {0.0f};
/* Do nothing if not enough points to smooth out */
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 1750a389788..fe087256d25 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -340,6 +340,23 @@ bool BKE_gpencil_has_time_modifiers(Object *ob)
return false;
}
+/* Check if exist transform stroke modifiers (to rotate sculpt or edit). */
+bool BKE_gpencil_has_transform_modifiers(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ /* Only if enabled in edit mode. */
+ if (!GPENCIL_MODIFIER_EDIT(md, true) && GPENCIL_MODIFIER_ACTIVE(md, false)) {
+ if ((md->type == eGpencilModifierType_Armature) || (md->type == eGpencilModifierType_Hook) ||
+ (md->type == eGpencilModifierType_Lattice) ||
+ (md->type == eGpencilModifierType_Offset)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
/* apply stroke modifiers */
void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph,
Object *ob,
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 170cc230332..332549c6b47 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -569,7 +569,7 @@ Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exist
char str[FILE_MAX], strtest[FILE_MAX];
STRNCPY(str, filepath);
- BLI_path_abs(str, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(str, bmain->name);
/* first search an identical filepath */
for (ima = bmain->images.first; ima; ima = ima->id.next) {
@@ -1861,13 +1861,13 @@ static void stampdata(
}
}
-/* Will always add prefix. */
static void stampdata_from_template(StampData *stamp_data,
const Scene *scene,
- const StampData *stamp_data_template)
+ const StampData *stamp_data_template,
+ bool do_prefix)
{
if (scene->r.stamp & R_STAMP_FILENAME) {
- SNPRINTF(stamp_data->file, "File %s", stamp_data_template->file);
+ SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", stamp_data_template->file);
}
else {
stamp_data->file[0] = '\0';
@@ -1879,67 +1879,71 @@ static void stampdata_from_template(StampData *stamp_data,
stamp_data->note[0] = '\0';
}
if (scene->r.stamp & R_STAMP_DATE) {
- SNPRINTF(stamp_data->date, "Date %s", stamp_data_template->date);
+ SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", stamp_data_template->date);
}
else {
stamp_data->date[0] = '\0';
}
if (scene->r.stamp & R_STAMP_MARKER) {
- SNPRINTF(stamp_data->marker, "Marker %s", stamp_data_template->marker);
+ SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", stamp_data_template->marker);
}
else {
stamp_data->marker[0] = '\0';
}
if (scene->r.stamp & R_STAMP_TIME) {
- SNPRINTF(stamp_data->time, "Timecode %s", stamp_data_template->time);
+ SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", stamp_data_template->time);
}
else {
stamp_data->time[0] = '\0';
}
if (scene->r.stamp & R_STAMP_FRAME) {
- SNPRINTF(stamp_data->frame, "Frame %s", stamp_data_template->frame);
+ SNPRINTF(stamp_data->frame, do_prefix ? "Frame %s" : "%s", stamp_data_template->frame);
}
else {
stamp_data->frame[0] = '\0';
}
if (scene->r.stamp & R_STAMP_CAMERA) {
- SNPRINTF(stamp_data->camera, "Camera %s", stamp_data_template->camera);
+ SNPRINTF(stamp_data->camera, do_prefix ? "Camera %s" : "%s", stamp_data_template->camera);
}
else {
stamp_data->camera[0] = '\0';
}
if (scene->r.stamp & R_STAMP_CAMERALENS) {
- SNPRINTF(stamp_data->cameralens, "Lens %s", stamp_data_template->cameralens);
+ SNPRINTF(
+ stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", stamp_data_template->cameralens);
}
else {
stamp_data->cameralens[0] = '\0';
}
if (scene->r.stamp & R_STAMP_SCENE) {
- SNPRINTF(stamp_data->scene, "Scene %s", stamp_data_template->scene);
+ SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", stamp_data_template->scene);
}
else {
stamp_data->scene[0] = '\0';
}
if (scene->r.stamp & R_STAMP_SEQSTRIP) {
- SNPRINTF(stamp_data->strip, "Strip %s", stamp_data_template->strip);
+ SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", stamp_data_template->strip);
}
else {
stamp_data->strip[0] = '\0';
}
if (scene->r.stamp & R_STAMP_RENDERTIME) {
- SNPRINTF(stamp_data->rendertime, "RenderTime %s", stamp_data_template->rendertime);
+ SNPRINTF(stamp_data->rendertime,
+ do_prefix ? "RenderTime %s" : "%s",
+ stamp_data_template->rendertime);
}
else {
stamp_data->rendertime[0] = '\0';
}
if (scene->r.stamp & R_STAMP_MEMORY) {
- SNPRINTF(stamp_data->memory, "Peak Memory %s", stamp_data_template->memory);
+ SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %s" : "%s", stamp_data_template->memory);
}
else {
stamp_data->memory[0] = '\0';
}
if (scene->r.stamp & R_STAMP_HOSTNAME) {
- SNPRINTF(stamp_data->hostname, "Hostname %s", stamp_data_template->hostname);
+ SNPRINTF(
+ stamp_data->hostname, do_prefix ? "Hostname %s" : "%s", stamp_data_template->hostname);
}
else {
stamp_data->hostname[0] = '\0';
@@ -1991,11 +1995,12 @@ void BKE_image_stamp_buf(Scene *scene,
display_device = scene->display_settings.display_device;
display = IMB_colormanagement_display_get_named(display_device);
+ bool do_prefix = (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0;
if (stamp_data_template == NULL) {
- stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true);
+ stampdata(scene, camera, &stamp_data, do_prefix, true);
}
else {
- stampdata_from_template(&stamp_data, scene, stamp_data_template);
+ stampdata_from_template(&stamp_data, scene, stamp_data_template, do_prefix);
}
/* TODO, do_versions */
@@ -5305,7 +5310,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
char str[FILE_MAX];
STRNCPY(str, iv->filepath);
- BLI_path_abs(str, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(str, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
/* exists? */
file = BLI_open(str, O_BINARY | O_RDONLY, 0);
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index f3c0d5da6ee..f12999b033d 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -32,6 +32,7 @@
#include "BKE_freestyle.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_object.h"
@@ -43,6 +44,7 @@
#include "DNA_object_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
@@ -55,9 +57,10 @@
#include "MEM_guardedalloc.h"
/* Set of flags which are dependent on a collection settings. */
-static const short g_base_collection_flags = (BASE_VISIBLE | BASE_SELECTABLE |
- BASE_ENABLED_VIEWPORT | BASE_ENABLED_RENDER |
- BASE_HOLDOUT | BASE_INDIRECT_ONLY);
+static const short g_base_collection_flags = (BASE_VISIBLE_DEPSGRAPH | BASE_VISIBLE_VIEWLAYER |
+ BASE_SELECTABLE | BASE_ENABLED_VIEWPORT |
+ BASE_ENABLED_RENDER | BASE_HOLDOUT |
+ BASE_INDIRECT_ONLY);
/* prototype */
static void object_bases_iterator_next(BLI_Iterator *iter, const int flag);
@@ -91,6 +94,7 @@ static Base *object_base_new(Object *ob)
{
Base *base = MEM_callocN(sizeof(Base), "Object Base");
base->object = ob;
+ base->local_view_bits = ~(0);
if (ob->base_flag & BASE_SELECTED) {
base->flag |= BASE_SELECTED;
}
@@ -652,7 +656,8 @@ static short layer_collection_sync(ViewLayer *view_layer,
ListBase *new_object_bases,
short parent_exclude,
short parent_restrict,
- short parent_layer_restrict)
+ short parent_layer_restrict,
+ unsigned short parent_local_collections_bits)
{
/* TODO: support recovery after removal of intermediate collections, reordering, ..
* For local edits we can make editing operating do the appropriate thing, but for
@@ -698,6 +703,13 @@ static short layer_collection_sync(ViewLayer *view_layer,
lc->flag = parent_exclude;
}
+ unsigned short local_collections_bits = parent_local_collections_bits &
+ lc->local_collections_bits;
+
+ /* Tag linked collection as a weak reference so we keep the layer
+ * collection pointer on file load and remember exclude state. */
+ id_lib_indirect_weak_link(&collection->id);
+
/* Collection restrict is inherited. */
short child_restrict = parent_restrict;
short child_layer_restrict = parent_layer_restrict;
@@ -713,7 +725,8 @@ static short layer_collection_sync(ViewLayer *view_layer,
new_object_bases,
lc->flag,
child_restrict,
- child_layer_restrict);
+ child_layer_restrict,
+ local_collections_bits);
/* Layer collection exclude is not inherited. */
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
@@ -724,9 +737,15 @@ static short layer_collection_sync(ViewLayer *view_layer,
lc->runtime_flag = child_runtime_flag;
}
- if (((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) &&
+ /* We separate restrict viewport and visible view layer because a layer collection can be
+ * hidden in the view layer yet (locally) visible in a viewport (if it is not restricted).*/
+ if (child_restrict & COLLECTION_RESTRICT_VIEWPORT) {
+ lc->runtime_flag |= LAYER_COLLECTION_RESTRICT_VIEWPORT;
+ }
+
+ if (((lc->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) == 0) &&
((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0)) {
- lc->runtime_flag |= LAYER_COLLECTION_VISIBLE;
+ lc->runtime_flag |= LAYER_COLLECTION_VISIBLE_VIEW_LAYER;
}
/* Sync objects, except if collection was excluded. */
@@ -735,6 +754,10 @@ static short layer_collection_sync(ViewLayer *view_layer,
continue;
}
+ /* Tag linked object as a weak reference so we keep the object
+ * base pointer on file load and remember hidden state. */
+ id_lib_indirect_weak_link(&cob->ob->id);
+
void **base_p;
Base *base;
if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) {
@@ -750,17 +773,18 @@ static short layer_collection_sync(ViewLayer *view_layer,
else {
/* Create new base. */
base = object_base_new(cob->ob);
+ base->local_collections_bits = local_collections_bits;
*base_p = base;
BLI_addtail(new_object_bases, base);
}
if ((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) {
- base->flag_from_collection |= BASE_ENABLED_VIEWPORT;
+ base->flag_from_collection |= (BASE_ENABLED_VIEWPORT | BASE_VISIBLE_DEPSGRAPH);
if ((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0) {
- base->flag_from_collection |= BASE_VISIBLE;
- if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) {
- base->flag_from_collection |= BASE_SELECTABLE;
- }
+ base->flag_from_collection |= BASE_VISIBLE_VIEWLAYER;
+ }
+ if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) {
+ base->flag_from_collection |= BASE_SELECTABLE;
}
}
@@ -827,7 +851,8 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
&new_object_bases,
parent_exclude,
parent_restrict,
- parent_layer_restrict);
+ parent_layer_restrict,
+ ~(0));
/* Any remaining object bases are to be removed. */
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
@@ -957,7 +982,7 @@ bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerColle
for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
- if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE)) {
+ if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
return true;
}
}
@@ -1009,6 +1034,60 @@ void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool
BKE_layer_collection_sync(scene, view_layer);
}
+bool BKE_base_is_visible(const View3D *v3d, const Base *base)
+{
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
+ return false;
+ }
+
+ if (v3d == NULL) {
+ return base->flag & BASE_VISIBLE_VIEWLAYER;
+ }
+
+ if ((v3d->localvd) && ((v3d->local_view_uuid & base->local_view_bits) == 0)) {
+ return false;
+ }
+
+ if (((1 << (base->object->type)) & v3d->object_type_exclude_viewport) != 0) {
+ return false;
+ }
+
+ if (v3d->flag & V3D_LOCAL_COLLECTIONS) {
+ return (v3d->local_collections_uuid & base->local_collections_bits) != 0;
+ }
+
+ return base->flag & BASE_VISIBLE_VIEWLAYER;
+}
+
+bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Object *ob)
+{
+ BLI_assert(v3d != NULL);
+
+ if (ob->restrictflag & OB_RESTRICT_VIEWPORT) {
+ return false;
+ }
+
+ if ((v3d->object_type_exclude_viewport & (1 << ob->type)) != 0) {
+ return false;
+ }
+
+ if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ return false;
+ }
+
+ if ((v3d->flag & V3D_LOCAL_COLLECTIONS) &&
+ ((v3d->local_collections_uuid & ob->runtime.local_collections_bits) == 0)) {
+ return false;
+ }
+
+ /* If not using local view or local collection the object may still be in a hidden collection. */
+ if (((v3d->localvd) == NULL) && ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0)) {
+ return (ob->base_flag & BASE_VISIBLE_VIEWLAYER) != 0;
+ }
+
+ return true;
+}
+
static void layer_collection_flag_set_recursive(LayerCollection *lc, const int flag)
{
lc->flag |= flag;
@@ -1033,13 +1112,13 @@ static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int
* If the collection or any of its parents is disabled, make it enabled.
* Don't change the children disable state though.
*/
-void BKE_layer_collection_isolate(Scene *scene,
- ViewLayer *view_layer,
- LayerCollection *lc,
- bool extend)
+void BKE_layer_collection_isolate_global(Scene *scene,
+ ViewLayer *view_layer,
+ LayerCollection *lc,
+ bool extend)
{
LayerCollection *lc_master = view_layer->layer_collections.first;
- bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE);
+ bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER);
if (!extend) {
/* Hide all collections . */
@@ -1123,7 +1202,9 @@ static void layer_collection_local_sync(ViewLayer *view_layer,
}
LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
- layer_collection_local_sync(view_layer, child, local_collections_uuid, visible);
+ if ((child->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
+ layer_collection_local_sync(view_layer, child, local_collections_uuid, visible);
+ }
}
}
@@ -1144,9 +1225,9 @@ void BKE_layer_collection_local_sync(ViewLayer *view_layer, View3D *v3d)
/**
* Isolate the collection locally
*
- * Same as BKE_layer_collection_local_isolate but for a viewport
+ * Same as BKE_layer_collection_isolate_local but for a viewport
*/
-void BKE_layer_collection_local_isolate(ViewLayer *view_layer,
+void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
View3D *v3d,
LayerCollection *lc,
bool extend)
@@ -1417,12 +1498,12 @@ static void objects_iterator_end(BLI_Iterator *iter)
void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED);
+ objects_iterator_begin(iter, data_in, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED);
}
void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter)
{
- objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED);
+ objects_iterator_next(iter, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED);
}
void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *iter)
@@ -1459,7 +1540,7 @@ void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *iter)
void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED);
+ objects_iterator_begin(iter, data_in, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED);
if (iter->valid) {
if (BKE_object_is_libdata((Object *)iter->current) == false) {
// First object is valid (selectable and not libdata) -> all good.
@@ -1476,7 +1557,7 @@ void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter)
{
// Search while there are objects and the one we have is not editable (editable = not libdata).
do {
- objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED);
+ objects_iterator_next(iter, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED);
} while (iter->valid && BKE_object_is_libdata((Object *)iter->current) != false);
}
@@ -1493,12 +1574,12 @@ void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter)
void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED);
+ objects_iterator_begin(iter, data_in, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED);
}
void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter)
{
- object_bases_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED);
+ object_bases_iterator_next(iter, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED);
}
void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *iter)
@@ -1557,7 +1638,7 @@ void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_
data->object_type = base->object->type;
}
- if (!base_is_in_mode(data, base)) {
+ if (!(base_is_in_mode(data, base) && BKE_base_is_visible(data->v3d, base))) {
BKE_view_layer_bases_in_mode_iterator_next(iter);
}
}
@@ -1570,7 +1651,7 @@ void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter)
if (base == data->base_active) {
/* first step */
base = data->view_layer->object_bases.first;
- if (base == data->base_active) {
+ if ((base == data->base_active) && BKE_base_is_visible(data->v3d, base)) {
base = base->next;
}
}
@@ -1579,7 +1660,8 @@ void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter)
}
while (base) {
- if ((base != data->base_active) && base_is_in_mode(data, base)) {
+ if ((base != data->base_active) && base_is_in_mode(data, base) &&
+ BKE_base_is_visible(data->v3d, base)) {
iter->current = base;
return;
}
@@ -1598,7 +1680,8 @@ void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
/* Evaluation */
/* Applies object's restrict flags on top of flags coming from the collection
- * and stores those in base->flag. BASE_VISIBLE is based on viewport visibility. */
+ * and stores those in base->flag. BASE_VISIBLE_DEPSGRAPH ignores viewport flags visibility
+ * (i.e., restriction and local collection). */
void BKE_base_eval_flags(Base *base)
{
/* Apply collection flags. */
@@ -1621,7 +1704,7 @@ void BKE_base_eval_flags(Base *base)
* can change these again, but for tools we always want the viewport
* visibility to be in sync regardless if depsgraph was evaluated. */
if (!(base->flag & BASE_ENABLED_VIEWPORT) || (base->flag & BASE_HIDDEN)) {
- base->flag &= ~(BASE_VISIBLE | BASE_SELECTABLE);
+ base->flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_VISIBLE_VIEWLAYER | BASE_SELECTABLE);
}
/* Deselect unselectable objects. */
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index bbee49e8150..909db9c7b52 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -165,12 +165,23 @@ void id_lib_extern(ID *id)
BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
if (id->tag & LIB_TAG_INDIRECT) {
id->tag &= ~LIB_TAG_INDIRECT;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
id->tag |= LIB_TAG_EXTERN;
id->lib->parent = NULL;
}
}
}
+void id_lib_indirect_weak_link(ID *id)
+{
+ if (id && ID_IS_LINKED(id)) {
+ BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
+ if (id->tag & LIB_TAG_INDIRECT) {
+ id->flag |= LIB_INDIRECT_WEAK_LINK;
+ }
+ }
+}
+
/**
* Ensure we have a real user
*
@@ -1407,9 +1418,10 @@ void *BKE_id_new_nomain(const short type, const char *name)
return id;
}
-void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag)
+void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int orig_flag)
{
ID *new_id = *r_newid;
+ int flag = orig_flag;
const bool is_private_id_data = (id->flag & LIB_PRIVATE_DATA) != 0;
@@ -1430,7 +1442,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag)
}
/* The id->flag bits to copy over. */
- const int copy_flag_mask = LIB_PRIVATE_DATA;
+ const int copy_idflag_mask = LIB_PRIVATE_DATA;
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
/* r_newid already contains pointer to allocated memory. */
@@ -1454,10 +1466,14 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag)
memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset);
}
- new_id->flag = (new_id->flag & ~copy_flag_mask) | (id->flag & copy_flag_mask);
+ new_id->flag = (new_id->flag & ~copy_idflag_mask) | (id->flag & copy_idflag_mask);
+
+ /* We do not want any handling of usercount in code duplicating the data here, we do that all
+ * at once in id_copy_libmanagement_cb() at the end. */
+ const int copy_data_flag = orig_flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
if (id->properties) {
- new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
+ new_id->properties = IDP_CopyProperty_ex(id->properties, copy_data_flag);
}
/* XXX Again... We need a way to control what we copy in a much more refined way.
@@ -1474,9 +1490,11 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag)
/* the duplicate should get a copy of the animdata */
if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) {
- BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0 ||
- is_private_id_data);
- iat->adt = BKE_animdata_copy(bmain, iat->adt, flag);
+ /* Note that even though horrors like root nodetrees are not in bmain, the actions they use
+ * in their anim data *are* in bmain... super-mega-hooray. */
+ BLI_assert((copy_data_flag & LIB_ID_COPY_ACTIONS) == 0 ||
+ (copy_data_flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ iat->adt = BKE_animdata_copy(bmain, iat->adt, copy_data_flag);
}
else {
iat->adt = NULL;
@@ -1764,6 +1782,7 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, const bool id_in_mainlist)
id->lib = NULL;
id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
if (id_in_mainlist) {
if (BKE_id_new_name_validate(which_libbase(bmain, GS(id->name)), id, NULL)) {
bmain->is_memfile_undo_written = false;
@@ -1977,6 +1996,7 @@ void BKE_library_make_local(Main *bmain,
if (id->lib == NULL) {
id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
}
/* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so it's possible to tag data
* you don't want to be made local, used for appending data,
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 61f506a8a6c..45dbb4b6ec1 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -389,7 +389,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
if (ob->data == new_id) {
switch (GS(new_id->name)) {
case ID_ME:
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
break;
case ID_CU:
BKE_curve_type_test(ob);
@@ -497,6 +497,7 @@ static void libblock_remap_data(
if (new_id && (new_id->tag & LIB_TAG_INDIRECT) &&
(r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
new_id->tag &= ~LIB_TAG_INDIRECT;
+ new_id->flag &= ~LIB_INDIRECT_WEAK_LINK;
new_id->tag |= LIB_TAG_EXTERN;
}
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index e03903c05e4..e6cfea6fb03 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -589,7 +589,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
(do_aspect_correct && width > height) ? (float)height / (float)width : 1.0f,
(do_aspect_correct && width < height) ? (float)width / (float)height : 1.0f};
- const float zvec[3] = {0.0f, 0.0f, 1.0f};
+ const float zvec[3] = {0.0f, 0.0f, -1.0f};
MaskLayer *masklay;
unsigned int masklay_index;
MemArena *sf_arena;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index ae9c3400ace..ba139c654d3 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -496,7 +496,6 @@ void BKE_mesh_clear_geometry(Mesh *mesh)
CustomData_free(&mesh->ldata, mesh->totloop);
CustomData_free(&mesh->pdata, mesh->totpoly);
- MEM_SAFE_FREE(mesh->bb);
MEM_SAFE_FREE(mesh->mselect);
MEM_SAFE_FREE(mesh->edit_mesh);
@@ -605,7 +604,6 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int
me_dst->edit_mesh = NULL;
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
- me_dst->bb = MEM_dupallocN(me_dst->bb);
/* TODO Do we want to add flag to prevent this? */
if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
@@ -659,6 +657,31 @@ Mesh *BKE_mesh_new_nomain(
return mesh;
}
+/* Copy user editable settings that we want to preserve through the modifier stack
+ * or operations where a mesh with new topology is created based on another mesh. */
+void BKE_mesh_copy_settings(Mesh *me_dst, const Mesh *me_src)
+{
+ /* Copy general settings. */
+ me_dst->editflag = me_src->editflag;
+ me_dst->flag = me_src->flag;
+ me_dst->smoothresh = me_src->smoothresh;
+ me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
+ me_dst->remesh_voxel_adaptivity = me_src->remesh_voxel_adaptivity;
+ me_dst->remesh_mode = me_src->remesh_mode;
+
+ /* Copy texture space. */
+ me_dst->texflag = me_src->texflag;
+ copy_v3_v3(me_dst->loc, me_src->loc);
+ copy_v3_v3(me_dst->size, me_src->size);
+
+ /* Copy materials. */
+ if (me_dst->mat != NULL) {
+ MEM_freeN(me_dst->mat);
+ }
+ me_dst->mat = MEM_dupallocN(me_src->mat);
+ me_dst->totcol = me_src->totcol;
+}
+
Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
int verts_len,
int edges_len,
@@ -672,7 +695,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
- me_dst->mat = MEM_dupallocN(me_src->mat);
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
me_dst->totvert = verts_len;
@@ -682,8 +704,7 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
me_dst->totpoly = polys_len;
me_dst->cd_flag = me_src->cd_flag;
- me_dst->editflag = me_src->editflag;
- me_dst->texflag = me_src->texflag;
+ BKE_mesh_copy_settings(me_dst, me_src);
CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len);
CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len);
@@ -772,18 +793,24 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
});
}
-Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params)
+Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
+ const struct BMeshToMeshParams *params,
+ const Mesh *me_settings)
{
BLI_assert(params->calc_object_remap == false);
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me(NULL, bm, mesh, params);
+ BKE_mesh_copy_settings(mesh, me_settings);
return mesh;
}
-Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra)
+Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
+ const CustomData_MeshMasks *cd_mask_extra,
+ const Mesh *me_settings)
{
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
+ BKE_mesh_copy_settings(mesh, me_settings);
return mesh;
}
@@ -792,9 +819,10 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks
*/
Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em,
const CustomData_MeshMasks *data_mask,
- float (*vertexCos)[3])
+ float (*vertexCos)[3],
+ const Mesh *me_settings)
{
- Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask);
+ Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask, me_settings);
/* Use editmesh directly where possible. */
me->runtime.is_original = true;
if (vertexCos) {
@@ -811,50 +839,49 @@ void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
BKE_id_make_local_generic(bmain, &me->id, true, lib_local);
}
-void BKE_mesh_boundbox_calc(Mesh *me, float r_loc[3], float r_size[3])
+BoundBox *BKE_mesh_boundbox_get(Object *ob)
{
- BoundBox *bb;
- float min[3], max[3];
- float mloc[3], msize[3];
-
- if (me->bb == NULL) {
- me->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- }
- bb = me->bb;
+ /* This is Object-level data access,
+ * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
+ if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
+ Mesh *me = ob->data;
+ float min[3], max[3];
- if (!r_loc) {
- r_loc = mloc;
- }
- if (!r_size) {
- r_size = msize;
- }
+ INIT_MINMAX(min, max);
+ if (!BKE_mesh_minmax(me, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
+ }
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
- mid_v3_v3v3(r_loc, min, max);
-
- r_size[0] = (max[0] - min[0]) / 2.0f;
- r_size[1] = (max[1] - min[1]) / 2.0f;
- r_size[2] = (max[2] - min[2]) / 2.0f;
-
- BKE_boundbox_init_from_minmax(bb, min, max);
-
- bb->flag &= ~BOUNDBOX_DIRTY;
+ return ob->runtime.bb;
}
void BKE_mesh_texspace_calc(Mesh *me)
{
- float loc[3], size[3];
- int a;
+ if (me->texflag & ME_AUTOSPACE) {
+ float min[3], max[3];
- BKE_mesh_boundbox_calc(me, loc, size);
+ INIT_MINMAX(min, max);
+ if (!BKE_mesh_minmax(me, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- if (me->texflag & ME_AUTOSPACE) {
- for (a = 0; a < 3; a++) {
+ float loc[3], size[3];
+ mid_v3_v3v3(loc, min, max);
+
+ size[0] = (max[0] - min[0]) / 2.0f;
+ size[1] = (max[1] - min[1]) / 2.0f;
+ size[2] = (max[2] - min[2]) / 2.0f;
+
+ for (int a = 0; a < 3; a++) {
if (size[a] == 0.0f) {
size[a] = 1.0f;
}
@@ -868,59 +895,33 @@ void BKE_mesh_texspace_calc(Mesh *me)
copy_v3_v3(me->loc, loc);
copy_v3_v3(me->size, size);
- zero_v3(me->rot);
+
+ me->texflag |= ME_AUTOSPACE_EVALUATED;
}
}
-BoundBox *BKE_mesh_boundbox_get(Object *ob)
+void BKE_mesh_texspace_ensure(Mesh *me)
{
- /* This is Object-level data access,
- * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
- if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
- Mesh *me = ob->data;
- float min[3], max[3];
-
- INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
-
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
- }
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+ if ((me->texflag & ME_AUTOSPACE) && !(me->texflag & ME_AUTOSPACE_EVALUATED)) {
+ BKE_mesh_texspace_calc(me);
}
-
- return ob->runtime.bb;
}
-BoundBox *BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_size[3])
+void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_size[3])
{
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
if (r_loc) {
copy_v3_v3(r_loc, me->loc);
}
- if (r_rot) {
- copy_v3_v3(r_rot, me->rot);
- }
if (r_size) {
copy_v3_v3(r_size, me->size);
}
-
- return me->bb;
}
-void BKE_mesh_texspace_get_reference(
- Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size)
+void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size)
{
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
if (r_texflag != NULL) {
*r_texflag = &me->texflag;
@@ -928,9 +929,6 @@ void BKE_mesh_texspace_get_reference(
if (r_loc != NULL) {
*r_loc = me->loc;
}
- if (r_rot != NULL) {
- *r_rot = me->rot;
- }
if (r_size != NULL) {
*r_size = me->size;
}
@@ -938,14 +936,13 @@ void BKE_mesh_texspace_get_reference(
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
{
- float *texloc, *texrot, *texsize;
+ float *texloc, *texsize;
short *texflag;
- if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize, &texrot)) {
+ if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) {
me->texflag = *texflag;
copy_v3_v3(me->loc, texloc);
copy_v3_v3(me->size, texsize);
- copy_v3_v3(me->rot, texrot);
}
}
@@ -974,7 +971,7 @@ void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int
float loc[3], size[3];
int a;
- BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size);
+ BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size);
if (invert) {
for (a = 0; a < totvert; a++) {
@@ -1080,12 +1077,12 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
{
Mesh *old = NULL;
- multires_force_update(ob);
-
if (ob == NULL) {
return;
}
+ multires_force_sculpt_rebuild(ob);
+
if (ob->type == OB_MESH) {
old = ob->data;
if (old) {
@@ -1949,9 +1946,6 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
{
DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
BKE_mesh_texspace_calc(mesh);
- /* Clear autospace flag in evaluated mesh, so that texspace does not get recomputed when bbox is
- * (e.g. after modifiers, etc.) */
- mesh->texflag &= ~ME_AUTOSPACE;
/* We are here because something did change in the mesh. This means we can not trust the existing
* evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
* evaluated mesh and let objects to re-create it with updated settings. */
@@ -1962,15 +1956,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
}
if (DEG_is_active(depsgraph)) {
Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id);
- BoundBox *bb = mesh->bb;
- if (bb != NULL) {
- if (mesh_orig->bb == NULL) {
- mesh_orig->bb = MEM_mallocN(sizeof(*mesh_orig->bb), __func__);
- }
- *mesh_orig->bb = *bb;
+ if (mesh->texflag & ME_AUTOSPACE_EVALUATED) {
+ mesh_orig->texflag |= ME_AUTOSPACE_EVALUATED;
copy_v3_v3(mesh_orig->loc, mesh->loc);
copy_v3_v3(mesh_orig->size, mesh->size);
- copy_v3_v3(mesh_orig->rot, mesh->rot);
}
}
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 0a991ee36c8..2ade368284c 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -556,7 +556,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));
if (alluv) {
- const char *uvname = "Orco";
+ const char *uvname = "UVMap";
CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
}
@@ -635,7 +635,7 @@ void BKE_mesh_from_nurbs_displist(Main *bmain,
me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
if (alluv) {
- const char *uvname = "Orco";
+ const char *uvname = "UVMap";
me->mloopuv = CustomData_add_layer_named(
&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
}
@@ -667,7 +667,6 @@ void BKE_mesh_from_nurbs_displist(Main *bmain,
me->texflag = cu->texflag & ~CU_AUTOSPACE;
copy_v3_v3(me->loc, cu->loc);
copy_v3_v3(me->size, cu->size);
- copy_v3_v3(me->rot, cu->rot);
BKE_mesh_texspace_calc(me);
cu->mat = NULL;
@@ -1080,6 +1079,7 @@ static Mesh *mesh_new_from_mball_object(Object *object)
Mesh *mesh_result = BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result);
+ BKE_mesh_texspace_copy_from_object(mesh_result, object);
/* Copy materials. */
mesh_result->totcol = mball->totcol;
@@ -1575,11 +1575,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* Clear selection history */
MEM_SAFE_FREE(tmp.mselect);
tmp.totselect = 0;
- BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb));
- if (mesh_dst->bb) {
- MEM_freeN(mesh_dst->bb);
- tmp.bb = NULL;
- }
+ tmp.texflag &= ~ME_AUTOSPACE_EVALUATED;
/* skip the listbase */
MEMCPY_STRUCT_AFTER(mesh_dst, &tmp, id.prev);
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
index ff7ff947e1d..ba8ed5facad 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
@@ -38,6 +38,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_library.h"
@@ -45,6 +46,8 @@
#include "BKE_bvhutils.h"
#include "BKE_mesh_remesh_voxel.h" /* own include */
+#include "bmesh_tools.h"
+
#ifdef WITH_OPENVDB
# include "openvdb_capi.h"
#endif
@@ -292,7 +295,10 @@ Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(Mesh *mesh,
return new_mesh;
}
-Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size)
+Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh,
+ float voxel_size,
+ float adaptivity,
+ float isovalue)
{
Mesh *new_mesh = NULL;
#ifdef WITH_OPENVDB
@@ -300,11 +306,12 @@ Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size)
struct OpenVDBTransform *xform = OpenVDBTransform_create();
OpenVDBTransform_create_linear_transform(xform, (double)voxel_size);
level_set = BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(mesh, xform);
- new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(level_set, 0.0, 0.0, false);
+ new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(
+ level_set, (double)isovalue, (double)adaptivity, false);
OpenVDBLevelSet_free(level_set);
OpenVDBTransform_free(xform);
#else
- UNUSED_VARS(mesh, voxel_size);
+ UNUSED_VARS(mesh, voxel_size, adaptivity, isovalue);
#endif
return new_mesh;
}
@@ -348,3 +355,112 @@ void BKE_remesh_reproject_paint_mask(Mesh *target, Mesh *source)
}
free_bvhtree_from_mesh(&bvhtree);
}
+
+struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh)
+{
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ BMesh *bm;
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BMVert *v;
+ BMEdge *ed, *ed_next;
+ BMFace *f, *f_next;
+ BMIter iter_a, iter_b;
+
+ /* Merge 3 edge poles vertices that exist in the same face */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH_MUTABLE (f, f_next, &iter_a, bm, BM_FACES_OF_MESH) {
+ BMVert *v1, *v2;
+ v1 = NULL;
+ v2 = NULL;
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (BM_vert_edge_count(v) == 3) {
+ if (v1) {
+ v2 = v;
+ }
+ else {
+ v1 = v;
+ }
+ }
+ }
+ if (v1 && v2 && (v1 != v2) && !BM_edge_exists(v1, v2)) {
+ BM_face_kill(bm, f);
+ BMEdge *e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NOP);
+ BM_elem_flag_set(e, BM_ELEM_TAG, true);
+ }
+ }
+
+ BM_ITER_MESH_MUTABLE (ed, ed_next, &iter_a, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(ed, BM_ELEM_TAG)) {
+ float co[3];
+ mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
+ BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true);
+ copy_v3_v3(vc->co, co);
+ }
+ }
+
+ /* Delete faces with a 3 edge pole in all their vertices */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) {
+ bool dissolve = true;
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (BM_vert_edge_count(v) != 3) {
+ dissolve = false;
+ }
+ }
+ if (dissolve) {
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, true);
+ }
+ }
+ }
+ BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS);
+
+ BM_ITER_MESH (ed, &iter_a, bm, BM_EDGES_OF_MESH) {
+ if (BM_edge_face_count(ed) != 2) {
+ BM_elem_flag_set(ed, BM_ELEM_TAG, true);
+ }
+ }
+ BM_mesh_edgenet(bm, false, true);
+
+ /* Smooth the result */
+ for (int i = 0; i < 4; i++) {
+ BM_ITER_MESH (v, &iter_a, bm, BM_VERTS_OF_MESH) {
+ float co[3];
+ zero_v3(co);
+ BM_ITER_ELEM (ed, &iter_b, v, BM_EDGES_OF_VERT) {
+ BMVert *vert = BM_edge_other_vert(ed, v);
+ add_v3_v3(co, vert->co);
+ }
+ mul_v3_fl(co, 1.0f / (float)BM_vert_edge_count(v));
+ mid_v3_v3v3(v->co, v->co, co);
+ }
+ }
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false);
+ BMO_op_callf(bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "recalc_face_normals faces=%hf",
+ BM_ELEM_TAG);
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ Mesh *result = BKE_mesh_from_bmesh_nomain(bm,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = false,
+ }),
+ mesh);
+
+ BKE_id_free(NULL, mesh);
+ BM_mesh_free(bm);
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index c8e75532075..fa03aec3e08 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -1619,6 +1619,12 @@ void BKE_mesh_calc_edges_loose(Mesh *mesh)
for (int i = 0; i < mesh->totloop; i++, ml++) {
mesh->medge[ml->e].flag &= ~ME_LOOSEEDGE;
}
+ med = mesh->medge;
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ if (med->flag & ME_LOOSEEDGE) {
+ med->flag |= ME_EDGEDRAW;
+ }
+ }
}
/**
diff --git a/source/blender/blenkernel/intern/mirror.c b/source/blender/blenkernel/intern/mirror.c
new file mode 100644
index 00000000000..02e0a2bb3b9
--- /dev/null
+++ b/source/blender/blenkernel/intern/mirror.c
@@ -0,0 +1,419 @@
+/*
+ * 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) Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_mesh.h"
+#include "BKE_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_deform.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_modifiertypes.h"
+
+Mesh *BKE_mirror_bisect_on_mirror_plane(MirrorModifierData *mmd,
+ const Mesh *mesh,
+ int axis,
+ const float plane_co[3],
+ float plane_no[3])
+{
+ bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) ||
+ (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) ||
+ (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z));
+
+ const float bisect_distance = 0.001f;
+
+ Mesh *result;
+ BMesh *bm;
+ BMIter viter;
+ BMVert *v, *v_next;
+
+ bm = BKE_mesh_to_bmesh_ex(mesh,
+ &(struct BMeshCreateParams){0},
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
+ .emask = CD_MASK_ORIGINDEX,
+ .pmask = CD_MASK_ORIGINDEX},
+ });
+
+ /* Define bisecting plane (aka mirror plane). */
+ float plane[4];
+ if (!do_bisect_flip_axis) {
+ /* That reversed condition is a tad weird, but for some reason that's how you keep
+ * the part of the mesh which is on the non-mirrored side when flip option is disabled,
+ * think that that is the expected behavior. */
+ negate_v3(plane_no);
+ }
+ plane_from_point_normal_v3(plane, plane_co, plane_no);
+
+ BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
+
+ /* Plane definitions for vert killing. */
+ float plane_offset[4];
+ copy_v3_v3(plane_offset, plane);
+ plane_offset[3] = plane[3] - bisect_distance;
+
+ /* Delete verts across the mirror plane. */
+ BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
+ if (plane_point_side_v3(plane_offset, v->co) > 0.0f) {
+ BM_vert_kill(bm, v);
+ }
+ }
+
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
+ BM_mesh_free(bm);
+
+ return result;
+}
+
+Mesh *BKE_mirror_apply_mirror_on_axis(MirrorModifierData *mmd,
+ const ModifierEvalContext *UNUSED(ctx),
+ Object *ob,
+ const Mesh *mesh,
+ int axis)
+{
+ const float tolerance_sq = mmd->tolerance * mmd->tolerance;
+ const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
+ int tot_vtargetmap = 0; /* total merge vertices */
+
+ const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) ||
+ (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) ||
+ (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z));
+
+ Mesh *result;
+ MVert *mv, *mv_prev;
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+ float mtx[4][4];
+ float plane_co[3], plane_no[3];
+ int i;
+ int a, totshape;
+ int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL;
+
+ /* mtx is the mirror transformation */
+ unit_m4(mtx);
+ mtx[axis][axis] = -1.0f;
+
+ Object *mirror_ob = mmd->mirror_ob;
+ if (mirror_ob != NULL) {
+ float tmp[4][4];
+ float itmp[4][4];
+
+ /* tmp is a transform from coords relative to the object's own origin,
+ * to coords relative to the mirror object origin */
+ invert_m4_m4(tmp, mirror_ob->obmat);
+ mul_m4_m4m4(tmp, tmp, ob->obmat);
+
+ /* itmp is the reverse transform back to origin-relative coordinates */
+ invert_m4_m4(itmp, tmp);
+
+ /* combine matrices to get a single matrix that translates coordinates into
+ * mirror-object-relative space, does the mirror, and translates back to
+ * origin-relative space */
+ mul_m4_series(mtx, itmp, mtx, tmp);
+
+ if (do_bisect) {
+ copy_v3_v3(plane_co, itmp[3]);
+ copy_v3_v3(plane_no, itmp[axis]);
+ }
+ }
+ else if (do_bisect) {
+ copy_v3_v3(plane_co, mtx[3]);
+ /* Need to negate here, since that axis is inverted (for mirror transform). */
+ negate_v3_v3(plane_no, mtx[axis]);
+ }
+
+ Mesh *mesh_bisect = NULL;
+ if (do_bisect) {
+ mesh_bisect = BKE_mirror_bisect_on_mirror_plane(mmd, mesh, axis, plane_co, plane_no);
+ mesh = mesh_bisect;
+ }
+
+ const int maxVerts = mesh->totvert;
+ const int maxEdges = mesh->totedge;
+ const int maxLoops = mesh->totloop;
+ const int maxPolys = mesh->totpoly;
+
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
+
+ /* Copy custom-data to original geometry. */
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys);
+
+ /* Subsurf for eg won't have mesh data in the custom-data arrays.
+ * now add mvert/medge/mpoly layers. */
+ if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
+ memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
+ }
+ if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
+ memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
+ }
+ if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
+ memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
+ memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
+ }
+
+ /* Copy custom-data to new geometry,
+ * copy from its self because this data may have been created in the checks above. */
+ CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
+ CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
+ /* loops are copied later */
+ CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys);
+
+ if (do_vtargetmap) {
+ /* second half is filled with -1 */
+ vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap");
+
+ vtmap_a = vtargetmap;
+ vtmap_b = vtargetmap + maxVerts;
+ }
+
+ /* mirror vertex coordinates */
+ mv_prev = result->mvert;
+ mv = mv_prev + maxVerts;
+ for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
+ mul_m4_v3(mtx, mv->co);
+
+ if (do_vtargetmap) {
+ /* compare location of the original and mirrored vertex, to see if they
+ * should be mapped for merging */
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_a = maxVerts + i;
+ tot_vtargetmap++;
+
+ /* average location */
+ mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
+ copy_v3_v3(mv_prev->co, mv->co);
+ }
+ else {
+ *vtmap_a = -1;
+ }
+
+ *vtmap_b = -1; /* fill here to avoid 2x loops */
+
+ vtmap_a++;
+ vtmap_b++;
+ }
+ }
+
+ /* handle shape keys */
+ totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY);
+ for (a = 0; a < totshape; a++) {
+ float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a);
+ for (i = maxVerts; i < result->totvert; i++) {
+ mul_m4_v3(mtx, cos[i]);
+ }
+ }
+
+ /* adjust mirrored edge vertex indices */
+ me = result->medge + maxEdges;
+ for (i = 0; i < maxEdges; i++, me++) {
+ me->v1 += maxVerts;
+ me->v2 += maxVerts;
+ }
+
+ /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
+ mp = result->mpoly + maxPolys;
+ ml = result->mloop;
+ for (i = 0; i < maxPolys; i++, mp++) {
+ MLoop *ml2;
+ int j, e;
+
+ /* reverse the loop, but we keep the first vertex in the face the same,
+ * to ensure that quads are split the same way as on the other side */
+ CustomData_copy_data(
+ &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1);
+
+ for (j = 1; j < mp->totloop; j++) {
+ CustomData_copy_data(&result->ldata,
+ &result->ldata,
+ mp->loopstart + j,
+ mp->loopstart + maxLoops + mp->totloop - j,
+ 1);
+ }
+
+ ml2 = ml + mp->loopstart + maxLoops;
+ e = ml2[0].e;
+ for (j = 0; j < mp->totloop - 1; j++) {
+ ml2[j].e = ml2[j + 1].e;
+ }
+ ml2[mp->totloop - 1].e = e;
+
+ mp->loopstart += maxLoops;
+ }
+
+ /* adjust mirrored loop vertex and edge indices */
+ ml = result->mloop + maxLoops;
+ for (i = 0; i < maxLoops; i++, ml++) {
+ ml->v += maxVerts;
+ ml->e += maxEdges;
+ }
+
+ /* handle uvs,
+ * let tessface recalc handle updating the MTFace data */
+ if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) ||
+ (is_zero_v2(mmd->uv_offset_copy) == false)) {
+ const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
+ const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
+
+ const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
+
+ for (a = 0; a < totuv; a++) {
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a);
+ int j = maxLoops;
+ dmloopuv += j; /* second set of loops only */
+ for (; j-- > 0; dmloopuv++) {
+ if (do_mirr_u) {
+ dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
+ }
+ if (do_mirr_v) {
+ dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
+ }
+ dmloopuv->uv[0] += mmd->uv_offset_copy[0];
+ dmloopuv->uv[1] += mmd->uv_offset_copy[1];
+ }
+ }
+ }
+
+ /* handle custom split normals */
+ if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) &&
+ CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) {
+ const int totloop = result->totloop;
+ const int totpoly = result->totpoly;
+ float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__);
+ CustomData *ldata = &result->ldata;
+ short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
+
+ /* The transform matrix of a normal must be
+ * the transpose of inverse of transform matrix of the geometry... */
+ float mtx_nor[4][4];
+ invert_m4_m4(mtx_nor, mtx);
+ transpose_m4(mtx_nor);
+
+ /* calculate custom normals into loop_normals, then mirror first half into second half */
+
+ BKE_mesh_calc_normals_poly(result->mvert,
+ NULL,
+ result->totvert,
+ result->mloop,
+ result->mpoly,
+ totloop,
+ totpoly,
+ poly_normals,
+ false);
+
+ BKE_mesh_normals_loop_split(result->mvert,
+ result->totvert,
+ result->medge,
+ result->totedge,
+ result->mloop,
+ loop_normals,
+ totloop,
+ result->mpoly,
+ poly_normals,
+ totpoly,
+ true,
+ mesh->smoothresh,
+ &lnors_spacearr,
+ clnors,
+ NULL);
+
+ /* mirroring has to account for loops being reversed in polys in second half */
+ mp = result->mpoly;
+ for (i = 0; i < maxPolys; i++, mp++) {
+ MPoly *mpmirror = result->mpoly + maxPolys + i;
+ int j;
+
+ for (j = mp->loopstart; j < mp->loopstart + mp->totloop; j++) {
+ int mirrorj = mpmirror->loopstart;
+ if (j > mp->loopstart) {
+ mirrorj += mpmirror->totloop - (j - mp->loopstart);
+ }
+ copy_v3_v3(loop_normals[mirrorj], loop_normals[j]);
+ mul_m4_v3(mtx_nor, loop_normals[mirrorj]);
+ BKE_lnor_space_custom_normal_to_data(
+ lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]);
+ }
+ }
+
+ MEM_freeN(poly_normals);
+ MEM_freeN(loop_normals);
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+ }
+
+ /* handle vgroup stuff */
+ if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) {
+ MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) +
+ maxVerts;
+ int *flip_map = NULL, flip_map_len = 0;
+
+ flip_map = defgroup_flip_map(ob, &flip_map_len, false);
+
+ if (flip_map) {
+ for (i = 0; i < maxVerts; dvert++, i++) {
+ /* merged vertices get both groups, others get flipped */
+ if (do_vtargetmap && (vtargetmap[i] != -1)) {
+ defvert_flip_merged(dvert, flip_map, flip_map_len);
+ }
+ else {
+ defvert_flip(dvert, flip_map, flip_map_len);
+ }
+ }
+
+ MEM_freeN(flip_map);
+ }
+ }
+
+ if (do_vtargetmap) {
+ /* slow - so only call if one or more merge verts are found,
+ * users may leave this on and not realize there is nothing to merge - campbell */
+ if (tot_vtargetmap) {
+ result = BKE_mesh_merge_verts(
+ result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED);
+ }
+ MEM_freeN(vtargetmap);
+ }
+
+ if (mesh_bisect != NULL) {
+ BKE_id_free(NULL, mesh_bisect);
+ }
+
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 656ec50f31b..1c83bec17e5 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -761,6 +761,23 @@ Object *modifiers_isDeformedByCurve(Object *ob)
return NULL;
}
+bool modifiers_usesMultires(Object *ob)
+{
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ MultiresModifierData *mmd = NULL;
+
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_Multires) {
+ mmd = (MultiresModifierData *)md;
+ if (mmd->totlvl != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool modifiers_usesArmature(Object *ob, bArmature *arm)
{
VirtualModifierData virtualModifierData;
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index f67bc419210..9385a9ae24d 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -409,8 +409,8 @@ typedef struct MovieClipCache {
/* cache for undistorted shot */
float principal[2];
- float polynomial_k1, polynomial_k2, polynomial_k3;
- float division_k1, division_k2;
+ float polynomial_k1;
+ float division_k1;
short distortion_model;
bool undistortion_used;
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 8cf960a7f14..6a5e31bd2a2 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -406,25 +406,38 @@ void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresMod
multires_ccg_mark_as_modified(subdiv_ccg, flags);
}
-void multires_force_update(Object *ob)
+void multires_flush_sculpt_updates(Object *ob)
{
- if (ob == NULL) {
- return;
- }
- SculptSession *sculpt_session = ob->sculpt;
- if (sculpt_session != NULL && sculpt_session->pbvh != NULL) {
- PBVH *pbvh = sculpt_session->pbvh;
- if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
+ if (ob && ob->sculpt && ob->sculpt->pbvh != NULL) {
+ SculptSession *sculpt_session = ob->sculpt;
+ if (BKE_pbvh_type(sculpt_session->pbvh) == PBVH_GRIDS) {
Mesh *mesh = ob->data;
multiresModifier_reshapeFromCCG(
sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg);
}
- else {
- /* NOTE: Disabled for until OpenSubdiv is enabled by default. */
- // BLI_assert(!"multires_force_update is used on non-grids PBVH");
+ }
+}
+
+void multires_force_sculpt_rebuild(Object *ob)
+{
+ multires_flush_sculpt_updates(ob);
+
+ if (ob && ob->sculpt) {
+ SculptSession *ss = ob->sculpt;
+ if (ss->pbvh) {
+ BKE_pbvh_free(ss->pbvh);
+ ob->sculpt->pbvh = NULL;
+ }
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
+ }
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
}
- BKE_pbvh_free(pbvh);
- ob->sculpt->pbvh = NULL;
}
}
@@ -433,14 +446,7 @@ void multires_force_external_reload(Object *ob)
Mesh *me = BKE_mesh_from_object(ob);
CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- multires_force_update(ob);
-}
-
-void multires_force_render_update(Object *ob)
-{
- if (ob && (ob->mode & OB_MODE_SCULPT) && modifiers_findByType(ob, eModifierType_Multires)) {
- multires_force_update(ob);
- }
+ multires_force_sculpt_rebuild(ob);
}
/* reset the multires levels to match the number of mdisps */
@@ -624,7 +630,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
if (mdisps && levels > 0) {
if (lvl > 0) {
@@ -689,7 +695,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd,
CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
if (mdisps && levels > 0 && direction == 1) {
multires_del_higher(mmd, ob, lvl);
@@ -781,7 +787,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object
float(*origco)[3];
int i, j, k, offset, totlvl;
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
me = BKE_mesh_from_object(ob);
totlvl = mmd->totlvl;
@@ -928,7 +934,7 @@ static void multires_subdivide(
BLI_assert(totlvl > lvl);
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if (!mdisps) {
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index 3257bc1b193..4e4a8831518 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -795,7 +795,7 @@ static Subdiv *multires_create_subdiv_for_reshape(struct Depsgraph *depsgraph,
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, deformed_mesh);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh)) {
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 2cc1083aba3..09581debd99 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -1488,7 +1488,7 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
/* set default flags */
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ fcu->auto_smoothing = U.auto_smoothing_new;
/* store path - make copy, and store that */
fcu->rna_path = BLI_strdupn("influence", 9);
@@ -1515,7 +1515,7 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
/* set default flags */
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ fcu->auto_smoothing = U.auto_smoothing_new;
/* store path - make copy, and store that */
fcu->rna_path = BLI_strdupn("strip_time", 10);
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 6e45130ce44..779728cb037 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -947,6 +947,68 @@ void nodeChainIter(const bNodeTree *ntree,
}
}
+static void iter_backwards_ex(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *),
+ void *userdata,
+ char recursion_mask)
+{
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) {
+ bNodeLink *link = sock->link;
+ if (link == NULL) {
+ continue;
+ }
+ if ((link->flag & NODE_LINK_VALID) == 0) {
+ /* Skip links marked as cyclic. */
+ continue;
+ }
+ if (link->fromnode->iter_flag & recursion_mask) {
+ continue;
+ }
+ else {
+ link->fromnode->iter_flag |= recursion_mask;
+ }
+
+ if (!callback(link->fromnode, link->tonode, userdata)) {
+ return;
+ }
+ iter_backwards_ex(ntree, link->fromnode, callback, userdata, recursion_mask);
+ }
+}
+
+/**
+ * Iterate over a chain of nodes, starting with \a node_start, executing
+ * \a callback for each node (which can return false to end iterator).
+ *
+ * Faster than nodeChainIter. Iter only once per node.
+ * Can be called recursively (using another nodeChainIterBackwards) by
+ * setting the recursion_lvl accordingly.
+ *
+ * \note Needs updated socket links (ntreeUpdateTree).
+ * \note Recursive
+ */
+void nodeChainIterBackwards(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *),
+ void *userdata,
+ int recursion_lvl)
+{
+ if (!node_start) {
+ return;
+ }
+
+ /* Limited by iter_flag type. */
+ BLI_assert(recursion_lvl < 8);
+ char recursion_mask = (1 << recursion_lvl);
+
+ /* Reset flag. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ node->iter_flag &= ~recursion_mask;
+ }
+
+ iter_backwards_ex(ntree, node_start, callback, userdata, recursion_mask);
+}
+
/**
* Iterate over all parents of \a node, executing \a callback for each parent
* (which can return false to end iterator)
@@ -3348,7 +3410,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
return;
}
- /* avoid reentrant updates, can be caused by RNA update callbacks */
+ /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
if (ntree->is_updating) {
return;
}
@@ -3409,7 +3471,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
void nodeUpdate(bNodeTree *ntree, bNode *node)
{
- /* avoid reentrant updates, can be caused by RNA update callbacks */
+ /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
if (ntree->is_updating) {
return;
}
@@ -3436,7 +3498,7 @@ bool nodeUpdateID(bNodeTree *ntree, ID *id)
return changed;
}
- /* avoid reentrant updates, can be caused by RNA update callbacks */
+ /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
if (ntree->is_updating) {
return changed;
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 7b43f281c73..773e2d19b22 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -680,7 +680,7 @@ bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
*/
int BKE_object_visibility(const Object *ob, const int dag_eval_mode)
{
- if ((ob->base_flag & BASE_VISIBLE) == 0) {
+ if ((ob->base_flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
return 0;
}
@@ -3269,8 +3269,7 @@ void BKE_object_sculpt_data_create(Object *ob)
ob->sculpt->mode_type = ob->mode;
}
-int BKE_object_obdata_texspace_get(
- Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot)
+int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, float **r_size)
{
if (ob->data == NULL) {
@@ -3279,14 +3278,12 @@ int BKE_object_obdata_texspace_get(
switch (GS(((ID *)ob->data)->name)) {
case ID_ME: {
- BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size);
+ BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_size);
break;
}
case ID_CU: {
Curve *cu = ob->data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
if (r_texflag) {
*r_texflag = &cu->texflag;
}
@@ -3296,9 +3293,6 @@ int BKE_object_obdata_texspace_get(
if (r_size) {
*r_size = cu->size;
}
- if (r_rot) {
- *r_rot = cu->rot;
- }
break;
}
case ID_MB: {
@@ -3312,9 +3306,6 @@ int BKE_object_obdata_texspace_get(
if (r_size) {
*r_size = mb->size;
}
- if (r_rot) {
- *r_rot = mb->rot;
- }
break;
}
default:
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index b9c4adafab2..6b6c68b197e 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -401,12 +401,8 @@ static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Obj
mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat);
const MVert *mvert = me_eval->mvert;
- const int *origindex = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
-
- for (int i = 0, j = 0; i < me_eval->totvert; i++) {
- if (origindex == NULL || origindex[i] != ORIGINDEX_NONE) {
- vertex_dupli(vdd, j++, mvert[i].co, mvert[i].no);
- }
+ for (int i = 0; i < me_eval->totvert; i++) {
+ vertex_dupli(vdd, i, mvert[i].co, mvert[i].no);
}
}
diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c
index b3ebe9b5ffa..be96927ed63 100644
--- a/source/blender/blenkernel/intern/object_facemap.c
+++ b/source/blender/blenkernel/intern/object_facemap.c
@@ -261,3 +261,41 @@ bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name)
{
return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
}
+
+int *BKE_object_facemap_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
+{
+ /* Build src to merged mapping of facemap indices. */
+ if (BLI_listbase_is_empty(&ob_src->fmaps) || BLI_listbase_is_empty(&ob_dst->fmaps)) {
+ *r_map_len = 0;
+ return NULL;
+ }
+
+ *r_map_len = BLI_listbase_count(&ob_src->fmaps);
+ int *fmap_index_map = MEM_malloc_arrayN(
+ *r_map_len, sizeof(*fmap_index_map), "defgroup index map create");
+ bool is_fmap_remap_needed = false;
+
+ int i = 0;
+ for (bFaceMap *fmap_src = ob_src->fmaps.first; fmap_src; fmap_src = fmap_src->next, i++) {
+ fmap_index_map[i] = BKE_object_facemap_name_index(ob_dst, fmap_src->name);
+ is_fmap_remap_needed = is_fmap_remap_needed || (fmap_index_map[i] != i);
+ }
+
+ if (!is_fmap_remap_needed) {
+ MEM_freeN(fmap_index_map);
+ fmap_index_map = NULL;
+ *r_map_len = 0;
+ }
+
+ return fmap_index_map;
+}
+
+void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len)
+{
+ if (map == NULL || map_len == 0) {
+ return;
+ }
+ for (int i = 0; i < fmap_len; i++, fmap++) {
+ *fmap = (*fmap < map_len && *fmap != -1) ? map[*fmap] : -1;
+ }
+}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 01f3f2e309b..21ca5e6d6a6 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -439,10 +439,10 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph,
* assumed viewport visibility. Select-ability does not matter here. */
if (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER) {
if (base->flag & BASE_ENABLED_RENDER) {
- base->flag |= BASE_VISIBLE;
+ base->flag |= BASE_VISIBLE_DEPSGRAPH;
}
else {
- base->flag &= ~BASE_VISIBLE;
+ base->flag &= ~BASE_VISIBLE_DEPSGRAPH;
}
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 8e647757b40..5fa3352d497 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -141,7 +141,9 @@ int BKE_packedfile_count_all(Main *bmain)
void BKE_packedfile_free(PackedFile *pf)
{
if (pf) {
- MEM_freeN(pf->data);
+ BLI_assert(pf->data != NULL);
+
+ MEM_SAFE_FREE(pf->data);
MEM_freeN(pf);
}
else {
@@ -151,6 +153,9 @@ void BKE_packedfile_free(PackedFile *pf)
PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src)
{
+ BLI_assert(pf_src != NULL);
+ BLI_assert(pf_src->data != NULL);
+
PackedFile *pf_dst;
pf_dst = MEM_dupallocN(pf_src);
@@ -161,6 +166,8 @@ PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src)
PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen)
{
+ BLI_assert(mem != NULL);
+
PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
pf->data = mem;
pf->size = memlen;
@@ -178,7 +185,7 @@ PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const
/* render result has no filename and can be ignored
* any other files with no name can be ignored too */
if (filename[0] == '\0') {
- return NULL;
+ return pf;
}
// XXX waitcursor(1);
@@ -260,7 +267,7 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
}
if (tot > 0) {
- BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
+ BKE_reportf(reports, RPT_INFO, "Packed %d file(s)", tot);
}
else if (verbose) {
BKE_report(reports, RPT_INFO, "No new files have been packed");
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 5980aa456e2..cc9d1b98ba4 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -224,7 +224,6 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode)
return rna_enum_brush_image_tool_items;
case PAINT_MODE_SCULPT_UV:
return rna_enum_brush_uv_sculpt_tool_items;
- return NULL;
case PAINT_MODE_GPENCIL:
return rna_enum_brush_gpencil_types_items;
case PAINT_MODE_INVALID:
@@ -992,10 +991,24 @@ static void sculptsession_free_pbvh(Object *object)
{
SculptSession *ss = object->sculpt;
- if (ss && ss->pbvh) {
+ if (!ss) {
+ return;
+ }
+
+ if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
ss->pbvh = NULL;
}
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
+ }
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
+ }
}
void BKE_sculptsession_bm_to_me_for_render(Object *object)
@@ -1090,6 +1103,12 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
return NULL;
}
+ /* Weight paint operates on original vertices, and needs to treat multires as regular modifier
+ * to make it so that PBVH vertices are at the multires surface. */
+ if ((ob->mode & OB_MODE_SCULPT) == 0) {
+ return NULL;
+ }
+
for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
if (md->type == eModifierType_Multires) {
MultiresModifierData *mmd = (MultiresModifierData *)md;
@@ -1135,7 +1154,10 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) {
+ if (md->type == eModifierType_Multires && (ob->mode & OB_MODE_SCULPT)) {
+ continue;
+ }
+ if (md->type == eModifierType_ShapeKey) {
continue;
}
@@ -1162,7 +1184,7 @@ static void sculpt_update_object(
Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
+ ss->deform_modifiers_active = sculpt_modifiers_active(scene, sd, ob);
ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0;
ss->building_vp_handle = false;
@@ -1183,10 +1205,11 @@ static void sculpt_update_object(
/* tessfaces aren't used and will become invalid */
BKE_mesh_tessface_clear(me);
- ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
+ ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
- /* VWPaint require mesh info for loop lookup, so require sculpt mode here */
- if (mmd && ob->mode & OB_MODE_SCULPT) {
+ /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
+ * so no extra checks is needed here. */
+ if (mmd) {
ss->multires = mmd;
ss->totvert = me_eval->totvert;
ss->totpoly = me_eval->totpoly;
@@ -1210,23 +1233,22 @@ static void sculpt_update_object(
BLI_assert(pbvh == ss->pbvh);
UNUSED_VARS_NDEBUG(pbvh);
- MEM_SAFE_FREE(ss->pmap);
- MEM_SAFE_FREE(ss->pmap_mem);
- if (need_pmap && ob->type == OB_MESH) {
+ if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
BKE_mesh_vert_poly_map_create(
&ss->pmap, &ss->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
}
pbvh_show_mask_set(ss->pbvh, ss->show_mask);
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
if (!ss->orig_cos) {
int a;
BKE_sculptsession_free_deformMats(ss);
- ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) :
- BKE_mesh_vert_coords_alloc(me, NULL);
+ ss->orig_cos = (ss->shapekey_active) ?
+ BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active) :
+ BKE_mesh_vert_coords_alloc(me, NULL);
BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos);
BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos, me->totvert);
@@ -1240,15 +1262,15 @@ static void sculpt_update_object(
BKE_sculptsession_free_deformMats(ss);
}
- if (ss->kb != NULL && ss->deform_cos == NULL) {
- ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
+ if (ss->shapekey_active != NULL && ss->deform_cos == NULL) {
+ ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active);
}
/* if pbvh is deformed, key block is already applied to it */
- if (ss->kb) {
+ if (ss->shapekey_active) {
bool pbvh_deformed = BKE_pbvh_is_deformed(ss->pbvh);
if (!pbvh_deformed || ss->deform_cos == NULL) {
- float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
+ float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active);
if (vertCos) {
if (!pbvh_deformed) {
@@ -1427,17 +1449,17 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc
* on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
* stuff and show final evaluated mesh so user would see actual object shape.
*/
- deformed |= object->sculpt->modifiers_active;
+ deformed |= object->sculpt->deform_modifiers_active;
if (for_construction) {
- deformed |= object->sculpt->kb != NULL;
+ deformed |= object->sculpt->shapekey_active != NULL;
}
else {
/* As in case with modifiers, we can't synchronize deformation made against
* PBVH and non-locked keyblock, so also use PBVH only for brushes and
* final DM to give final result to user.
*/
- deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0;
+ deformed |= object->sculpt->shapekey_active && (object->shapeflag & OB_SHAPE_LOCK) == 0;
}
return deformed;
@@ -1467,6 +1489,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
BKE_pbvh_build_mesh(pbvh,
+ me,
me->mpoly,
me->mloop,
me->mvert,
@@ -1566,7 +1589,7 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
/* Regular mesh only draws from PBVH without modifiers and shape keys. */
const bool full_shading = (v3d && (v3d->shading.type > OB_SOLID));
- return !(ss->kb || ss->modifiers_active || full_shading);
+ return !(ss->shapekey_active || ss->deform_modifiers_active || full_shading);
}
else {
/* Multires and dyntopo always draw directly from the PBVH. */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 312b8f883df..74fbfc318a8 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -4068,9 +4068,7 @@ void psys_get_texture(
0,
texvec);
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
sub_v3_v3(texvec, me->loc);
if (me->size[0] != 0.0f) {
texvec[0] /= me->size[0];
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 0eca4489309..01612ded396 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -27,6 +27,7 @@
#include "BLI_ghash.h"
#include "BLI_task.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_pbvh.h"
@@ -51,8 +52,6 @@
#define STACK_FIXED_DEPTH 100
-#define PBVH_THREADED_LIMIT 4
-
typedef struct PBVHStack {
PBVHNode *node;
bool revisiting;
@@ -535,6 +534,7 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
* (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
*/
void BKE_pbvh_build_mesh(PBVH *bvh,
+ const Mesh *mesh,
const MPoly *mpoly,
const MLoop *mloop,
MVert *verts,
@@ -547,6 +547,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
BBC *prim_bbc = NULL;
BB cb;
+ bvh->mesh = mesh;
bvh->type = PBVH_FACES;
bvh->mpoly = mpoly;
bvh->mloop = mloop;
@@ -990,6 +991,7 @@ typedef struct PBVHUpdateData {
float (*vnors)[3];
int flag;
+ bool show_vcol;
} PBVHUpdateData;
static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
@@ -1059,11 +1061,12 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
const int v = verts[i];
MVert *mvert = &bvh->verts[v];
- /* mvert is shared between nodes, hence between threads. */
- if (atomic_fetch_and_and_char(&mvert->flag, (char)~ME_VERT_PBVH_UPDATE) &
- ME_VERT_PBVH_UPDATE) {
+ /* No atomics necessary because we are iterating over uniq_verts only,
+ * so we know only this thread will handle this vertex. */
+ if (mvert->flag & ME_VERT_PBVH_UPDATE) {
normalize_v3(vnors[v]);
normal_float_to_short_v3(mvert->no, vnors[v]);
+ mvert->flag &= ~ME_VERT_PBVH_UPDATE;
}
}
@@ -1093,17 +1096,65 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
.vnors = vnors,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
-
- BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
MEM_freeN(vnors);
}
+static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
+ if (node->flag & PBVH_UpdateMask) {
+
+ bool has_unmasked = false;
+ bool has_masked = true;
+ if (node->flag & PBVH_Leaf) {
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ if (vd.mask && *vd.mask < 1.0f) {
+ has_unmasked = true;
+ }
+ if (vd.mask && *vd.mask > 0.0f) {
+ has_masked = false;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ else {
+ has_unmasked = true;
+ has_masked = true;
+ }
+ BKE_pbvh_node_fully_masked_set(node, !has_unmasked);
+ BKE_pbvh_node_fully_unmasked_set(node, has_masked);
+
+ node->flag &= ~PBVH_UpdateMask;
+ }
+}
+
+static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
+{
+ PBVHUpdateData data = {
+ .bvh = bvh,
+ .nodes = nodes,
+ .flag = flag,
+ };
+
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings);
+}
+
static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -1137,10 +1188,9 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
.flag = flag,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
}
static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol)
@@ -1151,71 +1201,106 @@ static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol)
return update_flags;
}
-static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol)
-{
- /* can't be done in parallel with OpenGL */
- for (int n = 0; n < totnode; n++) {
- PBVHNode *node = nodes[n];
-
- if (node->flag & PBVH_RebuildDrawBuffers) {
- GPU_pbvh_buffers_free(node->draw_buffers);
- switch (bvh->type) {
- case PBVH_GRIDS:
- node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden);
- break;
- case PBVH_FACES:
- node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
- bvh->mpoly,
- bvh->mloop,
- bvh->looptri,
- bvh->verts,
- node->prim_indices,
- node->totprim);
- break;
- case PBVH_BMESH:
- node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags &
- PBVH_DYNTOPO_SMOOTH_SHADING);
- break;
- }
-
- node->flag &= ~PBVH_RebuildDrawBuffers;
- }
+static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ /* Create and update draw buffers. The functions called here must not
+ * do any OpenGL calls. Flags are not cleared immediately, that happens
+ * after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
- if (node->flag & PBVH_UpdateDrawBuffers) {
- const int update_flags = pbvh_get_buffers_update_flags(bvh, show_vcol);
- switch (bvh->type) {
- case PBVH_GRIDS:
- GPU_pbvh_grid_buffers_update(node->draw_buffers,
- bvh->grids,
- bvh->grid_flag_mats,
- node->prim_indices,
- node->totprim,
- &bvh->gridkey,
- update_flags);
- break;
- case PBVH_FACES:
- GPU_pbvh_mesh_buffers_update(node->draw_buffers,
- bvh->verts,
- node->vert_indices,
- node->uniq_verts + node->face_verts,
- CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
- CustomData_get_layer(bvh->ldata, CD_MLOOPCOL),
- node->face_vert_indices,
- update_flags);
- break;
- case PBVH_BMESH:
- GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
- bvh->bm,
- node->bm_faces,
- node->bm_unique_verts,
- node->bm_other_verts,
- update_flags);
- break;
+ if (node->flag & PBVH_RebuildDrawBuffers) {
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden);
+ break;
+ case PBVH_FACES:
+ node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
+ bvh->mpoly,
+ bvh->mloop,
+ bvh->looptri,
+ bvh->verts,
+ node->prim_indices,
+ node->totprim,
+ bvh->mesh);
+ break;
+ case PBVH_BMESH:
+ node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags &
+ PBVH_DYNTOPO_SMOOTH_SHADING);
+ break;
+ }
+ }
+
+ if (node->flag & PBVH_UpdateDrawBuffers) {
+ const int update_flags = pbvh_get_buffers_update_flags(bvh, data->show_vcol);
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ GPU_pbvh_grid_buffers_update(node->draw_buffers,
+ bvh->grids,
+ bvh->grid_flag_mats,
+ node->prim_indices,
+ node->totprim,
+ &bvh->gridkey,
+ update_flags);
+ break;
+ case PBVH_FACES:
+ GPU_pbvh_mesh_buffers_update(node->draw_buffers,
+ bvh->verts,
+ node->vert_indices,
+ node->uniq_verts + node->face_verts,
+ CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
+ CustomData_get_layer(bvh->ldata, CD_MLOOPCOL),
+ node->face_vert_indices,
+ update_flags);
+ break;
+ case PBVH_BMESH:
+ GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
+ bvh->bm,
+ node->bm_faces,
+ node->bm_unique_verts,
+ node->bm_other_verts,
+ update_flags);
+ break;
+ }
+ }
+}
+
+static void pbvh_update_draw_buffers(
+ PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol, int update_flag)
+{
+ if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(bvh->type, PBVH_GRIDS, PBVH_BMESH)) {
+ /* Free buffers uses OpenGL, so not in parallel. */
+ for (int n = 0; n < totnode; n++) {
+ PBVHNode *node = nodes[n];
+ if (node->flag & PBVH_RebuildDrawBuffers) {
+ GPU_pbvh_buffers_free(node->draw_buffers);
+ node->draw_buffers = NULL;
+ }
+ else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) {
+ if (bvh->type == PBVH_GRIDS) {
+ GPU_pbvh_grid_buffers_update_free(
+ node->draw_buffers, bvh->grid_flag_mats, node->prim_indices);
+ }
+ else if (bvh->type == PBVH_BMESH) {
+ GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers);
+ }
}
-
- node->flag &= ~PBVH_UpdateDrawBuffers;
}
}
+
+ /* Parallel creation and update of draw buffers. */
+ PBVHUpdateData data = {
+ .bvh = bvh,
+ .nodes = nodes,
+ .show_vcol = show_vcol,
+ };
+
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings);
}
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
@@ -1270,6 +1355,24 @@ void BKE_pbvh_update_bounds(PBVH *bvh, int flag)
pbvh_flush_bb(bvh, bvh->nodes, flag);
}
+ MEM_SAFE_FREE(nodes);
+}
+
+void BKE_pbvh_update_vertex_data(PBVH *bvh, int flag)
+{
+ if (!bvh->nodes) {
+ return;
+ }
+
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
+
+ if (flag & (PBVH_UpdateMask)) {
+ pbvh_update_mask_redraw(bvh, nodes, totnode, flag);
+ }
+
if (nodes) {
MEM_freeN(nodes);
}
@@ -1378,19 +1481,24 @@ BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *bvh)
return bvh->grid_hidden;
}
-void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key)
+const CCGKey *BKE_pbvh_get_grid_key(const PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_GRIDS);
- *key = bvh->gridkey;
+ return &bvh->gridkey;
}
-struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh, int *num_grids)
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_GRIDS);
- *num_grids = bvh->totgrid;
return bvh->grids;
}
+int BKE_pbvh_get_grid_num_vertices(const PBVH *bvh)
+{
+ BLI_assert(bvh->type == PBVH_GRIDS);
+ return bvh->totgrid * bvh->gridkey.grid_area;
+}
+
BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_BMESH);
@@ -1405,6 +1513,11 @@ void BKE_pbvh_node_mark_update(PBVHNode *node)
PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
+void BKE_pbvh_node_mark_update_mask(PBVHNode *node)
+{
+ node->flag |= PBVH_UpdateMask | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+}
+
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node)
{
node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
@@ -1432,6 +1545,40 @@ void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden)
}
}
+void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked)
+{
+ BLI_assert(node->flag & PBVH_Leaf);
+
+ if (fully_masked) {
+ node->flag |= PBVH_FullyMasked;
+ }
+ else {
+ node->flag &= ~PBVH_FullyMasked;
+ }
+}
+
+bool BKE_pbvh_node_fully_masked_get(PBVHNode *node)
+{
+ return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyMasked);
+}
+
+void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked)
+{
+ BLI_assert(node->flag & PBVH_Leaf);
+
+ if (fully_masked) {
+ node->flag |= PBVH_FullyUnmasked;
+ }
+ else {
+ node->flag &= ~PBVH_FullyUnmasked;
+ }
+}
+
+bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node)
+{
+ return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked);
+}
+
void BKE_pbvh_node_get_verts(PBVH *bvh,
PBVHNode *node,
const int **r_vert_indices,
@@ -1571,8 +1718,8 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
/**
* \note doing a full search on all vertices here seems expensive,
- * however this is important to avoid having to recalculate boundbox & sync the buffers to the GPU
- * (which is far more expensive!) See: T47232.
+ * however this is important to avoid having to recalculate boundbox & sync the buffers to the
+ * GPU (which is far more expensive!) See: T47232.
*/
bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node)
{
@@ -1761,14 +1908,11 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
const MVert *vert = bvh->verts;
const MLoop *mloop = bvh->mloop;
const int *faces = node->prim_indices;
- int i, totface = node->totprim;
+ int totface = node->totprim;
bool hit = false;
- float min_depth = FLT_MAX;
- float location[3] = {0.0f};
- float nearest_vertex_co[3];
- copy_v3_fl(nearest_vertex_co, 0.0f);
+ float nearest_vertex_co[3] = {0.0f};
- for (i = 0; i < totface; i++) {
+ for (int i = 0; i < totface; i++) {
const MLoopTri *lt = &bvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
@@ -1776,35 +1920,33 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
continue;
}
+ const float *co[3];
if (origco) {
/* intersect with backuped original coordinates */
- hit |= ray_face_intersection_tri(ray_start,
- isect_precalc,
- origco[face_verts[0]],
- origco[face_verts[1]],
- origco[face_verts[2]],
- depth);
+ co[0] = origco[face_verts[0]];
+ co[1] = origco[face_verts[1]];
+ co[2] = origco[face_verts[2]];
}
else {
/* intersect with current coordinates */
- hit |= ray_face_intersection_tri(ray_start,
- isect_precalc,
- vert[mloop[lt->tri[0]].v].co,
- vert[mloop[lt->tri[1]].v].co,
- vert[mloop[lt->tri[2]].v].co,
- depth);
-
- if (hit && *depth < min_depth) {
- min_depth = *depth;
- normal_tri_v3(r_face_normal,
- vert[mloop[lt->tri[0]].v].co,
- vert[mloop[lt->tri[1]].v].co,
- vert[mloop[lt->tri[2]].v].co);
+ co[0] = vert[mloop[lt->tri[0]].v].co;
+ co[1] = vert[mloop[lt->tri[1]].v].co;
+ co[2] = vert[mloop[lt->tri[2]].v].co;
+ }
+
+ if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) {
+ hit = true;
+
+ if (r_face_normal) {
+ normal_tri_v3(r_face_normal, co[0], co[1], co[2]);
+ }
+
+ if (r_active_vertex_index) {
+ float location[3] = {0.0f};
madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
for (int j = 0; j < 3; j++) {
- if (len_squared_v3v3(location, vert[mloop[lt->tri[j]].v].co) <
- len_squared_v3v3(location, nearest_vertex_co)) {
- copy_v3_v3(nearest_vertex_co, vert[mloop[lt->tri[j]].v].co);
+ if (len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) {
+ copy_v3_v3(nearest_vertex_co, co[j]);
*r_active_vertex_index = mloop[lt->tri[j]].v;
}
}
@@ -1819,22 +1961,28 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
+ const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
- float *depth)
+ float *depth,
+ int *r_active_vertex_index,
+ float *r_face_normal)
{
const int totgrid = node->totprim;
const int gridsize = bvh->gridkey.grid_size;
bool hit = false;
+ float nearest_vertex_co[3] = {0.0};
+ const CCGKey *gridkey = &bvh->gridkey;
for (int i = 0; i < totgrid; i++) {
- CCGElem *grid = bvh->grids[node->prim_indices[i]];
+ const int grid_index = node->prim_indices[i];
+ CCGElem *grid = bvh->grids[grid_index];
BLI_bitmap *gh;
if (!grid) {
continue;
}
- gh = bvh->grid_hidden[node->prim_indices[i]];
+ gh = bvh->grid_hidden[grid_index];
for (int y = 0; y < gridsize - 1; y++) {
for (int x = 0; x < gridsize - 1; x++) {
@@ -1845,23 +1993,40 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
}
}
+ const float *co[4];
if (origco) {
- hit |= ray_face_intersection_quad(ray_start,
- isect_precalc,
- origco[y * gridsize + x],
- origco[y * gridsize + x + 1],
- origco[(y + 1) * gridsize + x + 1],
- origco[(y + 1) * gridsize + x],
- depth);
+ co[0] = origco[y * gridsize + x];
+ co[1] = origco[y * gridsize + x + 1];
+ co[2] = origco[(y + 1) * gridsize + x + 1];
+ co[3] = origco[(y + 1) * gridsize + x];
}
else {
- hit |= ray_face_intersection_quad(ray_start,
- isect_precalc,
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
- depth);
+ co[0] = CCG_grid_elem_co(gridkey, grid, x, y);
+ co[1] = CCG_grid_elem_co(gridkey, grid, x + 1, y);
+ co[2] = CCG_grid_elem_co(gridkey, grid, x + 1, y + 1);
+ co[3] = CCG_grid_elem_co(gridkey, grid, x, y + 1);
+ }
+
+ if (ray_face_intersection_quad(
+ ray_start, isect_precalc, co[0], co[1], co[2], co[3], depth)) {
+ hit = true;
+
+ if (r_face_normal) {
+ normal_quad_v3(r_face_normal, co[0], co[1], co[2], co[3]);
+ }
+
+ if (r_active_vertex_index) {
+ float location[3] = {0.0};
+ madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+ for (int j = 0; j < 4; j++) {
+ if (len_squared_v3v3(location, co[j]) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
+ copy_v3_v3(nearest_vertex_co, co[j]);
+ *r_active_vertex_index = gridkey->grid_area * grid_index + y * gridkey->grid_size +
+ x;
+ }
+ }
+ }
}
}
}
@@ -1904,7 +2069,15 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
face_normal);
break;
case PBVH_GRIDS:
- hit |= pbvh_grids_node_raycast(bvh, node, origco, ray_start, isect_precalc, depth);
+ hit |= pbvh_grids_node_raycast(bvh,
+ node,
+ origco,
+ ray_start,
+ ray_normal,
+ isect_precalc,
+ depth,
+ active_vertex_index,
+ face_normal);
break;
case PBVH_BMESH:
BM_mesh_elem_index_ensure(bvh->bm, BM_VERT);
@@ -2167,16 +2340,18 @@ typedef enum {
* Returns true if the AABB is at least partially within the frustum
* (ok, not a real frustum), false otherwise.
*/
-static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
- const float bb_max[3],
- const float (*planes)[4])
+static PlaneAABBIsect test_frustum_aabb(const float bb_min[3],
+ const float bb_max[3],
+ PBVHFrustumPlanes *frustum)
{
- float vmin[3], vmax[3];
PlaneAABBIsect ret = ISECT_INSIDE;
+ float(*planes)[4] = frustum->planes;
+
+ for (int i = 0; i < frustum->num_planes; i++) {
+ float vmin[3], vmax[3];
- for (int i = 0; i < 4; i++) {
for (int axis = 0; axis < 3; axis++) {
- if (planes[i][axis] > 0) {
+ if (planes[i][axis] < 0) {
vmin[axis] = bb_min[axis];
vmax[axis] = bb_max[axis];
}
@@ -2186,10 +2361,10 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
}
}
- if (dot_v3v3(planes[i], vmin) + planes[i][3] > 0) {
+ if (dot_v3v3(planes[i], vmin) + planes[i][3] < 0) {
return ISECT_OUTSIDE;
}
- else if (dot_v3v3(planes[i], vmax) + planes[i][3] >= 0) {
+ else if (dot_v3v3(planes[i], vmax) + planes[i][3] <= 0) {
ret = ISECT_INTERSECT;
}
}
@@ -2197,38 +2372,24 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
return ret;
}
-bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data)
+bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *data)
{
const float *bb_min, *bb_max;
/* BKE_pbvh_node_get_BB */
bb_min = node->vb.bmin;
bb_max = node->vb.bmax;
- return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
+ return test_frustum_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
}
-bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data)
+bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *data)
{
const float *bb_min, *bb_max;
/* BKE_pbvh_node_get_BB */
bb_min = node->vb.bmin;
bb_max = node->vb.bmax;
- return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
-}
-
-typedef struct PBVHNodeDrawCallbackData {
- void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers);
- void *user_data;
-} PBVHNodeDrawCallbackData;
-
-static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
-{
- PBVHNodeDrawCallbackData *data = data_v;
-
- if (!(node->flag & PBVH_FullyHidden)) {
- data->draw_fn(data->user_data, node->draw_buffers);
- }
+ return test_frustum_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
@@ -2240,63 +2401,96 @@ void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
BKE_pbvh_search_gather(
bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode);
- if (bvh->type == PBVH_BMESH) {
- pbvh_bmesh_normals_update(nodes, totnode);
- }
- else if (bvh->type == PBVH_FACES) {
- pbvh_faces_update_normals(bvh, nodes, totnode);
- }
- else if (bvh->type == PBVH_GRIDS) {
- struct CCGFace **faces;
- int num_faces;
- BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces);
- if (num_faces > 0) {
- BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces);
- MEM_freeN(faces);
+ if (totnode > 0) {
+ if (bvh->type == PBVH_BMESH) {
+ pbvh_bmesh_normals_update(nodes, totnode);
+ }
+ else if (bvh->type == PBVH_FACES) {
+ pbvh_faces_update_normals(bvh, nodes, totnode);
+ }
+ else if (bvh->type == PBVH_GRIDS) {
+ struct CCGFace **faces;
+ int num_faces;
+ BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces);
+ if (num_faces > 0) {
+ BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces);
+ MEM_freeN(faces);
+ }
}
}
- if (nodes) {
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
+}
+
+/**
+ * PBVH drawing, updating draw buffers as needed and culling any nodes outside
+ * the specified frustum.
+ */
+typedef struct PBVHDrawSearchData {
+ PBVHFrustumPlanes *frustum;
+ int accum_update_flag;
+} PBVHDrawSearchData;
+
+static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v)
+{
+ PBVHDrawSearchData *data = data_v;
+ if (data->frustum && !BKE_pbvh_node_frustum_contain_AABB(node, data->frustum)) {
+ return false;
}
+
+ data->accum_update_flag |= node->flag;
+ return true;
}
-void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol)
+void BKE_pbvh_draw_cb(PBVH *bvh,
+ bool show_vcol,
+ bool update_only_visible,
+ PBVHFrustumPlanes *frustum,
+ void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
+ void *user_data)
{
- /* Update GPU buffers */
PBVHNode **nodes;
int totnode;
- BKE_pbvh_search_gather(
- bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateDrawBuffers), &nodes, &totnode);
+ const int update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
- pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol);
+ if (!update_only_visible) {
+ /* Update all draw buffers, also those outside the view. */
+ BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode);
- if (nodes) {
- MEM_freeN(nodes);
+ if (totnode) {
+ pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, update_flag);
+ }
+
+ MEM_SAFE_FREE(nodes);
}
-}
-/**
- * Version of #BKE_pbvh_draw that runs a callback.
- */
-void BKE_pbvh_draw_cb(PBVH *bvh,
- float (*planes)[4],
- void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
- void *user_data)
-{
- PBVHNodeDrawCallbackData draw_data = {
- .draw_fn = draw_fn,
- .user_data = user_data,
- };
+ /* Gather visible nodes. */
+ PBVHDrawSearchData data = {.frustum = frustum, .accum_update_flag = 0};
+ BKE_pbvh_search_gather(bvh, pbvh_draw_search_cb, &data, &nodes, &totnode);
- if (planes) {
- BKE_pbvh_search_callback(
- bvh, BKE_pbvh_node_planes_contain_AABB, planes, pbvh_node_draw_cb, &draw_data);
+ if (update_only_visible && (data.accum_update_flag & update_flag)) {
+ /* Update draw buffers in visible nodes. */
+ pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, data.accum_update_flag);
}
- else {
- BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data);
+
+ /* Draw. */
+ for (int a = 0; a < totnode; a++) {
+ PBVHNode *node = nodes[a];
+
+ if (node->flag & PBVH_UpdateDrawBuffers) {
+ /* Flush buffers uses OpenGL, so not in parallel. */
+ GPU_pbvh_buffers_update_flush(node->draw_buffers);
+ }
+
+ node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
+
+ if (!(node->flag & PBVH_FullyHidden)) {
+ draw_fn(user_data, node->draw_buffers);
+ }
}
+
+ MEM_SAFE_FREE(nodes);
}
void BKE_pbvh_draw_debug_cb(
@@ -2494,7 +2688,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
- vi->key = &bvh->gridkey;
+ vi->key = bvh->gridkey;
vi->grids = grids;
vi->grid_indices = grid_indices;
@@ -2546,3 +2740,11 @@ void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
{
bvh->show_mask = show_mask;
}
+
+void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings,
+ bool use_threading,
+ int totnode)
+{
+ memset(settings, 0, sizeof(*settings));
+ settings->use_threading = use_threading && totnode > 1;
+}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index c04e172f116..6d38ae13994 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1516,10 +1516,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
float *r_face_normal)
{
bool hit = false;
-
- float min_depth = FLT_MAX;
float nearest_vertex_co[3] = {0.0f};
- float location[3] = {0.0f};
+
if (use_original && node->bm_tot_ortri) {
for (int i = 0; i < node->bm_tot_ortri; i++) {
const int *t = node->bm_ortri[i];
@@ -1542,18 +1540,24 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
BMVert *v_tri[3];
BM_face_as_array_vert_tri(f, v_tri);
- hit |= ray_face_intersection_tri(
- ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth);
-
- if (hit && *depth < min_depth) {
- min_depth = *depth;
- normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
- madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
- for (int j = 0; j < 3; j++) {
- if (len_squared_v3v3(location, v_tri[j]->co) <
- len_squared_v3v3(location, nearest_vertex_co)) {
- copy_v3_v3(nearest_vertex_co, v_tri[j]->co);
- *r_active_vertex_index = BM_elem_index_get(v_tri[j]);
+
+ if (ray_face_intersection_tri(
+ ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth)) {
+ hit = true;
+
+ if (r_face_normal) {
+ normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
+ }
+
+ if (r_active_vertex_index) {
+ float location[3] = {0.0f};
+ madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+ for (int j = 0; j < 3; j++) {
+ if (len_squared_v3v3(location, v_tri[j]->co) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
+ copy_v3_v3(nearest_vertex_co, v_tri[j]->co);
+ *r_active_vertex_index = BM_elem_index_get(v_tri[j]);
+ }
}
}
}
@@ -1974,7 +1978,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
if (mode & PBVH_Collapse) {
EdgeQueue q;
- BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert * [2]), 0, 128, BLI_MEMPOOL_NOP);
+ BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
EdgeQueueContext eq_ctx = {
&q,
queue_pool,
@@ -1993,7 +1997,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
if (mode & PBVH_Subdivide) {
EdgeQueue q;
- BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert * [2]), 0, 128, BLI_MEMPOOL_NOP);
+ BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
EdgeQueueContext eq_ctx = {
&q,
queue_pool,
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index bad103743eb..bdee05f1aab 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -127,6 +127,7 @@ struct PBVH {
int leaf_limit;
/* Mesh data */
+ const struct Mesh *mesh;
MVert *verts;
const MPoly *mpoly;
const MLoop *mloop;
diff --git a/source/blender/blenkernel/intern/pbvh_parallel.cc b/source/blender/blenkernel/intern/pbvh_parallel.cc
new file mode 100644
index 00000000000..aa4c659c8bd
--- /dev/null
+++ b/source/blender/blenkernel/intern/pbvh_parallel.cc
@@ -0,0 +1,145 @@
+/*
+ * 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 "MEM_guardedalloc.h"
+
+#include "BLI_task.h"
+#include "BLI_threads.h"
+
+#include "BKE_pbvh.h"
+
+#include "atomic_ops.h"
+
+#ifdef WITH_TBB
+
+# include <tbb/tbb.h>
+
+/* Functor for running TBB parallel_for and parallel_reduce. */
+struct PBVHTask {
+ PBVHParallelRangeFunc func;
+ void *userdata;
+ const PBVHParallelSettings *settings;
+
+ void *userdata_chunk;
+
+ /* Root constructor. */
+ PBVHTask(PBVHParallelRangeFunc func, void *userdata, const PBVHParallelSettings *settings)
+ : func(func), userdata(userdata), settings(settings)
+ {
+ init_chunk(settings->userdata_chunk);
+ }
+
+ /* Copy constructor. */
+ PBVHTask(const PBVHTask &other)
+ : func(other.func), userdata(other.userdata), settings(other.settings)
+ {
+ init_chunk(other.userdata_chunk);
+ }
+
+ /* Splitting constructor for parallel reduce. */
+ PBVHTask(PBVHTask &other, tbb::split)
+ : func(other.func), userdata(other.userdata), settings(other.settings)
+ {
+ init_chunk(settings->userdata_chunk);
+ }
+
+ ~PBVHTask()
+ {
+ MEM_SAFE_FREE(userdata_chunk);
+ }
+
+ void init_chunk(void *from_chunk)
+ {
+ if (from_chunk) {
+ userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "PBVHTask");
+ memcpy(userdata_chunk, from_chunk, settings->userdata_chunk_size);
+ }
+ else {
+ userdata_chunk = NULL;
+ }
+ }
+
+ void operator()(const tbb::blocked_range<int> &r) const
+ {
+ TaskParallelTLS tls;
+ tls.thread_id = get_thread_id();
+ tls.userdata_chunk = userdata_chunk;
+ for (int i = r.begin(); i != r.end(); ++i) {
+ func(userdata, i, &tls);
+ }
+ }
+
+ void join(const PBVHTask &other)
+ {
+ settings->func_reduce(userdata, userdata_chunk, other.userdata_chunk);
+ }
+
+ int get_thread_id() const
+ {
+ /* Get a unique thread ID for texture nodes. In the future we should get rid
+ * of the thread ID and change texture evaluation to not require per-thread
+ * storage that can't be efficiently allocated on the stack. */
+ static tbb::enumerable_thread_specific<int> pbvh_thread_id(-1);
+ static int pbvh_thread_id_counter = 0;
+
+ int &thread_id = pbvh_thread_id.local();
+ if (thread_id == -1) {
+ thread_id = atomic_fetch_and_add_int32(&pbvh_thread_id_counter, 1);
+ if (thread_id >= BLENDER_MAX_THREADS) {
+ BLI_assert(!"Maximum number of threads exceeded for sculpting");
+ thread_id = thread_id % BLENDER_MAX_THREADS;
+ }
+ }
+ return thread_id;
+ }
+};
+
+#endif
+
+void BKE_pbvh_parallel_range(const int start,
+ const int stop,
+ void *userdata,
+ PBVHParallelRangeFunc func,
+ const struct PBVHParallelSettings *settings)
+{
+#ifdef WITH_TBB
+ /* Multithreading. */
+ if (settings->use_threading) {
+ PBVHTask task(func, userdata, settings);
+
+ if (settings->func_reduce) {
+ parallel_reduce(tbb::blocked_range<int>(start, stop), task);
+ if (settings->userdata_chunk) {
+ memcpy(settings->userdata_chunk, task.userdata_chunk, settings->userdata_chunk_size);
+ }
+ }
+ else {
+ parallel_for(tbb::blocked_range<int>(start, stop), task);
+ }
+
+ return;
+ }
+#endif
+
+ /* Single threaded. Nothing to reduce as everything is accumulated into the
+ * main userdata chunk directly. */
+ TaskParallelTLS tls;
+ tls.thread_id = 0;
+ tls.userdata_chunk = settings->userdata_chunk;
+ for (int i = start; i < stop; i++) {
+ func(userdata, i, &tls);
+ }
+}
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 514f000d73d..c57808f3dee 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -51,6 +51,7 @@
#include "BKE_collection.h"
#include "BKE_effect.h"
+#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -61,7 +62,6 @@
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#ifdef WITH_BULLET
-# include "BKE_global.h"
# include "BKE_library.h"
# include "BKE_library_query.h"
#endif
@@ -174,13 +174,22 @@ void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
/* free physics references */
if (is_orig) {
if (rbo->shared->physics_object) {
- BLI_assert(rbw);
- if (rbw) {
+ if (rbw != NULL) {
/* We can only remove the body from the world if the world is known.
* The world is generally only unknown if it's an evaluated copy of
* an object that's being freed, in which case this code isn't run anyway. */
RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object);
}
+ else {
+ /* We have no access to 'owner' RBW when deleting the object ID itself... No choice bu to
+ * loop over all scenes then. */
+ for (Scene *scene = G_MAIN->scenes.first; scene != NULL; scene = scene->id.next) {
+ RigidBodyWorld *scene_rbw = scene->rigidbody_world;
+ if (scene_rbw != NULL) {
+ RB_dworld_remove_body(scene_rbw->shared->physics_world, rbo->shared->physics_object);
+ }
+ }
+ }
RB_body_delete(rbo->shared->physics_object);
rbo->shared->physics_object = NULL;
@@ -1415,7 +1424,7 @@ bool BKE_rigidbody_add_object(Main *bmain, Scene *scene, Object *ob, int type, R
return true;
}
-void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob)
+void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob, const bool free_us)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
RigidBodyCon *rbc;
@@ -1438,8 +1447,13 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob)
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, obt) {
if (obt && obt->rigidbody_constraint) {
rbc = obt->rigidbody_constraint;
- if (ELEM(ob, rbc->ob1, rbc->ob2)) {
- BKE_rigidbody_remove_constraint(scene, obt);
+ if (rbc->ob1 == ob) {
+ rbc->ob1 = NULL;
+ DEG_id_tag_update(&obt->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ if (rbc->ob2 == ob) {
+ rbc->ob2 = NULL;
+ DEG_id_tag_update(&obt->id, ID_RECALC_COPY_ON_WRITE);
}
}
}
@@ -1454,7 +1468,7 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob)
* when we remove them from RB simulation. */
BKE_collection_object_add(bmain, scene->master_collection, ob);
}
- BKE_collection_object_remove(bmain, rbw->group, ob, false);
+ BKE_collection_object_remove(bmain, rbw->group, ob, free_us);
}
/* remove object's settings */
@@ -1468,15 +1482,24 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob)
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
}
-void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
+void BKE_rigidbody_remove_constraint(Main *bmain, Scene *scene, Object *ob, const bool free_us)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
RigidBodyCon *rbc = ob->rigidbody_constraint;
- /* remove from rigidbody world, free object won't do this */
- if (rbw && rbw->shared->physics_world && rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ if (rbw != NULL) {
+ /* Remove from RBW constraints collection. */
+ if (rbw->constraints != NULL) {
+ BKE_collection_object_remove(bmain, rbw->constraints, ob, free_us);
+ DEG_id_tag_update(&rbw->constraints->id, ID_RECALC_COPY_ON_WRITE);
+ }
+
+ /* remove from rigidbody world, free object won't do this */
+ if (rbw->shared->physics_world && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ }
}
+
/* remove object's settings */
BKE_rigidbody_free_constraint(ob);
@@ -1657,9 +1680,12 @@ static void rigidbody_update_simulation(Depsgraph *depsgraph,
float ctime = DEG_get_ctime(depsgraph);
/* update world */
- if (rebuild) {
- BKE_rigidbody_validate_sim_world(scene, rbw, true);
+ /* Note physics_world can get NULL when undoing the deletion of the last object in it (see
+ * T70667). */
+ if (rebuild || rbw->shared->physics_world == NULL) {
+ BKE_rigidbody_validate_sim_world(scene, rbw, rebuild);
}
+
rigidbody_update_sim_world(scene, rbw);
/* XXX TODO For rebuild: remove all constraints first.
@@ -2086,10 +2112,10 @@ bool BKE_rigidbody_add_object(Main *bmain, Scene *scene, Object *ob, int type, R
return false;
}
-void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob)
+void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob, const bool free_us)
{
}
-void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
+void BKE_rigidbody_remove_constraint(Main *bmain, Scene *scene, Object *ob, const bool free_us)
{
}
void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 855e0c58e16..2d5061db487 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -345,6 +345,10 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
flag_subdata);
}
+ if (sce_src->display.shading.prop) {
+ sce_dst->display.shading.prop = IDP_CopyProperty(sce_src->display.shading.prop);
+ }
+
BKE_sound_reset_scene_runtime(sce_dst);
/* Copy sequencer, this is local data! */
@@ -1072,19 +1076,19 @@ Object *BKE_scene_camera_switch_find(Scene *scene)
}
#endif
-int BKE_scene_camera_switch_update(Scene *scene)
+bool BKE_scene_camera_switch_update(Scene *scene)
{
#ifdef DURIAN_CAMERA_SWITCH
Object *camera = BKE_scene_camera_switch_find(scene);
- if (camera) {
+ if (camera && (camera != scene->camera)) {
scene->camera = camera;
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
- return 1;
+ return true;
}
#else
(void)scene;
#endif
- return 0;
+ return false;
}
char *BKE_scene_find_marker_name(Scene *scene, int frame)
@@ -1140,15 +1144,18 @@ int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, in
return (delta_prev < delta_next) ? second_prev : second_next;
}
-void BKE_scene_remove_rigidbody_object(struct Main *bmain, Scene *scene, Object *ob)
+void BKE_scene_remove_rigidbody_object(struct Main *bmain,
+ Scene *scene,
+ Object *ob,
+ const bool free_us)
{
/* remove rigid body constraint from world before removing object */
if (ob->rigidbody_constraint) {
- BKE_rigidbody_remove_constraint(scene, ob);
+ BKE_rigidbody_remove_constraint(bmain, scene, ob, free_us);
}
/* remove rigid body object from world before removing object */
if (ob->rigidbody_object) {
- BKE_rigidbody_remove_object(bmain, scene, ob);
+ BKE_rigidbody_remove_object(bmain, scene, ob, free_us);
}
}
@@ -1738,6 +1745,8 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl
switch (unit_type) {
case B_UNIT_LENGTH:
+ case B_UNIT_VELOCITY:
+ case B_UNIT_ACCELERATION:
return value * (double)unit->scale_length;
case B_UNIT_AREA:
case B_UNIT_POWER:
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index eb4fc6994a9..ccb1869ee21 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -241,10 +241,11 @@ static SeqCacheKey *seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCac
* This can happen because only FINAL_OUT item insertion will trigger recycling
* but that is also the point, where prefetch can be suspended.
*
- * We could use temp cache as a shield and later untemp entry,
+ * We could use temp cache as a shield and later make it a non-temporary entry,
* but it is not worth of increasing system complexity.
*/
- if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) {
+ if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE &&
+ BKE_sequencer_prefetch_job_is_running(scene)) {
int pfjob_start, pfjob_end;
BKE_sequencer_prefetch_get_time_range(scene, &pfjob_start, &pfjob_end);
@@ -319,7 +320,7 @@ static void seq_cache_recycle_linked(Scene *scene, SeqCacheKey *base)
}
}
-SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene)
+static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene)
{
SeqCache *cache = seq_cache_get_from_scene(scene);
SeqCacheKey *finalkey = NULL;
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index dbdaaaa5fc3..236fb43e89c 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -3822,7 +3822,7 @@ void BKE_sequencer_text_font_load(TextVars *data, const bool do_id_user)
char path[FILE_MAX];
STRNCPY(path, data->text_font->name);
BLI_assert(BLI_thread_is_main());
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&data->text_font->id));
data->text_blf_id = BLF_load(path);
}
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index a7543881dad..57b8c92de3e 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -34,6 +34,7 @@
#include "BLT_translation.h"
+#include "DNA_mask_types.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
@@ -1044,7 +1045,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context,
frame_offset = seq->start;
}
else /*if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE)*/ {
- frame_offset = 0;
+ frame_offset = ((Mask *)smd->mask_id)->sfra;
}
ImBuf *mask = modifier_mask_get(smd, context, cfra, frame_offset, ibuf->rect_float != NULL);
diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c
index 172db70823a..6dd1c47407f 100644
--- a/source/blender/blenkernel/intern/seqprefetch.c
+++ b/source/blender/blenkernel/intern/seqprefetch.c
@@ -31,6 +31,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_anim_types.h"
#include "BLI_listbase.h"
#include "BLI_threads.h"
@@ -55,6 +56,7 @@ typedef struct PrefetchJob {
struct PrefetchJob *next, *prev;
struct Main *bmain;
+ struct Main *bmain_eval;
struct Scene *scene;
struct Scene *scene_eval;
struct Depsgraph *depsgraph;
@@ -109,7 +111,7 @@ static PrefetchJob *seq_prefetch_job_get(Scene *scene)
return NULL;
}
-static bool seq_prefetch_job_is_running(Scene *scene)
+bool BKE_sequencer_prefetch_job_is_running(Scene *scene)
{
PrefetchJob *pfjob = seq_prefetch_job_get(scene);
@@ -185,12 +187,12 @@ static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob)
static void seq_prefetch_update_depsgraph(PrefetchJob *pfjob)
{
DEG_evaluate_on_framechange(
- pfjob->bmain, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched);
+ pfjob->bmain_eval, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched);
}
static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob)
{
- Main *bmain = pfjob->bmain;
+ Main *bmain = pfjob->bmain_eval;
Scene *scene = pfjob->scene;
ViewLayer *view_layer = BKE_view_layer_default_render(scene);
@@ -198,7 +200,7 @@ static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob)
DEG_debug_name_set(pfjob->depsgraph, "SEQUENCER PREFETCH");
/* Make sure there is a correct evaluated scene pointer. */
- DEG_graph_build_for_render_pipeline(pfjob->depsgraph, pfjob->bmain, scene, view_layer);
+ DEG_graph_build_for_render_pipeline(pfjob->depsgraph, bmain, scene, view_layer);
/* Update immediately so we have proper evaluated scene. */
seq_prefetch_update_depsgraph(pfjob);
@@ -229,7 +231,9 @@ static void seq_prefetch_update_area(PrefetchJob *pfjob)
}
}
-/* Use also to update scene and context changes */
+/* Use also to update scene and context changes
+ * This function should almost always be called by cache invalidation, not directly.
+ */
void BKE_sequencer_prefetch_stop(Scene *scene)
{
PrefetchJob *pfjob;
@@ -251,7 +255,7 @@ static void seq_prefetch_update_context(const SeqRenderData *context)
PrefetchJob *pfjob;
pfjob = seq_prefetch_job_get(context->scene);
- BKE_sequencer_new_render_data(pfjob->bmain,
+ BKE_sequencer_new_render_data(pfjob->bmain_eval,
pfjob->depsgraph,
pfjob->scene_eval,
context->rectx,
@@ -314,6 +318,7 @@ void BKE_sequencer_prefetch_free(Scene *scene)
BLI_mutex_end(&pfjob->prefetch_suspend_mutex);
BLI_condition_end(&pfjob->prefetch_suspend_cond);
seq_prefetch_free_depsgraph(pfjob);
+ BKE_main_free(pfjob->bmain_eval);
MEM_freeN(pfjob);
scene->ed->prefetch_job = NULL;
}
@@ -322,16 +327,26 @@ static void *seq_prefetch_frames(void *job)
{
PrefetchJob *pfjob = (PrefetchJob *)job;
- /* set to NULL before return! */
- pfjob->scene_eval->ed->prefetch_job = pfjob;
+ while (pfjob->cfra + pfjob->num_frames_prefetched <= pfjob->scene->r.efra) {
+ pfjob->scene_eval->ed->prefetch_job = NULL;
- while (pfjob->cfra + pfjob->num_frames_prefetched < pfjob->scene->r.efra) {
- BKE_animsys_evaluate_all_animation(pfjob->context_cpy.bmain,
- pfjob->context_cpy.depsgraph,
- pfjob->context_cpy.scene,
- pfjob->cfra + pfjob->num_frames_prefetched);
+ AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id);
+ BKE_animsys_evaluate_animdata(pfjob->context_cpy.scene,
+ &pfjob->context_cpy.scene->id,
+ adt,
+ pfjob->cfra + pfjob->num_frames_prefetched,
+ ADT_RECALC_ALL,
+ false);
seq_prefetch_update_depsgraph(pfjob);
+ /* This is quite hacky solution:
+ * We need cross-reference original scene with copy for cache.
+ * However depsgraph must not have this data, because it will try to kill this job.
+ * Scene copy don't reference original scene. Perhaps, this could be done by depsgraph.
+ * Set to NULL before return!
+ */
+ pfjob->scene_eval->ed->prefetch_job = pfjob;
+
ImBuf *ibuf = BKE_sequencer_give_ibuf(
&pfjob->context_cpy, pfjob->cfra + pfjob->num_frames_prefetched, 0);
BKE_sequencer_cache_free_temp_cache(
@@ -371,10 +386,9 @@ static void *seq_prefetch_frames(void *job)
return 0;
}
-PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra)
+static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra)
{
- PrefetchJob *pfjob;
- pfjob = seq_prefetch_job_get(context->scene);
+ PrefetchJob *pfjob = seq_prefetch_job_get(context->scene);
if (!pfjob) {
if (context->scene->ed) {
@@ -386,6 +400,7 @@ PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra)
BLI_condition_init(&pfjob->prefetch_suspend_cond);
pfjob->bmain = context->bmain;
+ pfjob->bmain_eval = BKE_main_new();
pfjob->scene = context->scene;
seq_prefetch_init_depsgraph(pfjob);
@@ -419,7 +434,7 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, floa
if (!context->is_prefetch_render && !context->is_proxy_render) {
bool playing = seq_prefetch_is_playing(context->bmain);
bool scrubbing = seq_prefetch_is_scrubbing(context->bmain);
- bool running = seq_prefetch_job_is_running(scene);
+ bool running = BKE_sequencer_prefetch_job_is_running(scene);
seq_prefetch_resume(scene);
/* conditions to start:
* prefetch enabled, prefetch not running, not scrubbing,
@@ -437,7 +452,7 @@ bool BKE_sequencer_prefetch_need_redraw(Main *bmain, Scene *scene)
{
bool playing = seq_prefetch_is_playing(bmain);
bool scrubbing = seq_prefetch_is_scrubbing(bmain);
- bool running = seq_prefetch_job_is_running(scene);
+ bool running = BKE_sequencer_prefetch_job_is_running(scene);
bool suspended = seq_prefetch_job_is_waiting(scene);
/* force redraw, when prefetching and using cache view. */
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 2e36982f7d8..26dd9aab511 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -3340,7 +3340,8 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
/* anim-data */
adt = BKE_animdata_from_id(&mask->id);
- BKE_animsys_evaluate_animdata(context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(
+ context->scene, &mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false);
maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
@@ -4349,6 +4350,7 @@ static void sequence_invalidate_cache(Scene *scene,
}
sequence_do_invalidate_dependent(scene, seq, &ed->seqbase);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
BKE_sequencer_prefetch_stop(scene);
}
@@ -5543,7 +5545,7 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad
Strip *strip;
seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
/* basic defaults */
seq->len = seq_load->len ? seq_load->len : 1;
@@ -5702,7 +5704,9 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
seq->views_format = seq_load->views_format;
}
seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+
+ seq->type = SEQ_TYPE_MOVIE;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
for (i = 0; i < totfiles; i++) {
if (anim_arr[i]) {
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 992ceda7b74..6f755aa6460 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -866,9 +866,9 @@ static bool target_project_solve_point_tri(const float *vtri_co[3],
{
float x[3], tmp[3];
float dist = sqrtf(hit_dist_sq);
- float epsilon = dist * 1.0e-5f;
-
- CLAMP_MIN(epsilon, 1.0e-5f);
+ float magnitude_estimate = dist + len_manhattan_v3(vtri_co[0]) + len_manhattan_v3(vtri_co[1]) +
+ len_manhattan_v3(vtri_co[2]);
+ float epsilon = magnitude_estimate * 1.0e-6f;
/* Initial solution vector: barycentric weights plus distance along normal. */
interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co);
@@ -929,7 +929,7 @@ static bool update_hit(BVHTreeNearest *nearest,
if (dist_sq < nearest->dist_sq) {
#ifdef TRACE_TARGET_PROJECT
printf(
- "===> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq);
+ "#=#=#> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq);
#endif
nearest->index = index;
nearest->dist_sq = dist_sq;
@@ -1088,14 +1088,14 @@ void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree,
if (type == MOD_SHRINKWRAP_TARGET_PROJECT) {
#ifdef TRACE_TARGET_PROJECT
- printf("====== TARGET PROJECT START ======\n");
+ printf("\n====== TARGET PROJECT START ======\n");
#endif
BLI_bvhtree_find_nearest_ex(
tree->bvh, co, nearest, mesh_looptri_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER);
#ifdef TRACE_TARGET_PROJECT
- printf("====== TARGET PROJECT END: %d %g ======\n", nearest->index, nearest->dist_sq);
+ printf("====== TARGET PROJECT END: %d %g ======\n\n", nearest->index, nearest->dist_sq);
#endif
if (nearest->index < 0) {
@@ -1260,7 +1260,10 @@ static void shrinkwrap_snap_with_side(float r_point_co[3],
float forcesign,
bool forcesnap)
{
- float dist = len_v3v3(point_co, hit_co);
+ float delta[3];
+ sub_v3_v3v3(delta, point_co, hit_co);
+
+ float dist = len_v3(delta);
/* If exactly on the surface, push out along normal */
if (dist < FLT_EPSILON) {
@@ -1273,13 +1276,28 @@ static void shrinkwrap_snap_with_side(float r_point_co[3],
}
/* Move to the correct side if needed */
else {
- float delta[3];
- sub_v3_v3v3(delta, point_co, hit_co);
- float dsign = signf(dot_v3v3(delta, hit_no) * forcesign);
+ float dsign = signf(dot_v3v3(delta, hit_no));
+
+ if (forcesign == 0.0f) {
+ forcesign = dsign;
+ }
/* If on the wrong side or too close, move to correct */
- if (forcesnap || dsign * dist < goal_dist) {
- interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign) / dist);
+ if (forcesnap || dsign * dist * forcesign < goal_dist) {
+ mul_v3_fl(delta, dsign / dist);
+
+ /* At very small distance, blend in the hit normal to stabilize math. */
+ float dist_epsilon = (fabsf(goal_dist) + len_manhattan_v3(hit_co)) * 1e-4f;
+
+ if (dist < dist_epsilon) {
+#ifdef TRACE_TARGET_PROJECT
+ printf("zero_factor %g = %g / %g\n", dist / dist_epsilon, dist, dist_epsilon);
+#endif
+
+ interp_v3_v3v3(delta, hit_no, delta, dist / dist_epsilon);
+ }
+
+ madd_v3_v3v3fl(r_point_co, hit_co, delta, goal_dist * forcesign);
}
else {
copy_v3_v3(r_point_co, point_co);
@@ -1304,13 +1322,13 @@ void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
const float point_co[3],
float r_point_co[3])
{
- float dist, tmp[3];
+ float tmp[3];
switch (mode) {
/* Offsets along the line between point_co and hit_co. */
case MOD_SHRINKWRAP_ON_SURFACE:
- if (goal_dist != 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) {
- interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist);
+ if (goal_dist != 0) {
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, 0, true);
}
else {
copy_v3_v3(r_point_co, hit_co);
@@ -1506,3 +1524,38 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
MEM_freeN(vertexCos);
}
+
+void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target)
+{
+ ShrinkwrapModifierData ssmd = {0};
+ int totvert;
+
+ ssmd.target = ob_target;
+ ssmd.shrinkType = MOD_SHRINKWRAP_TARGET_PROJECT;
+ ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE;
+ ssmd.keepDist = 0.0f;
+ ssmd.projLimit = target_me->remesh_voxel_size;
+
+ float(*vertexCos)[3] = BKE_mesh_vert_coords_alloc(src_me, &totvert);
+
+ ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+
+ calc.smd = &ssmd;
+ calc.numVerts = src_me->totvert;
+ calc.vertexCos = vertexCos;
+ calc.vgroup = -1;
+ calc.target = target_me;
+ calc.keepDist = ssmd.keepDist;
+ BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob_target, ob_target);
+
+ ShrinkwrapTreeData tree;
+ if (BKE_shrinkwrap_init_tree(&tree, calc.target, ssmd.shrinkType, ssmd.shrinkMode, false)) {
+ calc.tree = &tree;
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface);
+ BKE_shrinkwrap_free_tree(&tree);
+ }
+
+ BKE_mesh_vert_coords_apply(src_me, vertexCos);
+
+ MEM_freeN(vertexCos);
+}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 74873db179d..3db51c95fcb 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -2527,17 +2527,13 @@ static void update_flowsfluids(
}
/* sample subframes */
else {
-# if 0
int scene_frame = (int)DEG_get_ctime(depsgraph);
-# endif
// float scene_subframe = scene->r.subframe; // UNUSED
int subframe;
for (subframe = 0; subframe <= subframes; subframe++) {
EmissionMap em_temp = {NULL};
float sample_size = 1.0f / (float)(subframes + 1);
-# if 0
float prev_frame_pos = sample_size * (float)(subframe + 1);
-# endif
float sdt = dt * sample_size;
int hires_multiplier = 1;
@@ -2545,8 +2541,6 @@ static void update_flowsfluids(
hires_multiplier = sds->amplify + 1;
}
- /* TODO: setting the scene frame no longer works with the new depsgraph. */
-# if 0
/* set scene frame to match previous frame + subframe
* or use current frame for last sample */
if (subframe < subframes) {
@@ -2557,7 +2551,6 @@ static void update_flowsfluids(
scene->r.cfra = scene_frame;
scene->r.subframe = 0.0f;
}
-# endif
if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
/* emit_from_particles() updates timestep internally */
@@ -2569,8 +2562,13 @@ static void update_flowsfluids(
else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
/* update flow object frame */
BLI_mutex_lock(&object_update_lock);
- BKE_object_modifier_update_subframe(
- depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke);
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ collob,
+ true,
+ 5,
+ BKE_scene_frame_get(scene),
+ eModifierType_Smoke);
BLI_mutex_unlock(&object_update_lock);
/* apply flow */
@@ -3352,14 +3350,16 @@ struct Mesh *smokeModifier_do(
if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) {
result = createDomainGeometry(smd->domain, ob);
+ BKE_mesh_copy_settings(result, me);
}
else {
result = BKE_mesh_copy_for_eval(me, false);
}
- /* XXX This is really not a nice hack, but until root of the problem is understood,
- * this should be an acceptable workaround I think.
- * See T58492 for details on the issue. */
- result->texflag |= ME_AUTOSPACE;
+
+ /* Smoke simulation needs a texture space relative to the adaptive domain bounds, not the
+ * original mesh. So recompute it at this point in the modifier stack. See T58492. */
+ BKE_mesh_texspace_calc(result);
+
return result;
}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index d346d4d6f8d..8654c50a783 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -129,6 +129,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv)
const int num_grids = topology_refiner_count_face_corners(topology_refiner);
const int grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
const int grid_area = grid_size * grid_size;
+ subdiv_ccg->grid_element_size = element_size;
subdiv_ccg->num_grids = num_grids;
subdiv_ccg->grids = MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids");
subdiv_ccg->grids_storage = MEM_calloc_arrayN(
@@ -169,11 +170,11 @@ typedef struct CCGEvalGridsData {
SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator;
} CCGEvalGridsData;
-static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
- const int ptex_face_index,
- const float u,
- const float v,
- unsigned char *element)
+static void subdiv_ccg_eval_grid_element_limit(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
{
Subdiv *subdiv = data->subdiv;
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
@@ -191,16 +192,35 @@ static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
else {
BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, (float *)element);
}
- if (subdiv_ccg->has_mask) {
- float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
- if (data->mask_evaluator != NULL) {
- *mask_value_ptr = data->mask_evaluator->eval_mask(
- data->mask_evaluator, ptex_face_index, u, v);
- }
- else {
- *mask_value_ptr = 0.0f;
- }
+}
+
+static void subdiv_ccg_eval_grid_element_mask(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ if (!subdiv_ccg->has_mask) {
+ return;
+ }
+ float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
+ if (data->mask_evaluator != NULL) {
+ *mask_value_ptr = data->mask_evaluator->eval_mask(data->mask_evaluator, ptex_face_index, u, v);
}
+ else {
+ *mask_value_ptr = 0.0f;
+ }
+}
+
+static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
+{
+ subdiv_ccg_eval_grid_element_limit(data, ptex_face_index, u, v, element);
+ subdiv_ccg_eval_grid_element_mask(data, ptex_face_index, u, v, element);
}
static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, const int face_index)
@@ -366,25 +386,33 @@ static void subdiv_ccg_allocate_adjacent_edges(SubdivCCG *subdiv_ccg, const int
subdiv_ccg->num_adjacent_edges, sizeof(*subdiv_ccg->adjacent_edges), "ccg adjacent edges");
}
+static SubdivCCGCoord subdiv_ccg_coord(int grid_index, int x, int y)
+{
+ SubdivCCGCoord coord = {.grid_index = grid_index, .x = x, .y = y};
+ return coord;
+}
+
+static CCGElem *subdiv_ccg_coord_to_elem(const CCGKey *key,
+ const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord)
+{
+ return CCG_grid_elem(key, subdiv_ccg->grids[coord->grid_index], coord->x, coord->y);
+}
+
/* Returns storage where boundary elements are to be stored. */
-static CCGElem **subdiv_ccg_adjacent_edge_add_face(SubdivCCG *subdiv_ccg,
- SubdivCCGAdjacentEdge *adjacent_edge,
- SubdivCCGFace *face)
+static SubdivCCGCoord *subdiv_ccg_adjacent_edge_add_face(SubdivCCG *subdiv_ccg,
+ SubdivCCGAdjacentEdge *adjacent_edge)
{
const int grid_size = subdiv_ccg->grid_size * 2;
const int adjacent_face_index = adjacent_edge->num_adjacent_faces;
++adjacent_edge->num_adjacent_faces;
- /* Store new adjacent face. */
- adjacent_edge->faces = MEM_reallocN(
- adjacent_edge->faces, adjacent_edge->num_adjacent_faces * sizeof(*adjacent_edge->faces));
- adjacent_edge->faces[adjacent_face_index] = face;
/* Allocate memory for the boundary elements. */
- adjacent_edge->boundary_elements = MEM_reallocN(adjacent_edge->boundary_elements,
- adjacent_edge->num_adjacent_faces *
- sizeof(*adjacent_edge->boundary_elements));
- adjacent_edge->boundary_elements[adjacent_face_index] = MEM_malloc_arrayN(
- grid_size * 2, sizeof(CCGElem *), "ccg adjacent boundary");
- return adjacent_edge->boundary_elements[adjacent_face_index];
+ adjacent_edge->boundary_coords = MEM_reallocN(adjacent_edge->boundary_coords,
+ adjacent_edge->num_adjacent_faces *
+ sizeof(*adjacent_edge->boundary_coords));
+ adjacent_edge->boundary_coords[adjacent_face_index] = MEM_malloc_arrayN(
+ grid_size * 2, sizeof(SubdivCCGCoord), "ccg adjacent boundary");
+ return adjacent_edge->boundary_coords[adjacent_face_index];
}
static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg)
@@ -404,9 +432,6 @@ static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg)
StaticOrHeapIntStorage face_edges_storage;
static_or_heap_storage_init(&face_vertices_storage);
static_or_heap_storage_init(&face_edges_storage);
- /* Key to access elements. */
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
/* Store adjacency for all faces. */
const int num_faces = subdiv_ccg->num_faces;
for (int face_index = 0; face_index < num_faces; face_index++) {
@@ -428,34 +453,32 @@ static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg)
const bool is_edge_flipped = (edge_vertices[0] != vertex_index);
/* Grid which is adjacent to the current corner. */
const int current_grid_index = face->start_grid_index + corner;
- CCGElem *current_grid = subdiv_ccg->grids[current_grid_index];
/* Grid which is adjacent to the next corner. */
const int next_grid_index = face->start_grid_index + (corner + 1) % num_face_grids;
- CCGElem *next_grid = subdiv_ccg->grids[next_grid_index];
/* Add new face to the adjacent edge. */
SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[edge_index];
- CCGElem **boundary_elements = subdiv_ccg_adjacent_edge_add_face(
- subdiv_ccg, adjacent_edge, face);
+ SubdivCCGCoord *boundary_coords = subdiv_ccg_adjacent_edge_add_face(subdiv_ccg,
+ adjacent_edge);
/* Fill CCG elements along the edge. */
int boundary_element_index = 0;
if (is_edge_flipped) {
for (int i = 0; i < grid_size; i++) {
- boundary_elements[boundary_element_index++] = CCG_grid_elem(
- &key, next_grid, grid_size - i - 1, grid_size - 1);
+ boundary_coords[boundary_element_index++] = subdiv_ccg_coord(
+ next_grid_index, grid_size - i - 1, grid_size - 1);
}
for (int i = 0; i < grid_size; i++) {
- boundary_elements[boundary_element_index++] = CCG_grid_elem(
- &key, current_grid, grid_size - 1, i);
+ boundary_coords[boundary_element_index++] = subdiv_ccg_coord(
+ current_grid_index, grid_size - 1, i);
}
}
else {
for (int i = 0; i < grid_size; i++) {
- boundary_elements[boundary_element_index++] = CCG_grid_elem(
- &key, current_grid, grid_size - 1, grid_size - i - 1);
+ boundary_coords[boundary_element_index++] = subdiv_ccg_coord(
+ current_grid_index, grid_size - 1, grid_size - i - 1);
}
for (int i = 0; i < grid_size; i++) {
- boundary_elements[boundary_element_index++] = CCG_grid_elem(
- &key, next_grid, i, grid_size - 1);
+ boundary_coords[boundary_element_index++] = subdiv_ccg_coord(
+ next_grid_index, i, grid_size - 1);
}
}
}
@@ -475,21 +498,16 @@ static void subdiv_ccg_allocate_adjacent_vertices(SubdivCCG *subdiv_ccg, const i
/* Returns storage where corner elements are to be stored. This is a pointer
* to the actual storage. */
-static CCGElem **subdiv_ccg_adjacent_vertex_add_face(SubdivCCGAdjacentVertex *adjacent_vertex,
- SubdivCCGFace *face)
+static SubdivCCGCoord *subdiv_ccg_adjacent_vertex_add_face(
+ SubdivCCGAdjacentVertex *adjacent_vertex)
{
const int adjacent_face_index = adjacent_vertex->num_adjacent_faces;
++adjacent_vertex->num_adjacent_faces;
- /* Store new adjacent face. */
- adjacent_vertex->faces = MEM_reallocN(adjacent_vertex->faces,
- adjacent_vertex->num_adjacent_faces *
- sizeof(*adjacent_vertex->faces));
- adjacent_vertex->faces[adjacent_face_index] = face;
/* Allocate memory for the boundary elements. */
- adjacent_vertex->corner_elements = MEM_reallocN(adjacent_vertex->corner_elements,
- adjacent_vertex->num_adjacent_faces *
- sizeof(*adjacent_vertex->corner_elements));
- return &adjacent_vertex->corner_elements[adjacent_face_index];
+ adjacent_vertex->corner_coords = MEM_reallocN(adjacent_vertex->corner_coords,
+ adjacent_vertex->num_adjacent_faces *
+ sizeof(*adjacent_vertex->corner_coords));
+ return &adjacent_vertex->corner_coords[adjacent_face_index];
}
static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg)
@@ -522,11 +540,10 @@ static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg)
const int vertex_index = face_vertices[corner];
/* Grid which is adjacent to the current corner. */
const int grid_index = face->start_grid_index + corner;
- CCGElem *grid = subdiv_ccg->grids[grid_index];
/* Add new face to the adjacent edge. */
SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[vertex_index];
- CCGElem **corner_element = subdiv_ccg_adjacent_vertex_add_face(adjacent_vertex, face);
- *corner_element = CCG_grid_elem(&key, grid, grid_size - 1, grid_size - 1);
+ SubdivCCGCoord *corner_coord = subdiv_ccg_adjacent_vertex_add_face(adjacent_vertex);
+ *corner_coord = subdiv_ccg_coord(grid_index, grid_size - 1, grid_size - 1);
}
}
/* Free possibly heap-allocated storage. */
@@ -572,9 +589,9 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
{
/* Make sure evaluator is ready. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
if (coarse_mesh->totpoly) {
- return false;
+ return NULL;
}
}
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
@@ -619,17 +636,15 @@ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
for (int i = 0; i < subdiv_ccg->num_adjacent_edges; i++) {
SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[i];
for (int face_index = 0; face_index < adjacent_edge->num_adjacent_faces; face_index++) {
- MEM_SAFE_FREE(adjacent_edge->boundary_elements[face_index]);
+ MEM_SAFE_FREE(adjacent_edge->boundary_coords[face_index]);
}
- MEM_SAFE_FREE(adjacent_edge->faces);
- MEM_SAFE_FREE(adjacent_edge->boundary_elements);
+ MEM_SAFE_FREE(adjacent_edge->boundary_coords);
}
MEM_SAFE_FREE(subdiv_ccg->adjacent_edges);
/* Free map of adjacent vertices. */
for (int i = 0; i < subdiv_ccg->num_adjacent_vertices; i++) {
SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[i];
- MEM_SAFE_FREE(adjacent_vertex->faces);
- MEM_SAFE_FREE(adjacent_vertex->corner_elements);
+ MEM_SAFE_FREE(adjacent_vertex->corner_coords);
}
MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices);
MEM_freeN(subdiv_ccg);
@@ -1032,7 +1047,8 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG *subdiv_ccg,
}
for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
for (int i = 1; i < grid_size2 - 1; i++) {
- CCGElem *grid_element = adjacent_edge->boundary_elements[face_index][i];
+ CCGElem *grid_element = subdiv_ccg_coord_to_elem(
+ key, subdiv_ccg, &adjacent_edge->boundary_coords[face_index][i]);
element_accumulator_add(&tls->accumulators[i], subdiv_ccg, key, grid_element);
}
}
@@ -1042,7 +1058,8 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG *subdiv_ccg,
/* Copy averaged value to all the other faces. */
for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
for (int i = 1; i < grid_size2 - 1; i++) {
- CCGElem *grid_element = adjacent_edge->boundary_elements[face_index][i];
+ CCGElem *grid_element = subdiv_ccg_coord_to_elem(
+ key, subdiv_ccg, &adjacent_edge->boundary_coords[face_index][i]);
element_accumulator_copy(subdiv_ccg, key, grid_element, &tls->accumulators[i]);
}
}
@@ -1084,13 +1101,15 @@ static void subdiv_ccg_average_grids_corners(SubdivCCG *subdiv_ccg,
GridElementAccumulator accumulator;
element_accumulator_init(&accumulator);
for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
- CCGElem *grid_element = adjacent_vertex->corner_elements[face_index];
+ CCGElem *grid_element = subdiv_ccg_coord_to_elem(
+ key, subdiv_ccg, &adjacent_vertex->corner_coords[face_index]);
element_accumulator_add(&accumulator, subdiv_ccg, key, grid_element);
}
element_accumulator_mul_fl(&accumulator, 1.0f / (float)num_adjacent_faces);
/* Copy averaged value to all the other faces. */
for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
- CCGElem *grid_element = adjacent_vertex->corner_elements[face_index];
+ CCGElem *grid_element = subdiv_ccg_coord_to_elem(
+ key, subdiv_ccg, &adjacent_vertex->corner_coords[face_index]);
element_accumulator_copy(subdiv_ccg, key, grid_element, &accumulator);
}
}
@@ -1224,3 +1243,540 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg,
*r_num_faces = num_grids * (grid_size - 1) * (grid_size - 1);
*r_num_loops = *r_num_faces * 4;
}
+
+/* =============================================================================
+ * Neighbors.
+ */
+
+void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord)
+{
+ printf("%s: grid index: %d, coord: (%d, %d)\n", message, coord->grid_index, coord->x, coord->y);
+}
+
+bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord)
+{
+ if (coord->grid_index < 0 || coord->grid_index >= subdiv_ccg->num_grids) {
+ return false;
+ }
+ const int grid_size = subdiv_ccg->grid_size;
+ if (coord->x < 0 || coord->x >= grid_size) {
+ return false;
+ }
+ if (coord->y < 0 || coord->y >= grid_size) {
+ return false;
+ }
+ return true;
+}
+
+BLI_INLINE void subdiv_ccg_neighbors_init(SubdivCCGNeighbors *neighbors,
+ const int num_unique,
+ const int num_duplicates)
+{
+ const int size = num_unique + num_duplicates;
+ neighbors->size = size;
+ neighbors->num_duplicates = num_duplicates;
+ if (size < ARRAY_SIZE(neighbors->coords_fixed)) {
+ neighbors->coords = neighbors->coords_fixed;
+ }
+ else {
+ neighbors->coords = MEM_mallocN(sizeof(*neighbors->coords) * size,
+ "SubdivCCGNeighbors.coords");
+ }
+}
+
+/* Check whether given coordinate belongs to a grid corner. */
+BLI_INLINE bool is_corner_grid_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord)
+{
+ const int grid_size_1 = subdiv_ccg->grid_size - 1;
+ return (coord->x == 0 && coord->y == 0) || (coord->x == 0 && coord->y == grid_size_1) ||
+ (coord->x == grid_size_1 && coord->y == grid_size_1) ||
+ (coord->x == grid_size_1 && coord->y == 0);
+}
+
+/* Check whether given coordinate belongs to a grid boundary. */
+BLI_INLINE bool is_boundary_grid_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord)
+{
+ const int grid_size_1 = subdiv_ccg->grid_size - 1;
+ return coord->x == 0 || coord->y == 0 || coord->x == grid_size_1 || coord->y == grid_size_1;
+}
+
+/* Check whether coordinate is at the boundary between two grids of the same face. */
+BLI_INLINE bool is_inner_edge_grid_coordinate(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord)
+{
+ const int grid_size_1 = subdiv_ccg->grid_size - 1;
+ if (coord->x == 0) {
+ return coord->y > 0 && coord->y < grid_size_1;
+ }
+ if (coord->y == 0) {
+ return coord->x > 0 && coord->x < grid_size_1;
+ }
+ return false;
+}
+
+BLI_INLINE SubdivCCGCoord coord_at_prev_row(const SubdivCCG *UNUSED(subdiv_ccg),
+ const SubdivCCGCoord *coord)
+{
+ BLI_assert(coord->y > 0);
+ SubdivCCGCoord result = *coord;
+ result.y -= 1;
+ return result;
+}
+BLI_INLINE SubdivCCGCoord coord_at_next_row(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord)
+{
+ UNUSED_VARS_NDEBUG(subdiv_ccg);
+ BLI_assert(coord->y < subdiv_ccg->grid_size - 1);
+ SubdivCCGCoord result = *coord;
+ result.y += 1;
+ return result;
+}
+
+BLI_INLINE SubdivCCGCoord coord_at_prev_col(const SubdivCCG *UNUSED(subdiv_ccg),
+ const SubdivCCGCoord *coord)
+{
+ BLI_assert(coord->x > 0);
+ SubdivCCGCoord result = *coord;
+ result.x -= 1;
+ return result;
+}
+BLI_INLINE SubdivCCGCoord coord_at_next_col(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord)
+{
+ UNUSED_VARS_NDEBUG(subdiv_ccg);
+ BLI_assert(coord->x < subdiv_ccg->grid_size - 1);
+ SubdivCCGCoord result = *coord;
+ result.x += 1;
+ return result;
+}
+
+/* For the input coordinate which is at the boundary of the grid do one step inside. */
+static SubdivCCGCoord coord_step_inside_from_boundary(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord)
+
+{
+ SubdivCCGCoord result = *coord;
+ const int grid_size_1 = subdiv_ccg->grid_size - 1;
+ if (result.x == grid_size_1) {
+ --result.x;
+ }
+ else if (result.y == grid_size_1) {
+ --result.y;
+ }
+ else if (result.x == 0) {
+ ++result.x;
+ }
+ else if (result.y == 0) {
+ ++result.y;
+ }
+ else {
+ BLI_assert(!"non-boundary element given");
+ }
+ return result;
+}
+
+BLI_INLINE
+int next_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord)
+{
+ SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
+ const int face_grid_index = coord->grid_index;
+ int next_face_grid_index = face_grid_index + 1 - face->start_grid_index;
+ if (next_face_grid_index == face->num_grids) {
+ next_face_grid_index = 0;
+ }
+ return face->start_grid_index + next_face_grid_index;
+}
+BLI_INLINE int prev_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord)
+{
+ SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
+ const int face_grid_index = coord->grid_index;
+ int prev_face_grid_index = face_grid_index - 1 - face->start_grid_index;
+ if (prev_face_grid_index < 0) {
+ prev_face_grid_index = face->num_grids - 1;
+ }
+ return face->start_grid_index + prev_face_grid_index;
+}
+
+/* Simple case of getting neighbors of a corner coordinate: the corner is a face center, so
+ * can only iterate over grid of a single face, without looking into adjacency. */
+static void neighbor_coords_corner_center_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors)
+{
+ SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
+ const int num_adjacent_grids = face->num_grids;
+
+ subdiv_ccg_neighbors_init(
+ r_neighbors, num_adjacent_grids, (include_duplicates) ? num_adjacent_grids - 1 : 0);
+
+ int duplicate_face_grid_index = num_adjacent_grids;
+ for (int face_grid_index = 0; face_grid_index < num_adjacent_grids; ++face_grid_index) {
+ SubdivCCGCoord neighbor_coord;
+ neighbor_coord.grid_index = face->start_grid_index + face_grid_index;
+ neighbor_coord.x = 1;
+ neighbor_coord.y = 0;
+ r_neighbors->coords[face_grid_index] = neighbor_coord;
+
+ if (include_duplicates && neighbor_coord.grid_index != coord->grid_index) {
+ neighbor_coord.x = 0;
+ r_neighbors->coords[duplicate_face_grid_index++] = neighbor_coord;
+ }
+ }
+}
+
+/* Get index within adjacent_vertices array for the given CCG coordinate. */
+static int adjacent_vertex_index_from_coord(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+
+ const SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
+ const int face_index = face - subdiv_ccg->faces;
+ const int face_grid_index = coord->grid_index - face->start_grid_index;
+ const int num_face_grids = face->num_grids;
+ const int num_face_vertices = num_face_grids;
+
+ StaticOrHeapIntStorage face_vertices_storage;
+ static_or_heap_storage_init(&face_vertices_storage);
+
+ int *face_vertices = static_or_heap_storage_get(&face_vertices_storage, num_face_vertices);
+ topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices);
+
+ const int adjacent_vertex_index = face_vertices[face_grid_index];
+ static_or_heap_storage_free(&face_vertices_storage);
+ return adjacent_vertex_index;
+}
+
+/* The corner is adjacent to a coarse vertex. */
+static void neighbor_coords_corner_vertex_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+
+ const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord);
+ BLI_assert(adjacent_vertex_index >= 0);
+ BLI_assert(adjacent_vertex_index < subdiv_ccg->num_adjacent_vertices);
+ const int num_vertex_edges = topology_refiner->getNumVertexEdges(topology_refiner,
+ adjacent_vertex_index);
+
+ SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[adjacent_vertex_index];
+ const int num_adjacent_faces = adjacent_vertex->num_adjacent_faces;
+
+ subdiv_ccg_neighbors_init(
+ r_neighbors, num_vertex_edges, (include_duplicates) ? num_adjacent_faces - 1 : 0);
+
+ StaticOrHeapIntStorage vertex_edges_storage;
+ static_or_heap_storage_init(&vertex_edges_storage);
+
+ int *vertex_edges = static_or_heap_storage_get(&vertex_edges_storage, num_vertex_edges);
+ topology_refiner->getVertexEdges(topology_refiner, adjacent_vertex_index, vertex_edges);
+
+ for (int i = 0; i < num_vertex_edges; ++i) {
+ const int edge_index = vertex_edges[i];
+
+ /* Use very first grid of every edge. */
+ const int edge_face_index = 0;
+
+ /* Depending edge orientation we use first (zero-based) or previous-to-last point. */
+ int edge_vertices_indices[2];
+ topology_refiner->getEdgeVertices(topology_refiner, edge_index, edge_vertices_indices);
+ int edge_point_index, duplicate_edge_point_index;
+ if (edge_vertices_indices[0] == adjacent_vertex_index) {
+ duplicate_edge_point_index = 0;
+ edge_point_index = duplicate_edge_point_index + 1;
+ }
+ else {
+ /* Edge "consists" of 2 grids, which makes it 2 * grid_size elements per edge.
+ * The index of last edge element is 2 * grid_size - 1 (due to zero-based indices),
+ * and we are interested in previous to last element. */
+ duplicate_edge_point_index = subdiv_ccg->grid_size * 2 - 1;
+ edge_point_index = duplicate_edge_point_index - 1;
+ }
+
+ SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[edge_index];
+ r_neighbors->coords[i] = adjacent_edge->boundary_coords[edge_face_index][edge_point_index];
+ }
+
+ if (include_duplicates) {
+ /* Add duplicates of the current grid vertex in adjacent faces if requested. */
+ for (int i = 0, duplicate_i = num_vertex_edges; i < num_adjacent_faces; i++) {
+ SubdivCCGCoord neighbor_coord = adjacent_vertex->corner_coords[i];
+ if (neighbor_coord.grid_index != coord->grid_index) {
+ r_neighbors->coords[duplicate_i++] = neighbor_coord;
+ }
+ }
+ }
+
+ static_or_heap_storage_free(&vertex_edges_storage);
+}
+
+static int adjacent_edge_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
+
+ const int face_grid_index = coord->grid_index - face->start_grid_index;
+ const int face_index = face - subdiv_ccg->faces;
+ const int num_face_edges = topology_refiner->getNumFaceEdges(topology_refiner, face_index);
+
+ StaticOrHeapIntStorage face_edges_storage;
+ static_or_heap_storage_init(&face_edges_storage);
+ int *face_edges_indices = static_or_heap_storage_get(&face_edges_storage, num_face_edges);
+ topology_refiner->getFaceEdges(topology_refiner, face_index, face_edges_indices);
+
+ const int grid_size_1 = subdiv_ccg->grid_size - 1;
+ int adjacent_edge_index = -1;
+ if (coord->x == grid_size_1) {
+ adjacent_edge_index = face_edges_indices[face_grid_index];
+ }
+ else {
+ BLI_assert(coord->y == grid_size_1);
+ adjacent_edge_index =
+ face_edges_indices[face_grid_index == 0 ? face->num_grids - 1 : face_grid_index - 1];
+ }
+
+ static_or_heap_storage_free(&face_edges_storage);
+
+ return adjacent_edge_index;
+}
+
+static int adjacent_edge_point_index_from_coord(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const int adjacent_edge_index)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+
+ const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord);
+ int edge_vertices_indices[2];
+ topology_refiner->getEdgeVertices(topology_refiner, adjacent_edge_index, edge_vertices_indices);
+
+ /* Vertex index of an edge which is used to see whether edge points in the right direction.
+ * Tricky part here is that depending whether input coordinate is are maximum X or Y coordinate
+ * of the grid we need to use different edge direction.
+ * Basically, the edge adjacent to a previous loop needs to point opposite direction. */
+ int directional_edge_vertex_index = -1;
+
+ const int grid_size_1 = subdiv_ccg->grid_size - 1;
+ int adjacent_edge_point_index = -1;
+ if (coord->x == grid_size_1) {
+ adjacent_edge_point_index = subdiv_ccg->grid_size - coord->y - 1;
+ directional_edge_vertex_index = edge_vertices_indices[0];
+ }
+ else {
+ BLI_assert(coord->y == grid_size_1);
+ adjacent_edge_point_index = subdiv_ccg->grid_size + coord->x;
+ directional_edge_vertex_index = edge_vertices_indices[1];
+ }
+
+ /* Flip the index if the edde points opposite direction. */
+ if (adjacent_vertex_index != directional_edge_vertex_index) {
+ const int num_edge_points = subdiv_ccg->grid_size * 2;
+ adjacent_edge_point_index = num_edge_points - adjacent_edge_point_index - 1;
+ }
+
+ return adjacent_edge_point_index;
+}
+
+/* Adjacent edge has two points in the middle which corresponds to grid corners, but which are
+ * the same point in the final geometry.
+ * So need to use extra step when calculating next/previous points, so we don't go from a corner
+ * of one grid to a corner of adjacent grid. */
+static int next_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int point_index)
+{
+ if (point_index == subdiv_ccg->grid_size - 1) {
+ return point_index + 2;
+ }
+ return point_index + 1;
+}
+static int prev_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int point_index)
+{
+ if (point_index == subdiv_ccg->grid_size) {
+ return point_index - 2;
+ }
+ return point_index - 1;
+}
+
+/* Common implementation of neighbor calculation when input coordinate is at the edge between two
+ * coarse faces, but is not at the coarse vertex. */
+static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors)
+
+{
+ const int adjacent_edge_index = adjacent_edge_index_from_coord(subdiv_ccg, coord);
+ BLI_assert(adjacent_edge_index >= 0);
+ BLI_assert(adjacent_edge_index < subdiv_ccg->num_adjacent_edges);
+ const SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[adjacent_edge_index];
+
+ /* 2 neighbor points along the edge, plus one inner point per every adjacent grid. */
+ const int num_adjacent_faces = adjacent_edge->num_adjacent_faces;
+ subdiv_ccg_neighbors_init(
+ r_neighbors, num_adjacent_faces + 2, (include_duplicates) ? num_adjacent_faces - 1 : 0);
+
+ const int point_index = adjacent_edge_point_index_from_coord(
+ subdiv_ccg, coord, adjacent_edge_index);
+ const int next_point_index = next_adjacent_edge_point_index(subdiv_ccg, point_index);
+ const int prev_point_index = prev_adjacent_edge_point_index(subdiv_ccg, point_index);
+
+ for (int i = 0, duplicate_i = num_adjacent_faces; i < num_adjacent_faces; ++i) {
+ SubdivCCGCoord *boundary_coords = adjacent_edge->boundary_coords[i];
+ /* One step into the grid from the edge for each adjacent face. */
+ SubdivCCGCoord grid_coord = boundary_coords[point_index];
+ r_neighbors->coords[i + 2] = coord_step_inside_from_boundary(subdiv_ccg, &grid_coord);
+
+ if (grid_coord.grid_index == coord->grid_index) {
+ /* Prev and next along the edge for the current grid. */
+ r_neighbors->coords[0] = boundary_coords[prev_point_index];
+ r_neighbors->coords[1] = boundary_coords[next_point_index];
+ }
+ else if (include_duplicates) {
+ /* Same coordinate on neighboring grids if requested. */
+ r_neighbors->coords[duplicate_i + 2] = grid_coord;
+ duplicate_i++;
+ }
+ }
+}
+
+/* The corner is at the middle of edge between faces. */
+static void neighbor_coords_corner_edge_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors)
+{
+ neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
+}
+
+/* Input coordinate is at one of 4 corners of its grid corners. */
+static void neighbor_coords_corner_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors)
+{
+ if (coord->x == 0 && coord->y == 0) {
+ neighbor_coords_corner_center_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
+ }
+ else {
+ const int grid_size_1 = subdiv_ccg->grid_size - 1;
+ if (coord->x == grid_size_1 && coord->y == grid_size_1) {
+ neighbor_coords_corner_vertex_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
+ }
+ else {
+ neighbor_coords_corner_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
+ }
+ }
+}
+
+/* Simple case of getting neighbors of a boundary coordinate: the input coordinate is at the
+ * boundary between two grids of the same face and there is no need to check adjacency with
+ * other faces. */
+static void neighbor_coords_boundary_inner_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors)
+{
+ subdiv_ccg_neighbors_init(r_neighbors, 4, (include_duplicates) ? 1 : 0);
+
+ if (coord->x == 0) {
+ r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord);
+ r_neighbors->coords[1] = coord_at_next_row(subdiv_ccg, coord);
+ r_neighbors->coords[2] = coord_at_next_col(subdiv_ccg, coord);
+
+ r_neighbors->coords[3].grid_index = prev_grid_index_from_coord(subdiv_ccg, coord);
+ r_neighbors->coords[3].x = coord->y;
+ r_neighbors->coords[3].y = 1;
+
+ if (include_duplicates) {
+ r_neighbors->coords[4] = r_neighbors->coords[3];
+ r_neighbors->coords[4].y = 0;
+ }
+ }
+ else if (coord->y == 0) {
+ r_neighbors->coords[0] = coord_at_prev_col(subdiv_ccg, coord);
+ r_neighbors->coords[1] = coord_at_next_col(subdiv_ccg, coord);
+ r_neighbors->coords[2] = coord_at_next_row(subdiv_ccg, coord);
+
+ r_neighbors->coords[3].grid_index = next_grid_index_from_coord(subdiv_ccg, coord);
+ r_neighbors->coords[3].x = 1;
+ r_neighbors->coords[3].y = coord->x;
+
+ if (include_duplicates) {
+ r_neighbors->coords[4] = r_neighbors->coords[3];
+ r_neighbors->coords[4].x = 0;
+ }
+ }
+}
+
+/* Input coordinate is on an edge between two faces. Need to check adjacency. */
+static void neighbor_coords_boundary_outer_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors)
+{
+ neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
+}
+
+/* Input coordinate is at one of 4 boundaries of its grid.
+ * It could either be an inner boundary (which connects face center to the face edge) or could be
+ * a part of coarse face edge. */
+static void neighbor_coords_boundary_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors)
+{
+ if (is_inner_edge_grid_coordinate(subdiv_ccg, coord)) {
+ neighbor_coords_boundary_inner_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
+ }
+ else {
+ neighbor_coords_boundary_outer_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
+ }
+}
+
+/* Input coordinate is inside of its grid, all the neighbors belong to the same grid. */
+static void neighbor_coords_inner_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ SubdivCCGNeighbors *r_neighbors)
+{
+ subdiv_ccg_neighbors_init(r_neighbors, 4, 0);
+
+ r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord);
+ r_neighbors->coords[1] = coord_at_next_row(subdiv_ccg, coord);
+ r_neighbors->coords[2] = coord_at_prev_col(subdiv_ccg, coord);
+ r_neighbors->coords[3] = coord_at_next_col(subdiv_ccg, coord);
+}
+
+void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
+ const SubdivCCGCoord *coord,
+ const bool include_duplicates,
+ SubdivCCGNeighbors *r_neighbors)
+{
+ BLI_assert(coord->grid_index >= 0);
+ BLI_assert(coord->grid_index < subdiv_ccg->num_grids);
+ BLI_assert(coord->x >= 0);
+ BLI_assert(coord->x < subdiv_ccg->grid_size);
+ BLI_assert(coord->y >= 0);
+ BLI_assert(coord->y < subdiv_ccg->grid_size);
+
+ if (is_corner_grid_coord(subdiv_ccg, coord)) {
+ neighbor_coords_corner_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
+ }
+ else if (is_boundary_grid_coord(subdiv_ccg, coord)) {
+ neighbor_coords_boundary_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
+ }
+ else {
+ neighbor_coords_inner_get(subdiv_ccg, coord, r_neighbors);
+ }
+
+#ifndef NDEBUG
+ for (int i = 0; i < r_neighbors->size; i++) {
+ BLI_assert(BKE_subdiv_ccg_check_coord_valid(subdiv_ccg, &r_neighbors->coords[i]));
+ }
+#endif
+}
diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c
new file mode 100644
index 00000000000..9c7949e7bdb
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_deform.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) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_deform.h"
+
+#include <string.h>
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
+
+#include "MEM_guardedalloc.h"
+
+/* ================================================================================================
+ * Subdivision context.
+ */
+
+typedef struct SubdivDeformContext {
+ const Mesh *coarse_mesh;
+ Subdiv *subdiv;
+
+ float (*vertex_cos)[3];
+ int num_verts;
+
+ /* Accumulated values.
+ *
+ * Averaging is happening for vertices which correspond to the coarse ones.
+ * This is needed for displacement.
+ *
+ * Displacement is being accumulated to a vertices coordinates, since those
+ * are not needed during traversal of face-vertices vertices. */
+ /* Per-subdivided vertex counter of averaged values. */
+ int *accumulated_counters;
+
+ bool have_displacement;
+} SubdivDeformContext;
+
+static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_vertices)
+{
+ if (!ctx->have_displacement) {
+ return;
+ }
+ ctx->accumulated_counters = MEM_calloc_arrayN(
+ sizeof(*ctx->accumulated_counters), num_vertices, "subdiv accumulated counters");
+}
+
+static void subdiv_mesh_context_free(SubdivDeformContext *ctx)
+{
+ MEM_SAFE_FREE(ctx->accumulated_counters);
+}
+
+/* ================================================================================================
+ * Accumulation helpers.
+ */
+
+static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ int vertex_index)
+{
+ Subdiv *subdiv = ctx->subdiv;
+ float dummy_P[3], dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
+ /* Accumulate displacement if needed. */
+ if (ctx->have_displacement) {
+ BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
+ /* NOTE: The storage for vertex coordinates is coming from an external world, not necessarily
+ * initialized to zeroes. */
+ if (ctx->accumulated_counters[vertex_index] == 0) {
+ copy_v3_v3(ctx->vertex_cos[vertex_index], D);
+ }
+ else {
+ add_v3_v3(ctx->vertex_cos[vertex_index], D);
+ }
+ }
+ ++ctx->accumulated_counters[vertex_index];
+}
+
+/* ================================================================================================
+ * Subdivision callbacks.
+ */
+
+static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
+ const int UNUSED(num_vertices),
+ const int UNUSED(num_edges),
+ const int UNUSED(num_loops),
+ const int UNUSED(num_polygons))
+{
+ SubdivDeformContext *subdiv_context = foreach_context->user_data;
+ subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->totvert);
+ return true;
+}
+
+static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int UNUSED(subdiv_vertex_index))
+{
+ SubdivDeformContext *ctx = foreach_context->user_data;
+ subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, coarse_vertex_index);
+}
+
+static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int UNUSED(subdiv_vertex_index))
+{
+ SubdivDeformContext *ctx = foreach_context->user_data;
+ BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
+ BLI_assert(coarse_vertex_index < ctx->num_verts);
+ float inv_num_accumulated = 1.0f;
+ if (ctx->accumulated_counters != NULL) {
+ inv_num_accumulated = 1.0f / ctx->accumulated_counters[coarse_vertex_index];
+ }
+ /* Displacement is accumulated in subdiv vertex position.
+ * Needs to be backed up before copying data from original vertex. */
+ float D[3] = {0.0f, 0.0f, 0.0f};
+ float *vertex_co = ctx->vertex_cos[coarse_vertex_index];
+ if (ctx->have_displacement) {
+ copy_v3_v3(D, vertex_co);
+ mul_v3_fl(D, inv_num_accumulated);
+ }
+ /* Copy custom data and evaluate position. */
+ BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, vertex_co);
+ /* Apply displacement. */
+ add_v3_v3(vertex_co, D);
+}
+
+/* ================================================================================================
+ * Initialization.
+ */
+
+static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
+ SubdivForeachContext *foreach_context)
+{
+ memset(foreach_context, 0, sizeof(*foreach_context));
+ /* General information. */
+ foreach_context->topology_info = subdiv_mesh_topology_info;
+ /* Every boundary geometry. Used for displacement and normals averaging. */
+ if (subdiv_context->have_displacement) {
+ foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
+ }
+ foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
+}
+
+/* ================================================================================================
+ * Public entry point.
+ */
+
+void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
+ const struct Mesh *coarse_mesh,
+ float (*vertex_cos)[3],
+ int num_verts)
+{
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ /* Make sure evaluator is up to date with possible new topology, and that
+ * is is refined for the new positions of coarse vertices.
+ */
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
+ /* This could happen in two situations:
+ * - OpenSubdiv is disabled.
+ * - Something totally bad happened, and OpenSubdiv rejected our
+ * topology.
+ * In either way, we can't safely continue. */
+ if (coarse_mesh->totpoly) {
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ return;
+ }
+ }
+
+ /* Initialize subdivion mesh creation context. */
+ SubdivDeformContext subdiv_context = {0};
+ subdiv_context.coarse_mesh = coarse_mesh;
+ subdiv_context.subdiv = subdiv;
+ subdiv_context.vertex_cos = vertex_cos;
+ subdiv_context.num_verts = num_verts;
+ subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL);
+
+ SubdivForeachContext foreach_context;
+ setup_foreach_callbacks(&subdiv_context, &foreach_context);
+ foreach_context.user_data = &subdiv_context;
+
+ /* Dummy mesh rasterization settings. */
+ SubdivToMeshSettings mesh_settings;
+ mesh_settings.resolution = 1;
+ mesh_settings.use_optimal_display = false;
+
+ /* Multi-threaded traversal/evaluation. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ BKE_subdiv_foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+
+ // BKE_mesh_validate(result, true, true);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+
+ /* Free used memory. */
+ subdiv_mesh_context_free(&subdiv_context);
+}
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 419371c7a4b..bf5e886dd22 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -61,7 +61,9 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv)
return true;
}
-static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh)
+static void set_coarse_positions(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
{
const MVert *mvert = mesh->mvert;
const MLoop *mloop = mesh->mloop;
@@ -83,8 +85,15 @@ static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh)
if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
continue;
}
- const MVert *vertex = &mvert[vertex_index];
- subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex->co, manifold_veretx_index, 1);
+ const float *vertex_co;
+ if (coarse_vertex_cos != NULL) {
+ vertex_co = coarse_vertex_cos[vertex_index];
+ }
+ else {
+ const MVert *vertex = &mvert[vertex_index];
+ vertex_co = vertex->co;
+ }
+ subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex_co, manifold_veretx_index, 1);
manifold_veretx_index++;
}
MEM_freeN(vertex_used_map);
@@ -112,7 +121,9 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
}
}
-bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
+bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
{
if (!BKE_subdiv_eval_begin(subdiv)) {
return false;
@@ -123,7 +134,7 @@ bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
return false;
}
/* Set coordinates of base mesh vertices. */
- set_coarse_positions(subdiv, mesh);
+ set_coarse_positions(subdiv, mesh, coarse_vertex_cos);
/* Set face-varyign data to UV maps. */
const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 1604c2560ff..a30dde6284b 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -482,6 +482,8 @@ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *
}
/* Accumulate displacement if needed. */
if (ctx->have_displacement) {
+ /* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero
+ * locations as a default calloc(). */
BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
add_v3_v3(subdiv_vert->co, D);
}
@@ -1164,7 +1166,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
/* Make sure evaluator is up to date with possible new topology, and that
* is is refined for the new positions of coarse vertices.
*/
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -1175,7 +1177,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
return NULL;
}
}
- /* Initialize subdivion mesh creation context/ */
+ /* Initialize subdivion mesh creation context. */
SubdivMeshContext subdiv_context = {0};
subdiv_context.settings = settings;
subdiv_context.coarse_mesh = coarse_mesh;
@@ -1198,7 +1200,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
if (!subdiv_context.can_evaluate_normals) {
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
- /* Free used memoty. */
+ /* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
return result;
}
diff --git a/source/blender/blenkernel/intern/subdiv_topology.c b/source/blender/blenkernel/intern/subdiv_topology.c
new file mode 100644
index 00000000000..455fa2cf28f
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_topology.c
@@ -0,0 +1,34 @@
+/*
+ * 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) 2019 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_topology.h"
+
+#include "BKE_subdiv.h"
+
+#include "opensubdiv_topology_refiner_capi.h"
+
+int BKE_subdiv_topology_num_fvar_layers_get(const struct Subdiv *subdiv)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ return topology_refiner->getNumFVarChannels(topology_refiner);
+}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 83be64e84c9..5c050dde990 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -312,7 +312,7 @@ bool BKE_text_reload(Text *text)
}
BLI_strncpy(filepath_abs, text->name, FILE_MAX);
- BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(filepath_abs, ID_BLEND_PATH_FROM_GLOBAL(&text->id));
buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
if (buffer == NULL) {
@@ -352,7 +352,7 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
if (buffer == NULL) {
- return false;
+ return NULL;
}
ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0);
@@ -477,7 +477,7 @@ int BKE_text_file_modified_check(Text *text)
}
BLI_strncpy(file, text->name, FILE_MAX);
- BLI_path_abs(file, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id));
if (!BLI_exists(file)) {
return 2;
@@ -511,7 +511,7 @@ void BKE_text_file_modified_ignore(Text *text)
}
BLI_strncpy(file, text->name, FILE_MAX);
- BLI_path_abs(file, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id));
if (!BLI_exists(file)) {
return;
@@ -1218,6 +1218,58 @@ void txt_sel_line(Text *text)
text->selc = text->sell->len;
}
+void txt_sel_set(Text *text, int startl, int startc, int endl, int endc)
+{
+ TextLine *froml, *tol;
+ int fromllen, tollen;
+
+ /* Support negative indices. */
+ if (startl < 0 || endl < 0) {
+ int end = BLI_listbase_count(&text->lines) - 1;
+ if (startl < 0) {
+ startl = end + startl + 1;
+ }
+ if (endl < 0) {
+ endl = end + endl + 1;
+ }
+ }
+ CLAMP_MIN(startl, 0);
+ CLAMP_MIN(endl, 0);
+
+ froml = BLI_findlink(&text->lines, startl);
+ if (froml == NULL) {
+ froml = text->lines.last;
+ }
+ if (startl == endl) {
+ tol = froml;
+ }
+ else {
+ tol = BLI_findlink(&text->lines, endl);
+ if (tol == NULL) {
+ tol = text->lines.last;
+ }
+ }
+
+ fromllen = BLI_strlen_utf8(froml->line);
+ tollen = BLI_strlen_utf8(tol->line);
+
+ /* Support negative indices. */
+ if (startc < 0) {
+ startc = fromllen + startc + 1;
+ }
+ if (endc < 0) {
+ endc = tollen + endc + 1;
+ }
+
+ CLAMP(startc, 0, fromllen);
+ CLAMP(endc, 0, tollen);
+
+ text->curl = froml;
+ text->curc = BLI_str_utf8_offset_from_index(froml->line, startc);
+ text->sell = tol;
+ text->selc = BLI_str_utf8_offset_from_index(tol->line, endc);
+}
+
/* -------------------------------------------------------------------- */
/** \name Buffer Conversion for Undo/Redo
*
diff --git a/source/blender/blenlib/BLI_array_ref.h b/source/blender/blenlib/BLI_array_ref.h
index 1373a0da355..e34647676d8 100644
--- a/source/blender/blenlib/BLI_array_ref.h
+++ b/source/blender/blenlib/BLI_array_ref.h
@@ -21,17 +21,17 @@
* \ingroup bli
*
* These classes offer a convenient way to work with continuous chunks of memory of a certain type.
- * We differentiate ArrayRef and MutableArrayRef. The elements in the former are const while the
+ * We differentiate #ArrayRef and #MutableArrayRef. The elements in the former are const while the
* elements in the other are not.
*
* Passing array references as parameters has multiple benefits:
* - Less templates are used because the function does not have to work with different
* container types.
- * - It encourages an Struct-of-Arrays data layout which is often benefitial when
+ * - It encourages an Struct-of-Arrays data layout which is often beneficial when
* writing high performance code. Also it makes it easier to reuse code.
* - Array references offer convenient ways of slicing and other operations.
*
- * The instances of ArrayRef and MutableArrayRef are very small and should be passed by value.
+ * The instances of #ArrayRef and #MutableArrayRef are very small and should be passed by value.
* Since array references do not own any memory, it is generally not save to store them.
*/
@@ -202,7 +202,7 @@ template<typename T> class ArrayRef {
/**
* Does a linear search to count how often the value is in the array.
- * Returns the number of occurences.
+ * Returns the number of occurrences.
*/
uint count(const T &value) const
{
@@ -226,7 +226,7 @@ template<typename T> class ArrayRef {
}
/**
- * Return a reference to the last elemeent in the array.
+ * Return a reference to the last element in the array.
* Asserts that the array is not empty.
*/
const T &last() const
@@ -363,7 +363,7 @@ template<typename T> class MutableArrayRef {
/**
* Return a continuous part of the array.
- * Aserts that the slice stays in the array bounds.
+ * Asserts that the slice stays in the array bounds.
*/
MutableArrayRef slice(uint start, uint length) const
{
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index bd1cd327d3c..312991e7f15 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -15,7 +15,7 @@
*/
#ifndef __BLI_COMPILER_COMPAT_H__
-# define __BLI_COMPILER_COMPAT_H__
+#define __BLI_COMPILER_COMPAT_H__
/** \file
* \ingroup bli
@@ -23,32 +23,32 @@
* Use to help with cross platform portability.
*/
-# if defined(_MSC_VER)
-# define alloca _alloca
-# endif
+#if defined(_MSC_VER)
+# define alloca _alloca
+#endif
-# if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus)
+#if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus)
extern "C++" {
/* Some magic to be sure we don't have reference in the type. */
template<typename T> static inline T decltype_helper(T x)
{
return x;
}
-# define typeof(x) decltype(decltype_helper(x))
+# define typeof(x) decltype(decltype_helper(x))
}
-# endif
+#endif
/* little macro so inline keyword works */
-# if defined(_MSC_VER)
-# define BLI_INLINE static __forceinline
-# else
-# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__))
-# endif
+#if defined(_MSC_VER)
+# define BLI_INLINE static __forceinline
+#else
+# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__))
+#endif
-# if defined(__GNUC__)
-# define BLI_NOINLINE __attribute__((noinline))
-# else
-# define BLI_NOINLINE
-# endif
+#if defined(__GNUC__)
+# define BLI_NOINLINE __attribute__((noinline))
+#else
+# define BLI_NOINLINE
+#endif
#endif /* __BLI_COMPILER_COMPAT_H__ */
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index d78f167a8fd..bdf7588291f 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -50,6 +50,7 @@ int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_copy(const char *path, const char *to) ATTR_NONNULL();
int BLI_rename(const char *from, const char *to) ATTR_NONNULL();
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL();
+int BLI_delete_soft(const char *path, const char **error_message) ATTR_NONNULL();
#if 0 /* Unused */
int BLI_move(const char *path, const char *to) ATTR_NONNULL();
int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index 72cd5c7f4ec..b8a87e9d9fa 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -26,13 +26,11 @@
typedef struct _GSQueue GSQueue;
-GSQueue *BLI_gsqueue_new(size_t elem_size);
-bool BLI_gsqueue_is_empty(GSQueue *gq);
-int BLI_gsqueue_len(GSQueue *gq);
-void BLI_gsqueue_peek(GSQueue *gq, void *r_item);
+GSQueue *BLI_gsqueue_new(const size_t elem_size);
+bool BLI_gsqueue_is_empty(const GSQueue *gq);
+size_t BLI_gsqueue_len(const GSQueue *gq);
void BLI_gsqueue_pop(GSQueue *gq, void *r_item);
void BLI_gsqueue_push(GSQueue *gq, const void *item);
-void BLI_gsqueue_push_back(GSQueue *gq, const void *item);
void BLI_gsqueue_free(GSQueue *gq);
#endif /* __BLI_GSQUEUE_H__ */
diff --git a/source/blender/blenlib/BLI_hash_cxx.h b/source/blender/blenlib/BLI_hash_cxx.h
index 78b8ee20b0c..e899f27c9ee 100644
--- a/source/blender/blenlib/BLI_hash_cxx.h
+++ b/source/blender/blenlib/BLI_hash_cxx.h
@@ -27,6 +27,7 @@
#include <functional>
#include <string>
#include <utility>
+#include <memory>
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
@@ -89,6 +90,13 @@ template<typename T> struct DefaultHash<T *> {
}
};
+template<typename T> struct DefaultHash<std::unique_ptr<T>> {
+ uint32_t operator()(const std::unique_ptr<T> &value) const
+ {
+ return DefaultHash<T *>{}(value.get());
+ }
+};
+
template<typename T1, typename T2> struct DefaultHash<std::pair<T1, T2>> {
uint32_t operator()(const std::pair<T1, T2> &value) const
{
diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h
index e442bd7a99d..c028266ef64 100644
--- a/source/blender/blenlib/BLI_kdtree_impl.h
+++ b/source/blender/blenlib/BLI_kdtree_impl.h
@@ -21,9 +21,9 @@
#include "BLI_compiler_attrs.h"
-#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2
-#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
-#define BLI_kdtree_nd_(id) _CONCAT(KDTREE_PREFIX_ID, _##id)
+#define _BLI_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2
+#define _BLI_CONCAT(MACRO_ARG1, MACRO_ARG2) _BLI_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
+#define BLI_kdtree_nd_(id) _BLI_CONCAT(KDTREE_PREFIX_ID, _##id)
struct KDTree;
typedef struct KDTree KDTree;
@@ -93,6 +93,6 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)(
const void *user_data),
const void *user_data) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
-#undef _CONCAT_AUX
-#undef _CONCAT
+#undef _BLI_CONCAT_AUX
+#undef _BLI_CONCAT
#undef BLI_kdtree_nd_
diff --git a/source/blender/blenlib/BLI_map.h b/source/blender/blenlib/BLI_map.h
index a5358304c77..1edf7653c71 100644
--- a/source/blender/blenlib/BLI_map.h
+++ b/source/blender/blenlib/BLI_map.h
@@ -142,20 +142,20 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
return (ValueT *)(m_values + offset * sizeof(ValueT));
}
- void copy_in(uint offset, const KeyT &key, const ValueT &value)
+ template<typename ForwardKeyT, typename ForwardValueT>
+ void store(uint offset, ForwardKeyT &&key, ForwardValueT &&value)
{
BLI_assert(m_status[offset] != IS_SET);
m_status[offset] = IS_SET;
- new (this->key(offset)) KeyT(key);
- new (this->value(offset)) ValueT(value);
+ new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
+ new (this->value(offset)) ValueT(std::forward<ForwardValueT>(value));
}
- void move_in(uint offset, KeyT &key, ValueT &value)
+ template<typename ForwardKeyT> void store_without_value(uint offset, ForwardKeyT &&key)
{
BLI_assert(m_status[offset] != IS_SET);
m_status[offset] = IS_SET;
- new (this->key(offset)) KeyT(std::move(key));
- new (this->value(offset)) ValueT(std::move(value));
+ new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
}
void set_dummy(uint offset)
@@ -199,17 +199,19 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
*/
void add_new(const KeyT &key, const ValueT &value)
{
- BLI_assert(!this->contains(key));
- this->ensure_can_add();
-
- ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
- if (item.is_empty(offset)) {
- item.copy_in(offset, key, value);
- m_array.update__empty_to_set();
- return;
- }
- }
- ITER_SLOTS_END(offset);
+ this->add_new__impl(key, value);
+ }
+ void add_new(const KeyT &key, ValueT &&value)
+ {
+ this->add_new__impl(key, std::move(value));
+ }
+ void add_new(KeyT &&key, const ValueT &value)
+ {
+ this->add_new__impl(std::move(key), value);
+ }
+ void add_new(KeyT &&key, ValueT &&value)
+ {
+ this->add_new__impl(std::move(key), std::move(value));
}
/**
@@ -218,19 +220,19 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
*/
bool add(const KeyT &key, const ValueT &value)
{
- this->ensure_can_add();
-
- ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
- if (item.is_empty(offset)) {
- item.copy_in(offset, key, value);
- m_array.update__empty_to_set();
- return true;
- }
- else if (item.has_key(offset, key)) {
- return false;
- }
- }
- ITER_SLOTS_END(offset);
+ return this->add__impl(key, value);
+ }
+ bool add(const KeyT &key, ValueT &&value)
+ {
+ return this->add__impl(key, std::move(value));
+ }
+ bool add(KeyT &&key, const ValueT &value)
+ {
+ return this->add__impl(std::move(key), value);
+ }
+ bool add(KeyT &&key, ValueT &&value)
+ {
+ return this->add__impl(std::move(key), std::move(value));
}
/**
@@ -285,30 +287,30 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
}
/**
- * Check if the key exists in the map.
- * If it does exist, call the modify function with a reference to the corresponding value.
- * If it does not exist, call the create function and insert a new key-value-pair.
- * Returns true when a new pair was inserted, otherwise false.
+ * First, checks if the key exists in the map.
+ * If it does exist, call the modify function with a pointer to the corresponding value.
+ * If it does not exist, call the create function with a pointer to where the value should be
+ * created.
+ *
+ * Returns whatever is returned from one of the callback functions. Both callbacks have to return
+ * the same type.
+ *
+ * CreateValueF: Takes a pointer to where the value should be created.
+ * ModifyValueF: Takes a pointer to the value that should be modified.
*/
template<typename CreateValueF, typename ModifyValueF>
- bool add_or_modify(const KeyT &key,
+ auto add_or_modify(const KeyT &key,
const CreateValueF &create_value,
- const ModifyValueF &modify_value)
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
{
- this->ensure_can_add();
-
- ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
- if (item.is_empty(offset)) {
- item.copy_in(offset, key, create_value());
- m_array.update__empty_to_set();
- return true;
- }
- else if (item.has_key(offset, key)) {
- modify_value(*item.value(offset));
- return false;
- }
- }
- ITER_SLOTS_END(offset);
+ return this->add_or_modify__impl(key, create_value, modify_value);
+ }
+ template<typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify(KeyT &&key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ return this->add_or_modify__impl(std::move(key), create_value, modify_value);
}
/**
@@ -316,8 +318,19 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
*/
bool add_override(const KeyT &key, const ValueT &value)
{
- return this->add_or_modify(
- key, [&value]() { return value; }, [&value](ValueT &old_value) { old_value = value; });
+ return this->add_override__impl(key, value);
+ }
+ bool add_override(const KeyT &key, ValueT &&value)
+ {
+ return this->add_override__impl(key, std::move(value));
+ }
+ bool add_override(KeyT &&key, const ValueT &value)
+ {
+ return this->add_override__impl(std::move(key), value);
+ }
+ bool add_override(KeyT &&key, ValueT &&value)
+ {
+ return this->add_override__impl(std::move(key), std::move(value));
}
/**
@@ -384,19 +397,12 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
template<typename CreateValueF>
ValueT &lookup_or_add(const KeyT &key, const CreateValueF &create_value)
{
- this->ensure_can_add();
-
- ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
- if (item.is_empty(offset)) {
- item.copy_in(offset, key, create_value());
- m_array.update__empty_to_set();
- return *item.value(offset);
- }
- else if (item.has_key(offset, key)) {
- return *item.value(offset);
- }
- }
- ITER_SLOTS_END(offset);
+ return this->lookup_or_add__impl(key, create_value);
+ }
+ template<typename CreateValueF>
+ ValueT &lookup_or_add(KeyT &&key, const CreateValueF &create_value)
+ {
+ return this->lookup_or_add__impl(std::move(key), create_value);
}
/**
@@ -608,12 +614,106 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
{
ITER_SLOTS_BEGIN (key, new_array, , item, offset) {
if (item.is_empty(offset)) {
- item.move_in(offset, key, value);
+ item.store(offset, std::move(key), std::move(value));
return;
}
}
ITER_SLOTS_END(offset);
}
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ bool add_override__impl(ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ return this->add_or_modify(
+ std::forward<ForwardKeyT>(key),
+ [&](ValueT *dst) {
+ new (dst) ValueT(std::forward<ForwardValueT>(value));
+ return true;
+ },
+ [&](ValueT *old_value) {
+ *old_value = std::forward<ForwardValueT>(value);
+ return false;
+ });
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ bool add__impl(ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardKeyT>(key), std::forward<ForwardValueT>(value));
+ m_array.update__empty_to_set();
+ return true;
+ }
+ else if (item.has_key(offset, key)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename ForwardValueT>
+ void add_new__impl(ForwardKeyT &&key, ForwardValueT &&value)
+ {
+ BLI_assert(!this->contains(key));
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardKeyT>(key), std::forward<ForwardValueT>(value));
+ m_array.update__empty_to_set();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify__impl(ForwardKeyT &&key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ using CreateReturnT = decltype(create_value(nullptr));
+ using ModifyReturnT = decltype(modify_value(nullptr));
+ BLI_STATIC_ASSERT((std::is_same<CreateReturnT, ModifyReturnT>::value),
+ "Both callbacks should return the same type.");
+
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ m_array.update__empty_to_set();
+ item.store_without_value(offset, std::forward<ForwardKeyT>(key));
+ ValueT *value_ptr = item.value(offset);
+ return create_value(value_ptr);
+ }
+ else if (item.has_key(offset, key)) {
+ ValueT *value_ptr = item.value(offset);
+ return modify_value(value_ptr);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardKeyT, typename CreateValueF>
+ ValueT &lookup_or_add__impl(ForwardKeyT &&key, const CreateValueF &create_value)
+ {
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardKeyT>(key), create_value());
+ m_array.update__empty_to_set();
+ return *item.value(offset);
+ }
+ else if (item.has_key(offset, key)) {
+ return *item.value(offset);
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
};
#undef ITER_SLOTS_BEGIN
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 87517ebe060..eec5d214473 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -97,10 +97,10 @@ bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3],
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
bool is_poly_convex_v2(const float verts[][2], unsigned int nr);
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
-bool is_quad_flip_v3_first_third_fast(const float v0[3],
- const float v1[3],
+bool is_quad_flip_v3_first_third_fast(const float v1[3],
const float v2[3],
- const float v3[3]);
+ const float v3[3],
+ const float v4[3]);
/********************************* Distance **********************************/
diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h
index c5ef26ffb91..8bd8642a4e8 100644
--- a/source/blender/blenlib/BLI_memblock.h
+++ b/source/blender/blenlib/BLI_memblock.h
@@ -30,16 +30,20 @@ extern "C" {
#include "BLI_compiler_attrs.h"
+#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */
+
struct BLI_memblock;
typedef struct BLI_memblock BLI_memblock;
typedef void (*MemblockValFreeFP)(void *val);
-BLI_memblock *BLI_memblock_create(uint elem_size) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT;
+void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP valfreefp) ATTR_NONNULL(1);
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
+#define BLI_memblock_create(elem_size) BLI_memblock_create_ex(elem_size, BLI_MEM_BLOCK_CHUNK_SIZE)
+
typedef struct BLI_memblock_iter {
void **chunk_list;
int cur_index;
@@ -53,6 +57,9 @@ typedef struct BLI_memblock_iter {
void BLI_memblock_iternew(BLI_memblock *pool, BLI_memblock_iter *iter) ATTR_NONNULL();
void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_set.h b/source/blender/blenlib/BLI_set.h
index feb0574338e..dc101add1a7 100644
--- a/source/blender/blenlib/BLI_set.h
+++ b/source/blender/blenlib/BLI_set.h
@@ -117,20 +117,12 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
return (T *)(m_values + offset * sizeof(T));
}
- void copy_in(uint offset, const T &value)
+ template<typename ForwardT> void store(uint offset, ForwardT &&value)
{
BLI_assert(m_status[offset] != IS_SET);
m_status[offset] = IS_SET;
T *dst = this->value(offset);
- new (dst) T(value);
- }
-
- void move_in(uint offset, T &value)
- {
- BLI_assert(m_status[offset] != IS_SET);
- m_status[offset] = IS_SET;
- T *dst = this->value(offset);
- new (dst) T(std::move(value));
+ new (dst) T(std::forward<ForwardT>(value));
}
void set_dummy(uint offset)
@@ -201,17 +193,11 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
*/
void add_new(const T &value)
{
- BLI_assert(!this->contains(value));
- this->ensure_can_add();
-
- ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
- if (item.is_empty(offset)) {
- item.copy_in(offset, value);
- m_array.update__empty_to_set();
- return;
- }
- }
- ITER_SLOTS_END(offset);
+ this->add_new__impl(value);
+ }
+ void add_new(T &&value)
+ {
+ this->add_new__impl(std::move(value));
}
/**
@@ -219,19 +205,11 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
*/
bool add(const T &value)
{
- this->ensure_can_add();
-
- ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
- if (item.is_empty(offset)) {
- item.copy_in(offset, value);
- m_array.update__empty_to_set();
- return true;
- }
- else if (item.has_value(offset, value)) {
- return false;
- }
- }
- ITER_SLOTS_END(offset);
+ return this->add__impl(value);
+ }
+ bool add(T &&value)
+ {
+ return this->add__impl(std::move(value));
}
/**
@@ -445,7 +423,7 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
{
ITER_SLOTS_BEGIN (old_value, new_array, , item, offset) {
if (item.is_empty(offset)) {
- item.move_in(offset, old_value);
+ item.store(offset, std::move(old_value));
return;
}
}
@@ -463,6 +441,38 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
}
ITER_SLOTS_END(offset);
}
+
+ template<typename ForwardT> void add_new__impl(ForwardT &&value)
+ {
+ BLI_assert(!this->contains(value));
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardT> bool add__impl(ForwardT &&value)
+ {
+ this->ensure_can_add();
+
+ ITER_SLOTS_BEGIN (value, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ item.store(offset, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return true;
+ }
+ else if (item.has_value(offset, value)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
};
#undef ITER_SLOTS_BEGIN
diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h
index b6250afdee0..08e61915a83 100644
--- a/source/blender/blenlib/BLI_sort.h
+++ b/source/blender/blenlib/BLI_sort.h
@@ -31,7 +31,7 @@
# define BLI_qsort_r qsort_r
#endif
-/* Quick sort reentrant */
+/* Quick sort re-entrant */
typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx);
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
diff --git a/source/blender/blenlib/BLI_stack_cxx.h b/source/blender/blenlib/BLI_stack_cxx.h
index 4c9f2ed7d44..7915acadfac 100644
--- a/source/blender/blenlib/BLI_stack_cxx.h
+++ b/source/blender/blenlib/BLI_stack_cxx.h
@@ -73,7 +73,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class St
void push(T &&value)
{
- m_elements.append(std::forward<T>(value));
+ m_elements.append(std::move(value));
}
/**
diff --git a/source/blender/blenlib/BLI_string_map.h b/source/blender/blenlib/BLI_string_map.h
index 2daf192f0a7..ba870eb878a 100644
--- a/source/blender/blenlib/BLI_string_map.h
+++ b/source/blender/blenlib/BLI_string_map.h
@@ -152,20 +152,13 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
return StringRefNull(start, length);
}
- void move_in(uint offset, uint32_t hash, uint32_t index, T &value)
+ template<typename ForwardT>
+ void store(uint offset, uint32_t hash, uint32_t index, ForwardT &&value)
{
BLI_assert(!this->is_set(offset));
m_hashes[offset] = hash;
m_indices[offset] = index;
- new (this->value(offset)) T(std::move(value));
- }
-
- void copy_in(uint offset, uint32_t hash, uint32_t index, const T &value)
- {
- BLI_assert(!this->is_set(offset));
- m_hashes[offset] = hash;
- m_indices[offset] = index;
- new (this->value(offset)) T(value);
+ new (this->value(offset)) T(std::forward<ForwardT>(value));
}
};
@@ -189,18 +182,11 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
*/
void add_new(StringRef key, const T &value)
{
- BLI_assert(!this->contains(key));
- this->ensure_can_add();
- uint32_t hash = this->compute_string_hash(key);
- ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
- if (item.is_empty(offset)) {
- uint32_t index = this->save_key_in_array(key);
- item.copy_in(offset, hash, index, value);
- m_array.update__empty_to_set();
- return;
- }
- }
- ITER_SLOTS_END(offset);
+ this->add_new__impl(key, value);
+ }
+ void add_new(StringRef key, T &&value)
+ {
+ this->add_new__impl(key, std::move(value));
}
/**
@@ -407,7 +393,23 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
{
ITER_SLOTS_BEGIN (hash, new_array, , item, offset) {
if (item.is_empty(offset)) {
- item.move_in(offset, hash, index, value);
+ item.store(offset, hash, index, std::move(value));
+ return;
+ }
+ }
+ ITER_SLOTS_END(offset);
+ }
+
+ template<typename ForwardT> void add_new__impl(StringRef key, ForwardT &&value)
+ {
+ BLI_assert(!this->contains(key));
+ this->ensure_can_add();
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ uint32_t index = this->save_key_in_array(key);
+ item.store(offset, hash, index, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
return;
}
}
diff --git a/source/blender/blenlib/BLI_vector.h b/source/blender/blenlib/BLI_vector.h
index 97357ecd384..46c46a1440f 100644
--- a/source/blender/blenlib/BLI_vector.h
+++ b/source/blender/blenlib/BLI_vector.h
@@ -50,7 +50,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
Allocator m_allocator;
char m_small_buffer[sizeof(T) * N];
-#ifdef DEBUG
+#ifndef NDEBUG
/* Storing size in debug builds, because it makes debugging much easier sometimes. */
uint m_debug_size;
# define UPDATE_VECTOR_SIZE(ptr) (ptr)->m_debug_size = (uint)((ptr)->m_end - (ptr)->m_begin)
@@ -419,7 +419,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
{
BLI_assert(!this->empty());
m_end--;
- T value = *m_end;
+ T value = std::move(*m_end);
destruct(m_end);
UPDATE_VECTOR_SIZE(this);
return value;
@@ -435,7 +435,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
T *element_to_remove = m_begin + index;
m_end--;
if (element_to_remove < m_end) {
- *element_to_remove = *m_end;
+ *element_to_remove = std::move(*m_end);
}
destruct(m_end);
UPDATE_VECTOR_SIZE(this);
@@ -512,6 +512,14 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
return m_end;
}
+ /**
+ * Get the current capacity of the vector.
+ */
+ uint capacity() const
+ {
+ return (uint)(m_capacity_end - m_begin);
+ }
+
void print_stats() const
{
std::cout << "Small Vector at " << (void *)this << ":" << std::endl;
@@ -538,11 +546,6 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
}
}
- uint capacity() const
- {
- return (uint)(m_capacity_end - m_begin);
- }
-
BLI_NOINLINE void grow(uint min_capacity)
{
if (this->capacity() >= min_capacity) {
diff --git a/source/blender/blenlib/BLI_set_vector.h b/source/blender/blenlib/BLI_vector_set.h
index c0b99d568cc..fb21f7ed987 100644
--- a/source/blender/blenlib/BLI_set_vector.h
+++ b/source/blender/blenlib/BLI_vector_set.h
@@ -14,15 +14,15 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_SET_VECTOR_H__
-#define __BLI_SET_VECTOR_H__
+#ifndef __BLI_VECTOR_SET_H__
+#define __BLI_VECTOR_SET_H__
/** \file
* \ingroup bli
*
- * A SetVector is a combination of a set and a vector. The elements are stored in a continuous
- * array, but every element exists at most once. The insertion order is maintained, as long as
- * there are no deletes. The expected time to check if a value is in the SetVector is O(1).
+ * A VectorSet is a set built on top of a vector. The elements are stored in a continuous array,
+ * but every element exists at most once. The insertion order is maintained, as long as there are
+ * no deletes. The expected time to check if a value is in the VectorSet is O(1).
*/
#include "BLI_hash_cxx.h"
@@ -49,7 +49,7 @@ namespace BLI {
// clang-format on
-template<typename T, typename Allocator = GuardedAllocator> class SetVector {
+template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
private:
static constexpr int32_t IS_EMPTY = -1;
static constexpr int32_t IS_DUMMY = -2;
@@ -115,19 +115,22 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector {
Vector<T, 4, Allocator> m_elements;
public:
- SetVector() = default;
+ VectorSet()
+ {
+ BLI_assert(m_array.slots_usable() <= m_elements.capacity());
+ }
- SetVector(ArrayRef<T> values)
+ VectorSet(ArrayRef<T> values) : VectorSet()
{
this->add_multiple(values);
}
- SetVector(const std::initializer_list<T> &values)
+ VectorSet(const std::initializer_list<T> &values) : VectorSet()
{
this->add_multiple(values);
}
- SetVector(const Vector<T> &values)
+ VectorSet(const Vector<T> &values) : VectorSet()
{
this->add_multiple(values);
}
@@ -147,15 +150,11 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector {
*/
void add_new(const T &value)
{
- BLI_assert(!this->contains(value));
- this->ensure_can_add();
- ITER_SLOTS_BEGIN (value, m_array, , slot) {
- if (slot.is_empty()) {
- this->add_new_in_slot(slot, value);
- return;
- }
- }
- ITER_SLOTS_END;
+ this->add_new__impl(value);
+ }
+ void add_new(T &&value)
+ {
+ this->add_new__impl(std::move(value));
}
/**
@@ -163,17 +162,11 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector {
*/
bool add(const T &value)
{
- this->ensure_can_add();
- ITER_SLOTS_BEGIN (value, m_array, , slot) {
- if (slot.is_empty()) {
- this->add_new_in_slot(slot, value);
- return true;
- }
- else if (slot.has_value(value, m_elements)) {
- return false;
- }
- }
- ITER_SLOTS_END;
+ return this->add__impl(value);
+ }
+ bool add(T &&value)
+ {
+ return this->add__impl(std::move(value));
}
/**
@@ -284,16 +277,6 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector {
return m_array.slots_set();
}
- T *begin()
- {
- return m_elements.begin();
- }
-
- T *end()
- {
- return m_elements.end();
- }
-
const T *begin() const
{
return m_elements.begin();
@@ -319,6 +302,15 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector {
return m_elements;
}
+ void print_stats() const
+ {
+ std::cout << "VectorSet at " << (void *)this << ":\n";
+ std::cout << " Size: " << this->size() << "\n";
+ std::cout << " Usable Slots: " << m_array.slots_usable() << "\n";
+ std::cout << " Total Slots: " << m_array.slots_total() << "\n";
+ std::cout << " Average Collisions: " << this->compute_average_collisions() << "\n";
+ }
+
private:
void update_slot_index(T &value, uint old_index, uint new_index)
{
@@ -332,11 +324,11 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector {
ITER_SLOTS_END;
}
- void add_new_in_slot(Slot &slot, const T &value)
+ template<typename ForwardT> void add_new_in_slot(Slot &slot, ForwardT &&value)
{
uint index = m_elements.size();
slot.set_index(index);
- m_elements.append(value);
+ m_elements.append_unchecked(std::forward<ForwardT>(value));
m_array.update__empty_to_set();
}
@@ -356,6 +348,7 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector {
}
m_array = std::move(new_array);
+ m_elements.reserve(m_array.slots_usable());
}
void add_after_grow(uint index, ArrayType &new_array)
@@ -369,6 +362,59 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector {
}
ITER_SLOTS_END;
}
+
+ float compute_average_collisions() const
+ {
+ if (m_elements.size() == 0) {
+ return 0.0f;
+ }
+
+ uint collisions_sum = 0;
+ for (const T &value : m_elements) {
+ collisions_sum += this->count_collisions(value);
+ }
+ return (float)collisions_sum / (float)m_elements.size();
+ }
+
+ uint count_collisions(const T &value) const
+ {
+ uint collisions = 0;
+ ITER_SLOTS_BEGIN (value, m_array, const, slot) {
+ if (slot.is_empty() || slot.has_value(value, m_elements)) {
+ return collisions;
+ }
+ collisions++;
+ }
+ ITER_SLOTS_END;
+ }
+
+ template<typename ForwardT> void add_new__impl(ForwardT &&value)
+ {
+ BLI_assert(!this->contains(value));
+ this->ensure_can_add();
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.is_empty()) {
+ this->add_new_in_slot(slot, std::forward<ForwardT>(value));
+ return;
+ }
+ }
+ ITER_SLOTS_END;
+ }
+
+ template<typename ForwardT> bool add__impl(ForwardT &&value)
+ {
+ this->ensure_can_add();
+ ITER_SLOTS_BEGIN (value, m_array, , slot) {
+ if (slot.is_empty()) {
+ this->add_new_in_slot(slot, std::forward<ForwardT>(value));
+ return true;
+ }
+ else if (slot.has_value(value, m_elements)) {
+ return false;
+ }
+ }
+ ITER_SLOTS_END;
+ }
};
#undef ITER_SLOTS_BEGIN
@@ -376,4 +422,4 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector {
} // namespace BLI
-#endif /* __BLI_SET_VECTOR_H__ */
+#endif /* __BLI_VECTOR_SET_H__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index a5950051f90..f3740b5d39f 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -221,7 +221,6 @@ set(SRC
BLI_rect.h
BLI_scanfill.h
BLI_set.h
- BLI_set_vector.h
BLI_smallhash.h
BLI_sort.h
BLI_sort_utils.h
@@ -248,6 +247,7 @@ set(SRC
BLI_utildefines_variadic.h
BLI_uvproject.h
BLI_vector.h
+ BLI_vector_set.h
BLI_vfontdata.h
BLI_voronoi_2d.h
BLI_voxel.h
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index ae4f5dcebcf..0fe9fd62198 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -325,7 +325,7 @@ void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc, void *userdat
#include "list_sort_impl.h"
#undef SORT_IMPL_FUNC
-/* reentrant call */
+/* re-entrant call */
#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC linklist_sort_fn_r
#include "list_sort_impl.h"
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index f26860afe77..f7239f1b9d1 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -37,7 +37,6 @@
#include "BLI_strict_flags.h" /* keep last */
-#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */
#define CHUNK_LIST_SIZE 16
struct BLI_memblock {
@@ -61,18 +60,19 @@ struct BLI_memblock {
int chunk_len;
};
-BLI_memblock *BLI_memblock_create(uint elem_size)
+BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size)
{
- BLI_assert(elem_size < BLI_MEM_BLOCK_CHUNK_SIZE);
+ BLI_assert(elem_size < chunk_size);
BLI_memblock *mblk = MEM_mallocN(sizeof(BLI_memblock), "BLI_memblock");
mblk->elem_size = (int)elem_size;
mblk->elem_next = 0;
mblk->elem_last = -1;
- mblk->chunk_size = BLI_MEM_BLOCK_CHUNK_SIZE;
+ mblk->chunk_size = (int)chunk_size;
mblk->chunk_len = CHUNK_LIST_SIZE;
mblk->chunk_list = MEM_callocN(sizeof(void *) * (uint)mblk->chunk_len, "chunk list");
- mblk->chunk_list[0] = MEM_callocN((uint)mblk->chunk_size, "BLI_memblock chunk");
+ mblk->chunk_list[0] = MEM_mallocN_aligned((uint)mblk->chunk_size, 32, "BLI_memblock chunk");
+ memset(mblk->chunk_list[0], 0x0, (uint)mblk->chunk_size);
mblk->chunk_max_ofs = (mblk->chunk_size / mblk->elem_size) * mblk->elem_size;
mblk->elem_next_ofs = 0;
mblk->chunk_next = 0;
@@ -143,8 +143,9 @@ void *BLI_memblock_alloc(BLI_memblock *mblk)
}
if (UNLIKELY(mblk->chunk_list[mblk->chunk_next] == NULL)) {
- mblk->chunk_list[mblk->chunk_next] = MEM_callocN((uint)mblk->chunk_size,
- "BLI_memblock chunk");
+ mblk->chunk_list[mblk->chunk_next] = MEM_mallocN_aligned(
+ (uint)mblk->chunk_size, 32, "BLI_memblock chunk");
+ memset(mblk->chunk_list[mblk->chunk_next], 0x0, (uint)mblk->chunk_size);
}
}
return ptr;
@@ -180,3 +181,11 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
}
return ptr;
}
+
+/* Direct access. elem is element index inside the chosen chunk. */
+void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
+{
+ BLI_assert(chunk < mblk->chunk_len);
+ BLI_assert(elem < (mblk->chunk_size / mblk->elem_size));
+ return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem;
+}
diff --git a/source/blender/blenlib/intern/BLI_temporary_allocator.cc b/source/blender/blenlib/intern/BLI_temporary_allocator.cc
index e41cf36f66d..b145e65530d 100644
--- a/source/blender/blenlib/intern/BLI_temporary_allocator.cc
+++ b/source/blender/blenlib/intern/BLI_temporary_allocator.cc
@@ -73,7 +73,7 @@ struct ThreadLocalBuffers {
}
};
-thread_local ThreadLocalBuffers local_storage;
+static thread_local ThreadLocalBuffers local_storage;
void *BLI_temporary_allocate(uint size)
{
diff --git a/source/blender/blenlib/intern/BLI_timer.c b/source/blender/blenlib/intern/BLI_timer.c
index 0443dea9a2e..af987587d90 100644
--- a/source/blender/blenlib/intern/BLI_timer.c
+++ b/source/blender/blenlib/intern/BLI_timer.c
@@ -42,7 +42,6 @@ typedef struct TimedFunction {
typedef struct TimerContainer {
ListBase funcs;
- bool file_load_cb_registered;
} TimerContainer;
static TimerContainer GlobalTimer = {{0}};
diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c
index d5dcd40346f..af4fa9fa54e 100644
--- a/source/blender/blenlib/intern/delaunay_2d.c
+++ b/source/blender/blenlib/intern/delaunay_2d.c
@@ -325,6 +325,18 @@ static bool exists_edge(const CDTVert *a, const CDTVert *b)
return false;
}
+/** Is the vertex v incident on face f? */
+static bool vert_touches_face(const CDTVert *v, const CDTFace *f)
+{
+ SymEdge *se = v->symedge;
+ do {
+ if (se->face == f) {
+ return true;
+ }
+ } while ((se = se->rot) != v->symedge);
+ return false;
+}
+
/**
* Assume s1 and s2 are both SymEdges in a face with > 3 sides,
* and one is not the next of the other.
@@ -1901,35 +1913,108 @@ static void dissolve_symedge(CDT_state *cdt, SymEdge *se)
delete_edge(cdt, se);
}
-static void remove_non_constraint_edges(CDT_state *cdt, const bool valid_bmesh)
+/* Remove all non-constraint edges. */
+static void remove_non_constraint_edges(CDT_state *cdt)
+{
+ LinkNode *ln;
+ CDTEdge *e;
+ SymEdge *se;
+
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ e = (CDTEdge *)ln->link;
+ se = &e->symedges[0];
+ if (!is_deleted_edge(e) && !is_constrained_edge(e)) {
+ dissolve_symedge(cdt, se);
+ }
+ }
+}
+
+/*
+ * Remove the non-constraint edges, but leave enough of them so that all of the
+ * faces that would be bmesh faces (that is, the faces that have some input representative)
+ * are valid: they can't have holes, they can't have repeated vertices, and they can't have
+ * repeated edges.
+ *
+ * Not essential, but to make the result look more aesthetically nice,
+ * remove the edges in order of decreasing length, so that it is more likely that the
+ * final remaining support edges are short, and therefore likely to make a fairly
+ * direct path from an outer face to an inner hole face.
+ */
+
+/* For sorting edges by decreasing length (squared). */
+struct EdgeToSort {
+ double len_squared;
+ CDTEdge *e;
+};
+
+static int edge_to_sort_cmp(const void *a, const void *b)
+{
+ const struct EdgeToSort *e1 = a;
+ const struct EdgeToSort *e2 = b;
+
+ if (e1->len_squared > e2->len_squared) {
+ return -1;
+ }
+ else if (e1->len_squared < e2->len_squared) {
+ return 1;
+ }
+ return 0;
+}
+
+static void remove_non_constraint_edges_leave_valid_bmesh(CDT_state *cdt)
{
LinkNode *ln;
CDTEdge *e;
SymEdge *se, *se2;
CDTFace *fleft, *fright;
bool dissolve;
+ size_t nedges;
+ int i, ndissolvable;
+ const double *co1, *co2;
+ struct EdgeToSort *sorted_edges;
+ nedges = 0;
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ nedges++;
+ }
+ if (nedges == 0) {
+ return;
+ }
+ sorted_edges = BLI_memarena_alloc(cdt->arena, nedges * sizeof(*sorted_edges));
+ i = 0;
for (ln = cdt->edges; ln; ln = ln->next) {
e = (CDTEdge *)ln->link;
- dissolve = !is_deleted_edge(e) && !is_constrained_edge(e);
- if (dissolve) {
- se = &e->symedges[0];
- if (valid_bmesh && !edge_touches_frame(e)) {
- fleft = se->face;
- fright = sym(se)->face;
- if (fleft != cdt->outer_face && fright != cdt->outer_face &&
- (fleft->input_ids != NULL || fright->input_ids != NULL)) {
- /* Is there another symedge with same left and right faces? */
- for (se2 = se->next; dissolve && se2 != se; se2 = se2->next) {
- if (sym(se2)->face == fright) {
- dissolve = false;
- }
+ if (!is_deleted_edge(e) && !is_constrained_edge(e)) {
+ sorted_edges[i].e = e;
+ co1 = e->symedges[0].vert->co;
+ co2 = e->symedges[1].vert->co;
+ sorted_edges[i].len_squared = len_squared_v2v2_db(co1, co2);
+ i++;
+ }
+ }
+ ndissolvable = i;
+ qsort(sorted_edges, ndissolvable, sizeof(*sorted_edges), edge_to_sort_cmp);
+ for (i = 0; i < ndissolvable; i++) {
+ e = sorted_edges[i].e;
+ se = &e->symedges[0];
+ dissolve = true;
+ if (!edge_touches_frame(e)) {
+ fleft = se->face;
+ fright = sym(se)->face;
+ if (fleft != cdt->outer_face && fright != cdt->outer_face &&
+ (fleft->input_ids != NULL || fright->input_ids != NULL)) {
+ /* Is there another symedge with same left and right faces?
+ * Or is there a vertex not part of e touching the same left and right faces? */
+ for (se2 = se->next; dissolve && se2 != se; se2 = se2->next) {
+ if (sym(se2)->face == fright ||
+ (se2->vert != se->next->vert && vert_touches_face(se2->vert, fright))) {
+ dissolve = false;
}
}
}
- if (dissolve) {
- dissolve_symedge(cdt, se);
- }
+ }
+ if (dissolve) {
+ dissolve_symedge(cdt, se);
}
}
}
@@ -2066,8 +2151,11 @@ static void prepare_cdt_for_output(CDT_state *cdt, const CDT_output_type output_
UNUSED_VARS(f);
#endif
- if (output_type == CDT_CONSTRAINTS || output_type == CDT_CONSTRAINTS_VALID_BMESH) {
- remove_non_constraint_edges(cdt, output_type == CDT_CONSTRAINTS_VALID_BMESH);
+ if (output_type == CDT_CONSTRAINTS) {
+ remove_non_constraint_edges(cdt);
+ }
+ else if (output_type == CDT_CONSTRAINTS_VALID_BMESH) {
+ remove_non_constraint_edges_leave_valid_bmesh(cdt);
}
else if (output_type == CDT_FULL || output_type == CDT_INSIDE) {
remove_outer_edges(cdt, output_type == CDT_INSIDE);
diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c
index 14fc4c5bf26..c7631f8991e 100644
--- a/source/blender/blenlib/intern/expr_pylike_eval.c
+++ b/source/blender/blenlib/intern/expr_pylike_eval.c
@@ -504,7 +504,9 @@ static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void *
if (jmp_gap >= 1 && prev_ops[-1].opcode == OPCODE_CONST) {
UnaryOpFunc func = funcptr;
- double result = func(prev_ops[-1].arg.dval);
+ /* volatile because some compilers overly aggressive optimize this call out.
+ * see D6012 for details. */
+ volatile double result = func(prev_ops[-1].arg.dval);
if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
prev_ops[-1].arg.dval = result;
@@ -520,7 +522,9 @@ static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void *
prev_ops[-1].opcode == OPCODE_CONST) {
BinaryOpFunc func = funcptr;
- double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval);
+ /* volatile because some compilers overly aggressive optimize this call out.
+ * see D6012 for details. */
+ volatile double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval);
if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
prev_ops[-2].arg.dval = result;
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 1de8744a6a6..3a45989fb63 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -33,16 +33,24 @@
#include "zlib.h"
#ifdef WIN32
+# include <windows.h>
+# include <shellapi.h>
+# include <shobjidl.h>
# include <io.h>
# include "BLI_winstuff.h"
# include "BLI_fileops_types.h"
# include "utf_winfunc.h"
# include "utfconv.h"
#else
+# if defined(__APPLE__)
+# include <CoreFoundation/CoreFoundation.h>
+# include <objc/runtime.h>
+# include <objc/message.h>
+# endif
# include <sys/param.h>
# include <dirent.h>
# include <unistd.h>
-# include <sys/stat.h>
+# include <sys/wait.h>
#endif
#include "MEM_guardedalloc.h"
@@ -288,6 +296,64 @@ int BLI_access(const char *filename, int mode)
return uaccess(filename, mode);
}
+static bool delete_soft(const wchar_t *path_16, const char **error_message)
+{
+ /* Deletes file or directory to recycling bin. The latter moves all contained files and
+ * directories recursively to the recycling bin as well. */
+ IFileOperation *pfo;
+ IShellItem *pSI;
+
+ HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+
+ if (FAILED(hr)) {
+ *error_message = "Failed to initialize COM";
+ goto error_1;
+ }
+
+ hr = CoCreateInstance(
+ &CLSID_FileOperation, NULL, CLSCTX_ALL, &IID_IFileOperation, (void **)&pfo);
+ if (FAILED(hr)) {
+ *error_message = "Failed to create FileOperation instance";
+ goto error_2;
+ }
+
+ /* Flags for deletion:
+ * FOF_ALLOWUNDO: Enables moving file to recycling bin.
+ * FOF_SILENT: Don't show progress dialog box.
+ * FOF_WANTNUKEWARNING: Show dialog box if file can't be moved to recycling bin. */
+ hr = pfo->lpVtbl->SetOperationFlags(pfo, FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING);
+
+ if (FAILED(hr)) {
+ *error_message = "Failed to set operation flags";
+ goto error_2;
+ }
+
+ hr = SHCreateItemFromParsingName(path_16, NULL, &IID_IShellItem, (void **)&pSI);
+ if (FAILED(hr)) {
+ *error_message = "Failed to parse path";
+ goto error_2;
+ }
+
+ hr = pfo->lpVtbl->DeleteItem(pfo, pSI, NULL);
+ if (FAILED(hr)) {
+ *error_message = "Failed to prepare delete operation";
+ goto error_2;
+ }
+
+ hr = pfo->lpVtbl->PerformOperations(pfo);
+
+ if (FAILED(hr)) {
+ *error_message = "Failed to delete file or directory";
+ }
+
+error_2:
+ pfo->lpVtbl->Release(pfo);
+ CoUninitialize(); /* Has to be uninitialized when CoInitializeEx returns either S_OK or S_FALSE
+ */
+error_1:
+ return FAILED(hr);
+}
+
static bool delete_unique(const char *path, const bool dir)
{
bool err;
@@ -370,6 +436,24 @@ int BLI_delete(const char *file, bool dir, bool recursive)
return err;
}
+/**
+ * Moves the files or directories to the recycling bin.
+ */
+int BLI_delete_soft(const char *file, const char **error_message)
+{
+ int err;
+
+ BLI_assert(!BLI_path_is_rel(file));
+
+ UTF16_ENCODE(file);
+
+ err = delete_soft(file_16, error_message);
+
+ UTF16_UN_ENCODE(file);
+
+ return err;
+}
+
/* Not used anywhere! */
# if 0
int BLI_move(const char *file, const char *to)
@@ -720,6 +804,100 @@ static int delete_single_file(const char *from, const char *UNUSED(to))
return RecursiveOp_Callback_OK;
}
+# ifdef __APPLE__
+static int delete_soft(const char *file, const char **error_message)
+{
+ int ret = -1;
+
+ Class NSAutoreleasePoolClass = objc_getClass("NSAutoreleasePool");
+ SEL allocSel = sel_registerName("alloc");
+ SEL initSel = sel_registerName("init");
+ id poolAlloc = ((id(*)(Class, SEL))objc_msgSend)(NSAutoreleasePoolClass, allocSel);
+ id pool = ((id(*)(id, SEL))objc_msgSend)(poolAlloc, initSel);
+
+ Class NSStringClass = objc_getClass("NSString");
+ SEL stringWithUTF8StringSel = sel_registerName("stringWithUTF8String:");
+ id pathString = ((id(*)(Class, SEL, const char *))objc_msgSend)(
+ NSStringClass, stringWithUTF8StringSel, file);
+
+ Class NSFileManagerClass = objc_getClass("NSFileManager");
+ SEL defaultManagerSel = sel_registerName("defaultManager");
+ id fileManager = ((id(*)(Class, SEL))objc_msgSend)(NSFileManagerClass, defaultManagerSel);
+
+ Class NSURLClass = objc_getClass("NSURL");
+ SEL fileURLWithPathSel = sel_registerName("fileURLWithPath:");
+ id nsurl = ((id(*)(Class, SEL, id))objc_msgSend)(NSURLClass, fileURLWithPathSel, pathString);
+
+ SEL trashItemAtURLSel = sel_registerName("trashItemAtURL:resultingItemURL:error:");
+ BOOL deleteSuccessful = ((BOOL(*)(id, SEL, id, id, id))objc_msgSend)(
+ fileManager, trashItemAtURLSel, nsurl, nil, nil);
+
+ if (deleteSuccessful) {
+ ret = 0;
+ }
+ else {
+ *error_message = "The Cocoa API call to delete file or directory failed";
+ }
+
+ SEL drainSel = sel_registerName("drain");
+ ((void (*)(id, SEL))objc_msgSend)(pool, drainSel);
+
+ return ret;
+}
+# else
+static int delete_soft(const char *file, const char **error_message)
+{
+ const char *args[5];
+ const char *process_failed;
+
+ char *xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP");
+ char *xdg_session_desktop = getenv("XDG_SESSION_DESKTOP");
+
+ if ((xdg_current_desktop != NULL && strcmp(xdg_current_desktop, "KDE") == 0) ||
+ (xdg_session_desktop != NULL && strcmp(xdg_session_desktop, "KDE") == 0)) {
+ args[0] = "kioclient5";
+ args[1] = "move";
+ args[2] = file;
+ args[3] = "trash:/";
+ args[4] = NULL;
+ process_failed = "kioclient5 reported failure";
+ }
+ else {
+ args[0] = "gio";
+ args[1] = "trash";
+ args[2] = file;
+ args[3] = NULL;
+ process_failed = "gio reported failure";
+ }
+
+ int pid = fork();
+
+ if (pid != 0) {
+ /* Parent process */
+ int wstatus = 0;
+
+ waitpid(pid, &wstatus, 0);
+
+ if (!WIFEXITED(wstatus)) {
+ *error_message =
+ "Blender may not support moving files or directories to trash on your system.";
+ return -1;
+ }
+ else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus)) {
+ *error_message = process_failed;
+ return -1;
+ }
+
+ return 0;
+ }
+
+ execvp(args[0], (char **)args);
+
+ *error_message = "Forking process failed.";
+ return -1; /* This should only be reached if execvp fails and stack isn't replaced. */
+}
+# endif
+
FILE *BLI_fopen(const char *filename, const char *mode)
{
BLI_assert(!BLI_path_is_rel(filename));
@@ -770,7 +948,20 @@ int BLI_delete(const char *file, bool dir, bool recursive)
}
/**
- * Do the two paths denote the same filesystem object?
+ * Soft deletes the specified file or directory (depending on dir) by moving the files to the
+ * recycling bin, optionally doing recursive delete of directory contents.
+ *
+ * \return zero on success (matching 'remove' behavior).
+ */
+int BLI_delete_soft(const char *file, const char **error_message)
+{
+ BLI_assert(!BLI_path_is_rel(file));
+
+ return delete_soft(file, error_message);
+}
+
+/**
+ * Do the two paths denote the same file-system object?
*/
static bool check_the_same(const char *path_a, const char *path_b)
{
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
index 6d0fdfacb10..5e1fbf6eade 100644
--- a/source/blender/blenlib/intern/gsqueue.c
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -12,9 +12,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
*/
/** \file
@@ -22,9 +19,6 @@
*
* \brief A generic structure queue
* (a queue for fixed length generally small) structures.
- *
- * \note Only use this if you need (first-in-first-out),
- * otherwise #BLI_Stack is more efficient (first-in-last-out).
*/
#include <string.h>
@@ -35,148 +29,168 @@
#include "BLI_gsqueue.h"
#include "BLI_strict_flags.h"
-typedef struct _GSQueueElem GSQueueElem;
-struct _GSQueueElem {
- GSQueueElem *next;
+/* target chunk size: 64kb */
+#define CHUNK_SIZE_DEFAULT (1 << 16)
+/* ensure we get at least this many elems per chunk */
+#define CHUNK_ELEM_MIN 32
+
+struct QueueChunk {
+ struct QueueChunk *next;
char data[0];
};
struct _GSQueue {
- GSQueueElem *head;
- GSQueueElem *tail;
- size_t elem_size;
+ struct QueueChunk *chunk_first; /* first active chunk to pop from */
+ struct QueueChunk *chunk_last; /* flast active chunk to push onto */
+ struct QueueChunk *chunk_free; /* free chunks to reuse */
+ size_t chunk_first_index; /* index into 'chunk_first' */
+ size_t chunk_last_index; /* index into 'chunk_last' */
+ size_t chunk_elem_max; /* number of elements per chunk */
+ size_t elem_size; /* memory size of elements */
+ size_t totelem; /* total number of elements */
};
-/**
- * Create a new GSQueue.
- *
- * \param elem_size: The size of the structures in the queue.
- * \retval The new queue
- */
-GSQueue *BLI_gsqueue_new(size_t elem_size)
+static void *queue_get_first_elem(GSQueue *queue)
{
- GSQueue *gq = MEM_mallocN(sizeof(*gq), "gqueue_new");
- gq->head = gq->tail = NULL;
- gq->elem_size = elem_size;
-
- return gq;
+ return ((char *)(queue)->chunk_first->data) + ((queue)->elem_size * (queue)->chunk_first_index);
}
-/**
- * Query if the queue is empty
- */
-bool BLI_gsqueue_is_empty(GSQueue *gq)
+static void *queue_get_last_elem(GSQueue *queue)
{
- return (gq->head == NULL);
+ return ((char *)(queue)->chunk_last->data) + ((queue)->elem_size * (queue)->chunk_last_index);
}
/**
- * Query number elements in the queue
+ * \return number of elements per chunk, optimized for slop-space.
*/
-int BLI_gsqueue_len(GSQueue *gq)
+static size_t queue_chunk_elem_max_calc(const size_t elem_size, size_t chunk_size)
{
- GSQueueElem *elem;
- int size = 0;
+ /* get at least this number of elems per chunk */
+ const size_t elem_size_min = elem_size * CHUNK_ELEM_MIN;
- for (elem = gq->head; elem; elem = elem->next) {
- size++;
+ BLI_assert((elem_size != 0) && (chunk_size != 0));
+
+ while (UNLIKELY(chunk_size <= elem_size_min)) {
+ chunk_size <<= 1;
}
- return size;
+ /* account for slop-space */
+ chunk_size -= (sizeof(struct QueueChunk) + MEM_SIZE_OVERHEAD);
+
+ return chunk_size / elem_size;
}
-/**
- * Access the item at the head of the queue
- * without removing it.
- *
- * \param r_item: A pointer to an appropriately
- * sized structure (the size passed to #BLI_gsqueue_new)
- */
-void BLI_gsqueue_peek(GSQueue *gq, void *r_item)
+GSQueue *BLI_gsqueue_new(const size_t elem_size)
{
- memcpy(r_item, &gq->head->data, gq->elem_size);
+ GSQueue *queue = MEM_callocN(sizeof(*queue), "BLI_gsqueue_new");
+
+ queue->chunk_elem_max = queue_chunk_elem_max_calc(elem_size, CHUNK_SIZE_DEFAULT);
+ queue->elem_size = elem_size;
+ /* force init */
+ queue->chunk_last_index = queue->chunk_elem_max - 1;
+
+ return queue;
}
-/**
- * Access the item at the head of the queue
- * and remove it.
- *
- * \param r_item: A pointer to an appropriately
- * sized structure (the size passed to #BLI_gsqueue_new).
- * Can be NULL if desired.
- */
-void BLI_gsqueue_pop(GSQueue *gq, void *r_item)
+static void queue_free_chunk(struct QueueChunk *data)
{
- GSQueueElem *elem = gq->head;
- if (elem == gq->tail) {
- gq->head = gq->tail = NULL;
- }
- else {
- gq->head = gq->head->next;
+ while (data) {
+ struct QueueChunk *data_next = data->next;
+ MEM_freeN(data);
+ data = data_next;
}
+}
- if (r_item) {
- memcpy(r_item, elem->data, gq->elem_size);
- }
- MEM_freeN(elem);
+/**
+ * Free the queue's data and the queue itself
+ */
+void BLI_gsqueue_free(GSQueue *queue)
+{
+ queue_free_chunk(queue->chunk_first);
+ queue_free_chunk(queue->chunk_free);
+ MEM_freeN(queue);
}
/**
- * Push an element onto the tail of the queue.
+ * Copies the source value onto the end of the queue
*
- * \param item: A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new).
+ * \note This copies #GSQueue.elem_size bytes from \a src,
+ * (the pointer itself is not stored).
+ *
+ * \param src: source data to be copied to the queue.
*/
-void BLI_gsqueue_push(GSQueue *gq, const void *item)
+void BLI_gsqueue_push(GSQueue *queue, const void *src)
{
- GSQueueElem *elem;
+ queue->chunk_last_index++;
+ queue->totelem++;
+
+ if (UNLIKELY(queue->chunk_last_index == queue->chunk_elem_max)) {
+ struct QueueChunk *chunk;
+ if (queue->chunk_free) {
+ chunk = queue->chunk_free;
+ queue->chunk_free = chunk->next;
+ }
+ else {
+ chunk = MEM_mallocN(sizeof(*chunk) + (queue->elem_size * queue->chunk_elem_max), __func__);
+ }
- /* compare: prevent events added double in row */
- if (!BLI_gsqueue_is_empty(gq)) {
- if (0 == memcmp(item, gq->head->data, gq->elem_size)) {
- return;
+ chunk->next = NULL;
+
+ if (queue->chunk_last == NULL) {
+ queue->chunk_first = chunk;
+ }
+ else {
+ queue->chunk_last->next = chunk;
}
- }
- elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push");
- memcpy(elem->data, item, gq->elem_size);
- elem->next = NULL;
- if (BLI_gsqueue_is_empty(gq)) {
- gq->tail = gq->head = elem;
- }
- else {
- gq->tail = gq->tail->next = elem;
+ queue->chunk_last = chunk;
+ queue->chunk_last_index = 0;
}
+
+ BLI_assert(queue->chunk_last_index < queue->chunk_elem_max);
+
+ /* Return last of queue */
+ memcpy(queue_get_last_elem(queue), src, queue->elem_size);
}
/**
- * Push an element back onto the head of the queue (so
- * it would be returned from the next call to BLI_gsqueue_pop).
+ * Retrieves and removes the first element from the queue.
+ * The value is copies to \a dst, which must be at least \a elem_size bytes.
*
- * \param item: A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new).
+ * Does not reduce amount of allocated memory.
*/
-void BLI_gsqueue_push_back(GSQueue *gq, const void *item)
+void BLI_gsqueue_pop(GSQueue *queue, void *dst)
{
- GSQueueElem *elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push");
- memcpy(elem->data, item, gq->elem_size);
- elem->next = gq->head;
+ BLI_assert(BLI_gsqueue_is_empty(queue) == false);
- if (BLI_gsqueue_is_empty(gq)) {
- gq->head = gq->tail = elem;
- }
- else {
- gq->head = elem;
+ memcpy(dst, queue_get_first_elem(queue), queue->elem_size);
+ queue->chunk_first_index++;
+ queue->totelem--;
+
+ if (UNLIKELY(queue->chunk_first_index == queue->chunk_elem_max || queue->totelem == 0)) {
+ struct QueueChunk *chunk_free = queue->chunk_first;
+
+ queue->chunk_first = queue->chunk_first->next;
+ queue->chunk_first_index = 0;
+ if (queue->chunk_first == NULL) {
+ queue->chunk_last = NULL;
+ queue->chunk_last_index = queue->chunk_elem_max - 1;
+ }
+
+ chunk_free->next = queue->chunk_free;
+ queue->chunk_free = chunk_free;
}
}
+size_t BLI_gsqueue_len(const GSQueue *queue)
+{
+ return queue->totelem;
+}
+
/**
- * Free the queue
+ * Returns true if the queue is empty, false otherwise
*/
-void BLI_gsqueue_free(GSQueue *gq)
+bool BLI_gsqueue_is_empty(const GSQueue *queue)
{
- while (gq->head) {
- BLI_gsqueue_pop(gq, NULL);
- }
- MEM_freeN(gq);
+ return (queue->chunk_first == NULL);
}
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 232dc245152..fe5f9f7673f 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -312,7 +312,7 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase)
#include "list_sort_impl.h"
#undef SORT_IMPL_FUNC
-/* reentrant call */
+/* re-entrant call */
#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC listbase_sort_fn_r
#include "list_sort_impl.h"
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index e9d196ccdbb..33e272ed7eb 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1146,8 +1146,8 @@ bool invert_m4(float m[4][4])
* \return true on success (i.e. can always find a pivot) and false on failure.
* Mark Segal - 1992.
*
- * \note this is less performant than #EIG_invert_m4_m4 (Eigen), but e.g.
- * for non-invertible scale matrices, findinging a partial solution can
+ * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
+ * for non-invertible scale matrices, finding a partial solution can
* be useful to have a valid local transform center, see T57767.
*/
bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4])
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index a1c3d16a404..235589abdab 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -215,10 +215,10 @@ bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
fdeltav = len_squared_v3(fdelta);
if (trace) {
- printf("START (%g, %g, %g) %g\n", x[0], x[1], x[2], fdeltav);
+ printf("START (%g, %g, %g) %g %g\n", x[0], x[1], x[2], fdeltav, epsilon);
}
- for (int i = 0; i < max_iterations && fdeltav > epsilon; i++) {
+ for (int i = 0; i == 0 || (i < max_iterations && fdeltav > epsilon); i++) {
/* Newton's method step. */
func_jacobian(userdata, x, jacobian);
@@ -248,7 +248,7 @@ bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
}
/* Line search correction. */
- while (next_fdeltav > fdeltav) {
+ while (next_fdeltav > fdeltav && next_fdeltav > epsilon) {
float g0 = sqrtf(fdeltav), g1 = sqrtf(next_fdeltav);
float g01 = -g0 / len_v3(step);
float det = 2.0f * (g1 - g0 - g01);
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index 08c3653153e..c9b0eb3ed5e 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -907,7 +907,7 @@ unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const
return 0;
}
- axis_dominant_v3_to_m3(mat_2d, n);
+ axis_dominant_v3_to_m3_negate(mat_2d, n);
}
/* STEP 1: COUNT POLYS */
diff --git a/source/blender/blenlib/intern/sort.c b/source/blender/blenlib/intern/sort.c
index 225015db00d..4ae87fff535 100644
--- a/source/blender/blenlib/intern/sort.c
+++ b/source/blender/blenlib/intern/sort.c
@@ -90,7 +90,7 @@ BLI_INLINE char *med3(char *a, char *b, char *c, BLI_sort_cmp_t cmp, void *thunk
}
/**
- * Quick sort reentrant.
+ * Quick sort re-entrant.
*/
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
{
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index 76aef3761ae..301675c026e 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -36,10 +36,6 @@
/* ensure we get at least this many elems per chunk */
#define CHUNK_ELEM_MIN 32
-/* Gets the last element in the stack */
-#define CHUNK_LAST_ELEM(_stack) \
- ((void)0, (((char *)(_stack)->chunk_curr->data) + ((_stack)->elem_size * (_stack)->chunk_index)))
-
struct StackChunk {
struct StackChunk *next;
char data[0];
@@ -56,6 +52,11 @@ struct BLI_Stack {
#endif
};
+static void *stack_get_last_elem(BLI_Stack *stack)
+{
+ return ((char *)(stack)->chunk_curr->data) + ((stack)->elem_size * (stack)->chunk_index);
+}
+
/**
* \return number of elements per chunk, optimized for slop-space.
*/
@@ -148,7 +149,7 @@ void *BLI_stack_push_r(BLI_Stack *stack)
#endif
/* Return end of stack */
- return CHUNK_LAST_ELEM(stack);
+ return stack_get_last_elem(stack);
}
/**
@@ -175,7 +176,7 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
- memcpy(dst, CHUNK_LAST_ELEM(stack), stack->elem_size);
+ memcpy(dst, stack_get_last_elem(stack), stack->elem_size);
BLI_stack_discard(stack);
}
@@ -220,7 +221,7 @@ void *BLI_stack_peek(BLI_Stack *stack)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
- return CHUNK_LAST_ELEM(stack);
+ return stack_get_last_elem(stack);
}
/**
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 8d921b062dc..fd5de717a24 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -209,7 +209,6 @@ int BLI_exists(const char *name)
BLI_stat_t st;
wchar_t *tmp_16 = alloc_utf16_from_8(name, 1);
int len, res;
- unsigned int old_error_mode;
len = wcslen(tmp_16);
/* in Windows #stat doesn't recognize dir ending on a slash
@@ -230,14 +229,8 @@ int BLI_exists(const char *name)
tmp_16[3] = L'\0';
}
- /* change error mode so user does not get a "no disk in drive" popup
- * when looking for a file on an empty CD/DVD drive */
- old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
-
res = BLI_wstat(tmp_16, &st);
- SetErrorMode(old_error_mode);
-
free(tmp_16);
if (res == -1) {
return (0);
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 2f6c88c128a..6cdaec97d9a 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -1064,22 +1064,28 @@ BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings *
chunk_size = settings->min_iter_per_thread;
}
else {
- /* Basic heuristic to avoid threading on low amount of items. We could make that limit
- * configurable in settings too... */
- if (tot_items > 0 && tot_items < 256) {
- chunk_size = tot_items;
- }
- /* NOTE: The idea here is to compensate for rather measurable threading
+ /* Multiplier used in heuristics below to define "optimal" chunk size.
+ * The idea here is to increase the chunk size to compensate for a rather measurable threading
* overhead caused by fetching tasks. With too many CPU threads we are starting
- * to spend too much time in those overheads. */
- else if (num_tasks > 32) {
- chunk_size = 128;
- }
- else if (num_tasks > 16) {
- chunk_size = 64;
- }
- else {
- chunk_size = 32;
+ * to spend too much time in those overheads.
+ * First values are: 1 if num_tasks < 16;
+ * else 2 if num_tasks < 32;
+ * else 3 if num_tasks < 48;
+ * else 4 if num_tasks < 64;
+ * etc.
+ * Note: If we wanted to keep the 'power of two' multiplier, we'd need something like:
+ * 1 << max_ii(0, (int)(sizeof(int) * 8) - 1 - bitscan_reverse_i(num_tasks) - 3)
+ */
+ const int num_tasks_factor = max_ii(1, num_tasks >> 3);
+
+ /* We could make that 'base' 32 number configurable in TaskParallelSettings too, or maybe just
+ * always use that heuristic using TaskParallelSettings.min_iter_per_thread as basis? */
+ chunk_size = 32 * num_tasks_factor;
+
+ /* Basic heuristic to avoid threading on low amount of items.
+ * We could make that limit configurable in settings too. */
+ if (tot_items > 0 && tot_items < max_ii(256, chunk_size * 2)) {
+ chunk_size = tot_items;
}
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 6bebcc88e41..2c5134a7dc5 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -24,15 +24,12 @@
#include "zlib.h"
#include <limits.h>
-#include <stdio.h> // for printf fopen fwrite fclose sprintf FILE
-#include <stdlib.h> // for getenv atoi
-#include <stddef.h> // for offsetof
-#include <fcntl.h> // for open
-#include <string.h> // for strrchr strncmp strstr
-#include <math.h> // for fabs
-#include <stdarg.h> /* for va_start/end */
-#include <time.h> /* for gmtime */
-#include <ctype.h> /* for isdigit */
+#include <stdlib.h> /* for atoi. */
+#include <stddef.h> /* for offsetof. */
+#include <fcntl.h> /* for open flags (O_BINARY, O_RDONLY). */
+#include <stdarg.h> /* for va_start/end. */
+#include <time.h> /* for gmtime. */
+#include <ctype.h> /* for isdigit. */
#include "BLI_utildefines.h"
#ifndef WIN32
@@ -96,8 +93,6 @@
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
-#include "RNA_access.h"
-
#include "MEM_guardedalloc.h"
#include "BLI_endian_switch.h"
@@ -180,7 +175,7 @@
* - read associated 'direct data'
* - link direct data (internal and to LibBlock)
* - read #FileGlobal
- * - read #USER data, only when indicated (file is ``~/X.XX/startup.blend``)
+ * - read #USER data, only when indicated (file is `~/.config/blender/X.XX/config/userpref.blend`)
* - free file
* - per Library (per #Main)
* - read file
@@ -2663,6 +2658,7 @@ static void direct_link_id(FileData *fd, ID *id)
* function are still in a clear tag state.
* (glowering at certain nodetree fake data-lock here...). */
id->tag = 0;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
/* Link direct data of overrides. */
if (id->override_library) {
@@ -2834,6 +2830,12 @@ static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
if (pf) {
pf->data = newpackedadr(fd, pf->data);
+ if (pf->data == NULL) {
+ /* We cannot allow a PackedFile with a NULL data field,
+ * the whole code assumes this is not possible. See T70315. */
+ printf("%s: NULL packedfile data, cleaning up...\n", __func__);
+ MEM_SAFE_FREE(pf);
+ }
}
return pf;
@@ -4378,7 +4380,7 @@ static void direct_link_curve(FileData *fd, Curve *cu)
switch_endian_knots(nu);
}
}
- cu->bb = NULL;
+ cu->texflag &= ~CU_AUTOSPACE_EVALUATED;
}
/** \} */
@@ -5045,7 +5047,7 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
- mesh->bb = NULL;
+ mesh->texflag &= ~ME_AUTOSPACE_EVALUATED;
mesh->edit_mesh = NULL;
BKE_mesh_runtime_reset(mesh);
@@ -5749,8 +5751,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
/* runtime only */
- csmd->delta_cache = NULL;
- csmd->delta_cache_num = 0;
+ csmd->delta_cache.deltas = NULL;
+ csmd->delta_cache.totverts = 0;
}
else if (md->type == eModifierType_MeshSequenceCache) {
MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
@@ -7188,6 +7190,8 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
rv3d->render_engine = NULL;
rv3d->sms = NULL;
rv3d->smooth_timer = NULL;
+
+ rv3d->rflag &= ~(RV3D_NAVIGATING | RV3D_PAINTING);
}
}
}
@@ -7286,13 +7290,6 @@ static void direct_link_area(FileData *fd, ScrArea *area)
}
v3d->shading.prev_type = OB_SOLID;
- if (v3d->fx_settings.dof) {
- v3d->fx_settings.dof = newdataadr(fd, v3d->fx_settings.dof);
- }
- if (v3d->fx_settings.ssao) {
- v3d->fx_settings.ssao = newdataadr(fd, v3d->fx_settings.ssao);
- }
-
direct_link_view3dshading(fd, &v3d->shading);
blo_do_versions_view3d_split_250(v3d, &sl->regionbase);
@@ -7899,6 +7896,45 @@ static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
+static int lib_link_main_data_restore_cb(void *user_data,
+ ID *UNUSED(id_self),
+ ID **id_pointer,
+ int cb_flag)
+{
+ if (cb_flag & IDWALK_CB_PRIVATE || *id_pointer == NULL) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* Special ugly case here, thanks again for those non-IDs IDs... */
+ /* We probably need to add more cases here (hint: nodetrees),
+ * but will wait for changes from D5559 to get in first. */
+ if (GS((*id_pointer)->name) == ID_GR) {
+ Collection *collection = (Collection *)*id_pointer;
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return IDWALK_RET_NOP;
+ }
+ }
+
+ struct IDNameLib_Map *id_map = user_data;
+
+ /* Note: Handling of usercount here is really bad, defining its own system...
+ * Will have to be refactored at some point, but that is not top priority task for now.
+ * And all usercounts are properly recomputed at the end of the undo management code anyway. */
+ *id_pointer = restore_pointer_by_name(
+ id_map, *id_pointer, (cb_flag & IDWALK_CB_USER_ONE) ? USER_REAL : USER_IGNORE);
+
+ return IDWALK_RET_NOP;
+}
+
+static void lib_link_main_data_restore(struct IDNameLib_Map *id_map, Main *newmain)
+{
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (newmain, id) {
+ BKE_library_foreach_ID_link(newmain, id, lib_link_main_data_restore_cb, id_map, IDWALK_NOP);
+ }
+ FOREACH_MAIN_ID_END;
+}
+
static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer)
{
bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
@@ -8218,11 +8254,24 @@ void blo_lib_link_restore(Main *oldmain,
/* keep cursor location through undo */
memcpy(&win->scene->cursor, &oldscene->cursor, sizeof(win->scene->cursor));
+ /* Note: even though that function seems to redo part of what is done by
+ * `lib_link_workspace_layout_restore()` above, it seems to have a slightly different scope:
+ * while the former updates the whole UI pointers from Main db (going over all layouts of
+ * all workspaces), that one only focuses one current active screen, takes care of
+ * potential local view, and needs window's scene pointer to be final... */
lib_link_window_scene_data_restore(win, win->scene, cur_view_layer);
BLI_assert(win->screen == NULL);
}
+ /* Restore all ID pointers in Main database itself
+ * (especially IDProperties might point to some word-space of other 'weirdly unchanged' ID
+ * pointers, see T69146).
+ * Note that this will re-apply again a few pointers in workspaces or so,
+ * but since we are remapping final ones already set above,
+ * that is just some minor harmless double-processing. */
+ lib_link_main_data_restore(id_map, newmain);
+
/* update IDs stored in all possible clipboards */
lib_link_clipboard_restore(id_map);
@@ -9110,7 +9159,12 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
return bhead;
}
-static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id)
+static BHead *read_libblock(FileData *fd,
+ Main *main,
+ BHead *bhead,
+ const int tag,
+ const bool placeholder_set_indirect_extern,
+ ID **r_id)
{
/* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
@@ -9230,7 +9284,16 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_LINK_PLACEHOLDER) {
/* That way, we know which data-lock needs do_versions (required currently for linking). */
- id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+ id->tag = tag | LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+
+ if (placeholder_set_indirect_extern) {
+ if (id->flag & LIB_INDIRECT_WEAK_LINK) {
+ id->tag |= LIB_TAG_INDIRECT;
+ }
+ else {
+ id->tag |= LIB_TAG_EXTERN;
+ }
+ }
return blo_bhead_next(fd, bhead);
}
@@ -9793,8 +9856,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
* to the file format definition. So we can use the entry at the
* end of mainlist, added in direct_link_library. */
Main *libmain = mainlist.last;
- bhead = read_libblock(
- fd, libmain, bhead, LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_EXTERN, NULL);
+ bhead = read_libblock(fd, libmain, bhead, 0, true, NULL);
}
break;
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
@@ -9807,7 +9869,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = blo_bhead_next(fd, bhead);
}
else {
- bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL);
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, false, NULL);
}
}
}
@@ -10055,7 +10117,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
if (id == NULL) {
/* ID has not been read yet, add placeholder to the main of the
* library it belongs to, so that it will be read later. */
- read_libblock(fd, libmain, bhead, LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_INDIRECT, NULL);
+ read_libblock(fd, libmain, bhead, LIB_TAG_INDIRECT, false, NULL);
// commented because this can print way too much
// if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name);
@@ -10063,6 +10125,12 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
libmain->curlib->parent = mainvar->curlib;
}
else {
+ /* Convert any previously read weak link to regular link
+ * to signal that we want to read this data-block. */
+ if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
+ }
+
/* "id" is either a placeholder or real ID that is already in the
* main of the library (A) it belongs to. However it might have been
* put there by another library (C) which only updated its own
@@ -10104,9 +10172,15 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
ID *id = is_yet_read(fd, mainvar, bhead);
if (id == NULL) {
- read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, NULL);
+ read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, NULL);
}
else {
+ /* Convert any previously read weak link to regular link
+ * to signal that we want to read this data-block. */
+ if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
+ }
+
/* this is actually only needed on UI call? when ID was already read before,
* and another append happens which invokes same ID...
* in that case the lookup table needs this entry */
@@ -11256,6 +11330,7 @@ static void add_loose_objects_to_scene(Main *mainvar,
BKE_scene_object_base_flag_sync_from_base(base);
ob->id.tag &= ~LIB_TAG_INDIRECT;
+ ob->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
ob->id.tag |= LIB_TAG_EXTERN;
}
}
@@ -11348,6 +11423,7 @@ static void add_collections_to_scene(Main *mainvar,
/* Those are kept for safety and consistency, but should not be needed anymore? */
collection->id.tag &= ~LIB_TAG_INDIRECT;
+ collection->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
collection->id.tag |= LIB_TAG_EXTERN;
}
}
@@ -11372,7 +11448,7 @@ static ID *link_named_part(
if (id == NULL) {
/* not read yet */
const int tag = force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN;
- read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, &id);
+ read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, false, &id);
if (id) {
/* sort by name in list */
@@ -11388,6 +11464,7 @@ static ID *link_named_part(
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) {
id->tag &= ~LIB_TAG_INDIRECT;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
id->tag |= LIB_TAG_EXTERN;
}
}
@@ -11426,7 +11503,7 @@ int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const unsigned int
if (BKE_idcode_is_valid(bhead->code) && BKE_idcode_is_linkable(bhead->code) &&
(id_types_mask == 0 ||
(BKE_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) {
- read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, &id);
+ read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, &id);
num_directly_linked++;
}
@@ -11712,7 +11789,7 @@ static int has_linked_ids_to_read(Main *mainvar)
while (a--) {
for (ID *id = lbarray[a]->first; id; id = id->next) {
- if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) {
return true;
}
}
@@ -11743,11 +11820,12 @@ static void read_library_linked_id(
}
id->tag &= ~LIB_TAG_ID_LINK_PLACEHOLDER;
+ id->flag &= ~LIB_INDIRECT_WEAK_LINK;
if (bhead) {
id->tag |= LIB_TAG_NEED_EXPAND;
// printf("read lib block %s\n", id->name);
- read_libblock(fd, mainvar, bhead, id->tag, r_id);
+ read_libblock(fd, mainvar, bhead, id->tag, false, r_id);
}
else {
blo_reportf_wrap(reports,
@@ -11781,7 +11859,7 @@ static void read_library_linked_ids(FileData *basefd,
while (id) {
ID *id_next = id->next;
- if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) {
BLI_remlink(lbarray[a], id);
/* When playing with lib renaming and such, you may end with cases where
@@ -11817,6 +11895,28 @@ static void read_library_linked_ids(FileData *basefd,
BLI_ghash_free(loaded_ids, NULL, NULL);
}
+static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar)
+{
+ /* Any remaining weak links at this point have been lost, silently drop
+ * those by setting them to NULL pointers. */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a = set_listbasepointers(mainvar, lbarray);
+
+ while (a--) {
+ ID *id = lbarray[a]->first;
+
+ while (id) {
+ ID *id_next = id->next;
+ if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && (id->flag & LIB_INDIRECT_WEAK_LINK)) {
+ /* printf("Dropping weak link to %s\n", id->name); */
+ change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, NULL);
+ BLI_freelinkN(lbarray[a], id);
+ }
+ id = id_next;
+ }
+ }
+}
+
static FileData *read_library_file_data(FileData *basefd,
ListBase *mainlist,
Main *mainl,
@@ -11943,6 +12043,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
Main *main_newid = BKE_main_new();
for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
+ /* Drop weak links for which no data-block was found. */
+ read_library_clear_weak_links(basefd, mainlist, mainptr);
+
/* Do versioning for newly added linked data-locks. If no data-locks
* were read from a library versionfile will still be zero and we can
* skip it. */
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 0a3e592bb15..d8e4f3d97a5 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -1673,15 +1673,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene) {
- Sequence *seq;
- SEQ_BEGIN (scene->ed, seq) {
- if (seq->sat == 0.0f) {
- seq->sat = 1.0f;
- }
+ Sequence *seq;
+ SEQ_BEGIN (scene->ed, seq) {
+ if (seq->sat == 0.0f) {
+ seq->sat = 1.0f;
}
- SEQ_END;
}
+ SEQ_END;
}
/* GSOC 2010 Sculpt - New settings for Brush */
@@ -1696,7 +1694,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
/* will have no effect */
if (brush->alpha == 0) {
- brush->alpha = 0.5f;
+ brush->alpha = 1.0f;
}
/* bad radius */
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 38c19fc647a..a3dc177262e 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1746,7 +1746,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "falloff_angle")) {
for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
br->falloff_angle = DEG2RADF(80);
- br->flag &= ~(BRUSH_FLAG_UNUSED_1 | BRUSH_FLAG_UNUSED_6 | BRUSH_GRAB_ACTIVE_VERTEX |
+ /* These flags are used for new feautres. They are not related to falloff_angle */
+ br->flag &= ~(BRUSH_FLAG_UNUSED_1 | BRUSH_ORIGINAL_PLANE | BRUSH_GRAB_ACTIVE_VERTEX |
BRUSH_SCENE_SPACING | BRUSH_FRONTFACE_FALLOFF);
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 2b88365f0fd..5328d3cb13c 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -585,13 +585,18 @@ static void do_versions_fix_annotations(bGPdata *gpd)
}
}
-static void do_versions_remove_region(ListBase *regionbase, int regiontype)
+static void do_versions_remove_region(ListBase *regionbase, ARegion *ar)
+{
+ BLI_freelinkN(regionbase, ar);
+}
+
+static void do_versions_remove_regions_by_type(ListBase *regionbase, int regiontype)
{
ARegion *ar, *ar_next;
for (ar = regionbase->first; ar; ar = ar_next) {
ar_next = ar->next;
if (ar->regiontype == regiontype) {
- BLI_freelinkN(regionbase, ar);
+ do_versions_remove_region(regionbase, ar);
}
}
}
@@ -1267,6 +1272,22 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
ma->blend_method = MA_BM_BLEND;
}
}
+
+ {
+ /* Update all ruler layers to set new flag. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ bGPdata *gpd = scene->gpd;
+ if (gpd == NULL) {
+ continue;
+ }
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (STREQ(gpl->info, "RulerData3D")) {
+ gpl->flag |= GP_LAYER_IS_RULER;
+ break;
+ }
+ }
+ }
+ }
}
}
@@ -3360,7 +3381,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
/* Remove multiple footers that were added by mistake. */
- do_versions_remove_region(regionbase, RGN_TYPE_FOOTER);
+ do_versions_remove_regions_by_type(regionbase, RGN_TYPE_FOOTER);
/* Add footer. */
ARegion *ar = do_versions_add_region(RGN_TYPE_FOOTER, "footer for text");
@@ -3822,7 +3843,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
ARegion *ar_toolprops = do_versions_find_region_or_null(regionbase,
RGN_TYPE_TOOL_PROPS);
- ARegion *ar_execute = do_versions_find_region_or_null(regionbase, RGN_TYPE_EXECUTE);
/* Reinsert UI region so that it spawns entire area width */
BLI_remlink(regionbase, ar_ui);
@@ -3839,15 +3859,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
BLI_freelinkN(regionbase, ar_toolprops);
}
- if (!ar_execute) {
- ARegion *ar_main = do_versions_find_region(regionbase, RGN_TYPE_WINDOW);
- ar_execute = MEM_callocN(sizeof(ARegion), "versioning execute region for file");
- BLI_insertlinkbefore(regionbase, ar_main, ar_execute);
- ar_execute->regiontype = RGN_TYPE_EXECUTE;
- ar_execute->alignment = RGN_ALIGN_BOTTOM;
- ar_execute->flag |= RGN_FLAG_DYNAMIC_SIZE;
- }
-
if (sfile->params) {
sfile->params->details_flags |= FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME;
}
@@ -3897,8 +3908,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- {
- /* Versioning code until next subversion bump goes here. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 15)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->toolsettings->snap_node_mode == SCE_SNAP_MODE_NODE_X) {
+ scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
+ }
+ }
if (!DNA_struct_elem_find(
fd->filesdna, "LayerCollection", "short", "local_collections_bits")) {
@@ -3910,5 +3925,55 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Fix wrong 3D viewport copying causing corrupt pointers (T69974). */
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+
+ for (ScrArea *sa_other = screen->areabase.first; sa_other; sa_other = sa_other->next) {
+ for (SpaceLink *sl_other = sa_other->spacedata.first; sl_other;
+ sl_other = sl_other->next) {
+ if (sl != sl_other && sl_other->spacetype == SPACE_VIEW3D) {
+ View3D *v3d_other = (View3D *)sl_other;
+
+ if (v3d->shading.prop == v3d_other->shading.prop) {
+ v3d_other->shading.prop = NULL;
+ }
+ }
+ }
+ }
+ }
+ else if (sl->spacetype == SPACE_FILE) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar_tools = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOLS);
+ ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+
+ if (ar_tools) {
+ ARegion *ar_next = ar_tools->next;
+
+ /* We temporarily had two tools regions, get rid of the second one. */
+ if (ar_next && ar_next->regiontype == RGN_TYPE_TOOLS) {
+ do_versions_remove_region(regionbase, ar_next);
+ }
+
+ BLI_remlink(regionbase, ar_tools);
+ BLI_insertlinkafter(regionbase, ar_header, ar_tools);
+ }
+ else {
+ ar_tools = do_versions_add_region(RGN_TYPE_TOOLS, "versioning file tools region");
+ BLI_insertlinkafter(regionbase, ar_header, ar_tools);
+ ar_tools->alignment = RGN_ALIGN_LEFT;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ {
+ /* Versioning code until next subversion bump goes here. */
}
}
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index 52d62725ef8..2c4ba4a1102 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -813,10 +813,10 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
copy_v3_v3(cycles_node_socket_vector_value(sockScale), mapping->size);
bNode *maximumNode = NULL;
- if (mapping->flag & TEXMAP_CLIP_MAX) {
+ if (mapping->flag & TEXMAP_CLIP_MIN) {
maximumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
maximumNode->custom1 = NODE_VECTOR_MATH_MAXIMUM;
- if (mapping->flag & TEXMAP_CLIP_MIN) {
+ if (mapping->flag & TEXMAP_CLIP_MAX) {
maximumNode->locx = node->locx + (node->width + 20.0f) * 2.0f;
}
else {
@@ -824,7 +824,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
}
maximumNode->locy = node->locy;
bNodeSocket *sockMaximumB = BLI_findlink(&maximumNode->inputs, 1);
- copy_v3_v3(cycles_node_socket_vector_value(sockMaximumB), mapping->max);
+ copy_v3_v3(cycles_node_socket_vector_value(sockMaximumB), mapping->min);
bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
@@ -834,7 +834,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
nodeRemLink(ntree, link);
}
}
- if (!(mapping->flag & TEXMAP_CLIP_MIN)) {
+ if (!(mapping->flag & TEXMAP_CLIP_MAX)) {
bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0);
nodeAddLink(ntree, node, sockMappingResult, maximumNode, sockMaximumA);
}
@@ -843,13 +843,13 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
}
bNode *minimumNode = NULL;
- if (mapping->flag & TEXMAP_CLIP_MIN) {
+ if (mapping->flag & TEXMAP_CLIP_MAX) {
minimumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
minimumNode->custom1 = NODE_VECTOR_MATH_MINIMUM;
minimumNode->locx = node->locx + node->width + 20.0f;
minimumNode->locy = node->locy;
bNodeSocket *sockMinimumB = BLI_findlink(&minimumNode->inputs, 1);
- copy_v3_v3(cycles_node_socket_vector_value(sockMinimumB), mapping->min);
+ copy_v3_v3(cycles_node_socket_vector_value(sockMinimumB), mapping->max);
bNodeSocket *sockMinimumResult = nodeFindSocket(minimumNode, SOCK_OUT, "Vector");
bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
@@ -878,7 +878,6 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
AnimData *animData = BKE_animdata_from_id(&ntree->id);
if (animData && animData->action) {
char *nodePath = BLI_sprintfN("nodes[\"%s\"]", node->name);
-
for (FCurve *fcu = animData->action->curves.first; fcu; fcu = fcu->next) {
if (STRPREFIX(fcu->rna_path, nodePath) &&
!BLI_str_endswith(fcu->rna_path, "default_value")) {
@@ -893,11 +892,11 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
else if (BLI_str_endswith(old_fcu_rna_path, "scale")) {
fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[3].default_value");
}
- else if (minimumNode && BLI_str_endswith(old_fcu_rna_path, "min")) {
+ else if (minimumNode && BLI_str_endswith(old_fcu_rna_path, "max")) {
fcu->rna_path = BLI_sprintfN(
"nodes[\"%s\"].%s", minimumNode->name, "inputs[1].default_value");
}
- else if (maximumNode && BLI_str_endswith(old_fcu_rna_path, "max")) {
+ else if (maximumNode && BLI_str_endswith(old_fcu_rna_path, "min")) {
fcu->rna_path = BLI_sprintfN(
"nodes[\"%s\"].%s", maximumNode->name, "inputs[1].default_value");
}
@@ -1093,12 +1092,13 @@ static void update_voronoi_node_crackle(bNodeTree *ntree)
}
}
-/* The coloring property of the Voronoi node was removed. Previously,
+/**
+ * The coloring property of the Voronoi node was removed. Previously,
* if the coloring enum was set to Intensity (0), the voronoi distance
* was returned in all outputs, otherwise, the Cell ID was returned.
* Since we remapped the Fac output in update_voronoi_node_fac_output,
* then to fix this, we relink the Color output to the Distance
- * output if coloring was set to 0, and the otherway around otherwise.
+ * output if coloring was set to 0, and the other way around otherwise.
*/
static void update_voronoi_node_coloring(bNodeTree *ntree)
{
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 87c8869622a..c9fb8b6990b 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -41,11 +41,13 @@
#include "DNA_light_types.h"
#include "BKE_appdir.h"
+#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -285,6 +287,10 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
CURVEMAP_SLOPE_POSITIVE);
}
+ if (ts->sculpt) {
+ ts->sculpt->paint.symmetry_flags |= PAINT_SYMMETRY_FEATHER;
+ }
+
/* Correct default startup UV's. */
Mesh *me = BLI_findstring(&bmain->meshes, "Cube", offsetof(ID, name) + 2);
if (me && (me->totloop == 24) && (me->mloopuv != NULL)) {
@@ -352,6 +358,12 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
scene->audio.flag &= ~AUDIO_SYNC;
scene->flag &= ~SCE_FRAME_DROP;
}
+
+ /* Change default selection mode for Grease Pencil. */
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ ToolSettings *ts = scene->toolsettings;
+ ts->gpencil_selectmode_edit = GP_SELECTMODE_STROKE;
+ }
}
/* Objects */
@@ -407,7 +419,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
/* Enable for UV sculpt (other brush types will be created as needed),
* without this the grab brush will be active but not selectable from the list. */
- Brush *brush = BLI_findstring(&bmain->brushes, "Grab", offsetof(ID, name) + 2);
+ const char *brush_name = "Grab";
+ Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (brush) {
brush->ob_mode |= OB_MODE_EDIT;
}
@@ -415,13 +428,103 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
brush->blur_kernel_radius = 2;
+
+ /* Use full strength for all non-sculpt brushes,
+ * when painting we want to use full color/weight always.
+ *
+ * Note that sculpt is an exception,
+ * it's values are overwritten by #BKE_brush_sculpt_reset below. */
+ brush->alpha = 1.0;
}
{
/* Change the spacing of the Smear brush to 3.0% */
- Brush *brush = BLI_findstring(&bmain->brushes, "Smear", offsetof(ID, name) + 2);
+ const char *brush_name;
+ Brush *brush;
+
+ brush_name = "Smear";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (brush) {
brush->spacing = 3.0;
}
+
+ brush_name = "Draw Sharp";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_DRAW_SHARP;
+ }
+
+ brush_name = "Elastic Deform";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_ELASTIC_DEFORM;
+ }
+
+ brush_name = "Pose";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_POSE;
+ }
+
+ brush_name = "Simplify";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_SIMPLIFY;
+ }
+
+ /* Use the same tool icon color in the brush cursor */
+ for (brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ if (brush->ob_mode & OB_MODE_SCULPT) {
+ BLI_assert(brush->sculpt_tool != 0);
+ BKE_brush_sculpt_reset(brush);
+ }
+ }
+ }
+
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ /* Update Grease Pencil brushes. */
+ Brush *brush;
+
+ /* Pencil brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pencil", "Pencil");
+
+ /* Pen brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pen", "Pen");
+
+ /* Pen Soft brush. */
+ brush = (Brush *)rename_id_for_versioning(bmain, ID_BR, "Draw Soft", "Pencil Soft");
+ if (brush) {
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ }
+
+ /* Ink Pen brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Ink", "Ink Pen");
+
+ /* Ink Pen Rough brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Noise", "Ink Pen Rough");
+
+ /* Marker Bold brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Marker", "Marker Bold");
+
+ /* Marker Chisel brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Block", "Marker Chisel");
+
+ /* Remove useless Fill Area.001 brush. */
+ brush = BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2);
+ if (brush) {
+ BKE_id_delete(bmain, brush);
+ }
+
+ /* Reset all grease pencil brushes. */
+ Scene *scene = bmain->scenes.first;
+ BKE_brush_gpencil_presets(bmain, scene->toolsettings);
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 62bd605a2c2..1b30c7371a2 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -1705,19 +1705,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
/* add default radius values to old curve points */
for (cu = bmain->curves.first; cu; cu = cu->id.next) {
for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu) {
- if (nu->bezt) {
- for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
- if (!bezt->radius) {
- bezt->radius = 1.0;
- }
+ if (nu->bezt) {
+ for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
+ if (!bezt->radius) {
+ bezt->radius = 1.0;
}
}
- else if (nu->bp) {
- for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
- if (!bp->radius) {
- bp->radius = 1.0;
- }
+ }
+ else if (nu->bp) {
+ for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
+ if (!bp->radius) {
+ bp->radius = 1.0;
}
}
}
@@ -2515,17 +2513,15 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
for (cu = bmain->curves.first; cu; cu = cu->id.next) {
for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu) {
- nu->radius_interp = 3;
-
- /* resolu and resolv are now used differently for surfaces
- * rather than using the resolution to define the entire number of divisions,
- * use it for the number of divisions per segment
- */
- if (nu->pntsv > 1) {
- nu->resolu = MAX2(1, (int)(((float)nu->resolu / (float)nu->pntsu) + 0.5f));
- nu->resolv = MAX2(1, (int)(((float)nu->resolv / (float)nu->pntsv) + 0.5f));
- }
+ nu->radius_interp = 3;
+
+ /* resolu and resolv are now used differently for surfaces
+ * rather than using the resolution to define the entire number of divisions,
+ * use it for the number of divisions per segment
+ */
+ if (nu->pntsv > 1) {
+ nu->resolu = MAX2(1, (int)(((float)nu->resolu / (float)nu->pntsu) + 0.5f));
+ nu->resolv = MAX2(1, (int)(((float)nu->resolv / (float)nu->pntsv) + 0.5f));
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 739dc32d1fe..e1ee020940e 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -29,6 +29,8 @@
#include "DNA_curve_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_anim_types.h"
#include "BKE_addon.h"
#include "BKE_colorband.h"
@@ -145,12 +147,18 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_outliner.active);
}
+ if (!USER_VERSION_ATLEAST(281, 14)) {
+ FROM_DEFAULT_V4_UCHAR(space_file.execution_buts);
+ FROM_DEFAULT_V4_UCHAR(tui.icon_folder);
+ FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_before);
+ FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_after);
+ copy_v4_v4_uchar(btheme->space_nla.nla_track, btheme->space_nla.header);
+ }
+
/**
* Include next version bump.
*/
{
- FROM_DEFAULT_V4_UCHAR(space_file.execution_buts);
- FROM_DEFAULT_V4_UCHAR(tui.icon_folder);
}
#undef FROM_DEFAULT_V4_UCHAR
@@ -615,6 +623,24 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
BKE_addon_remove_safe(&userdef->addons, "io_scene_x3d");
}
+ if (!USER_VERSION_ATLEAST(281, 12)) {
+ userdef->render_display_type = USER_RENDER_DISPLAY_WINDOW;
+ userdef->filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW;
+ }
+
+ if (!USER_VERSION_ATLEAST(281, 13)) {
+ userdef->auto_smoothing_new = FCURVE_SMOOTH_CONT_ACCEL;
+
+ if (userdef->file_space_data.display_type == FILE_DEFAULTDISPLAY) {
+ memcpy(
+ &userdef->file_space_data, &U_default.file_space_data, sizeof(userdef->file_space_data));
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(282, 1)) {
+ userdef->file_space_data.filter_id = U_default.file_space_data.filter_id;
+ }
+
/**
* Include next version bump.
*/
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 95b5f91056a..3fe35f7b993 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -26,35 +26,36 @@
* FILE FORMAT
* ===========
*
- * IFF-style structure (but not IFF compatible!)
+ * IFF-style structure (but not IFF compatible!)
*
- * start file:
+ * Start file:
* <pre>
- * BLENDER_V100 12 bytes (version 1.00)
- * V = big endian, v = little endian
- * _ = 4 byte pointer, - = 8 byte pointer
+ * `BLENDER_V100` `12` bytes (version 1.00 is just an example).
+ * `V` = big endian, `v` = little endian.
+ * `_` = 4 byte pointer, `-` = 8 byte pointer.
* </pre>
*
* data-blocks: (also see struct #BHead).
* <pre>
- * <bh.code> 4 chars
- * <bh.len> int, len data after BHead
- * <bh.old> void, old pointer
- * <bh.SDNAnr> int
- * <bh.nr> int, in case of array: number of structs
- * data
- * ...
- * ...
+ * `bh.code` `char[4]` see `BLO_blend_defs.h` for a list of known types.
+ * `bh.len` `int32` length data after #BHead in bytes.
+ * `bh.old` `void *` old pointer (the address at the time of writing the file).
+ * `bh.SDNAnr` `int32` struct index of structs stored in #DNA1 data.
+ * `bh.nr` `int32` in case of array: number of structs.
+ * data
+ * ...
+ * ...
* </pre>
*
* Almost all data in Blender are structures. Each struct saved
* gets a BHead header. With BHead the struct can be linked again
- * and compared with StructDNA .
+ * and compared with #StructDNA.
+
* WRITE
* =====
*
* Preferred writing order: (not really a must, but why would you do it random?)
- * Any case: direct data is ALWAYS after the lib block
+ * Any case: direct data is ALWAYS after the lib block.
*
* (Local file data)
* - for each LibBlock
@@ -2860,12 +2861,6 @@ static void write_area_regions(WriteData *wd, ScrArea *area)
writestruct(wd, DATA, View3D, 1, v3d->localvd);
}
- if (v3d->fx_settings.ssao) {
- writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao);
- }
- if (v3d->fx_settings.dof) {
- writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
- }
write_view3dshading(wd, &v3d->shading);
}
else if (sl->spacetype == SPACE_GRAPH) {
@@ -3644,7 +3639,9 @@ static void write_libraries(WriteData *wd, Main *main)
found_one = false;
while (!found_one && tot--) {
for (id = lbarray[tot]->first; id; id = id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ if (id->us > 0 &&
+ ((id->tag & LIB_TAG_EXTERN) ||
+ ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
found_one = true;
break;
}
@@ -3674,7 +3671,9 @@ static void write_libraries(WriteData *wd, Main *main)
/* Write link placeholders for all direct linked IDs. */
while (a--) {
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ if (id->us > 0 &&
+ ((id->tag & LIB_TAG_EXTERN) ||
+ ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) {
if (!BKE_idcode_is_linkable(GS(id->name))) {
printf(
"ERROR: write file: data-block '%s' from lib '%s' is not linkable "
diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt
index 1b46efb1bb5..0361137f5b1 100644
--- a/source/blender/blentranslation/msgfmt/CMakeLists.txt
+++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt
@@ -32,6 +32,10 @@ set(SRC
add_cc_flags_custom_test(msgfmt)
+if(APPLE)
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
+endif()
+
add_executable(msgfmt ${SRC})
target_link_libraries(msgfmt bf_blenlib)
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 599871a505a..00954eb400c 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -99,6 +99,8 @@ set(SRC
intern/bmesh_mesh.h
intern/bmesh_mesh_conv.c
intern/bmesh_mesh_conv.h
+ intern/bmesh_mesh_duplicate.c
+ intern/bmesh_mesh_duplicate.h
intern/bmesh_mesh_validate.c
intern/bmesh_mesh_validate.h
intern/bmesh_mods.c
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index b7356a89314..bdb719e0d7a 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -216,6 +216,7 @@ extern "C" {
#include "intern/bmesh_marking.h"
#include "intern/bmesh_mesh.h"
#include "intern/bmesh_mesh_conv.h"
+#include "intern/bmesh_mesh_duplicate.h"
#include "intern/bmesh_mesh_validate.h"
#include "intern/bmesh_mods.h"
#include "intern/bmesh_operators.h"
diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.c b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
new file mode 100644
index 00000000000..51f9d2eab1d
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
@@ -0,0 +1,139 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bmesh
+ *
+ * Duplicate geometry from one mesh from another.
+ */
+
+#include "DNA_object_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_alloca.h"
+#include "BLI_math_vector.h"
+
+#include "bmesh.h"
+#include "intern/bmesh_private.h" /* for element checking */
+
+static BMVert *bm_vert_copy(BMesh *bm_src, BMesh *bm_dst, BMVert *v_src)
+{
+ BMVert *v_dst = BM_vert_create(bm_dst, v_src->co, NULL, BM_CREATE_SKIP_CD);
+ BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst);
+ return v_dst;
+}
+
+static BMEdge *bm_edge_copy_with_arrays(BMesh *bm_src,
+ BMesh *bm_dst,
+ BMEdge *e_src,
+ BMVert **verts_dst)
+{
+ BMVert *e_dst_v1 = verts_dst[BM_elem_index_get(e_src->v1)];
+ BMVert *e_dst_v2 = verts_dst[BM_elem_index_get(e_src->v2)];
+ BMEdge *e_dst = BM_edge_create(bm_dst, e_dst_v1, e_dst_v2, NULL, BM_CREATE_SKIP_CD);
+ BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst);
+ return e_dst;
+}
+
+static BMFace *bm_face_copy_with_arrays(
+ BMesh *bm_src, BMesh *bm_dst, BMFace *f_src, BMVert **verts_dst, BMEdge **edges_dst
+
+)
+{
+ BMFace *f_dst;
+ BMVert **vtar = BLI_array_alloca(vtar, f_src->len);
+ BMEdge **edar = BLI_array_alloca(edar, f_src->len);
+ BMLoop *l_iter_src, *l_iter_dst, *l_first_src;
+ int i;
+
+ l_first_src = BM_FACE_FIRST_LOOP(f_src);
+
+ /* Lookup verts & edges. */
+ l_iter_src = l_first_src;
+ i = 0;
+ do {
+ vtar[i] = verts_dst[BM_elem_index_get(l_iter_src->v)];
+ edar[i] = edges_dst[BM_elem_index_get(l_iter_src->e)];
+ i++;
+ } while ((l_iter_src = l_iter_src->next) != l_first_src);
+
+ /* Create new face. */
+ f_dst = BM_face_create(bm_dst, vtar, edar, f_src->len, NULL, BM_CREATE_SKIP_CD);
+
+ /* Copy attributes. */
+ BM_elem_attrs_copy(bm_src, bm_dst, f_src, f_dst);
+
+ /* Copy per-loop custom data. */
+ l_iter_src = l_first_src;
+ l_iter_dst = BM_FACE_FIRST_LOOP(f_dst);
+ do {
+ BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst);
+ } while ((void)(l_iter_dst = l_iter_dst->next), (l_iter_src = l_iter_src->next) != l_first_src);
+
+ return f_dst;
+}
+
+/**
+ * Geometry must be completely isolated.
+ */
+void BM_mesh_copy_arrays(BMesh *bm_src,
+ BMesh *bm_dst,
+ BMVert **verts_src,
+ uint verts_src_len,
+ BMEdge **edges_src,
+ uint edges_src_len,
+ BMFace **faces_src,
+ uint faces_src_len)
+{
+ /* Vertices. */
+ BMVert **verts_dst = MEM_mallocN(sizeof(*verts_dst) * verts_src_len, __func__);
+ for (uint i = 0; i < verts_src_len; i++) {
+ BMVert *v_src = verts_src[i];
+ BM_elem_index_set(v_src, i); /* set_dirty! */
+
+ BMVert *v_dst = bm_vert_copy(bm_src, bm_dst, v_src);
+ BM_elem_index_set(v_dst, i); /* set_ok */
+ verts_dst[i] = v_dst;
+ }
+ bm_src->elem_index_dirty |= BM_VERT;
+ bm_dst->elem_index_dirty &= ~BM_VERT;
+
+ /* Edges. */
+ BMEdge **edges_dst = MEM_mallocN(sizeof(*edges_dst) * edges_src_len, __func__);
+ for (uint i = 0; i < edges_src_len; i++) {
+ BMEdge *e_src = edges_src[i];
+ BM_elem_index_set(e_src, i); /* set_dirty! */
+
+ BMEdge *e_dst = bm_edge_copy_with_arrays(bm_src, bm_dst, e_src, verts_dst);
+ BM_elem_index_set(e_dst, i);
+ edges_dst[i] = e_dst;
+ }
+ bm_src->elem_index_dirty |= BM_EDGE;
+ bm_dst->elem_index_dirty &= ~BM_EDGE;
+
+ /* Faces. */
+ for (uint i = 0; i < faces_src_len; i++) {
+ BMFace *f_src = faces_src[i];
+ BMFace *f_dst = bm_face_copy_with_arrays(bm_src, bm_dst, f_src, verts_dst, edges_dst);
+ BM_elem_index_set(f_dst, i);
+ }
+ bm_dst->elem_index_dirty &= ~BM_FACE;
+
+ /* Cleanup. */
+ MEM_freeN(verts_dst);
+ MEM_freeN(edges_dst);
+}
diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.h b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
new file mode 100644
index 00000000000..17d4071b69f
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef __BMESH_MESH_DUPLICATE_H__
+#define __BMESH_MESH_DUPLICATE_H__
+
+/** \file
+ * \ingroup bmesh
+ */
+
+void BM_mesh_copy_arrays(BMesh *bm_src,
+ BMesh *bm_dst,
+ BMVert **verts_src,
+ uint verts_src_len,
+ BMEdge **edges_src,
+ uint edges_src_len,
+ BMFace **faces_src,
+ uint faces_src_len);
+
+#endif /* __BMESH_MESH_DUPLICATE_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 219bec15e5b..cebfd4df75b 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -2808,6 +2808,91 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
return group_curr;
}
+int BM_mesh_calc_edge_groups_as_arrays(
+ BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int (**r_groups)[3])
+{
+ int(*groups)[3] = MEM_mallocN(sizeof(*groups) * bm->totvert, __func__);
+ STACK_DECLARE(groups);
+ STACK_INIT(groups, bm->totvert);
+
+ /* Clear all selected vertices */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ BMVert **stack = MEM_mallocN(sizeof(*stack) * bm->totvert, __func__);
+ STACK_DECLARE(stack);
+ STACK_INIT(stack, bm->totvert);
+
+ STACK_DECLARE(verts);
+ STACK_INIT(verts, bm->totvert);
+
+ STACK_DECLARE(edges);
+ STACK_INIT(edges, bm->totedge);
+
+ STACK_DECLARE(faces);
+ STACK_INIT(faces, bm->totface);
+
+ BMIter iter;
+ BMVert *v_stack_init;
+ BM_ITER_MESH (v_stack_init, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v_stack_init, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ const uint verts_init = STACK_SIZE(verts);
+ const uint edges_init = STACK_SIZE(edges);
+ const uint faces_init = STACK_SIZE(faces);
+
+ /* Initialize stack. */
+ BM_elem_flag_enable(v_stack_init, BM_ELEM_TAG);
+ STACK_PUSH(verts, v_stack_init);
+
+ if (v_stack_init->e != NULL) {
+ BMVert *v_iter = v_stack_init;
+ do {
+ BMEdge *e_iter, *e_first;
+ e_iter = e_first = v_iter->e;
+ do {
+ if (!BM_elem_flag_test(e_iter, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e_iter, BM_ELEM_TAG);
+ STACK_PUSH(edges, e_iter);
+
+ if (e_iter->l != NULL) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_iter->l;
+ do {
+ if (!BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(l_iter->f, BM_ELEM_TAG);
+ STACK_PUSH(faces, l_iter->f);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ BMVert *v_other = BM_edge_other_vert(e_iter, v_iter);
+ if (!BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+ STACK_PUSH(verts, v_other);
+
+ STACK_PUSH(stack, v_other);
+ }
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_iter)) != e_first);
+ } while ((v_iter = STACK_POP(stack)));
+ }
+
+ int *g = STACK_PUSH_RET(groups);
+ g[0] = STACK_SIZE(verts) - verts_init;
+ g[1] = STACK_SIZE(edges) - edges_init;
+ g[2] = STACK_SIZE(faces) - faces_init;
+ }
+
+ MEM_freeN(stack);
+
+ /* Reduce alloc to required size. */
+ groups = MEM_reallocN(groups, sizeof(*groups) * STACK_SIZE(groups));
+ *r_groups = groups;
+ return STACK_SIZE(groups);
+}
+
float bmesh_subd_falloff_calc(const int falloff, float val)
{
switch (falloff) {
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index 3a864fbb5dd..134e0b99691 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -249,6 +249,13 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
void *user_data,
const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm,
+ BMVert **verts,
+ BMEdge **edges,
+ BMFace **faces,
+ int (**r_groups)[3]) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2, 3, 4, 5);
+
/* not really any good place to put this */
float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 5403043efb4..bad5036f6cf 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -400,7 +400,7 @@ static void bridge_loop_pair(BMesh *bm,
f_example = l_a ? l_a->f : (l_b ? l_b->f : NULL);
if (v_b != v_b_next) {
- BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next};
+ BMVert *v_arr[4] = {v_b, v_b_next, v_a_next, v_a};
f = BM_face_exists(v_arr, 4);
if (f == NULL) {
/* copy if loop data if its is missing on one ring */
@@ -425,7 +425,7 @@ static void bridge_loop_pair(BMesh *bm,
}
}
else {
- BMVert *v_arr[3] = {v_a, v_b, v_a_next};
+ BMVert *v_arr[3] = {v_b, v_a_next, v_a};
f = BM_face_exists(v_arr, 3);
if (f == NULL) {
/* fan-fill a triangle */
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index ff7dcc388b3..64687ac154c 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -1507,7 +1507,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW);
}
- BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001);
+ BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.0000005 * depth);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
index 6422904c83c..ffdcf179491 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.c
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -650,6 +650,8 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
BMEdge *e;
int i;
+ BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE);
+
/* Store all intersections in this array. */
struct EDBMSplitElem(*pair_iter)[2], (*pair_array)[2] = NULL;
BLI_Stack *pair_stack = BLI_stack_new(sizeof(*pair_array), __func__);
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 79593f07383..47325c4dece 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -104,7 +104,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED);
fcu->array_index = 0;
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ fcu->auto_smoothing = U.auto_smoothing_new;
for (unsigned int j = 0; j < curve->getKeyCount(); j++) {
BezTriple bez;
diff --git a/source/blender/collada/BCAnimationCurve.cpp b/source/blender/collada/BCAnimationCurve.cpp
index bf32ec9148c..f944a77196c 100644
--- a/source/blender/collada/BCAnimationCurve.cpp
+++ b/source/blender/collada/BCAnimationCurve.cpp
@@ -383,7 +383,7 @@ void BCAnimationCurve::adjust_range(const int frame_index)
void BCAnimationCurve::add_value(const float val, const int frame_index)
{
FCurve *fcu = get_edit_fcurve();
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ fcu->auto_smoothing = U.auto_smoothing_new;
insert_vert_fcurve(fcu, frame_index, val, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NOFLAGS);
if (fcu->totvert == 1) {
diff --git a/source/blender/collada/BlenderContext.cpp b/source/blender/collada/BlenderContext.cpp
index 8735d71ec40..a9783a9b9c4 100644
--- a/source/blender/collada/BlenderContext.cpp
+++ b/source/blender/collada/BlenderContext.cpp
@@ -21,6 +21,8 @@
#include <vector>
#include "BlenderContext.h"
+#include "ExportSettings.h"
+
#include "BKE_scene.h"
bool bc_is_base_node(LinkNode *export_set, Object *ob, ViewLayer *view_layer)
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index 71201c8a55c..6e31e17fb26 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -107,7 +107,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
/* make absolute source path */
BLI_strncpy(source_path, image->name, sizeof(source_path));
- BLI_path_abs(source_path, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(source_path, ID_BLEND_PATH_FROM_GLOBAL(&image->id));
BLI_cleanup_path(NULL, source_path);
if (use_copies) {
diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp
index a97b5e0eca1..7e834045795 100644
--- a/source/blender/collada/collada_internal.cpp
+++ b/source/blender/collada/collada_internal.cpp
@@ -314,7 +314,7 @@ std::string get_joint_sid(Bone *bone)
{
return translate_id(bone->name);
}
-std::string get_joint_sid(EditBone *bone)
+static std::string get_joint_sid(EditBone *bone)
{
return translate_id(bone->name);
}
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index dd5611c4bef..b688840cb09 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -1149,7 +1149,7 @@ void bc_copy_m4d_v44(double (&r)[4][4], std::vector<std::vector<double>> &a)
/**
* Returns name of Active UV Layer or empty String if no active UV Layer defined
*/
-std::string bc_get_active_uvlayer_name(Mesh *me)
+static std::string bc_get_active_uvlayer_name(Mesh *me)
{
int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (num_layers) {
@@ -1165,7 +1165,7 @@ std::string bc_get_active_uvlayer_name(Mesh *me)
* Returns name of Active UV Layer or empty String if no active UV Layer defined.
* Assuming the Object is of type MESH
*/
-std::string bc_get_active_uvlayer_name(Object *ob)
+static std::string bc_get_active_uvlayer_name(Object *ob)
{
Mesh *me = (Mesh *)ob->data;
return bc_get_active_uvlayer_name(me);
@@ -1174,7 +1174,7 @@ std::string bc_get_active_uvlayer_name(Object *ob)
/**
* Returns UV Layer name or empty string if layer index is out of range
*/
-std::string bc_get_uvlayer_name(Mesh *me, int layer)
+static std::string bc_get_uvlayer_name(Mesh *me, int layer)
{
int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (num_layers && layer < num_layers) {
@@ -1206,7 +1206,7 @@ static bNodeTree *prepare_material_nodetree(Material *ma)
return ma->nodetree;
}
-bNode *bc_add_node(
+static bNode *bc_add_node(
bContext *C, bNodeTree *ntree, int node_type, int locx, int locy, std::string label)
{
bNode *node = nodeAddStaticNode(C, ntree, node_type);
@@ -1221,7 +1221,7 @@ bNode *bc_add_node(
return node;
}
-bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy)
+static bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy)
{
return bc_add_node(C, ntree, node_type, locx, locy, "");
}
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 2a8914c8cd9..f0685b169fa 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -566,6 +566,7 @@ if(WITH_OPENIMAGEDENOISE)
add_definitions(-DOIDN_STATIC_LIB)
list(APPEND INC_SYS
${OPENIMAGEDENOISE_INCLUDE_DIRS}
+ ${TBB_INCLUDE_DIRS}
)
endif()
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index e44dddbcf54..d5a93d21b99 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -179,14 +179,14 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSce
/* Evaluation ----------------------------------- */
+bool DEG_is_evaluating(struct Depsgraph *depsgraph);
+
bool DEG_is_active(const struct Depsgraph *depsgraph);
void DEG_make_active(struct Depsgraph *depsgraph);
void DEG_make_inactive(struct Depsgraph *depsgraph);
/* Evaluation Debug ------------------------------ */
-bool DEG_debug_is_evaluating(struct Depsgraph *depsgraph);
-
void DEG_debug_print_begin(struct Depsgraph *depsgraph);
void DEG_debug_print_eval(struct Depsgraph *depsgraph,
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 37dfaf2c3e2..e24fa9e8996 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -74,6 +74,13 @@ void DEG_graph_build_for_compositor_preview(struct Depsgraph *graph,
struct ViewLayer *view_layer,
struct bNodeTree *nodetree);
+void DEG_graph_build_from_ids(struct Depsgraph *graph,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct ID **ids,
+ const int num_ids);
+
/* Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 82f7f33411a..fb456611b15 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -236,9 +236,21 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
/* Starts traversal from given component of the given ID, invokes callback for every other
* component which is directly on indirectly dependent on the source one. */
+enum {
+ /* Ignore transform solvers which depends on multiple inputs and affects final transform.
+ * Is used for cases like snapping objects which are part of a rigid body simulation:
+ * without this there will be "false-positive" dependencies between transform components of
+ * objects:
+ *
+ * object 1 transform before solver ---> solver ------> object 1 final transform
+ * object 2 transform before solver -----^ \------> object 2 final transform
+ */
+ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS,
+};
void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachIDComponentCallback callback,
void *user_data);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 4cbdd169980..4ca7240abd1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -74,6 +74,10 @@ DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuild
{
}
+DepsgraphBuilder::~DepsgraphBuilder()
+{
+}
+
bool DepsgraphBuilder::need_pull_base_into_graph(Base *base)
{
/* Simple check: enabled bases are always part of dependency graph. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index 040bb6cfeea..97e12e9ceb2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -35,11 +35,13 @@ class DepsgraphBuilderCache;
class DepsgraphBuilder {
public:
- bool need_pull_base_into_graph(Base *base);
+ virtual ~DepsgraphBuilder();
- bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan);
- bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan);
- bool check_pchan_has_bbone_segments(Object *object, const char *bone_name);
+ virtual bool need_pull_base_into_graph(Base *base);
+
+ virtual bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan);
+ virtual bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan);
+ virtual bool check_pchan_has_bbone_segments(Object *object, const char *bone_name);
protected:
/* NOTE: The builder does NOT take ownership over any of those resources. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 88f2f041354..d0e40d49527 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -527,6 +527,9 @@ void DepsgraphNodeBuilder::build_object(int base_index,
eDepsNode_LinkedState_Type linked_state,
bool is_visible)
{
+ if (object->proxy != NULL) {
+ object->proxy->proxy_from = object;
+ }
const bool has_object = built_map_.checkIsBuiltAndTag(object);
/* Skip rest of components if the ID node was already there. */
if (has_object) {
@@ -609,12 +612,8 @@ void DepsgraphNodeBuilder::build_object(int base_index,
build_particle_systems(object, is_visible);
}
/* Proxy object to copy from. */
- if (object->proxy_from != NULL) {
- build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible);
- }
- if (object->proxy_group != NULL) {
- build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible);
- }
+ build_object_proxy_from(object, is_visible);
+ build_object_proxy_group(object, is_visible);
/* Object dupligroup. */
if (object->instance_collection != NULL) {
const bool is_current_parent_collection_visible = is_parent_collection_visible_;
@@ -653,6 +652,22 @@ void DepsgraphNodeBuilder::build_object_flags(int base_index,
is_from_set));
}
+void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_visible)
+{
+ if (object->proxy_from == NULL) {
+ return;
+ }
+ build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible);
+}
+
+void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_visible)
+{
+ if (object->proxy_group == NULL) {
+ return;
+ }
+ build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible);
+}
+
void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible)
{
if (object->data == NULL) {
@@ -900,19 +915,17 @@ void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index
{
/* Create data node for this driver */
ID *id_cow = get_cow_id(id);
- ChannelDriver *driver_orig = fcurve->driver;
/* TODO(sergey): ideally we could pass the COW of fcu, but since it
* has not yet been allocated at this point we can't. As a workaround
* the animation systems allocates an array so we can do a fast lookup
* with the driver index. */
- ensure_operation_node(
- id,
- NodeType::PARAMETERS,
- OperationCode::DRIVER,
- function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig),
- fcurve->rna_path ? fcurve->rna_path : "",
- fcurve->array_index);
+ ensure_operation_node(id,
+ NodeType::PARAMETERS,
+ OperationCode::DRIVER,
+ function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, fcurve),
+ fcurve->rna_path ? fcurve->rna_path : "",
+ fcurve->array_index);
build_driver_variables(id, fcurve);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 65f3521b556..865f60432c1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -93,8 +93,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
return (T *)cow->id.orig_id;
}
- void begin_build();
- void end_build();
+ virtual void begin_build();
+ virtual void end_build();
IDNode *add_id_node(ID *id);
IDNode *find_id_node(ID *id);
@@ -145,71 +145,75 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
OperationNode *find_operation_node(
ID *id, NodeType comp_type, OperationCode opcode, const char *name = "", int name_tag = -1);
- void build_id(ID *id);
+ virtual void build_id(ID *id);
- void build_scene_render(Scene *scene, ViewLayer *view_layer);
- void build_scene_parameters(Scene *scene);
- void build_scene_compositor(Scene *scene);
+ virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
+ virtual void build_scene_parameters(Scene *scene);
+ virtual void build_scene_compositor(Scene *scene);
- void build_layer_collections(ListBase *lb);
- void build_view_layer(Scene *scene,
- ViewLayer *view_layer,
- eDepsNode_LinkedState_Type linked_state);
- void build_collection(LayerCollection *from_layer_collection, Collection *collection);
- void build_object(int base_index,
- Object *object,
- eDepsNode_LinkedState_Type linked_state,
- bool is_visible);
- void build_object_flags(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state);
- void build_object_data(Object *object, bool is_object_visible);
- void build_object_data_camera(Object *object);
- void build_object_data_geometry(Object *object, bool is_object_visible);
- void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible);
- void build_object_data_light(Object *object);
- void build_object_data_lightprobe(Object *object);
- void build_object_data_speaker(Object *object);
- void build_object_transform(Object *object);
- void build_object_constraints(Object *object);
- void build_object_pointcache(Object *object);
- void build_pose_constraints(Object *object,
- bPoseChannel *pchan,
- int pchan_index,
- bool is_object_visible);
- void build_rigidbody(Scene *scene);
- void build_particle_systems(Object *object, bool is_object_visible);
- void build_particle_settings(ParticleSettings *part);
- void build_animdata(ID *id);
- void build_animdata_nlastrip_targets(ListBase *strips);
- void build_animation_images(ID *id);
- void build_action(bAction *action);
- void build_driver(ID *id, FCurve *fcurve, int driver_index);
- void build_driver_variables(ID *id, FCurve *fcurve);
- void build_driver_id_property(ID *id, const char *rna_path);
- void build_parameters(ID *id);
- void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
- void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
- void build_rig(Object *object, bool is_object_visible);
- void build_proxy_rig(Object *object);
- void build_armature(bArmature *armature);
- void build_shapekeys(Key *key);
- void build_camera(Camera *camera);
- void build_light(Light *lamp);
- void build_nodetree(bNodeTree *ntree);
- void build_material(Material *ma);
- void build_materials(Material **materials, int num_materials);
- void build_texture(Tex *tex);
- void build_image(Image *image);
- void build_world(World *world);
- void build_gpencil(bGPdata *gpd);
- void build_cachefile(CacheFile *cache_file);
- void build_mask(Mask *mask);
- void build_movieclip(MovieClip *clip);
- void build_lightprobe(LightProbe *probe);
- void build_speaker(Speaker *speaker);
- void build_sound(bSound *sound);
- void build_scene_sequencer(Scene *scene);
- void build_scene_audio(Scene *scene);
- void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
+ virtual void build_layer_collections(ListBase *lb);
+ virtual void build_view_layer(Scene *scene,
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state);
+ virtual void build_collection(LayerCollection *from_layer_collection, Collection *collection);
+ virtual void build_object(int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state,
+ bool is_visible);
+ virtual void build_object_proxy_from(Object *object, bool is_object_visible);
+ virtual void build_object_proxy_group(Object *object, bool is_object_visible);
+ virtual void build_object_flags(int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state);
+ virtual void build_object_data(Object *object, bool is_object_visible);
+ virtual void build_object_data_camera(Object *object);
+ virtual void build_object_data_geometry(Object *object, bool is_object_visible);
+ virtual void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible);
+ virtual void build_object_data_light(Object *object);
+ virtual void build_object_data_lightprobe(Object *object);
+ virtual void build_object_data_speaker(Object *object);
+ virtual void build_object_transform(Object *object);
+ virtual void build_object_constraints(Object *object);
+ virtual void build_object_pointcache(Object *object);
+ virtual void build_pose_constraints(Object *object,
+ bPoseChannel *pchan,
+ int pchan_index,
+ bool is_object_visible);
+ virtual void build_rigidbody(Scene *scene);
+ virtual void build_particle_systems(Object *object, bool is_object_visible);
+ virtual void build_particle_settings(ParticleSettings *part);
+ virtual void build_animdata(ID *id);
+ virtual void build_animdata_nlastrip_targets(ListBase *strips);
+ virtual void build_animation_images(ID *id);
+ virtual void build_action(bAction *action);
+ virtual void build_driver(ID *id, FCurve *fcurve, int driver_index);
+ virtual void build_driver_variables(ID *id, FCurve *fcurve);
+ virtual void build_driver_id_property(ID *id, const char *rna_path);
+ virtual void build_parameters(ID *id);
+ virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
+ virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
+ virtual void build_rig(Object *object, bool is_object_visible);
+ virtual void build_proxy_rig(Object *object);
+ virtual void build_armature(bArmature *armature);
+ virtual void build_shapekeys(Key *key);
+ virtual void build_camera(Camera *camera);
+ virtual void build_light(Light *lamp);
+ virtual void build_nodetree(bNodeTree *ntree);
+ virtual void build_material(Material *ma);
+ virtual void build_materials(Material **materials, int num_materials);
+ virtual void build_texture(Tex *tex);
+ virtual void build_image(Image *image);
+ virtual void build_world(World *world);
+ virtual void build_gpencil(bGPdata *gpd);
+ virtual void build_cachefile(CacheFile *cache_file);
+ virtual void build_mask(Mask *mask);
+ virtual void build_movieclip(MovieClip *clip);
+ virtual void build_lightprobe(LightProbe *probe);
+ virtual void build_speaker(Speaker *speaker);
+ virtual void build_sound(bSound *sound);
+ virtual void build_scene_sequencer(Scene *scene);
+ virtual void build_scene_audio(Scene *scene);
+ virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
/* Per-ID information about what was already in the dependency graph.
* Allows to re-use certain values, to speed up following evaluation. */
@@ -259,7 +263,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
/* NOTE: Collection are possibly built recursively, so be careful when
* setting the current state. */
Collection *collection_;
- /* Accumulated flag over the hierarchy opf currently building collections.
+ /* Accumulated flag over the hierarchy of currently building collections.
* Denotes whether all the hierarchy from parent of collection_ to the
* very root is visible (aka not restricted.). */
bool is_parent_collection_visible_;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 61e9b83273b..f1e7278ffdb 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -657,20 +657,8 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
build_particle_systems(object);
}
/* Proxy object to copy from. */
- if (object->proxy_from != NULL) {
- /* Object is linked here (comes from the library). */
- build_object(NULL, object->proxy_from);
- ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM);
- ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM);
- add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform");
- }
- if (object->proxy_group != NULL && object->proxy_group != object->proxy) {
- /* Object is local here (local in .blend file, users interacts with it). */
- build_object(NULL, object->proxy_group);
- OperationKey proxy_group_eval_key(
- &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
- add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform");
- }
+ build_object_proxy_from(object);
+ build_object_proxy_group(object);
/* Object dupligroup. */
if (object->instance_collection != NULL) {
build_collection(NULL, object, object->instance_collection);
@@ -685,6 +673,31 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
build_parameters(&object->id);
}
+void DepsgraphRelationBuilder::build_object_proxy_from(Object *object)
+{
+ if (object->proxy_from == NULL) {
+ return;
+ }
+ /* Object is linked here (comes from the library). */
+ build_object(NULL, object->proxy_from);
+ ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM);
+ ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM);
+ add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform");
+}
+
+void DepsgraphRelationBuilder::build_object_proxy_group(Object *object)
+{
+ if (object->proxy_group == NULL || object->proxy_group == object->proxy) {
+ return;
+ }
+ /* Object is local here (local in .blend file, users interacts with it). */
+ build_object(NULL, object->proxy_group);
+ OperationKey proxy_group_eval_key(
+ &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
+ OperationKey transform_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
+ add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform");
+}
+
void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object)
{
if (base == NULL) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index e58ef989ac9..c6a0014577f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -191,93 +191,95 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
void add_customdata_mask(Object *object, const DEGCustomDataMeshMasks &customdata_masks);
void add_special_eval_flag(ID *object, uint32_t flag);
- void build_id(ID *id);
-
- void build_scene_render(Scene *scene, ViewLayer *view_layer);
- void build_scene_parameters(Scene *scene);
- void build_scene_compositor(Scene *scene);
-
- void build_layer_collections(ListBase *lb);
- void build_view_layer(Scene *scene,
- ViewLayer *view_layer,
- eDepsNode_LinkedState_Type linked_state);
- void build_collection(LayerCollection *from_layer_collection,
- Object *object,
- Collection *collection);
- void build_object(Base *base, Object *object);
- void build_object_flags(Base *base, Object *object);
- void build_object_data(Object *object);
- void build_object_data_camera(Object *object);
- void build_object_data_geometry(Object *object);
- void build_object_data_geometry_datablock(ID *obdata);
- void build_object_data_light(Object *object);
- void build_object_data_lightprobe(Object *object);
- void build_object_data_speaker(Object *object);
- void build_object_parent(Object *object);
- void build_object_pointcache(Object *object);
- void build_constraints(ID *id,
- NodeType component_type,
- const char *component_subdata,
- ListBase *constraints,
- RootPChanMap *root_map);
- void build_animdata(ID *id);
- void build_animdata_curves(ID *id);
- void build_animdata_curves_targets(ID *id,
- ComponentKey &adt_key,
- OperationNode *operation_from,
- ListBase *curves);
- void build_animdata_nlastrip_targets(ID *id,
- ComponentKey &adt_key,
- OperationNode *operation_from,
- ListBase *strips);
- void build_animdata_drivers(ID *id);
- void build_animation_images(ID *id);
- void build_action(bAction *action);
- void build_driver(ID *id, FCurve *fcurve);
- void build_driver_data(ID *id, FCurve *fcurve);
- void build_driver_variables(ID *id, FCurve *fcurve);
- void build_driver_id_property(ID *id, const char *rna_path);
- void build_parameters(ID *id);
- void build_world(World *world);
- void build_rigidbody(Scene *scene);
- void build_particle_systems(Object *object);
- void build_particle_settings(ParticleSettings *part);
- void build_particle_system_visualization_object(Object *object,
- ParticleSystem *psys,
- Object *draw_object);
- void build_ik_pose(Object *object,
- bPoseChannel *pchan,
- bConstraint *con,
- RootPChanMap *root_map);
- void build_splineik_pose(Object *object,
- bPoseChannel *pchan,
- bConstraint *con,
- RootPChanMap *root_map);
- void build_rig(Object *object);
- void build_proxy_rig(Object *object);
- void build_shapekeys(Key *key);
- void build_armature(bArmature *armature);
- void build_camera(Camera *camera);
- void build_light(Light *lamp);
- void build_nodetree(bNodeTree *ntree);
- void build_material(Material *ma);
- void build_materials(Material **materials, int num_materials);
- void build_texture(Tex *tex);
- void build_image(Image *image);
- void build_gpencil(bGPdata *gpd);
- void build_cachefile(CacheFile *cache_file);
- void build_mask(Mask *mask);
- void build_movieclip(MovieClip *clip);
- void build_lightprobe(LightProbe *probe);
- void build_speaker(Speaker *speaker);
- void build_sound(bSound *sound);
- void build_scene_sequencer(Scene *scene);
- void build_scene_audio(Scene *scene);
- void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
-
- void build_nested_datablock(ID *owner, ID *id);
- void build_nested_nodetree(ID *owner, bNodeTree *ntree);
- void build_nested_shapekey(ID *owner, Key *key);
+ virtual void build_id(ID *id);
+
+ virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
+ virtual void build_scene_parameters(Scene *scene);
+ virtual void build_scene_compositor(Scene *scene);
+
+ virtual void build_layer_collections(ListBase *lb);
+ virtual void build_view_layer(Scene *scene,
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state);
+ virtual void build_collection(LayerCollection *from_layer_collection,
+ Object *object,
+ Collection *collection);
+ virtual void build_object(Base *base, Object *object);
+ virtual void build_object_proxy_from(Object *object);
+ virtual void build_object_proxy_group(Object *object);
+ virtual void build_object_flags(Base *base, Object *object);
+ virtual void build_object_data(Object *object);
+ virtual void build_object_data_camera(Object *object);
+ virtual void build_object_data_geometry(Object *object);
+ virtual void build_object_data_geometry_datablock(ID *obdata);
+ virtual void build_object_data_light(Object *object);
+ virtual void build_object_data_lightprobe(Object *object);
+ virtual void build_object_data_speaker(Object *object);
+ virtual void build_object_parent(Object *object);
+ virtual void build_object_pointcache(Object *object);
+ virtual void build_constraints(ID *id,
+ NodeType component_type,
+ const char *component_subdata,
+ ListBase *constraints,
+ RootPChanMap *root_map);
+ virtual void build_animdata(ID *id);
+ virtual void build_animdata_curves(ID *id);
+ virtual void build_animdata_curves_targets(ID *id,
+ ComponentKey &adt_key,
+ OperationNode *operation_from,
+ ListBase *curves);
+ virtual void build_animdata_nlastrip_targets(ID *id,
+ ComponentKey &adt_key,
+ OperationNode *operation_from,
+ ListBase *strips);
+ virtual void build_animdata_drivers(ID *id);
+ virtual void build_animation_images(ID *id);
+ virtual void build_action(bAction *action);
+ virtual void build_driver(ID *id, FCurve *fcurve);
+ virtual void build_driver_data(ID *id, FCurve *fcurve);
+ virtual void build_driver_variables(ID *id, FCurve *fcurve);
+ virtual void build_driver_id_property(ID *id, const char *rna_path);
+ virtual void build_parameters(ID *id);
+ virtual void build_world(World *world);
+ virtual void build_rigidbody(Scene *scene);
+ virtual void build_particle_systems(Object *object);
+ virtual void build_particle_settings(ParticleSettings *part);
+ virtual void build_particle_system_visualization_object(Object *object,
+ ParticleSystem *psys,
+ Object *draw_object);
+ virtual void build_ik_pose(Object *object,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
+ virtual void build_splineik_pose(Object *object,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
+ virtual void build_rig(Object *object);
+ virtual void build_proxy_rig(Object *object);
+ virtual void build_shapekeys(Key *key);
+ virtual void build_armature(bArmature *armature);
+ virtual void build_camera(Camera *camera);
+ virtual void build_light(Light *lamp);
+ virtual void build_nodetree(bNodeTree *ntree);
+ virtual void build_material(Material *ma);
+ virtual void build_materials(Material **materials, int num_materials);
+ virtual void build_texture(Tex *tex);
+ virtual void build_image(Image *image);
+ virtual void build_gpencil(bGPdata *gpd);
+ virtual void build_cachefile(CacheFile *cache_file);
+ virtual void build_mask(Mask *mask);
+ virtual void build_movieclip(MovieClip *clip);
+ virtual void build_lightprobe(LightProbe *probe);
+ virtual void build_speaker(Speaker *speaker);
+ virtual void build_sound(bSound *sound);
+ virtual void build_scene_sequencer(Scene *scene);
+ virtual void build_scene_audio(Scene *scene);
+ virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
+
+ virtual void build_nested_datablock(ID *owner, ID *id);
+ virtual void build_nested_nodetree(ID *owner, bNodeTree *ntree);
+ virtual void build_nested_shapekey(ID *owner, Key *key);
void add_particle_collision_relations(const OperationKey &key,
Object *object,
@@ -290,8 +292,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
bool add_absorption,
const char *name);
- void build_copy_on_write_relations();
- void build_copy_on_write_relations(IDNode *id_node);
+ virtual void build_copy_on_write_relations();
+ virtual void build_copy_on_write_relations(IDNode *id_node);
template<typename KeyType> OperationNode *find_operation_node(const KeyType &key);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index e53ac40f196..180499519f6 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -280,7 +280,11 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
else if (RNA_struct_is_a(ptr->type, &RNA_Mesh) || RNA_struct_is_a(ptr->type, &RNA_Modifier) ||
RNA_struct_is_a(ptr->type, &RNA_GpencilModifier) ||
RNA_struct_is_a(ptr->type, &RNA_Spline) || RNA_struct_is_a(ptr->type, &RNA_TextBox) ||
- RNA_struct_is_a(ptr->type, &RNA_GPencilLayer)) {
+ RNA_struct_is_a(ptr->type, &RNA_GPencilLayer) ||
+ RNA_struct_is_a(ptr->type, &RNA_LatticePoint) ||
+ RNA_struct_is_a(ptr->type, &RNA_MeshUVLoop) ||
+ RNA_struct_is_a(ptr->type, &RNA_MeshLoopColor) ||
+ RNA_struct_is_a(ptr->type, &RNA_VertexGroupElement)) {
/* When modifier is used as FROM operation this is likely referencing to
* the property (for example, modifier's influence).
* But when it's used as TO operation, this is geometry component. */
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index dcdea87fe1a..8f9595d2476 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -76,7 +76,7 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
ctime(BKE_scene_frame_get(scene)),
scene_cow(NULL),
is_active(false),
- debug_is_evaluating(false),
+ is_evaluating(false),
is_render_pipeline_depsgraph(false)
{
BLI_spin_init(&lock);
@@ -334,6 +334,12 @@ void DEG_graph_free(Depsgraph *graph)
OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph);
}
+bool DEG_is_evaluating(struct Depsgraph *depsgraph)
+{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ return deg_graph->is_evaluating;
+}
+
bool DEG_is_active(const struct Depsgraph *depsgraph)
{
if (depsgraph == NULL) {
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 30ae4edde34..43829f4e045 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -198,7 +198,7 @@ struct Depsgraph {
int debug_flags;
string debug_name;
- bool debug_is_evaluating;
+ bool is_evaluating;
/* Is set to truth for dependency graph which are used for post-processing (compositor and
* sequencer).
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 968ed8ef403..f67ab381c79 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -59,6 +59,7 @@ extern "C" {
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
+#include "intern/depsgraph_registry.h"
#include "intern/depsgraph_type.h"
/* ****************** */
@@ -323,6 +324,147 @@ void DEG_graph_build_for_compositor_preview(
}
}
+/* Optimized builders for dependency graph built from a given set of IDs.
+ *
+ * General notes:
+ *
+ * - We pull in all bases if their objects are in the set of IDs. This allows to have proper
+ * visibility and other flags assigned to the objects.
+ * All other bases (the ones which points to object which is outside of the set of IDs) are
+ * completely ignored.
+ *
+ * - Proxy groups pointing to objects which are outside of the IDs set are also ignored.
+ * This way we avoid high-poly character body pulled into the dependency graph when it's coming
+ * from a library into an animation file and the dependency graph constructed for a proxy rig. */
+
+namespace DEG {
+namespace {
+
+class DepsgraphFromIDsFilter {
+ public:
+ DepsgraphFromIDsFilter(ID **ids, const int num_ids)
+ {
+ for (int i = 0; i < num_ids; ++i) {
+ ids_.insert(ids[0]);
+ }
+ }
+
+ bool contains(ID *id)
+ {
+ return ids_.find(id) != ids_.end();
+ }
+
+ protected:
+ set<ID *> ids_;
+};
+
+class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder {
+ public:
+ DepsgraphFromIDsNodeBuilder(
+ Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache, ID **ids, const int num_ids)
+ : DepsgraphNodeBuilder(bmain, graph, cache), filter_(ids, num_ids)
+ {
+ }
+
+ virtual bool need_pull_base_into_graph(Base *base) override
+ {
+ if (!filter_.contains(&base->object->id)) {
+ return false;
+ }
+ return DepsgraphNodeBuilder::need_pull_base_into_graph(base);
+ }
+
+ virtual void build_object_proxy_group(Object *object, bool is_visible) override
+ {
+ if (object->proxy_group == NULL) {
+ return;
+ }
+ if (!filter_.contains(&object->proxy_group->id)) {
+ return;
+ }
+ DepsgraphNodeBuilder::build_object_proxy_group(object, is_visible);
+ }
+
+ protected:
+ DepsgraphFromIDsFilter filter_;
+};
+
+class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder {
+ public:
+ DepsgraphFromIDsRelationBuilder(
+ Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache, ID **ids, const int num_ids)
+ : DepsgraphRelationBuilder(bmain, graph, cache), filter_(ids, num_ids)
+ {
+ }
+
+ virtual bool need_pull_base_into_graph(Base *base) override
+ {
+ if (!filter_.contains(&base->object->id)) {
+ return false;
+ }
+ return DepsgraphRelationBuilder::need_pull_base_into_graph(base);
+ }
+
+ virtual void build_object_proxy_group(Object *object) override
+ {
+ if (object->proxy_group == NULL) {
+ return;
+ }
+ if (!filter_.contains(&object->proxy_group->id)) {
+ return;
+ }
+ DepsgraphRelationBuilder::build_object_proxy_group(object);
+ }
+
+ protected:
+ DepsgraphFromIDsFilter filter_;
+};
+
+} // namespace
+} // namespace DEG
+
+void DEG_graph_build_from_ids(Depsgraph *graph,
+ Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ID **ids,
+ const int num_ids)
+{
+ double start_time = 0.0;
+ if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) {
+ start_time = PIL_check_seconds_timer();
+ }
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ /* Perform sanity checks. */
+ BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1);
+ BLI_assert(deg_graph->scene == scene);
+ BLI_assert(deg_graph->view_layer == view_layer);
+ DEG::DepsgraphBuilderCache builder_cache;
+ /* Generate all the nodes in the graph first */
+ DEG::DepsgraphFromIDsNodeBuilder node_builder(bmain, deg_graph, &builder_cache, ids, num_ids);
+ node_builder.begin_build();
+ node_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY);
+ for (int i = 0; i < num_ids; ++i) {
+ node_builder.build_id(ids[i]);
+ }
+ node_builder.end_build();
+ /* Hook up relationships between operations - to determine evaluation order. */
+ DEG::DepsgraphFromIDsRelationBuilder relation_builder(
+ bmain, deg_graph, &builder_cache, ids, num_ids);
+ relation_builder.begin_build();
+ relation_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY);
+ for (int i = 0; i < num_ids; ++i) {
+ relation_builder.build_id(ids[i]);
+ }
+ relation_builder.build_copy_on_write_relations();
+ /* Finalize building. */
+ graph_build_finalize_common(deg_graph, bmain);
+ /* Finish statistics. */
+ if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) {
+ printf("Depsgraph built in %f seconds.\n", PIL_check_seconds_timer() - start_time);
+ }
+}
+
/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
@@ -356,12 +498,7 @@ void DEG_graph_relations_update(Depsgraph *graph, Main *bmain, Scene *scene, Vie
void DEG_relations_tag_update(Main *bmain)
{
DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__);
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
- if (depsgraph != NULL) {
- DEG_graph_tag_relations_update(depsgraph);
- }
- }
+ for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
+ DEG_graph_tag_relations_update(reinterpret_cast<Depsgraph *>(depsgraph));
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index d079c958e04..bb60db5209c 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -246,12 +246,6 @@ void DEG_stats_simple(const Depsgraph *graph,
}
}
-bool DEG_debug_is_evaluating(struct Depsgraph *depsgraph)
-{
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
- return deg_graph->debug_is_evaluating;
-}
-
static DEG::string depsgraph_name_for_logging(struct Depsgraph *depsgraph)
{
const char *name = DEG_debug_name_get(depsgraph);
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index b2b7d2a9d00..665a32b886c 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -73,7 +73,7 @@ void DEG_evaluate_on_framechange(Main *bmain, Depsgraph *graph, float ctime)
/* Update time on primary timesource. */
DEG::TimeSourceNode *tsrc = deg_graph->find_time_source();
tsrc->cfra = ctime;
- tsrc->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_TIME);
+ deg_graph->need_update_time = true;
DEG::deg_graph_flush_updates(bmain, deg_graph);
/* Update time in scene. */
if (deg_graph->scene_cow) {
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index 33cb1ba7416..b7a40fb69bd 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -68,9 +68,20 @@ void deg_foreach_clear_flags(const Depsgraph *graph)
}
}
+bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags)
+{
+ if (flags & DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS) {
+ if (op_node->opcode == OperationCode::RIGIDBODY_SIM) {
+ return false;
+ }
+ }
+ return true;
+}
+
void deg_foreach_dependent_operation(const Depsgraph *graph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachOperation callback,
void *user_data)
{
@@ -91,6 +102,9 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
continue;
}
for (OperationNode *op_node : comp_node->operations) {
+ if (!deg_foreach_needs_visit(op_node, flags)) {
+ continue;
+ }
queue.push_back(op_node);
op_node->scheduled = true;
op_node->owner->custom_flags |= DEG_NODE_VISITED;
@@ -108,7 +122,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
/* Schedule outgoing operation nodes. */
if (op_node->outlinks.size() == 1) {
OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to;
- if (to_node->scheduled == false) {
+ if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) {
to_node->scheduled = true;
op_node = to_node;
}
@@ -119,7 +133,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
else {
for (Relation *rel : op_node->outlinks) {
OperationNode *to_node = (OperationNode *)rel->to;
- if (to_node->scheduled == false) {
+ if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) {
queue.push_front(to_node);
to_node->scheduled = true;
}
@@ -150,6 +164,7 @@ void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user
void deg_foreach_dependent_ID_component(const Depsgraph *graph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachIDComponentCallback callback,
void *user_data)
{
@@ -157,7 +172,7 @@ void deg_foreach_dependent_ID_component(const Depsgraph *graph,
data.callback = callback;
data.user_data = user_data;
deg_foreach_dependent_operation(
- graph, id, source_component_type, deg_foreach_dependent_component_callback, &data);
+ graph, id, source_component_type, flags, deg_foreach_dependent_component_callback, &data);
}
struct ForeachIDData {
@@ -185,7 +200,7 @@ void deg_foreach_dependent_ID(const Depsgraph *graph,
data.callback = callback;
data.user_data = user_data;
deg_foreach_dependent_operation(
- graph, id, DEG_OB_COMP_ANY, deg_foreach_dependent_ID_callback, &data);
+ graph, id, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data);
}
void deg_foreach_ancestor_ID(const Depsgraph *graph,
@@ -278,11 +293,12 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph,
const ID *id,
eDepsObjectComponentType source_component_type,
+ int flags,
DEGForeachIDComponentCallback callback,
void *user_data)
{
DEG::deg_foreach_dependent_ID_component(
- (const DEG::Depsgraph *)depsgraph, id, source_component_type, callback, user_data);
+ (const DEG::Depsgraph *)depsgraph, id, source_component_type, flags, callback, user_data);
}
void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 251857b58c9..db469612f76 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -146,11 +146,13 @@ bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
*temp_dupli_object = *dob->ob;
temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROM_DUPLI;
temp_dupli_object->base_local_view_bits = dupli_parent->base_local_view_bits;
+ temp_dupli_object->runtime.local_collections_bits =
+ dupli_parent->runtime.local_collections_bits;
temp_dupli_object->dt = MIN2(temp_dupli_object->dt, dupli_parent->dt);
copy_v4_v4(temp_dupli_object->color, dupli_parent->color);
/* Duplicated elements shouldn't care whether their original collection is visible or not. */
- temp_dupli_object->base_flag |= BASE_VISIBLE;
+ temp_dupli_object->base_flag |= BASE_VISIBLE_DEPSGRAPH;
int ob_visibility = BKE_object_visibility(temp_dupli_object, data->eval_mode);
if ((ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) == 0) {
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 2fdce0e30a5..ce5917110d6 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -367,7 +367,7 @@ static void graph_id_tag_update_single_flag(Main *bmain,
eUpdateSource update_source)
{
if (tag == ID_RECALC_EDITORS) {
- if (graph != NULL) {
+ if (graph != NULL && graph->is_active) {
depsgraph_update_editors_tag(bmain, graph, id);
}
return;
@@ -462,7 +462,8 @@ const char *update_source_as_string(eUpdateSource source)
int deg_recalc_flags_for_legacy_zero()
{
- return ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE);
+ return ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE |
+ ID_RECALC_TIME | ID_RECALC_EDITORS);
}
int deg_recalc_flags_effective(Depsgraph *graph, int flags)
@@ -510,6 +511,14 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti
* to evaluation though) with `do_time=true`. This means early output checks should be aware of
* this. */
for (DEG::IDNode *id_node : graph->id_nodes) {
+ const ID_Type id_type = GS(id_node->id_orig->name);
+ if (id_type == ID_OB) {
+ Object *object_orig = reinterpret_cast<Object *>(id_node->id_orig);
+ if (object_orig->proxy != NULL) {
+ object_orig->proxy->proxy_from = object_orig;
+ }
+ }
+
if (!id_node->visible_components_mask) {
/* ID has no components which affects anything visible.
* No need bother with it to tag or anything. */
@@ -536,7 +545,6 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti
* other type of cache).
*
* TODO(sergey): Need to generalize this somehow. */
- const ID_Type id_type = GS(id_node->id_orig->name);
if (id_type == ID_OB) {
flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY;
}
@@ -614,6 +622,12 @@ void graph_id_tag_update(
Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source)
{
const int debug_flags = (graph != NULL) ? DEG_debug_flags_get((::Depsgraph *)graph) : G.debug;
+ if (graph != NULL && graph->is_evaluating) {
+ if (debug_flags & G_DEBUG_DEPSGRAPH) {
+ printf("ID tagged for update during dependency graph evaluation.");
+ }
+ return;
+ }
if (debug_flags & G_DEBUG_DEPSGRAPH_TAG) {
printf("%s: id=%s flags=%s source=%s\n",
__func__,
@@ -808,24 +822,6 @@ static void deg_graph_clear_id_recalc_flags(ID *id)
}
}
-static void deg_graph_clear_id_node_func(void *__restrict data_v,
- const int i,
- const TaskParallelTLS *__restrict /*tls*/)
-{
- /* TODO: we clear original ID recalc flags here, but this may not work
- * correctly when there are multiple depsgraph with others still using
- * the recalc flag. */
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(data_v);
- DEG::IDNode *id_node = deg_graph->id_nodes[i];
-
- id_node->is_user_modified = false;
-
- deg_graph_clear_id_recalc_flags(id_node->id_cow);
- if (deg_graph->is_active) {
- deg_graph_clear_id_recalc_flags(id_node->id_orig);
- }
-}
-
void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
@@ -835,10 +831,15 @@ void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph)
return;
}
/* Go over all ID nodes nodes, clearing tags. */
- const int num_id_nodes = deg_graph->id_nodes.size();
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 1024;
- BLI_task_parallel_range(0, num_id_nodes, deg_graph, deg_graph_clear_id_node_func, &settings);
+ for (DEG::IDNode *id_node : deg_graph->id_nodes) {
+ /* TODO: we clear original ID recalc flags here, but this may not work
+ * correctly when there are multiple depsgraph with others still using
+ * the recalc flag. */
+ id_node->is_user_modified = false;
+ deg_graph_clear_id_recalc_flags(id_node->id_cow);
+ if (deg_graph->is_active) {
+ deg_graph_clear_id_recalc_flags(id_node->id_orig);
+ }
+ }
memset(deg_graph->id_type_updated, 0, sizeof(deg_graph->id_type_updated));
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index b2415c9e89d..d6b3c54a149 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -91,10 +91,6 @@ static void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id)
BLI_task_pool_delayed_push_end(pool, thread_id);
}
-struct CalculatePendingData {
- Depsgraph *graph;
-};
-
static bool check_operation_node_visible(OperationNode *op_node)
{
const ComponentNode *comp_node = op_node->owner;
@@ -106,13 +102,8 @@ static bool check_operation_node_visible(OperationNode *op_node)
return comp_node->affects_directly_visible;
}
-static void calculate_pending_func(void *__restrict data_v,
- const int i,
- const TaskParallelTLS *__restrict /*tls*/)
+static void calculate_pending_parents_for_node(OperationNode *node)
{
- CalculatePendingData *data = (CalculatePendingData *)data_v;
- Depsgraph *graph = data->graph;
- OperationNode *node = graph->operations[i];
/* Update counters, applies for both visible and invisible IDs. */
node->num_links_pending = 0;
node->scheduled = false;
@@ -134,7 +125,7 @@ static void calculate_pending_func(void *__restrict data_v,
if (!check_operation_node_visible(from)) {
continue;
}
- /* No need to vait for operation which is up to date. */
+ /* No need to wait for operation which is up to date. */
if ((from->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) {
continue;
}
@@ -145,13 +136,9 @@ static void calculate_pending_func(void *__restrict data_v,
static void calculate_pending_parents(Depsgraph *graph)
{
- const int num_operations = graph->operations.size();
- CalculatePendingData data;
- data.graph = graph;
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 1024;
- BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, &settings);
+ for (OperationNode *node : graph->operations) {
+ calculate_pending_parents_for_node(node);
+ }
}
static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph)
@@ -221,7 +208,7 @@ static void schedule_node(
static void schedule_graph(TaskPool *pool, Depsgraph *graph)
{
for (OperationNode *node : graph->operations) {
- schedule_node(pool, graph, node, false, 0);
+ schedule_node(pool, graph, node, false, -1);
}
}
@@ -270,7 +257,7 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
}
const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0;
- graph->debug_is_evaluating = true;
+ graph->is_evaluating = true;
depsgraph_ensure_view_layer(graph);
/* Set up evaluation state. */
DepsgraphEvalState state;
@@ -311,7 +298,7 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
if (need_free_scheduler) {
BLI_task_scheduler_free(task_scheduler);
}
- graph->debug_is_evaluating = false;
+ graph->is_evaluating = false;
if (do_time_debug) {
printf("Depsgraph updated in %f seconds.\n", PIL_check_seconds_timer() - start_time);
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 1f9c12f604d..73a0823f84b 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -755,6 +755,25 @@ void update_animation_data_after_copy(const ID *id_orig, ID *id_cow)
update_nla_tracks_orig_pointers(&anim_data_orig->nla_tracks, &anim_data_cow->nla_tracks);
}
+/* Some builders (like motion path one) will ignore proxies from being built. This code makes it so
+ * proxy and proxy_group pointers never point to an original objects, preventing evaluation code
+ * from assign evaluated pointer to an original proxy->proxy_from. */
+void update_proxy_pointers_after_copy(const Depsgraph * /*depsgraph*/,
+ const Object * /*object_orig*/,
+ Object *object_cow)
+{
+ if (object_cow->proxy != NULL) {
+ if ((object_cow->proxy->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
+ object_cow->proxy = NULL;
+ }
+ }
+ if (object_cow->proxy_group != NULL) {
+ if ((object_cow->proxy_group->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
+ object_cow->proxy_group = NULL;
+ }
+ }
+}
+
/* Do some special treatment of data transfer from original ID to it's
* CoW complementary part.
*
@@ -788,6 +807,7 @@ void update_id_after_copy(const Depsgraph *depsgraph,
}
update_particles_after_copy(depsgraph, object_orig, object_cow);
update_modifiers_orig_pointers(object_orig, object_cow);
+ update_proxy_pointers_after_copy(depsgraph, object_orig, object_cow);
break;
}
case ID_SCE: {
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index 2479373b687..96e2974a7ab 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -87,15 +87,6 @@ typedef std::deque<OperationNode *> FlushQueue;
namespace {
-void flush_init_operation_node_func(void *__restrict data_v,
- const int i,
- const TaskParallelTLS *__restrict /*tls*/)
-{
- Depsgraph *graph = (Depsgraph *)data_v;
- OperationNode *node = graph->operations[i];
- node->scheduled = false;
-}
-
void flush_init_id_node_func(void *__restrict data_v,
const int i,
const TaskParallelTLS *__restrict /*tls*/)
@@ -110,13 +101,10 @@ void flush_init_id_node_func(void *__restrict data_v,
BLI_INLINE void flush_prepare(Depsgraph *graph)
{
- {
- const int num_operations = graph->operations.size();
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 1024;
- BLI_task_parallel_range(0, num_operations, graph, flush_init_operation_node_func, &settings);
+ for (OperationNode *node : graph->operations) {
+ node->scheduled = false;
}
+
{
const int num_id_nodes = graph->id_nodes.size();
TaskParallelSettings settings;
@@ -351,9 +339,6 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
BLI_assert(bmain != NULL);
BLI_assert(graph != NULL);
/* Nothing to update, early out. */
- if (BLI_gset_len(graph->entry_tags) == 0 && !graph->need_update_time) {
- return;
- }
if (graph->need_update_time) {
const Scene *scene_orig = graph->scene;
const float ctime = BKE_scene_frame_get(scene_orig);
@@ -361,6 +346,9 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
graph->ctime = ctime;
time_source->tag_update(graph, DEG::DEG_UPDATE_SOURCE_TIME);
}
+ if (BLI_gset_len(graph->entry_tags) == 0) {
+ return;
+ }
/* Reset all flags, get ready for the flush. */
flush_prepare(graph);
/* Starting from the tagged "entry" nodes, flush outwards. */
@@ -395,27 +383,13 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
invalidate_tagged_evaluated_data(graph);
}
-static void graph_clear_operation_func(void *__restrict data_v,
- const int i,
- const TaskParallelTLS *__restrict /*tls*/)
-{
- Depsgraph *graph = (Depsgraph *)data_v;
- OperationNode *node = graph->operations[i];
- /* Clear node's "pending update" settings. */
- node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE |
- DEPSOP_FLAG_USER_MODIFIED);
-}
-
/* Clear tags from all operation nodes. */
void deg_graph_clear_tags(Depsgraph *graph)
{
/* Go over all operation nodes, clearing tags. */
- {
- const int num_operations = graph->operations.size();
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 1024;
- BLI_task_parallel_range(0, num_operations, graph, graph_clear_operation_func, &settings);
+ for (OperationNode *node : graph->operations) {
+ node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE |
+ DEPSOP_FLAG_USER_MODIFIED);
}
/* Clear any entry tags which haven't been flushed. */
BLI_gset_clear(graph->entry_tags, NULL);
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 179ce21b71d..38e538c4e65 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -314,6 +314,7 @@ data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_skin_root_vert.glsl SRC)
data_to_c_simple(modes/shaders/edit_curve_overlay_handle_vert.glsl SRC)
data_to_c_simple(modes/shaders/edit_curve_overlay_handle_geom.glsl SRC)
data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC)
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index f548bd15bf4..0dd1a4fd686 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -72,7 +72,6 @@ static struct {
typedef struct BASIC_PrivateData {
DRWShadingGroup *depth_shgrp;
DRWShadingGroup *depth_shgrp_cull;
- DRWShadingGroup *depth_shgrp_hair;
} BASIC_PrivateData; /* Transient data */
/* Functions */
@@ -162,7 +161,8 @@ static void basic_cache_populate(void *vedata, Object *ob)
}
}
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const bool do_cull = (draw_ctx->v3d &&
(draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 7df1c299454..d59d1f56e92 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -29,6 +29,7 @@
#include "eevee_private.h"
#include "GPU_texture.h"
#include "GPU_extensions.h"
+#include "GPU_platform.h"
#include "GPU_state.h"
static struct {
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 19f3983998e..4b0af273f7f 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -51,7 +51,6 @@ static struct {
struct GPUTexture *planar_pool_placeholder;
struct GPUTexture *depth_placeholder;
struct GPUTexture *depth_array_placeholder;
- struct GPUTexture *cube_face_minmaxz;
struct GPUVertFormat *format_probe_display_cube;
struct GPUVertFormat *format_probe_display_planar;
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 712bcc43f52..701d73461fc 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -48,6 +48,9 @@ static struct {
char *frag_shader_lib;
char *vert_shader_str;
char *vert_shadow_shader_str;
+ char *vert_background_shader_str;
+ char *vert_volume_shader_str;
+ char *geom_volume_shader_str;
char *volume_shader_lib;
struct GPUShader *default_prepass_sh;
@@ -565,6 +568,15 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
e_data.vert_shadow_shader_str = BLI_string_joinN(
datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl);
+ e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_background_vert_glsl);
+
+ e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_vert_glsl);
+
+ e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_geom_glsl);
+
e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl,
NULL,
datatoc_default_world_frag_glsl,
@@ -637,7 +649,7 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor
wo,
engine,
options,
- datatoc_background_vert_glsl,
+ e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
SHADER_DEFINES "#define PROBE_CAPTURE\n",
@@ -657,7 +669,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor
wo,
engine,
options,
- datatoc_background_vert_glsl,
+ e_data.vert_background_shader_str,
NULL,
e_data.frag_shader_lib,
SHADER_DEFINES "#define WORLD_BACKGROUND\n",
@@ -680,8 +692,8 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *
wo,
engine,
options,
- datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
+ e_data.vert_volume_shader_str,
+ e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
defines,
true);
@@ -741,8 +753,8 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material
ma,
engine,
options,
- datatoc_volumetric_vert_glsl,
- datatoc_volumetric_geom_glsl,
+ e_data.vert_volume_shader_str,
+ e_data.geom_volume_shader_str,
e_data.volume_shader_lib,
defines,
true);
@@ -1338,6 +1350,24 @@ static void material_transparent(Material *ma,
const float *spec_p = &ma->spec;
const float *rough_p = &ma->roughness;
+ const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0);
+
+ DRWState cur_state;
+ DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
+ DRW_STATE_BLEND_CUSTOM);
+
+ /* Depth prepass */
+ if (use_prepass) {
+ *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
+
+ cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
+
+ DRW_shgroup_state_disable(*shgrp_depth, all_state);
+ DRW_shgroup_state_enable(*shgrp_depth, cur_state);
+ }
+
if (ma->use_nodes && ma->nodetree) {
static float error_col[3] = {1.0f, 0.0f, 1.0f};
static float compile_col[3] = {0.5f, 0.5f, 0.5f};
@@ -1394,30 +1424,13 @@ static void material_transparent(Material *ma,
DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1);
}
- const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0);
-
- DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
- DRW_STATE_BLEND_CUSTOM);
-
- DRWState cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
+ cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
/* Disable other blend modes and use the one we want. */
DRW_shgroup_state_disable(*shgrp, all_state);
DRW_shgroup_state_enable(*shgrp, cur_state);
-
- /* Depth prepass */
- if (use_prepass) {
- *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
-
- cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
-
- DRW_shgroup_state_disable(*shgrp_depth, all_state);
- DRW_shgroup_state_enable(*shgrp_depth, cur_state);
- }
}
/* Return correct material or &defmaterial if slot is empty. */
@@ -1441,7 +1454,8 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
Scene *scene = draw_ctx->scene;
GHash *material_hash = stl->g_data->material_hash;
- bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
/* First get materials for this mesh. */
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
@@ -1574,7 +1588,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
/* Shadow Pass */
struct GPUMaterial *gpumat;
- switch (ma_array[i]->blend_shadow) {
+ const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree);
+ char blend_shadow = use_gpumat ? ma_array[i]->blend_shadow : MA_BS_SOLID;
+ switch (blend_shadow) {
case MA_BS_SOLID:
EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob);
*cast_shadow = true;
@@ -1734,6 +1750,9 @@ void EEVEE_materials_free(void)
MEM_SAFE_FREE(e_data.frag_shader_lib);
MEM_SAFE_FREE(e_data.vert_shader_str);
MEM_SAFE_FREE(e_data.vert_shadow_shader_str);
+ MEM_SAFE_FREE(e_data.vert_background_shader_str);
+ MEM_SAFE_FREE(e_data.vert_volume_shader_str);
+ MEM_SAFE_FREE(e_data.geom_volume_shader_str);
MEM_SAFE_FREE(e_data.volume_shader_lib);
DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh);
DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh);
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index 924b3d3b19b..48e9b5bcc13 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -33,6 +33,7 @@
#include "eevee_private.h"
#include "GPU_extensions.h"
+#include "GPU_platform.h"
#include "GPU_state.h"
static struct {
@@ -40,7 +41,6 @@ static struct {
struct GPUShader *gtao_sh;
struct GPUShader *gtao_layer_sh;
struct GPUShader *gtao_debug_sh;
- struct GPUTexture *src_depth;
struct GPUTexture *dummy_horizon_tx;
} e_data = {NULL}; /* Engine data */
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 2daf2388d63..591ca31017c 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -46,7 +46,6 @@ static struct {
/* These are just references, not actually allocated */
struct GPUTexture *depth_src;
- struct GPUTexture *color_src;
} e_data = {{NULL}}; /* Engine data */
extern char datatoc_ambient_occlusion_lib_glsl[];
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
index 257ec6bc8f0..46fc6e07c1c 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -163,7 +163,7 @@ void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
return;
}
- /* Grrr needed for correctness but not 99% of the time not needed.
+ /* Unfortunately needed for correctness but not 99% of the time not needed.
* TODO detect when needed? */
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index 30ad8482f76..8376b8c67b8 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -356,7 +356,7 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
if (!DRW_pass_is_empty(psl->sss_translucency_ps)) {
- /* We sample the shadowmaps using normal sampler. We need to disable Comparison mode.
+ /* We sample the shadow-maps using normal sampler. We need to disable Comparison mode.
* TODO(fclem) avoid this by using sampler objects.*/
GPU_texture_bind(sldata->shadow_cube_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cube_pool, false);
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 726082c0f02..aaa351a1922 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -54,7 +54,6 @@ static struct {
struct GPUShader *volumetric_integration_sh;
struct GPUShader *volumetric_resolve_sh;
- GPUTexture *color_src;
GPUTexture *depth_src;
GPUTexture *dummy_density;
@@ -255,7 +254,7 @@ void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
if (DRW_view_is_persp_get(NULL)) {
float sample_distribution = scene_eval->eevee.volumetric_sample_distribution;
- sample_distribution = 4.0f * (1.00001f - sample_distribution);
+ sample_distribution = 4.0f * (max_ff(1.0f - sample_distribution, 1e-2f));
const float clip_start = common_data->view_vecs[0][2];
/* Negate */
@@ -413,7 +412,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
DRWShadingGroup *grp = DRW_shgroup_material_create(mat, vedata->psl->volumetric_objects_ps);
- BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize);
+ BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, &texcosize);
/* TODO(fclem) remove those "unnecessary" UBOs */
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
@@ -632,7 +631,7 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
int tex_transmit = GPU_texture_opengl_bindcode(txl->volume_transmit_history);
/* TODO(fclem) Encapsulate these GL calls into DRWManager. */
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
- /* Subtility here! we need to tell the GL that the texture is layered (GL_TRUE)
+ /* Subtlety here! we need to tell the GL that the texture is layered (GL_TRUE)
* in order to bind the full 3D texture and not just a 2D slice. */
glBindImageTexture(0, tex_scatter, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
glBindImageTexture(1, tex_transmit, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F);
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index 98012aea303..f10d98e68bd 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -140,6 +140,10 @@ float min_v3(vec3 v)
{
return min(v.x, min(v.y, v.z));
}
+float min_v4(vec4 v)
+{
+ return min(min(v.x, v.y), min(v.z, v.w));
+}
float max_v2(vec2 v)
{
return max(v.x, v.y);
@@ -148,6 +152,10 @@ float max_v3(vec3 v)
{
return max(v.x, max(v.y, v.z));
}
+float max_v4(vec4 v)
+{
+ return max(max(v.x, v.y), max(v.z, v.w));
+}
float sum(vec2 v)
{
@@ -918,14 +926,15 @@ void main()
Closure cl = nodetree_exec();
float holdout = 1.0 - saturate(cl.holdout);
+ float transmit = saturate(avg(cl.transmittance));
+ float alpha = 1.0 - transmit;
# ifdef USE_ALPHA_BLEND
vec2 uvs = gl_FragCoord.xy * volCoordScale.zw;
vec3 vol_transmit, vol_scatter;
volumetric_resolve(uvs, gl_FragCoord.z, vol_transmit, vol_scatter);
- float transmit = saturate(avg(cl.transmittance));
- outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, (1.0 - transmit) * holdout);
+ outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, alpha * holdout);
outTransmittance = vec4(cl.transmittance, transmit * holdout);
# else
outRadiance = vec4(cl.radiance, holdout);
@@ -953,6 +962,16 @@ void main()
outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac;
# endif
+
+# ifndef USE_ALPHA_BLEND
+ float alpha_div = 1.0 / max(1e-8, alpha);
+ outRadiance.rgb *= alpha_div;
+ outRadiance.a = 1.0;
+ ssrData.rgb *= alpha_div;
+# ifdef USE_SSS
+ sssAlbedo.rgb *= alpha_div;
+# endif
+# endif
}
# endif /* MESH_SHADER && !SHADOW_SHADER */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
index 86f53522bc6..6531ceb8dbe 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
@@ -70,6 +70,18 @@ float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector)
#define scube(x) shadows_cube_data[x]
#define scascade(x) shadows_cascade_data[x]
+float shadow_cube_radial_depth(vec3 cubevec, float tex_id, int shadow_id)
+{
+ float depth = sample_cube(sssShadowCubes, cubevec, tex_id).r;
+ /* To reverting the constant bias from shadow rendering. (Tweaked for 16bit shadowmaps) */
+ const float depth_bias = 3.1e-5;
+ depth = saturate(depth - depth_bias);
+
+ depth = linear_depth(true, depth, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
+ depth *= length(cubevec / max_v3(abs(cubevec)));
+ return depth;
+}
+
vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, float sss_scale)
{
int shadow_id = int(ld.l_shadowid);
@@ -79,12 +91,12 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, f
/* We use the full l_vector.xyz so that the spread is minimize
* if the shading point is further away from the light source */
/* TODO(fclem) do something better than this. */
- // vec3 T, B;
- // make_orthonormal_basis(L.xyz / L.w, T, B);
- // rand.xy *= data.sh_blur;
- // W = W + T * rand.x + B * rand.y;
+ vec3 T, B;
+ make_orthonormal_basis(L.xyz / L.w, T, B);
- float s, dist;
+ vec3 n;
+ vec4 depths;
+ float d, dist;
int data_id = int(sd(shadow_id).sh_data_index);
if (ld.l_type == SUN) {
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
@@ -105,20 +117,62 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, f
return vec3(0.0);
}
- float tex_id = scascade(data_id).sh_tex_index;
- s = sample_cascade(sssShadowCascades, shpos.xy, tex_id + id).r;
- s *= range;
+ float tex_id = scascade(data_id).sh_tex_index + id;
+
+ /* Assume cascades have same height and width. */
+ vec2 ofs = vec2(1.0, 0.0) / float(textureSize(sssShadowCascades, 0).x);
+ d = sample_cascade(sssShadowCascades, shpos.xy, tex_id).r;
+ depths.x = sample_cascade(sssShadowCascades, shpos.xy + ofs.xy, tex_id).r;
+ depths.y = sample_cascade(sssShadowCascades, shpos.xy + ofs.yx, tex_id).r;
+ depths.z = sample_cascade(sssShadowCascades, shpos.xy - ofs.xy, tex_id).r;
+ depths.w = sample_cascade(sssShadowCascades, shpos.xy - ofs.yx, tex_id).r;
+
+ /* To reverting the constant bias from shadow rendering. (Tweaked for 16bit shadowmaps) */
+ float depth_bias = 3.1e-5;
+ depths = saturate(depths - depth_bias);
+ d = saturate(d - depth_bias);
+
+ /* Size of a texel in world space.
+ * FIXME This is only correct if l_right is the same right vector used for shadowmap creation.
+ * This won't work if the shadow matrix is rotated (soft shadows).
+ * TODO precompute */
+ float unit_world_in_uv_space = length(mat3(scascade(data_id).shadowmat[int(id)]) * ld.l_right);
+ float dx_scale = 2.0 * ofs.x / unit_world_in_uv_space;
+
+ d *= range;
+ depths *= range;
+
+ /* This is the normal of the occluder in world space. */
+ // vec3 T = ld.l_forward * dx + ld.l_right * dx_scale;
+ // vec3 B = ld.l_forward * dy + ld.l_up * dx_scale;
+ // n = normalize(cross(T, B));
}
else {
+ float ofs = 1.0 / float(textureSize(sssShadowCubes, 0).x);
+
vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
dist = length(cubevec);
cubevec /= dist;
/* tex_id == data_id for cube shadowmap */
float tex_id = float(data_id);
- s = sample_cube(sssShadowCubes, cubevec, tex_id).r;
- s = length(cubevec / max_v3(abs(cubevec))) *
- linear_depth(true, s, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
+ d = shadow_cube_radial_depth(cubevec, tex_id, shadow_id);
+ /* NOTE: The offset is irregular in respect to cubeface uvs. But it has
+ * a much more uniform behavior than biasing based on face derivatives. */
+ depths.x = shadow_cube_radial_depth(cubevec + T * ofs, tex_id, shadow_id);
+ depths.y = shadow_cube_radial_depth(cubevec + B * ofs, tex_id, shadow_id);
+ depths.z = shadow_cube_radial_depth(cubevec - T * ofs, tex_id, shadow_id);
+ depths.w = shadow_cube_radial_depth(cubevec - B * ofs, tex_id, shadow_id);
}
+
+ float dx = depths.x - depths.z;
+ float dy = depths.y - depths.w;
+
+ float s = min(d, min_v4(depths));
+
+ /* To avoid light leak from depth discontinuity and shadowmap aliasing. */
+ float slope_bias = (abs(dx) + abs(dy)) * 0.5;
+ s -= slope_bias;
+
float delta = dist - s;
float power = light_translucent_power_with_falloff(ld, N, l_vector);
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index b1c78cae54f..6427f02ed25 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -70,7 +70,6 @@ vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArrayShadow tex)
vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube)
{
/* Manual Shadow Cube Layer indexing. */
- /* TODO Shadow Cube Array. */
float face = cubeFaceIndexEEVEE(cubevec);
vec2 uv = cubeFaceCoordEEVEE(cubevec, face, tex);
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index f6646ca575e..704e16b2907 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -28,6 +28,8 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
+#include "BKE_object.h"
+
#include "ED_screen.h"
#include "GPU_matrix.h"
@@ -156,7 +158,8 @@ static void external_cache_populate(void *vedata, Object *ob)
{
EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
- if (!DRW_object_is_renderable(ob)) {
+ if (!(DRW_object_is_renderable(ob) &&
+ DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
return;
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index 33e6d73eeeb..f9df1342bf8 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -50,10 +50,6 @@ static bool gpencil_has_noninstanced_object(Object *ob_instance)
if (ob->type != OB_GPENCIL) {
continue;
}
- /* object must be visible (invisible objects don't create VBO data) */
- if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
- continue;
- }
/* is not duplicated and the name is equals */
if ((ob->base_flag & BASE_FROM_DUPLI) == 0) {
if (STREQ(ob->id.name, ob_instance->id.name)) {
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index fbaf35890f1..af315597e68 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -37,7 +37,6 @@
#include "DNA_gpencil_types.h"
#include "DNA_material_types.h"
#include "DNA_view3d_types.h"
-#include "DNA_gpencil_modifier_types.h"
/* If builtin shaders are needed */
#include "GPU_shader.h"
@@ -135,24 +134,24 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
GpencilBatchCache *cache,
bGPdata *gpd)
{
- if (!cache->is_dirty) {
+ if ((!cache->is_dirty) || (gpd == NULL)) {
return;
}
Object *ob = cache_ob->ob;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const bool main_onion = draw_ctx->v3d != NULL ?
- (draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) :
- true;
+ const bool main_onion = stl->storage->is_main_onion;
const bool playing = stl->storage->is_playing;
- const bool overlay = draw_ctx->v3d != NULL ?
- (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) :
- true;
+ const bool overlay = stl->storage->is_main_overlay;
const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
main_onion && !playing && gpencil_onion_active(gpd);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ /* Onion skinning. */
+ const int step = gpd->gstep;
+ const int mode = gpd->onion_mode;
+ const short onion_keytype = gpd->onion_keytype;
+
cache_ob->tot_vertex = 0;
cache_ob->tot_triangles = 0;
int idx_eval = 0;
@@ -165,7 +164,33 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
continue;
}
- /* if multiedit or onion skin need to count all frames of the layer */
+ /* Relative onion mode needs to find the frame range before. */
+ int frame_from = -9999;
+ int frame_to = 9999;
+ if ((is_onion) && (mode == GP_ONION_MODE_RELATIVE)) {
+ /* 1) Found first Frame. */
+ int idx = 0;
+ if (gpl->actframe) {
+ for (bGPDframe *gf = gpl->actframe->prev; gf; gf = gf->prev) {
+ idx++;
+ frame_from = gf->framenum;
+ if (idx >= step) {
+ break;
+ }
+ }
+ /* 2) Found last Frame. */
+ idx = 0;
+ for (bGPDframe *gf = gpl->actframe->next; gf; gf = gf->next) {
+ idx++;
+ frame_to = gf->framenum;
+ if (idx >= gpd->gstep_next) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* If multiedit or onion skin need to count all frames of the layer. */
if ((is_multiedit) || (is_onion)) {
init_gpf = gpl->frames.first;
}
@@ -179,9 +204,46 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- cache_ob->tot_vertex += gps->totpoints + 3;
- cache_ob->tot_triangles += gps->totpoints - 1;
+ if (!is_onion) {
+ if ((!is_multiedit) ||
+ ((is_multiedit) && ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)))) {
+ cache_ob->tot_vertex += gps->totpoints + 3;
+ cache_ob->tot_triangles += gps->totpoints - 1;
+ }
+ }
+ else {
+ bool select = ((is_multiedit) &&
+ ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)));
+
+ if (!select) {
+ /* Only selected frames. */
+ if ((mode == GP_ONION_MODE_SELECTED) && ((gpf->flag & GP_FRAME_SELECT) == 0)) {
+ continue;
+ }
+ /* Verify keyframe type. */
+ if ((onion_keytype > -1) && (gpf->key_type != onion_keytype)) {
+ continue;
+ }
+ /* Absolute range. */
+ if (mode == GP_ONION_MODE_ABSOLUTE) {
+ if ((gpl->actframe) && (abs(gpl->actframe->framenum - gpf->framenum) > step)) {
+ continue;
+ }
+ }
+ /* Relative range. */
+ if (mode == GP_ONION_MODE_RELATIVE) {
+ if ((gpf->framenum < frame_from) || (gpf->framenum > frame_to)) {
+ continue;
+ }
+ }
+ }
+
+ cache_ob->tot_vertex += gps->totpoints + 3;
+ cache_ob->tot_triangles += gps->totpoints - 1;
+ }
}
+
+ /* If not multiframe nor Onion skin, don't need follow counting. */
if ((!is_multiedit) && (!is_onion)) {
break;
}
@@ -194,23 +256,6 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
cache->b_point.tot_vertex = cache_ob->tot_vertex;
cache->b_edit.tot_vertex = cache_ob->tot_vertex;
cache->b_edlin.tot_vertex = cache_ob->tot_vertex;
-
- /* some modifiers can change the number of points */
- int factor = 0;
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
- /* only modifiers that change size */
- if (mti && mti->getDuplicationFactor) {
- factor = mti->getDuplicationFactor(md);
-
- cache->b_fill.tot_vertex *= factor;
- cache->b_stroke.tot_vertex *= factor;
- cache->b_point.tot_vertex *= factor;
- cache->b_edit.tot_vertex *= factor;
- cache->b_edlin.tot_vertex *= factor;
- }
- }
}
/* Helper for doing all the checks on whether a stroke can be drawn */
@@ -414,10 +459,12 @@ static void set_wireframe_color(Object *ob,
}
/* create shading group for filling */
-static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
+static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
MaterialGPencilStyle *gp_style,
@@ -431,6 +478,8 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
/* e_data.gpencil_fill_sh */
DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1);
/* set style type */
@@ -540,7 +589,7 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata,
}
else {
/* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture);
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
stl->shgroups[id].texture_clamp = 0;
DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
}
@@ -560,10 +609,12 @@ bool gpencil_onion_active(bGPdata *gpd)
}
/* create shading group for strokes */
-DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
+DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -585,6 +636,8 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
/* avoid wrong values */
if ((gpd) && (gpd->pixfactor == 0.0f)) {
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
@@ -716,17 +769,19 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata,
}
else {
/* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture);
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
}
return grp;
}
/* create shading group for points */
-static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
+static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
DRWPass *pass,
GPUShader *shader,
Object *ob,
+ float (*obmat)[4],
bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -747,6 +802,8 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
+
/* avoid wrong values */
if ((gpd) && (gpd->pixfactor == 0.0f)) {
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
@@ -885,7 +942,7 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata,
}
else {
/* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture);
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
}
return grp;
@@ -1071,7 +1128,7 @@ static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
*/
const bool show_points = (show_sculpt_points) || (is_weight_paint) ||
(GPENCIL_EDIT_MODE(gpd) &&
- ((ts->gpencil_selectmode_edit & GP_SELECTMODE_STROKE) == 0));
+ (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE));
if (cache->is_dirty) {
if ((obact == ob) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
@@ -1144,7 +1201,8 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
const bool playing = stl->storage->is_playing;
const bool is_render = (bool)stl->storage->is_render;
const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
- const bool overlay_multiedit = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) : true;
+ const bool overlay_multiedit = v3d != NULL ? !(v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) :
+ true;
/* Get evaluation context */
/* NOTE: We must check if C is valid, otherwise we get crashes when trying to save files
@@ -1168,6 +1226,12 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
continue;
}
+ /* Copy color to temp fields. */
+ if ((is_multiedit) && (gp_style)) {
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+ }
+
/* be sure recalc all cache in source stroke to avoid recalculation when frame change
* and improve fps */
gpencil_recalc_geometry_caches(
@@ -1185,7 +1249,8 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
}
}
- if ((gpl->actframe->framenum == gpf->framenum) || (!is_multiedit) || (overlay_multiedit)) {
+ if ((gpl->actframe && (gpl->actframe->framenum == gpf->framenum)) || (!is_multiedit) ||
+ (overlay_multiedit)) {
/* hide any blend layer */
if ((!stl->storage->simplify_blend) || (gpl->blend_mode == eGplBlendMode_Regular)) {
/* fill */
@@ -1216,12 +1281,14 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
if (!stl->g_data->shgrps_edit_line) {
stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh,
psl->edit_pass);
+ DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_line, "gpModelMatrix", ob->obmat);
}
if (!stl->g_data->shgrps_edit_point) {
stl->g_data->shgrps_edit_point = DRW_shgroup_create(e_data->gpencil_edit_point_sh,
psl->edit_pass);
const float *viewport_size = DRW_viewport_size_get();
DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1);
+ DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_point, "gpModelMatrix", ob->obmat);
}
gpencil_add_editpoints_vertexdata(cache, ob, gpd, gpl, gpf, gps);
@@ -1304,19 +1371,19 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
int idx;
float fac = 1.0f;
int step = 0;
- int mode = 0;
bool colflag = false;
- bGPDframe *gpf_loop = NULL;
+ const int mode = gpd->onion_mode;
+ bGPDframe *gpf_loop = ((gpd->onion_flag & GP_ONION_LOOP) && (mode != GP_ONION_MODE_SELECTED)) ?
+ gpl->frames.first :
+ NULL;
int last = gpf->framenum;
- colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL;
+ colflag = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0;
const short onion_keytype = gpd->onion_keytype;
-
/* -------------------------------
* 1) Draw Previous Frames First
* ------------------------------- */
step = gpd->gstep;
- mode = gpd->onion_mode;
if (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) {
copy_v3_v3(color, gpd->gcolor_prev);
@@ -1365,7 +1432,7 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
}
/* if loop option, save the frame to use later */
- if ((mode != GP_ONION_MODE_ABSOLUTE) && (gpd->onion_flag & GP_ONION_LOOP)) {
+ if ((mode == GP_ONION_MODE_SELECTED) && (gpd->onion_flag & GP_ONION_LOOP)) {
gpf_loop = gf;
}
@@ -1376,7 +1443,6 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
* 2) Now draw next frames
* ------------------------------- */
step = gpd->gstep_next;
- mode = gpd->onion_mode;
if (gpd->onion_flag & GP_ONION_GHOST_NEXTCOL) {
copy_v3_v3(color, gpd->gcolor_next);
@@ -1555,6 +1621,9 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
}
+ static float unit_mat[4][4] = {
+ {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}};
+
/* drawing strokes */
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
* that is being edited. (Stroke buffer is currently stored in gp-data)
@@ -1575,10 +1644,12 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
if (gpd->runtime.sbuffer_used > 1) {
if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_stroke_create(
+ e_data,
vedata,
psl->drawing_pass,
e_data->gpencil_stroke_sh,
NULL,
+ unit_mat,
gpd,
NULL,
NULL,
@@ -1599,10 +1670,12 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
}
else {
stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_point_create(
+ e_data,
vedata,
psl->drawing_pass,
e_data->gpencil_point_sh,
NULL,
+ unit_mat,
gpd,
NULL,
NULL,
@@ -1662,6 +1735,8 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->drawing_pass);
const float *viewport_size = DRW_viewport_size_get();
DRW_shgroup_uniform_vec2(shgrp, "Viewport", viewport_size, 1);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", unit_mat);
+
/* Disable stencil for this type */
DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
stl->g_data->batch_buffer_ctrlpoint = gpencil_get_buffer_ctrlpoint_geom(gpd);
@@ -1671,7 +1746,7 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
}
/* create all missing batches */
-static void gpencil_create_batches(GpencilBatchCache *cache)
+static void gpencil_batches_ensure(GpencilBatchCache *cache)
{
if ((cache->b_point.vbo) && (cache->b_point.batch == NULL)) {
cache->b_point.batch = GPU_batch_create_ex(
@@ -1722,8 +1797,8 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
const bool overlay = draw_ctx->v3d != NULL ?
(bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) :
true;
- const bool main_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true;
- const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && main_onion &&
+ const bool screen_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true;
+ const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && screen_onion &&
overlay && gpencil_onion_active(gpd);
int start_stroke = 0;
@@ -1785,10 +1860,12 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
case eGpencilBatchGroupType_Stroke: {
const int len = elm->vertex_idx - start_stroke;
- shgrp = gpencil_shgroup_stroke_create(vedata,
+ shgrp = gpencil_shgroup_stroke_create(e_data,
+ vedata,
stroke_pass,
e_data->gpencil_stroke_sh,
ob,
+ obmat,
gpd,
gpl,
gps,
@@ -1797,32 +1874,37 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
elm->onion,
scale,
cache_ob->shading_type);
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_stroke.batch, obmat, start_stroke, len);
- }
- stl->storage->shgroup_id++;
- start_stroke = elm->vertex_idx;
/* set stencil mask id */
if (gpencil_is_stencil_required(gp_style)) {
+ if (stencil_id == 1) {
+ /* Clear previous stencils. */
+ DRW_shgroup_clear_framebuffer(shgrp, GPU_STENCIL_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ }
DRW_shgroup_stencil_mask(shgrp, stencil_id);
stencil_id++;
}
else {
/* Disable stencil for this type */
DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
}
+
+ if ((do_onion) || (elm->onion == false)) {
+ DRW_shgroup_call_range(shgrp, cache->b_stroke.batch, start_stroke, len);
+ }
+ stl->storage->shgroup_id++;
+ start_stroke = elm->vertex_idx;
break;
}
case eGpencilBatchGroupType_Point: {
const int len = elm->vertex_idx - start_point;
- shgrp = gpencil_shgroup_point_create(vedata,
+ shgrp = gpencil_shgroup_point_create(e_data,
+ vedata,
stroke_pass,
e_data->gpencil_point_sh,
ob,
+ obmat,
gpd,
gpl,
gps,
@@ -1832,49 +1914,50 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
scale,
cache_ob->shading_type);
+ /* Disable stencil for this type */
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
+
if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_point.batch, obmat, start_point, len);
+ DRW_shgroup_call_range(shgrp, cache->b_point.batch, start_point, len);
}
stl->storage->shgroup_id++;
start_point = elm->vertex_idx;
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
break;
}
case eGpencilBatchGroupType_Fill: {
const int len = elm->vertex_idx - start_fill;
- shgrp = gpencil_shgroup_fill_create(vedata,
+ shgrp = gpencil_shgroup_fill_create(e_data,
+ vedata,
stroke_pass,
e_data->gpencil_fill_sh,
ob,
+ obmat,
gpd,
gpl,
gp_style,
stl->storage->shgroup_id,
cache_ob->shading_type);
+ /* Disable stencil for this type */
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
+
if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range_obmat(shgrp, cache->b_fill.batch, obmat, start_fill, len);
+ DRW_shgroup_call_range(shgrp, cache->b_fill.batch, start_fill, len);
}
stl->storage->shgroup_id++;
start_fill = elm->vertex_idx;
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- /* set stencil mask id as not used */
- DRW_shgroup_stencil_mask(shgrp, 0x0);
break;
}
case eGpencilBatchGroupType_Edit: {
if (stl->g_data->shgrps_edit_point) {
const int len = elm->vertex_idx - start_edit;
+
+ shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_point);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
/* use always the same group */
- DRW_shgroup_call_range_obmat(
- stl->g_data->shgrps_edit_point, cache->b_edit.batch, obmat, start_edit, len);
+ DRW_shgroup_call_range(
+ stl->g_data->shgrps_edit_point, cache->b_edit.batch, start_edit, len);
start_edit = elm->vertex_idx;
}
@@ -1883,9 +1966,12 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
case eGpencilBatchGroupType_Edlin: {
if (stl->g_data->shgrps_edit_line) {
const int len = elm->vertex_idx - start_edlin;
+
+ shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_line);
+ DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
/* use always the same group */
- DRW_shgroup_call_range_obmat(
- stl->g_data->shgrps_edit_line, cache->b_edlin.batch, obmat, start_edlin, len);
+ DRW_shgroup_call_range(
+ stl->g_data->shgrps_edit_line, cache->b_edlin.batch, start_edlin, len);
start_edlin = elm->vertex_idx;
}
@@ -1963,7 +2049,7 @@ void gpencil_populate_multiedit(GPENCIL_e_data *e_data,
}
/* create batchs and shading groups */
- gpencil_create_batches(cache);
+ gpencil_batches_ensure(cache);
gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
cache->is_dirty = false;
@@ -1992,13 +2078,9 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
bGPdata *gpd_eval = (bGPdata *)ob->data;
bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
- const bool main_onion = draw_ctx->v3d != NULL ?
- (draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) :
- true;
+ const bool main_onion = stl->storage->is_main_onion;
const bool playing = stl->storage->is_playing;
- const bool overlay = draw_ctx->v3d != NULL ?
- (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) :
- true;
+ const bool overlay = stl->storage->is_main_overlay;
const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
main_onion && !playing && gpencil_onion_active(gpd);
@@ -2086,7 +2168,7 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data,
}
/* create batchs and shading groups */
- gpencil_create_batches(cache);
+ gpencil_batches_ensure(cache);
gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
cache->is_dirty = false;
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index d03f975ca37..051c2837727 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -24,11 +24,13 @@
#include "BKE_gpencil.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_shader_fx.h"
#include "DNA_gpencil_types.h"
+#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "draw_mode_engines.h"
@@ -61,6 +63,8 @@ extern char datatoc_gpencil_edit_point_geom_glsl[];
extern char datatoc_gpencil_edit_point_frag_glsl[];
extern char datatoc_gpencil_blend_frag_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+
extern char datatoc_common_colormanagement_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
@@ -111,7 +115,7 @@ static void GPENCIL_create_framebuffers(void *vedata)
const float *viewport_size = DRW_viewport_size_get();
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
- /* create multiframe framebuffer for AA */
+ /* create multisample framebuffer for AA */
if ((stl->storage->framebuffer_flag & GP_FRAMEBUFFER_MULTISAMPLE) &&
(stl->storage->multisamples > 0)) {
gpencil_multisample_ensure(vedata, size[0], size[1]);
@@ -176,6 +180,12 @@ static void GPENCIL_create_framebuffers(void *vedata)
static void GPENCIL_create_shaders(void)
{
+ /* blank texture used if no texture defined for fill shader */
+ if (!e_data.gpencil_blank_texture) {
+ float rect[1][1][4] = {{{0.0f}}};
+ e_data.gpencil_blank_texture = DRW_texture_create_2d(
+ 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
+ }
/* normal fill shader */
if (!e_data.gpencil_fill_sh) {
e_data.gpencil_fill_sh = GPU_shader_create_from_arrays({
@@ -221,7 +231,12 @@ static void GPENCIL_create_shaders(void)
/* used for edit lines for edit modes */
if (!e_data.gpencil_line_sh) {
- e_data.gpencil_line_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+ e_data.gpencil_line_sh = DRW_shader_create_with_lib(
+ datatoc_gpencil_edit_point_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
}
/* used to filling during drawing */
@@ -279,16 +294,56 @@ static void GPENCIL_engine_free(void)
DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_line_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh);
+ DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture);
+
/* effects */
GPENCIL_delete_fx_shaders(&e_data);
}
+/* Helper: Check if the main overlay and onion switches are enabled in any screen.
+ *
+ * This is required to generate the onion skin and limit the times the cache is updated because the
+ * cache is generated only in the first screen and if the first screen has the onion disabled the
+ * cache for onion skin is not generated. The loop adds time, but always is faster than regenerate
+ * the cache all the times.
+ */
+static void gpencil_check_screen_switches(const DRWContextState *draw_ctx,
+ GPENCIL_StorageList *stl)
+{
+ stl->storage->is_main_overlay = false;
+ stl->storage->is_main_onion = false;
+ /* Check if main onion switch is enabled in any screen. */
+ Main *bmain = CTX_data_main(draw_ctx->evil_C);
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa && sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = sa->spacedata.first;
+ if (v3d == NULL) {
+ continue;
+ }
+ if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) {
+ stl->storage->is_main_overlay = true;
+ }
+ if (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) {
+ stl->storage->is_main_onion = true;
+ }
+ }
+ /* If found, don't need loop more. */
+ if ((stl->storage->is_main_overlay) && (stl->storage->is_main_onion)) {
+ return;
+ }
+ }
+ }
+}
+
void GPENCIL_cache_init(void *vedata)
{
GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
@@ -299,6 +354,7 @@ void GPENCIL_cache_init(void *vedata)
ToolSettings *ts = scene->toolsettings;
View3D *v3d = draw_ctx->v3d;
Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ const View3DCursor *cursor = &scene->cursor;
/* Special handling for when active object is GP object (e.g. for draw mode) */
Object *obact = draw_ctx->obact;
@@ -330,17 +386,11 @@ void GPENCIL_cache_init(void *vedata)
stl->g_data->shgrps_edit_point = NULL;
/* reset textures */
- stl->g_data->gpencil_blank_texture = NULL;
stl->g_data->batch_buffer_stroke = NULL;
stl->g_data->batch_buffer_fill = NULL;
stl->g_data->batch_buffer_ctrlpoint = NULL;
stl->g_data->batch_grid = NULL;
- /* blank texture used if no texture defined for fill shader */
- float rect[1][1][4] = {{{0.0f}}};
- stl->g_data->gpencil_blank_texture = DRW_texture_create_2d(
- 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
-
if (!stl->shgroups) {
/* Alloc maximum size because count strokes is very slow and can be very complex due onion
* skinning.
@@ -380,10 +430,15 @@ void GPENCIL_cache_init(void *vedata)
stl->storage->reset_cache = true;
}
stl->storage->is_playing = playing;
+
+ /* Found if main overlay and onion switches are enabled in any screen. */
+ gpencil_check_screen_switches(draw_ctx, stl);
}
else {
stl->storage->is_playing = false;
stl->storage->reset_cache = false;
+ stl->storage->is_main_overlay = false;
+ stl->storage->is_main_onion = false;
}
/* save render state */
stl->storage->is_render = DRW_state_is_image_render();
@@ -530,11 +585,42 @@ void GPENCIL_cache_init(void *vedata)
}
/* grid pass */
- if (v3d) {
+ if ((v3d) && (obact) && (obact->type == OB_GPENCIL)) {
psl->grid_pass = DRW_pass_create("GPencil Grid Pass",
DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass);
+
+ /* define grid orientation */
+ switch (ts->gp_sculpt.lock_axis) {
+ case GP_LOCKAXIS_VIEW: {
+ /* align always to view */
+ invert_m4_m4(stl->storage->grid_matrix, draw_ctx->rv3d->viewmat);
+ /* copy ob location */
+ copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]);
+ break;
+ }
+ case GP_LOCKAXIS_CURSOR: {
+ float scale[3] = {1.0f, 1.0f, 1.0f};
+ loc_eul_size_to_mat4(
+ stl->storage->grid_matrix, cursor->location, cursor->rotation_euler, scale);
+ break;
+ }
+ default: {
+ copy_m4_m4(stl->storage->grid_matrix, obact->obmat);
+ break;
+ }
+ }
+
+ /* Move the origin to Object or Cursor */
+ if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
+ copy_v3_v3(stl->storage->grid_matrix[3], cursor->location);
+ }
+ else {
+ copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]);
+ }
+ DRW_shgroup_uniform_mat4(
+ stl->g_data->shgrps_grid, "gpModelMatrix", stl->storage->grid_matrix);
}
/* blend layers pass */
@@ -605,8 +691,6 @@ void GPENCIL_cache_populate(void *vedata, Object *ob)
Scene *scene = draw_ctx->scene;
ToolSettings *ts = scene->toolsettings;
View3D *v3d = draw_ctx->v3d;
- const View3DCursor *cursor = &scene->cursor;
- float grid_matrix[4][4];
if (ob->type == OB_GPENCIL && ob->data) {
bGPdata *gpd = (bGPdata *)ob->data;
@@ -667,36 +751,7 @@ void GPENCIL_cache_populate(void *vedata, Object *ob)
((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) == 0)) {
stl->g_data->batch_grid = gpencil_get_grid(ob);
-
- /* define grid orientation */
- switch (ts->gp_sculpt.lock_axis) {
- case GP_LOCKAXIS_VIEW: {
- /* align always to view */
- invert_m4_m4(grid_matrix, draw_ctx->rv3d->viewmat);
- /* copy ob location */
- copy_v3_v3(grid_matrix[3], ob->obmat[3]);
- break;
- }
- case GP_LOCKAXIS_CURSOR: {
- float scale[3] = {1.0f, 1.0f, 1.0f};
- loc_eul_size_to_mat4(grid_matrix, cursor->location, cursor->rotation_euler, scale);
- break;
- }
- default: {
- copy_m4_m4(grid_matrix, ob->obmat);
- break;
- }
- }
-
- /* Move the origin to Object or Cursor */
- if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
- copy_v3_v3(grid_matrix[3], cursor->location);
- }
- else {
- copy_v3_v3(grid_matrix[3], ob->obmat[3]);
- }
-
- DRW_shgroup_call_obmat(stl->g_data->shgrps_grid, stl->g_data->batch_grid, grid_matrix);
+ DRW_shgroup_call(stl->g_data->shgrps_grid, stl->g_data->batch_grid, NULL);
}
}
}
@@ -781,8 +836,6 @@ void DRW_gpencil_free_runtime_data(void *ved)
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
/* free gpu data */
- DRW_TEXTURE_FREE_SAFE(stl->g_data->gpencil_blank_texture);
-
GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_stroke);
MEM_SAFE_FREE(stl->g_data->batch_buffer_stroke);
@@ -834,76 +887,13 @@ static void gpencil_draw_pass_range(GPENCIL_FramebufferList *fbl,
const bool do_antialiasing = ((!stl->storage->is_mat_preview) && (multi));
- DRWShadingGroup *shgrp = init_shgrp;
- DRWShadingGroup *from_shgrp = init_shgrp;
- DRWShadingGroup *to_shgrp = init_shgrp;
- int stencil_tot = 0;
- bool do_last = true;
-
if (do_antialiasing) {
MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
}
- /* Loop all shading groups to separate by stencil groups. */
- while ((shgrp) && (shgrp != end_shgrp)) {
- do_last = true;
- /* Count number of groups using stencil. */
- if (DRW_shgroup_stencil_mask_get(shgrp) != 0) {
- stencil_tot++;
- }
-
- /* Draw stencil group and clear stencil bit. This is required because the number of
- * shading groups can be greater than the limit of 255 stencil values.
- * Only count as stencil if the shading group has an stencil value assigned. This reduces
- * the number of clears because Dots, Fills and some Line strokes don't need stencil.
- */
- if (stencil_tot == 255) {
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d :
- psl->stroke_pass_2d,
- from_shgrp,
- to_shgrp);
- /* Clear Stencil and prepare for next group. */
- if (do_antialiasing) {
- GPU_framebuffer_clear_stencil(fbl->multisample_fb, 0x0);
- }
- else {
- GPU_framebuffer_clear_stencil(fb, 0x0);
- }
-
- /* Set new init group and reset. */
- do_last = false;
-
- shgrp = DRW_shgroup_get_next(shgrp);
- if (shgrp) {
- from_shgrp = to_shgrp = shgrp;
- stencil_tot = 0;
- if (shgrp != end_shgrp) {
- continue;
- }
- else {
- do_last = true;
- break;
- }
- }
- else {
- /* No more groups. */
- break;
- }
- }
-
- /* Still below stencil group limit. */
- shgrp = DRW_shgroup_get_next(shgrp);
- if (shgrp) {
- to_shgrp = shgrp;
- }
- }
-
- /* Draw last pending groups. */
- if (do_last) {
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
- from_shgrp,
- to_shgrp);
- }
+ DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
+ init_shgrp,
+ end_shgrp);
if (do_antialiasing) {
MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl);
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 79bcffac512..36bc205f41a 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -143,6 +143,8 @@ typedef struct GPENCIL_Storage {
bool is_playing;
bool is_render;
bool is_mat_preview;
+ bool is_main_overlay;
+ bool is_main_onion;
bool background_ready;
int is_xray;
bool is_ontop;
@@ -153,6 +155,7 @@ typedef struct GPENCIL_Storage {
int do_select_outline;
float select_color[4];
short multisamples;
+ float grid_matrix[4][4];
short framebuffer_flag; /* flag what framebuffer need to create */
@@ -265,9 +268,6 @@ typedef struct g_data {
/* grid geometry */
GPUBatch *batch_grid;
- /* textures */
- struct GPUTexture *gpencil_blank_texture;
-
/* runtime pointers texture */
struct GPUTexture *input_depth_tx;
struct GPUTexture *input_color_tx;
@@ -297,6 +297,9 @@ typedef enum eGPsession_Flag {
} eGPsession_Flag;
typedef struct GPENCIL_e_data {
+ /* textures */
+ struct GPUTexture *gpencil_blank_texture;
+
/* general drawing shaders */
struct GPUShader *gpencil_fill_sh;
struct GPUShader *gpencil_stroke_sh;
@@ -386,10 +389,12 @@ typedef struct GpencilBatchCache {
} GpencilBatchCache;
/* general drawing functions */
-struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_Data *vedata,
+struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data,
+ struct GPENCIL_Data *vedata,
struct DRWPass *pass,
struct GPUShader *shader,
struct Object *ob,
+ float (*obmat)[4],
struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDstroke *gps,
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index aa0abe0341a..ba00fc18757 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -73,7 +73,7 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra
* because there is no viewport. So we need to manually create one
* NOTE : use 32 bit format for precision in render mode.
*/
- /* create multiframe framebuffer for AA */
+ /* create multisample framebuffer for AA */
if (U.gpencil_multisamples > 0) {
int rect_w = (int)viewport_size[0];
int rect_h = (int)viewport_size[1];
@@ -308,6 +308,9 @@ void GPENCIL_render_to_image(void *vedata,
DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache);
GPENCIL_cache_finish(vedata);
+
+ DRW_render_instance_buffer_finish();
+
GPENCIL_draw_scene(vedata);
/* combined data */
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
index a1cfb2ae4ae..f75322f90e2 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
@@ -1,4 +1,6 @@
+uniform mat4 gpModelMatrix;
+
in vec3 pos;
in vec4 color;
in float size;
@@ -8,7 +10,7 @@ out float finalThickness;
void main()
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
finalThickness = size;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
index eb452f4c660..263dc570423 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
@@ -1,4 +1,6 @@
+uniform mat4 gpModelMatrix;
+
in vec3 pos;
in vec4 color;
in vec2 texCoord;
@@ -8,7 +10,7 @@ out vec2 texCoord_interp;
void main(void)
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
texCoord_interp = texCoord;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
index ef8b361373f..87963c66858 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
@@ -6,6 +6,7 @@ uniform float pixfactor;
uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform mat4 gpModelMatrix;
in vec3 pos;
in vec4 color;
@@ -30,8 +31,8 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor);
void main()
{
- gl_Position = point_object_to_ndc(pos);
- finalprev_pos = point_object_to_ndc(prev_pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
+ finalprev_pos = point_world_to_ndc((gpModelMatrix * vec4(prev_pos, 1.0)).xyz);
finalColor = color;
if (keep_size == TRUE) {
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
index c7089f357f9..582b9a7f249 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
@@ -6,6 +6,7 @@ uniform float pixfactor;
uniform int viewport_xray;
uniform int shading_type[2];
uniform vec4 wire_color;
+uniform mat4 gpModelMatrix;
in vec3 pos;
in vec4 color;
@@ -28,7 +29,7 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor);
void main(void)
{
- gl_Position = point_object_to_ndc(pos);
+ gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
finalColor = color;
if (keep_size == TRUE) {
diff --git a/source/blender/draw/engines/select/select_draw_utils.c b/source/blender/draw/engines/select/select_draw_utils.c
index 927956dad19..f1d008c29c7 100644
--- a/source/blender/draw/engines/select/select_draw_utils.c
+++ b/source/blender/draw/engines/select/select_draw_utils.c
@@ -49,8 +49,7 @@ void select_id_object_min_max(Object *obj, float r_min[3], float r_max[3])
BoundBox *bb;
BMEditMesh *em = BKE_editmesh_from_object(obj);
if (em) {
- /* Use Object Texture Space. */
- bb = BKE_mesh_texspace_get(em->mesh_eval_cage, NULL, NULL, NULL);
+ bb = BKE_editmesh_cage_boundbox_get(em);
}
else {
bb = BKE_object_boundbox_get(obj);
@@ -63,10 +62,10 @@ short select_id_get_object_select_mode(Scene *scene, Object *ob)
{
short r_select_mode = 0;
if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) {
- /* In order to sample flat colors for vertex weights / texturepaint / vertexpaint
+ /* In order to sample flat colors for vertex weights / texture-paint / vertex-paint
* we need to be in SCE_SELECT_FACE mode so select_cache_init() correctly sets up
* a shgroup with select_id_flat.
- * Note this is not working correctly for vertexpaint (yet), but has been discussed
+ * Note this is not working correctly for vertex-paint (yet), but has been discussed
* in T66645 and there is a solution by @mano-wii in P1032.
* So OB_MODE_VERTEX_PAINT is already included here [required for P1032 I guess]. */
Mesh *me_orig = DEG_get_original_object(ob)->data;
@@ -129,7 +128,11 @@ static void draw_select_id_edit_mesh(SELECTID_StorageList *stl,
}
else {
if (ob->dt >= OB_SOLID) {
+#ifdef USE_CAGE_OCCLUSION
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
+#else
struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me);
+#endif
DRWShadingGroup *face_shgrp = stl->g_data->shgrp_face_unif;
DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob);
}
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index 5dc20a589f0..abfa57dd218 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -252,7 +252,11 @@ static void select_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
}
else if (ob->dt >= OB_SOLID) {
+#ifdef USE_CAGE_OCCLUSION
+ struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
+#else
struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me);
+#endif
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
}
diff --git a/source/blender/draw/engines/select/select_private.h b/source/blender/draw/engines/select/select_private.h
index 642cd6ffc56..1e99a49252e 100644
--- a/source/blender/draw/engines/select/select_private.h
+++ b/source/blender/draw/engines/select/select_private.h
@@ -23,6 +23,8 @@
#ifndef __SELECT_PRIVATE_H__
#define __SELECT_PRIVATE_H__
+#define USE_CAGE_OCCLUSION
+
#include "DRW_render.h"
/* GPUViewport.storage
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl
index a6d7c4b393b..3ac220aee59 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl
@@ -1,5 +1,5 @@
vec3 background_color(WorldData world_data, float y)
{
return mix(world_data.background_color_low, world_data.background_color_high, y).xyz +
- bayer_dither_noise();
+ (world_data.background_dither_factor * bayer_dither_noise());
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
index 16df56b393a..f60eca24821 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
@@ -16,5 +16,6 @@ struct WorldData {
float background_alpha;
float curvature_ridge;
float curvature_valley;
- int pad[3];
+ float background_dither_factor;
+ int pad[2];
};
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
index 505b4822ad6..abd8c1f6579 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
@@ -1,5 +1,6 @@
-uniform int object_id = 0;
+
layout(location = 0) out uint objectId;
+
uniform float ImageTransparencyCutoff = 0.1;
#ifdef V3D_SHADING_TEXTURE_COLOR
uniform sampler2D image;
@@ -10,11 +11,10 @@ in vec2 uv_interp;
void main()
{
#ifdef V3D_SHADING_TEXTURE_COLOR
- vec4 diffuse_color = texture(image, uv_interp);
- if (diffuse_color.a < ImageTransparencyCutoff) {
+ if (texture(image, uv_interp).a < ImageTransparencyCutoff) {
discard;
}
#endif
- objectId = uint(object_id);
+ objectId = uint(resource_id + 1) & 0xFFu;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
index 3333dfeff38..f799ce41cb2 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
@@ -8,8 +8,7 @@ uniform float alpha = 0.5;
uniform vec2 invertedViewportSize;
uniform vec4 viewvecs[3];
-uniform vec3 materialDiffuseColor;
-uniform vec3 materialSpecularColor;
+uniform vec4 materialColorAndMetal;
uniform float materialRoughness;
uniform float shadowMultiplier = 0.5;
@@ -42,17 +41,17 @@ layout(location = 1) out
void main()
{
- vec4 diffuse_color;
+ vec4 base_color;
#if defined(V3D_SHADING_TEXTURE_COLOR)
- diffuse_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
- if (diffuse_color.a < ImageTransparencyCutoff) {
+ base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
+ if (base_color.a < ImageTransparencyCutoff) {
discard;
}
#elif defined(V3D_SHADING_VERTEX_COLOR)
- diffuse_color = vec4(vertexColor, 1.0);
+ base_color.rgb = vertexColor;
#else
- diffuse_color = vec4(materialDiffuseColor, 1.0);
+ base_color.rgb = materialColorAndMetal.rgb;
#endif /* V3D_SHADING_TEXTURE_COLOR */
vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
@@ -64,7 +63,7 @@ void main()
/* -------- SHADING --------- */
#ifdef V3D_LIGHTING_FLAT
- vec3 shaded_color = diffuse_color.rgb;
+ vec3 shaded_color = base_color.rgb;
#elif defined(V3D_LIGHTING_MATCAP)
bool flipped = world_data.matcap_orientation != 0;
@@ -75,11 +74,20 @@ void main()
# else
vec3 matcap_specular = vec3(0.0);
# endif
- vec3 shaded_color = matcap_diffuse * diffuse_color.rgb + matcap_specular;
+ vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular;
#elif defined(V3D_LIGHTING_STUDIO)
+# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ float metallic = materialColorAndMetal.a;
+ vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic);
+ vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic);
+# else
+ vec3 specular_color = vec3(0.0);
+ vec3 diffuse_color = base_color.rgb;
+# endif
+
vec3 shaded_color = get_world_lighting(
- world_data, diffuse_color.rgb, materialSpecularColor, materialRoughness, nor, I_vs);
+ world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs);
#endif
#ifdef V3D_SHADING_SHADOW
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index c673b2484de..b5f95f2dcf8 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -1,7 +1,5 @@
-uniform int object_id = 0;
-uniform vec3 materialDiffuseColor;
-uniform float materialMetallic;
+uniform vec4 materialColorAndMetal;
uniform float materialRoughness;
uniform sampler2D image;
@@ -48,7 +46,7 @@ void main()
# elif defined(V3D_SHADING_VERTEX_COLOR)
color.rgb = vertexColor;
# else
- color.rgb = materialDiffuseColor;
+ color.rgb = materialColorAndMetal.rgb;
# endif
# ifdef V3D_LIGHTING_MATCAP
@@ -56,7 +54,7 @@ void main()
metallic = float(gl_FrontFacing);
roughness = 0.0;
# else
- metallic = materialMetallic;
+ metallic = materialColorAndMetal.a;
roughness = materialRoughness;
# endif
@@ -64,7 +62,7 @@ void main()
/* Add some variation to the hairs to avoid uniform look. */
float hair_variation = hair_rand * 0.1;
color = clamp(color - hair_variation, 0.0, 1.0);
- metallic = clamp(materialMetallic - hair_variation, 0.0, 1.0);
+ metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0);
roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0);
# endif
@@ -73,7 +71,7 @@ void main()
#endif /* MATDATA_PASS_ENABLED */
#ifdef OBJECT_ID_PASS_ENABLED
- objectId = uint(object_id);
+ objectId = uint(resource_id + 1) & 0xFFu;
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 7eb12dbdeb9..04dd9ab85bb 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -25,6 +25,10 @@ out vec2 uv_interp;
out vec3 vertexColor;
#endif
+#ifdef OBJECT_ID_PASS_ENABLED
+RESOURCE_ID_VARYING
+#endif
+
/* From http://libnoise.sourceforge.net/noisegen/index.html */
float integer_noise(int n)
{
@@ -91,12 +95,18 @@ void main()
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- normal_viewport = normal_object_to_view(nor);
# ifndef HAIR_SHADER
+ normal_viewport = normal_object_to_view(nor);
normal_viewport = normalize(normal_viewport);
+# else
+ normal_viewport = normal_world_to_view(nor);
# endif
#endif
+#ifdef OBJECT_ID_PASS_ENABLED
+ PASS_RESOURCE_ID
+#endif
+
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index 4a9b0ae3b7d..c38d8fe06bc 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -1,6 +1,4 @@
-uniform vec3 OrcoTexCoFactors[2];
-
uniform sampler2D depthBuffer;
uniform sampler3D densityTexture;
@@ -215,14 +213,14 @@ void main()
vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0);
vs_ray_dir /= abs(vs_ray_dir.z);
- /* TODO(fclem) Precompute the matrix/ */
- vec3 ls_ray_dir = mat3(ViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1] * 2.0;
- ls_ray_dir = mat3(ModelMatrixInverse) * ls_ray_dir;
+ vec3 ls_ray_dir = point_view_to_object(vs_ray_ori + vs_ray_dir);
vec3 ls_ray_ori = point_view_to_object(vs_ray_ori);
vec3 ls_ray_end = point_view_to_object(vs_ray_end);
- ls_ray_ori = (OrcoTexCoFactors[0] + ls_ray_ori * OrcoTexCoFactors[1]) * 2.0 - 1.0;
- ls_ray_end = (OrcoTexCoFactors[0] + ls_ray_end * OrcoTexCoFactors[1]) * 2.0 - 1.0;
+ ls_ray_dir = (OrcoTexCoFactors[0].xyz + ls_ray_dir * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0;
+ ls_ray_ori = (OrcoTexCoFactors[0].xyz + ls_ray_ori * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0;
+ ls_ray_end = (OrcoTexCoFactors[0].xyz + ls_ray_end * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0;
+ ls_ray_dir -= ls_ray_ori;
/* TODO: Align rays to volume center so that it mimics old behaviour of slicing the volume. */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
index 6f0bb56fafd..3542a1a91fc 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
@@ -1,10 +1,11 @@
-uniform vec3 OrcoTexCoFactors[2];
uniform float slicePosition;
uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
in vec3 pos;
+RESOURCE_ID_VARYING
+
#ifdef VOLUME_SLICE
in vec3 uvs;
@@ -27,6 +28,8 @@ void main()
#else
vec3 final_pos = pos;
#endif
- final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0]) / OrcoTexCoFactors[1];
+ final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0].xyz) / OrcoTexCoFactors[1].xyz;
gl_Position = point_object_to_ndc(final_pos);
+
+ PASS_RESOURCE_ID
}
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index 743a1fc42b6..3e63f05ca64 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -111,6 +111,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
zero_v3(wd->background_color_low);
zero_v3(wd->background_color_high);
}
+ wd->background_dither_factor = workbench_background_dither_factor(wpd);
studiolight_update_world(wpd, wpd->studio_light, wd);
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index 262ea7110a4..2e8b952f234 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -78,12 +78,10 @@ static struct {
struct GPUTexture *object_id_tx; /* ref only, not alloced */
struct GPUTexture *color_buffer_tx; /* ref only, not alloced */
struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */
- struct GPUTexture *metallic_buffer_tx; /* ref only, not alloced */
struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
SceneDisplay display; /* world light direction for shadows */
- int next_object_id;
struct GPUUniformBuffer *sampling_ubo;
struct GPUTexture *jitter_tx;
@@ -147,6 +145,7 @@ static char *workbench_build_prepass_frag(void)
{
DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl);
@@ -330,7 +329,6 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
static void workbench_init_object_data(DrawData *dd)
{
WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
- data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
data->shadow_bbox_dirty = true;
}
@@ -379,11 +377,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
workbench_effect_info_init(stl->effects);
}
- if (!e_data.next_object_id) {
+ if (!e_data.shadow_pass_sh) {
WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
memset(sh_data->prepass_sh_cache, 0, sizeof(sh_data->prepass_sh_cache));
memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache));
- e_data.next_object_id = 1;
#ifdef DEBUG_SHADOW_VOLUME
const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
#else
@@ -868,18 +865,11 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_ObjectData),
- &workbench_init_object_data,
- NULL);
WORKBENCH_MaterialData material_template;
const bool is_ghost = (ob->dtx & OB_DRAWXRAY);
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.iuser = iuser;
@@ -899,8 +889,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass);
workbench_material_copy(material, &material_template);
DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1);
- workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, true, interp);
+ workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, interp);
BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
}
return material;
@@ -943,8 +932,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o
(ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass,
shader);
DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, true, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, interp);
}
}
}
@@ -956,7 +944,8 @@ static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata,
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
WORKBENCH_MaterialData *material;
/* Force workbench to render active object textured when in texture paint mode */
diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c
index 06442060623..772d859392b 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_taa.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_taa.c
@@ -139,7 +139,7 @@ void workbench_taa_engine_init(WORKBENCH_Data *vedata)
/* reset complete drawing when navigating. */
if (effect_info->jitter_index != 0) {
- if (rv3d && rv3d->rflag & RV3D_NAVIGATING) {
+ if (rv3d && rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) {
effect_info->jitter_index = 0;
}
}
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 1cbc60ef858..d731b167c06 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -63,8 +63,6 @@ static struct {
struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */
struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
-
- int next_object_id;
} e_data = {{{{NULL}}}};
/* Shaders */
@@ -98,6 +96,18 @@ static char *workbench_build_forward_vert(bool is_hair)
return str;
}
+static char *workbench_build_forward_outline_frag(void)
+{
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl);
+
+ char *str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
static char *workbench_build_forward_transparent_accum_frag(void)
{
DynStr *ds = BLI_dynstr_new();
@@ -129,12 +139,6 @@ static char *workbench_build_forward_composite_frag(void)
return str;
}
-static void workbench_init_object_data(DrawData *dd)
-{
- WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
- data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
-}
-
WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_Data *vedata,
Object *ob,
Material *mat,
@@ -149,18 +153,11 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_MaterialData *material;
- WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
- &ob->id,
- &draw_engine_workbench_solid,
- sizeof(WORKBENCH_ObjectData),
- &workbench_init_object_data,
- NULL);
WORKBENCH_MaterialData material_template;
DRWShadingGroup *grp;
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
- material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.iuser = iuser;
@@ -205,7 +202,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
}
- workbench_material_shgroup_uniform(wpd, grp, material, ob, false, false, interp);
+ workbench_material_shgroup_uniform(wpd, grp, material, ob, false, interp);
material->shgrp = grp;
/* Depth */
@@ -219,8 +216,6 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh,
psl->object_outline_pass);
}
- material->object_id = engine_object_data->object_id;
- DRW_shgroup_uniform_int(material->shgrp_object_outline, "object_id", &material->object_id, 1);
if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES);
}
@@ -292,26 +287,30 @@ void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUSh
char *defines_texture = workbench_material_build_defines(wpd, true, false, false);
char *defines_hair = workbench_material_build_defines(wpd, false, true, false);
char *forward_vert = workbench_build_forward_vert(false);
+ char *forward_frag = workbench_build_forward_outline_frag();
char *forward_hair_vert = workbench_build_forward_vert(true);
+ const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n";
+
sh_data->object_outline_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL},
});
sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_texture, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL},
});
sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL},
- .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, defines_hair, NULL},
+ .frag = (const char *[]){forward_frag, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL},
});
MEM_freeN(forward_hair_vert);
MEM_freeN(forward_vert);
+ MEM_freeN(forward_frag);
MEM_freeN(defines);
MEM_freeN(defines_texture);
MEM_freeN(defines_hair);
@@ -527,7 +526,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
ob, psys, md, psl->transparent_accum_pass, shader);
DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, interp);
DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
/* Hairs have lots of layer and can rapidly become the most prominent surface.
* So lower their alpha artificially. */
@@ -551,7 +550,6 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
shgrp = DRW_shgroup_hair_create(
ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh);
- DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
}
}
}
@@ -562,7 +560,8 @@ static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
WORKBENCH_MaterialData *material;
/* Force workbench to render active object textured when in texture paint mode */
@@ -637,7 +636,8 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
WORKBENCH_MaterialData *material;
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const int materials_len = MAX2(1, ob->totcol);
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index e050877187e..0f9551a8cc9 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -44,20 +44,15 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
WORKBENCH_MaterialData *data,
int color_type)
{
- copy_v3_fl3(data->diffuse_color, 0.8f, 0.8f, 0.8f);
- copy_v3_v3(data->base_color, data->diffuse_color);
- copy_v3_fl3(data->specular_color, 0.05f, 0.05f, 0.05f); /* Dielectric: 5% reflective. */
data->metallic = 0.0f;
data->roughness = 0.632455532f; /* sqrtf(0.4f); */
data->alpha = wpd->shading.xray_alpha;
if (color_type == V3D_SHADING_SINGLE_COLOR) {
- copy_v3_v3(data->diffuse_color, wpd->shading.single_color);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ copy_v3_v3(data->base_color, wpd->shading.single_color);
}
else if (color_type == V3D_SHADING_ERROR_COLOR) {
- copy_v3_fl3(data->diffuse_color, 0.8, 0.0, 0.8);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8);
}
else if (color_type == V3D_SHADING_RANDOM_COLOR) {
uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
@@ -67,30 +62,24 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
float hue = BLI_hash_int_01(hash);
float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
- hsv_to_rgb_v(hsv, data->diffuse_color);
- copy_v3_v3(data->base_color, data->diffuse_color);
+ hsv_to_rgb_v(hsv, data->base_color);
}
else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) {
- copy_v3_v3(data->diffuse_color, ob->color);
- copy_v3_v3(data->base_color, data->diffuse_color);
data->alpha *= ob->color[3];
+ copy_v3_v3(data->base_color, ob->color);
}
else {
/* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */
if (mat) {
data->alpha *= mat->a;
+ copy_v3_v3(data->base_color, &mat->r);
if (workbench_is_specular_highlight_enabled(wpd)) {
- copy_v3_v3(data->base_color, &mat->r);
- mul_v3_v3fl(data->diffuse_color, &mat->r, 1.0f - mat->metallic);
- mul_v3_v3fl(data->specular_color, &mat->r, mat->metallic);
- add_v3_fl(data->specular_color, 0.05f * (1.0f - mat->metallic));
data->metallic = mat->metallic;
data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
}
- else {
- copy_v3_v3(data->base_color, &mat->r);
- copy_v3_v3(data->diffuse_color, &mat->r);
- }
+ }
+ else {
+ copy_v3_fl(data->base_color, 0.8f);
}
}
}
@@ -160,34 +149,40 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
return str;
}
-uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost)
+uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost)
{
- uint input[4];
- uint result;
- float *color = material_template->diffuse_color;
- input[0] = (uint)(color[0] * 512);
- input[1] = (uint)(color[1] * 512);
- input[2] = (uint)(color[2] * 512);
- input[3] = material_template->object_id;
- result = BLI_ghashutil_uinthash_v4_murmur(input);
-
- color = material_template->specular_color;
- input[0] = (uint)(color[0] * 512);
- input[1] = (uint)(color[1] * 512);
- input[2] = (uint)(color[2] * 512);
- input[3] = (uint)(material_template->roughness * 512);
- result += BLI_ghashutil_uinthash_v4_murmur(input);
-
- result += BLI_ghashutil_uinthash((uint)(material_template->alpha * 512));
- result += BLI_ghashutil_uinthash((uint)is_ghost);
- result += BLI_ghashutil_uinthash(material_template->color_type);
-
- /* add texture reference */
- if (material_template->ima) {
- result += BLI_ghashutil_inthash_p_murmur(material_template->ima);
- }
-
- return result;
+ union {
+ struct {
+ /* WHATCH: Keep in sync with View3DShading.color_type max value. */
+ uchar color_type;
+ uchar diff_r;
+ uchar diff_g;
+ uchar diff_b;
+
+ uchar alpha;
+ uchar ghost;
+ uchar metal;
+ uchar roughness;
+
+ void *ima;
+ };
+ /* HACK to ensure input is 4 uint long. */
+ uint a[4];
+ } input = {.color_type = (uchar)(mat->color_type),
+ .diff_r = (uchar)(mat->base_color[0] * 0xFF),
+ .diff_g = (uchar)(mat->base_color[1] * 0xFF),
+ .diff_b = (uchar)(mat->base_color[2] * 0xFF),
+
+ .alpha = (uint)(mat->alpha * 0xFF),
+ .ghost = (uchar)is_ghost,
+ .metal = (uchar)(mat->metallic * 0xFF),
+ .roughness = (uchar)(mat->roughness * 0xFF),
+
+ .ima = mat->ima};
+
+ BLI_assert(sizeof(input) == sizeof(uint) * 4);
+
+ return BLI_ghashutil_uinthash_v4((uint *)&input);
}
int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
@@ -266,8 +261,8 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
int color_type = wpd->shading.color_type;
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
- if ((color_type == V3D_SHADING_TEXTURE_COLOR && (ima == NULL || use_sculpt_pbvh)) ||
- (ob->dt < OB_TEXTURE)) {
+ if ((color_type == V3D_SHADING_TEXTURE_COLOR) &&
+ (ima == NULL || use_sculpt_pbvh || (ob->dt < OB_TEXTURE))) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) {
@@ -315,35 +310,28 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
Object *ob,
- const bool use_metallic,
const bool deferred,
const int interp)
{
- if (!deferred || workbench_is_matdata_pass_enabled(wpd)) {
- if (workbench_material_determine_color_type(wpd, material->ima, ob, false) ==
- V3D_SHADING_TEXTURE_COLOR) {
- GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "image", tex);
- DRW_shgroup_uniform_bool_copy(
- grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
- DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
- }
- else {
- DRW_shgroup_uniform_vec3(grp,
- "materialDiffuseColor",
- (use_metallic) ? material->base_color : material->diffuse_color,
- 1);
- }
+ if (!(!deferred || workbench_is_matdata_pass_enabled(wpd))) {
+ return;
+ }
- if (workbench_is_specular_highlight_enabled(wpd)) {
- if (use_metallic) {
- DRW_shgroup_uniform_float(grp, "materialMetallic", &material->metallic, 1);
- }
- else {
- DRW_shgroup_uniform_vec3(grp, "materialSpecularColor", material->specular_color, 1);
- }
- DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
- }
+ const bool use_highlight = workbench_is_specular_highlight_enabled(wpd);
+ const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type(
+ wpd, material->ima, ob, false));
+ if (use_texture) {
+ GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_bool_copy(
+ grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
+ DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
+ }
+
+ DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1);
+
+ if (use_highlight) {
+ DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
}
if (WORLD_CLIPPING_ENABLED(wpd)) {
@@ -354,10 +342,7 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
const WORKBENCH_MaterialData *source_material)
{
- dest_material->object_id = source_material->object_id;
copy_v3_v3(dest_material->base_color, source_material->base_color);
- copy_v3_v3(dest_material->diffuse_color, source_material->diffuse_color);
- copy_v3_v3(dest_material->specular_color, source_material->specular_color);
dest_material->metallic = source_material->metallic;
dest_material->roughness = source_material->roughness;
dest_material->ima = source_material->ima;
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index d880d5d58b5..595b92d19d0 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -75,7 +75,8 @@
V3D_SHADING_VERTEX_COLOR))
#define IS_NAVIGATING(wpd) \
- ((DRW_context_state_get()->rv3d) && (DRW_context_state_get()->rv3d->rflag & RV3D_NAVIGATING))
+ ((DRW_context_state_get()->rv3d) && \
+ (DRW_context_state_get()->rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)))
#define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
#define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
@@ -193,7 +194,8 @@ typedef struct WORKBENCH_UBO_World {
float background_alpha;
float curvature_ridge;
float curvature_valley;
- int pad[3];
+ float background_dither_factor;
+ int pad[2];
} WORKBENCH_UBO_World;
BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16)
@@ -281,13 +283,8 @@ typedef struct WORKBENCH_EffectInfo {
} WORKBENCH_EffectInfo;
typedef struct WORKBENCH_MaterialData {
- float base_color[3];
- float diffuse_color[3];
- float specular_color[3];
- float alpha;
- float metallic;
- float roughness;
- int object_id;
+ float base_color[3], metallic;
+ float roughness, alpha;
int color_type;
int interp;
Image *ima;
@@ -308,8 +305,6 @@ typedef struct WORKBENCH_ObjectData {
float shadow_min[3], shadow_max[3];
BoundBox shadow_bbox;
bool shadow_bbox_dirty;
-
- int object_id;
} WORKBENCH_ObjectData;
/* inline helper functions */
@@ -412,6 +407,13 @@ BLI_INLINE eGPUTextureFormat workbench_color_texture_format(const WORKBENCH_Priv
return result;
}
+BLI_INLINE bool workbench_background_dither_factor(const WORKBENCH_PrivateData *wpd)
+{
+ /* Only apply dithering when rendering on a RGBA8 texture.
+ * The dithering will remove banding when using a gradient as background */
+ return workbench_color_texture_format(wpd) == GPU_RGBA8;
+}
+
/* workbench_deferred.c */
void workbench_deferred_engine_init(WORKBENCH_Data *vedata);
void workbench_deferred_engine_free(void);
@@ -500,7 +502,6 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
Object *ob,
- const bool use_metallic,
const bool deferred,
const int interp);
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c
index ac27ff0b736..941a6741998 100644
--- a/source/blender/draw/engines/workbench/workbench_studiolight.c
+++ b/source/blender/draw/engines/workbench/workbench_studiolight.c
@@ -131,7 +131,7 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd,
static void compute_parallel_lines_nor_and_dist(const float v1[2],
const float v2[2],
const float v3[2],
- float r_line[2])
+ float r_line[4])
{
sub_v2_v2v2(r_line, v2, v1);
/* Find orthogonal vector. */
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 7ae9d90daff..23f0898c138 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -27,6 +27,7 @@
#include "BLI_rand.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
@@ -45,8 +46,6 @@ enum {
static struct {
struct GPUShader *volume_sh[VOLUME_SH_MAX];
struct GPUShader *volume_coba_sh;
- struct GPUShader *volume_slice_sh;
- struct GPUShader *volume_slice_coba_sh;
struct GPUTexture *dummy_tex;
struct GPUTexture *dummy_coba_tex;
} e_data = {{NULL}};
@@ -54,6 +53,7 @@ static struct {
extern char datatoc_workbench_volume_vert_glsl[];
extern char datatoc_workbench_volume_frag_glsl[];
extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
{
@@ -78,12 +78,16 @@ static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
char *defines = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
+ char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl);
+
e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl,
NULL,
datatoc_workbench_volume_frag_glsl,
- datatoc_common_view_lib_glsl,
+ libs,
defines);
+ MEM_freeN(libs);
MEM_freeN(defines);
}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 4b170e8a2ea..7bcb048017e 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -75,15 +75,13 @@ struct RenderEngineType;
struct bContext;
struct rcti;
+typedef struct DRWCallBuffer DRWCallBuffer;
typedef struct DRWInterface DRWInterface;
typedef struct DRWPass DRWPass;
typedef struct DRWShadingGroup DRWShadingGroup;
typedef struct DRWUniform DRWUniform;
typedef struct DRWView DRWView;
-/* Opaque type to avoid usage as a DRWCall but it is exactly the same thing. */
-typedef struct DRWCallBuffer DRWCallBuffer;
-
/* TODO Put it somewhere else? */
typedef struct BoundSphere {
float center[3], radius;
@@ -415,35 +413,29 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
Object *ob,
float (*obmat)[4],
struct GPUBatch *geom,
- uint v_sta,
- uint v_ct,
bool bypass_culling,
void *user_data);
/* If ob is NULL, unit modelmatrix is assumed and culling is bypassed. */
-#define DRW_shgroup_call(shgrp, geom, ob) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, NULL)
+#define DRW_shgroup_call(shgrp, geom, ob) DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, NULL)
/* Same as DRW_shgroup_call but override the obmat. Not culled. */
#define DRW_shgroup_call_obmat(shgrp, geom, obmat) \
- DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, 0, 0, false, NULL)
+ DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, false, NULL)
/* TODO(fclem) remove this when we have DRWView */
/* user_data is used by DRWCallVisibilityFn defined in DRWView. */
#define DRW_shgroup_call_with_callback(shgrp, geom, ob, user_data) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, user_data)
+ DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, user_data)
/* Same as DRW_shgroup_call but bypass culling even if ob is not NULL. */
#define DRW_shgroup_call_no_cull(shgrp, geom, ob) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, true, NULL)
+ DRW_shgroup_call_ex(shgrp, ob, NULL, geom, true, NULL)
-/* Only draw a certain range of geom. */
-#define DRW_shgroup_call_range(shgrp, geom, ob, v_sta, v_ct) \
- DRW_shgroup_call_ex(shgrp, ob, NULL, geom, v_sta, v_ct, false, NULL)
-
-/* Same as DRW_shgroup_call_range but override the obmat. Special for gpencil. */
-#define DRW_shgroup_call_range_obmat(shgrp, geom, obmat, v_sta, v_ct) \
- DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, v_sta, v_ct, false, NULL)
+void DRW_shgroup_call_range(DRWShadingGroup *shgroup,
+ struct GPUBatch *geom,
+ uint v_sta,
+ uint v_ct);
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_ct);
void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_ct);
@@ -480,6 +472,16 @@ void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
+/* Issue a clear command. */
+void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil);
+
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup,
const char *name,
const struct GPUTexture *tex);
@@ -536,17 +538,17 @@ void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4]);
/* Store value instead of referencing it. */
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value);
+void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
+void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
+void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgrp, const char *name, const int *value);
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value);
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value);
void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
-/* TODO: workaround functions waiting for the clearing operation to be available inside the
- * shgroups. */
-DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup);
-uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup);
-
/* Passes */
DRWPass *DRW_pass_create(const char *name, DRWState state);
/* TODO Replace with passes inheritance. */
diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c
index 72459309133..7e0110cbb99 100644
--- a/source/blender/draw/intern/draw_anim_viz.c
+++ b/source/blender/draw/intern/draw_anim_viz.c
@@ -215,7 +215,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl,
DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
}
/* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), NULL, start_index, len);
+ DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), start_index, len);
}
/* Draw points. */
@@ -231,7 +231,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl,
DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
}
/* Only draw the required range. */
- DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), NULL, start_index, len);
+ DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), start_index, len);
/* Draw frame numbers at each framestep value */
bool show_kf_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
@@ -289,10 +289,9 @@ static void MPATH_cache_populate(void *vedata, Object *ob)
}
}
}
- else {
- if (ob->mpath) {
- MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath);
- }
+
+ if (ob->mpath) {
+ MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath);
}
}
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
index 865cfea14e3..5cd6a4a1286 100644
--- a/source/blender/draw/intern/draw_armature.c
+++ b/source/blender/draw/intern/draw_armature.c
@@ -60,7 +60,6 @@ static struct {
Object *ob;
/* Reset when changing current_armature */
DRWCallBuffer *bone_octahedral_solid;
- DRWCallBuffer *bone_octahedral_wire;
DRWCallBuffer *bone_octahedral_outline;
DRWCallBuffer *bone_box_solid;
DRWCallBuffer *bone_box_wire;
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 06ed661ad8e..b085d402e81 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -53,7 +53,6 @@ static struct DRWShapeCache {
GPUBatch *drw_cursor;
GPUBatch *drw_cursor_only_circle;
GPUBatch *drw_fullscreen_quad;
- GPUBatch *drw_fullscreen_quad_texcoord;
GPUBatch *drw_quad;
GPUBatch *drw_quad_wires;
GPUBatch *drw_grid;
@@ -72,8 +71,6 @@ static struct DRWShapeCache {
GPUBatch *drw_empty_capsule_body;
GPUBatch *drw_empty_capsule_cap;
GPUBatch *drw_empty_cone;
- GPUBatch *drw_arrows;
- GPUBatch *drw_axis_names;
GPUBatch *drw_image_plane;
GPUBatch *drw_image_plane_wire;
GPUBatch *drw_field_wind;
@@ -99,7 +96,6 @@ static struct DRWShapeCache {
GPUBatch *drw_bone_octahedral_wire;
GPUBatch *drw_bone_box;
GPUBatch *drw_bone_box_wire;
- GPUBatch *drw_bone_wire_wire;
GPUBatch *drw_bone_envelope;
GPUBatch *drw_bone_envelope_outline;
GPUBatch *drw_bone_point;
@@ -111,7 +107,6 @@ static struct DRWShapeCache {
GPUBatch *drw_camera;
GPUBatch *drw_camera_frame;
GPUBatch *drw_camera_tria;
- GPUBatch *drw_camera_focus;
GPUBatch *drw_particle_cross;
GPUBatch *drw_particle_circle;
GPUBatch *drw_particle_axis;
@@ -347,6 +342,7 @@ GPUBatch *DRW_cache_fullscreen_quad_get(void)
attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "texCoord");
+ GPU_vertformat_alias_add(&format, "orco"); /* Fix driver bug (see T70004) */
}
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 75b8d820884..b1eab3c73ae 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -48,6 +48,9 @@ typedef struct DRW_MeshCDMask {
uint32_t vcol : 8;
uint32_t orco : 1;
uint32_t tan_orco : 1;
+ /** Edit uv layer is from the base edit mesh as
+ * modifiers could remove it. (see T68857) */
+ uint32_t edit_uv : 1;
} DRW_MeshCDMask;
typedef enum eMRIterType {
@@ -78,7 +81,7 @@ BLI_INLINE int mesh_render_mat_len_get(Mesh *me)
typedef struct MeshBufferCache {
/* Every VBO below contains at least enough
- * data for every loops in the mesh (except fdots).
+ * data for every loops in the mesh (except fdots and skin roots).
* For some VBOs, it extends to (in this exact order) :
* loops + loose_edges*2 + loose_verts */
struct {
@@ -101,6 +104,7 @@ typedef struct MeshBufferCache {
GPUVertBuf *fdots_uv;
// GPUVertBuf *fdots_edit_data; /* inside fdots_nor for now. */
GPUVertBuf *fdots_edituv_data;
+ GPUVertBuf *skin_roots;
/* Selection */
GPUVertBuf *vert_idx; /* extend */
GPUVertBuf *edge_idx; /* extend */
@@ -154,6 +158,7 @@ typedef enum DRWBatchFlag {
MBC_WIRE_LOOPS = (1 << 24),
MBC_WIRE_LOOPS_UVS = (1 << 25),
MBC_SURF_PER_MAT = (1 << 26),
+ MBC_SKIN_ROOTS = (1 << 27),
} DRWBatchFlag;
#define MBC_EDITUV \
@@ -182,6 +187,7 @@ typedef struct MeshBatchCache {
GPUBatch *edit_lnor;
GPUBatch *edit_fdots;
GPUBatch *edit_mesh_analysis;
+ GPUBatch *edit_skin_roots;
/* Edit UVs */
GPUBatch *edituv_faces_stretch_area;
GPUBatch *edituv_faces_stretch_angle;
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index d7971a9e7db..fb439016a87 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -949,10 +949,8 @@ BLI_INLINE void lines_adjacency_triangle(
GPUIndexBufBuilder *elb = &data->elb;
/* Iter around the triangle's edges. */
for (int e = 0; e < 3; e++) {
- uint tmp = v1;
- v1 = v2, v2 = v3, v3 = tmp;
- tmp = l1;
- l1 = l2, l2 = l3, l3 = tmp;
+ SHIFT3(uint, v3, v2, v1);
+ SHIFT3(uint, l3, l2, l1);
bool inv_indices = (v2 > v3);
void **pval;
@@ -1185,8 +1183,7 @@ static void extract_edituv_lines_loop_mesh(const MeshRenderData *mr,
{
int loopend = mpoly->totloop + mpoly->loopstart - 1;
int loop_next_idx = (loop_idx == loopend) ? mpoly->loopstart : (loop_idx + 1);
- const bool real_edge = (mr->extract_type == MR_EXTRACT_MAPPED &&
- mr->e_origindex[mloop->e] != ORIGINDEX_NONE);
+ const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[mloop->e] != ORIGINDEX_NONE);
edituv_edge_add(data,
(mpoly->flag & ME_HIDE) != 0 || !real_edge,
(mpoly->flag & ME_FACE_SEL) != 0,
@@ -1604,6 +1601,14 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf)
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
uint32_t uv_layers = mr->cache->cd_used.uv;
+ /* HACK to fix T68857 */
+ if (mr->extract_type == MR_EXTRACT_BMESH && mr->cache->cd_used.edit_uv == 1) {
+ int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
+ if (layer != -1) {
+ uv_layers |= (1 << layer);
+ }
+ }
+
for (int i = 0; i < MAX_MTFACE; i++) {
if (uv_layers & (1 << i)) {
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
@@ -3855,6 +3860,69 @@ static const MeshExtract extract_fdots_edituv_data = {
/** \} */
/* ---------------------------------------------------------------------- */
+/** \name Extract Skin Modifier Roots
+ * \{ */
+
+typedef struct SkinRootData {
+ float size;
+ float local_pos[3];
+} SkinRootData;
+
+static void *extract_skin_roots_init(const MeshRenderData *mr, void *buf)
+{
+ /* Exclusively for edit mode. */
+ BLI_assert(mr->bm);
+
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "local_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+ GPUVertBuf *vbo = buf;
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->bm->totvert);
+
+ SkinRootData *vbo_data = (SkinRootData *)vbo->data;
+
+ int root_len = 0;
+ int cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MVERT_SKIN);
+
+ BMIter iter;
+ BMVert *eve;
+ BM_ITER_MESH (eve, &iter, mr->bm, BM_VERTS_OF_MESH) {
+ const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_ofs);
+ if (vs->flag & MVERT_SKIN_ROOT) {
+ vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f;
+ copy_v3_v3(vbo_data->local_pos, eve->co);
+ vbo_data++;
+ root_len++;
+ }
+ }
+
+ /* It's really unlikely that all verts will be roots. Resize to avoid loosing VRAM. */
+ GPU_vertbuf_data_len_set(vbo, root_len);
+
+ return NULL;
+}
+
+static const MeshExtract extract_skin_roots = {
+ extract_skin_roots_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ false,
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
/** \name Extract Selection Index
* \{ */
@@ -4286,6 +4354,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
TEST_ASSIGN(VBO, vbo, edge_idx);
TEST_ASSIGN(VBO, vbo, vert_idx);
TEST_ASSIGN(VBO, vbo, fdot_idx);
+ TEST_ASSIGN(VBO, vbo, skin_roots);
TEST_ASSIGN(IBO, ibo, tris);
TEST_ASSIGN(IBO, ibo, lines);
@@ -4329,7 +4398,8 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
if (mbc.buf.name) { \
extract_task_create( \
task_pool, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \
- }
+ } \
+ ((void)0)
EXTRACT(vbo, pos_nor);
EXTRACT(vbo, lnor);
@@ -4352,6 +4422,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
EXTRACT(vbo, edge_idx);
EXTRACT(vbo, vert_idx);
EXTRACT(vbo, fdot_idx);
+ EXTRACT(vbo, skin_roots);
EXTRACT(ibo, tris);
EXTRACT(ibo, lines);
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 970b6053cf9..8cb318bd0bb 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -142,6 +142,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edit_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edit_skin_roots(struct Mesh *me);
/* edit-mesh selection */
struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(struct Mesh *me);
@@ -151,8 +152,8 @@ struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me);
/* edit-mesh UV editor */
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Mesh *me,
- float *tot_area,
- float *tot_uv_area);
+ float **tot_area,
+ float **tot_uv_area);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Mesh *me);
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 56b2b20cc05..ca185fa7d7d 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -90,9 +90,15 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
*((uint32_t *)a) = 0;
}
+static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used)
+{
+ cd_used->edit_uv = 1;
+}
+
static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
- const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata;
+ const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ const CustomData *cd_ldata = &me_final->ldata;
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
@@ -102,7 +108,8 @@ static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used
static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
- const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata;
+ const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ const CustomData *cd_ldata = &me_final->ldata;
int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
@@ -112,7 +119,8 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd
static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
- const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata;
+ const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ const CustomData *cd_ldata = &me_final->ldata;
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
if (layer != -1) {
@@ -124,7 +132,8 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
struct GPUMaterial **gpumat_array,
int gpumat_array_len)
{
- const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata;
+ const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ const CustomData *cd_ldata = &me_final->ldata;
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;
@@ -227,7 +236,8 @@ static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me,
int **r_auto_layers_srgb,
int *r_auto_layers_len)
{
- const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata;
+ const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ const CustomData *cd_ldata = &me_final->ldata;
int uv_len_used = count_bits_i(cd_used.uv);
int vcol_len_used = count_bits_i(cd_used.vcol);
@@ -458,6 +468,16 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
}
}
+static void mesh_batch_cache_discard_shaded_batches(MeshBatchCache *cache)
+{
+ if (cache->surface_per_mat) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]);
+ }
+ }
+ cache->batch_ready &= ~MBC_SURF_PER_MAT;
+}
+
static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
{
FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
@@ -468,21 +488,13 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.vcol);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.orco);
}
+ mesh_batch_cache_discard_shaded_batches(cache);
+ mesh_cd_layers_type_clear(&cache->cd_used);
- if (cache->surface_per_mat) {
- for (int i = 0; i < cache->mat_len; i++) {
- GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]);
- }
- }
MEM_SAFE_FREE(cache->surface_per_mat);
-
- cache->batch_ready &= ~MBC_SURF_PER_MAT;
-
MEM_SAFE_FREE(cache->auto_layer_names);
MEM_SAFE_FREE(cache->auto_layer_is_srgb);
- mesh_cd_layers_type_clear(&cache->cd_used);
-
cache->mat_len = 0;
}
@@ -513,6 +525,37 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
cache->tot_uv_area = 0.0f;
cache->batch_ready &= ~MBC_EDITUV;
+
+ /* We discarded the vbo.uv so we need to reset the cd_used flag. */
+ cache->cd_used.uv = 0;
+ cache->cd_used.edit_uv = 0;
+
+ /* Discard other batches that uses vbo.uv */
+ mesh_batch_cache_discard_shaded_batches(cache);
+
+ GPU_BATCH_DISCARD_SAFE(cache->batch.surface);
+ cache->batch_ready &= ~MBC_SURFACE;
+}
+
+static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache)
+{
+ FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
+ GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_tris);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_lines);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points);
+ GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots);
+ }
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots);
+ GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs);
+ cache->batch_ready &= ~MBC_EDITUV;
}
void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
@@ -541,8 +584,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS |
MBC_EDIT_SELECTION_FACES | MBC_EDIT_SELECTION_EDGES |
MBC_EDIT_SELECTION_VERTS | MBC_EDIT_MESH_ANALYSIS);
- /* Because visible UVs depends on edit mode selection, discard everything. */
- mesh_batch_cache_discard_uvedit(cache);
+ /* Because visible UVs depends on edit mode selection, discard topology. */
+ mesh_batch_cache_discard_uvedit_select(cache);
break;
case BKE_MESH_BATCH_DIRTY_SELECT_PAINT:
/* Paint mode selection flag is packed inside the nor attrib.
@@ -836,6 +879,13 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(Mesh *me)
return DRW_batch_request(&cache->batch.edit_fdots);
}
+GPUBatch *DRW_mesh_batch_cache_get_edit_skin_roots(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+ mesh_batch_cache_add_request(cache, MBC_SKIN_ROOTS);
+ return DRW_batch_request(&cache->batch.edit_skin_roots);
+}
+
/** \} */
/* ---------------------------------------------------------------------- */
@@ -876,24 +926,37 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me)
/** \name UV Image editor API
* \{ */
+static void edituv_request_active_uv(MeshBatchCache *cache, Mesh *me)
+{
+ DRW_MeshCDMask cd_needed;
+ mesh_cd_layers_type_clear(&cd_needed);
+ mesh_cd_calc_edit_uv_layer(me, &cd_needed);
+
+ BLI_assert(cd_needed.edit_uv != 0 &&
+ "No uv layer available in edituv, but batches requested anyway!");
+
+ mesh_cd_calc_active_mask_uv_layer(me, &cd_needed);
+ mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
+}
+
/* Creates the GPUBatch for drawing the UV Stretching Area Overlay.
* Optional retrieves the total area or total uv area of the mesh.
*
* The `cache->tot_area` and cache->tot_uv_area` update are calculation are
* only valid after calling `DRW_mesh_batch_cache_create_requested`. */
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
- float *tot_area,
- float *tot_uv_area)
+ float **tot_area,
+ float **tot_uv_area)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA);
if (tot_area != NULL) {
- *tot_area = cache->tot_area;
+ *tot_area = &cache->tot_area;
}
if (tot_uv_area != NULL) {
- *tot_uv_area = cache->tot_uv_area;
+ *tot_uv_area = &cache->tot_uv_area;
}
return DRW_batch_request(&cache->batch.edituv_faces_stretch_area);
}
@@ -901,7 +964,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE);
return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle);
}
@@ -909,7 +972,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES);
return DRW_batch_request(&cache->batch.edituv_faces);
}
@@ -917,7 +980,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES);
return DRW_batch_request(&cache->batch.edituv_edges);
}
@@ -925,7 +988,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS);
return DRW_batch_request(&cache->batch.edituv_verts);
}
@@ -933,7 +996,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS);
return DRW_batch_request(&cache->batch.edituv_fdots);
}
@@ -941,7 +1004,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me)
GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, me);
mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS_UVS);
return DRW_batch_request(&cache->batch.wire_loops_uvs);
}
@@ -1016,12 +1079,37 @@ void DRW_mesh_batch_cache_create_requested(
}
}
+ /* HACK: if MBC_SURF_PER_MAT is requested and ibo.tris is already available, it won't have it's
+ * index ranges initialized. So discard ibo.tris in order to recreate it.
+ * This needs to happen before saved_elem_ranges is populated. */
+ if ((batch_requested & MBC_SURF_PER_MAT) != 0 && (cache->batch_ready & MBC_SURF_PER_MAT) == 0) {
+ FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
+ {
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.tris);
+ }
+ /* Clear all batches that reference ibo.tris. */
+ GPU_BATCH_CLEAR_SAFE(cache->batch.surface);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_mesh_analysis);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_triangles);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_lnor);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edit_selection_faces);
+ for (int i = 0; i < cache->mat_len; i++) {
+ GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]);
+ }
+
+ cache->batch_ready &= ~(MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_MESH_ANALYSIS |
+ MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR | MBC_EDIT_SELECTION_FACES);
+ }
+
if (batch_requested &
(MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA |
MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) {
/* Modifiers will only generate an orco layer if the mesh is deformed. */
if (cache->cd_needed.orco != 0) {
- if (CustomData_get_layer(&me->vdata, CD_ORCO) == NULL) {
+ /* Orco is always extracted from final mesh. */
+ Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) {
/* Skip orco calculation */
cache->cd_needed.orco = 0;
}
@@ -1083,9 +1171,6 @@ void DRW_mesh_batch_cache_create_requested(
FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
{
GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.edituv_data);
- GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_angle);
- GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_area);
- GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv);
GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.fdots_uv);
GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_tris);
GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_lines);
@@ -1241,6 +1326,18 @@ void DRW_mesh_batch_cache_create_requested(
DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_pos);
DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_nor);
}
+ if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_LINES)) {
+ DRW_vbo_request(cache->batch.edit_skin_roots, &mbufcache->vbo.skin_roots);
+ /* HACK(fclem): This is to workaround the deferred batch init
+ * that prevent drawing using DRW_shgroup_call_instances_with_attribs.
+ * So we instead create the whole instancing batch here.
+ * Note that we use GPU_PRIM_LINES instead of expected GPU_PRIM_LINE_STRIP
+ * in order to mimic the old stipple pattern. */
+ cache->batch.edit_skin_roots->inst = cache->batch.edit_skin_roots->verts[0];
+ cache->batch.edit_skin_roots->verts[0] = NULL;
+ GPUBatch *circle = DRW_cache_screenspace_circle_get();
+ GPU_batch_vertbuf_add(cache->batch.edit_skin_roots, circle->verts[0]);
+ }
/* Selection */
if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) {
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index d6e5da9307e..b1fde427de2 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -83,6 +83,7 @@ void DRW_globals_update(void)
UI_GetThemeColor4fv(TH_VNORMAL, gb->colorVNormal);
UI_GetThemeColor4fv(TH_LNORMAL, gb->colorLNormal);
UI_GetThemeColor4fv(TH_FACE_DOT, gb->colorFaceDot);
+ UI_GetThemeColor4fv(TH_SKIN_ROOT, gb->colorSkinRoot);
UI_GetThemeColor4fv(TH_BACK, gb->colorBackground);
/* Custom median color to slightly affect the edit mesh colors. */
@@ -277,7 +278,6 @@ static struct {
struct GPUVertFormat *instance_scaled;
struct GPUVertFormat *instance_sized;
struct GPUVertFormat *instance_outline;
- struct GPUVertFormat *instance;
struct GPUVertFormat *instance_camera;
struct GPUVertFormat *instance_distance_lines;
struct GPUVertFormat *instance_spot;
@@ -1095,7 +1095,7 @@ struct GPUShader *volume_velocity_shader_get(bool use_needle)
NULL,
datatoc_gpu_shader_flat_color_frag_glsl,
datatoc_common_view_lib_glsl,
- "#define USE_NEEDLE");
+ "#define USE_NEEDLE\n");
}
return sh_data->volume_velocity_needle_sh;
}
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 9899b6c0194..01c0946247a 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -73,6 +73,7 @@ typedef struct GlobalsUboStorage {
float colorVNormal[4];
float colorLNormal[4];
float colorFaceDot[4];
+ float colorSkinRoot[4];
float colorDeselect[4];
float colorOutline[4];
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index f77243ca9f1..58085cf08c6 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -201,30 +201,33 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
/* Transform Feedback subdiv. */
if (need_ft_update) {
int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len;
- GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
+ if (final_points_len) {
+ GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
#ifdef USE_TRANSFORM_FEEDBACK
- DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
- tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
+ tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf);
#else
- DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
-
- ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
- pr_call->next = g_tf_calls;
- pr_call->vbo = hair_cache->final[subdiv].proc_buf;
- pr_call->shgrp = tf_shgrp;
- pr_call->vert_len = final_points_len;
- g_tf_calls = pr_call;
- DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
+
+ ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
+ pr_call->next = g_tf_calls;
+ pr_call->vbo = hair_cache->final[subdiv].proc_buf;
+ pr_call->shgrp = tf_shgrp;
+ pr_call->vert_len = final_points_len;
+ g_tf_calls = pr_call;
+ DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
#endif
- DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex);
- DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
- DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex);
+ DRW_shgroup_uniform_int(
+ tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
+ DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ }
}
return shgrp;
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 69756203d66..81b10e095c3 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -64,7 +64,7 @@ typedef struct DRWTempBufferHandle {
/** Format pointer for reuse. */
GPUVertFormat *format;
/** Touched vertex length for resize. */
- uint *vert_len;
+ int *vert_len;
} DRWTempBufferHandle;
static ListBase g_idatalists = {NULL, NULL};
@@ -112,7 +112,7 @@ static void instance_batch_free(GPUBatch *geom, void *UNUSED(user_data))
*/
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
- uint *vert_len)
+ int *vert_len)
{
BLI_assert(format != NULL);
BLI_assert(vert_len != NULL);
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index 2ede68e16d8..524c4cd96d8 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -40,7 +40,7 @@ DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
- uint *vert_len);
+ int *vert_len);
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *geom);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index f4648405cfd..b75053f461e 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -165,7 +165,7 @@ struct DRWTextStore *DRW_text_cache_ensure(void)
bool DRW_object_is_renderable(const Object *ob)
{
- BLI_assert((ob->base_flag & BASE_VISIBLE) != 0);
+ BLI_assert((ob->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0);
if (ob->type == OB_MESH) {
if ((ob == DST.draw_ctx.object_edit) || BKE_object_is_in_editmode(ob)) {
@@ -538,8 +538,11 @@ static void drw_viewport_cache_resize(void)
GPU_texture_free(*tex);
}
- BLI_memblock_clear(DST.vmempool->calls, NULL);
- BLI_memblock_clear(DST.vmempool->states, NULL);
+ BLI_memblock_clear(DST.vmempool->commands, NULL);
+ BLI_memblock_clear(DST.vmempool->commands_small, NULL);
+ BLI_memblock_clear(DST.vmempool->callbuffers, NULL);
+ BLI_memblock_clear(DST.vmempool->obmats, NULL);
+ BLI_memblock_clear(DST.vmempool->obinfos, NULL);
BLI_memblock_clear(DST.vmempool->cullstates, NULL);
BLI_memblock_clear(DST.vmempool->shgroups, NULL);
BLI_memblock_clear(DST.vmempool->uniforms, NULL);
@@ -587,28 +590,28 @@ static void drw_context_state_init(void)
}
}
-static DRWCallState *draw_unit_state_create(void)
+static void draw_unit_state_create(void)
{
- DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states);
- state->flag = 0;
- state->matflag = 0;
+ DRWObjectInfos *infos = BLI_memblock_alloc(DST.vmempool->obinfos);
+ DRWObjectMatrix *mats = BLI_memblock_alloc(DST.vmempool->obmats);
+ DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates);
- unit_m4(state->model);
- unit_m4(state->modelinverse);
+ unit_m4(mats->model);
+ unit_m4(mats->modelinverse);
- copy_v3_fl(state->orcotexfac[0], 0.0f);
- copy_v3_fl(state->orcotexfac[1], 1.0f);
+ copy_v3_fl(infos->orcotexfac[0], 0.0f);
+ copy_v3_fl(infos->orcotexfac[1], 1.0f);
- state->ob_index = 0;
- state->ob_random = 0.0f;
- copy_v3_fl(state->ob_color, 1.0f);
+ infos->ob_index = 0;
+ infos->ob_random = 0.0f;
+ infos->ob_neg_scale = 1.0f;
+ copy_v3_fl(infos->ob_color, 1.0f);
/* TODO(fclem) get rid of this. */
- state->culling = BLI_memblock_alloc(DST.vmempool->cullstates);
- state->culling->bsphere.radius = -1.0f;
- state->culling->user_data = NULL;
+ culling->bsphere.radius = -1.0f;
+ culling->user_data = NULL;
- return state;
+ DRW_handle_increment(&DST.resource_handle);
}
/* It also stores viewport variable to an immutable place: DST
@@ -633,33 +636,48 @@ static void drw_viewport_var_init(void)
DST.vmempool = GPU_viewport_mempool_get(DST.viewport);
- if (DST.vmempool->calls == NULL) {
- DST.vmempool->calls = BLI_memblock_create(sizeof(DRWCall));
+ if (DST.vmempool->commands == NULL) {
+ DST.vmempool->commands = BLI_memblock_create(sizeof(DRWCommandChunk));
}
- if (DST.vmempool->states == NULL) {
- DST.vmempool->states = BLI_memblock_create(sizeof(DRWCallState));
+ if (DST.vmempool->commands_small == NULL) {
+ DST.vmempool->commands_small = BLI_memblock_create(sizeof(DRWCommandSmallChunk));
+ }
+ if (DST.vmempool->callbuffers == NULL) {
+ DST.vmempool->callbuffers = BLI_memblock_create(sizeof(DRWCallBuffer));
+ }
+ if (DST.vmempool->obmats == NULL) {
+ uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len);
+ }
+ if (DST.vmempool->obinfos == NULL) {
+ uint chunk_len = sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->obinfos = BLI_memblock_create_ex(sizeof(DRWObjectInfos), chunk_len);
}
if (DST.vmempool->cullstates == NULL) {
- DST.vmempool->cullstates = BLI_memblock_create(sizeof(DRWCullingState));
+ uint chunk_len = sizeof(DRWCullingState) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->cullstates = BLI_memblock_create_ex(sizeof(DRWCullingState), chunk_len);
}
if (DST.vmempool->shgroups == NULL) {
DST.vmempool->shgroups = BLI_memblock_create(sizeof(DRWShadingGroup));
}
if (DST.vmempool->uniforms == NULL) {
- DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniform));
+ DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniformChunk));
}
if (DST.vmempool->views == NULL) {
DST.vmempool->views = BLI_memblock_create(sizeof(DRWView));
}
if (DST.vmempool->passes == NULL) {
- DST.vmempool->passes = BLI_memblock_create(sizeof(DRWPass));
+ uint chunk_len = sizeof(DRWPass) * DRW_RESOURCE_CHUNK_LEN;
+ DST.vmempool->passes = BLI_memblock_create_ex(sizeof(DRWPass), chunk_len);
}
if (DST.vmempool->images == NULL) {
DST.vmempool->images = BLI_memblock_create(sizeof(GPUTexture *));
}
- /* Alloc default unit state */
- DST.unit_state = draw_unit_state_create();
+ DST.resource_handle = 0;
+ DST.pass_handle = 0;
+
+ draw_unit_state_create();
DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport);
DRW_instance_data_list_reset(DST.idatalist);
@@ -673,8 +691,6 @@ static void drw_viewport_var_init(void)
DST.default_framebuffer = NULL;
DST.vmempool = NULL;
-
- DST.unit_state = NULL;
}
DST.primary_view_ct = 0;
@@ -717,6 +733,10 @@ static void drw_viewport_var_init(void)
G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(DRWViewUboStorage), NULL);
}
+ if (DST.draw_list == NULL) {
+ DST.draw_list = GPU_draw_list_create(DRW_DRAWLIST_LEN);
+ }
+
memset(DST.object_instance_data, 0x0, sizeof(DST.object_instance_data));
}
@@ -1100,7 +1120,7 @@ static void drw_engines_world_update(Scene *scene)
static void drw_engines_cache_populate(Object *ob)
{
- DST.ob_state = NULL;
+ DST.ob_handle = 0;
/* HACK: DrawData is copied by COW from the duplicated object.
* This is valid for IDs that cannot be instantiated but this
@@ -1152,7 +1172,7 @@ static void drw_engines_cache_finish(void)
MEM_freeN(DST.vedata_array);
}
-static void drw_engines_draw_background(void)
+static bool drw_engines_draw_background(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
@@ -1166,10 +1186,20 @@ static void drw_engines_draw_background(void)
DRW_stats_group_end();
PROFILE_END_UPDATE(data->background_time, stime);
- return;
+ return true;
}
}
+ /* No draw engines draw the background. We clear the background.
+ * We draw the background after drawing of the scene so the camera background
+ * images can be drawn using ALPHA Under. Otherwise the background always
+ * interfered with the alpha blending. */
+ DRW_clear_background();
+ return false;
+}
+
+static void drw_draw_background_alpha_under(void)
+{
/* No draw_background found, doing default background */
const bool do_alpha_checker = !DRW_state_draw_background();
DRW_draw_background(do_alpha_checker);
@@ -1546,20 +1576,6 @@ void DRW_draw_view(const bContext *C)
DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, C);
}
-static bool is_object_visible_in_viewport(View3D *v3d, Object *ob)
-{
- if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
- return false;
- }
-
- if ((v3d->flag & V3D_LOCAL_COLLECTIONS) &&
- ((v3d->local_collections_uuid & ob->runtime.local_collections_bits) == 0)) {
- return false;
- }
-
- return true;
-}
-
/**
* Used for both regular and off-screen drawing.
* Need to reset DST before calling this function
@@ -1635,7 +1651,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
}
- if (!is_object_visible_in_viewport(v3d, ob)) {
+ if (!BKE_object_is_visible_in_viewport(v3d, ob)) {
continue;
}
DST.dupli_parent = data_.dupli_parent;
@@ -1666,7 +1682,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
DRW_hair_update();
- drw_engines_draw_background();
+ const bool background_drawn = drw_engines_draw_background();
GPU_framebuffer_bind(DST.default_framebuffer);
@@ -1677,6 +1693,10 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
drw_engines_draw_scene();
+ if (!background_drawn) {
+ drw_draw_background_alpha_under();
+ }
+
/* Fix 3D view being "laggy" on macos and win+nvidia. (See T56996, T61474) */
GPU_flush();
@@ -1918,6 +1938,8 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph
RenderResult *render_result = RE_engine_get_result(engine);
RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
+ DST.buffer_finish_called = false;
+
DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
/* Force cache to reset. */
@@ -2028,13 +2050,15 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
RE_SetActiveRenderView(render, render_view->name);
drw_view_reset();
engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect);
+ DST.buffer_finish_called = false;
+
/* grease pencil: render result is merged in the previous render result. */
if (DRW_render_check_grease_pencil(depsgraph)) {
DRW_state_reset();
drw_view_reset();
DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
+ DST.buffer_finish_called = false;
}
- DST.buffer_finish_called = false;
}
RE_engine_end_result(engine, render_result, false, false, false);
@@ -2080,7 +2104,7 @@ void DRW_render_object_iter(
if ((object_type_exclude_viewport & (1 << ob->type)) == 0) {
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
- DST.ob_state = NULL;
+ DST.ob_handle = 0;
drw_duplidata_load(DST.dupli_source);
if (!DST.dupli_source) {
@@ -2187,6 +2211,7 @@ void DRW_render_instance_buffer_finish(void)
BLI_assert(!DST.buffer_finish_called && "DRW_render_instance_buffer_finish called twice!");
DST.buffer_finish_called = true;
DRW_instance_buffer_finish(DST.idatalist);
+ drw_resource_buffer_finish(DST.vmempool);
}
/**
@@ -2210,7 +2235,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
Object *obact = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(obact);
#ifndef USE_GPU_SELECT
- UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect);
+ UNUSED_VARS(scene, view_layer, v3d, ar, rect);
#else
RegionView3D *rv3d = ar->regiondata;
@@ -2326,7 +2351,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
v3d->object_type_exclude_select);
bool filter_exclude = false;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) {
- if (!is_object_visible_in_viewport(v3d, ob)) {
+ if (!BKE_object_is_visible_in_viewport(v3d, ob)) {
continue;
}
if ((ob->base_flag & BASE_SELECTABLE) &&
@@ -2418,8 +2443,38 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/**
* object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
*/
-static void drw_draw_depth_loop_imp(void)
+static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph,
+ ARegion *ar,
+ View3D *v3d,
+ GPUViewport *viewport,
+ const bool use_opengl_context)
{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (use_opengl_context) {
+ DRW_opengl_context_enable();
+ }
+
+ DST.viewport = viewport;
+ DST.options.is_depth = true;
+
+ /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
+ DST.draw_ctx = (DRWContextState){
+ .ar = ar,
+ .rv3d = rv3d,
+ .v3d = v3d,
+ .scene = scene,
+ .view_layer = view_layer,
+ .obact = OBACT(view_layer),
+ .engine_type = engine_type,
+ .depsgraph = depsgraph,
+ };
+
+ drw_engines_data_validate();
+
/* Setup framebuffer */
DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(
DST.viewport);
@@ -2441,13 +2496,12 @@ static void drw_draw_depth_loop_imp(void)
drw_engines_cache_init();
drw_engines_world_update(DST.draw_ctx.scene);
- View3D *v3d = DST.draw_ctx.v3d;
const int object_type_exclude_viewport = v3d->object_type_exclude_viewport;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (DST.draw_ctx.depsgraph, ob) {
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
}
- if (!is_object_visible_in_viewport(v3d, ob)) {
+ if (!BKE_object_is_visible_in_viewport(v3d, ob)) {
continue;
}
DST.dupli_parent = data_.dupli_parent;
@@ -2477,6 +2531,20 @@ static void drw_draw_depth_loop_imp(void)
/* TODO: Reading depth for operators should be done here. */
GPU_framebuffer_restore();
+
+ drw_engines_disable();
+
+ drw_viewport_cache_resize();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ drw_state_ensure_not_reused(&DST);
+#endif
+
+ /* Changin context */
+ if (use_opengl_context) {
+ DRW_opengl_context_disable();
+ }
}
/**
@@ -2488,55 +2556,18 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
GPUViewport *viewport,
bool use_opengl_context)
{
- Scene *scene = DEG_get_evaluated_scene(depsgraph);
- RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
- RegionView3D *rv3d = ar->regiondata;
-
- if (use_opengl_context) {
- DRW_opengl_context_enable();
- }
-
/* Reset before using it. */
drw_state_prepare_clean_for_draw(&DST);
- DST.viewport = viewport;
- DST.options.is_depth = true;
-
- /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
- DST.draw_ctx = (DRWContextState){
- .ar = ar,
- .rv3d = rv3d,
- .v3d = v3d,
- .scene = scene,
- .view_layer = view_layer,
- .obact = OBACT(view_layer),
- .engine_type = engine_type,
- .depsgraph = depsgraph,
- };
-
/* Get list of enabled engines */
{
drw_engines_enable_basic();
if (DRW_state_draw_support()) {
drw_engines_enable_from_object_mode();
}
- drw_engines_data_validate();
}
- drw_draw_depth_loop_imp();
-
- drw_engines_disable();
-
-#ifdef DEBUG
- /* Avoid accidental reuse. */
- drw_state_ensure_not_reused(&DST);
-#endif
-
- /* Changin context */
- if (use_opengl_context) {
- DRW_opengl_context_disable();
- }
+ drw_draw_depth_loop_imp(depsgraph, ar, v3d, viewport, use_opengl_context);
}
/**
@@ -2547,43 +2578,12 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
View3D *v3d,
GPUViewport *viewport)
{
- Scene *scene = DEG_get_evaluated_scene(depsgraph);
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
- RegionView3D *rv3d = ar->regiondata;
-
- DRW_opengl_context_enable();
-
/* Reset before using it. */
drw_state_prepare_clean_for_draw(&DST);
- DST.viewport = viewport;
- DST.options.is_depth = true;
-
- /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
- DST.draw_ctx = (DRWContextState){
- .ar = ar,
- .rv3d = rv3d,
- .v3d = v3d,
- .scene = scene,
- .view_layer = view_layer,
- .obact = OBACT(view_layer),
- .depsgraph = depsgraph,
- };
-
use_drw_engine(&draw_engine_gpencil_type);
- drw_engines_data_validate();
-
- drw_draw_depth_loop_imp();
-
- drw_engines_disable();
-
-#ifdef DEBUG
- /* Avoid accidental reuse. */
- drw_state_ensure_not_reused(&DST);
-#endif
- /* Changin context */
- DRW_opengl_context_disable();
+ drw_draw_depth_loop_imp(depsgraph, ar, v3d, viewport, true);
}
void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const rcti *rect)
@@ -2631,7 +2631,13 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const rc
drw_engines_cache_finish();
+#if 0 /* This is a workaround to a nasty bug that seems to be a nasty driver bug. (See T69377) */
DRW_render_instance_buffer_finish();
+#else
+ DST.buffer_finish_called = true;
+ // DRW_instance_buffer_finish(DST.idatalist);
+ drw_resource_buffer_finish(DST.vmempool);
+#endif
}
/* Start Drawing */
@@ -2937,6 +2943,10 @@ void DRW_engines_free(void)
MEM_SAFE_FREE(DST.uniform_names.buffer);
+ if (DST.draw_list) {
+ GPU_draw_list_discard(DST.draw_list);
+ }
+
DRW_opengl_context_disable();
}
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 85f6cf05e83..709116c78e5 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -28,8 +28,10 @@
#include "DRW_engine.h"
#include "DRW_render.h"
+#include "BLI_assert.h"
#include "BLI_linklist.h"
#include "BLI_threads.h"
+#include "BLI_memblock.h"
#include "GPU_batch.h"
#include "GPU_context.h"
@@ -43,6 +45,9 @@
/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
#define USE_GPU_SELECT
+/* Use drawcall batching using instanced rendering. */
+#define USE_BATCHING 1
+
// #define DRW_DEBUG_CULLING
#define DRW_DEBUG_USE_UNIFORM_NAME 0
#define DRW_UNIFORM_BUFFER_NAME 64
@@ -90,20 +95,6 @@
* > DRWUniform
*/
-/* Used by DRWCallState.flag */
-enum {
- DRW_CALL_NEGSCALE = (1 << 1),
-};
-
-/* Used by DRWCallState.matflag */
-enum {
- DRW_CALL_MODELINVERSE = (1 << 0),
- DRW_CALL_MODELVIEWPROJECTION = (1 << 1),
- DRW_CALL_ORCOTEXFAC = (1 << 2),
- DRW_CALL_OBJECTINFO = (1 << 3),
- DRW_CALL_OBJECTCOLOR = (1 << 4),
-};
-
typedef struct DRWCullingState {
uint32_t mask;
/* Culling: Using Bounding Sphere for now for faster culling.
@@ -113,38 +104,161 @@ typedef struct DRWCullingState {
void *user_data;
} DRWCullingState;
-typedef struct DRWCallState {
- DRWCullingState *culling;
- uchar flag;
- uchar matflag; /* Which matrices to compute. */
- short ob_index;
- /* Matrices */
+/* Minimum max UBO size is 64KiB. We take the largest
+ * UBO struct and alloc the max number.
+ * ((1 << 16) / sizeof(DRWObjectMatrix)) = 512
+ * Keep in sync with common_view_lib.glsl */
+#define DRW_RESOURCE_CHUNK_LEN 512
+
+/**
+ * Identifier used to sort similar drawcalls together.
+ * Also used to reference elements inside memory blocks.
+ *
+ * From MSB to LSB
+ * 1 bit for negative scale.
+ * 22 bits for chunk id.
+ * 9 bits for resource id inside the chunk. (can go up to 511)
+ * |-|----------------------|---------|
+ *
+ * Use manual bit-shift and mask instead of bit-fields to avoid
+ * compiler dependent behavior that would mess the ordering of
+ * the members thus changing the sorting order.
+ */
+typedef uint32_t DRWResourceHandle;
+
+BLI_INLINE uint32_t DRW_handle_negative_scale_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x80000000) != 0;
+}
+
+BLI_INLINE uint32_t DRW_handle_chunk_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x7FFFFFFF) >> 9;
+}
+
+BLI_INLINE uint32_t DRW_handle_id_get(const DRWResourceHandle *handle)
+{
+ return (*handle & 0x000001FF);
+}
+
+BLI_INLINE void DRW_handle_increment(DRWResourceHandle *handle)
+{
+ *handle += 1;
+}
+
+BLI_INLINE void DRW_handle_negative_scale_enable(DRWResourceHandle *handle)
+{
+ *handle |= 0x80000000;
+}
+
+BLI_INLINE void *DRW_memblock_elem_from_handle(struct BLI_memblock *memblock,
+ const DRWResourceHandle *handle)
+{
+ int elem = DRW_handle_id_get(handle);
+ int chunk = DRW_handle_chunk_get(handle);
+ return BLI_memblock_elem_get(memblock, chunk, elem);
+}
+
+typedef struct DRWObjectMatrix {
float model[4][4];
float modelinverse[4][4];
- float orcotexfac[2][3];
- float ob_random;
+} DRWObjectMatrix;
+
+typedef struct DRWObjectInfos {
+ float orcotexfac[2][4];
float ob_color[4];
-} DRWCallState;
+ float ob_index;
+ float pad; /* UNUSED*/
+ float ob_random;
+ float ob_neg_scale;
+} DRWObjectInfos;
+
+BLI_STATIC_ASSERT_ALIGN(DRWObjectMatrix, 16)
+BLI_STATIC_ASSERT_ALIGN(DRWObjectInfos, 16)
-typedef struct DRWCall {
- struct DRWCall *next;
- DRWCallState *state;
+typedef enum {
+ /* Draw Commands */
+ DRW_CMD_DRAW = 0, /* Only sortable type. Must be 0. */
+ DRW_CMD_DRAW_RANGE = 1,
+ DRW_CMD_DRAW_INSTANCE = 2,
+ DRW_CMD_DRAW_PROCEDURAL = 3,
+ /* Other Commands */
+ DRW_CMD_CLEAR = 12,
+ DRW_CMD_DRWSTATE = 13,
+ DRW_CMD_STENCIL = 14,
+ DRW_CMD_SELECTID = 15,
+ /* Needs to fit in 4bits */
+} eDRWCommandType;
+
+#define DRW_MAX_DRAW_CMD_TYPE DRW_CMD_DRAW_PROCEDURAL
+
+typedef struct DRWCommandDraw {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
+} DRWCommandDraw;
+/* Assume DRWResourceHandle to be 0. */
+typedef struct DRWCommandDrawRange {
GPUBatch *batch;
uint vert_first;
uint vert_count;
+} DRWCommandDrawRange;
+
+typedef struct DRWCommandDrawInstance {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
uint inst_count;
+} DRWCommandDrawInstance;
-#ifdef USE_GPU_SELECT
- /* TODO(fclem) remove once we have a dedicated selection engine. */
- int select_id;
- GPUVertBuf *inst_selectid;
-#endif
-} DRWCall;
+typedef struct DRWCommandDrawProcedural {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
+ uint vert_count;
+} DRWCommandDrawProcedural;
+
+typedef struct DRWCommandSetMutableState {
+ /** State changes (or'd or and'd with the pass's state) */
+ DRWState enable;
+ DRWState disable;
+} DRWCommandSetMutableState;
+
+typedef struct DRWCommandSetStencil {
+ uint mask;
+} DRWCommandSetStencil;
+
+typedef struct DRWCommandSetSelectID {
+ GPUVertBuf *select_buf;
+ uint select_id;
+} DRWCommandSetSelectID;
+
+typedef struct DRWCommandClear {
+ eGPUFrameBufferBits clear_channels;
+ uchar r, g, b, a; /* [0..1] for each channels. Normalized. */
+ float depth; /* [0..1] for depth. Normalized. */
+ uchar stencil; /* Stencil value [0..255] */
+} DRWCommandClear;
+
+typedef union DRWCommand {
+ DRWCommandDraw draw;
+ DRWCommandDrawRange range;
+ DRWCommandDrawInstance instance;
+ DRWCommandDrawProcedural procedural;
+ DRWCommandSetMutableState state;
+ DRWCommandSetStencil stencil;
+ DRWCommandSetSelectID select_id;
+ DRWCommandClear clear;
+} DRWCommand;
+
+/* Used for agregating calls into GPUVertBufs. */
+struct DRWCallBuffer {
+ GPUVertBuf *buf;
+ GPUVertBuf *buf_select;
+ int count;
+};
/* Used by DRWUniform.type */
typedef enum {
- DRW_UNIFORM_INT,
+ DRW_UNIFORM_INT = 0,
DRW_UNIFORM_INT_COPY,
DRW_UNIFORM_FLOAT,
DRW_UNIFORM_FLOAT_COPY,
@@ -153,55 +267,56 @@ typedef enum {
DRW_UNIFORM_TEXTURE_REF,
DRW_UNIFORM_BLOCK,
DRW_UNIFORM_BLOCK_PERSIST,
+ DRW_UNIFORM_TFEEDBACK_TARGET,
+ /** Per drawcall uniforms/UBO */
+ DRW_UNIFORM_BLOCK_OBMATS,
+ DRW_UNIFORM_BLOCK_OBINFOS,
+ DRW_UNIFORM_RESOURCE_CHUNK,
+ /** Legacy / Fallback */
+ DRW_UNIFORM_BASE_INSTANCE,
+ DRW_UNIFORM_MODEL_MATRIX,
+ DRW_UNIFORM_MODEL_MATRIX_INVERSE,
+ DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX,
+ /* WARNING: set DRWUniform->type
+ * bit length accordingly. */
} DRWUniformType;
struct DRWUniform {
- DRWUniform *next; /* single-linked list */
union {
/* For reference or array/vector types. */
const void *pvalue;
/* Single values. */
- float fvalue[2];
- int ivalue[2];
+ float fvalue[4];
+ int ivalue[4];
};
- int name_ofs; /* name offset in name buffer. */
int location;
- char type; /* DRWUniformType */
- char length; /* cannot be more than 16 */
- char arraysize; /* cannot be more than 16 too */
+ uint32_t type : 5; /* DRWUniformType */
+ uint32_t length : 5; /* cannot be more than 16 */
+ uint32_t arraysize : 5; /* cannot be more than 16 too */
+ uint32_t name_ofs : 17; /* name offset in name buffer. */
};
struct DRWShadingGroup {
DRWShadingGroup *next;
- GPUShader *shader; /* Shader to bind */
- DRWUniform *uniforms; /* Uniforms pointers */
+ GPUShader *shader; /* Shader to bind */
+ struct DRWUniformChunk *uniforms; /* Uniforms pointers */
struct {
- DRWCall *first, *last; /* Linked list of DRWCall */
- } calls;
+ /* Chunks of draw calls. */
+ struct DRWCommandChunk *first, *last;
+ } cmd;
- /** TODO Maybe remove from here */
- struct GPUVertBuf *tfeedback_target;
-
- /** State changes for this batch only (or'd with the pass's state) */
- DRWState state_extra;
- /** State changes for this batch only (and'd with the pass's state) */
- DRWState state_extra_disable;
- /** Stencil mask to use for stencil test / write operations */
- uint stencil_mask;
-
- /* Builtin matrices locations */
- int model;
- int modelinverse;
- int modelviewprojection;
- int orcotexfac;
- int callid;
- int objectinfo;
- int objectcolor;
- uchar matflag; /* Matrices needed, same as DRWCall.flag */
-
- DRWPass *pass_parent; /* backlink to pass we're in */
+ union {
+ struct {
+ int objectinfo; /* Equal to 1 if the shader needs obinfos. */
+ DRWResourceHandle pass_handle; /* Memblock key to parent pass. */
+ };
+ struct {
+ float distance; /* Distance from camera. */
+ uint original_index; /* Original position inside the shgroup list. */
+ } z_sorting;
+ };
};
#define MAX_PASS_NAME 32
@@ -213,6 +328,7 @@ struct DRWPass {
DRWShadingGroup *last;
} shgroups;
+ DRWResourceHandle handle;
DRWState state;
char name[MAX_PASS_NAME];
};
@@ -232,6 +348,8 @@ typedef struct DRWViewUboStorage {
float viewcamtexcofac[4];
} DRWViewUboStorage;
+BLI_STATIC_ASSERT_ALIGN(DRWViewUboStorage, 16)
+
#define MAX_CULLED_VIEWS 32
struct DRWView {
@@ -253,13 +371,45 @@ struct DRWView {
void *user_data;
};
-/* TODO(fclem): Future awaits */
-#if 0
-typedef struct ModelUboStorage {
- float model[4][4];
- float modelinverse[4][4];
-} ModelUboStorage;
-#endif
+/* ------------ Data Chunks --------------- */
+/**
+ * In order to keep a cache friendly data structure,
+ * we alloc most of our little data into chunks of multiple item.
+ * Iteration, allocation and memory usage are better.
+ * We loose a bit of memory by allocating more than what we need
+ * but it's counterbalanced by not needing the linked-list pointers
+ * for each item.
+ **/
+
+typedef struct DRWUniformChunk {
+ struct DRWUniformChunk *next; /* single-linked list */
+ uint32_t uniform_len;
+ uint32_t uniform_used;
+ DRWUniform uniforms[10];
+} DRWUniformChunk;
+
+typedef struct DRWCommandChunk {
+ struct DRWCommandChunk *next;
+ uint32_t command_len;
+ uint32_t command_used;
+ /* 4bits for each command. */
+ uint64_t command_type[6];
+ /* -- 64 bytes aligned -- */
+ DRWCommand commands[96];
+ /* -- 64 bytes aligned -- */
+} DRWCommandChunk;
+
+typedef struct DRWCommandSmallChunk {
+ struct DRWCommandChunk *next;
+ uint32_t command_len;
+ uint32_t command_used;
+ /* 4bits for each command. */
+ /* TODO reduce size of command_type. */
+ uint64_t command_type[6];
+ DRWCommand commands[6];
+} DRWCommandSmallChunk;
+
+BLI_STATIC_ASSERT_ALIGN(DRWCommandChunk, 16);
/* ------------- DRAW DEBUG ------------ */
@@ -280,21 +430,31 @@ typedef struct DRWDebugSphere {
#define DST_MAX_SLOTS 64 /* Cannot be changed without modifying RST.bound_tex_slots */
#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */
#define STENCIL_UNDEFINED 256
+#define DRW_DRAWLIST_LEN 256
typedef struct DRWManager {
/* TODO clean up this struct a bit */
/* Cache generation */
ViewportMemoryPool *vmempool;
DRWInstanceDataList *idatalist;
- DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
- /* Default Unit model matrix state without culling. */
- DRWCallState *unit_state;
/* State of the object being evaluated if already allocated. */
- DRWCallState *ob_state;
+ DRWResourceHandle ob_handle;
+ /** True if current DST.ob_state has its matching DRWObjectInfos init. */
+ bool ob_state_obinfo_init;
+ /** Handle of current object resource in object resource arrays (DRWObjectMatrices/Infos). */
+ DRWResourceHandle resource_handle;
+ /** Handle of next DRWPass to be allocated. */
+ DRWResourceHandle pass_handle;
+
+ /** Dupli state. NULL if not dupli. */
struct DupliObject *dupli_source;
struct Object *dupli_parent;
struct Object *dupli_origin;
+ /** Ghash containing original objects. */
struct GHash *dupli_ghash;
- void **dupli_datas; /* Array of dupli_data (one for each enabled engine) to handle duplis. */
+ /** TODO(fclem) try to remove usage of this. */
+ DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
+ /* Array of dupli_data (one for each enabled engine) to handle duplis. */
+ void **dupli_datas;
/* Rendering state */
GPUShader *shader;
@@ -357,6 +517,8 @@ typedef struct DRWManager {
/** Mutex to lock the drw manager and avoid concurrent context usage. */
TicketMutex *gl_context_mutex;
+ GPUDrawList *draw_list;
+
/** GPU Resource State: Memory storage between drawing. */
struct {
/* High end GPUs supports up to 32 binds per shader stage.
@@ -397,9 +559,13 @@ void drw_state_set(DRWState state);
void drw_debug_draw(void);
void drw_debug_init(void);
+eDRWCommandType command_type_get(uint64_t *command_type_bits, int index);
+
void drw_batch_cache_validate(Object *ob);
void drw_batch_cache_generate_requested(struct Object *ob);
+void drw_resource_buffer_finish(ViewportMemoryPool *vmempool);
+
/* Procedural Drawing */
GPUBatch *drw_cache_procedural_points_get(void);
GPUBatch *drw_cache_procedural_lines_get(void);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index cd174e899d4..330f72eda18 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -34,6 +34,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "BLI_alloca.h"
#include "BLI_hash.h"
#include "BLI_link_utils.h"
#include "BLI_mempool.h"
@@ -51,6 +52,36 @@
/** \name Uniform Buffer Object (DRW_uniformbuffer)
* \{ */
+static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_len)
+{
+ /* Count unique batches. Tt's not really important if
+ * there is collisions. If there is a lot of different batches,
+ * the sorting benefit will be negligible.
+ * So at least sort fast! */
+ uchar idx[128] = {0};
+ /* Shift by 6 positions knowing each GPUBatch is > 64 bytes */
+#define KEY(a) ((((size_t)((a).draw.batch)) >> 6) % ARRAY_SIZE(idx))
+ BLI_assert(array_len <= ARRAY_SIZE(idx));
+
+ for (int i = 0; i < array_len; i++) {
+ /* Early out if nothing to sort. */
+ if (++idx[KEY(array[i])] == array_len) {
+ return;
+ }
+ }
+ /* Cumulate batch indices */
+ for (int i = 1; i < ARRAY_SIZE(idx); i++) {
+ idx[i] += idx[i - 1];
+ }
+ /* Traverse in reverse to not change the order of the resource ids. */
+ for (int src = array_len - 1; src >= 0; src--) {
+ array_tmp[--idx[KEY(array[src])]] = array[src];
+ }
+#undef KEY
+
+ memcpy(array, array_tmp, sizeof(*array) * array_len);
+}
+
GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data)
{
return GPU_uniformbuffer_create(size, data, NULL);
@@ -66,20 +97,94 @@ void DRW_uniformbuffer_free(GPUUniformBuffer *ubo)
GPU_uniformbuffer_free(ubo);
}
+void drw_resource_buffer_finish(ViewportMemoryPool *vmempool)
+{
+ int chunk_id = DRW_handle_chunk_get(&DST.resource_handle);
+ int elem_id = DRW_handle_id_get(&DST.resource_handle);
+ int ubo_len = 1 + chunk_id - ((elem_id == 0) ? 1 : 0);
+ size_t list_size = sizeof(GPUUniformBuffer *) * ubo_len;
+
+ /* TODO find a better system. currently a lot of obinfos UBO are going to be unused
+ * if not rendering with Eevee. */
+
+ if (vmempool->matrices_ubo == NULL) {
+ vmempool->matrices_ubo = MEM_callocN(list_size, __func__);
+ vmempool->obinfos_ubo = MEM_callocN(list_size, __func__);
+ vmempool->ubo_len = ubo_len;
+ }
+
+ /* Remove unecessary buffers */
+ for (int i = ubo_len; i < vmempool->ubo_len; i++) {
+ GPU_uniformbuffer_free(vmempool->matrices_ubo[i]);
+ GPU_uniformbuffer_free(vmempool->obinfos_ubo[i]);
+ }
+
+ if (ubo_len != vmempool->ubo_len) {
+ vmempool->matrices_ubo = MEM_recallocN(vmempool->matrices_ubo, list_size);
+ vmempool->obinfos_ubo = MEM_recallocN(vmempool->obinfos_ubo, list_size);
+ vmempool->ubo_len = ubo_len;
+ }
+
+ /* Create/Update buffers. */
+ for (int i = 0; i < ubo_len; i++) {
+ void *data_obmat = BLI_memblock_elem_get(vmempool->obmats, i, 0);
+ void *data_infos = BLI_memblock_elem_get(vmempool->obinfos, i, 0);
+ if (vmempool->matrices_ubo[i] == NULL) {
+ vmempool->matrices_ubo[i] = GPU_uniformbuffer_create(
+ sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN, data_obmat, NULL);
+ vmempool->obinfos_ubo[i] = GPU_uniformbuffer_create(
+ sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN, data_infos, NULL);
+ }
+ else {
+ GPU_uniformbuffer_update(vmempool->matrices_ubo[i], data_obmat);
+ GPU_uniformbuffer_update(vmempool->obinfos_ubo[i], data_infos);
+ }
+ }
+
+ /* Aligned alloc to avoid unaligned memcpy. */
+ DRWCommandChunk *chunk_tmp = MEM_mallocN_aligned(sizeof(DRWCommandChunk), 16, "tmp call chunk");
+ DRWCommandChunk *chunk;
+ BLI_memblock_iter iter;
+ BLI_memblock_iternew(vmempool->commands, &iter);
+ while ((chunk = BLI_memblock_iterstep(&iter))) {
+ bool sortable = true;
+ /* We can only sort chunks that contain DRWCommandDraw only. */
+ for (int i = 0; i < ARRAY_SIZE(chunk->command_type) && sortable; i++) {
+ if (chunk->command_type[i] != 0) {
+ sortable = false;
+ }
+ }
+ if (sortable) {
+ draw_call_sort(chunk->commands, chunk_tmp->commands, chunk->command_used);
+ }
+ }
+ MEM_freeN(chunk_tmp);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Uniforms (DRW_shgroup_uniform)
* \{ */
-static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
- int loc,
- DRWUniformType type,
- const void *value,
- int length,
- int arraysize)
+static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
+ int loc,
+ DRWUniformType type,
+ const void *value,
+ int length,
+ int arraysize)
{
- DRWUniform *uni = BLI_memblock_alloc(DST.vmempool->uniforms);
+ DRWUniformChunk *unichunk = shgroup->uniforms;
+ /* Happens on first uniform or if chunk is full. */
+ if (!unichunk || unichunk->uniform_used == unichunk->uniform_len) {
+ unichunk = BLI_memblock_alloc(DST.vmempool->uniforms);
+ unichunk->uniform_len = ARRAY_SIZE(shgroup->uniforms->uniforms);
+ unichunk->uniform_used = 0;
+ BLI_LINKS_PREPEND(shgroup->uniforms, unichunk);
+ }
+
+ DRWUniform *uni = unichunk->uniforms + unichunk->uniform_used++;
+
uni->location = loc;
uni->type = type;
uni->length = length;
@@ -87,11 +192,11 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
switch (type) {
case DRW_UNIFORM_INT_COPY:
- BLI_assert(length <= 2);
+ BLI_assert(length <= 4);
memcpy(uni->ivalue, value, sizeof(int) * length);
break;
case DRW_UNIFORM_FLOAT_COPY:
- BLI_assert(length <= 2);
+ BLI_assert(length <= 4);
memcpy(uni->fvalue, value, sizeof(float) * length);
break;
default:
@@ -99,7 +204,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
break;
}
- BLI_LINKS_PREPEND(shgroup->uniforms, uni);
+ return uni;
}
static void drw_shgroup_builtin_uniform(
@@ -136,7 +241,8 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
BLI_assert(arraysize > 0 && arraysize <= 16);
BLI_assert(length >= 0 && length <= 16);
- drw_shgroup_uniform_create_ex(shgroup, location, type, value, length, arraysize);
+ DRWUniform *uni = drw_shgroup_uniform_create_ex(
+ shgroup, location, type, value, length, arraysize);
/* If location is -2, the uniform has not yet been queried.
* We save the name for query just before drawing. */
@@ -155,7 +261,7 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
memcpy(dst, name, len); /* Copies NULL terminator. */
DST.uniform_names.buffer_ofs += len;
- shgroup->uniforms->name_ofs = ofs;
+ uni->name_ofs = ofs;
}
}
@@ -286,6 +392,21 @@ void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, co
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1);
}
+void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 2, 1);
+}
+
+void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 3, 1);
+}
+
+void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 4, 1);
+}
+
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
{
int ival = value;
@@ -302,13 +423,23 @@ void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, c
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 2, 1);
}
+void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 3, 1);
+}
+
+void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 4, 1);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Draw Call (DRW_calls)
* \{ */
-static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
+static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4])
{
ID *ob_data = (ob) ? ob->data : NULL;
float *texcoloc = NULL;
@@ -316,13 +447,11 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
if (ob_data != NULL) {
switch (GS(ob_data->name)) {
case ID_ME:
- BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
break;
case ID_CU: {
Curve *cu = (Curve *)ob_data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
texcoloc = cu->loc;
texcosize = cu->size;
break;
@@ -351,159 +480,283 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
}
}
-static void drw_call_state_update_matflag(DRWCallState *state,
- DRWShadingGroup *shgroup,
- Object *ob)
+BLI_INLINE void drw_call_matrix_init(DRWObjectMatrix *ob_mats, Object *ob, float (*obmat)[4])
{
- uchar new_flags = ((state->matflag ^ shgroup->matflag) & shgroup->matflag);
-
- /* HACK: Here we set the matflags bit to 1 when computing the value
- * so that it's not recomputed for other drawcalls.
- * This is the opposite of what draw_matrices_model_prepare() does. */
- state->matflag |= shgroup->matflag;
-
- if (new_flags & DRW_CALL_MODELINVERSE) {
- if (ob) {
- copy_m4_m4(state->modelinverse, ob->imat);
- }
- else {
- invert_m4_m4(state->modelinverse, state->model);
- }
+ copy_m4_m4(ob_mats->model, obmat);
+ if (ob) {
+ copy_m4_m4(ob_mats->modelinverse, ob->imat);
}
-
- /* Orco factors: We compute this at creation to not have to save the *ob_data */
- if (new_flags & DRW_CALL_ORCOTEXFAC) {
- drw_call_calc_orco(ob, state->orcotexfac);
- }
-
- if (new_flags & DRW_CALL_OBJECTINFO) {
- state->ob_index = ob ? ob->index : 0;
- uint random;
- if (DST.dupli_source) {
- random = DST.dupli_source->random_id;
- }
- else {
- random = BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
- }
- state->ob_random = random * (1.0f / (float)0xFFFFFFFF);
- }
-
- if (new_flags & DRW_CALL_OBJECTCOLOR) {
- copy_v4_v4(state->ob_color, ob->color);
+ else {
+ /* WATCH: Can be costly. */
+ invert_m4_m4(ob_mats->modelinverse, ob_mats->model);
}
}
-static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
{
- DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states);
- state->flag = 0;
- state->matflag = 0;
-
- /* Matrices */
- copy_m4_m4(state->model, obmat);
-
- if (ob && (ob->transflag & OB_NEG_SCALE)) {
- state->flag |= DRW_CALL_NEGSCALE;
- }
-
- drw_call_state_update_matflag(state, shgroup, ob);
-
- DRWCullingState *cull = BLI_memblock_alloc(DST.vmempool->cullstates);
- state->culling = cull;
+ BLI_assert(ob);
+ /* Index. */
+ ob_infos->ob_index = ob->index;
+ /* Orco factors. */
+ drw_call_calc_orco(ob, ob_infos->orcotexfac);
+ /* Random float value. */
+ uint random = (DST.dupli_source) ?
+ DST.dupli_source->random_id :
+ /* TODO(fclem) this is rather costly to do at runtime. Maybe we can
+ * put it in ob->runtime and make depsgraph ensure it is up to date. */
+ BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
+ ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF);
+ /* Negative scalling. */
+ ob_infos->ob_neg_scale = (ob->transflag & OB_NEG_SCALE) ? -1.0f : 1.0f;
+ /* Object Color. */
+ copy_v4_v4(ob_infos->ob_color, ob->color);
+}
+static void drw_call_culling_init(DRWCullingState *cull, Object *ob)
+{
BoundBox *bbox;
if (ob != NULL && (bbox = BKE_object_boundbox_get(ob))) {
float corner[3];
/* Get BoundSphere center and radius from the BoundBox. */
mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]);
- mul_v3_m4v3(corner, obmat, bbox->vec[0]);
- mul_m4_v3(obmat, cull->bsphere.center);
+ mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]);
+ mul_m4_v3(ob->obmat, cull->bsphere.center);
cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner);
}
else {
- /* TODO(fclem) Bypass alloc if we can (see if eevee's
- * probe visibility collection still works). */
/* Bypass test. */
cull->bsphere.radius = -1.0f;
}
+ /* Reset user data */
+ cull->user_data = NULL;
+}
+
+static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob)
+{
+ DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates);
+ DRWObjectMatrix *ob_mats = BLI_memblock_alloc(DST.vmempool->obmats);
+ /* FIXME Meh, not always needed but can be accessed after creation.
+ * Also it needs to have the same resource handle. */
+ DRWObjectInfos *ob_infos = BLI_memblock_alloc(DST.vmempool->obinfos);
+ UNUSED_VARS(ob_infos);
+
+ DRWResourceHandle handle = DST.resource_handle;
+ DRW_handle_increment(&DST.resource_handle);
+
+ if (ob && (ob->transflag & OB_NEG_SCALE)) {
+ DRW_handle_negative_scale_enable(&handle);
+ }
+
+ drw_call_matrix_init(ob_mats, ob, obmat);
+ drw_call_culling_init(culling, ob);
+ /* ob_infos is init only if needed. */
- return state;
+ return handle;
}
-static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup,
+ float (*obmat)[4],
+ Object *ob)
{
if (ob == NULL) {
if (obmat == NULL) {
- BLI_assert(DST.unit_state);
- return DST.unit_state;
+ DRWResourceHandle handle = 0;
+ return handle;
}
else {
- return drw_call_state_create(shgroup, obmat, ob);
+ return drw_resource_handle_new(obmat, NULL);
}
}
else {
- if (DST.ob_state == NULL) {
- DST.ob_state = drw_call_state_create(shgroup, obmat, ob);
+ if (DST.ob_handle == 0) {
+ DST.ob_handle = drw_resource_handle_new(obmat, ob);
+ DST.ob_state_obinfo_init = false;
}
- else {
- /* If the DRWCallState is reused, add necessary matrices. */
- drw_call_state_update_matflag(DST.ob_state, shgroup, ob);
+
+ if (shgroup->objectinfo) {
+ if (!DST.ob_state_obinfo_init) {
+ DST.ob_state_obinfo_init = true;
+ DRWObjectInfos *ob_infos = DRW_memblock_elem_from_handle(DST.vmempool->obinfos,
+ &DST.ob_handle);
+
+ drw_call_obinfos_init(ob_infos, ob);
+ }
}
- return DST.ob_state;
+ return DST.ob_handle;
}
}
+static void command_type_set(uint64_t *command_type_bits, int index, eDRWCommandType type)
+{
+ command_type_bits[index / 16] |= ((uint64_t)type) << ((index % 16) * 4);
+}
+
+eDRWCommandType command_type_get(uint64_t *command_type_bits, int index)
+{
+ return ((command_type_bits[index / 16] >> ((index % 16) * 4)) & 0xF);
+}
+
+static void *drw_command_create(DRWShadingGroup *shgroup, eDRWCommandType type)
+{
+ DRWCommandChunk *chunk = shgroup->cmd.last;
+
+ if (chunk == NULL) {
+ DRWCommandSmallChunk *smallchunk = BLI_memblock_alloc(DST.vmempool->commands_small);
+ smallchunk->command_len = ARRAY_SIZE(smallchunk->commands);
+ smallchunk->command_used = 0;
+ smallchunk->command_type[0] = 0x0lu;
+ chunk = (DRWCommandChunk *)smallchunk;
+ BLI_LINKS_APPEND(&shgroup->cmd, chunk);
+ }
+ else if (chunk->command_used == chunk->command_len) {
+ chunk = BLI_memblock_alloc(DST.vmempool->commands);
+ chunk->command_len = ARRAY_SIZE(chunk->commands);
+ chunk->command_used = 0;
+ memset(chunk->command_type, 0x0, sizeof(chunk->command_type));
+ BLI_LINKS_APPEND(&shgroup->cmd, chunk);
+ }
+
+ command_type_set(chunk->command_type, chunk->command_used, type);
+
+ return chunk->commands + chunk->command_used++;
+}
+
+static void drw_command_draw(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle)
+{
+ DRWCommandDraw *cmd = drw_command_create(shgroup, DRW_CMD_DRAW);
+ cmd->batch = batch;
+ cmd->handle = handle;
+}
+
+static void drw_command_draw_range(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ uint start,
+ uint count)
+{
+ DRWCommandDrawRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_RANGE);
+ cmd->batch = batch;
+ cmd->vert_first = start;
+ cmd->vert_count = count;
+}
+
+static void drw_command_draw_instance(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ uint count)
+{
+ DRWCommandDrawInstance *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE);
+ cmd->batch = batch;
+ cmd->handle = handle;
+ cmd->inst_count = count;
+}
+
+static void drw_command_draw_procedural(DRWShadingGroup *shgroup,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ uint vert_count)
+{
+ DRWCommandDrawProcedural *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_PROCEDURAL);
+ cmd->batch = batch;
+ cmd->handle = handle;
+ cmd->vert_count = vert_count;
+}
+
+static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, uint select_id)
+{
+ /* Only one can be valid. */
+ BLI_assert(buf == NULL || select_id == -1);
+ DRWCommandSetSelectID *cmd = drw_command_create(shgroup, DRW_CMD_SELECTID);
+ cmd->select_buf = buf;
+ cmd->select_id = select_id;
+}
+
+static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, uint mask)
+{
+ BLI_assert(mask <= 0xFF);
+ DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL);
+ cmd->mask = mask;
+}
+
+static void drw_command_clear(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil)
+{
+ DRWCommandClear *cmd = drw_command_create(shgroup, DRW_CMD_CLEAR);
+ cmd->clear_channels = channels;
+ cmd->r = r;
+ cmd->g = g;
+ cmd->b = b;
+ cmd->a = a;
+ cmd->depth = depth;
+ cmd->stencil = stencil;
+}
+
+static void drw_command_set_mutable_state(DRWShadingGroup *shgroup,
+ DRWState enable,
+ DRWState disable)
+{
+ /* TODO Restrict what state can be changed. */
+ DRWCommandSetMutableState *cmd = drw_command_create(shgroup, DRW_CMD_DRWSTATE);
+ cmd->enable = enable;
+ cmd->disable = disable;
+}
+
void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
Object *ob,
float (*obmat)[4],
struct GPUBatch *geom,
- uint v_sta,
- uint v_ct,
bool bypass_culling,
void *user_data)
{
BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : obmat, ob);
+ drw_command_draw(shgroup, geom, handle);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : obmat, ob);
- call->batch = geom;
- call->vert_first = v_sta;
- call->vert_count = v_ct; /* 0 means auto from batch. */
- call->inst_count = 0;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
- if (call->state->culling) {
- call->state->culling->user_data = user_data;
+ /* Culling data. */
+ if (user_data || bypass_culling) {
+ DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates,
+ &DST.ob_handle);
+
+ if (user_data) {
+ culling->user_data = user_data;
+ }
if (bypass_culling) {
/* NOTE this will disable culling for the whole object. */
- call->state->culling->bsphere.radius = -1.0f;
+ culling->bsphere.radius = -1.0f;
}
}
}
+void DRW_shgroup_call_range(DRWShadingGroup *shgroup, struct GPUBatch *geom, uint v_sta, uint v_ct)
+{
+ BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ drw_command_draw_range(shgroup, geom, v_sta, v_ct);
+}
+
static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup,
GPUBatch *geom,
Object *ob,
uint vert_count)
{
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = geom;
- call->vert_first = 0;
- call->vert_count = vert_count;
- call->inst_count = 0;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ BLI_assert(vert_count > 0);
+ BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_procedural(shgroup, geom, handle, vert_count);
}
void DRW_shgroup_call_procedural_points(DRWShadingGroup *shgroup, Object *ob, uint point_len)
@@ -524,25 +777,18 @@ void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob,
drw_shgroup_call_procedural_add_ex(shgroup, geom, ob, tria_count * 3);
}
+/* Should be removed */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
uint count)
{
BLI_assert(geom != NULL);
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = geom;
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = count;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_instance(shgroup, geom, handle, count);
}
void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
@@ -552,25 +798,16 @@ void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
{
BLI_assert(geom != NULL);
BLI_assert(inst_attributes->verts[0] != NULL);
-
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
GPUVertBuf *buf_inst = inst_attributes->verts[0];
-
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
-
- call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob);
- call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom);
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = buf_inst->vertex_len;
-#ifdef USE_GPU_SELECT
- call->select_id = DST.select_id;
- call->inst_selectid = NULL;
-#endif
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom);
+ drw_command_draw(shgroup, batch, handle);
}
-// #define SCULPT_DEBUG_BUFFERS
-
+#define SCULPT_DEBUG_BUFFERS (G.debug_value == 889)
typedef struct DRWSculptCallbackData {
Object *ob;
DRWShadingGroup **shading_groups;
@@ -578,13 +815,11 @@ typedef struct DRWSculptCallbackData {
bool use_mats;
bool use_mask;
bool fast_mode; /* Set by draw manager. Do not init. */
-#ifdef SCULPT_DEBUG_BUFFERS
- int node_nr;
-#endif
+
+ int debug_node_nr;
} DRWSculptCallbackData;
-#ifdef SCULPT_DEBUG_BUFFERS
-# define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9])
+#define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9])
static float sculpt_debug_colors[9][4] = {
{1.0f, 0.2f, 0.2f, 1.0f},
{0.2f, 1.0f, 0.2f, 1.0f},
@@ -596,59 +831,72 @@ static float sculpt_debug_colors[9][4] = {
{0.2f, 1.0f, 0.7f, 1.0f},
{0.7f, 0.2f, 1.0f, 1.0f},
};
-#endif
static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers)
{
- GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire);
- short index = 0;
-
/* Meh... use_mask is a bit misleading here. */
if (scd->use_mask && !GPU_pbvh_buffers_has_mask(buffers)) {
return;
}
+ GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire);
+ short index = 0;
+
if (scd->use_mats) {
index = GPU_pbvh_buffers_material_index_get(buffers);
}
DRWShadingGroup *shgrp = scd->shading_groups[index];
if (geom != NULL && shgrp != NULL) {
-#ifdef SCULPT_DEBUG_BUFFERS
- /* Color each buffers in different colors. Only work in solid/Xray mode. */
- shgrp = DRW_shgroup_create_sub(shgrp);
- DRW_shgroup_uniform_vec3(shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->node_nr++), 1);
-#endif
+ if (SCULPT_DEBUG_BUFFERS) {
+ /* Color each buffers in different colors. Only work in solid/Xray mode. */
+ shgrp = DRW_shgroup_create_sub(shgrp);
+ DRW_shgroup_uniform_vec3(
+ shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->debug_node_nr++), 1);
+ }
/* DRW_shgroup_call_no_cull reuses matrices calculations for all the drawcalls of this
* object. */
DRW_shgroup_call_no_cull(shgrp, geom, scd->ob);
}
}
-#ifdef SCULPT_DEBUG_BUFFERS
static void sculpt_debug_cb(void *user_data,
const float bmin[3],
const float bmax[3],
PBVHNodeFlags flag)
{
- int *node_nr = (int *)user_data;
+ int *debug_node_nr = (int *)user_data;
BoundBox bb;
BKE_boundbox_init_from_minmax(&bb, bmin, bmax);
-# if 0 /* Nodes hierarchy. */
+#if 0 /* Nodes hierarchy. */
if (flag & PBVH_Leaf) {
DRW_debug_bbox(&bb, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
}
else {
DRW_debug_bbox(&bb, (float[4]){0.5f, 0.5f, 0.5f, 0.6f});
}
-# else /* Color coded leaf bounds. */
+#else /* Color coded leaf bounds. */
if (flag & PBVH_Leaf) {
- DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*node_nr)++));
+ DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*debug_node_nr)++));
}
-# endif
-}
#endif
+}
+
+static void drw_sculpt_get_frustum_planes(Object *ob, float planes[6][4])
+{
+ /* TODO: take into account partial redraw for clipping planes. */
+ DRW_view_frustum_planes_get(DRW_view_default_get(), planes);
+
+ /* Transform clipping planes to object space. Transforming a plane with a
+ * 4x4 matrix is done by multiplying with the transpose inverse.
+ * The inverse cancels out here since we transform by inverse(obmat). */
+ float tmat[4][4];
+ transpose_m4_m4(tmat, ob->obmat);
+ for (int i = 0; i < 6; i++) {
+ mul_m4_v4(tmat, planes[i]);
+ }
+}
static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
{
@@ -658,31 +906,46 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
return;
}
- float(*planes)[4] = NULL; /* TODO proper culling. */
- scd->fast_mode = false;
-
const DRWContextState *drwctx = DRW_context_state_get();
+ RegionView3D *rv3d = drwctx->rv3d;
+
+ /* Frustum planes to show only visible PBVH nodes. */
+ float planes[6][4];
+ drw_sculpt_get_frustum_planes(scd->ob, planes);
+ PBVHFrustumPlanes frustum = {.planes = planes, .num_planes = 6};
+
+ /* Fast mode to show low poly multires while navigating. */
+ scd->fast_mode = false;
if (drwctx->evil_C != NULL) {
Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C);
if (p && (p->flags & PAINT_FAST_NAVIGATE)) {
- scd->fast_mode = (drwctx->rv3d->rflag & RV3D_NAVIGATING) != 0;
+ scd->fast_mode = rv3d && (rv3d->rflag & RV3D_NAVIGATING);
}
}
+ /* Update draw buffers only for visible nodes while painting.
+ * But do update them otherwise so navigating stays smooth. */
+ const bool update_only_visible = rv3d && (rv3d->rflag & RV3D_PAINTING);
+
Mesh *mesh = scd->ob->data;
BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg);
- BKE_pbvh_update_draw_buffers(pbvh, use_vcol);
- BKE_pbvh_draw_cb(pbvh, planes, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, scd);
+ BKE_pbvh_draw_cb(pbvh,
+ use_vcol,
+ update_only_visible,
+ &frustum,
+ (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb,
+ scd);
-#ifdef SCULPT_DEBUG_BUFFERS
- int node_nr = 0;
- DRW_debug_modelmat(scd->ob->obmat);
- BKE_pbvh_draw_debug_cb(
- pbvh,
- (void (*)(void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb,
- &node_nr);
-#endif
+ if (SCULPT_DEBUG_BUFFERS) {
+ int debug_node_nr = 0;
+ DRW_debug_modelmat(scd->ob->obmat);
+ BKE_pbvh_draw_debug_cb(
+ pbvh,
+ (void (*)(
+ void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb,
+ &debug_node_nr);
+ }
}
void DRW_shgroup_call_sculpt(
@@ -719,27 +982,26 @@ DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup,
BLI_assert(ELEM(prim_type, GPU_PRIM_POINTS, GPU_PRIM_LINES, GPU_PRIM_TRI_FAN));
BLI_assert(format != NULL);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
+ DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers);
+ callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count);
+ callbuf->buf_select = NULL;
+ callbuf->count = 0;
- call->state = drw_call_state_object(shgroup, NULL, NULL);
- GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->vert_count);
- call->batch = DRW_temp_batch_request(DST.idatalist, buf, prim_type);
- call->vert_first = 0;
- call->vert_count = 0;
- call->inst_count = 0;
-
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
/* Not actually used for rendering but alloced in one chunk. */
if (inst_select_format.attr_len == 0) {
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
}
- call->inst_selectid = DRW_temp_buffer_request(
- DST.idatalist, &inst_select_format, &call->vert_count);
+ callbuf->buf_select = DRW_temp_buffer_request(
+ DST.idatalist, &inst_select_format, &callbuf->count);
+ drw_command_set_select_id(shgroup, callbuf->buf_select, -1);
}
-#endif
- return (DRWCallBuffer *)call;
+
+ DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL);
+ GPUBatch *batch = DRW_temp_batch_request(DST.idatalist, callbuf->buf, prim_type);
+ drw_command_draw(shgroup, batch, handle);
+
+ return callbuf;
}
DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup,
@@ -749,56 +1011,52 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup,
BLI_assert(geom != NULL);
BLI_assert(format != NULL);
- DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls);
- BLI_LINKS_APPEND(&shgroup->calls, call);
+ DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers);
+ callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count);
+ callbuf->buf_select = NULL;
+ callbuf->count = 0;
- call->state = drw_call_state_object(shgroup, NULL, NULL);
- GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->inst_count);
- call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf, geom);
- call->vert_first = 0;
- call->vert_count = 0; /* Auto from batch. */
- call->inst_count = 0;
-
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
/* Not actually used for rendering but alloced in one chunk. */
if (inst_select_format.attr_len == 0) {
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
}
- call->inst_selectid = DRW_temp_buffer_request(
- DST.idatalist, &inst_select_format, &call->inst_count);
+ callbuf->buf_select = DRW_temp_buffer_request(
+ DST.idatalist, &inst_select_format, &callbuf->count);
+ drw_command_set_select_id(shgroup, callbuf->buf_select, -1);
}
-#endif
- return (DRWCallBuffer *)call;
+
+ DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL);
+ GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, callbuf->buf, geom);
+ drw_command_draw(shgroup, batch, handle);
+
+ return callbuf;
}
void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint attr_len)
{
- DRWCall *call = (DRWCall *)callbuf;
- const bool is_instance = call->batch->inst != NULL;
- GPUVertBuf *buf = is_instance ? call->batch->inst : call->batch->verts[0];
- uint count = is_instance ? call->inst_count++ : call->vert_count++;
- const bool resize = (count == buf->vertex_alloc);
+ GPUVertBuf *buf = callbuf->buf;
+ const bool resize = (callbuf->count == buf->vertex_alloc);
BLI_assert(attr_len == buf->format.attr_len);
UNUSED_VARS_NDEBUG(attr_len);
if (UNLIKELY(resize)) {
- GPU_vertbuf_data_resize(buf, count + DRW_BUFFER_VERTS_CHUNK);
+ GPU_vertbuf_data_resize(buf, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
}
for (int i = 0; i < attr_len; i++) {
- GPU_vertbuf_attr_set(buf, i, count, attr[i]);
+ GPU_vertbuf_attr_set(buf, i, callbuf->count, attr[i]);
}
-#ifdef USE_GPU_SELECT
if (G.f & G_FLAG_PICKSEL) {
if (UNLIKELY(resize)) {
- GPU_vertbuf_data_resize(call->inst_selectid, count + DRW_BUFFER_VERTS_CHUNK);
+ GPU_vertbuf_data_resize(callbuf->buf_select, callbuf->count + DRW_BUFFER_VERTS_CHUNK);
}
- GPU_vertbuf_attr_set(call->inst_selectid, 0, count, &DST.select_id);
+ GPU_vertbuf_attr_set(callbuf->buf_select, 0, callbuf->count, &DST.select_id);
}
-#endif
+
+ callbuf->count++;
}
/** \} */
@@ -811,7 +1069,54 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
{
shgroup->uniforms = NULL;
+ /* TODO(fclem) make them builtin. */
int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock");
+ int model_ubo_location = GPU_shader_get_uniform_block(shader, "modelBlock");
+ int info_ubo_location = GPU_shader_get_uniform_block(shader, "infoBlock");
+ int baseinst_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_BASE_INSTANCE);
+ int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK);
+
+ if (chunkid_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1);
+ }
+
+ if (baseinst_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1);
+ }
+
+ if (model_ubo_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 1);
+ }
+ else {
+ int model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
+ int modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
+ int modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
+ if (model != -1) {
+ drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 1);
+ }
+ if (modelinverse != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 1);
+ }
+ if (modelviewprojection != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, modelviewprojection, DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX, NULL, 0, 1);
+ }
+ }
+
+ if (info_ubo_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 1);
+
+ /* Abusing this loc to tell shgroup we need the obinfos. */
+ shgroup->objectinfo = 1;
+ }
+ else {
+ shgroup->objectinfo = 0;
+ }
if (view_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
@@ -834,31 +1139,6 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL) == -1);
-
- shgroup->model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
- shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
- shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
- shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_ORCO);
- shgroup->objectinfo = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_INFO);
- shgroup->objectcolor = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_COLOR);
- shgroup->callid = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CALLID);
-
- shgroup->matflag = 0;
- if (shgroup->modelinverse > -1) {
- shgroup->matflag |= DRW_CALL_MODELINVERSE;
- }
- if (shgroup->modelviewprojection > -1) {
- shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION;
- }
- if (shgroup->orcotexfac > -1) {
- shgroup->matflag |= DRW_CALL_ORCOTEXFAC;
- }
- if (shgroup->objectinfo > -1) {
- shgroup->matflag |= DRW_CALL_OBJECTINFO;
- }
- if (shgroup->objectcolor > -1) {
- shgroup->matflag |= DRW_CALL_OBJECTCOLOR;
- }
}
static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
@@ -868,13 +1148,9 @@ static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass
BLI_LINKS_APPEND(&pass->shgroups, shgroup);
shgroup->shader = shader;
- shgroup->state_extra = 0;
- shgroup->state_extra_disable = ~0x0;
- shgroup->stencil_mask = 0;
- shgroup->calls.first = NULL;
- shgroup->calls.last = NULL;
- shgroup->tfeedback_target = NULL;
- shgroup->pass_parent = pass;
+ shgroup->cmd.first = NULL;
+ shgroup->cmd.last = NULL;
+ shgroup->pass_handle = pass->handle;
return shgroup;
}
@@ -975,7 +1251,7 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
BLI_assert(tf_target != NULL);
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
drw_shgroup_init(shgroup, shader);
- shgroup->tfeedback_target = tf_target;
+ drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 1);
return shgroup;
}
@@ -985,37 +1261,42 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
*/
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
{
- shgroup->state_extra |= state;
+ drw_command_set_mutable_state(shgroup, state, 0x0);
}
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
{
- shgroup->state_extra_disable &= ~state;
+ drw_command_set_mutable_state(shgroup, 0x0, state);
}
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
{
- BLI_assert(mask <= 255);
- shgroup->stencil_mask = mask;
+ drw_command_set_stencil_mask(shgroup, mask);
}
-bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
-{
- return shgroup->calls.first == NULL;
-}
-
-/* This is a workaround function waiting for the clearing operation to be available inside the
- * shgroups. */
-DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup)
+void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
+ eGPUFrameBufferBits channels,
+ uchar r,
+ uchar g,
+ uchar b,
+ uchar a,
+ float depth,
+ uchar stencil)
{
- return shgroup->next;
+ drw_command_clear(shgroup, channels, r, g, b, a, depth, stencil);
}
-/* This is a workaround function waiting for the clearing operation to be available inside the
- * shgroups. */
-uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup)
+bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
{
- return shgroup->stencil_mask;
+ DRWCommandChunk *chunk = shgroup->cmd.first;
+ for (; chunk; chunk = chunk->next) {
+ for (int i = 0; i < chunk->command_used; i++) {
+ if (command_type_get(chunk->command_type, i) <= DRW_MAX_DRAW_CMD_TYPE) {
+ return false;
+ }
+ }
+ }
+ return true;
}
DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
@@ -1023,11 +1304,14 @@ DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
DRWShadingGroup *shgroup_new = BLI_memblock_alloc(DST.vmempool->shgroups);
*shgroup_new = *shgroup;
- shgroup_new->uniforms = NULL;
- shgroup_new->calls.first = NULL;
- shgroup_new->calls.last = NULL;
+ drw_shgroup_init(shgroup_new, shgroup_new->shader);
+ shgroup_new->cmd.first = NULL;
+ shgroup_new->cmd.last = NULL;
+
+ DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes,
+ &shgroup->pass_handle);
- BLI_LINKS_INSERT_AFTER(&shgroup->pass_parent->shgroups, shgroup, shgroup_new);
+ BLI_LINKS_INSERT_AFTER(&parent_pass->shgroups, shgroup, shgroup_new);
return shgroup_new;
}
@@ -1522,6 +1806,8 @@ DRWPass *DRW_pass_create(const char *name, DRWState state)
pass->shgroups.first = NULL;
pass->shgroups.last = NULL;
+ pass->handle = DST.pass_handle;
+ DRW_handle_increment(&DST.pass_handle);
return pass;
}
@@ -1560,47 +1846,22 @@ void DRW_pass_foreach_shgroup(DRWPass *pass,
}
}
-typedef struct ZSortData {
- const float *axis;
- const float *origin;
-} ZSortData;
-
-static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
+static int pass_shgroup_dist_sort(const void *a, const void *b)
{
- const ZSortData *zsortdata = (ZSortData *)thunk;
const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a;
const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b;
- const DRWCall *call_a = (DRWCall *)shgrp_a->calls.first;
- const DRWCall *call_b = (DRWCall *)shgrp_b->calls.first;
-
- if (call_a == NULL) {
- return -1;
- }
- if (call_b == NULL) {
- return -1;
- }
-
- float tmp[3];
- sub_v3_v3v3(tmp, zsortdata->origin, call_a->state->model[3]);
- const float a_sq = dot_v3v3(zsortdata->axis, tmp);
- sub_v3_v3v3(tmp, zsortdata->origin, call_b->state->model[3]);
- const float b_sq = dot_v3v3(zsortdata->axis, tmp);
-
- if (a_sq < b_sq) {
+ if (shgrp_a->z_sorting.distance < shgrp_b->z_sorting.distance) {
return 1;
}
- else if (a_sq > b_sq) {
+ else if (shgrp_a->z_sorting.distance > shgrp_b->z_sorting.distance) {
return -1;
}
else {
- /* If there is a depth prepass put it before */
- if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
+ /* If distances are the same, keep original order. */
+ if (shgrp_a->z_sorting.original_index > shgrp_b->z_sorting.original_index) {
return -1;
}
- else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
- return 1;
- }
else {
return 0;
}
@@ -1611,35 +1872,61 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
#define SORT_IMPL_LINKTYPE DRWShadingGroup
-#define SORT_IMPL_USE_THUNK
#define SORT_IMPL_FUNC shgroup_sort_fn_r
#include "../../blenlib/intern/list_sort_impl.h"
#undef SORT_IMPL_FUNC
-#undef SORT_IMPL_USE_THUNK
#undef SORT_IMPL_LINKTYPE
/**
* Sort Shading groups by decreasing Z of their first draw call.
- * This is useful for order dependent effect such as transparency.
+ * This is useful for order dependent effect such as alpha-blending.
*/
void DRW_pass_sort_shgroup_z(DRWPass *pass)
{
const float(*viewinv)[4] = DST.view_active->storage.viewinv;
- ZSortData zsortdata = {viewinv[2], viewinv[3]};
-
- if (pass->shgroups.first && pass->shgroups.first->next) {
- pass->shgroups.first = shgroup_sort_fn_r(
- pass->shgroups.first, pass_shgroup_dist_sort, &zsortdata);
+ if (!(pass->shgroups.first && pass->shgroups.first->next)) {
+ /* Nothing to sort */
+ return;
+ }
- /* Find the next last */
- DRWShadingGroup *last = pass->shgroups.first;
- while ((last = last->next)) {
- /* Do nothing */
+ uint index = 0;
+ DRWShadingGroup *shgroup = pass->shgroups.first;
+ do {
+ DRWResourceHandle handle = 0;
+ /* Find first DRWCommandDraw. */
+ DRWCommandChunk *cmd_chunk = shgroup->cmd.first;
+ for (; cmd_chunk && handle == 0; cmd_chunk = cmd_chunk->next) {
+ for (int i = 0; i < cmd_chunk->command_used && handle == 0; i++) {
+ if (DRW_CMD_DRAW == command_type_get(cmd_chunk->command_type, i)) {
+ handle = cmd_chunk->commands[i].draw.handle;
+ }
+ }
}
- pass->shgroups.last = last;
+ /* To be sorted a shgroup needs to have at least one draw command. */
+ BLI_assert(handle != 0);
+
+ DRWObjectMatrix *obmats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, &handle);
+
+ /* Compute distance to camera. */
+ float tmp[3];
+ sub_v3_v3v3(tmp, viewinv[3], obmats->model[3]);
+ shgroup->z_sorting.distance = dot_v3v3(viewinv[2], tmp);
+ shgroup->z_sorting.original_index = index++;
+
+ } while ((shgroup = shgroup->next));
+
+ /* Sort using computed distances. */
+ pass->shgroups.first = shgroup_sort_fn_r(pass->shgroups.first, pass_shgroup_dist_sort);
+
+ /* Find the new last */
+ DRWShadingGroup *last = pass->shgroups.first;
+ while ((last = last->next)) {
+ /* Reset the pass id for debugging. */
+ last->pass_handle = pass->handle;
}
+ pass->shgroups.last = last;
}
/** \} */
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 1dcaf39fc19..fa7c44c1b1f 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -29,6 +29,7 @@
#include "BKE_global.h"
#include "GPU_extensions.h"
+#include "GPU_platform.h"
#include "intern/gpu_shader_private.h"
#include "intern/gpu_primitive_private.h"
@@ -36,16 +37,41 @@
# include "GPU_select.h"
#endif
-#ifdef USE_GPU_SELECT
void DRW_select_load_id(uint id)
{
+#ifdef USE_GPU_SELECT
BLI_assert(G.f & G_FLAG_PICKSEL);
DST.select_id = id;
-}
#endif
+}
#define DEBUG_UBO_BINDING
+typedef struct DRWCommandsState {
+ GPUBatch *batch;
+ int resource_chunk;
+ int base_inst;
+ int inst_count;
+ int v_first;
+ int v_count;
+ bool neg_scale;
+ /* Resource location. */
+ int obmats_loc;
+ int obinfos_loc;
+ int baseinst_loc;
+ int chunkid_loc;
+ /* Legacy matrix support. */
+ int obmat_loc;
+ int obinv_loc;
+ int mvp_loc;
+ /* Selection ID state. */
+ GPUVertBuf *select_buf;
+ uint select_id;
+ /* Drawing State */
+ DRWState drw_state_enabled;
+ DRWState drw_state_disabled;
+} DRWCommandsState;
+
/* -------------------------------------------------------------------- */
/** \name Draw State (DRW_state)
* \{ */
@@ -407,9 +433,10 @@ void DRW_state_reset(void)
/** \name Culling (DRW_culling)
* \{ */
-static bool draw_call_is_culled(DRWCall *call, DRWView *view)
+static bool draw_call_is_culled(const DRWResourceHandle *handle, DRWView *view)
{
- return (call->state->culling->mask & view->culling_mask) != 0;
+ DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates, handle);
+ return (culling->mask & view->culling_mask) != 0;
}
/* Set active view for rendering. */
@@ -588,66 +615,96 @@ static void draw_compute_culling(DRWView *view)
/** \name Draw (DRW_draw)
* \{ */
-static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call)
+BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup,
+ DRWResourceHandle *handle,
+ float obmat_loc,
+ float obinv_loc,
+ float mvp_loc)
{
- BLI_assert(call);
- DRWCallState *state = call->state;
-
- if (shgroup->model != -1) {
- GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model);
- }
- if (shgroup->modelinverse != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse);
- }
- if (shgroup->objectinfo != -1) {
- float infos[4];
- infos[0] = state->ob_index;
- // infos[1]; /* UNUSED. */
- infos[2] = state->ob_random;
- infos[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f;
- GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)infos);
- }
- if (shgroup->objectcolor != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->objectcolor, 4, 1, (float *)state->ob_color);
+ /* Still supported for compatibility with gpu_shader_* but should be forbidden. */
+ DRWObjectMatrix *ob_mats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, handle);
+ if (obmat_loc != -1) {
+ GPU_shader_uniform_vector(shgroup->shader, obmat_loc, 16, 1, (float *)ob_mats->model);
}
- if (shgroup->orcotexfac != -1) {
- GPU_shader_uniform_vector(
- shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac);
+ if (obinv_loc != -1) {
+ GPU_shader_uniform_vector(shgroup->shader, obinv_loc, 16, 1, (float *)ob_mats->modelinverse);
}
/* Still supported for compatibility with gpu_shader_* but should be forbidden
* and is slow (since it does not cache the result). */
- if (shgroup->modelviewprojection != -1) {
+ if (mvp_loc != -1) {
float mvp[4][4];
- mul_m4_m4m4(mvp, DST.view_active->storage.persmat, state->model);
- GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)mvp);
+ mul_m4_m4m4(mvp, DST.view_active->storage.persmat, ob_mats->model);
+ GPU_shader_uniform_vector(shgroup->shader, mvp_loc, 16, 1, (float *)mvp);
}
}
+BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom)
+{
+ /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ }
+
+ DST.batch = geom;
+
+ GPU_batch_program_set_no_use(
+ geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
+
+ geom->program_in_use = true; /* XXX hacking #GPUBatch */
+
+ GPU_batch_bind(geom);
+}
+
BLI_INLINE void draw_geometry_execute(DRWShadingGroup *shgroup,
GPUBatch *geom,
- uint vert_first,
- uint vert_count,
- uint inst_first,
- uint inst_count)
+ int vert_first,
+ int vert_count,
+ int inst_first,
+ int inst_count,
+ int baseinst_loc)
{
+ /* inst_count can be -1. */
+ inst_count = max_ii(0, inst_count);
+
+ if (baseinst_loc != -1) {
+ /* Fallback when ARB_shader_draw_parameters is not supported. */
+ GPU_shader_uniform_vector_int(shgroup->shader, baseinst_loc, 1, 1, (int *)&inst_first);
+ /* Avoids VAO reconfiguration on older hardware. (see GPU_batch_draw_advanced) */
+ inst_first = 0;
+ }
+
/* bind vertex array */
if (DST.batch != geom) {
- DST.batch = geom;
-
- GPU_batch_program_set_no_use(
- geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
-
- GPU_batch_bind(geom);
+ draw_geometry_bind(shgroup, geom);
}
- /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */
- geom->program_in_use = true;
-
GPU_batch_draw_advanced(geom, vert_first, vert_count, inst_first, inst_count);
+}
- geom->program_in_use = false; /* XXX hacking #GPUBatch */
+BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ if (state->inst_count == 0) {
+ return;
+ }
+ if (state->baseinst_loc == -1) {
+ /* bind vertex array */
+ if (DST.batch != state->batch) {
+ GPU_draw_list_submit(DST.draw_list);
+ draw_geometry_bind(shgroup, state->batch);
+ }
+ GPU_draw_list_command_add(
+ DST.draw_list, state->v_first, state->v_count, state->base_inst, state->inst_count);
+ }
+ /* Fallback when unsupported */
+ else {
+ draw_geometry_execute(shgroup,
+ state->batch,
+ state->v_first,
+ state->v_count,
+ state->base_inst,
+ state->inst_count,
+ state->baseinst_loc);
+ }
}
enum {
@@ -719,6 +776,9 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
/* UBO isn't bound yet. Find an empty slot and bind it. */
idx = get_empty_slot_index(DST.RST.bound_ubo_slots);
+ /* [0..1] are reserved ubo slots. */
+ idx += 2;
+
if (idx < GPU_max_ubo_binds()) {
GPUUniformBuffer **gpu_ubo_slot = &DST.RST.bound_ubos[idx];
/* Unbind any previous UBO. */
@@ -738,10 +798,13 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
}
}
else {
+ BLI_assert(idx < 64);
/* This UBO slot was released but the UBO is
* still bound here. Just flag the slot again. */
BLI_assert(DST.RST.bound_ubos[idx] == ubo);
}
+ /* Remove offset for flag bitfield. */
+ idx -= 2;
set_bound_flags(&DST.RST.bound_ubo_slots, &DST.RST.bound_ubo_slots_persist, idx, bind_type);
}
@@ -785,8 +848,12 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup)
printf("Trying to draw with missing UBO binding.\n");
valid = false;
}
+
+ DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes,
+ &shgroup->pass_handle);
+
printf("Pass : %s, Shader : %s, Block : %s\n",
- shgroup->pass_parent->name,
+ parent_pass->name,
shgroup->shader->name,
blockname);
}
@@ -818,119 +885,331 @@ static void release_ubo_slots(bool with_persist)
}
}
-static void draw_update_uniforms(DRWShadingGroup *shgroup)
+static void draw_update_uniforms(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ bool *use_tfeedback)
{
- for (DRWUniform *uni = shgroup->uniforms; uni; uni = uni->next) {
- GPUTexture *tex;
- GPUUniformBuffer *ubo;
- if (uni->location == -2) {
- uni->location = GPU_shader_get_uniform_ensure(shgroup->shader,
- DST.uniform_names.buffer + uni->name_ofs);
- if (uni->location == -1) {
- continue;
+ for (DRWUniformChunk *unichunk = shgroup->uniforms; unichunk; unichunk = unichunk->next) {
+ DRWUniform *uni = unichunk->uniforms;
+ for (int i = 0; i < unichunk->uniform_used; i++, uni++) {
+ GPUTexture *tex;
+ GPUUniformBuffer *ubo;
+ if (uni->location == -2) {
+ uni->location = GPU_shader_get_uniform_ensure(shgroup->shader,
+ DST.uniform_names.buffer + uni->name_ofs);
+ if (uni->location == -1) {
+ continue;
+ }
+ }
+ const void *data = uni->pvalue;
+ if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) {
+ data = uni->fvalue;
+ }
+ switch (uni->type) {
+ case DRW_UNIFORM_INT_COPY:
+ case DRW_UNIFORM_INT:
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ break;
+ case DRW_UNIFORM_FLOAT_COPY:
+ case DRW_UNIFORM_FLOAT:
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ break;
+ case DRW_UNIFORM_TEXTURE:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_PERSIST:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_PERSIST);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_REF:
+ tex = *((GPUTexture **)uni->pvalue);
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_BLOCK:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_TEMP);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_PERSIST:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_PERSIST);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_OBMATS:
+ state->obmats_loc = uni->location;
+ ubo = DST.vmempool->matrices_ubo[0];
+ GPU_uniformbuffer_bind(ubo, 0);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_OBINFOS:
+ state->obinfos_loc = uni->location;
+ ubo = DST.vmempool->obinfos_ubo[0];
+ GPU_uniformbuffer_bind(ubo, 1);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_RESOURCE_CHUNK:
+ state->chunkid_loc = uni->location;
+ GPU_shader_uniform_int(shgroup->shader, uni->location, 0);
+ break;
+ case DRW_UNIFORM_TFEEDBACK_TARGET:
+ BLI_assert(data && (*use_tfeedback == false));
+ *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
+ ((GPUVertBuf *)data)->vbo_id);
+ break;
+ /* Legacy/Fallback support. */
+ case DRW_UNIFORM_BASE_INSTANCE:
+ state->baseinst_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODEL_MATRIX:
+ state->obmat_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODEL_MATRIX_INVERSE:
+ state->obinv_loc = uni->location;
+ break;
+ case DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX:
+ state->mvp_loc = uni->location;
+ break;
}
- }
- const void *data = uni->pvalue;
- if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) {
- data = uni->fvalue;
- }
- switch (uni->type) {
- case DRW_UNIFORM_INT_COPY:
- case DRW_UNIFORM_INT:
- GPU_shader_uniform_vector_int(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
- break;
- case DRW_UNIFORM_FLOAT_COPY:
- case DRW_UNIFORM_FLOAT:
- GPU_shader_uniform_vector(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
- break;
- case DRW_UNIFORM_TEXTURE:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_TEXTURE_PERSIST:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_PERSIST);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_TEXTURE_REF:
- tex = *((GPUTexture **)uni->pvalue);
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_BLOCK:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_TEMP);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
- break;
- case DRW_UNIFORM_BLOCK_PERSIST:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_PERSIST);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
- break;
}
}
BLI_assert(ubo_bindings_validate(shgroup));
}
-BLI_INLINE bool draw_select_do_call(DRWShadingGroup *shgroup, DRWCall *call)
+BLI_INLINE void draw_select_buffer(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ GPUBatch *batch,
+ const DRWResourceHandle *handle)
{
-#ifdef USE_GPU_SELECT
- if ((G.f & G_FLAG_PICKSEL) == 0) {
- return false;
+ const bool is_instancing = (batch->inst != NULL);
+ int start = 0;
+ int count = 1;
+ int tot = is_instancing ? batch->inst->vertex_len : batch->verts[0]->vertex_len;
+ /* Hack : get "vbo" data without actually drawing. */
+ int *select_id = (void *)state->select_buf->data;
+
+ /* Batching */
+ if (!is_instancing) {
+ /* FIXME: Meh a bit nasty. */
+ if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) {
+ count = 3;
+ }
+ else if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) {
+ count = 2;
+ }
}
- if (call->inst_selectid != NULL) {
- const bool is_instancing = (call->inst_count != 0);
- uint start = 0;
- uint count = 1;
- uint tot = is_instancing ? call->inst_count : call->vert_count;
- /* Hack : get vbo data without actually drawing. */
- GPUVertBufRaw raw;
- GPU_vertbuf_attr_get_raw_data(call->inst_selectid, 0, &raw);
- int *select_id = GPU_vertbuf_raw_step(&raw);
-
- /* Batching */
- if (!is_instancing) {
- /* FIXME: Meh a bit nasty. */
- if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) {
- count = 3;
- }
- else if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) {
- count = 2;
- }
+
+ while (start < tot) {
+ GPU_select_load_id(select_id[start]);
+ if (is_instancing) {
+ draw_geometry_execute(shgroup, batch, 0, 0, start, count, state->baseinst_loc);
}
+ else {
+ draw_geometry_execute(
+ shgroup, batch, start, count, DRW_handle_id_get(handle), 0, state->baseinst_loc);
+ }
+ start += count;
+ }
+}
- while (start < tot) {
- GPU_select_load_id(select_id[start]);
- if (is_instancing) {
- draw_geometry_execute(shgroup, call->batch, 0, 0, start, count);
- }
- else {
- draw_geometry_execute(shgroup, call->batch, start, count, 0, 0);
+typedef struct DRWCommandIterator {
+ int cmd_index;
+ DRWCommandChunk *curr_chunk;
+} DRWCommandIterator;
+
+static void draw_command_iter_begin(DRWCommandIterator *iter, DRWShadingGroup *shgroup)
+{
+ iter->curr_chunk = shgroup->cmd.first;
+ iter->cmd_index = 0;
+}
+
+static DRWCommand *draw_command_iter_step(DRWCommandIterator *iter, eDRWCommandType *cmd_type)
+{
+ if (iter->curr_chunk) {
+ if (iter->cmd_index == iter->curr_chunk->command_len) {
+ iter->curr_chunk = iter->curr_chunk->next;
+ iter->cmd_index = 0;
+ }
+ if (iter->curr_chunk) {
+ *cmd_type = command_type_get(iter->curr_chunk->command_type, iter->cmd_index);
+ if (iter->cmd_index < iter->curr_chunk->command_used) {
+ return iter->curr_chunk->commands + iter->cmd_index++;
}
- start += count;
}
- return true;
}
+ return NULL;
+}
+
+static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHandle *handle)
+{
+ /* Front face is not a resource but it is inside the resource handle. */
+ bool neg_scale = DRW_handle_negative_scale_get(handle);
+ if (neg_scale != state->neg_scale) {
+ glFrontFace((neg_scale) ? GL_CW : GL_CCW);
+ state->neg_scale = neg_scale;
+ }
+
+ int chunk = DRW_handle_chunk_get(handle);
+ if (state->resource_chunk != chunk) {
+ if (state->chunkid_loc != -1) {
+ GPU_shader_uniform_int(NULL, state->chunkid_loc, chunk);
+ }
+ if (state->obmats_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
+ GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], 0);
+ }
+ if (state->obinfos_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
+ GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[chunk], 1);
+ }
+ state->resource_chunk = chunk;
+ }
+}
+
+static void draw_call_batching_flush(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ draw_indirect_call(shgroup, state);
+ GPU_draw_list_submit(DST.draw_list);
+
+ state->batch = NULL;
+ state->inst_count = 0;
+ state->base_inst = -1;
+}
+
+static void draw_call_single_do(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ GPUBatch *batch,
+ DRWResourceHandle handle,
+ int vert_first,
+ int vert_count,
+ int inst_count)
+{
+ draw_call_batching_flush(shgroup, state);
+
+ draw_call_resource_bind(state, &handle);
+
+ /* TODO This is Legacy. Need to be removed. */
+ if (state->obmats_loc == -1 &&
+ (state->obmat_loc != -1 || state->obinv_loc != -1 || state->mvp_loc != -1)) {
+ draw_legacy_matrix_update(
+ shgroup, &handle, state->obmat_loc, state->obinv_loc, state->mvp_loc);
+ }
+
+ if (G.f & G_FLAG_PICKSEL) {
+ if (state->select_buf != NULL) {
+ draw_select_buffer(shgroup, state, batch, &handle);
+ return;
+ }
+ else {
+ GPU_select_load_id(state->select_id);
+ }
+ }
+
+ draw_geometry_execute(shgroup,
+ batch,
+ vert_first,
+ vert_count,
+ DRW_handle_id_get(&handle),
+ inst_count,
+ state->baseinst_loc);
+}
+
+static void draw_call_batching_start(DRWCommandsState *state)
+{
+ state->neg_scale = false;
+ state->resource_chunk = 0;
+ state->base_inst = 0;
+ state->inst_count = 0;
+ state->v_first = 0;
+ state->v_count = 0;
+ state->batch = NULL;
+
+ state->select_id = -1;
+ state->select_buf = NULL;
+}
+
+/* NOTE: Does not support batches with instancing VBOs. */
+static void draw_call_batching_do(DRWShadingGroup *shgroup,
+ DRWCommandsState *state,
+ DRWCommandDraw *call)
+{
+ /* If any condition requires to interupt the merging. */
+ bool neg_scale = DRW_handle_negative_scale_get(&call->handle);
+ int chunk = DRW_handle_chunk_get(&call->handle);
+ int id = DRW_handle_id_get(&call->handle);
+ if ((state->neg_scale != neg_scale) || /* Need to change state. */
+ (state->resource_chunk != chunk) || /* Need to change UBOs. */
+ (state->batch != call->batch) /* Need to change VAO. */
+ ) {
+ draw_call_batching_flush(shgroup, state);
+
+ state->batch = call->batch;
+ state->v_first = (call->batch->elem) ? call->batch->elem->index_start : 0;
+ state->v_count = (call->batch->elem) ? call->batch->elem->index_len :
+ call->batch->verts[0]->vertex_len;
+ state->inst_count = 1;
+ state->base_inst = id;
+
+ draw_call_resource_bind(state, &call->handle);
+
+ GPU_draw_list_init(DST.draw_list, state->batch);
+ }
+ /* Is the id consecutive? */
+ else if (id != state->base_inst + state->inst_count) {
+ /* We need to add a draw command for the pending instances. */
+ draw_indirect_call(shgroup, state);
+ state->inst_count = 1;
+ state->base_inst = id;
+ }
+ /* We avoid a drawcall by merging with the precedent
+ * drawcall using instancing. */
else {
- GPU_select_load_id(call->select_id);
- return false;
+ state->inst_count++;
+ }
+}
+
+/* Flush remaining pending drawcalls. */
+static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState *state)
+{
+ draw_call_batching_flush(shgroup, state);
+
+ /* Reset state */
+ if (state->neg_scale) {
+ glFrontFace(GL_CCW);
+ }
+ if (state->obmats_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
+ }
+ if (state->obinfos_loc != -1) {
+ GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
}
-#else
- return false;
-#endif
}
static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
{
BLI_assert(shgroup->shader);
+ DRWCommandsState state = {
+ .obmats_loc = -1,
+ .obinfos_loc = -1,
+ .baseinst_loc = -1,
+ .chunkid_loc = -1,
+ .obmat_loc = -1,
+ .obinv_loc = -1,
+ .mvp_loc = -1,
+ .drw_state_enabled = 0,
+ .drw_state_disabled = 0,
+ };
+
const bool shader_changed = (DST.shader != shgroup->shader);
bool use_tfeedback = false;
@@ -940,56 +1219,116 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
}
GPU_shader_bind(shgroup->shader);
DST.shader = shgroup->shader;
+ /* XXX hacking gawain */
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ }
DST.batch = NULL;
}
- if (shgroup->tfeedback_target != NULL) {
- use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
- shgroup->tfeedback_target->vbo_id);
- }
-
release_ubo_slots(shader_changed);
release_texture_slots(shader_changed);
- drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
- drw_stencil_set(shgroup->stencil_mask);
+ draw_update_uniforms(shgroup, &state, &use_tfeedback);
- draw_update_uniforms(shgroup);
+ drw_state_set(pass_state);
/* Rendering Calls */
{
- bool prev_neg_scale = false;
- int callid = 0;
- for (DRWCall *call = shgroup->calls.first; call; call = call->next) {
-
- if (draw_call_is_culled(call, DST.view_active)) {
- continue;
+ DRWCommandIterator iter;
+ DRWCommand *cmd;
+ eDRWCommandType cmd_type;
+
+ draw_command_iter_begin(&iter, shgroup);
+
+ draw_call_batching_start(&state);
+
+ while ((cmd = draw_command_iter_step(&iter, &cmd_type))) {
+
+ switch (cmd_type) {
+ case DRW_CMD_DRWSTATE:
+ case DRW_CMD_STENCIL:
+ draw_call_batching_flush(shgroup, &state);
+ break;
+ case DRW_CMD_DRAW:
+ case DRW_CMD_DRAW_PROCEDURAL:
+ case DRW_CMD_DRAW_INSTANCE:
+ if (draw_call_is_culled(&cmd->instance.handle, DST.view_active)) {
+ continue;
+ }
+ break;
+ default:
+ break;
}
- /* XXX small exception/optimisation for outline rendering. */
- if (shgroup->callid != -1) {
- GPU_shader_uniform_vector_int(shgroup->shader, shgroup->callid, 1, 1, &callid);
- callid += 1;
- }
-
- /* Negative scale objects */
- bool neg_scale = call->state->flag & DRW_CALL_NEGSCALE;
- if (neg_scale != prev_neg_scale) {
- glFrontFace((neg_scale) ? GL_CW : GL_CCW);
- prev_neg_scale = neg_scale;
- }
-
- draw_geometry_prepare(shgroup, call);
-
- if (draw_select_do_call(shgroup, call)) {
- continue;
+ switch (cmd_type) {
+ case DRW_CMD_CLEAR:
+ GPU_framebuffer_clear(
+#ifndef NDEBUG
+ GPU_framebuffer_active_get(),
+#else
+ NULL,
+#endif
+ cmd->clear.clear_channels,
+ (float[4]){cmd->clear.r / 255.0f,
+ cmd->clear.g / 255.0f,
+ cmd->clear.b / 255.0f,
+ cmd->clear.a / 255.0f},
+ cmd->clear.depth,
+ cmd->clear.stencil);
+ break;
+ case DRW_CMD_DRWSTATE:
+ state.drw_state_enabled |= cmd->state.enable;
+ state.drw_state_disabled |= cmd->state.disable;
+ drw_state_set((pass_state & ~state.drw_state_disabled) | state.drw_state_enabled);
+ break;
+ case DRW_CMD_STENCIL:
+ drw_stencil_set(cmd->stencil.mask);
+ break;
+ case DRW_CMD_SELECTID:
+ state.select_id = cmd->select_id.select_id;
+ state.select_buf = cmd->select_id.select_buf;
+ break;
+ case DRW_CMD_DRAW:
+ if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) ||
+ cmd->draw.batch->inst) {
+ draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0);
+ }
+ else {
+ draw_call_batching_do(shgroup, &state, &cmd->draw);
+ }
+ break;
+ case DRW_CMD_DRAW_PROCEDURAL:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->procedural.batch,
+ cmd->procedural.handle,
+ 0,
+ cmd->procedural.vert_count,
+ 1);
+ break;
+ case DRW_CMD_DRAW_INSTANCE:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->instance.batch,
+ cmd->instance.handle,
+ 0,
+ 0,
+ cmd->instance.inst_count);
+ break;
+ case DRW_CMD_DRAW_RANGE:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->range.batch,
+ (DRWResourceHandle)0,
+ cmd->range.vert_first,
+ cmd->range.vert_count,
+ 1);
+ break;
}
-
- draw_geometry_execute(
- shgroup, call->batch, call->vert_first, call->vert_count, 0, call->inst_count);
}
- /* Reset state */
- glFrontFace(GL_CCW);
+
+ draw_call_batching_finish(shgroup, &state);
}
if (use_tfeedback) {
@@ -1065,6 +1404,17 @@ static void drw_draw_pass_ex(DRWPass *pass,
DST.shader = NULL;
}
+ if (DST.batch) {
+ DST.batch->program_in_use = false;
+ DST.batch = NULL;
+ }
+
+ /* Fix T67342 for some reason. AMD Pro driver bug. */
+ if ((DST.state & DRW_STATE_BLEND_CUSTOM) != 0 &&
+ GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
+ drw_state_set(DST.state & ~DRW_STATE_BLEND_CUSTOM);
+ }
+
/* HACK: Rasterized discard can affect clear commands which are not
* part of a DRWPass (as of now). So disable rasterized discard here
* if it has been enabled. */
diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c
index 7aa2e007f79..58643eb12a8 100644
--- a/source/blender/draw/intern/draw_view.c
+++ b/source/blender/draw/intern/draw_view.c
@@ -41,11 +41,9 @@
#include "BKE_object.h"
#include "BKE_paint.h"
-#include "DRW_render.h"
-
#include "view3d_intern.h"
-#include "draw_view.h"
+#include "draw_manager.h"
/* ******************** region info ***************** */
@@ -60,18 +58,17 @@ void DRW_draw_region_info(void)
}
/* ************************* Background ************************** */
+void DRW_clear_background()
+{
+ GPU_clear_color(0.0, 0.0, 0.0, 0.0);
+ GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT);
+}
void DRW_draw_background(bool do_alpha_checker)
{
- /* Just to make sure */
- glDepthMask(GL_TRUE);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glStencilMask(0xFF);
-
+ drw_state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL);
if (do_alpha_checker) {
/* Transparent render, do alpha checker. */
- GPU_depth_test(false);
-
GPU_matrix_push();
GPU_matrix_identity_set();
GPU_matrix_identity_projection_set();
@@ -79,18 +76,11 @@ void DRW_draw_background(bool do_alpha_checker)
imm_draw_box_checker_2d(-1.0f, -1.0f, 1.0f, 1.0f);
GPU_matrix_pop();
-
- GPU_clear(GPU_DEPTH_BIT | GPU_STENCIL_BIT);
-
- GPU_depth_test(true);
}
- else if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) {
+ else {
float m[4][4];
unit_m4(m);
- /* Gradient background Color */
- GPU_depth_test(false);
-
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
uint color = GPU_vertformat_attr_add(
@@ -103,8 +93,8 @@ void DRW_draw_background(bool do_alpha_checker)
immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR_DITHER);
- UI_GetThemeColor3ubv(TH_BACK_GRAD, col_lo);
UI_GetThemeColor3ubv(TH_BACK, col_hi);
+ UI_GetThemeColor3ubv(UI_GetThemeValue(TH_SHOW_BACK_GRAD) ? TH_BACK_GRAD : TH_BACK, col_lo);
immBegin(GPU_PRIM_TRI_FAN, 4);
immAttr3ubv(color, col_lo);
@@ -119,16 +109,6 @@ void DRW_draw_background(bool do_alpha_checker)
immUnbindProgram();
GPU_matrix_pop();
-
- GPU_clear(GPU_DEPTH_BIT | GPU_STENCIL_BIT);
-
- GPU_depth_test(true);
- }
- else {
- /* Solid background Color */
- UI_ThemeClearColorAlpha(TH_BACK, 1.0f);
-
- GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT);
}
}
diff --git a/source/blender/draw/intern/draw_view.h b/source/blender/draw/intern/draw_view.h
index 715c3c0d40c..7be186f1c72 100644
--- a/source/blender/draw/intern/draw_view.h
+++ b/source/blender/draw/intern/draw_view.h
@@ -24,6 +24,7 @@
#define __DRAW_VIEW_H__
void DRW_draw_region_info(void);
+void DRW_clear_background(void);
void DRW_draw_background(bool do_alpha_checker);
void DRW_draw_cursor(void);
void DRW_draw_gizmo_3d(void);
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
index e68e03c2438..afaaba0712f 100644
--- a/source/blender/draw/modes/edit_curve_mode.c
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -126,7 +126,7 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata))
datatoc_edit_curve_overlay_normals_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, "#define IN_PLACE_INSTANCES\n", NULL},
});
}
@@ -270,7 +270,7 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
geom = DRW_cache_curve_edge_wire_get(ob);
if (geom) {
- DRW_shgroup_call(wire_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(wire_shgrp, geom, ob);
}
if ((cu->flag & CU_3D) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0) {
@@ -280,12 +280,12 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
geom = DRW_cache_curve_edge_overlay_get(ob);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob);
}
geom = DRW_cache_curve_vert_overlay_get(ob, stl->g_data->show_handles);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob);
}
}
}
@@ -294,12 +294,12 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
if (BKE_object_is_in_editmode(ob)) {
struct GPUBatch *geom = DRW_cache_curve_edge_overlay_get(ob);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob);
}
geom = DRW_cache_curve_vert_overlay_get(ob, false);
if (geom) {
- DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob);
+ DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob);
}
}
}
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
index 83a271a3ccd..9957dbae3fb 100644
--- a/source/blender/draw/modes/edit_mesh_mode.c
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -55,6 +55,7 @@ extern char datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl[];
extern char datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl[];
extern char datatoc_edit_normals_vert_glsl[];
extern char datatoc_edit_normals_geom_glsl[];
+extern char datatoc_edit_mesh_skin_root_vert_glsl[];
extern char datatoc_common_globals_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
@@ -89,7 +90,6 @@ typedef struct EDIT_MESH_PassList {
typedef struct EDIT_MESH_FramebufferList {
struct GPUFrameBuffer *occlude_wire_fb;
- struct GPUFrameBuffer *ghost_wire_fb;
} EDIT_MESH_FramebufferList;
typedef struct EDIT_MESH_StorageList {
@@ -104,8 +104,6 @@ typedef struct EDIT_MESH_Data {
EDIT_MESH_StorageList *stl;
} EDIT_MESH_Data;
-#define MAX_SHADERS 16
-
/** Can only contain shaders (freed as array). */
typedef struct EDIT_MESH_Shaders {
/* weight */
@@ -117,6 +115,7 @@ typedef struct EDIT_MESH_Shaders {
GPUShader *overlay_edge_flat;
GPUShader *overlay_face;
GPUShader *overlay_facedot;
+ GPUShader *overlay_skin_root;
GPUShader *overlay_mix;
GPUShader *overlay_facefill;
@@ -144,6 +143,7 @@ typedef struct EDIT_MESH_ComponentShadingGroupList {
DRWShadingGroup *faces;
DRWShadingGroup *faces_cage;
DRWShadingGroup *facedots;
+ DRWShadingGroup *skin_roots;
} EDIT_MESH_ComponentShadingGroupList;
typedef struct EDIT_MESH_PrivateData {
@@ -159,12 +159,6 @@ typedef struct EDIT_MESH_PrivateData {
EDIT_MESH_ComponentShadingGroupList edit_shgrps;
EDIT_MESH_ComponentShadingGroupList edit_in_front_shgrps;
- DRWShadingGroup *vert_shgrp_in_front;
- DRWShadingGroup *edge_shgrp_in_front;
- DRWShadingGroup *face_shgrp_in_front;
- DRWShadingGroup *face_cage_shgrp_in_front;
- DRWShadingGroup *facedot_shgrp_in_front;
-
DRWShadingGroup *facefill_occluded_shgrp;
DRWShadingGroup *facefill_occluded_cage_shgrp;
DRWShadingGroup *mesh_analysis_shgrp;
@@ -275,6 +269,12 @@ static void EDIT_MESH_engine_init(void *vedata)
.frag = (const char *[]){lib, datatoc_edit_mesh_overlay_facefill_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg_data->def, NULL},
});
+ sh_data->overlay_skin_root = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){lib, datatoc_edit_mesh_skin_root_vert_glsl, NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, NULL},
+ });
+
MEM_freeN(lib);
sh_data->overlay_mix = DRW_shader_create_fullscreen(datatoc_edit_mesh_overlay_mix_frag_glsl,
@@ -350,6 +350,7 @@ static void edit_mesh_create_overlay_passes(float face_alpha,
GPUShader *edge_sh = (select_vert) ? sh_data->overlay_edge : sh_data->overlay_edge_flat;
GPUShader *face_sh = sh_data->overlay_face;
GPUShader *facedot_sh = sh_data->overlay_facedot;
+ GPUShader *skin_root_sh = sh_data->overlay_skin_root;
/* Faces */
passes->faces = DRW_pass_create("Edit Mesh Faces", DRW_STATE_WRITE_COLOR | statemod);
@@ -397,6 +398,10 @@ static void edit_mesh_create_overlay_passes(float face_alpha,
if (rv3d->rflag & RV3D_CLIPPING) {
DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
}
+
+ grp = shgrps->skin_roots = DRW_shgroup_create(skin_root_sh, passes->verts);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
}
if (select_face) {
grp = shgrps->facedots = DRW_shgroup_create(facedot_sh, passes->verts);
@@ -641,21 +646,24 @@ static void EDIT_MESH_cache_init(void *vedata)
static void edit_mesh_add_ob_to_pass(Scene *scene,
Object *ob,
+ DRWShadingGroup *skin_roots_shgrp,
DRWShadingGroup *vert_shgrp,
DRWShadingGroup *edge_shgrp,
DRWShadingGroup *face_shgrp,
DRWShadingGroup *face_cage_shgrp,
DRWShadingGroup *facedot_shgrp)
{
- struct GPUBatch *geom_tris, *geom_verts, *geom_edges, *geom_fcenter;
+ struct GPUBatch *geom_tris, *geom_verts, *geom_edges, *geom_fcenter, *skin_roots;
ToolSettings *tsettings = scene->toolsettings;
bool has_edit_mesh_cage = false;
+ bool has_skin_roots = false;
/* TODO: Should be its own function. */
Mesh *me = (Mesh *)ob->data;
BMEditMesh *embm = me->edit_mesh;
if (embm) {
has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
+ has_skin_roots = CustomData_get_offset(&embm->bm->vdata, CD_MVERT_SKIN) != -1;
}
face_shgrp = (has_edit_mesh_cage) ? face_cage_shgrp : face_shgrp;
@@ -668,6 +676,21 @@ static void edit_mesh_add_ob_to_pass(Scene *scene,
if ((tsettings->selectmode & SCE_SELECT_VERTEX) != 0) {
geom_verts = DRW_mesh_batch_cache_get_edit_vertices(ob->data);
DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob);
+
+ if (has_skin_roots) {
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(skin_roots_shgrp);
+ /* We need to upload the matrix. But the ob can be temporary allocated so we cannot
+ * use direct reference to ob->obmat. */
+ DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[0]", ob->obmat[0]);
+ DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[1]", ob->obmat[1]);
+ DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[2]", ob->obmat[2]);
+ DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[3]", ob->obmat[3]);
+
+ skin_roots = DRW_mesh_batch_cache_get_edit_skin_roots(ob->data);
+ /* NOTE(fclem) We cannot use ob here since it would offset the instance attribs with
+ * base instance offset. */
+ DRW_shgroup_call(grp, skin_roots, NULL);
+ }
}
if (facedot_shgrp && (tsettings->selectmode & SCE_SELECT_FACE) != 0) {
@@ -730,6 +753,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
if (g_data->do_zbufclip) {
edit_mesh_add_ob_to_pass(scene,
ob,
+ g_data->edit_shgrps.skin_roots,
g_data->edit_shgrps.verts,
g_data->edit_shgrps.edges,
g_data->facefill_occluded_shgrp,
@@ -739,6 +763,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
else if (do_in_front) {
edit_mesh_add_ob_to_pass(scene,
ob,
+ g_data->edit_in_front_shgrps.skin_roots,
g_data->edit_in_front_shgrps.verts,
g_data->edit_in_front_shgrps.edges,
g_data->edit_in_front_shgrps.faces,
@@ -748,6 +773,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
else {
edit_mesh_add_ob_to_pass(scene,
ob,
+ g_data->edit_shgrps.skin_roots,
g_data->edit_shgrps.verts,
g_data->edit_shgrps.edges,
g_data->edit_shgrps.faces,
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index ba5ecb143ae..70bccb4849c 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -122,8 +122,9 @@ typedef struct OBJECT_PassList {
struct DRWPass *bone_axes[2];
struct DRWPass *particle;
struct DRWPass *lightprobes;
- struct DRWPass *camera_images_back;
- struct DRWPass *camera_images_front;
+ struct DRWPass *camera_images_back_alpha_under;
+ struct DRWPass *camera_images_back_alpha_over;
+ struct DRWPass *camera_images_front_alpha_over;
} OBJECT_PassList;
typedef struct OBJECT_FramebufferList {
@@ -286,15 +287,10 @@ typedef struct OBJECT_PrivateData {
DRWShadingGroup *outlines_transform;
/* Lightprobes */
- DRWCallBuffer *lightprobes_cube_select;
- DRWCallBuffer *lightprobes_cube_select_dupli;
- DRWCallBuffer *lightprobes_cube_active;
- DRWCallBuffer *lightprobes_cube_transform;
-
- DRWCallBuffer *lightprobes_planar_select;
- DRWCallBuffer *lightprobes_planar_select_dupli;
- DRWCallBuffer *lightprobes_planar_active;
- DRWCallBuffer *lightprobes_planar_transform;
+ DRWShadingGroup *probe_outlines_transform;
+ DRWShadingGroup *probe_outlines_select;
+ DRWShadingGroup *probe_outlines_select_dupli;
+ DRWShadingGroup *probe_outlines_active;
/* Objects Centers */
DRWCallBuffer *center_active;
@@ -303,17 +299,6 @@ typedef struct OBJECT_PrivateData {
DRWCallBuffer *center_selected_lib;
DRWCallBuffer *center_deselected_lib;
- /* Outlines id offset (accessed as an array) */
- int id_ofs_active;
- int id_ofs_select;
- int id_ofs_select_dupli;
- int id_ofs_transform;
-
- int id_ofs_prb_active;
- int id_ofs_prb_select;
- int id_ofs_prb_select_dupli;
- int id_ofs_prb_transform;
-
bool xray_enabled;
bool xray_enabled_and_not_wire;
} OBJECT_PrivateData; /* Transient data */
@@ -417,7 +402,10 @@ static void OBJECT_engine_init(void *vedata)
if (!sh_data->outline_resolve) {
/* Outline */
sh_data->outline_prepass = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, datatoc_gpu_shader_3D_vert_glsl, NULL},
+ .vert = (const char *[]){sh_cfg_data->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_object_outline_prepass_vert_glsl,
+ NULL},
.frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg_data->def, NULL},
});
@@ -431,7 +419,7 @@ static void OBJECT_engine_init(void *vedata)
datatoc_object_outline_prepass_geom_glsl,
NULL},
.frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg_data->def, NULL},
+ .defs = (const char *[]){sh_cfg_data->def, "#define USE_GEOM\n", NULL},
});
sh_data->outline_resolve = DRW_shader_create_fullscreen(
@@ -539,10 +527,11 @@ static void OBJECT_engine_init(void *vedata)
/* Lightprobes */
sh_data->lightprobe_grid = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg_data->lib,
+ datatoc_common_view_lib_glsl,
datatoc_common_globals_lib_glsl,
datatoc_object_lightprobe_grid_vert_glsl,
NULL},
- .frag = (const char *[]){datatoc_gpu_shader_flat_id_frag_glsl, NULL},
+ .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg_data->def, NULL},
});
@@ -697,12 +686,12 @@ static void OBJECT_engine_free(void)
}
static DRWShadingGroup *shgroup_outline(DRWPass *pass,
- const int *ofs,
+ int outline_id,
GPUShader *sh,
eGPUShaderConfig sh_cfg)
{
DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_int(grp, "baseId", ofs, 1);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
@@ -741,128 +730,89 @@ static DRWShadingGroup *shgroup_points(DRWPass *pass,
return grp;
}
-static int *shgroup_theme_id_to_probe_outline_counter(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
-{
- if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
- switch (theme_id) {
- case TH_ACTIVE:
- case TH_SELECT:
- return &stl->g_data->id_ofs_prb_select_dupli;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_prb_transform;
- }
- }
-
- switch (theme_id) {
- case TH_ACTIVE:
- return &stl->g_data->id_ofs_prb_active;
- case TH_SELECT:
- return &stl->g_data->id_ofs_prb_select;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_prb_transform;
- }
-}
-
-static int *shgroup_theme_id_to_outline_counter(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
+static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl,
+ int theme_id,
+ const int base_flag)
{
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return &stl->g_data->id_ofs_select_dupli;
+ return stl->g_data->outlines_select_dupli;
case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
default:
- return &stl->g_data->id_ofs_transform;
+ return NULL;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return &stl->g_data->id_ofs_active;
- case TH_SELECT:
- return &stl->g_data->id_ofs_select;
- case TH_TRANSFORM:
- default:
- return &stl->g_data->id_ofs_transform;
- }
-}
-
-static DRWCallBuffer *buffer_theme_id_to_probe_planar_outline_shgrp(OBJECT_StorageList *stl,
- int theme_id)
-{
- /* does not increment counter */
- switch (theme_id) {
- case TH_ACTIVE:
- return stl->g_data->lightprobes_planar_active;
+ return stl->g_data->outlines_active;
case TH_SELECT:
- return stl->g_data->lightprobes_planar_select;
+ return stl->g_data->outlines_select;
case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
default:
- return stl->g_data->lightprobes_planar_transform;
+ return NULL;
}
}
-static DRWCallBuffer *buffer_theme_id_to_probe_cube_outline_shgrp(OBJECT_StorageList *stl,
+static DRWShadingGroup *shgroup_theme_id_to_probe_outline_or_null(OBJECT_StorageList *stl,
int theme_id,
const int base_flag)
{
- /* does not increment counter */
+ if (UNLIKELY(DRW_state_is_select())) {
+ return stl->g_data->probe_outlines_select;
+ }
+
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return stl->g_data->lightprobes_cube_select_dupli;
+ return stl->g_data->probe_outlines_select_dupli;
case TH_TRANSFORM:
+ return stl->g_data->probe_outlines_transform;
default:
- return stl->g_data->lightprobes_cube_transform;
+ return NULL;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return stl->g_data->lightprobes_cube_active;
+ return stl->g_data->probe_outlines_active;
case TH_SELECT:
- return stl->g_data->lightprobes_cube_select;
+ return stl->g_data->probe_outlines_select;
case TH_TRANSFORM:
+ return stl->g_data->probe_outlines_transform;
default:
- return stl->g_data->lightprobes_cube_transform;
+ return NULL;
}
}
-static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl,
- int theme_id,
- const int base_flag)
+static int shgroup_theme_id_to_outline_id(int theme_id, const int base_flag)
{
- int *counter = shgroup_theme_id_to_outline_counter(stl, theme_id, base_flag);
- *counter += 1;
-
if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
switch (theme_id) {
case TH_ACTIVE:
case TH_SELECT:
- return stl->g_data->outlines_select_dupli;
+ return 2;
case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
+ return 0;
default:
- return NULL;
+ return -1;
}
}
switch (theme_id) {
case TH_ACTIVE:
- return stl->g_data->outlines_active;
+ return 3;
case TH_SELECT:
- return stl->g_data->outlines_select;
+ return 1;
case TH_TRANSFORM:
- return stl->g_data->outlines_transform;
+ return 0;
default:
- return NULL;
+ return -1;
}
}
@@ -1042,13 +992,19 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data,
}
}
-/* Draw Camera Background Images */
+/* -------------------------------------------------------------------- */
+/** \name Camera Background Images
+ * \{ */
typedef struct CameraEngineData {
DrawData dd;
ListBase bg_data;
} CameraEngineData;
+
typedef struct CameraEngineBGData {
+ CameraBGImage *camera_image;
+ GPUTexture *texture;
float transform_mat[4][4];
+ bool premultiplied;
} CameraEngineBGData;
static void camera_engine_data_free(DrawData *dd)
@@ -1083,6 +1039,26 @@ static void camera_background_images_stereo_setup(Scene *scene,
iuser->flag &= ~IMA_SHOW_STEREO;
}
}
+static void camera_background_images_add_shgroup(DRWPass *pass,
+ CameraEngineBGData *bg_data,
+ GPUShader *shader,
+ GPUBatch *batch)
+{
+ CameraBGImage *camera_image = bg_data->camera_image;
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+
+ DRW_shgroup_uniform_float_copy(
+ grp, "depth", camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND ? 0.000001f : 0.999999f);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", camera_image->alpha);
+ DRW_shgroup_uniform_texture(grp, "image", bg_data->texture);
+ DRW_shgroup_uniform_bool_copy(grp, "imagePremultiplied", bg_data->premultiplied);
+ DRW_shgroup_uniform_float_copy(
+ grp, "flipX", (camera_image->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0);
+ DRW_shgroup_uniform_float_copy(
+ grp, "flipY", (camera_image->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0);
+ DRW_shgroup_uniform_mat4(grp, "TransformMat", bg_data->transform_mat);
+ DRW_shgroup_call(grp, batch, NULL);
+}
static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
OBJECT_PassList *psl,
@@ -1306,25 +1282,46 @@ static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
scale_m4,
uv2img_space);
- DRWPass *pass = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) ? psl->camera_images_front :
- psl->camera_images_back;
- GPUShader *shader = DRW_state_do_color_management() ? sh_data->object_camera_image_cm :
- sh_data->object_camera_image;
- DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+ /* Keep the references so we can reverse the loop */
+ bg_data->camera_image = bgpic;
+ bg_data->texture = tex;
+ bg_data->premultiplied = premultiplied;
+ }
- DRW_shgroup_uniform_float_copy(
- grp, "depth", (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) ? 0.000001 : 0.999999);
- DRW_shgroup_uniform_float_copy(grp, "alpha", bgpic->alpha);
- DRW_shgroup_uniform_texture(grp, "image", tex);
- DRW_shgroup_uniform_bool_copy(grp, "imagePremultiplied", premultiplied);
+ /* Mark the rest bg_data's to be reused in the next drawing call */
+ LinkData *last_node = list_node ? list_node->prev : camera_engine_data->bg_data.last;
+ while (list_node != NULL) {
+ CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data;
+ bg_data->texture = NULL;
+ bg_data->camera_image = NULL;
+ list_node = list_node->next;
+ }
- DRW_shgroup_uniform_float_copy(
- grp, "flipX", (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0);
- DRW_shgroup_uniform_float_copy(
- grp, "flipY", (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0);
- DRW_shgroup_uniform_mat4(grp, "TransformMat", bg_data->transform_mat);
+ GPUShader *shader = DRW_state_do_color_management() ? sh_data->object_camera_image_cm :
+ sh_data->object_camera_image;
+ /* loop 1: camera images alpha under */
+ for (list_node = last_node; list_node; list_node = list_node->prev) {
+ CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data;
+ CameraBGImage *camera_image = bg_data->camera_image;
+ if ((camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND) == 0) {
+ camera_background_images_add_shgroup(
+ psl->camera_images_back_alpha_under, bg_data, shader, batch);
+ }
+ }
- DRW_shgroup_call(grp, batch, NULL);
+ /* loop 2: camera images alpha over */
+ for (list_node = camera_engine_data->bg_data.first; list_node; list_node = list_node->next) {
+ CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data;
+ CameraBGImage *camera_image = bg_data->camera_image;
+ if (camera_image == NULL) {
+ break;
+ }
+ camera_background_images_add_shgroup((camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND) ?
+ psl->camera_images_front_alpha_over :
+ psl->camera_images_back_alpha_over,
+ bg_data,
+ shader,
+ batch);
}
}
}
@@ -1337,6 +1334,7 @@ static void camera_background_images_free_textures(void)
}
BLI_freelistN(&e_data.movie_clips);
}
+/* \} */
static void OBJECT_cache_init(void *vedata)
{
@@ -1346,7 +1344,8 @@ static void OBJECT_cache_init(void *vedata)
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
OBJECT_PrivateData *g_data;
const DRWContextState *draw_ctx = DRW_context_state_get();
- OBJECT_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ eGPUShaderConfig cfg = draw_ctx->sh_cfg;
+ OBJECT_Shaders *sh_data = &e_data.sh_data[cfg];
const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
@@ -1367,59 +1366,25 @@ static void OBJECT_cache_init(void *vedata)
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+ psl->lightprobes = DRW_pass_create("Outlines Probe Pass", state);
GPUShader *sh = sh_data->outline_prepass;
+ g_data->probe_outlines_transform = shgroup_outline(psl->lightprobes, 0, sh, cfg);
+ g_data->probe_outlines_select = shgroup_outline(psl->lightprobes, 1, sh, cfg);
+ g_data->probe_outlines_select_dupli = shgroup_outline(psl->lightprobes, 2, sh, cfg);
+ g_data->probe_outlines_active = shgroup_outline(psl->lightprobes, 3, sh, cfg);
+
+ psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+
if (g_data->xray_enabled_and_not_wire) {
sh = sh_data->outline_prepass_wire;
}
- g_data->outlines_select = shgroup_outline(
- psl->outlines, &g_data->id_ofs_select, sh, draw_ctx->sh_cfg);
- g_data->outlines_select_dupli = shgroup_outline(
- psl->outlines, &g_data->id_ofs_select_dupli, sh, draw_ctx->sh_cfg);
- g_data->outlines_transform = shgroup_outline(
- psl->outlines, &g_data->id_ofs_transform, sh, draw_ctx->sh_cfg);
- g_data->outlines_active = shgroup_outline(
- psl->outlines, &g_data->id_ofs_active, sh, draw_ctx->sh_cfg);
-
- g_data->id_ofs_select = 0;
- g_data->id_ofs_select_dupli = 0;
- g_data->id_ofs_active = 0;
- g_data->id_ofs_transform = 0;
- }
-
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRWPass *pass = psl->lightprobes = DRW_pass_create("Object Probe Pass", state);
- struct GPUBatch *sphere = DRW_cache_sphere_get();
- struct GPUBatch *quad = DRW_cache_quad_get();
-
- /* Cubemap */
- g_data->lightprobes_cube_select = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_select_dupli = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_active = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg);
- g_data->lightprobes_cube_transform = buffer_instance_outline(
- pass, sphere, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg);
-
- /* Planar */
- g_data->lightprobes_planar_select = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_select_dupli = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_active = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg);
- g_data->lightprobes_planar_transform = buffer_instance_outline(
- pass, quad, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg);
-
- g_data->id_ofs_prb_select = 0;
- g_data->id_ofs_prb_select_dupli = 0;
- g_data->id_ofs_prb_active = 0;
- g_data->id_ofs_prb_transform = 0;
+ g_data->outlines_transform = shgroup_outline(psl->outlines, 0, sh, cfg);
+ g_data->outlines_select = shgroup_outline(psl->outlines, 1, sh, cfg);
+ g_data->outlines_select_dupli = shgroup_outline(psl->outlines, 2, sh, cfg);
+ g_data->outlines_active = shgroup_outline(psl->outlines, 3, sh, cfg);
}
{
@@ -1438,7 +1403,6 @@ static void OBJECT_cache_init(void *vedata)
DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", alphaOcclu);
- DRW_shgroup_uniform_int(grp, "idOffsets", &stl->g_data->id_ofs_active, 4);
DRW_shgroup_call(grp, quad, NULL);
/* This is the bleed pass if do_outline_expand is false. */
@@ -1512,9 +1476,15 @@ static void OBJECT_cache_init(void *vedata)
/* Camera background images */
{
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
- psl->camera_images_back = DRW_pass_create("Camera Images Back", state);
- psl->camera_images_front = DRW_pass_create("Camera Images Front", state);
+ psl->camera_images_back_alpha_over = DRW_pass_create(
+ "Camera Images Back Over",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA_PREMUL);
+ psl->camera_images_back_alpha_under = DRW_pass_create(
+ "Camera Images Back Under",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL);
+ psl->camera_images_front_alpha_over = DRW_pass_create(
+ "Camera Images Front Over",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA_PREMUL);
}
for (int i = 0; i < 2; i++) {
@@ -1965,9 +1935,10 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye
}
if (la->mode & LA_SHOW_CONE) {
-
- DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat);
- DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat);
+ if (!DRW_state_is_select()) {
+ DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat);
+ DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat);
+ }
}
}
else {
@@ -1981,8 +1952,10 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye
}
if (la->mode & LA_SHOW_CONE) {
- DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat);
- DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat);
+ if (!DRW_state_is_select()) {
+ DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat);
+ DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat);
+ }
}
}
@@ -2695,12 +2668,21 @@ static void DRW_shgroup_volume_extra(OBJECT_ShadingGroupList *sgl,
DRW_object_wire_theme_get(ob, view_layer, &color);
/* Small cube showing voxel size. */
+ float min[3];
+ madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
float voxel_cubemat[4][4] = {{0.0f}};
- voxel_cubemat[0][0] = 1.0f / (float)sds->res[0];
- voxel_cubemat[1][1] = 1.0f / (float)sds->res[1];
- voxel_cubemat[2][2] = 1.0f / (float)sds->res[2];
+ /* scale small cube to voxel size */
+ voxel_cubemat[0][0] = 1.0f / (float)sds->base_res[0];
+ voxel_cubemat[1][1] = 1.0f / (float)sds->base_res[1];
+ voxel_cubemat[2][2] = 1.0f / (float)sds->base_res[2];
voxel_cubemat[3][0] = voxel_cubemat[3][1] = voxel_cubemat[3][2] = -1.0f;
voxel_cubemat[3][3] = 1.0f;
+ /* translate small cube to corner */
+ voxel_cubemat[3][0] = min[0];
+ voxel_cubemat[3][1] = min[1];
+ voxel_cubemat[3][2] = min[2];
+ voxel_cubemat[3][3] = 1.0f;
+ /* move small cube into the domain (otherwise its centered on vertex of domain object) */
translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f);
mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat);
@@ -2736,6 +2718,9 @@ static void DRW_shgroup_volume_extra(OBJECT_ShadingGroupList *sgl,
DRW_shgroup_uniform_texture(grp, "velocityZ", sds->tex_velocity_z);
DRW_shgroup_uniform_float_copy(grp, "displaySize", sds->vector_scale);
DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
+ DRW_shgroup_uniform_vec3_copy(grp, "cellSize", sds->cell_size);
+ DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", sds->p0);
+ DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", sds->res_min);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis);
DRW_shgroup_call_procedural_lines(grp, ob, line_count);
@@ -2766,15 +2751,6 @@ static void DRW_shgroup_speaker(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLa
DRW_buffer_add_entry(sgl->speaker, color, &one, ob->obmat);
}
-typedef struct OBJECT_LightProbeEngineData {
- DrawData dd;
-
- float increment_x[3];
- float increment_y[3];
- float increment_z[3];
- float corner[3];
-} OBJECT_LightProbeEngineData;
-
static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
OBJECT_StorageList *stl,
OBJECT_PassList *psl,
@@ -2791,13 +2767,10 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
OBJECT_ShadingGroupList *sgl = (ob->dtx & OB_DRAWXRAY) ? &stl->g_data->sgl_ghost :
&stl->g_data->sgl;
- OBJECT_LightProbeEngineData *prb_data = (OBJECT_LightProbeEngineData *)DRW_drawdata_ensure(
- &ob->id, &draw_engine_object_type, sizeof(OBJECT_LightProbeEngineData), NULL, NULL);
-
if (DRW_state_is_select() || do_outlines) {
- int *call_id = shgroup_theme_id_to_probe_outline_counter(stl, theme_id, ob->base_flag);
-
if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ float corner[3];
+ float increment[3][3];
/* Update transforms */
float cell_dim[3], half_cell_dim[3];
cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x);
@@ -2807,65 +2780,41 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data,
mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
/* First cell. */
- copy_v3_fl(prb_data->corner, -1.0f);
- add_v3_v3(prb_data->corner, half_cell_dim);
- mul_m4_v3(ob->obmat, prb_data->corner);
+ copy_v3_fl(corner, -1.0f);
+ add_v3_v3(corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, corner);
/* Opposite neighbor cell. */
- copy_v3_fl3(prb_data->increment_x, cell_dim[0], 0.0f, 0.0f);
- add_v3_v3(prb_data->increment_x, half_cell_dim);
- add_v3_fl(prb_data->increment_x, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_x);
- sub_v3_v3(prb_data->increment_x, prb_data->corner);
-
- copy_v3_fl3(prb_data->increment_y, 0.0f, cell_dim[1], 0.0f);
- add_v3_v3(prb_data->increment_y, half_cell_dim);
- add_v3_fl(prb_data->increment_y, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_y);
- sub_v3_v3(prb_data->increment_y, prb_data->corner);
-
- copy_v3_fl3(prb_data->increment_z, 0.0f, 0.0f, cell_dim[2]);
- add_v3_v3(prb_data->increment_z, half_cell_dim);
- add_v3_fl(prb_data->increment_z, -1.0f);
- mul_m4_v3(ob->obmat, prb_data->increment_z);
- sub_v3_v3(prb_data->increment_z, prb_data->corner);
+ copy_v3_fl3(increment[0], cell_dim[0], 0.0f, 0.0f);
+ copy_v3_fl3(increment[1], 0.0f, cell_dim[1], 0.0f);
+ copy_v3_fl3(increment[2], 0.0f, 0.0f, cell_dim[2]);
+
+ for (int i = 0; i < 3; i++) {
+ add_v3_v3(increment[i], half_cell_dim);
+ add_v3_fl(increment[i], -1.0f);
+ mul_m4_v3(ob->obmat, increment[i]);
+ sub_v3_v3(increment[i], corner);
+ }
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, ob->base_flag);
uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
DRWShadingGroup *grp = DRW_shgroup_create(sh_data->lightprobe_grid, psl->lightprobes);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_int_copy(grp, "call_id", *call_id);
- DRW_shgroup_uniform_int(grp, "baseId", call_id, 1); /* that's correct */
- DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_x", prb_data->increment_x, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_y", prb_data->increment_y, 1);
- DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1);
- DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+ DRW_shgroup_uniform_vec3_copy(grp, "corner", corner);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_x", increment[0]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_y", increment[1]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_z", increment[2]);
+ DRW_shgroup_uniform_ivec3_copy(grp, "grid_resolution", &prb->grid_resolution_x);
if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES);
}
DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
- *call_id += 1;
}
- else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
- float draw_size = 1.0f;
- float probe_cube_mat[4][4];
- // prb_data->draw_size = prb->data_draw_size * 0.1f;
- // unit_m4(prb_data->probe_cube_mat);
- // copy_v3_v3(prb_data->probe_cube_mat[3], ob->obmat[3]);
-
- DRWCallBuffer *buf = buffer_theme_id_to_probe_cube_outline_shgrp(
+ else if (prb->type == LIGHTPROBE_TYPE_PLANAR && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ DRWShadingGroup *grp = shgroup_theme_id_to_probe_outline_or_null(
stl, theme_id, ob->base_flag);
- /* TODO remove or change the drawing of the cube probes. This line draws nothing on purpose
- * to keep the call ids correct. */
- zero_m4(probe_cube_mat);
- DRW_buffer_add_entry(buf, call_id, &draw_size, probe_cube_mat);
- *call_id += 1;
- }
- else if (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) {
- float draw_size = 1.0f;
- DRWCallBuffer *buf = buffer_theme_id_to_probe_planar_outline_shgrp(stl, theme_id);
- DRW_buffer_add_entry(buf, call_id, &draw_size, ob->obmat);
- *call_id += 1;
+ DRW_shgroup_call_no_cull(grp, DRW_cache_quad_get(), ob);
}
}
@@ -3138,13 +3087,11 @@ static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob,
switch (GS(ob_data->name)) {
case ID_ME:
- BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
break;
case ID_CU: {
Curve *cu = (Curve *)ob_data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
texcoloc = cu->loc;
texcosize = cu->size;
break;
@@ -3176,7 +3123,8 @@ static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob,
DRW_buffer_add_entry(sgl->texspace, color, &one, tmp);
}
-static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id)
+static void DRW_shgroup_bounds(
+ OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id, char boundtype, bool around_origin)
{
float color[4], center[3], size[3], tmp[4][4], final_mat[4][4], one = 1.0f;
BoundBox bb_local;
@@ -3202,10 +3150,16 @@ static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int the
}
UI_GetThemeColor4fv(theme_id, color);
- BKE_boundbox_calc_center_aabb(bb, center);
BKE_boundbox_calc_size_aabb(bb, size);
- switch (ob->boundtype) {
+ if (around_origin) {
+ zero_v3(center);
+ }
+ else {
+ BKE_boundbox_calc_center_aabb(bb, center);
+ }
+
+ switch (boundtype) {
case OB_BOUND_BOX:
size_to_mat4(tmp, size);
copy_v3_v3(tmp[3], center);
@@ -3258,6 +3212,27 @@ static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int the
}
}
+static void DRW_shgroup_collision(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id)
+{
+ switch (ob->rigidbody_object->shape) {
+ case RB_SHAPE_BOX:
+ DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_BOX, true);
+ break;
+ case RB_SHAPE_SPHERE:
+ DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_SPHERE, true);
+ break;
+ case RB_SHAPE_CONE:
+ DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_CONE, true);
+ break;
+ case RB_SHAPE_CYLINDER:
+ DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_CYLINDER, true);
+ break;
+ case RB_SHAPE_CAPSULE:
+ DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_CAPSULE, true);
+ break;
+ }
+}
+
static void OBJECT_cache_populate_particles(OBJECT_Shaders *sh_data,
Object *ob,
OBJECT_PassList *psl)
@@ -3606,6 +3581,10 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
if (hide_object_extra) {
break;
}
+ if ((ob->base_flag & BASE_FROM_DUPLI) && (ob->transflag & OB_DUPLICOLLECTION) &&
+ ob->instance_collection) {
+ break;
+ }
DRW_shgroup_empty(sh_data, sgl, ob, view_layer, rv3d, draw_ctx->sh_cfg);
break;
case OB_SPEAKER:
@@ -3683,7 +3662,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
if (theme_id == TH_UNDEFINED) {
theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
}
- DRW_shgroup_bounds(sgl, ob, theme_id);
+ DRW_shgroup_bounds(sgl, ob, theme_id, ob->boundtype, false);
}
/* Helpers for when we're transforming origins. */
@@ -3742,7 +3721,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
/* Don't draw bounding box again if draw type is bound box. */
if ((ob->dtx & OB_DRAWBOUNDOX) && (ob->dt != OB_BOUNDBOX) &&
!ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE)) {
- DRW_shgroup_bounds(sgl, ob, theme_id);
+ DRW_shgroup_bounds(sgl, ob, theme_id, ob->boundtype, false);
}
if (ob->dtx & OB_AXIS) {
@@ -3752,6 +3731,10 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
DRW_buffer_add_entry(sgl->empties.empty_axes, color, &axes_size, ob->obmat);
}
+ if (ob->rigidbody_object) {
+ DRW_shgroup_collision(sgl, ob, theme_id);
+ }
+
if ((md = modifiers_findByType(ob, eModifierType_Smoke)) &&
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
(((SmokeModifierData *)md)->domain != NULL)) {
@@ -3782,55 +3765,33 @@ static void OBJECT_draw_scene(void *vedata)
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- int id_len_select = g_data->id_ofs_select;
- int id_len_select_dupli = g_data->id_ofs_select_dupli;
- int id_len_active = g_data->id_ofs_active;
- int id_len_transform = g_data->id_ofs_transform;
-
- int id_len_prb_select = g_data->id_ofs_prb_select;
- int id_len_prb_select_dupli = g_data->id_ofs_prb_select_dupli;
- int id_len_prb_active = g_data->id_ofs_prb_active;
- int id_len_prb_transform = g_data->id_ofs_prb_transform;
-
- int outline_calls = id_len_select + id_len_select_dupli + id_len_active + id_len_transform;
- outline_calls += id_len_prb_select + id_len_prb_select_dupli + id_len_prb_active +
- id_len_prb_transform;
+ int do_outlines = !DRW_pass_is_empty(psl->outlines) || !DRW_pass_is_empty(psl->lightprobes);
float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- DRW_draw_pass(psl->camera_images_back);
+ DRW_draw_pass(psl->camera_images_back_alpha_under);
+ DRW_draw_pass(psl->camera_images_back_alpha_over);
/* Don't draw Transparent passes in MSAA buffer. */
// DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */
- DRW_draw_pass(stl->g_data->sgl.transp_shapes);
+ DRW_draw_pass(g_data->sgl.transp_shapes);
MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
- DRW_draw_pass(stl->g_data->sgl.bone_solid);
- DRW_draw_pass(stl->g_data->sgl.bone_wire);
- DRW_draw_pass(stl->g_data->sgl.bone_outline);
- DRW_draw_pass(stl->g_data->sgl.non_meshes);
+ DRW_draw_pass(g_data->sgl.bone_solid);
+ DRW_draw_pass(g_data->sgl.bone_wire);
+ DRW_draw_pass(g_data->sgl.bone_outline);
+ DRW_draw_pass(g_data->sgl.non_meshes);
DRW_draw_pass(psl->particle);
- DRW_draw_pass(stl->g_data->sgl.bone_axes);
+ DRW_draw_pass(g_data->sgl.bone_axes);
MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
- DRW_draw_pass(stl->g_data->sgl.image_empties);
+ DRW_draw_pass(g_data->sgl.image_empties);
- if (DRW_state_is_fbo() && outline_calls > 0) {
+ if (DRW_state_is_fbo() && do_outlines) {
DRW_stats_group_start("Outlines");
- g_data->id_ofs_active = 1;
- g_data->id_ofs_select = g_data->id_ofs_active + id_len_active + id_len_prb_active + 1;
- g_data->id_ofs_select_dupli = g_data->id_ofs_select + id_len_select + id_len_prb_select + 1;
- g_data->id_ofs_transform = g_data->id_ofs_select_dupli + id_len_select_dupli +
- id_len_prb_select_dupli + 1;
-
- g_data->id_ofs_prb_active = g_data->id_ofs_active + id_len_active;
- g_data->id_ofs_prb_select = g_data->id_ofs_select + id_len_select;
- g_data->id_ofs_prb_select_dupli = g_data->id_ofs_select_dupli + id_len_select_dupli;
- g_data->id_ofs_prb_transform = g_data->id_ofs_transform + id_len_transform;
-
/* Render filled polygon on a separate framebuffer */
GPU_framebuffer_bind(fbl->outlines_fb);
GPU_framebuffer_clear_color_depth(fbl->outlines_fb, clearcol, 1.0f);
@@ -3865,7 +3826,7 @@ static void OBJECT_draw_scene(void *vedata)
}
/* Combine with scene buffer last */
- if (outline_calls > 0) {
+ if (do_outlines) {
DRW_draw_pass(psl->outlines_resolve);
}
}
@@ -3917,7 +3878,7 @@ static void OBJECT_draw_scene(void *vedata)
batch_camera_path_free(&stl->g_data->sgl_ghost.camera_path);
- DRW_draw_pass(psl->camera_images_front);
+ DRW_draw_pass(psl->camera_images_front_alpha_over);
camera_background_images_free_textures();
DRW_draw_pass(psl->ob_center);
diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c
index a5b1133abf4..9106e89663d 100644
--- a/source/blender/draw/modes/overlay_mode.c
+++ b/source/blender/draw/modes/overlay_mode.c
@@ -23,8 +23,6 @@
#include "DNA_mesh_types.h"
#include "DNA_view3d_types.h"
-#include "BIF_glutil.h"
-
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_object.h"
@@ -77,7 +75,6 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *face_wires_shgrp;
DRWShadingGroup *face_wires_xray_shgrp;
DRWView *view_wires;
- BLI_mempool *wire_color_mempool;
View3DOverlay overlay;
float wire_step_param;
bool clear_stencil;
@@ -208,10 +205,6 @@ static void overlay_cache_init(void *vedata)
if (v3d->shading.type == OB_WIRE) {
g_data->overlay.flag |= V3D_OVERLAY_WIREFRAMES;
-
- if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) {
- g_data->wire_color_mempool = BLI_mempool_create(sizeof(float[3]), 0, 512, 0);
- }
}
{
@@ -246,17 +239,11 @@ static void overlay_cache_init(void *vedata)
geometry_shader_uniforms(g_data->face_wires_shgrp);
geometry_shader_uniforms(g_data->face_wires_xray_shgrp);
}
- if (rv3d->rflag & RV3D_CLIPPING) {
- DRW_shgroup_state_enable(g_data->face_wires_shgrp, DRW_STATE_CLIP_PLANES);
- DRW_shgroup_state_enable(g_data->face_wires_xray_shgrp, DRW_STATE_CLIP_PLANES);
- }
-
g_data->wire_step_param = stl->g_data->overlay.wireframe_threshold - 254.0f / 255.0f;
}
}
static void overlay_wire_color_get(const View3D *v3d,
- const OVERLAY_PrivateData *pd,
const Object *ob,
const bool use_coloring,
float **rim_col,
@@ -305,8 +292,10 @@ static void overlay_wire_color_get(const View3D *v3d,
if (v3d->shading.type == OB_WIRE) {
if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) {
- *wire_col = BLI_mempool_alloc(pd->wire_color_mempool);
- *rim_col = BLI_mempool_alloc(pd->wire_color_mempool);
+ /* Theses stays valid until next call. So we need to copy them when using them as uniform. */
+ static float wire_col_val[3], rim_col_val[3];
+ *wire_col = wire_col_val;
+ *rim_col = rim_col_val;
if (v3d->shading.wire_color_type == V3D_SHADING_OBJECT_COLOR) {
linearrgb_to_srgb_v3_v3(*wire_col, ob->color);
@@ -400,7 +389,8 @@ static void overlay_cache_populate(void *vedata, Object *ob)
if ((!pd->show_overlays) ||
(((ob != draw_ctx->object_edit) && !is_edit_mode) || has_edit_mesh_cage) ||
ob->type != OB_MESH) {
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES);
const bool is_wire = (ob->dt < OB_SOLID);
const bool is_xray = (ob->dtx & OB_DRAWXRAY);
@@ -419,6 +409,10 @@ static void overlay_cache_populate(void *vedata, Object *ob)
shgrp = DRW_shgroup_create_sub(pd->face_wires_shgrp);
}
+ if (draw_ctx->rv3d->rflag & RV3D_CLIPPING) {
+ DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES);
+ }
+
float wire_step_param = 10.0f;
if (!use_sculpt_pbvh) {
wire_step_param = (all_wires) ? 1.0f : pd->wire_step_param;
@@ -427,9 +421,9 @@ static void overlay_cache_populate(void *vedata, Object *ob)
if (!(DRW_state_is_select() || DRW_state_is_depth())) {
float *rim_col, *wire_col;
- overlay_wire_color_get(v3d, pd, ob, use_coloring, &rim_col, &wire_col);
- DRW_shgroup_uniform_vec3(shgrp, "wireColor", wire_col, 1);
- DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1);
+ overlay_wire_color_get(v3d, ob, use_coloring, &rim_col, &wire_col);
+ DRW_shgroup_uniform_vec3_copy(shgrp, "wireColor", wire_col);
+ DRW_shgroup_uniform_vec3_copy(shgrp, "rimColor", rim_col);
DRW_shgroup_stencil_mask(shgrp,
(is_xray && (is_wire || !pd->clear_stencil)) ? 0x00 : 0xFF);
}
@@ -506,12 +500,6 @@ static void overlay_draw_scene(void *vedata)
/* TODO(fclem): find a way to unify the multisample pass together
* (non meshes + armature + wireframe) */
MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
-
- /* XXX TODO(fclem) do not discard data after drawing! Store them per viewport. */
- if (stl->g_data->wire_color_mempool) {
- BLI_mempool_destroy(stl->g_data->wire_color_mempool);
- stl->g_data->wire_color_mempool = NULL;
- }
}
static void overlay_engine_free(void)
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
index 1b196cd8bb7..9749619cffe 100644
--- a/source/blender/draw/modes/sculpt_mode.c
+++ b/source/blender/draw/modes/sculpt_mode.c
@@ -156,7 +156,8 @@ static void SCULPT_cache_populate(void *vedata, Object *ob)
const DRWContextState *draw_ctx = DRW_context_state_get();
if ((ob == draw_ctx->obact) &&
- (BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) || !ob->sculpt->modifiers_active)) {
+ (BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) ||
+ ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active)) {
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh && pbvh_has_mask(pbvh)) {
DRW_shgroup_call_sculpt(stl->g_data->mask_overlay_grp, ob, false, true, false);
diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/modes/shaders/common_globals_lib.glsl
index e559224eb9e..d147b193ccf 100644
--- a/source/blender/draw/modes/shaders/common_globals_lib.glsl
+++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl
@@ -34,6 +34,7 @@ layout(std140) uniform globalsBlock
vec4 colorVNormal;
vec4 colorLNormal;
vec4 colorFaceDot;
+ vec4 colorSkinRoot;
vec4 colorDeselect;
vec4 colorOutline;
vec4 colorLightNoAlpha;
diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl
index 20a54947db7..76089d1ae41 100644
--- a/source/blender/draw/modes/shaders/common_view_lib.glsl
+++ b/source/blender/draw/modes/shaders/common_view_lib.glsl
@@ -1,4 +1,5 @@
#define COMMON_VIEW_LIB
+#define DRW_RESOURCE_CHUNK_LEN 512
/* keep in sync with DRWManager.view_data */
layout(std140) uniform viewBlock
@@ -23,8 +24,77 @@ layout(std140) uniform viewBlock
_world_clip_planes_calc_clip_distance(p, clipPlanes)
#endif
+uniform int resourceChunk;
+
+#ifdef GPU_VERTEX_SHADER
+# ifdef GL_ARB_shader_draw_parameters
+# define baseInstance gl_BaseInstanceARB
+# else /* no ARB_shader_draw_parameters */
+uniform int baseInstance;
+# endif
+
+# ifdef IN_PLACE_INSTANCES
+/* When drawing instances of an object at the same position. */
+# define instanceId 0
+# elif defined(GPU_DEPRECATED_AMD_DRIVER)
+/* A driver bug make it so that when using an attribute with GL_INT_2_10_10_10_REV as format,
+ * the gl_InstanceID is incremented by the 2 bit component of the attrib.
+ * Ignore gl_InstanceID then. */
+# define instanceId 0
+# else
+# define instanceId gl_InstanceID
+# endif
+
+# define resource_id (baseInstance + instanceId)
+
+/* Use this to declare and pass the value if
+ * the fragment shader uses the resource_id. */
+# define RESOURCE_ID_VARYING flat out int resourceIDFrag;
+# define RESOURCE_ID_VARYING_GEOM flat out int resourceIDGeom;
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
+# define PASS_RESOURCE_ID_GEOM resourceIDGeom = resource_id;
+#endif
+
+/* If used in a fragment / geometry shader, we pass
+ * resource_id as varying. */
+#ifdef GPU_GEOMETRY_SHADER
+# define RESOURCE_ID_VARYING \
+ flat out int resourceIDFrag; \
+ flat in int resourceIDGeom[];
+
+# define resource_id resourceIDGeom
+# define PASS_RESOURCE_ID(i) resourceIDFrag = resource_id[i];
+#endif
+
+#ifdef GPU_FRAGMENT_SHADER
+flat in int resourceIDFrag;
+# define resource_id resourceIDFrag
+#endif
+
+#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC)
+struct ObjectMatrices {
+ mat4 drw_modelMatrix;
+ mat4 drw_modelMatrixInverse;
+};
+
+layout(std140) uniform modelBlock
+{
+ ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN];
+};
+
+# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix)
+# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse)
+
+#else /* GPU_INTEL */
+/* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage.
+ * So for now we just force using the legacy path. */
+/* Note that this is also a workaround of a problem on osx (amd or nvidia)
+ * and older amd driver on windows. */
uniform mat4 ModelMatrix;
uniform mat4 ModelMatrixInverse;
+#endif
+
+#define resource_handle (resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)
/** Transform shortcuts. */
/* Rule of thumb: Try to reuse world positions and normals because converting though viewspace
diff --git a/source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl
new file mode 100644
index 00000000000..5187571b27b
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl
@@ -0,0 +1,30 @@
+/* Need dedicated obmat since we use instancing attribs
+ * (we cannot let have baseinstance mess them). */
+uniform vec4 editModelMat[4];
+uniform vec3 screen_vecs[2];
+
+/* ---- Instantiated Attrs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attrs ---- */
+in float size;
+in vec3 local_pos;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ mat4 obmat = mat4(editModelMat[0], editModelMat[1], editModelMat[2], editModelMat[3]);
+ /* Could be optimized... but it is only for a handful of verts so not a priority. */
+ mat3 imat = inverse(mat3(obmat));
+ vec3 right = normalize(imat * vec3(screen_vecs[0]));
+ vec3 up = normalize(imat * vec3(screen_vecs[1]));
+ vec3 screen_pos = (right * pos.x + up * pos.y) * size;
+ vec4 pos_4d = obmat * vec4(local_pos + screen_pos, 1.0);
+ gl_Position = ViewProjectionMatrix * pos_4d;
+ finalColor = colorSkinRoot;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos_4d.xyz);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/object_camera_image_frag.glsl b/source/blender/draw/modes/shaders/object_camera_image_frag.glsl
index 5d8ad3c79ea..7804ebdb8c9 100644
--- a/source/blender/draw/modes/shaders/object_camera_image_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_camera_image_frag.glsl
@@ -19,5 +19,7 @@ void main()
#endif
color.a *= alpha;
+ color.rgb *= color.a;
+
fragColor = color;
}
diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
index d27d55c3fd6..144024a7d5d 100644
--- a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
@@ -1,18 +1,11 @@
-uniform mat4 ViewProjectionMatrix;
-
-uniform float sphere_size;
uniform ivec3 grid_resolution;
uniform vec3 corner;
uniform vec3 increment_x;
uniform vec3 increment_y;
uniform vec3 increment_z;
-uniform vec3 screen_vecs[2];
-
-uniform int call_id; /* we don't want the builtin callId which would be 0. */
-uniform int baseId;
-flat out uint finalId;
+flat out int objectId;
void main()
{
@@ -29,7 +22,8 @@ void main()
gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0);
gl_PointSize = 2.0f;
- finalId = uint(baseId + call_id);
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(ws_cell_location);
diff --git a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
index 7668a0c2c94..7b86d477a39 100644
--- a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
@@ -7,30 +7,9 @@ uniform usampler2D outlineId;
uniform sampler2D outlineDepth;
uniform sampler2D sceneDepth;
-uniform int idOffsets[4];
-
uniform float alphaOcclu;
uniform vec2 viewportSize;
-vec4 convert_id_to_color(int id)
-{
- if (id == 0) {
- return vec4(0.0);
- }
- if (id < idOffsets[1]) {
- return colorActive;
- }
- else if (id < idOffsets[2]) {
- return colorSelect;
- }
- else if (id < idOffsets[3]) {
- return colorDupliSelect;
- }
- else {
- return colorTransform;
- }
-}
-
void main()
{
ivec2 texel = ivec2(gl_FragCoord.xy);
@@ -85,7 +64,24 @@ void main()
const float epsilon = 3.0 / 8388608.0;
bool occluded = (ref_depth > scene_depth + epsilon);
- FragColor = convert_id_to_color(int(ref_id));
+ /* WATCH: Keep in sync with outlineId of the prepass. */
+ uint color_id = ref_id >> 14u;
+ if (ref_id == 0u) {
+ FragColor = vec4(0.0);
+ }
+ else if (color_id == 1u) {
+ FragColor = colorSelect;
+ }
+ else if (color_id == 2u) {
+ FragColor = colorDupliSelect;
+ }
+ else if (color_id == 3u) {
+ FragColor = colorActive;
+ }
+ else {
+ FragColor = colorTransform;
+ }
+
FragColor.a *= (occluded) ? alphaOcclu : 1.0;
FragColor.a = (outline) ? FragColor.a : 0.0;
}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
index c3447456ea6..5d6c4881b5b 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
@@ -1,10 +1,18 @@
-uniform int callId;
-uniform int baseId;
+
+/* Should be 2 bits only [0..3]. */
+uniform int outlineId;
+
+flat in int objectId;
/* using uint because 16bit uint can contain more ids than int. */
out uint outId;
+/* Replace top 2 bits (of the 16bit output) by outlineId.
+ * This leaves 16K different IDs to create outlines between objects.
+ * SHIFT = (32 - (16 - 2)) */
+#define SHIFT 18u
+
void main()
{
- outId = uint(baseId + callId);
+ outId = (uint(outlineId) << 14u) | ((uint(objectId) << SHIFT) >> SHIFT);
}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
index 5a3eb38fb6b..b32913dcd60 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
@@ -2,12 +2,15 @@
layout(lines_adjacency) in;
layout(line_strip, max_vertices = 2) out;
-in vec4 pPos[];
in vec3 vPos[];
+in int objectId_g[];
+
+flat out int objectId;
void vert_from_gl_in(int v)
{
- gl_Position = pPos[v];
+ gl_Position = gl_in[v].gl_Position;
+ objectId = objectId_g[v];
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_set_clip_distance(gl_in[v].gl_ClipDistance);
#endif
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
index e34afe95b5e..7740f9a4af2 100644
--- a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
@@ -1,16 +1,27 @@
in vec3 pos;
-out vec4 pPos;
+#ifdef USE_GEOM
out vec3 vPos;
+out int objectId_g;
+# define objectId objectId_g
+#else
+
+flat out int objectId;
+#endif
void main()
{
vec3 world_pos = point_object_to_world(pos);
+#ifdef USE_GEOM
vPos = point_world_to_view(world_pos);
- pPos = point_world_to_ndc(world_pos);
+#endif
+ gl_Position = point_world_to_ndc(world_pos);
/* Small bias to always be on top of the geom. */
- pPos.z -= 1e-3;
+ gl_Position.z -= 1e-3;
+
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
diff --git a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl
index e96a789b8b1..64f88bd74fa 100644
--- a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl
+++ b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl
@@ -6,6 +6,13 @@ uniform float displaySize = 1.0;
uniform float slicePosition;
uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
+/* SmokeDomainSettings.cell_size */
+uniform vec3 cellSize;
+/* SmokeDomainSettings.p0 */
+uniform vec3 domainOriginOffset;
+/* SmokeDomainSettings.res_min */
+uniform ivec3 adaptiveCellOffset;
+
flat out vec4 finalColor;
const vec3 corners[4] = vec3[4](vec3(0.0, 0.2, -0.5),
@@ -66,7 +73,6 @@ void main()
#endif
ivec3 volume_size = textureSize(velocityX, 0);
- float voxel_size = 1.0 / float(max(max(volume_size.x, volume_size.y), volume_size.z));
ivec3 cell_ofs = ivec3(0);
ivec3 cell_div = volume_size;
@@ -89,8 +95,7 @@ void main()
cell_co.z = cell / (cell_div.x * cell_div.y);
cell_co += cell_ofs;
- vec3 pos = (vec3(cell_co) + 0.5) / vec3(volume_size);
- pos = pos * 2.0 - 1.0;
+ vec3 pos = domainOriginOffset + cellSize * (vec3(cell_co + adaptiveCellOffset) + 0.5);
vec3 velocity;
velocity.x = texelFetch(velocityX, cell_co, 0).r;
@@ -102,9 +107,9 @@ void main()
#ifdef USE_NEEDLE
mat3 rot_mat = rotation_from_vector(velocity);
vec3 rotated_pos = rot_mat * corners[indices[gl_VertexID % 12]];
- pos += rotated_pos * length(velocity) * displaySize * voxel_size;
+ pos += rotated_pos * length(velocity) * displaySize * cellSize;
#else
- pos += (((gl_VertexID % 2) == 1) ? velocity : vec3(0.0)) * displaySize * voxel_size;
+ pos += ((gl_VertexID % 2) == 1) ? velocity * displaySize * cellSize : vec3(0.0);
#endif
vec3 world_pos = point_object_to_world(pos);
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index d80b96f0d74..8951677b32f 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -3411,7 +3411,7 @@ static void acf_nlatrack_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, flo
}
/* set color for nla track */
- UI_GetThemeColorShade3fv(TH_HEADER, ((nonSolo == false) ? 20 : -20), r_color);
+ UI_GetThemeColorShade3fv(TH_NLA_TRACK, ((nonSolo == false) ? 20 : -20), r_color);
}
/* name for nla track entries */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index afd2cdc2a2b..0fc137295d0 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -3339,7 +3339,7 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Select Channel keyframes";
+ ot->name = "Select Channel Keyframes";
ot->idname = "ANIM_OT_channel_select_keys";
ot->description = "Select all keyframes of channel under mouse";
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 48493c9e961..f73c8a5b71a 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -1818,7 +1818,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
!(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* Layer visibility - we check both object and base,
* since these may not be in sync yet. */
- if ((base->flag & BASE_VISIBLE) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
continue;
}
@@ -3017,7 +3017,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_m
*/
if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* layer visibility - we check both object and base, since these may not be in sync yet */
- if ((base->flag & BASE_VISIBLE) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
return false;
}
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 8c873eb6b45..36583ecf060 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -486,7 +486,7 @@ static void draw_marker(
float name_y = UI_DPI_FAC * 18;
/* Give an offset to the marker name when selected,
* or when near the current frame (5 frames range, starting from the current one). */
- if ((marker->flag & SELECT) || (IN_RANGE_INCL(marker->frame, cfra - 4, cfra))) {
+ if ((marker->flag & SELECT) || (cfra - 4 <= marker->frame && marker->frame <= cfra)) {
name_y += UI_DPI_FAC * 10;
}
draw_marker_name(fstyle, marker, xpos, name_y);
@@ -1148,33 +1148,48 @@ static void deselect_markers(ListBase *markers)
}
/* select/deselect TimeMarker at current frame */
-static void select_timeline_marker_frame(ListBase *markers, int frame, bool extend)
+static int select_timeline_marker_frame(ListBase *markers,
+ int frame,
+ bool extend,
+ bool wait_to_deselect_others)
{
- TimeMarker *marker, *marker_first = NULL;
+ TimeMarker *marker, *marker_selected = NULL;
+ int ret_val = OPERATOR_FINISHED;
+
+ if (extend) {
+ wait_to_deselect_others = false;
+ }
/* support for selection cycling */
for (marker = markers->first; marker; marker = marker->next) {
if (marker->frame == frame) {
if (marker->flag & SELECT) {
- marker_first = marker->next;
+ marker_selected = marker->next;
break;
}
}
}
- /* if extend is not set, then deselect markers */
- if (extend == false) {
- deselect_markers(markers);
+ if (wait_to_deselect_others && marker_selected) {
+ ret_val = OPERATOR_RUNNING_MODAL;
}
+ /* if extend is not set, then deselect markers */
+ else {
+ if (extend == false) {
+ deselect_markers(markers);
+ }
- LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) {
- /* this way a not-extend select will always give 1 selected marker */
- if (marker->frame == frame) {
- marker->flag ^= SELECT;
- break;
+ LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_selected) {
+ /* this way a not-extend select will always give 1 selected marker */
+ if (marker->frame == frame) {
+ marker->flag ^= SELECT;
+ break;
+ }
}
+ LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_selected);
}
- LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_first);
+
+ return ret_val;
}
static void select_marker_camera_switch(
@@ -1221,17 +1236,17 @@ static void select_marker_camera_switch(
#endif
}
-static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera)
+static int ed_marker_select(
+ bContext *C, const int mval[2], bool extend, bool camera, bool wait_to_deselect_others)
{
ListBase *markers = ED_context_get_markers(C);
- ARegion *ar = CTX_wm_region(C);
View2D *v2d = UI_view2d_fromcontext(C);
+ int ret_val = OPERATOR_FINISHED;
- float mouse_region_x = event->x - ar->winrct.xmin;
- if (region_position_is_over_marker(v2d, markers, mouse_region_x)) {
- float frame_at_mouse_position = UI_view2d_region_to_view_x(v2d, mouse_region_x);
+ if (region_position_is_over_marker(v2d, markers, mval[0])) {
+ float frame_at_mouse_position = UI_view2d_region_to_view_x(v2d, mval[0]);
int cfra = ED_markers_find_nearest_marker_time(markers, frame_at_mouse_position);
- select_timeline_marker_frame(markers, cfra, extend);
+ ret_val = select_timeline_marker_frame(markers, cfra, extend, wait_to_deselect_others);
select_marker_camera_switch(C, camera, extend, markers, cfra);
}
@@ -1243,17 +1258,22 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
/* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ return ret_val | OPERATOR_PASS_THROUGH;
}
-static int ed_marker_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int ed_marker_select_exec(bContext *C, wmOperator *op)
{
const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
bool camera = false;
#ifdef DURIAN_CAMERA_SWITCH
camera = RNA_boolean_get(op->ptr, "camera");
#endif
- return ed_marker_select(C, event, extend, camera);
+ int mval[2];
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
+
+ return ed_marker_select(C, mval, extend, camera, wait_to_deselect_others);
}
static void MARKER_OT_select(wmOperatorType *ot)
@@ -1266,12 +1286,15 @@ static void MARKER_OT_select(wmOperatorType *ot)
ot->idname = "MARKER_OT_select";
/* api callbacks */
- ot->invoke = ed_marker_select_invoke;
ot->poll = ed_markers_poll_markers_exist;
+ ot->exec = ed_marker_select_exec;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ WM_operator_properties_generic_select(ot);
prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
#ifdef DURIAN_CAMERA_SWITCH
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index bd4886817cd..30bf837f6c0 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -36,6 +36,7 @@
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
#include "GPU_batch.h"
@@ -67,6 +68,37 @@ typedef struct MPathTarget {
/* ........ */
+/* update scene for current frame */
+static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph)
+{
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+Depsgraph *animviz_depsgraph_build(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ListBase *targets)
+{
+ /* Allocate dependency graph. */
+ Depsgraph *depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
+
+ /* Make a flat array of IDs for the DEG API. */
+ const int num_ids = BLI_listbase_count(targets);
+ ID **ids = MEM_malloc_arrayN(sizeof(ID *), num_ids, "animviz IDS");
+ int current_id_index = 0;
+ for (MPathTarget *mpt = targets->first; mpt != NULL; mpt = mpt->next) {
+ ids[current_id_index++] = &mpt->ob->id;
+ }
+
+ /* Build graph from all requested IDs. */
+ DEG_graph_build_from_ids(depsgraph, bmain, scene, view_layer, ids, num_ids);
+ MEM_freeN(ids);
+
+ /* Update once so we can access pointers of evaluated animation data. */
+ motionpaths_calc_update_scene(bmain, depsgraph);
+ return depsgraph;
+}
+
/* get list of motion paths to be baked for the given object
* - assumes the given list is ready to be used
*/
@@ -106,24 +138,6 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
/* ........ */
-/* update scene for current frame */
-static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph)
-{
- /* Do all updates
- * - if this is too slow, resort to using a more efficient way
- * that doesn't force complete update, but for now, this is the
- * most accurate way!
- *
- * TODO(segey): Bring back partial updates, which became impossible
- * with the new depsgraph due to unsorted nature of bases.
- *
- * TODO(sergey): Use evaluation context dedicated to motion paths.
- */
- BKE_scene_graph_update_for_newframe(depsgraph, bmain);
-}
-
-/* ........ */
-
/* perform baking for the targets on the current frame */
static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
{
@@ -201,6 +215,135 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
}
}
+/* Get pointer to animviz settings for the given target. */
+static bAnimVizSettings *animviz_target_settings_get(MPathTarget *mpt)
+{
+ if (mpt->pchan != NULL) {
+ return &mpt->ob->pose->avs;
+ }
+ return &mpt->ob->avs;
+}
+
+static void motionpath_get_global_framerange(ListBase *targets, int *r_sfra, int *r_efra)
+{
+ *r_sfra = INT_MAX;
+ *r_efra = INT_MIN;
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ *r_sfra = min_ii(*r_sfra, mpt->mpath->start_frame);
+ *r_efra = max_ii(*r_efra, mpt->mpath->end_frame);
+ }
+}
+
+static int motionpath_get_prev_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame)
+{
+ /* If the current frame is outside of the configured motion path range we ignore update of this
+ * motion path by using invalid frame range where start frame is above the end frame. */
+ if (current_frame <= mpt->mpath->start_frame) {
+ return INT_MAX;
+ }
+
+ float current_frame_float = current_frame;
+ DLRBT_Node *node = BLI_dlrbTree_search_prev(fcu_keys, compare_ak_cfraPtr, &current_frame_float);
+ if (node == NULL) {
+ return mpt->mpath->start_frame;
+ }
+
+ ActKeyColumn *key_data = (ActKeyColumn *)node;
+ return key_data->cfra;
+}
+
+static int motionpath_get_prev_prev_keyframe(MPathTarget *mpt,
+ DLRBT_Tree *fcu_keys,
+ int current_frame)
+{
+ int frame = motionpath_get_prev_keyframe(mpt, fcu_keys, current_frame);
+ return motionpath_get_prev_keyframe(mpt, fcu_keys, frame);
+}
+
+static int motionpath_get_next_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame)
+{
+ /* If the current frame is outside of the configured motion path range we ignore update of this
+ * motion path by using invalid frame range where start frame is above the end frame. */
+ if (current_frame >= mpt->mpath->end_frame) {
+ return INT_MIN;
+ }
+
+ float current_frame_float = current_frame;
+ DLRBT_Node *node = BLI_dlrbTree_search_next(fcu_keys, compare_ak_cfraPtr, &current_frame_float);
+ if (node == NULL) {
+ return mpt->mpath->end_frame;
+ }
+
+ ActKeyColumn *key_data = (ActKeyColumn *)node;
+ return key_data->cfra;
+}
+
+static int motionpath_get_next_next_keyframe(MPathTarget *mpt,
+ DLRBT_Tree *fcu_keys,
+ int current_frame)
+{
+ int frame = motionpath_get_next_keyframe(mpt, fcu_keys, current_frame);
+ return motionpath_get_next_keyframe(mpt, fcu_keys, frame);
+}
+
+static bool motionpath_check_can_use_keyframe_range(MPathTarget *UNUSED(mpt),
+ AnimData *adt,
+ ListBase *fcurve_list)
+{
+ if (adt == NULL || fcurve_list == NULL) {
+ return false;
+ }
+ /* NOTE: We might needed to do a full frame range update if there is a specific setup of NLA
+ * or drivers or modifiers on the f-curves. */
+ return true;
+}
+
+static void motionpath_calculate_update_range(MPathTarget *mpt,
+ AnimData *adt,
+ ListBase *fcurve_list,
+ int current_frame,
+ int *r_sfra,
+ int *r_efra)
+{
+ /* Similar to the case when there is only a single keyframe: need to update en entire range to
+ * a constant value. */
+ if (!motionpath_check_can_use_keyframe_range(mpt, adt, fcurve_list)) {
+ *r_sfra = mpt->mpath->start_frame;
+ *r_efra = mpt->mpath->end_frame;
+ return;
+ }
+
+ *r_sfra = INT_MAX;
+ *r_efra = INT_MIN;
+
+ /* NOTE: Iterate over individual f-curves, and check their keyframes individually and pick a
+ * widest range from them. This is because it's possible to have more narrow keyframe on a
+ * channel which wasn't edited.
+ * Could be optimized further by storing some flags about which channels has been modified so
+ * we ignore all others (which can potentially make an update range unnecessary wide). */
+ for (FCurve *fcu = fcurve_list->first; fcu != NULL; fcu = fcu->next) {
+ DLRBT_Tree fcu_keys;
+ BLI_dlrbTree_init(&fcu_keys);
+ fcurve_to_keylist(adt, fcu, &fcu_keys, 0);
+
+ int fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, current_frame);
+ int fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, current_frame);
+
+ /* Extend range furher, since accelleration compensation propagates even further away. */
+ if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) {
+ fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, fcu_sfra);
+ fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, fcu_efra);
+ }
+
+ if (fcu_sfra <= fcu_efra) {
+ *r_sfra = min_ii(*r_sfra, fcu_sfra);
+ *r_efra = max_ii(*r_efra, fcu_efra);
+ }
+
+ BLI_dlrbTree_free(&fcu_keys);
+ }
+}
+
/* Perform baking of the given object's and/or its bones' transforms to motion paths
* - scene: current scene
* - ob: object whose flagged motionpaths should get calculated
@@ -211,39 +354,36 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
ListBase *targets,
- bool restore,
- bool current_frame_only)
+ eAnimvizCalcRange range,
+ bool restore)
{
- /* sanity check */
+ /* Sanity check. */
if (ELEM(NULL, targets, targets->first)) {
return;
}
- /* Compute frame range to bake within.
- * TODO: this method could be improved...
- * 1) max range for standard baking
- * 2) minimum range for recalc baking (i.e. between keyframes, but how?) */
- int sfra = INT_MAX;
- int efra = INT_MIN;
-
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
- /* try to increase area to do (only as much as needed) */
- sfra = MIN2(sfra, mpt->mpath->start_frame);
- efra = MAX2(efra, mpt->mpath->end_frame);
- }
-
- if (efra <= sfra) {
- return;
- }
-
- /* Limit frame range if we are updating just the current frame. */
- /* set frame values */
- int cfra = CFRA;
- if (current_frame_only) {
- if (cfra < sfra || cfra > efra) {
- return;
- }
- sfra = efra = cfra;
+ const int cfra = CFRA;
+ int sfra = INT_MAX, efra = INT_MIN;
+ switch (range) {
+ case ANIMVIZ_CALC_RANGE_CURRENT_FRAME:
+ motionpath_get_global_framerange(targets, &sfra, &efra);
+ if (sfra > efra) {
+ return;
+ }
+ if (cfra < sfra || cfra > efra) {
+ return;
+ }
+ sfra = efra = cfra;
+ break;
+ case ANIMVIZ_CALC_RANGE_CHANGED:
+ /* Nothing to do here, will be handled later when iterating through the targets. */
+ break;
+ case ANIMVIZ_CALC_RANGE_FULL:
+ motionpath_get_global_framerange(targets, &sfra, &efra);
+ if (sfra > efra) {
+ return;
+ }
+ break;
}
/* get copies of objects/bones to get the calculated results from
@@ -271,16 +411,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
/* build list of all keyframes in active action for object or pchan */
BLI_dlrbTree_init(&mpt->keys);
+ ListBase *fcurve_list = NULL;
if (adt) {
- bAnimVizSettings *avs;
-
/* get pointer to animviz settings for each target */
- if (mpt->pchan) {
- avs = &mpt->ob->pose->avs;
- }
- else {
- avs = &mpt->ob->avs;
- }
+ bAnimVizSettings *avs = animviz_target_settings_get(mpt);
/* it is assumed that keyframes for bones are all grouped in a single group
* unless an option is set to always use the whole action
@@ -289,13 +423,28 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
if (agrp) {
+ fcurve_list = &agrp->channels;
agroup_to_keylist(adt, agrp, &mpt->keys, 0);
}
}
else {
+ fcurve_list = &adt->action->curves;
action_to_keylist(adt, adt->action, &mpt->keys, 0);
}
}
+
+ if (range == ANIMVIZ_CALC_RANGE_CHANGED) {
+ int mpt_sfra, mpt_efra;
+ motionpath_calculate_update_range(mpt, adt, fcurve_list, cfra, &mpt_sfra, &mpt_efra);
+ if (mpt_sfra <= mpt_efra) {
+ sfra = min_ii(sfra, mpt_sfra);
+ efra = max_ii(efra, mpt_efra);
+ }
+ }
+ }
+
+ if (sfra > efra) {
+ return;
}
/* calculate path over requested range */
@@ -306,7 +455,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
efra,
efra - sfra + 1);
for (CFRA = sfra; CFRA <= efra; CFRA++) {
- if (current_frame_only) {
+ if (range == ANIMVIZ_CALC_RANGE_CURRENT_FRAME) {
/* For current frame, only update tagged. */
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
@@ -324,7 +473,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
* may be a temporary one that works on a subset of the data.
* We always have to restore the current frame though. */
CFRA = cfra;
- if (!current_frame_only && restore) {
+ if (range != ANIMVIZ_CALC_RANGE_CURRENT_FRAME && restore) {
motionpaths_calc_update_scene(bmain, depsgraph);
}
@@ -334,16 +483,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
/* clear recalc flags from targets */
for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
- bAnimVizSettings *avs;
bMotionPath *mpath = mpt->mpath;
/* get pointer to animviz settings for each target */
- if (mpt->pchan) {
- avs = &mpt->ob->pose->avs;
- }
- else {
- avs = &mpt->ob->avs;
- }
+ bAnimVizSettings *avs = animviz_target_settings_get(mpt);
/* clear the flag requesting recalculation of targets */
avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 7b9e6a10f44..64f7fe034dc 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -62,13 +62,11 @@
/* Get (or add relevant data to be able to do so) F-Curve from the driver stack,
* for the given Animation Data block. This assumes that all the destinations are valid.
- *
- * - add: 0 - don't add anything if not found,
- * 1 - add new Driver FCurve (with keyframes for visual tweaking),
- * 2 - add new Driver FCurve (with generator, for script backwards compatibility)
- * -1 - add new Driver FCurve without driver stuff (for pasting)
*/
-FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add)
+FCurve *verify_driver_fcurve(ID *id,
+ const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode)
{
AnimData *adt;
FCurve *fcu;
@@ -80,7 +78,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
- if ((adt == NULL) && (add)) {
+ if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
adt = BKE_animdata_add_id(id);
}
if (adt == NULL) {
@@ -94,9 +92,9 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
*/
fcu = list_find_fcurve(&adt->drivers, rna_path, array_index);
- if ((fcu == NULL) && (add)) {
+ if (fcu == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
/* use default settings to make a F-Curve */
- fcu = alloc_driver_fcurve(rna_path, array_index, add);
+ fcu = alloc_driver_fcurve(rna_path, array_index, creation_mode);
/* just add F-Curve to end of driver list */
BLI_addtail(&adt->drivers, fcu);
@@ -106,12 +104,14 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
return fcu;
}
-struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add)
+struct FCurve *alloc_driver_fcurve(const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode)
{
FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve");
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ fcu->auto_smoothing = U.auto_smoothing_new;
/* store path - make copy, and store that */
if (rna_path) {
@@ -119,18 +119,12 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index,
}
fcu->array_index = array_index;
- /* If add is negative, don't init this data yet,
- * since it will be filled in by the pasted driver. */
- if (add > 0) {
- BezTriple *bezt;
- size_t i;
-
+ if (!ELEM(creation_mode, DRIVER_FCURVE_LOOKUP_ONLY, DRIVER_FCURVE_EMPTY)) {
/* add some new driver data */
fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
/* F-Modifier or Keyframes? */
- // FIXME: replace these magic numbers with defines
- if (add == 2) {
+ if (creation_mode == DRIVER_FCURVE_GENERATOR) {
/* Python API Backwards compatibility hack:
* Create FModifier so that old scripts won't break
* for now before 2.7 series -- (September 4, 2013)
@@ -142,14 +136,10 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index,
* - These are configured to 0,0 and 1,1 to give a 1-1 mapping
* which can be easily tweaked from there.
*/
- insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
- insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
-
- /* configure this curve to extrapolate */
- for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) {
- bezt->h1 = bezt->h2 = HD_VECT;
- }
-
+ insert_vert_fcurve(
+ fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
+ insert_vert_fcurve(
+ fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
calchandles_fcurve(fcu);
}
@@ -177,7 +167,8 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
int driver_type)
{
FCurve *fcu;
- short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1;
+ short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? DRIVER_FCURVE_GENERATOR :
+ DRIVER_FCURVE_KEYFRAMES;
const char *prop_name = RNA_property_identifier(src_prop);
/* Create F-Curve with Driver */
@@ -593,7 +584,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
* Note: here is one of the places where we don't want new F-Curve + Driver added!
* so 'add' var must be 0
*/
- fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
if (fcu) {
BLI_remlink(&adt->drivers, fcu);
free_fcurve(fcu);
@@ -653,7 +644,7 @@ bool ANIM_copy_driver(
}
/* try to get F-Curve with Driver */
- fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
/* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
ANIM_drivers_copybuf_free();
@@ -711,7 +702,7 @@ bool ANIM_paste_driver(
}
/* create Driver F-Curve, but without data which will be copied across... */
- fcu = verify_driver_fcurve(id, rna_path, array_index, -1);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_EMPTY);
if (fcu) {
/* copy across the curve data from the buffer curve
@@ -855,7 +846,7 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch
ANIM_driver_vars_copybuf_free();
/* Create a dummy driver F-Curve. */
- FCurve *fcu = alloc_driver_fcurve(NULL, 0, 1);
+ FCurve *fcu = alloc_driver_fcurve(NULL, 0, DRIVER_FCURVE_KEYFRAMES);
ChannelDriver *driver = fcu->driver;
/* Create a variable. */
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index c174ce83bea..479e7192b0e 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -545,8 +545,7 @@ int actkeyblock_get_valid_hold(ActKeyColumn *ac)
return 0;
}
- const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD |
- ACTKEYBLOCK_FLAG_ANY_HOLD);
+ const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD);
return (ac->block.flag & ~ac->block.conflict) & hold_mask;
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 0f8b8742659..8203a9131fa 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -202,7 +202,7 @@ FCurve *verify_fcurve(Main *bmain,
fcu = MEM_callocN(sizeof(FCurve), "FCurve");
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ fcu->auto_smoothing = U.auto_smoothing_new;
if (BLI_listbase_is_empty(&act->curves)) {
fcu->flag |= FCURVE_ACTIVE; /* first one added active */
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index eff621d7b71..c37f9ce126b 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -251,12 +251,13 @@ void *get_bone_from_selectbuffer(Base **bases,
/* x and y are mouse coords (area space) */
void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
unsigned int buffer[MAXPICKBUF];
short hits;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
// rect.xmin = ... mouseco!
rect.xmin = rect.xmax = xy[0];
@@ -648,8 +649,9 @@ bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint ba
bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -674,12 +676,13 @@ static int ebone_select_flag(EditBone *ebone)
bool ED_armature_edit_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
EditBone *nearBone = NULL;
int selmask;
Base *basact = NULL;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 8f4896c0b82..ad115896a43 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -182,12 +182,25 @@ static bool pose_has_protected_selected(Object *ob, short warn)
/* ********************************************** */
/* Motion Paths */
+static eAnimvizCalcRange pose_path_convert_range(ePosePathCalcRange range)
+{
+ switch (range) {
+ case POSE_PATH_CALC_RANGE_CURRENT_FRAME:
+ return ANIMVIZ_CALC_RANGE_CURRENT_FRAME;
+ case POSE_PATH_CALC_RANGE_CHANGED:
+ return ANIMVIZ_CALC_RANGE_CHANGED;
+ case POSE_PATH_CALC_RANGE_FULL:
+ return ANIMVIZ_CALC_RANGE_FULL;
+ }
+ return ANIMVIZ_CALC_RANGE_FULL;
+}
+
/* For the object with pose/action: update paths for those that have got them
* This should selectively update paths that exist...
*
* To be called from various tools that do incremental updates
*/
-void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool current_frame_only)
+void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, ePosePathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
if (C == NULL) {
@@ -195,12 +208,12 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
}
Main *bmain = CTX_data_main(C);
- /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
- * nested pointers, like animation data. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ListBase targets = {NULL, NULL};
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ Depsgraph *depsgraph;
bool free_depsgraph = false;
+ ListBase targets = {NULL, NULL};
/* set flag to force recalc, then grab the relevant bones to target */
ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
animviz_get_object_motionpaths(ob, &targets);
@@ -210,7 +223,21 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
TIMEIT_START(pose_path_calc);
#endif
- animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, !free_depsgraph, current_frame_only);
+ /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead
+ * of building all the relations and so on for a temporary one. */
+ if (range == POSE_PATH_CALC_RANGE_CURRENT_FRAME) {
+ /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
+ * nested pointers, like animation data. */
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ free_depsgraph = false;
+ }
+ else {
+ depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets);
+ free_depsgraph = true;
+ }
+
+ animviz_calc_motionpaths(
+ depsgraph, bmain, scene, &targets, pose_path_convert_range(range), !free_depsgraph);
#ifdef DEBUG_TIME
TIMEIT_END(pose_path_calc);
@@ -218,13 +245,13 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
BLI_freelistN(&targets);
- if (!current_frame_only) {
+ if (range != POSE_PATH_CALC_RANGE_CURRENT_FRAME) {
/* Tag armature object for copy on write - so paths will draw/redraw.
* For currently frame only we update evaluated object directly. */
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
- /* Free temporary depsgraph instance */
+ /* Free temporary depsgraph. */
if (free_depsgraph) {
DEG_graph_free(depsgraph);
}
@@ -293,7 +320,7 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
#ifdef DEBUG_TIME
TIMEIT_END(recalc_pose_paths);
@@ -371,7 +398,7 @@ static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index a59067e60c1..c3a7d45f598 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -368,8 +368,9 @@ bool ED_pose_deselect_all_multi_ex(Base **bases,
bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer,
vc.v3d,
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 6274eb549da..7ed41b5b4d0 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -368,30 +368,14 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo
switch (pso->mode) {
case POSESLIDE_PUSH: /* make the current pose more pronounced */
{
- /* perform a weighted average here, favoring the middle pose
- * - numerator should be larger than denominator to 'expand' the result
- * - perform this weighting a number of times given by the percentage...
- */
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- while (iters-- > 0) {
- (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f)) / 5.0f;
- }
+ /* Slide the pose away from the breakdown pose in the timeline */
+ (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage;
break;
}
case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
{
- /* perform a weighted average here, favoring the middle pose
- * - numerator should be smaller than denominator to 'relax' the result
- * - perform this weighting a number of times given by the percentage...
- */
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- while (iters-- > 0) {
- (*val) = (((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f)) / 6.0f;
- }
+ /* Slide the pose towards the breakdown pose in the timeline */
+ (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage;
break;
}
case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
@@ -1003,7 +987,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
pose_slide_refresh(C, pso);
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* header print */
pose_slide_draw_status(pso);
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 52a3f7711c4..55c9b661074 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -543,16 +543,14 @@ static void set_pose_keys(Object *ob)
* \param chan: Bone that pose to paste comes from
* \param selOnly: Only paste on selected bones
* \param flip: Flip on x-axis
- * \return Whether the bone that we pasted to if we succeeded
+ * \return The channel of the bone that was pasted to, or NULL if no paste was performed.
*/
static bPoseChannel *pose_bone_do_paste(Object *ob,
bPoseChannel *chan,
const bool selOnly,
const bool flip)
{
- bPoseChannel *pchan;
char name[MAXBONENAME];
- short paste_ok;
/* get the name - if flipping, we must flip this first */
if (flip) {
@@ -567,131 +565,126 @@ static bPoseChannel *pose_bone_do_paste(Object *ob,
* 2) if selection-masking is on, channel is selected -
* only selected bones get pasted on, allowing making both sides symmetrical.
*/
- pchan = BKE_pose_channel_find_name(ob->pose, name);
-
- if (selOnly) {
- paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, name);
+ if (pchan == NULL) {
+ return NULL;
}
- else {
- paste_ok = (pchan != NULL);
+ if (selOnly && (pchan->bone->flag & BONE_SELECTED) == 0) {
+ return NULL;
}
- /* continue? */
- if (paste_ok) {
- /* only loc rot size
- * - only copies transform info for the pose
- */
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- pchan->flag = chan->flag;
-
- /* check if rotation modes are compatible (i.e. do they need any conversions) */
- if (pchan->rotmode == chan->rotmode) {
- /* copy the type of rotation in use */
- if (pchan->rotmode > 0) {
- copy_v3_v3(pchan->eul, chan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- }
- else {
- copy_qt_qt(pchan->quat, chan->quat);
- }
- }
- else if (pchan->rotmode > 0) {
- /* quat/axis-angle to euler */
- if (chan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
- }
- else {
- quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
- }
+ /* only loc rot size
+ * - only copies transform info for the pose
+ */
+ copy_v3_v3(pchan->loc, chan->loc);
+ copy_v3_v3(pchan->size, chan->size);
+ pchan->flag = chan->flag;
+
+ /* check if rotation modes are compatible (i.e. do they need any conversions) */
+ if (pchan->rotmode == chan->rotmode) {
+ /* copy the type of rotation in use */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pchan->eul, chan->eul);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* quat/euler to axis angle */
- if (chan->rotmode > 0) {
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
- }
- else {
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
- }
+ copy_v3_v3(pchan->rotAxis, chan->rotAxis);
+ pchan->rotAngle = chan->rotAngle;
}
else {
- /* euler/axis-angle to quat */
- if (chan->rotmode > 0) {
- eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
- }
- else {
- axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
- }
+ copy_qt_qt(pchan->quat, chan->quat);
+ }
+ }
+ else if (pchan->rotmode > 0) {
+ /* quat/axis-angle to euler */
+ if (chan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
+ }
+ else {
+ quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
+ }
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* quat/euler to axis angle */
+ if (chan->rotmode > 0) {
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
+ }
+ else {
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
+ }
+ }
+ else {
+ /* euler/axis-angle to quat */
+ if (chan->rotmode > 0) {
+ eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
}
+ else {
+ axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
+ }
+ }
- /* B-Bone posing options should also be included... */
- pchan->curve_in_x = chan->curve_in_x;
- pchan->curve_in_y = chan->curve_in_y;
- pchan->curve_out_x = chan->curve_out_x;
- pchan->curve_out_y = chan->curve_out_y;
-
- pchan->roll1 = chan->roll1;
- pchan->roll2 = chan->roll2;
- pchan->ease1 = chan->ease1;
- pchan->ease2 = chan->ease2;
- pchan->scale_in_x = chan->scale_in_x;
- pchan->scale_in_y = chan->scale_in_y;
- pchan->scale_out_x = chan->scale_out_x;
- pchan->scale_out_y = chan->scale_out_y;
-
- /* paste flipped pose? */
- if (flip) {
- pchan->loc[0] *= -1;
-
- pchan->curve_in_x *= -1;
- pchan->curve_out_x *= -1;
- pchan->roll1 *= -1; // XXX?
- pchan->roll2 *= -1; // XXX?
-
- /* has to be done as eulers... */
- if (pchan->rotmode > 0) {
- pchan->eul[1] *= -1;
- pchan->eul[2] *= -1;
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float eul[3];
+ /* B-Bone posing options should also be included... */
+ pchan->curve_in_x = chan->curve_in_x;
+ pchan->curve_in_y = chan->curve_in_y;
+ pchan->curve_out_x = chan->curve_out_x;
+ pchan->curve_out_y = chan->curve_out_y;
+
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->ease1 = chan->ease1;
+ pchan->ease2 = chan->ease2;
+ pchan->scale_in_x = chan->scale_in_x;
+ pchan->scale_in_y = chan->scale_in_y;
+ pchan->scale_out_x = chan->scale_out_x;
+ pchan->scale_out_y = chan->scale_out_y;
+
+ /* paste flipped pose? */
+ if (flip) {
+ pchan->loc[0] *= -1;
- axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- eul[1] *= -1;
- eul[2] *= -1;
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- float eul[3];
+ pchan->curve_in_x *= -1;
+ pchan->curve_out_x *= -1;
+ pchan->roll1 *= -1; // XXX?
+ pchan->roll2 *= -1; // XXX?
- normalize_qt(pchan->quat);
- quat_to_eul(eul, pchan->quat);
- eul[1] *= -1;
- eul[2] *= -1;
- eul_to_quat(pchan->quat, eul);
- }
+ /* has to be done as eulers... */
+ if (pchan->rotmode > 0) {
+ pchan->eul[1] *= -1;
+ pchan->eul[2] *= -1;
}
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float eul[3];
- /* ID properties */
- if (chan->prop) {
- if (pchan->prop) {
- /* if we have existing properties on a bone, just copy over the values of
- * matching properties (i.e. ones which will have some impact) on to the
- * target instead of just blinding replacing all [
- */
- IDP_SyncGroupValues(pchan->prop, chan->prop);
- }
- else {
- /* no existing properties, so assume that we want copies too? */
- pchan->prop = IDP_CopyProperty(chan->prop);
- }
+ axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ float eul[3];
+
+ normalize_qt(pchan->quat);
+ quat_to_eul(eul, pchan->quat);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eul_to_quat(pchan->quat, eul);
+ }
+ }
+
+ /* ID properties */
+ if (chan->prop) {
+ if (pchan->prop) {
+ /* if we have existing properties on a bone, just copy over the values of
+ * matching properties (i.e. ones which will have some impact) on to the
+ * target instead of just blinding replacing all [
+ */
+ IDP_SyncGroupValues(pchan->prop, chan->prop);
+ }
+ else {
+ /* no existing properties, so assume that we want copies too? */
+ pchan->prop = IDP_CopyProperty(chan->prop);
}
}
- /* return whether paste went ahead */
return pchan;
}
@@ -831,7 +824,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
/* Recalculate paths if any of the bones have paths... */
if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
}
/* Notifiers for updates, */
@@ -1112,7 +1105,7 @@ static int pose_clear_transform_generic_exec(bContext *C,
/* now recalculate paths */
if ((ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob_iter, false);
+ ED_pose_recalculate_paths(C, scene, ob_iter, POSE_PATH_CALC_RANGE_FULL);
}
BLI_freelistN(&dsources);
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index fbaf2c896d0..8d2d7d790d2 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -32,6 +32,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
@@ -223,6 +224,11 @@ void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob)
{
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ AnimData *adt = BKE_animdata_from_id(&ob->id);
+ if (adt && adt->action) {
+ DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
+ }
}
/* reset changes made to current pose */
@@ -327,7 +333,8 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
if (ob->id.tag & LIB_TAG_DOIT) {
if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
// ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
- ED_pose_recalculate_paths(C, scene, ob, false);
+ /* TODO(sergey): Should ensure we can use more narrow update range here. */
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
}
}
}
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 3d2ac009072..81c9c759188 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -33,10 +33,7 @@
#include "WM_types.h"
#include "ED_curve.h"
-#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
-#include "ED_transform.h"
#include "curve_intern.h"
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 7e878d0f905..994d844287c 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -56,13 +56,11 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_keyframes_edit.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "ED_types.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "ED_curve.h"
@@ -4876,6 +4874,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
bool ED_curve_editnurb_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu;
BezTriple *bezt = NULL;
@@ -4884,7 +4883,7 @@ bool ED_curve_editnurb_select_pick(
short hand;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, mval);
if (ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact)) {
@@ -5635,9 +5634,10 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.rv3d && !RNA_struct_property_is_set(op->ptr, "location")) {
Curve *cu;
@@ -7136,7 +7136,6 @@ static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op))
copy_v3_v3(curve->loc, loc);
copy_v3_v3(curve->size, size);
- zero_v3(curve->rot);
curve->texflag &= ~CU_AUTOSPACE;
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 4912ae5451d..d97223de9b8 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -44,7 +44,6 @@
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_undo.h"
#include "ED_view3d.h"
#include "ED_curve.h"
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index c7c19aa2d02..4c4bac6a249 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -31,7 +31,6 @@
#include "BKE_curve.h"
#include "BKE_fcurve.h"
#include "BKE_report.h"
-#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -575,9 +574,10 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
BLI_assert(op->customdata == NULL);
struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
if (is_invoke) {
- ED_view3d_viewcontext_init(C, &cdd->vc);
+ ED_view3d_viewcontext_init(C, &cdd->vc, depsgraph);
if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
MEM_freeN(cdd);
BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport");
@@ -586,7 +586,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
}
else {
cdd->vc.bmain = CTX_data_main(C);
- cdd->vc.depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ cdd->vc.depsgraph = depsgraph;
cdd->vc.scene = CTX_data_scene(C);
cdd->vc.view_layer = CTX_data_view_layer(C);
cdd->vc.obedit = CTX_data_edit_object(C);
@@ -1064,7 +1064,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
cdd->draw_handle_view = ED_region_draw_cb_activate(
cdd->vc.ar->type, curve_draw_stroke_3d, op, REGION_DRAW_POST_VIEW);
- WM_cursor_modal_set(cdd->vc.win, BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(cdd->vc.win, WM_CURSOR_PAINT_BRUSH);
{
View3D *v3d = cdd->vc.v3d;
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index d0abcf32107..9df79a082e1 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -37,7 +37,6 @@
#include "BKE_fcurve.h"
#include "BKE_layer.h"
#include "BKE_report.h"
-#include "BKE_object.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -278,8 +277,9 @@ bool ED_curve_deselect_all_multi_ex(Base **bases, int bases_len)
bool ED_curve_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -684,6 +684,7 @@ void CURVE_OT_select_linked(wmOperatorType *ot)
static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu;
BezTriple *bezt;
@@ -693,7 +694,7 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent
Base *basact = NULL;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, event->mval);
if (!ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, NULL, &basact)) {
@@ -1960,6 +1961,7 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst
static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu_dst;
BezTriple *bezt_dst;
@@ -1969,7 +1971,7 @@ static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
Base *basact = NULL;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, event->mval);
if (!ED_curve_pick_vert(&vc, 1, &nu_dst, &bezt_dst, &bp_dst, NULL, &basact)) {
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 835abd1a630..f21b4f06246 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -40,9 +40,7 @@
#include "DEG_depsgraph.h"
-#include "ED_object.h"
#include "ED_undo.h"
-#include "ED_util.h"
#include "ED_curve.h"
#include "WM_types.h"
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 781eb2634fb..e11807d818f 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -60,7 +60,6 @@
#include "ED_curve.h"
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "UI_interface.h"
@@ -1877,6 +1876,7 @@ void ED_curve_editfont_make(Object *obedit)
memcpy(ef->textbufinfo, cu->strinfo, ef->len * sizeof(CharInfo));
+ ef->pos = cu->pos;
if (ef->pos > ef->len) {
ef->pos = ef->len;
}
@@ -1884,7 +1884,6 @@ void ED_curve_editfont_make(Object *obedit)
cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
/* Other vars */
- ef->pos = cu->pos;
ef->selstart = cu->selstart;
ef->selend = cu->selend;
@@ -2201,6 +2200,7 @@ void FONT_OT_unlink(wmOperatorType *ot)
bool ED_curve_editfont_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
ViewContext vc;
@@ -2212,7 +2212,7 @@ bool ED_curve_editfont_select_pick(
const float dist = ED_view3d_select_dist_px();
float dist_sq_best = dist * dist;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 2f8f15bc6c7..ae858ec4c24 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -29,7 +29,6 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BKE_context.h"
#include "BKE_font.h"
@@ -39,7 +38,6 @@
#include "ED_object.h"
#include "ED_curve.h"
-#include "ED_util.h"
#include "WM_types.h"
#include "WM_api.h"
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 765362b374e..8a3a078bdd2 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -645,6 +645,8 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.clay_strips
brush.sculpt.crease
brush.sculpt.draw
+ brush.sculpt.draw_sharp
+ brush.sculpt.elastic_deform
brush.sculpt.fill
brush.sculpt.flatten
brush.sculpt.grab
@@ -653,6 +655,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.mask
brush.sculpt.nudge
brush.sculpt.pinch
+ brush.sculpt.pose
brush.sculpt.rotate
brush.sculpt.scrape
brush.sculpt.simplify
@@ -736,6 +739,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.sculpt.border_hide
ops.sculpt.border_mask
ops.sculpt.lasso_mask
+ ops.sculpt.mesh_filter
ops.transform.bone_envelope
ops.transform.bone_size
ops.transform.edge_slide
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 1a132c2957a..ecbc503e084 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -258,9 +258,9 @@ static int gizmo_button2d_test_select(bContext *C, wmGizmo *gz, const int mval[2
static int gizmo_button2d_cursor_get(wmGizmo *gz)
{
if (RNA_boolean_get(gz->ptr, "show_drag")) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
static void gizmo_button2d_free(wmGizmo *gz)
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index ba3b8c2602e..ef4fd23b64d 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -752,30 +752,30 @@ static int gizmo_cage2d_get_cursor(wmGizmo *gz)
int highlight_part = gz->highlight_part;
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
switch (highlight_part) {
case ED_GIZMO_CAGE2D_PART_TRANSLATE:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X:
- return CURSOR_X_MOVE;
+ return WM_CURSOR_X_MOVE;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y:
- return CURSOR_Y_MOVE;
+ return WM_CURSOR_Y_MOVE;
/* TODO diagonal cursor */
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_ROTATE:
- return BC_CROSSCURSOR;
+ return WM_CURSOR_CROSS;
default:
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
index 406f76bc65e..723be3cfe6b 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -424,10 +424,10 @@ static void gizmo_cage3d_draw(const bContext *C, wmGizmo *gz)
static int gizmo_cage3d_get_cursor(wmGizmo *gz)
{
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
typedef struct RectTransformInteraction {
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 37ee95d5058..5342f8695b2 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -412,7 +412,7 @@ static void gizmo_move_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
static int gizmo_move_cursor_get(wmGizmo *UNUSED(gz))
{
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 22f1753a810..7a10547f35c 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1560,10 +1560,10 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_draw_cursor_set(tGPsdata *p)
{
if (p->paintmode == GP_PAINTMODE_ERASER) {
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ WM_cursor_modal_set(p->win, WM_CURSOR_ERASER);
}
else {
- WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(p->win, WM_CURSOR_PAINT_BRUSH);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 2a2e7c21df4..af9cadfb938 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -52,6 +52,7 @@
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_material.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
@@ -109,6 +110,7 @@ typedef struct tGP_BrushEditData {
/* Is the brush currently painting? */
bool is_painting;
bool is_weight_mode;
+ bool is_transformed;
/* Start of new sculpt stroke */
bool first;
@@ -532,7 +534,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
// XXX: screen-space strokes in 3D space will suffer!
if (gso->sa->spacetype == SPACE_VIEW3D) {
RegionView3D *rv3d = gso->ar->regiondata;
- float *rvec = gso->scene->cursor.location;
+ float *rvec = gso->object->loc;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
float mval_f[2];
@@ -657,7 +659,7 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
* See: gpencil_paint.c :: gp_stroke_convertcoords()
*/
RegionView3D *rv3d = gso->ar->regiondata;
- const float *rvec = gso->scene->cursor.location;
+ const float *rvec = gso->object->loc;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
float mval_f[2];
@@ -1326,9 +1328,12 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
gso->vrgroup = -1;
}
+ /* Check if some modifier can transform the stroke. */
+ gso->is_transformed = BKE_gpencil_has_transform_modifiers(ob);
}
else {
gso->vrgroup = -1;
+ gso->is_transformed = false;
}
gso->sa = CTX_wm_area(C);
@@ -1397,7 +1402,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gpsculpt_brush_header_set(C, gso);
/* setup cursor drawing */
- // WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ // WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_CROSS);
if (gso->sa->spacetype != SPACE_VIEW3D) {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
}
@@ -1463,7 +1468,7 @@ static bool gpsculpt_brush_poll(bContext *C)
/* Init Sculpt Stroke ---------------------------------- */
-static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
+static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso)
{
bGPdata *gpd = gso->gpd;
@@ -1487,9 +1492,11 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
* spent too much time editing the wrong frame.
*/
- // XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
BKE_gpencil_frame_addcopy(gpl, cfra);
+ /* Need tag to recalculate evaluated data to avoid crashes. */
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
}
}
@@ -1504,12 +1511,17 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
* For strokes with one point only this is impossible to calculate because there isn't a
* valid reference point.
*/
-static float gpsculpt_rotation_eval_get(GP_SpaceConversion *gsc,
+static float gpsculpt_rotation_eval_get(tGP_BrushEditData *gso,
bGPDstroke *gps_eval,
bGPDspoint *pt_eval,
int idx_eval)
{
+ /* If multiframe or no modifiers, return 0. */
+ if ((GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd)) || (!gso->is_transformed)) {
+ return 0.0f;
+ }
+ GP_SpaceConversion *gsc = &gso->gsc;
bGPDstroke *gps_orig = gps_eval->runtime.gps_orig;
bGPDspoint *pt_orig = &gps_orig->points[pt_eval->runtime.idx_orig];
bGPDspoint *pt_prev_eval = NULL;
@@ -1564,12 +1576,16 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
gso->gp_brush->size * gso->pressure :
gso->gp_brush->size;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
bGPDspoint *pt1, *pt2;
bGPDspoint *pt = NULL;
int pc1[2] = {0};
int pc2[2] = {0};
int i;
+ int index;
bool include_last = false;
bool changed = false;
float rot_eval = 0.0f;
@@ -1579,6 +1595,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
@@ -1586,9 +1603,9 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
round_v2i_v2fl(mval_i, gso->mval);
if (len_v2v2_int(mval_i, pc1) <= radius) {
/* apply operation to this point */
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, 0);
- changed = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, 0);
+ changed = apply(gso, gps_active, rot_eval, 0, radius, pc1);
}
}
}
@@ -1631,9 +1648,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
/* To each point individually... */
pt = &gps->points[i];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i);
- ok = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
+ ok = apply(gso, gps_active, rot_eval, index, radius, pc1);
}
/* Only do the second point if this is the last segment,
@@ -1646,9 +1665,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
*/
if (i + 1 == gps->totpoints - 1) {
pt = &gps->points[i + 1];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i + 1);
- ok |= apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc2);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i + 1;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1);
+ ok |= apply(gso, gps_active, rot_eval, index, radius, pc2);
include_last = false;
}
}
@@ -1665,10 +1686,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
* (but wasn't added then, to avoid double-ups).
*/
pt = &gps->points[i];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i);
- changed |= apply(
- gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
+ changed |= apply(gso, gps_active, rot_eval, index, radius, pc1);
include_last = false;
}
}
@@ -1688,6 +1710,7 @@ static bool gpsculpt_brush_do_frame(bContext *C,
{
bool changed = false;
Object *ob = CTX_data_active_object(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
@@ -1720,18 +1743,19 @@ static bool gpsculpt_brush_do_frame(bContext *C,
case GP_SCULPT_TYPE_GRAB: /* Grab points */
{
- if (gps->runtime.gps_orig != NULL) {
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ if (gps_active != NULL) {
if (gso->first) {
/* First time this brush stroke is being applied:
* 1) Prepare data buffers (init/clear) for this stroke
* 2) Use the points now under the cursor
*/
- gp_brush_grab_stroke_init(gso, gps->runtime.gps_orig);
+ gp_brush_grab_stroke_init(gso, gps_active);
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
}
else {
/* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps->runtime.gps_orig, diff_mat);
+ gp_brush_grab_apply_cached(gso, gps_active, diff_mat);
changed |= true;
}
}
@@ -1862,8 +1886,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
}
/* affect strokes in this frame */
- changed |= gpsculpt_brush_do_frame(
- C, gso, gpl, (gpf == gpl->actframe) ? gpf_eval : gpf, diff_mat);
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
}
}
}
@@ -2079,7 +2102,7 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
ARegion *ar = CTX_wm_region(C);
/* ensure that we'll have a new frame to draw on */
- gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_init_stroke(C, gso);
/* apply first dab... */
gso->is_painting = true;
@@ -2194,7 +2217,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
gso->is_painting = true;
gso->first = true;
- gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_init_stroke(C, gso);
gpsculpt_brush_apply_event(C, op, event);
break;
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index d72f61c64b1..67ffc6adc9f 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -492,51 +492,44 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
bGPdata *gpd_src = (bGPdata *)ob_src->data;
bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
- /* sanity checks */
+ /* Sanity checks. */
if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
return OPERATOR_CANCELLED;
}
- /* cannot copy itself and check destination type */
+ /* Cannot copy itself and check destination type. */
if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
return OPERATOR_CANCELLED;
}
bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
- /* make copy of layer */
- bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
- gpl_dst->prev = gpl_dst->next = NULL;
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- BLI_uniquename(&gpd_dst->layers,
- gpl_dst,
- DATA_("GP_Layer"),
- '.',
- offsetof(bGPDlayer, info),
- sizeof(gpl_dst->info));
+ /* Create new layer. */
+ bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true);
+ /* Need to copy some variables (not all). */
+ gpl_dst->onion_flag = gpl_src->onion_flag;
+ gpl_dst->thickness = gpl_src->thickness;
+ gpl_dst->line_change = gpl_src->line_change;
+ copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor);
+ gpl_dst->opacity = gpl_src->opacity;
- /* copy frames */
- BLI_listbase_clear(&gpl_dst->frames);
+ /* Create all frames. */
for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
continue;
}
- /* make a copy of source frame */
- bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
- gpf_dst->prev = gpf_dst->next = NULL;
- BLI_addtail(&gpl_dst->frames, gpf_dst);
+ /* Create new frame. */
+ bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum);
- /* copy strokes */
- BLI_listbase_clear(&gpf_dst->strokes);
+ /* Copy strokes. */
for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke */
+ /* Make copy of source stroke. */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
- /* check if material is in destination object,
- * otherwise add the slot with the material
- */
+ /* Check if material is in destination object,
+ * otherwise add the slot with the material. */
Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
if (ma_src != NULL) {
int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
@@ -545,7 +538,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
gps_dst->mat_nr = idx;
}
- /* add new stroke to frame */
+ /* Add new stroke to frame. */
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
}
@@ -568,7 +561,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
};
/* identifiers */
- ot->name = "Duplicate Layer to new Object";
+ ot->name = "Duplicate Layer to New Object";
ot->idname = "GPENCIL_OT_layer_duplicate_object";
ot->description = "Make a copy of the active Grease Pencil layer to new object";
@@ -799,7 +792,7 @@ static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Clean Loose points";
+ ot->name = "Clean Loose Points";
ot->idname = "GPENCIL_OT_frame_clean_loose";
ot->description = "Remove loose points";
@@ -1587,7 +1580,9 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
/* ******************* Brush create presets ************************** */
static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
{
- BKE_brush_gpencil_presets(C);
+ Main *bmain = CTX_data_main(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ BKE_brush_gpencil_presets(bmain, ts);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index a5e9fe9b166..91ecbed7b5b 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -237,11 +237,38 @@ static int gpencil_selectmode_toggle_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
const int mode = RNA_int_get(op->ptr, "mode");
+ bool changed = false;
+
+ if (ts->gpencil_selectmode_edit == mode) {
+ return OPERATOR_FINISHED;
+ }
/* Just set mode */
ts->gpencil_selectmode_edit = mode;
+ /* If the mode is Stroke, extend selection. */
+ if ((ob) && (ts->gpencil_selectmode_edit == GP_SELECTMODE_STROKE)) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ /* Extend selection to all points in all selected strokes. */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
+ changed = true;
+ bGPDspoint *pt;
+ for (int i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
@@ -328,7 +355,7 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
Paint *paint = &ts->gp_paint->paint;
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
}
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index ea93f861c6e..993ec15248f 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1394,7 +1394,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
}
- WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_PAINT_BRUSH);
gpencil_fill_status_indicators(C, tgpf);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 0bbabafb2b0..7ff6243b0d2 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -214,6 +214,8 @@ typedef struct tGPDprimitive {
int sel_cp;
/** flag to determine operations in progress */
int flag;
+ /** flag to determine operations previous mode */
+ int prev_flag;
/** recorded mouse-position */
float mval[2];
/** previous recorded mouse-position */
@@ -467,6 +469,7 @@ enum {
GP_STROKE_CIRCLE = 2,
GP_STROKE_ARC = 3,
GP_STROKE_CURVE = 4,
+ GP_STROKE_POLYLINE = 5,
};
enum {
@@ -672,7 +675,9 @@ struct GP_EditableStrokes_Iter {
ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* get evaluated frame with modifiers applied */ \
- bGPDframe *gpf_eval_ = &obeval_->runtime.gpencil_evaluated_frames[idx_eval]; \
+ bGPDframe *gpf_eval_ = (!is_multiedit_) ? \
+ &obeval_->runtime.gpencil_evaluated_frames[idx_eval] : \
+ gpf_; \
/* loop over strokes */ \
for (bGPDstroke *gps = gpf_eval_->strokes.first; gps; gps = gps->next) { \
/* skip strokes that are invalid for current view */ \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 86de9a75a56..1438c33a972 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -560,7 +560,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* update shift indicator in header */
gpencil_interpolate_status_indicators(C, tgpi);
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index 930911ffac5..36cef3ccdc0 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -35,6 +35,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "WM_api.h"
@@ -97,6 +98,7 @@ static void gpencil_insert_points_to_stroke(bGPDstroke *gps,
static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpoints)
{
+ Main *bmain = CTX_data_main(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
@@ -111,7 +113,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
Brush *brush = paint->brush;
diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c
index af49587f9ad..3d56cb0fcb1 100644
--- a/source/blender/editors/gpencil/gpencil_ops_versioning.c
+++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c
@@ -54,6 +54,9 @@
#include "ED_object.h"
#include "ED_gpencil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
/* Free all of a gp-colors */
@@ -111,6 +114,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
ob = BKE_object_add_for_data(
bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false);
zero_v3(ob->loc);
+ DEG_relations_tag_update(bmain); /* added object */
/* convert grease pencil palettes (version >= 2.78) to materials and weights */
for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 0a4b068a926..f29e782c618 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -598,6 +598,7 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
float sco[2] = {0.0f};
float a[2], b[2], c[2], d[2];
float pressure = 0.0f;
+ float strength = 0.0f;
const float average_fac = 1.0f / steps;
/* Compute smoothed coordinate by taking the ones nearby */
@@ -605,21 +606,25 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(a, &pta->x);
madd_v2_v2fl(sco, a, average_fac);
pressure += pta->pressure * average_fac;
+ strength += pta->strength * average_fac;
}
if (ptb) {
copy_v2_v2(b, &ptb->x);
madd_v2_v2fl(sco, b, average_fac);
pressure += ptb->pressure * average_fac;
+ strength += ptb->strength * average_fac;
}
if (ptc) {
copy_v2_v2(c, &ptc->x);
madd_v2_v2fl(sco, c, average_fac);
pressure += ptc->pressure * average_fac;
+ strength += ptc->strength * average_fac;
}
if (ptd) {
copy_v2_v2(d, &ptd->x);
madd_v2_v2fl(sco, d, average_fac);
pressure += ptd->pressure * average_fac;
+ strength += ptd->strength * average_fac;
}
/* Based on influence factor, blend between original and optimal smoothed coordinate. */
@@ -627,10 +632,156 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(&ptc->x, c);
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
+ /* Interpolate strength. */
+ ptc->strength = interpf(ptc->strength, strength, inf);
+}
+
+/* Helper: Apply smooth to segment from Index to Index */
+static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int to_idx)
+{
+ const short num_points = to_idx - from_idx;
+ /* Do nothing if not enough points to smooth out */
+ if ((num_points < 3) || (inf == 0.0f)) {
+ return;
+ }
+
+ if (from_idx <= 2) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ const float average_fac = 0.25f;
+
+ for (int i = from_idx; i < to_idx + 1; i++) {
+
+ tGPspoint *pta = i >= 3 ? &points[i - 3] : NULL;
+ tGPspoint *ptb = i >= 2 ? &points[i - 2] : NULL;
+ tGPspoint *ptc = i >= 1 ? &points[i - 1] : &points[i];
+ tGPspoint *ptd = &points[i];
+
+ float sco[2] = {0.0f};
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ if (pta) {
+ madd_v2_v2fl(sco, &pta->x, average_fac);
+ }
+ else {
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+ }
+
+ if (ptb) {
+ madd_v2_v2fl(sco, &ptb->x, average_fac);
+ }
+ else {
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+ }
+
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+
+ madd_v2_v2fl(sco, &ptd->x, average_fac);
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate. */
+ interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
+ }
+}
+
+/* Smooth all the sections created with fake events to avoid abrupt transitions.
+ *
+ * As the fake events add points between two real events, this produces a straight line, but if
+ * there is 3 or more real points that used fakes, the stroke is not smooth and produces abrupt
+ * angles.
+ * This function reads these segments and finds the real points and smooth with the surrounding
+ * points. */
+static void gp_smooth_fake_segments(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
+
+ if (brush->gpencil_settings->input_samples < 2) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ tGPspoint *pt = NULL;
+ /* Index where segment starts. */
+ int from_idx = 0;
+ /* Index where segment ends. */
+ int to_idx = 0;
+
+ bool doit = false;
+ /* Loop all points except the extremes. */
+ for (int i = 1; i < gpd->runtime.sbuffer_used - 1; i++) {
+ pt = &points[i];
+ bool is_fake = (bool)(pt->tflag & GP_TPOINT_FAKE);
+ to_idx = i;
+
+ /* Detect fake points in the stroke. */
+ if ((!doit) && (is_fake)) {
+ from_idx = i;
+ doit = true;
+ }
+ /* If detect control point after fake points, select a segment with same length in both sides,
+ * except if it is more than stroke length. */
+ if ((doit) && (!is_fake)) {
+ if (i + (i - from_idx) < gpd->runtime.sbuffer_used - 1) {
+ to_idx = i + (i - from_idx);
+ /* Smooth this segments (need loop to get cumulative smooth). */
+ for (int r = 0; r < 5; r++) {
+ gp_smooth_segment(gpd, 0.1f, from_idx, to_idx);
+ }
+ }
+ else {
+ break;
+ }
+ /* Reset to new segments. */
+ from_idx = i;
+ doit = false;
+ }
+ }
+}
+
+/* Smooth the section added with fake events when pen moves very fast. */
+static void gp_smooth_fake_events(tGPsdata *p, int size_before, int size_after)
+{
+ bGPdata *gpd = p->gpd;
+ const short totpoints = size_after - size_before - 1;
+ /* Do nothing if not enough data to smooth out. */
+ if (totpoints < 1) {
+ return;
+ }
+
+ /* Back two points to get smoother effect. */
+ size_before -= 2;
+ CLAMP_MIN(size_before, 1);
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ /* Extreme points. */
+ const tGPspoint *pta = &points[size_before - 1];
+ const tGPspoint *ptb = &points[size_after - 1];
+ tGPspoint *pt1, *pt2;
+ int i;
+
+ /* Get total length of the segment to smooth. */
+ float totlen = 0.0f;
+ for (i = size_before; i < size_after; i++) {
+ pt1 = &points[i - 1];
+ pt2 = &points[i];
+ totlen += len_v2v2(&pt1->x, &pt2->x);
+ }
+ /* Smooth interpolating the position of the points. */
+ float pointlen = 0.0f;
+ for (i = size_before; i < size_after - 1; i++) {
+ pt1 = &points[i - 1];
+ pt2 = &points[i];
+ pointlen += len_v2v2(&pt1->x, &pt2->x);
+ pt2->pressure = interpf(ptb->pressure, pta->pressure, pointlen / totlen);
+ pt2->strength = interpf(ptb->strength, pta->strength, pointlen / totlen);
+ }
}
/* add current stroke-point to buffer (returns whether point was successfully added) */
-static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
+static short gp_stroke_addpoint(
+ tGPsdata *p, const float mval[2], float pressure, double curtime, bool is_fake)
{
bGPdata *gpd = p->gpd;
Brush *brush = p->brush;
@@ -689,6 +840,14 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
/* get pointer to destination point */
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
+ /* Set if point was created by fake events. */
+ if (is_fake) {
+ pt->tflag |= GP_TPOINT_FAKE;
+ }
+ else {
+ pt->tflag &= ~GP_TPOINT_FAKE;
+ }
+
/* store settings */
/* pressure */
if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
@@ -846,7 +1005,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
bGPDspoint *pts;
MDeformVert *dvert = NULL;
- /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
+ /* First time point is adding to temporary buffer (need to allocate new point in stroke) */
if (gpd->runtime.sbuffer_used == 0) {
gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
if (gps->dvert != NULL) {
@@ -937,6 +1096,22 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
(!is_depth);
int i, totelem;
+ /* For very low pressure at the end, truncate stroke. */
+ if (p->paintmode == GP_PAINTMODE_DRAW) {
+ int last_i = gpd->runtime.sbuffer_used - 1;
+ while (last_i > 0) {
+ ptc = (tGPspoint *)gpd->runtime.sbuffer + last_i;
+ if (ptc->pressure > 0.001f) {
+ break;
+ }
+ else {
+ gpd->runtime.sbuffer_used = last_i - 1;
+ CLAMP_MIN(gpd->runtime.sbuffer_used, 1);
+ }
+
+ last_i--;
+ }
+ }
/* Since strokes are so fine,
* when using their depth we need a margin otherwise they might get missed. */
int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
@@ -1187,6 +1362,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
}
+ /* Smooth any point created with fake events when the mouse/pen move very fast. */
+ gp_smooth_fake_segments(p);
+
pt = gps->points;
dvert = gps->dvert;
@@ -1834,6 +2012,7 @@ static void gp_set_default_eraser(Main *bmain, Brush *brush_dft)
/* initialize a drawing brush */
static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1842,7 +2021,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
changed = true;
}
/* be sure curves are initializated */
@@ -2489,10 +2668,10 @@ static void gpencil_draw_cursor_set(tGPsdata *p)
#if 0
Brush *brush = p->brush;
if ((p->paintmode == GP_PAINTMODE_ERASER) || (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ WM_cursor_modal_set(p->win, WM_CURSOR_CROSS); /* XXX need a better cursor */
}
else {
- WM_cursor_modal_set(p->win, CURSOR_NONE);
+ WM_cursor_modal_set(p->win, WM_CURSOR_NONE);
}
#endif
}
@@ -2569,7 +2748,8 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
/* ------------------------------- */
/* create a new stroke point at the point indicated by the painting context */
-static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
+static void gpencil_draw_apply(
+ bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph, bool is_fake)
{
bGPdata *gpd = p->gpd;
tGPspoint *pt = NULL;
@@ -2598,7 +2778,7 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
}
/* try to add point */
- short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
/* handle errors while adding point */
if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
@@ -2612,12 +2792,12 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
/* XXX We only need to reuse previous point if overflow! */
if (ok == GP_STROKEADD_OVERFLOW) {
p->inittime = p->ocurtime;
- gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
+ gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime, is_fake);
}
else {
p->inittime = p->curtime;
}
- gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
}
else if (ok == GP_STROKEADD_INVALID) {
/* the painting operation cannot continue... */
@@ -2823,8 +3003,13 @@ static void gpencil_speed_guide(tGPsdata *p, GP_Sculpt_Guide *guide)
}
/* handle draw event */
-static void gpencil_draw_apply_event(
- bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
+static void gpencil_draw_apply_event(bContext *C,
+ wmOperator *op,
+ const wmEvent *event,
+ Depsgraph *depsgraph,
+ float x,
+ float y,
+ const bool is_fake)
{
tGPsdata *p = op->customdata;
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
@@ -2977,10 +3162,10 @@ static void gpencil_draw_apply_event(
/* create fake events */
float tmp[2];
copy_v2_v2(tmp, p->mval);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
if (len_v2v2(p->mval, p->mvalo)) {
sub_v2_v2v2(pt, p->mval, p->mvalo);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
}
copy_v2_v2(p->mval, tmp);
}
@@ -3011,7 +3196,7 @@ static void gpencil_draw_apply_event(
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
- gpencil_draw_apply(C, op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph, is_fake);
/* force refresh */
/* just active area for now, since doing whole screen is too slow */
@@ -3077,7 +3262,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
}
/* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(C, op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph, false);
}
RNA_END;
@@ -3211,7 +3396,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (paintmode != GP_PAINTMODE_ERASER) {
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
if ((gpl) && ((gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE))) {
- BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hide");
+ BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden");
return OPERATOR_CANCELLED;
}
}
@@ -3250,8 +3435,6 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
/* TODO: set any additional settings that we can take from the events?
* TODO? if tablet is erasing, force eraser to be on? */
- /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
-
/* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
@@ -3272,7 +3455,8 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
p->status = GP_STATUS_PAINTING;
/* handle the initial drawing - i.e. for just doing a simple dot */
- gpencil_draw_apply_event(C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f);
+ gpencil_draw_apply_event(
+ C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f, false);
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
@@ -3389,24 +3573,21 @@ static void gpencil_move_last_stroke_to_back(bContext *C)
BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
}
-/* add events for missing mouse movements when the artist draw very fast */
-static void gpencil_add_missing_events(bContext *C,
- wmOperator *op,
- const wmEvent *event,
- tGPsdata *p)
+/* Add fake events for missing mouse movements when the artist draw very fast */
+static bool gpencil_add_fake_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
{
Brush *brush = p->brush;
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
int input_samples = brush->gpencil_settings->input_samples;
-
+ bool added_events = false;
/* ensure sampling when using circular guide */
if (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR)) {
input_samples = GP_MAX_INPUT_SAMPLES;
}
if (input_samples == 0) {
- return;
+ return added_events;
}
RegionView3D *rv3d = p->ar->regiondata;
@@ -3456,7 +3637,8 @@ static void gpencil_add_missing_events(bContext *C,
interp_v2_v2v2(pt, a, b, 0.5f);
sub_v2_v2v2(pt, b, pt);
/* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
+ added_events = true;
}
else if (dist >= factor) {
int slices = 2 + (int)((dist - 1.0) / factor);
@@ -3465,9 +3647,11 @@ static void gpencil_add_missing_events(bContext *C,
interp_v2_v2v2(pt, a, b, n * i);
sub_v2_v2v2(pt, b, pt);
/* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
+ added_events = true;
}
}
+ return added_events;
}
/* events handling during interactive drawing part of operator */
@@ -3476,6 +3660,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
tGPsdata *p = op->customdata;
ToolSettings *ts = CTX_data_tool_settings(C);
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ tGPspoint *points = (tGPspoint *)p->gpd->runtime.sbuffer;
+
/* default exit state - pass through to support MMB view nav, etc. */
int estate = OPERATOR_PASS_THROUGH;
@@ -3500,7 +3686,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* special mode for editing control points */
if (p->paintmode == GP_PAINTMODE_SET_CP) {
wmWindow *win = p->win;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
bool drawmode = false;
switch (event->type) {
@@ -3598,7 +3784,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* toggle painting mode upon mouse-button movement
- * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
+ * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox
+ * only)
* - RIGHTMOUSE = polyline (hotkey) / eraser (all)
* (Disabling RIGHTMOUSE case here results in bugs like [#32647])
* also making sure we have a valid event value, to not exit too early
@@ -3772,11 +3959,23 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* handle drawing event */
/* printf("\t\tGP - add point\n"); */
+ int size_before = p->gpd->runtime.sbuffer_used;
+ bool added_events = false;
if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) && (p->paintmode != GP_PAINTMODE_ERASER)) {
- gpencil_add_missing_events(C, op, event, p);
+ added_events = gpencil_add_fake_events(C, op, event, p);
}
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f);
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f, false);
+ int size_after = p->gpd->runtime.sbuffer_used;
+
+ /* Last point of the event is always real (not fake). */
+ tGPspoint *pt = &points[size_after - 1];
+ pt->tflag &= ~GP_TPOINT_FAKE;
+
+ /* Smooth the fake events to get smoother strokes, specially at ends. */
+ if (added_events) {
+ gp_smooth_fake_events(p, size_before, size_after);
+ }
/* finish painting operation if anything went wrong just now */
if (p->status == GP_STATUS_ERROR) {
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 8d4c75d2e8c..bf7b2edb025 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -90,6 +90,7 @@
#define IN_MOVE 3
#define IN_BRUSH_SIZE 4
#define IN_BRUSH_STRENGTH 5
+#define IN_POLYLINE 6
#define SELECT_NONE 0
#define SELECT_START 1
@@ -184,6 +185,29 @@ static void gpencil_primitive_to_square(tGPDprimitive *tgpi, const float x, cons
}
}
+/* Helper to constrain a primitive */
+static void gpencil_primitive_constrain(tGPDprimitive *tgpi, bool line_mode)
+{
+ float x = tgpi->end[0] - tgpi->origin[0];
+ float y = tgpi->end[1] - tgpi->origin[1];
+
+ if (line_mode) {
+ float angle = fabsf(atan2f(y, x));
+ if (angle < 0.4f || angle > (M_PI - 0.4f)) {
+ tgpi->end[1] = tgpi->origin[1];
+ }
+ else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) {
+ tgpi->end[0] = tgpi->origin[0];
+ }
+ else {
+ gpencil_primitive_to_square(tgpi, x, y);
+ }
+ }
+ else {
+ gpencil_primitive_to_square(tgpi, x, y);
+ }
+ }
+
/* Helper to rotate point around origin */
static void gp_rotate_v2_v2v2fl(float v[2],
const float p[2],
@@ -404,6 +428,11 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
"adjust subdivision number, Shift to align, Alt to center, E: extrude"),
UI_MAX_DRAW_STR);
}
+ else if (tgpi->type == GP_STROKE_POLYLINE) {
+ BLI_strncpy(msg_str,
+ TIP_("Line: ESC to cancel, LMB to set, Enter/MMB to confirm, Shift to align"),
+ UI_MAX_DRAW_STR);
+ }
else if (tgpi->type == GP_STROKE_BOX) {
BLI_strncpy(msg_str,
TIP_("Rectangle: ESC to cancel, LMB set origin, Enter/MMB to confirm, WHEEL/+- "
@@ -429,7 +458,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
UI_MAX_DRAW_STR);
}
- if (ELEM(tgpi->type, GP_STROKE_CIRCLE, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_BOX)) {
+ if (ELEM(tgpi->type, GP_STROKE_CIRCLE, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_BOX, GP_STROKE_POLYLINE)) {
if (hasNumInput(&tgpi->num)) {
char str_offs[NUM_STR_REP_LEN];
@@ -528,7 +557,7 @@ static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D)
}
/* create a line */
-static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
+static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, bool editable)
{
const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
const float step = 1.0f / (float)(tgpi->tot_edges - 1);
@@ -540,15 +569,22 @@ static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
a += step;
}
- float color[4];
- UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
- gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
- if (tgpi->tot_stored_edges) {
- UI_GetThemeColor4fv(TH_REDALERT, color);
- gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
+ if (editable) {
+ float color[4];
+ UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
+ gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
+ if (tgpi->tot_stored_edges) {
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
+ }
+ else {
+ gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
+ }
}
else {
- gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
+ float color[4];
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
}
}
@@ -693,7 +729,10 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
gp_primitive_rectangle(tgpi, points2D);
break;
case GP_STROKE_LINE:
- gp_primitive_line(tgpi, points2D);
+ gp_primitive_line(tgpi, points2D, true);
+ break;
+ case GP_STROKE_POLYLINE:
+ gp_primitive_line(tgpi, points2D, false);
break;
case GP_STROKE_CIRCLE:
gp_primitive_circle(tgpi, points2D);
@@ -1041,6 +1080,7 @@ static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive
gp_primitive_update_strokes(C, tgpi);
}
+/* Initialise mouse points */
static void gpencil_primitive_interaction_begin(tGPDprimitive *tgpi, const wmEvent *event)
{
copy_v2fl_v2i(tgpi->mval, event->mval);
@@ -1134,7 +1174,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* if brush doesn't exist, create a new set (fix damaged files from old versions) */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
/* Set Draw brush. */
@@ -1164,6 +1204,10 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* set default edge count */
switch (tgpi->type) {
+ case GP_STROKE_POLYLINE: {
+ RNA_int_set(op->ptr, "edges", 8);
+ break;
+ }
case GP_STROKE_LINE: {
RNA_int_set(op->ptr, "edges", 8);
break;
@@ -1214,7 +1258,7 @@ static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *
op->flag |= OP_IS_MODAL_CURSOR_REGION;
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
/* update sindicator in header */
gpencil_primitive_status_indicators(C, tgpi);
@@ -1319,21 +1363,57 @@ static void gpencil_primitive_edit_event_handling(
if (tgpi->flag == IN_CURVE_EDIT) {
if ((a < BIG_SIZE_CTL && tgpi->tot_stored_edges == 0) || b < BIG_SIZE_CTL) {
move = MOVE_ENDS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
else if (tgpi->curve) {
move = MOVE_CP;
- WM_cursor_modal_set(win, BC_HANDCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_HAND);
}
else {
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
}
}
else if (tgpi->flag == IN_PROGRESS) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
switch (event->type) {
+ case LEFTMOUSE: {
+ if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
+ /* set control points and enter edit mode */
+ if ((ELEM(tgpi->type, GP_STROKE_POLYLINE))) {
+ gpencil_primitive_add_segment(tgpi);
+ copy_v2_v2(tgpi->start, tgpi->end);
+ copy_v2_v2(tgpi->origin, tgpi->start);
+ gp_primitive_update_cps(tgpi);
+
+ tgpi->flag = IN_POLYLINE;
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
+ }
+ else {
+ tgpi->flag = IN_CURVE_EDIT;
+ gp_primitive_update_cps(tgpi);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ }
+ else if ((event->val == KM_PRESS) && !ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
+ /* find nearest cp based on stroke end points */
+ if (move == MOVE_ENDS) {
+ tgpi->sel_cp = (a < b) ? SELECT_START : SELECT_END;
+ }
+ else if (move == MOVE_CP) {
+ tgpi->sel_cp = (c < d) ? SELECT_CP1 : SELECT_CP2;
+ }
+ else {
+ tgpi->sel_cp = SELECT_NONE;
+ }
+ break;
+ }
+ else {
+ tgpi->sel_cp = SELECT_NONE;
+ }
+ break;
+ }
case MOUSEMOVE: {
if ((event->val == KM_PRESS) && tgpi->sel_cp != SELECT_NONE) {
if (tgpi->sel_cp == SELECT_START && tgpi->tot_stored_edges == 0) {
@@ -1366,31 +1446,6 @@ static void gpencil_primitive_edit_event_handling(
}
break;
}
- case LEFTMOUSE: {
- if ((event->val == KM_PRESS)) {
- /* find nearest cp based on stroke end points */
- if (move == MOVE_ENDS) {
- tgpi->sel_cp = (a < b) ? SELECT_START : SELECT_END;
- }
- else if (move == MOVE_CP) {
- tgpi->sel_cp = (c < d) ? SELECT_CP1 : SELECT_CP2;
- }
- else {
- tgpi->sel_cp = SELECT_NONE;
- }
- break;
- }
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
- /* set control points and enter edit mode */
- tgpi->flag = IN_CURVE_EDIT;
- gp_primitive_update_cps(tgpi);
- gpencil_primitive_update(C, op, tgpi);
- }
- else {
- tgpi->sel_cp = SELECT_NONE;
- }
- break;
- }
case MKEY: {
if ((event->val == KM_PRESS) && (tgpi->curve) && (ELEM(tgpi->orign_type, GP_STROKE_ARC))) {
tgpi->flip ^= 1;
@@ -1402,7 +1457,7 @@ static void gpencil_primitive_edit_event_handling(
case EKEY: {
if (tgpi->flag == IN_CURVE_EDIT && !ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
gpencil_primitive_add_segment(tgpi);
copy_v2_v2(tgpi->start, tgpi->end);
copy_v2_v2(tgpi->origin, tgpi->start);
@@ -1524,6 +1579,96 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
copy_v2_v2(tgpi->mvalo, tgpi->mval);
return OPERATOR_RUNNING_MODAL;
}
+ else if (tgpi->flag == IN_POLYLINE) {
+
+ switch (event->type) {
+
+ case ESCKEY: {
+ /* return to normal cursor and header status */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_primitive_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+ case LEFTMOUSE: {
+ if (event->val == KM_PRESS) {
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
+ gpencil_primitive_add_segment(tgpi);
+
+ gpencil_primitive_update(C, op, tgpi);
+ copy_v2_v2(tgpi->start, tgpi->end);
+ copy_v2_v2(tgpi->origin, tgpi->end);
+ }
+ break;
+ }
+ case SPACEKEY: /* confirm */
+ case MIDDLEMOUSE:
+ case RETKEY:
+ case RIGHTMOUSE: {
+ if (event->val == KM_PRESS) {
+ tgpi->flag = IDLE;
+ tgpi->tot_edges = tgpi->tot_stored_edges ? 1 : 0;
+ gp_primitive_update_strokes(C, tgpi);
+ gpencil_primitive_interaction_end(C, op, win, tgpi);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ }
+ case MOUSEMOVE: {
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
+ copy_v2_v2(tgpi->end, tgpi->mval);
+
+ if (event->shift) {
+ gpencil_primitive_constrain(tgpi, true);
+ }
+
+ gpencil_primitive_update(C, op, tgpi);
+ break;
+ }
+ case PADPLUSKEY:
+ case WHEELUPMOUSE: {
+ if ((event->val != KM_RELEASE)) {
+ tgpi->tot_edges = tgpi->tot_edges + 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case PADMINUS:
+ case WHEELDOWNMOUSE: {
+ if ((event->val != KM_RELEASE)) {
+ tgpi->tot_edges = tgpi->tot_edges - 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case FKEY: /* brush thickness/ brush strength */
+ {
+ if ((event->val == KM_PRESS)) {
+ if (event->shift) {
+ tgpi->prev_flag = tgpi->flag;
+ tgpi->flag = IN_BRUSH_STRENGTH;
+ }
+ else {
+ tgpi->prev_flag = tgpi->flag;
+ tgpi->flag = IN_BRUSH_SIZE;
+ }
+ WM_cursor_modal_set(win, WM_CURSOR_NS_SCROLL);
+ }
+ break;
+ }
+ }
+
+ copy_v2_v2(tgpi->mvalo, tgpi->mval);
+ return OPERATOR_RUNNING_MODAL;
+ }
else if (tgpi->flag == IN_BRUSH_SIZE) {
switch (event->type) {
case MOUSEMOVE:
@@ -1534,11 +1679,11 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case MIDDLEMOUSE:
case LEFTMOUSE:
tgpi->brush_size = 0;
- tgpi->flag = IN_CURVE_EDIT;
+ tgpi->flag = tgpi->prev_flag;
break;
case RIGHTMOUSE:
if (event->val == KM_RELEASE) {
- tgpi->flag = IN_CURVE_EDIT;
+ tgpi->flag = tgpi->prev_flag;
gpencil_primitive_size(tgpi, true);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1557,11 +1702,11 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case MIDDLEMOUSE:
case LEFTMOUSE:
tgpi->brush_strength = 0.0f;
- tgpi->flag = IN_CURVE_EDIT;
+ tgpi->flag = tgpi->prev_flag;
break;
case RIGHTMOUSE:
if (event->val == KM_RELEASE) {
- tgpi->flag = IN_CURVE_EDIT;
+ tgpi->flag = tgpi->prev_flag;
gpencil_primitive_strength(tgpi, true);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1570,7 +1715,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
copy_v2_v2(tgpi->mvalo, tgpi->mval);
return OPERATOR_RUNNING_MODAL;
}
- else if (tgpi->flag != IDLE) {
+ else if (!ELEM(tgpi->flag, IDLE) && !ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
gpencil_primitive_edit_event_handling(C, op, win, event, tgpi);
}
@@ -1581,24 +1726,38 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
/* TODO: Ignore if not in main region yet */
tgpi->flag = IN_PROGRESS;
gpencil_primitive_interaction_begin(tgpi, event);
+ if (ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
+ tgpi->flag = IN_POLYLINE;
+ gpencil_primitive_update(C, op, tgpi);
+ return OPERATOR_RUNNING_MODAL;
+ }
}
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) {
- tgpi->flag = IN_CURVE_EDIT;
- }
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
+ (!ELEM(tgpi->type, GP_STROKE_POLYLINE))) {
/* set control points and enter edit mode */
tgpi->flag = IN_CURVE_EDIT;
gp_primitive_update_cps(tgpi);
gpencil_primitive_update(C, op, tgpi);
}
else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
- (tgpi->type != GP_STROKE_CURVE)) {
+ (!ELEM(tgpi->type, GP_STROKE_CURVE, GP_STROKE_POLYLINE))) {
/* stop drawing primitive */
tgpi->flag = IDLE;
gpencil_primitive_interaction_end(C, op, win, tgpi);
/* done! */
return OPERATOR_FINISHED;
}
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
+ (ELEM(tgpi->type, GP_STROKE_POLYLINE))) {
+ /* set control points and enter edit mode */
+ tgpi->flag = IN_POLYLINE;
+ gpencil_primitive_update(C, op, tgpi);
+ copy_v2_v2(tgpi->mvalo, tgpi->mval);
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) {
+ tgpi->flag = IN_CURVE_EDIT;
+ }
else {
if (G.debug & G_DEBUG) {
printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag);
@@ -1618,7 +1777,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
/* exception to cancel current stroke when we have previous strokes in buffer */
if (tgpi->tot_stored_edges > 0) {
tgpi->flag = IDLE;
- tgpi->tot_edges = 0;
+ tgpi->tot_edges = tgpi->tot_stored_edges ? 1 : 0;
gp_primitive_update_strokes(C, tgpi);
gpencil_primitive_interaction_end(C, op, win, tgpi);
/* done! */
@@ -1665,7 +1824,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
{
if ((event->val == KM_PRESS)) {
tgpi->flag = IN_MOVE;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
break;
}
@@ -1673,12 +1832,14 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
{
if ((event->val == KM_PRESS)) {
if (event->shift) {
+ tgpi->prev_flag = tgpi->flag;
tgpi->flag = IN_BRUSH_STRENGTH;
}
else {
+ tgpi->prev_flag = tgpi->flag;
tgpi->flag = IN_BRUSH_SIZE;
}
- WM_cursor_modal_set(win, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NS_SCROLL);
}
break;
}
@@ -1704,7 +1865,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case TABKEY: {
if (tgpi->flag == IN_CURVE_EDIT) {
tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
gp_primitive_update_cps(tgpi);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1712,7 +1873,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
case MOUSEMOVE: /* calculate new position */
{
- if (tgpi->flag == IN_CURVE_EDIT) {
+ if (ELEM(tgpi->flag, IN_CURVE_EDIT)) {
break;
}
/* only handle mousemove if not doing numinput */
@@ -1725,26 +1886,11 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
/* Keep square if shift key */
if (event->shift) {
- float x = tgpi->end[0] - tgpi->origin[0];
- float y = tgpi->end[1] - tgpi->origin[1];
- if (tgpi->type == GP_STROKE_LINE || tgpi->curve) {
- float angle = fabsf(atan2f(y, x));
- if (angle < 0.4f || angle > (M_PI - 0.4f)) {
- tgpi->end[1] = tgpi->origin[1];
- }
- else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) {
- tgpi->end[0] = tgpi->origin[0];
- }
- else {
- gpencil_primitive_to_square(tgpi, x, y);
- }
- }
- else {
- gpencil_primitive_to_square(tgpi, x, y);
- }
+ gpencil_primitive_constrain(
+ tgpi, (ELEM(tgpi->type, GP_STROKE_LINE, GP_STROKE_POLYLINE) || tgpi->curve));
}
/* Center primitive if alt key */
- if (event->alt) {
+ if (event->alt && !ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
tgpi->start[0] = tgpi->origin[0] - (tgpi->end[0] - tgpi->origin[0]);
tgpi->start[1] = tgpi->origin[1] - (tgpi->end[1] - tgpi->origin[1]);
}
@@ -1796,6 +1942,7 @@ void GPENCIL_OT_primitive(wmOperatorType *ot)
static EnumPropertyItem primitive_type[] = {
{GP_STROKE_BOX, "BOX", 0, "Box", ""},
{GP_STROKE_LINE, "LINE", 0, "Line", ""},
+ {GP_STROKE_POLYLINE, "POLYLINE", 0, "Polyline", ""},
{GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""},
{GP_STROKE_ARC, "ARC", 0, "Arc", ""},
{GP_STROKE_CURVE, "CURVE", 0, "Curve", ""},
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index b7b73c1b501..be265ed4bd5 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -832,7 +832,8 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
* from gpencil_paint.c #gp_stroke_eraser_dostroke().
* It would be great to de-duplicate the logic here sometime, but that can wait.
*/
-static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
+static bool gp_stroke_do_circle_sel(bGPdata *gpd,
+ bGPDlayer *gpl,
bGPDstroke *gps,
GP_SpaceConversion *gsc,
const int mx,
@@ -844,12 +845,14 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
const int selectmode,
const float scale)
{
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bGPDspoint *pt1 = NULL;
bGPDspoint *pt2 = NULL;
- bGPDstroke *gps_orig = gps->runtime.gps_orig;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
int i;
bool changed = false;
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
@@ -862,12 +865,12 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
/* change selection */
if (select) {
- gps_orig->points->flag |= GP_SPOINT_SELECT;
- gps_orig->flag |= GP_STROKE_SELECT;
+ gps_active->points->flag |= GP_SPOINT_SELECT;
+ gps_active->flag |= GP_STROKE_SELECT;
}
else {
- gps_orig->points->flag &= ~GP_SPOINT_SELECT;
- gps_orig->flag &= ~GP_STROKE_SELECT;
+ gps_active->points->flag &= ~GP_SPOINT_SELECT;
+ gps_active->flag &= ~GP_STROKE_SELECT;
}
return true;
@@ -907,20 +910,24 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
*/
hit = true;
if (select) {
- if (pt1->runtime.pt_orig != NULL) {
- pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
+ pt_active->flag |= GP_SPOINT_SELECT;
}
- if (pt2->runtime.pt_orig != NULL) {
- pt2->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ if (pt_active != NULL) {
+ pt_active->flag |= GP_SPOINT_SELECT;
}
changed = true;
}
else {
- if (pt1->runtime.pt_orig != NULL) {
- pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
- if (pt2->runtime.pt_orig != NULL) {
- pt2->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ if (pt_active != NULL) {
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
changed = true;
}
@@ -935,28 +942,29 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
/* if stroke mode expand selection */
if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
- if (pt1->runtime.pt_orig != NULL) {
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
if (select) {
- pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active->flag |= GP_SPOINT_SELECT;
}
else {
- pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
}
}
}
/* expand selection to segment */
- if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) &&
- (pt1->runtime.pt_orig != NULL)) {
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && (pt_active != NULL)) {
float r_hita[3], r_hitb[3];
bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
ED_gpencil_select_stroke_segment(
- gpl, gps_orig, pt1->runtime.pt_orig, hit_select, false, scale, r_hita, r_hitb);
+ gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb);
}
/* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps_orig);
+ BKE_gpencil_stroke_sync_selection(gps_active);
}
return changed;
@@ -1016,8 +1024,18 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
/* find visible strokes, and select if hit */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
- changed |= gp_stroke_do_circle_sel(
- gpl, gps, &gsc, mx, my, radius, select, &rect, gpstroke_iter.diff_mat, selectmode, scale);
+ changed |= gp_stroke_do_circle_sel(gpd,
+ gpl,
+ gps,
+ &gsc,
+ mx,
+ my,
+ radius,
+ select,
+ &rect,
+ gpstroke_iter.diff_mat,
+ selectmode,
+ scale);
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
@@ -1090,6 +1108,8 @@ static int gpencil_generic_select_exec(bContext *C,
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
const bool segmentmode = ((selectmode == GP_SELECTMODE_SEGMENT) &&
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const float scale = ts->gp_sculpt.isect_threshold;
@@ -1125,36 +1145,32 @@ static int gpencil_generic_select_exec(bContext *C,
/* select/deselect points */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
bool hit = false;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
+ bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
/* convert point coords to screenspace */
const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
if (strokemode == false) {
- const bool is_select = (pt->runtime.pt_orig->flag & GP_SPOINT_SELECT) != 0;
+ const bool is_select = (pt_active->flag & GP_SPOINT_SELECT) != 0;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(pt->runtime.pt_orig->flag, sel_op_result, GP_SPOINT_SELECT);
+ SET_FLAG_FROM_TEST(pt_active->flag, sel_op_result, GP_SPOINT_SELECT);
changed = true;
/* expand selection to segment */
if ((sel_op_result != -1) && (segmentmode)) {
- bool hit_select = (bool)(pt->runtime.pt_orig->flag & GP_SPOINT_SELECT);
+ bool hit_select = (bool)(pt_active->flag & GP_SPOINT_SELECT);
float r_hita[3], r_hitb[3];
- ED_gpencil_select_stroke_segment(gpl,
- gps->runtime.gps_orig,
- pt->runtime.pt_orig,
- hit_select,
- false,
- scale,
- r_hita,
- r_hitb);
+ ED_gpencil_select_stroke_segment(
+ gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb);
}
}
}
@@ -1168,19 +1184,21 @@ static int gpencil_generic_select_exec(bContext *C,
/* if stroke mode expand selection */
if (strokemode) {
- const bool is_select = BKE_gpencil_stroke_select_check(gps->runtime.gps_orig);
+ const bool is_select = BKE_gpencil_stroke_select_check(gps_active);
const bool is_inside = hit;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
+ bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+
if (sel_op_result) {
- pt->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active->flag |= GP_SPOINT_SELECT;
}
else {
- pt->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
}
changed = true;
@@ -1188,7 +1206,7 @@ static int gpencil_generic_select_exec(bContext *C,
}
/* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps->runtime.gps_orig);
+ BKE_gpencil_stroke_sync_selection(gps_active);
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
@@ -1369,6 +1387,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
const float scale = ts->gp_sculpt.isect_threshold;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
/* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
const float radius = 0.50f * U.widget_unit;
@@ -1414,13 +1433,14 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* XXX: maybe we should go from the top of the stack down instead... */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
@@ -1437,8 +1457,8 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* only use this point if it is a better match than the current hit - T44685 */
if (pt_distance < hit_distance) {
hit_layer = gpl;
- hit_stroke = gps->runtime.gps_orig;
- hit_point = pt->runtime.pt_orig;
+ hit_stroke = gps_active;
+ hit_point = (!is_multiedit) ? pt->runtime.pt_orig : pt;
hit_distance = pt_distance;
}
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 89a2a987f60..b194d28a8b8 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -1391,7 +1391,7 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
/* ensure a color exists and is assigned to object */
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index cb6c66ed795..bf9b69f12e1 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -834,12 +834,28 @@ void ED_drivers_editor_init(struct bContext *C, struct ScrArea *sa);
/* ************************************************ */
+typedef enum eAnimvizCalcRange {
+ /* Update motion paths at the current frame only. */
+ ANIMVIZ_CALC_RANGE_CURRENT_FRAME,
+
+ /* Try to limit updates to a close neighborhood of the current frame. */
+ ANIMVIZ_CALC_RANGE_CHANGED,
+
+ /* Update an entire range of the motion paths. */
+ ANIMVIZ_CALC_RANGE_FULL,
+} eAnimvizCalcRange;
+
+struct Depsgraph *animviz_depsgraph_build(struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct ListBase *targets);
+
void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
struct Main *bmain,
struct Scene *scene,
ListBase *targets,
- bool restore,
- bool current_frame_only);
+ eAnimvizCalcRange range,
+ bool restore);
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 173ba65fc47..7ac42967dda 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -284,10 +284,18 @@ bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool
bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select_tag_update(struct Object *ob);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
+
+/* Corresponds to eAnimvizCalcRange. */
+typedef enum ePosePathCalcRange {
+ POSE_PATH_CALC_RANGE_CURRENT_FRAME,
+ POSE_PATH_CALC_RANGE_CHANGED,
+ POSE_PATH_CALC_RANGE_FULL,
+} ePosePathCalcRange;
void ED_pose_recalculate_paths(struct bContext *C,
struct Scene *scene,
struct Object *ob,
- bool current_frame_only);
+ ePosePathCalcRange range);
+
struct Object *ED_pose_object_from_context(struct bContext *C);
/* meshlaplacian.c */
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 37090ce3421..83890c1621c 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -98,6 +98,8 @@ struct rcti;
struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile);
short ED_fileselect_set_params(struct SpaceFile *sfile);
+void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
+void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, int temp_win_size[]);
void ED_fileselect_reset_params(struct SpaceFile *sfile);
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 63ddc669ab2..0ff1b8bb40b 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -71,8 +71,15 @@ typedef struct tGPspoint {
float uv_rot; /* uv rotation for dor mode */
float rnd[3]; /* rnd value */
bool rnd_dirty; /* rnd flag */
+ short tflag; /* Internal flag */
} tGPspoint;
+/* tGPspoint->flag */
+typedef enum etGPspoint_tFlag {
+ /* Created by Fake event (used when mouse/pen move very fast while drawing). */
+ GP_TPOINT_FAKE = (1 << 0),
+} etGPspoint_tFlag;
+
/* used to sort by zdepth gpencil objects in viewport */
/* TODO: this could be a system parameter in userprefs screen */
#define GP_CACHE_BLOCK_SIZE 16
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 7d69f86dbf8..69742af9f50 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -77,6 +77,7 @@ void ED_image_mouse_pos(struct SpaceImage *sima,
struct ARegion *ar,
const int mval[2],
float co[2]);
+void ED_image_view_center_to_point(struct SpaceImage *sima, float x, float y);
void ED_image_point_pos(
struct SpaceImage *sima, struct ARegion *ar, float x, float y, float *xr, float *yr);
void ED_image_point_pos__reverse(struct SpaceImage *sima,
@@ -94,6 +95,7 @@ bool ED_space_image_paint_curve(const struct bContext *C);
bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct ViewLayer *view_layer);
bool ED_space_image_maskedit_poll(struct bContext *C);
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
+bool ED_space_image_cursor_poll(struct bContext *C);
void ED_image_draw_info(struct Scene *scene,
struct ARegion *ar,
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 42e5add2ef0..16b3c9c240a 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -310,15 +310,24 @@ extern EnumPropertyItem prop_driver_create_mapping_types[];
/* -------- */
+typedef enum eDriverFCurveCreationMode {
+ DRIVER_FCURVE_LOOKUP_ONLY = 0, /* Don't add anything if not found. */
+ DRIVER_FCURVE_KEYFRAMES = 1, /* Add with keyframes, for visual tweaking. */
+ DRIVER_FCURVE_GENERATOR = 2, /* Add with generator, for script backwards compatibility. */
+ DRIVER_FCURVE_EMPTY = 3 /* Add without data, for pasting. */
+} eDriverFCurveCreationMode;
+
/* Low-level call to add a new driver F-Curve. This shouldn't be used directly for most tools,
* although there are special cases where this approach is preferable.
*/
struct FCurve *verify_driver_fcurve(struct ID *id,
const char rna_path[],
const int array_index,
- short add);
+ eDriverFCurveCreationMode creation_mode);
-struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add);
+struct FCurve *alloc_driver_fcurve(const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode);
/* -------- */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index d8d62ad6f08..fc7b0d8be8f 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -380,17 +380,17 @@ float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vert
void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr);
/* mesh_data.c */
-#if 0
-void ED_mesh_geometry_add(
- struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces);
-#endif
-void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_verts_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count);
-void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_verts_remove(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_edges_remove(struct Mesh *mesh, struct ReportList *reports, int count);
-void ED_mesh_vertices_remove(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_loops_remove(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_polys_remove(struct Mesh *mesh, struct ReportList *reports, int count);
+
+void ED_mesh_geometry_clear(struct Mesh *mesh);
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_edges_loose);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index c481c19a552..38d75aa57e9 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -238,9 +238,17 @@ void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Objec
/* object motion paths */
void ED_objects_clear_paths(struct bContext *C, bool only_selected);
+
+/* Corresponds to eAnimvizCalcRange. */
+typedef enum eObjectPathCalcRange {
+ OBJECT_PATH_CALC_RANGE_CURRENT_FRAME,
+ OBJECT_PATH_CALC_RANGE_CHANGED,
+ OBJECT_PATH_CALC_RANGE_FULL,
+} eObjectPathCalcRange;
+
void ED_objects_recalculate_paths(struct bContext *C,
struct Scene *scene,
- bool current_frame_only);
+ eObjectPathCalcRange range);
/* constraints */
struct ListBase *get_active_constraints(struct Object *ob);
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index 88cc8a85897..fec4beea809 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -40,13 +40,44 @@ void ED_imapaint_dirty_region(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
-/* paint_image_undo.c */
+/* image_undo.c */
void ED_image_undo_push_begin(const char *name, int paint_mode);
+void ED_image_undo_push_begin_with_image(const char *name,
+ struct Image *image,
+ struct ImBuf *ibuf);
+
void ED_image_undo_push_end(void);
void ED_image_undo_restore(struct UndoStep *us);
void ED_image_undosys_type(struct UndoType *ut);
+void *ED_image_paint_tile_find(struct ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **r_mask,
+ bool validate);
+void *ED_image_paint_tile_push(struct ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ struct ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **r_mask,
+ bool **r_valid,
+ bool use_thread_lock,
+ bool find_prev);
+void ED_image_paint_tile_lock_init(void);
+void ED_image_paint_tile_lock_end(void);
+
+struct ListBase *ED_image_paint_tile_list_get(void);
+
+#define ED_IMAGE_UNDO_TILE_BITS 6
+#define ED_IMAGE_UNDO_TILE_SIZE (1 << ED_IMAGE_UNDO_TILE_BITS)
+#define ED_IMAGE_UNDO_TILE_NUMBER(size) \
+ (((size) + ED_IMAGE_UNDO_TILE_SIZE - 1) >> ED_IMAGE_UNDO_TILE_BITS)
+
/* paint_curve_undo.c */
void ED_paintcurve_undo_push_begin(const char *name);
void ED_paintcurve_undo_push_end(void);
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 3ef3c0ba937..0c973f4ca88 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -40,12 +40,18 @@ int PE_start_edit(struct PTCacheEdit *edit);
/* access */
struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys);
-struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
+struct PTCacheEdit *PE_get_current(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
struct PTCacheEdit *PE_create_current(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void PE_current_changed(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
-int PE_minmax(struct Scene *scene, struct ViewLayer *view_layer, float min[3], float max[3]);
+int PE_minmax(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ float min[3],
+ float max[3]);
struct ParticleEditSettings *PE_settings(struct Scene *scene);
/* update calls */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index d0fab134dcc..c3e61f5f2b2 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -66,6 +66,7 @@ void ED_region_do_listen(struct wmWindow *win,
void ED_region_do_layout(struct bContext *C, struct ARegion *ar);
void ED_region_do_draw(struct bContext *C, struct ARegion *ar);
void ED_region_exit(struct bContext *C, struct ARegion *ar);
+void ED_region_remove(struct bContext *C, struct ScrArea *sa, struct ARegion *ar);
void ED_region_pixelspace(struct ARegion *ar);
void ED_region_update_rect(struct ARegion *ar);
void ED_region_init(struct ARegion *ar);
@@ -238,6 +239,15 @@ struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *sa,
const short state);
+ScrArea *ED_screen_temp_space_open(struct bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ eSpace_Type space_type,
+ int display_type,
+ bool dialog);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
void ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
void ED_screens_navigation_bar_tools_menu_create(struct bContext *C,
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index dc7b25392e8..28280fae3a8 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -521,7 +521,9 @@ int view3d_opengl_select(struct ViewContext *vc,
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
-void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc);
+void ED_view3d_viewcontext_init(struct bContext *C,
+ struct ViewContext *vc,
+ struct Depsgraph *depsgraph);
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index ffabace48c0..4e4db46adf6 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -858,9 +858,9 @@ DEF_ICON_BLANK(855)
DEF_ICON_BLANK(856)
DEF_ICON_BLANK(857)
DEF_ICON_BLANK(858)
-DEF_ICON_BLANK(859)
-DEF_ICON_BLANK(860)
-DEF_ICON_BLANK(861)
+DEF_ICON(DESKTOP)
+DEF_ICON(EXTERNAL_DRIVE)
+DEF_ICON(NETWORK_DRIVE)
/* SEQUENCE / IMAGE EDITOR */
DEF_ICON(SEQ_SEQUENCER)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 702d319817f..f5721c008b2 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -524,6 +524,7 @@ bool UI_but_is_tool(const uiBut *but);
bool UI_but_is_utf8(const uiBut *but);
#define UI_but_is_decorator(but) ((but)->func == ui_but_anim_decorate_cb)
+bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title);
bool UI_block_is_empty(const uiBlock *block);
bool UI_block_can_add_separator(const uiBlock *block);
@@ -1810,6 +1811,7 @@ void uiLayoutSetActivateInit(uiLayout *layout, bool active);
void uiLayoutSetEnabled(uiLayout *layout, bool enabled);
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert);
void uiLayoutSetAlignment(uiLayout *layout, char alignment);
+void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size);
void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect);
void uiLayoutSetScaleX(uiLayout *layout, float scale);
void uiLayoutSetScaleY(uiLayout *layout, float scale);
@@ -1827,6 +1829,7 @@ bool uiLayoutGetActivateInit(uiLayout *layout);
bool uiLayoutGetEnabled(uiLayout *layout);
bool uiLayoutGetRedAlert(uiLayout *layout);
int uiLayoutGetAlignment(uiLayout *layout);
+bool uiLayoutGetFixedSize(uiLayout *layout);
bool uiLayoutGetKeepAspect(uiLayout *layout);
int uiLayoutGetWidth(uiLayout *layout);
float uiLayoutGetScaleX(uiLayout *layout);
@@ -2451,6 +2454,8 @@ void UI_widgetbase_draw_cache_end(void);
void UI_theme_init_default(void);
void UI_style_init_default(void);
+void UI_interface_tag_script_reload(void);
+
/* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */
#define USE_UI_TOOLBAR_HACK
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index efa35c84b9e..8e04db8127e 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -234,6 +234,8 @@ typedef enum ThemeColorID {
TH_DIS_MARKER,
TH_PATH_BEFORE,
TH_PATH_AFTER,
+ TH_PATH_KEYFRAME_BEFORE,
+ TH_PATH_KEYFRAME_AFTER,
TH_CAMERA_PATH,
TH_LOCK_MARKER,
@@ -281,6 +283,7 @@ typedef enum ThemeColorID {
TH_NLA_TWEAK, /* 'tweaking' track in NLA */
TH_NLA_TWEAK_DUPLI, /* error/warning flag for other strips referencing dupli strip */
+ TH_NLA_TRACK,
TH_NLA_TRANSITION,
TH_NLA_TRANSITION_SEL,
TH_NLA_META,
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index bc8d25e8d9e..d33023c69a1 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -50,6 +50,7 @@ set(SRC
interface_eyedropper_datablock.c
interface_eyedropper_depth.c
interface_eyedropper_driver.c
+ interface_eyedropper_gpencil_color.c
interface_handlers.c
interface_icons.c
interface_icons_event.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 27a33a38b15..54fd91e5361 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -786,6 +786,8 @@ static bool ui_but_update_from_old_block(const bContext *C,
oldbut->flag = (oldbut->flag & ~flag_copy) | (but->flag & flag_copy);
oldbut->drawflag = (oldbut->drawflag & ~drawflag_copy) | (but->drawflag & drawflag_copy);
+ SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons);
+
/* copy hardmin for list rows to prevent 'sticking' highlight to mouse position
* when scrolling without moving mouse (see [#28432]) */
if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) {
@@ -3389,7 +3391,7 @@ static void ui_but_build_drawstr_float(uiBut *but, double value)
if (value == (double)FLT_MAX) {
STR_CONCAT(but->drawstr, slen, "inf");
}
- else if (value == (double)-FLT_MIN) {
+ else if (value == (double)-FLT_MAX) {
STR_CONCAT(but->drawstr, slen, "-inf");
}
else if (subtype == PROP_PERCENTAGE) {
@@ -6689,3 +6691,8 @@ void UI_exit(void)
ui_resources_free();
ui_but_clipboard_free();
}
+
+void UI_interface_tag_script_reload(void)
+{
+ ui_interface_tag_script_reload_queries();
+}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 168c6051327..c8baa1a7c7b 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -243,7 +243,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
}
/* create driver */
- fcu = verify_driver_fcurve(id, path, but->rnaindex, 1);
+ fcu = verify_driver_fcurve(id, path, but->rnaindex, DRIVER_FCURVE_KEYFRAMES);
if (fcu) {
ChannelDriver *driver = fcu->driver;
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 580ff527bf6..ae6a71f17e6 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -63,7 +63,14 @@
static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but)
{
/* Compute data path from context to property. */
+
+ /* If this returns null, we won't be able to bind shortcuts to these RNA properties.
+ * Support can be added at #wm_context_member_from_ptr. */
const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin);
+ if (member_id == NULL) {
+ return NULL;
+ }
+
const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin);
const char *member_id_data_path = member_id;
@@ -90,27 +97,35 @@ static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but)
return prop;
}
-static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **prop)
+static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **r_prop)
{
if (but->optype) {
/* Operator */
- *prop = (but->opptr && but->opptr->data) ? IDP_CopyProperty(but->opptr->data) : NULL;
+ *r_prop = (but->opptr && but->opptr->data) ? IDP_CopyProperty(but->opptr->data) : NULL;
return but->optype->idname;
}
else if (but->rnaprop) {
- if (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) {
+ const PropertyType rnaprop_type = RNA_property_type(but->rnaprop);
+
+ if (rnaprop_type == PROP_BOOLEAN) {
/* Boolean */
- *prop = shortcut_property_from_rna(C, but);
+ *r_prop = shortcut_property_from_rna(C, but);
+ if (*r_prop == NULL) {
+ return NULL;
+ }
return "WM_OT_context_toggle";
}
- else if (RNA_property_type(but->rnaprop) == PROP_ENUM) {
+ else if (rnaprop_type == PROP_ENUM) {
/* Enum */
- *prop = shortcut_property_from_rna(C, but);
+ *r_prop = shortcut_property_from_rna(C, but);
+ if (*r_prop == NULL) {
+ return NULL;
+ }
return "WM_OT_context_menu_enum";
}
}
- *prop = NULL;
+ *r_prop = NULL;
return NULL;
}
@@ -899,13 +914,13 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
if (is_array_component) {
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
true);
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
@@ -913,7 +928,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
}
else {
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
@@ -928,7 +943,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
if (ptr->owner_id && !is_whole_array &&
ELEM(type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy As New Driver"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy as New Driver"),
ICON_NONE,
"UI_OT_copy_as_driver_button");
}
@@ -950,7 +965,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
but->search_func == ui_rna_collection_search_cb)) &&
ui_jump_to_target_button_poll(C)) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump To Target"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump to Target"),
ICON_NONE,
"UI_OT_jump_to_target_button");
uiItemS(layout);
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 551e25a5986..72c31c7b39e 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -1849,9 +1849,17 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, cons
cumap = (CurveMapping *)but->poin;
}
+ float clip_size_x = BLI_rctf_size_x(&cumap->curr);
+ float clip_size_y = BLI_rctf_size_y(&cumap->curr);
+
+ /* zero-sized curve */
+ if (clip_size_x == 0.0f || clip_size_y == 0.0f) {
+ return;
+ }
+
/* calculate offset and zoom */
- float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&cumap->curr);
- float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr);
+ float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / clip_size_x;
+ float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / clip_size_y;
float offsx = cumap->curr.xmin - (1.0f / zoomx);
float offsy = cumap->curr.ymin - (1.0f / zoomy);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 3c26c37b610..988dea270f5 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -69,6 +69,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_gpencil_color");
return keymap;
}
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 68c12fe7652..0cf357c508b 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -290,7 +290,7 @@ static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
{
/* init */
if (eyedropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -332,7 +332,7 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper";
ot->idname = "UI_OT_eyedropper_color";
- ot->description = "Sample a color from the Blender Window to store in a property";
+ ot->description = "Sample a color from the Blender window to store in a property";
/* api callbacks */
ot->invoke = eyedropper_invoke;
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
index ffe93e48936..479cf9ccffe 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -304,7 +304,7 @@ static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEven
{
/* init */
if (eyedropper_colorband_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 336fae45895..fd5a46e7716 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -314,7 +314,7 @@ static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
{
/* init */
if (datadropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 2e51701e01d..8a48ca19db2 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -311,7 +311,7 @@ static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
{
/* init */
if (depthdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index e6fc52bc3bc..cc13367c190 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -180,7 +180,7 @@ static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
{
/* init */
if (driverdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
new file mode 100644
index 00000000000..02d4596e93c
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
@@ -0,0 +1,324 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Eyedropper (RGB Color)
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_gpencil_color
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_report.h"
+
+#include "UI_interface.h"
+
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_undo.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "interface_intern.h"
+#include "interface_eyedropper_intern.h"
+
+typedef struct EyedropperGPencil {
+ struct ColorManagedDisplay *display;
+ /** color under cursor RGB */
+ float color[3];
+} EyedropperGPencil;
+
+/* Helper: Draw status message while the user is running the operator */
+static void eyedropper_gpencil_status_indicators(bContext *C)
+{
+ char msg_str[UI_MAX_DRAW_STR];
+ BLI_strncpy(
+ msg_str, TIP_("LMB: Stroke - Shift: Fill - Shift+Ctrl: Stroke + Fill"), UI_MAX_DRAW_STR);
+
+ ED_workspace_status_text(C, msg_str);
+}
+
+/* Initialize. */
+static bool eyedropper_gpencil_init(bContext *C, wmOperator *op)
+{
+ EyedropperGPencil *eye = MEM_callocN(sizeof(EyedropperGPencil), __func__);
+
+ op->customdata = eye;
+ Scene *scene = CTX_data_scene(C);
+
+ const char *display_device;
+ display_device = scene->display_settings.display_device;
+ eye->display = IMB_colormanagement_display_get_named(display_device);
+
+ return true;
+}
+
+/* Exit and free memory. */
+static void eyedropper_gpencil_exit(bContext *C, wmOperator *op)
+{
+ /* Clear status message area. */
+ ED_workspace_status_text(C, NULL);
+
+ MEM_SAFE_FREE(op->customdata);
+}
+
+/* Set the material. */
+static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, EyedropperGPencil *eye)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Material *ma = NULL;
+
+ const bool only_stroke = ((!event->ctrl) && (!event->shift));
+ const bool only_fill = ((!event->ctrl) && (event->shift));
+ const bool both = ((event->ctrl) && (event->shift));
+
+ float col_conv[4];
+ bool found = false;
+
+ /* Convert from linear rgb space to display space because grease pencil colors are in display
+ * space, and this conversion is needed to undo the conversion to linear performed by
+ * eyedropper_color_sample_fl. */
+ if (eye->display) {
+ copy_v3_v3(col_conv, eye->color);
+ IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
+ }
+ else {
+ copy_v3_v3(col_conv, eye->color);
+ }
+
+ /* Look for a similar material in grease pencil slots. */
+ short *totcol = give_totcolp(ob);
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ if (ma == NULL) {
+ continue;
+ }
+
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ if (gp_style != NULL) {
+ /* Check stroke color. */
+ bool found_stroke = compare_v3v3(gp_style->stroke_rgba, col_conv, 0.01f) &&
+ (gp_style->flag & GP_STYLE_STROKE_SHOW);
+ /* Check fill color. */
+ bool found_fill = compare_v3v3(gp_style->fill_rgba, col_conv, 0.01f) &&
+ (gp_style->flag & GP_STYLE_FILL_SHOW);
+
+ if ((only_stroke) && (found_stroke) && ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) {
+ found = true;
+ }
+ else if ((only_fill) && (found_fill) && ((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0)) {
+ found = true;
+ }
+ else if ((both) && (found_stroke) && (found_fill)) {
+ found = true;
+ }
+
+ /* Found existing material. */
+ if (found) {
+ ob->actcol = i + 1;
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ return;
+ }
+ }
+ }
+
+ /* If material was not found add a new material with stroke and/or fill color
+ * depending of the secondary key (LMB: Stroke, Shift: Fill, Shift+Ctrl: Stroke/Fill)
+ */
+ int idx;
+ Material *ma_new = BKE_gpencil_object_material_new(bmain, ob, "Material", &idx);
+ WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, &ob->id);
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ DEG_relations_tag_update(bmain);
+
+ BLI_assert(ma_new != NULL);
+
+ MaterialGPencilStyle *gp_style_new = ma_new->gp_style;
+ BLI_assert(gp_style_new != NULL);
+
+ /* Only create Stroke (default option). */
+ if (only_stroke) {
+ /* Stroke color. */
+ gp_style_new->flag |= GP_STYLE_STROKE_SHOW;
+ gp_style_new->flag &= ~GP_STYLE_FILL_SHOW;
+ copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
+ zero_v4(gp_style_new->fill_rgba);
+ }
+ /* Fill Only. */
+ else if (only_fill) {
+ /* Fill color. */
+ gp_style_new->flag &= ~GP_STYLE_STROKE_SHOW;
+ gp_style_new->flag |= GP_STYLE_FILL_SHOW;
+ zero_v4(gp_style_new->stroke_rgba);
+ copy_v3_v3(gp_style_new->fill_rgba, col_conv);
+ }
+ /* Stroke and Fill. */
+ else if (both) {
+ gp_style_new->flag |= GP_STYLE_STROKE_SHOW | GP_STYLE_FILL_SHOW;
+ copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
+ copy_v3_v3(gp_style_new->fill_rgba, col_conv);
+ }
+ /* Push undo for new created material. */
+ ED_undo_push(C, "Add Grease Pencil Material");
+}
+
+/* Sample the color below cursor. */
+static void eyedropper_gpencil_color_sample(bContext *C, EyedropperGPencil *eye, int mx, int my)
+{
+ eyedropper_color_sample_fl(C, mx, my, eye->color);
+}
+
+/* Cancel operator. */
+static void eyedropper_gpencil_cancel(bContext *C, wmOperator *op)
+{
+ eyedropper_gpencil_exit(C, op);
+}
+
+/* Main modal status check. */
+static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ EyedropperGPencil *eye = (EyedropperGPencil *)op->customdata;
+ /* Handle modal keymap */
+ switch (event->type) {
+ case EVT_MODAL_MAP: {
+ switch (event->val) {
+ case EYE_MODAL_SAMPLE_BEGIN: {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ case EYE_MODAL_CANCEL: {
+ eyedropper_gpencil_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ case EYE_MODAL_SAMPLE_CONFIRM: {
+ eyedropper_gpencil_color_sample(C, eye, event->x, event->y);
+
+ /* Create material. */
+ eyedropper_gpencil_color_set(C, event, eye);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ eyedropper_gpencil_exit(C, op);
+ return OPERATOR_FINISHED;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ break;
+ }
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE: {
+ eyedropper_gpencil_color_sample(C, eye, event->x, event->y);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int eyedropper_gpencil_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* Init. */
+ if (eyedropper_gpencil_init(C, op)) {
+ /* Add modal temp handler. */
+ WM_event_add_modal_handler(C, op);
+ /* Status message. */
+ eyedropper_gpencil_status_indicators(C);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ return OPERATOR_PASS_THROUGH;
+ }
+}
+
+/* Repeat operator */
+static int eyedropper_gpencil_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (eyedropper_gpencil_init(C, op)) {
+
+ /* cleanup */
+ eyedropper_gpencil_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_PASS_THROUGH;
+ }
+}
+
+static bool eyedropper_gpencil_poll(bContext *C)
+{
+ /* Only valid if the current active object is grease pencil. */
+ Object *obact = CTX_data_active_object(C);
+ if ((obact == NULL) || (obact->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ /* Test we have a window below. */
+ return (CTX_wm_window(C) != NULL);
+}
+
+void UI_OT_eyedropper_gpencil_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Eyedropper";
+ ot->idname = "UI_OT_eyedropper_gpencil_color";
+ ot->description = "Sample a color from the Blender Window and create Grease Pencil material";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_gpencil_invoke;
+ ot->modal = eyedropper_gpencil_modal;
+ ot->cancel = eyedropper_gpencil_cancel;
+ ot->exec = eyedropper_gpencil_exec;
+ ot->poll = eyedropper_gpencil_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index cc13c4004a4..83820c919c8 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -108,6 +108,7 @@ static int ui_do_but_EXIT(bContext *C,
const wmEvent *event);
static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b);
static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str);
+static void button_tooltip_timer_reset(bContext *C, uiBut *but);
#ifdef USE_KEYNAV_LIMIT
static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event);
@@ -3258,7 +3259,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_but_update(but);
- WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT);
#ifdef WITH_INPUT_IME
if (is_num_but == false && BLT_lang_is_ime_supported()) {
@@ -3967,8 +3968,11 @@ static bool ui_do_but_extra_operator_icon(bContext *C,
uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data, event);
if (op_icon) {
+ ED_region_tag_redraw(data->region);
+ button_tooltip_timer_reset(C, but);
+
ui_but_extra_operator_icon_apply(C, but, op_icon);
- button_activate_exit(C, but, data, false, false);
+ /* Note: 'but', 'data' may now be freed, don't access. */
return true;
}
@@ -4217,9 +4221,8 @@ static int ui_do_but_TEX(
}
else if (!ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ return WM_UI_HANDLER_BREAK;
}
-
- return WM_UI_HANDLER_BREAK;
}
}
else if (data->state == BUTTON_STATE_TEXT_EDITING) {
@@ -4686,7 +4689,7 @@ static void ui_numedit_set_active(uiBut *but)
}
else {
if (data->changed_cursor == false) {
- WM_cursor_modal_set(data->window, CURSOR_X_MOVE);
+ WM_cursor_modal_set(data->window, WM_CURSOR_X_MOVE);
data->changed_cursor = true;
}
}
@@ -7494,6 +7497,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData");
data->wm = CTX_wm_manager(C);
data->window = CTX_wm_window(C);
+ BLI_assert(ar != NULL);
data->region = ar;
#ifdef USE_CONT_MOUSE_CORRECT
@@ -7565,7 +7569,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
if (but->type == UI_BTYPE_GRIP) {
const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect));
- WM_cursor_modal_set(data->window, horizontal ? CURSOR_X_MOVE : CURSOR_Y_MOVE);
+ WM_cursor_modal_set(data->window, horizontal ? WM_CURSOR_X_MOVE : WM_CURSOR_Y_MOVE);
}
else if (but->type == UI_BTYPE_NUM) {
ui_numedit_set_active(but);
@@ -8006,6 +8010,7 @@ void ui_but_execute_begin(struct bContext *UNUSED(C),
*active_back = but->active;
data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData_Fake");
but->active = data;
+ BLI_assert(ar != NULL);
data->region = ar;
}
@@ -9817,9 +9822,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
if (but && (U.pie_menu_confirm > 0) &&
(dist >= U.dpi_fac * (U.pie_menu_threshold + U.pie_menu_confirm))) {
- if (but) {
- return ui_but_pie_menu_apply(C, menu, but, true);
- }
+ return ui_but_pie_menu_apply(C, menu, but, true);
}
retval = ui_but_pie_menu_apply(C, menu, but, true);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index b844e237366..1495fb7e716 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1583,7 +1583,6 @@ static struct {
IconTextureDrawCall normal;
IconTextureDrawCall border;
bool enabled;
- float mat[4][4];
} g_icon_draw_cache = {{{{{0}}}}};
void UI_icon_draw_cache_begin(void)
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index e1ce77b8b61..b7fd953ed63 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -171,12 +171,13 @@ void icon_draw_rect_input(float x,
const bool simple_text = false;
- if ((event_type >= AKEY) || (ZKEY <= event_type)) {
+ if ((event_type >= AKEY) && (event_type <= ZKEY)) {
char str[2] = {'A' + (event_type - AKEY), '\0'};
icon_draw_rect_input_default_text(&rect, color, margin, str);
}
- if ((event_type >= F1KEY) || (F12KEY <= event_type)) {
- char str[3] = {'F', '1' + (event_type - F1KEY), '\0'};
+ else if ((event_type >= F1KEY) && (event_type <= F12KEY)) {
+ char str[4];
+ SNPRINTF(str, "F%d", 1 + (event_type - F1KEY));
icon_draw_rect_input_default_text(&rect, color, margin, str);
}
else if (event_type == LEFTSHIFTKEY) {
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 5c73b41b778..81979b1fc8f 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -971,6 +971,9 @@ void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
/* interface_eyedropper_driver.c */
void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
+/* interface_eyedropper_gpencil_color.c */
+void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot);
+
/* interface_util.c */
/**
@@ -993,4 +996,7 @@ void ui_rna_collection_search_cb(const struct bContext *C,
/* interface_ops.c */
bool ui_jump_to_target_button_poll(struct bContext *C);
+/* interface_queries.c */
+void ui_interface_tag_script_reload_queries(void);
+
#endif /* __INTERFACE_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 6a707b56f36..a6f8ba4560d 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -130,8 +130,8 @@ typedef struct uiItem {
} uiItem;
enum {
- UI_ITEM_FIXED = 1 << 0,
- UI_ITEM_MIN = 1 << 1,
+ UI_ITEM_AUTO_FIXED_SIZE = 1 << 0,
+ UI_ITEM_FIXED_SIZE = 1 << 1,
UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
UI_ITEM_PROP_SEP = 1 << 3,
@@ -307,7 +307,7 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool
return unit_x; /* No icon or name. */
}
if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
- layout->item.flag |= UI_ITEM_MIN;
+ layout->item.flag |= UI_ITEM_FIXED_SIZE;
}
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float margin = compact ? 1.25 : 1.50;
@@ -3269,7 +3269,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
litem->w += itemw;
litem->h = MAX2(itemh, litem->h);
@@ -3280,7 +3280,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
}
if (min_size_flag) {
- litem->item.flag |= UI_ITEM_MIN;
+ litem->item.flag |= UI_ITEM_FIXED_SIZE;
}
}
@@ -3326,7 +3326,7 @@ static void ui_litem_layout_row(uiLayout *litem)
extra_pixel = 0.0f;
for (item = litem->items.first; item; item = item->next) {
- if (item->flag & UI_ITEM_FIXED) {
+ if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
continue;
}
@@ -3342,18 +3342,19 @@ static void ui_litem_layout_row(uiLayout *litem)
x += neww;
- bool min_flag = item->flag & UI_ITEM_MIN;
+ bool min_flag = item->flag & UI_ITEM_FIXED_SIZE;
/* ignore min flag for rows with right or center alignment */
if (item->type != ITEM_BUTTON &&
ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) &&
- litem->alignment == UI_LAYOUT_ALIGN_EXPAND && ((uiItem *)litem)->flag & UI_ITEM_MIN) {
+ litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
+ ((uiItem *)litem)->flag & UI_ITEM_FIXED_SIZE) {
min_flag = false;
}
if ((neww < minw || min_flag) && w != 0) {
/* fixed size */
- item->flag |= UI_ITEM_FIXED;
- if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ item->flag |= UI_ITEM_AUTO_FIXED_SIZE;
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
minw = itemw;
}
fixedw += minw;
@@ -3362,7 +3363,7 @@ static void ui_litem_layout_row(uiLayout *litem)
}
else {
/* keep free size */
- item->flag &= ~UI_ITEM_FIXED;
+ item->flag &= ~UI_ITEM_AUTO_FIXED_SIZE;
freew += itemw;
}
}
@@ -3380,9 +3381,9 @@ static void ui_litem_layout_row(uiLayout *litem)
ui_item_size(item, &itemw, &itemh);
minw = ui_litem_min_width(itemw);
- if (item->flag & UI_ITEM_FIXED) {
+ if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
/* fixed minimum size items */
- if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
minw = itemw;
}
itemw = ui_item_fit(
@@ -3423,7 +3424,7 @@ static void ui_litem_layout_row(uiLayout *litem)
uiItem *last_item = litem->items.last;
extra_pixel = litem->w - (x - litem->x);
if (extra_pixel > 0 && litem->alignment == UI_LAYOUT_ALIGN_EXPAND && last_free_item &&
- last_item && last_item->flag & UI_ITEM_FIXED) {
+ last_item && last_item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
ui_item_move(last_free_item, 0, extra_pixel);
for (item = last_free_item->next; item; item = item->next) {
ui_item_move(item, extra_pixel, extra_pixel);
@@ -3449,7 +3450,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
litem->w = MAX2(litem->w, itemw);
litem->h += itemh;
@@ -3460,7 +3461,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
}
if (min_size_flag) {
- litem->item.flag |= UI_ITEM_MIN;
+ litem->item.flag |= UI_ITEM_FIXED_SIZE;
}
}
@@ -4279,7 +4280,7 @@ static void ui_litem_layout_absolute(uiLayout *litem)
static void ui_litem_estimate_split(uiLayout *litem)
{
ui_litem_estimate_row(litem);
- litem->item.flag &= ~UI_ITEM_MIN;
+ litem->item.flag &= ~UI_ITEM_FIXED_SIZE;
}
static void ui_litem_layout_split(uiLayout *litem)
@@ -5099,7 +5100,7 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
/* XXX uiBut hasn't scaled yet
* we can flag the button as not expandable, depending on its size */
if (w <= 2 * UI_UNIT_X && (!but->str || but->str[0] == '\0')) {
- bitem->item.flag |= UI_ITEM_MIN;
+ bitem->item.flag |= UI_ITEM_FIXED_SIZE;
}
if (layout->child_items_layout) {
@@ -5119,6 +5120,21 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
}
}
+void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
+{
+ if (fixed_size) {
+ layout->item.flag |= UI_ITEM_FIXED_SIZE;
+ }
+ else {
+ layout->item.flag &= ~UI_ITEM_FIXED_SIZE;
+ }
+}
+
+bool uiLayoutGetFixedSize(uiLayout *layout)
+{
+ return (layout->item.flag & UI_ITEM_FIXED_SIZE) != 0;
+}
+
void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
{
layout->root->opcontext = opcontext;
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index b3c46dda4c3..7ce4242c697 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -221,7 +221,7 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *op)
static void UI_OT_copy_as_driver_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy As New Driver";
+ ot->name = "Copy as New Driver";
ot->idname = "UI_OT_copy_as_driver_button";
ot->description =
"Create a new driver with this property as input, and copy it to the "
@@ -453,7 +453,7 @@ static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_unset_property_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Unset property";
+ ot->name = "Unset Property";
ot->idname = "UI_OT_unset_property_button";
ot->description = "Clear the property and use default or generated value in operators";
@@ -944,7 +944,7 @@ static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy To Selected";
+ ot->name = "Copy to Selected";
ot->idname = "UI_OT_copy_to_selected_button";
ot->description = "Copy property from this object to selected objects or bones";
@@ -1092,7 +1092,7 @@ static int jump_to_target_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_jump_to_target_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Jump To Target";
+ ot->name = "Jump to Target";
ot->idname = "UI_OT_jump_to_target_button";
ot->description = "Switch to the target object or bone";
@@ -1751,6 +1751,7 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_eyedropper_id);
WM_operatortype_append(UI_OT_eyedropper_depth);
WM_operatortype_append(UI_OT_eyedropper_driver);
+ WM_operatortype_append(UI_OT_eyedropper_gpencil_color);
}
/**
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 1c3d99d8bd2..34b1070f8b4 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -137,15 +137,15 @@ bool ui_but_has_array_value(const uiBut *but)
PROP_COORDS));
}
+static wmOperatorType *g_ot_tool_set_by_id = NULL;
bool UI_but_is_tool(const uiBut *but)
{
/* very evil! */
if (but->optype != NULL) {
- static wmOperatorType *ot = NULL;
- if (ot == NULL) {
- ot = WM_operatortype_find("WM_OT_tool_set_by_id", false);
+ if (g_ot_tool_set_by_id == NULL) {
+ g_ot_tool_set_by_id = WM_operatortype_find("WM_OT_tool_set_by_id", false);
}
- if (but->optype == ot) {
+ if (but->optype == g_ot_tool_set_by_id) {
return true;
}
}
@@ -463,14 +463,33 @@ bool ui_block_is_popup_any(const uiBlock *block)
return (ui_block_is_menu(block) || ui_block_is_popover(block) || ui_block_is_pie_menu(block));
}
-bool UI_block_is_empty(const uiBlock *block)
+static const uiBut *ui_but_next_non_separator(const uiBut *but)
{
- for (const uiBut *but = block->buttons.first; but; but = but->next) {
+ for (; but; but = but->next) {
if (!ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
- return false;
+ return but;
}
}
- return true;
+ return NULL;
+}
+
+bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title)
+{
+ const uiBut *but = block->buttons.first;
+ if (skip_title) {
+ /* Skip the first label, since popups often have a title,
+ * we may want to consider the block empty in this case. */
+ but = ui_but_next_non_separator(but);
+ if (but && but->type == UI_BTYPE_LABEL) {
+ but = but->next;
+ }
+ }
+ return (ui_but_next_non_separator(but) == NULL);
+}
+
+bool UI_block_is_empty(const uiBlock *block)
+{
+ return UI_block_is_empty_ex(block, false);
}
bool UI_block_can_add_separator(const uiBlock *block)
@@ -596,3 +615,14 @@ ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const wmEvent *event)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Manage Internal State
+ * \{ */
+
+void ui_interface_tag_script_reload_queries(void)
+{
+ g_ot_tool_set_by_id = NULL;
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index ab3a86ec9e1..fed3c0b3d11 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -474,7 +474,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup)
{
- if (!UI_block_is_empty(pup->block)) {
+ if (!UI_block_is_empty_ex(pup->block, true)) {
UI_popup_menu_end(C, pup);
return true;
}
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index 028d99ac052..cd0421dde09 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -334,7 +334,8 @@ int UI_popover_panel_invoke(bContext *C, const char *idname, bool keep_open, Rep
}
if (block) {
- UI_block_active_only_flagged_buttons(C, CTX_wm_region(C), block);
+ uiPopupBlockHandle *handle = block->handle;
+ UI_block_active_only_flagged_buttons(C, handle->region, block);
}
return OPERATOR_INTERFACE;
}
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 2073117d51c..63dee77e90e 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -765,7 +765,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
UI_but_tooltip_timer_remove(C, activebut);
}
/* standard cursor by default */
- WM_cursor_set(window, CURSOR_STD);
+ WM_cursor_set(window, WM_CURSOR_DEFAULT);
/* create handle */
handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index aac018db24e..fe484676ddd 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -3674,7 +3674,7 @@ void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Vectorscope Template
+/** \name Vector-Scope Template
* \{ */
void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 0ee2ed0f338..b3e039292e1 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -4521,7 +4521,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
}
/* align with open menu */
- if (but->active && (but->type != UI_BTYPE_POPOVER)) {
+ if (but->active && (but->type != UI_BTYPE_POPOVER) && !ui_but_menu_draw_as_popover(but)) {
int direction = ui_but_menu_direction(but);
if (direction == UI_DIR_UP) {
@@ -4638,9 +4638,6 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
case UI_BTYPE_SEARCH_MENU:
wt = widget_type(UI_WTYPE_NAME);
- if (but->block->theme_style == UI_BLOCK_THEME_STYLE_POPUP) {
- wt->wcol_theme = &btheme->tui.wcol_menu_back;
- }
break;
case UI_BTYPE_TAB:
@@ -4914,7 +4911,10 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol,
{
/* tsk, this isn't nice. */
const float unit_half = unit_size / 2;
- const float cent_x = mval_origin ? mval_origin[0] : BLI_rcti_cent_x(rect);
+ const float cent_x = mval_origin ? CLAMPIS(mval_origin[0],
+ rect->xmin + unit_size,
+ rect->xmax - unit_size) :
+ BLI_rcti_cent_x(rect);
rect->ymax -= unit_half;
rect->ymin += unit_half;
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index bea9af99c2e..c6125478571 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -371,7 +371,6 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_OBCENTER_DIA:
cp = &ts->obcenter_dia;
break;
- break;
case TH_EDGE:
cp = ts->edge;
break;
@@ -779,6 +778,12 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_PATH_AFTER:
cp = ts->path_after;
break;
+ case TH_PATH_KEYFRAME_BEFORE:
+ cp = ts->path_keyframe_before;
+ break;
+ case TH_PATH_KEYFRAME_AFTER:
+ cp = ts->path_keyframe_after;
+ break;
case TH_CAMERA_PATH:
cp = ts->camera_path;
break;
@@ -835,6 +840,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
cp = ts->nla_tweakdupli;
break;
+ case TH_NLA_TRACK:
+ cp = ts->nla_track;
+ break;
case TH_NLA_TRANSITION:
cp = ts->nla_transition;
break;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 4bfff5f02cf..b1a060089ee 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -1263,7 +1263,7 @@ void UI_view2d_view_restore(const bContext *C)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Gridline Drawing
+/** \name Grid-Line Drawing
* \{ */
/* Draw a constant grid in given 2d-region */
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 032fb7e4cc2..5cf7cb4e7c4 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -256,13 +256,13 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_int_set(op->ptr, "deltay", 0);
if (v2d->keepofs & V2D_LOCKOFS_X) {
- WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL);
}
else if (v2d->keepofs & V2D_LOCKOFS_Y) {
- WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL);
}
else {
- WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL);
}
/* add temp handler */
@@ -1113,13 +1113,13 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even
}
if (v2d->keepofs & V2D_LOCKOFS_X) {
- WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL);
}
else if (v2d->keepofs & V2D_LOCKOFS_Y) {
- WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL);
}
else {
- WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL);
}
/* add temp handler */
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index aac4da12658..573dfcde88a 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -604,6 +604,9 @@ static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(row, IFACE_("Options:"), ICON_NONE);
row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "relative_path", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
@@ -691,7 +694,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
FILE_BLENDER,
FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index 7e89ed9511f..837c5b1c6bd 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -89,8 +89,9 @@ bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool ED_lattice_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -634,11 +635,12 @@ static BPoint *findnearestLattvert(ViewContext *vc, int sel, Base **r_base)
bool ED_lattice_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
BPoint *bp = NULL;
Base *basact = NULL;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index b4ef2620895..7afd72f33c9 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -148,9 +148,10 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%.1f%%", RNA_float_get(op->ptr, "offset_pct"));
}
else {
+ double offset_val = (double)RNA_float_get(op->ptr, "offset");
bUnit_AsString2(offset_str,
NUM_STR_REP_LEN,
- (double)RNA_float_get(op->ptr, "offset"),
+ offset_val * sce->unit.scale_length,
3,
B_UNIT_LENGTH,
&sce->unit,
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 283e147b77b..4a511bbb5a2 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -455,7 +455,7 @@ void MESH_OT_bisect(struct wmOperatorType *ot)
0.00001,
0.1);
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
#ifdef USE_GIZMO
WM_gizmogrouptype_append(MESH_GGT_bisect);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
index 7155348fed5..993898bddd5 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
@@ -522,7 +522,6 @@ typedef struct GizmoGroupData_SpinRedo {
PropertyRNA *prop_axis_no;
PropertyRNA *prop_angle;
- float rotate_axis[3];
#ifdef USE_ANGLE_Z_ORIENT
/* Apply 'orient_mat' for the final value. */
float orient_axis_relative[3];
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 370cc6a2a6d..ec740447f93 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -101,17 +101,19 @@ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data))
/**
* Use for intersect and boolean.
*/
-static void edbm_intersect_select(BMEditMesh *em)
+static void edbm_intersect_select(BMEditMesh *em, bool do_select)
{
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ if (do_select) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
- BMIter iter;
- BMEdge *e;
+ if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ BMIter iter;
+ BMEdge *e;
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_edge_select_set(em->bm, e, true);
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_edge_select_set(em->bm, e, true);
+ }
}
}
}
@@ -210,10 +212,9 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
em->bm, BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT));
}
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
@@ -317,10 +318,9 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
boolean_operation,
eps);
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 61f9dc43c0f..395c614f328 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2777,7 +2777,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
op->flag |= OP_IS_MODAL_CURSOR_REGION;
/* add a modal handler for this operator - handles loop selection */
- WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_KNIFE);
WM_event_add_modal_handler(C, op);
knifetool_update_mval_i(kcd, event->mval);
@@ -2804,8 +2804,8 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
static const EnumPropertyItem modal_items[] = {
{KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
{KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
- {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""},
- {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""},
+ {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap to Midpoints On", ""},
+ {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap to Midpoints Off", ""},
{KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""},
{KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""},
{KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""},
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 3d34a4ad3b5..a709bd010aa 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -22,6 +22,7 @@
*/
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
@@ -142,10 +143,21 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- /* not essential, but switch out of vertex mode since the
- * selected regions wont be nicely isolated after flushing.
- * note: call after de-select to avoid selection flushing */
- EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *embm = me->edit_mesh;
+ if (embm) {
+ /* not essential, but switch out of vertex mode since the
+ * selected regions wont be nicely isolated after flushing.
+ * note: call after de-select to avoid selection flushing.
+ * note: do this on all participating meshes so this is in sync
+ * e.g. for later selection picking, see T68852.*/
+ EDBM_selectmode_disable(scene, embm, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ }
+ }
+ }
+ CTX_DATA_END;
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 3be94cf99c1..3c3e91e8afe 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -386,7 +386,6 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
bool ok = true;
if (is_interactive == false) {
if (exec_data.base_index >= bases_len) {
- return OPERATOR_CANCELLED;
ok = false;
}
else {
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 6d51e1d3393..8d98a3bf231 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -101,16 +101,21 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
BMIter face_iter;
/* Delete all unmasked faces */
+ const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
+ BLI_assert(cd_vert_mask_offset != -1);
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
float mask_threshold = RNA_float_get(op->ptr, "mask_threshold");
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- bool delete_face = false;
+ bool keep_face = true;
BM_ITER_ELEM (v, &face_iter, f, BM_VERTS_OF_FACE) {
- float mask = BM_elem_float_data_get(&bm->vdata, v, CD_PAINT_MASK);
- delete_face = mask < mask_threshold;
+ const float mask = BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
+ if (mask < mask_threshold) {
+ keep_face = false;
+ break;
+ }
}
- BM_elem_flag_set(f, BM_ELEM_TAG, delete_face);
+ BM_elem_flag_set(f, BM_ELEM_TAG, !keep_face);
}
BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
@@ -173,15 +178,16 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
}
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- BKE_editmesh_free_derivedmesh(em);
BKE_mesh_free(new_mesh);
new_mesh = BKE_mesh_from_bmesh_nomain(bm,
(&(struct BMeshToMeshParams){
.calc_object_remap = false,
- }));
+ }),
+ mesh);
- BM_mesh_free(bm);
+ BKE_editmesh_free(em);
+ MEM_freeN(em);
if (new_mesh->totvert == 0) {
BKE_mesh_free(new_mesh);
@@ -195,8 +201,6 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
Object *new_ob = ED_object_add_type(C, OB_MESH, NULL, ob->loc, ob->rot, false, local_view_bits);
BKE_mesh_nomain_to_mesh(new_mesh, new_ob->data, new_ob, &CD_MASK_EVERYTHING, true);
- BKE_mesh_free(new_mesh);
-
if (RNA_boolean_get(op->ptr, "apply_shrinkwrap")) {
BKE_shrinkwrap_mesh_nearest_surface_deform(C, new_ob, ob);
}
@@ -211,6 +215,8 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
}
}
+ BKE_mesh_calc_normals(new_ob->data);
+
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob);
BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index cad9e9a3d06..3e59a884696 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2642,8 +2642,9 @@ bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool EDBM_mesh_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -4219,7 +4220,8 @@ void MESH_OT_select_nth(wmOperatorType *ot)
void em_setup_viewcontext(bContext *C, ViewContext *vc)
{
- ED_view3d_viewcontext_init(C, vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, vc, depsgraph);
if (vc->obedit) {
vc->em = BKE_editmesh_from_object(vc->obedit);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 0c4db012786..a20ae5fc1ac 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3161,7 +3161,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
- BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count_multi);
+ BKE_reportf(op->reports, RPT_INFO, "Removed %d vertice(s)", count_multi);
return OPERATOR_FINISHED;
}
@@ -3872,7 +3872,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
/* internal */
RNA_def_int(
- ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
+ ot->srna, "cursor", WM_CURSOR_KNIFE, 0, WM_CURSOR_NUM, "Cursor", "", 0, WM_CURSOR_NUM);
}
/** \} */
@@ -3946,6 +3946,61 @@ static Base *mesh_separate_tagged(
return base_new;
}
+static Base *mesh_separate_arrays(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ Base *base_old,
+ BMesh *bm_old,
+ BMVert **verts,
+ uint verts_len,
+ BMEdge **edges,
+ uint edges_len,
+ BMFace **faces,
+ uint faces_len)
+{
+ Base *base_new;
+ Object *obedit = base_old->object;
+ BMesh *bm_new;
+
+ bm_new = BM_mesh_create(&bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0);
+ CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0);
+ CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0);
+ CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0);
+
+ CustomData_bmesh_init_pool(&bm_new->vdata, verts_len, BM_VERT);
+ CustomData_bmesh_init_pool(&bm_new->edata, edges_len, BM_EDGE);
+ CustomData_bmesh_init_pool(&bm_new->ldata, faces_len * 3, BM_LOOP);
+ CustomData_bmesh_init_pool(&bm_new->pdata, faces_len, BM_FACE);
+
+ base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, USER_DUP_MESH);
+
+ /* normally would call directly after but in this case delay recalc */
+ /* DAG_relations_tag_update(bmain); */
+
+ /* new in 2.5 */
+ assign_matarar(bmain, base_new->object, give_matarar(obedit), *give_totcolp(obedit));
+
+ ED_object_base_select(base_new, BA_SELECT);
+
+ BM_mesh_copy_arrays(bm_old, bm_new, verts, verts_len, edges, edges_len, faces, faces_len);
+
+ for (uint i = 0; i < verts_len; i++) {
+ BM_vert_kill(bm_old, verts[i]);
+ }
+
+ BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
+
+ BM_mesh_free(bm_new);
+ ((Mesh *)base_new->object->data)->edit_mesh = NULL;
+
+ return base_new;
+}
+
static bool mesh_separate_selected(
Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
{
@@ -3959,41 +4014,6 @@ static bool mesh_separate_selected(
return (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL);
}
-/* flush a hflag to from verts to edges/faces */
-static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag)
-{
- BMEdge *e;
- BMLoop *l_iter;
- BMLoop *l_first;
- BMFace *f;
-
- BMIter eiter;
- BMIter fiter;
-
- bool ok;
-
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e->v1, hflag) && BM_elem_flag_test(e->v2, hflag)) {
- BM_elem_flag_enable(e, hflag);
- }
- else {
- BM_elem_flag_disable(e, hflag);
- }
- }
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- ok = true;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (!BM_elem_flag_test(l_iter->v, hflag)) {
- ok = false;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
-
- BM_elem_flag_set(f, hflag, ok);
- }
-}
-
/**
* Sets an object to a single material. from one of its slots.
*
@@ -4109,72 +4129,64 @@ static bool mesh_separate_material(
static bool mesh_separate_loose(
Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
{
- int i;
- BMEdge *e;
- BMVert *v_seed;
- BMWalker walker;
- bool result = false;
- int max_iter = bm_old->totvert;
+ /* Without this, we duplicate the object mode mesh for each loose part.
+ * This can get very slow especially for large meshes with many parts
+ * which would duplicate the mesh on entering edit-mode. */
+ const bool clear_object_data = true;
- /* Clear all selected vertices */
- BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ bool result = false;
- /* A "while (true)" loop should work here as each iteration should
- * select and remove at least one vertex and when all vertices
- * are selected the loop will break out. But guard against bad
- * behavior by limiting iterations to the number of vertices in the
- * original mesh.*/
- for (i = 0; i < max_iter; i++) {
- int tot = 0;
- /* Get a seed vertex to start the walk */
- v_seed = BM_iter_at_index(bm_old, BM_VERTS_OF_MESH, NULL, 0);
+ BMVert **vert_groups = MEM_mallocN(sizeof(*vert_groups) * bm_old->totvert, __func__);
+ BMEdge **edge_groups = MEM_mallocN(sizeof(*edge_groups) * bm_old->totedge, __func__);
+ BMFace **face_groups = MEM_mallocN(sizeof(*face_groups) * bm_old->totface, __func__);
+
+ int(*groups)[3] = NULL;
+ int groups_len = BM_mesh_calc_edge_groups_as_arrays(
+ bm_old, vert_groups, edge_groups, face_groups, &groups);
+ if (groups_len <= 1) {
+ goto finally;
+ }
+
+ if (clear_object_data) {
+ ED_mesh_geometry_clear(base_old->object->data);
+ }
+
+ /* Separate out all groups except the first. */
+ uint group_ofs[3] = {UNPACK3(groups[0])};
+ for (int i = 1; i < groups_len; i++) {
+ Base *base_new = mesh_separate_arrays(bmain,
+ scene,
+ view_layer,
+ base_old,
+ bm_old,
+ vert_groups + group_ofs[0],
+ groups[i][0],
+ edge_groups + group_ofs[1],
+ groups[i][1],
+ face_groups + group_ofs[2],
+ groups[i][2]);
+ result |= (base_new != NULL);
- /* No vertices available, can't do anything */
- if (v_seed == NULL) {
- break;
- }
+ group_ofs[0] += groups[i][0];
+ group_ofs[1] += groups[i][1];
+ group_ofs[2] += groups[i][2];
+ }
- /* Select the seed explicitly, in case it has no edges */
- if (!BM_elem_flag_test(v_seed, BM_ELEM_TAG)) {
- BM_elem_flag_enable(v_seed, BM_ELEM_TAG);
- tot++;
- }
+ Mesh *me_old = base_old->object->data;
+ BMEditMesh *em_old = me_old->edit_mesh;
- /* Walk from the single vertex, selecting everything connected
- * to it */
- BMW_init(&walker,
- bm_old,
- BMW_VERT_SHELL,
- BMW_MASK_NOP,
- BMW_MASK_NOP,
- BMW_MASK_NOP,
- BMW_FLAG_NOP,
- BMW_NIL_LAY);
+ BM_mesh_elem_hflag_disable_all(em_old->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- for (e = BMW_begin(&walker, v_seed); e; e = BMW_step(&walker)) {
- if (!BM_elem_flag_test(e->v1, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- tot++;
- }
- if (!BM_elem_flag_test(e->v2, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
- tot++;
- }
- }
- BMW_end(&walker);
-
- if (bm_old->totvert == tot) {
- /* Every vertex selected, nothing to separate, work is done */
- break;
- }
+ if (clear_object_data) {
+ BM_mesh_bm_to_me(NULL, em_old->bm, me_old, (&(struct BMeshToMeshParams){0}));
+ }
- /* Flush the selection to get edge/face selections matching
- * the vertex selection */
- bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG);
+finally:
+ MEM_freeN(vert_groups);
+ MEM_freeN(edge_groups);
+ MEM_freeN(face_groups);
- /* Move selection into a separate object */
- result |= (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL);
- }
+ MEM_freeN(groups);
return result;
}
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 569994bead1..7007ff29401 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -880,14 +880,14 @@ void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot)
void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_loose)
{
- if (calc_edges_loose && mesh->totedge) {
- BKE_mesh_calc_edges_loose(mesh);
- }
-
if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0)) {
BKE_mesh_calc_edges(mesh, calc_edges, true);
}
+ if (calc_edges_loose && mesh->totedge) {
+ BKE_mesh_calc_edges_loose(mesh);
+ }
+
/* Default state is not to have tessface's so make sure this is the case. */
BKE_mesh_tessface_clear(mesh);
@@ -1023,73 +1023,104 @@ static void mesh_add_polys(Mesh *mesh, int len)
mesh->totpoly = totpoly;
}
-static void mesh_remove_verts(Mesh *mesh, int len)
+/* -------------------------------------------------------------------- */
+/** \name Add Geometry
+ * \{ */
+
+void ED_mesh_verts_add(Mesh *mesh, ReportList *reports, int count)
{
- int totvert;
+ if (mesh->edit_mesh) {
+ BKE_report(reports, RPT_ERROR, "Cannot add vertices in edit mode");
+ return;
+ }
+ mesh_add_verts(mesh, count);
+}
- if (len == 0) {
+void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count)
+{
+ if (mesh->edit_mesh) {
+ BKE_report(reports, RPT_ERROR, "Cannot add edges in edit mode");
+ return;
+ }
+ mesh_add_edges(mesh, count);
+}
+
+void ED_mesh_loops_add(Mesh *mesh, ReportList *reports, int count)
+{
+ if (mesh->edit_mesh) {
+ BKE_report(reports, RPT_ERROR, "Cannot add loops in edit mode");
return;
}
+ mesh_add_loops(mesh, count);
+}
- totvert = mesh->totvert - len;
- CustomData_free_elem(&mesh->vdata, totvert, len);
+void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count)
+{
+ if (mesh->edit_mesh) {
+ BKE_report(reports, RPT_ERROR, "Cannot add polygons in edit mode");
+ return;
+ }
+ mesh_add_polys(mesh, count);
+}
- /* set final vertex list size */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Geometry
+ * \{ */
+
+static void mesh_remove_verts(Mesh *mesh, int len)
+{
+ if (len == 0) {
+ return;
+ }
+ const int totvert = mesh->totvert - len;
+ CustomData_free_elem(&mesh->vdata, totvert, len);
mesh->totvert = totvert;
}
static void mesh_remove_edges(Mesh *mesh, int len)
{
- int totedge;
-
if (len == 0) {
return;
}
-
- totedge = mesh->totedge - len;
+ const int totedge = mesh->totedge - len;
CustomData_free_elem(&mesh->edata, totedge, len);
-
mesh->totedge = totedge;
}
-#if 0
-void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces)
+static void mesh_remove_loops(Mesh *mesh, int len)
{
- if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add geometry in edit mode");
+ if (len == 0) {
return;
}
-
- if (verts) {
- mesh_add_verts(mesh, verts);
- }
- if (edges) {
- mesh_add_edges(mesh, edges);
- }
- if (faces) {
- mesh_add_faces(mesh, faces);
- }
+ const int totloop = mesh->totloop - len;
+ CustomData_free_elem(&mesh->ldata, totloop, len);
+ mesh->totloop = totloop;
}
-#endif
-void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count)
+static void mesh_remove_polys(Mesh *mesh, int len)
{
- if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add edges in edit mode");
+ if (len == 0) {
return;
}
-
- mesh_add_edges(mesh, count);
+ const int totpoly = mesh->totpoly - len;
+ CustomData_free_elem(&mesh->pdata, totpoly, len);
+ mesh->totpoly = totpoly;
}
-void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count)
+void ED_mesh_verts_remove(Mesh *mesh, ReportList *reports, int count)
{
if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add vertices in edit mode");
+ BKE_report(reports, RPT_ERROR, "Cannot remove vertices in edit mode");
+ return;
+ }
+ else if (count > mesh->totvert) {
+ BKE_report(reports, RPT_ERROR, "Cannot remove more vertices than the mesh contains");
return;
}
- mesh_add_verts(mesh, count);
+ mesh_remove_verts(mesh, count);
}
void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count)
@@ -1106,40 +1137,44 @@ void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count)
mesh_remove_edges(mesh, count);
}
-void ED_mesh_vertices_remove(Mesh *mesh, ReportList *reports, int count)
+void ED_mesh_loops_remove(Mesh *mesh, ReportList *reports, int count)
{
if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot remove vertices in edit mode");
+ BKE_report(reports, RPT_ERROR, "Cannot remove loops in edit mode");
return;
}
- else if (count > mesh->totvert) {
- BKE_report(reports, RPT_ERROR, "Cannot remove more vertices than the mesh contains");
+ else if (count > mesh->totloop) {
+ BKE_report(reports, RPT_ERROR, "Cannot remove more loops than the mesh contains");
return;
}
- mesh_remove_verts(mesh, count);
+ mesh_remove_loops(mesh, count);
}
-void ED_mesh_loops_add(Mesh *mesh, ReportList *reports, int count)
+void ED_mesh_polys_remove(Mesh *mesh, ReportList *reports, int count)
{
if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add loops in edit mode");
+ BKE_report(reports, RPT_ERROR, "Cannot remove polys in edit mode");
+ return;
+ }
+ else if (count > mesh->totpoly) {
+ BKE_report(reports, RPT_ERROR, "Cannot remove more polys than the mesh contains");
return;
}
- mesh_add_loops(mesh, count);
+ mesh_remove_polys(mesh, count);
}
-void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count)
+void ED_mesh_geometry_clear(Mesh *mesh)
{
- if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add polygons in edit mode");
- return;
- }
-
- mesh_add_polys(mesh, count);
+ mesh_remove_verts(mesh, mesh->totvert);
+ mesh_remove_edges(mesh, mesh->totedge);
+ mesh_remove_loops(mesh, mesh->totloop);
+ mesh_remove_polys(mesh, mesh->totpoly);
}
+/** \} */
+
void ED_mesh_report_mirror_ex(wmOperator *op, int totmirr, int totfail, char selectmode)
{
const char *elem_type;
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index c68f5963cbd..a918996563f 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -54,6 +54,7 @@
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
+#include "BKE_object_facemap.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
@@ -267,6 +268,22 @@ static void join_mesh_single(Depsgraph *depsgraph,
mpoly->loopstart += *loopofs;
mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
}
+
+ /* Face maps. */
+ int *fmap = CustomData_get(pdata, *polyofs, CD_FACEMAP);
+ int *fmap_src = CustomData_get(&me->pdata, 0, CD_FACEMAP);
+
+ /* Remap to correct new face-map indices, if needed. */
+ if (fmap_src) {
+ BLI_assert(fmap != NULL);
+ int *fmap_index_map;
+ int fmap_index_map_len;
+ fmap_index_map = BKE_object_facemap_index_map_create(ob_src, ob_dst, &fmap_index_map_len);
+ BKE_object_facemap_index_map_apply(fmap, me->totpoly, fmap_index_map, fmap_index_map_len);
+ if (fmap_index_map != NULL) {
+ MEM_freeN(fmap_index_map);
+ }
+ }
}
/* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
@@ -403,7 +420,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
key->type = KEY_RELATIVE;
}
- /* first pass over objects - copying materials and vertexgroups across */
+ /* First pass over objects: Copying materials, vertex-groups & face-maps across. */
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
/* only act if a mesh, and not the one we're joining to */
if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
@@ -422,6 +439,19 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ob->actdef = 1;
}
+ /* Join this object's face maps to the base one's. */
+ for (bFaceMap *fmap = ob_iter->fmaps.first; fmap; fmap = fmap->next) {
+ /* See if this group exists in the object (if it doesn't, add it to the end) */
+ if (BKE_object_facemap_find_name(ob, fmap->name) == NULL) {
+ bFaceMap *fmap_new = MEM_callocN(sizeof(bFaceMap), "join faceMap");
+ memcpy(fmap_new, fmap, sizeof(bFaceMap));
+ BLI_addtail(&ob->fmaps, fmap_new);
+ }
+ }
+ if (ob->fmaps.first && ob->actfmap == 0) {
+ ob->actfmap = 1;
+ }
+
if (me->totvert) {
/* Add this object's materials to the base one's if they don't exist already
* (but only if limits not exceeded yet) */
@@ -1110,7 +1140,8 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
return false;
}
- ED_view3d_viewcontext_init(C, &vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_select_id_validate(&vc);
if (dist_px) {
@@ -1291,7 +1322,8 @@ bool ED_mesh_pick_vert(
return false;
}
- ED_view3d_viewcontext_init(C, &vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_select_id_validate(&vc);
if (use_zbuf) {
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 18ff7ae1a5e..64ae75a0ee8 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -693,13 +693,14 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
* stiffness circle) */
bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
static MetaElem *startelem = NULL;
ViewContext vc;
int a, hits;
unsigned int buffer[MAXPICKBUF];
rcti rect;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
BLI_rcti_init_pt_radius(&rect, mval, 12);
@@ -835,8 +836,9 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
bool ED_mball_deselect_all_multi(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 3d5ec3d4ed5..716ff94bbae 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1030,7 +1030,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
return OPERATOR_CANCELLED;
}
/* handled below */
- id_us_min((ID *)ima);
+ id_us_min(&ima->id);
Object *ob = NULL;
Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval);
@@ -1071,7 +1071,7 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Empty Image/Drop Image To Empty";
+ ot->name = "Add Empty Image/Drop Image to Empty";
ot->description = "Add an empty image type to scene with data";
ot->idname = "OBJECT_OT_drop_named_image";
@@ -2147,6 +2147,7 @@ static int convert_exec(bContext *C, wmOperator *op)
const bool gpencil_lines = RNA_boolean_get(op->ptr, "gpencil_lines");
const bool use_collections = RNA_boolean_get(op->ptr, "use_collections");
int a, mballConverted = 0;
+ bool gpencilConverted = false;
/* don't forget multiple users! */
@@ -2387,20 +2388,20 @@ static int convert_exec(bContext *C, wmOperator *op)
}
else if (target == OB_GPENCIL) {
if (ob->type != OB_CURVE) {
+ ob->flag &= ~OB_DONE;
BKE_report(
op->reports, RPT_ERROR, "Convert Surfaces to Grease Pencil is not supported.");
}
else {
- /* Create a new grease pencil object only if it was not created before.
- * All curves selected are converted as strokes of the same grease pencil object.
+ /* Create a new grease pencil object and copy transformations.
* Nurbs Surface are not supported.
*/
- if (gpencil_ob == NULL) {
- const float *cur = scene->cursor.location;
- ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
- gpencil_ob = ED_gpencil_add_object(C, scene, cur, local_view_bits);
- }
+ ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
+ gpencil_ob = ED_gpencil_add_object(C, scene, ob->loc, local_view_bits);
+ copy_v3_v3(gpencil_ob->rot, ob->rot);
+ copy_v3_v3(gpencil_ob->scale, ob->scale);
BKE_gpencil_convert_curve(bmain, scene, gpencil_ob, ob, false, false, true);
+ gpencilConverted = true;
}
}
}
@@ -2500,6 +2501,17 @@ static int convert_exec(bContext *C, wmOperator *op)
}
FOREACH_SCENE_OBJECT_END;
}
+ /* Remove curves converted to Grease Pencil object. */
+ if (gpencilConverted) {
+ FOREACH_SCENE_OBJECT_BEGIN (scene, ob_curve) {
+ if (ob_curve->type == OB_CURVE) {
+ if (ob_curve->flag & OB_DONE) {
+ ED_object_base_free_and_unlink(bmain, scene, ob_curve);
+ }
+ }
+ }
+ FOREACH_SCENE_OBJECT_END;
+ }
}
// XXX ED_object_editmode_enter(C, 0);
@@ -2585,7 +2597,7 @@ static Base *object_add_duplicate_internal(
DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
base = BKE_view_layer_base_find(view_layer, ob);
- if ((base != NULL) && (base->flag & BASE_VISIBLE)) {
+ if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
BKE_collection_object_add_from(bmain, scene, ob, obn);
}
else {
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 70a9870e6ae..bc79521ee9b 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -371,7 +371,7 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
ob = base->object;
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
/* copy data stored in job descriptor */
bkr.scene = scene;
@@ -435,7 +435,7 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
ob = base->object;
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data");
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index d9baec7c3ca..9e9cfe1beed 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -879,7 +879,7 @@ static int bake(Render *re,
else {
ob_cage_eval = DEG_get_evaluated_object(depsgraph, ob_cage);
ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER;
- ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER);
+ ob_cage_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER);
}
}
}
@@ -976,7 +976,7 @@ static int bake(Render *re,
highpoly[i].ob = ob_iter;
highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER;
- highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER);
+ highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER);
highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false);
/* lowpoly to highpoly transformation matrix */
@@ -992,10 +992,10 @@ static int bake(Render *re,
if (ob_cage != NULL) {
ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER;
- ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER);
+ ob_cage_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER);
}
ob_low_eval->restrictflag |= OB_RESTRICT_RENDER;
- ob_low_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER);
+ ob_low_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER);
/* populate the pixel arrays with the corresponding face data for each high poly object */
if (!RE_bake_pixels_populate_from_objects(me_low,
diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c
index fcaefaf220d..a00e5e7b198 100644
--- a/source/blender/editors/object/object_collection.c
+++ b/source/blender/editors/object/object_collection.c
@@ -186,7 +186,7 @@ void COLLECTION_OT_objects_add_active(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Selected To Active Collection";
+ ot->name = "Add Selected to Active Collection";
ot->description = "Add the object to an object collection that contains the active object";
ot->idname = "COLLECTION_OT_objects_add_active";
@@ -259,7 +259,7 @@ void COLLECTION_OT_objects_remove_active(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Remove Selected From Active Collection";
+ ot->name = "Remove Selected from Active Collection";
ot->description = "Remove the object from an object collection that contains the active object";
ot->idname = "COLLECTION_OT_objects_remove_active";
@@ -302,7 +302,7 @@ static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op
void COLLECTION_OT_objects_remove_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove From All Unlinked Collections";
+ ot->name = "Remove from All Unlinked Collections";
ot->description = "Remove selected objects from all collections not used in a scene";
ot->idname = "COLLECTION_OT_objects_remove_all";
@@ -361,7 +361,7 @@ void COLLECTION_OT_objects_remove(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Remove From Collection";
+ ot->name = "Remove from Collection";
ot->description = "Remove selected objects from a collection";
ot->idname = "COLLECTION_OT_objects_remove";
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 74abe104134..70d024c7902 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -218,7 +218,7 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op)
/* Hide selected or unselected objects. */
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (!(base->flag & BASE_VISIBLE)) {
+ if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) {
continue;
}
@@ -292,7 +292,7 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
if (v3d->flag & V3D_LOCAL_COLLECTIONS) {
- if ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) {
+ if (lc->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) {
return OPERATOR_CANCELLED;
}
if (toggle) {
@@ -300,11 +300,11 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op)
BKE_layer_collection_local_sync(view_layer, v3d);
}
else {
- BKE_layer_collection_local_isolate(view_layer, v3d, lc, extend);
+ BKE_layer_collection_isolate_local(view_layer, v3d, lc, extend);
}
}
else {
- BKE_layer_collection_isolate(scene, view_layer, lc, extend);
+ BKE_layer_collection_isolate_global(scene, view_layer, lc, extend);
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -910,12 +910,25 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot)
/* ********************************************** */
/* Motion Paths */
+static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range)
+{
+ switch (range) {
+ case OBJECT_PATH_CALC_RANGE_CURRENT_FRAME:
+ return ANIMVIZ_CALC_RANGE_CURRENT_FRAME;
+ case OBJECT_PATH_CALC_RANGE_CHANGED:
+ return ANIMVIZ_CALC_RANGE_CHANGED;
+ case OBJECT_PATH_CALC_RANGE_FULL:
+ return ANIMVIZ_CALC_RANGE_FULL;
+ }
+ return ANIMVIZ_CALC_RANGE_FULL;
+}
+
/* For the objects with animation: update paths for those that have got them
* This should selectively update paths that exist...
*
* To be called from various tools that do incremental updates
*/
-void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_only)
+void ED_objects_recalculate_paths(bContext *C, Scene *scene, eObjectPathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
if (C == NULL) {
@@ -923,11 +936,9 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
Main *bmain = CTX_data_main(C);
- /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
- * nested pointers, like animation data. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ListBase targets = {NULL, NULL};
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ListBase targets = {NULL, NULL};
/* loop over objects in scene */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
/* set flag to force recalc, then grab path(s) from object */
@@ -936,11 +947,27 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
CTX_DATA_END;
+ Depsgraph *depsgraph;
+ bool free_depsgraph = false;
+ /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead
+ * of building all the relations and so on for a temporary one. */
+ if (range == OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) {
+ /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
+ * nested pointers, like animation data. */
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ free_depsgraph = false;
+ }
+ else {
+ depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets);
+ free_depsgraph = true;
+ }
+
/* recalculate paths, then free */
- animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, true, current_frame_only);
+ animviz_calc_motionpaths(
+ depsgraph, bmain, scene, &targets, object_path_convert_range(range), true);
BLI_freelistN(&targets);
- if (!current_frame_only) {
+ if (range != OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) {
/* Tag objects for copy on write - so paths will draw/redraw
* For currently frame only we update evaluated object directly. */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
@@ -950,6 +977,11 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
CTX_DATA_END;
}
+
+ /* Free temporary depsgraph. */
+ if (free_depsgraph) {
+ DEG_graph_free(depsgraph);
+ }
}
/* show popup to determine settings */
@@ -995,7 +1027,7 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, false);
+ ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1060,7 +1092,7 @@ static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
}
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, false);
+ ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1515,7 +1547,7 @@ static int move_to_collection_exec(bContext *C, wmOperator *op)
}
int collection_index = RNA_property_int_get(op->ptr, prop);
- collection = BKE_collection_from_index(CTX_data_scene(C), collection_index);
+ collection = BKE_collection_from_index(scene, collection_index);
if (collection == NULL) {
BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found");
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 88d01936882..abcb4afa37d 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -677,7 +677,7 @@ static int modifier_apply_obdata(
/* Multires: ensure that recent sculpting is applied */
if (md_eval->type == eModifierType_Multires) {
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
}
if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) {
@@ -2022,7 +2022,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
is_bind = (csmd->bind_coords != NULL);
MEM_SAFE_FREE(csmd->bind_coords);
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
if (is_bind) {
/* toggle off */
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 0d20a07dcee..c030c551374 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1817,6 +1817,10 @@ static void single_object_users(
if (v3d) {
ID_NEW_REMAP(v3d->camera);
}
+ /* Camera pointers of markers. */
+ for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
+ ID_NEW_REMAP(marker->camera);
+ }
/* Making single user may affect other scenes if they share
* with current one some collections in their ViewLayer. */
@@ -2046,6 +2050,13 @@ void ED_object_single_users(Main *bmain,
single_obdata_users(bmain, scene, NULL, NULL, 0);
single_object_action_users(bmain, scene, NULL, NULL, 0);
single_mat_users_expand(bmain);
+ /* Duplicating obdata and other IDs may require another update of the collections and objects
+ * pointers, especially regarding drivers and custom props, see T66641.
+ * Note that this whole scene duplication code and 'make single user' functions have te be
+ * rewritten at some point to make use of proper modern ID management code,
+ * but that is no small task.
+ * For now we are doomed to that kind of band-aid to try to cover most of remapping cases. */
+ libblock_relink_collection(scene->master_collection);
}
/* Relink nodetrees' pointers that have been duplicated. */
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index 815cc618d4b..35762c5861e 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -40,12 +40,17 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mirror.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_shrinkwrap.h"
#include "BKE_customdata.h"
#include "BKE_mesh_remesh_voxel.h"
@@ -73,13 +78,24 @@ static bool object_remesh_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return false;
+ }
+
if (BKE_object_is_in_editmode(ob)) {
- CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run from edit mode.");
+ CTX_wm_operator_poll_msg_set(C, "The remesher cannot run from edit mode.");
return false;
}
if (ob->mode == OB_MODE_SCULPT && ob->sculpt->bm) {
- CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run with dyntopo activated.");
+ CTX_wm_operator_poll_msg_set(C, "The remesher cannot run with dyntopo activated.");
+ return false;
+ }
+
+ if (modifiers_usesMultires(ob)) {
+ CTX_wm_operator_poll_msg_set(
+ C, "The remesher cannot run with a Multires modifier in the modifier stack.");
+ return false;
}
return ED_operator_object_active_editable_mesh(C);
@@ -101,29 +117,35 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
ED_sculpt_undo_geometry_begin(ob);
}
- new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(mesh, mesh->remesh_voxel_size);
+ float isovalue = 0.0f;
+ if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
+ isovalue = mesh->remesh_voxel_size * 0.3f;
+ }
+
+ new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(
+ mesh, mesh->remesh_voxel_size, mesh->remesh_voxel_adaptivity, isovalue);
if (!new_mesh) {
return OPERATOR_CANCELLED;
}
- Mesh *obj_mesh_copy = NULL;
- if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
- obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0);
- CustomData_copy(
- &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert);
- for (int i = 0; i < mesh->totvert; i++) {
- copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co);
- }
+ if (mesh->flag & ME_REMESH_FIX_POLES && mesh->remesh_voxel_adaptivity <= 0.0f) {
+ new_mesh = BKE_mesh_remesh_voxel_fix_poles(new_mesh);
+ BKE_mesh_calc_normals(new_mesh);
}
- BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+ if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_shrinkwrap_remesh_target_project(new_mesh, mesh, ob);
+ }
if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
- BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy);
- BKE_mesh_free(obj_mesh_copy);
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_remesh_reproject_paint_mask(new_mesh, mesh);
}
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+
if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) {
BKE_mesh_smooth_flag_set(ob->data, true);
}
@@ -163,14 +185,26 @@ enum {
/****************** quadriflow remesh operator *********************/
+#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
+
+typedef enum eSymmetryAxes {
+ SYMMETRY_AXES_X = (1 << 0),
+ SYMMETRY_AXES_Y = (1 << 1),
+ SYMMETRY_AXES_Z = (1 << 2),
+} eSymmetryAxes;
+
typedef struct QuadriFlowJob {
/* from wmJob */
struct Object *owner;
+ struct Main *bmain;
short *stop, *do_update;
float *progress;
int target_faces;
int seed;
+ bool use_paint_symmetry;
+ eSymmetryAxes symmetry_axes;
+
bool use_preserve_sharp;
bool use_preserve_boundary;
bool use_mesh_curvature;
@@ -181,6 +215,57 @@ typedef struct QuadriFlowJob {
int success;
} QuadriFlowJob;
+static bool mesh_is_manifold_consistent(Mesh *mesh)
+{
+ /* In this check we count boundary edges as manifold. Additionally, we also
+ * check that the direction of the faces are consistent and doesn't suddenly
+ * flip
+ */
+
+ bool is_manifold_consistent = true;
+ const MLoop *mloop = mesh->mloop;
+ char *edge_faces = (char *)MEM_callocN(mesh->totedge * sizeof(char), "remesh_manifold_check");
+ int *edge_vert = (int *)MEM_malloc_arrayN(
+ mesh->totedge, sizeof(unsigned int), "remesh_consistent_check");
+
+ for (unsigned int i = 0; i < mesh->totedge; i++) {
+ edge_vert[i] = -1;
+ }
+
+ for (unsigned int loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
+ const MLoop *loop = &mloop[loop_idx];
+ edge_faces[loop->e] += 1;
+ if (edge_faces[loop->e] > 2) {
+ is_manifold_consistent = false;
+ break;
+ }
+
+ if (edge_vert[loop->e] == -1) {
+ edge_vert[loop->e] = loop->v;
+ }
+ else if (edge_vert[loop->e] == loop->v) {
+ /* Mesh has flips in the surface so it is non consistent */
+ is_manifold_consistent = false;
+ break;
+ }
+ }
+
+ if (is_manifold_consistent) {
+ /* check for wire edges */
+ for (unsigned int i = 0; i < mesh->totedge; i++) {
+ if (edge_faces[i] == 0) {
+ is_manifold_consistent = false;
+ break;
+ }
+ }
+ }
+
+ MEM_freeN(edge_faces);
+ MEM_freeN(edge_vert);
+
+ return is_manifold_consistent;
+}
+
static void quadriflow_free_job(void *customdata)
{
QuadriFlowJob *qj = customdata;
@@ -221,6 +306,66 @@ static void quadriflow_update_job(void *customdata, float progress, int *cancel)
*(qj->progress) = progress;
}
+static Mesh *remesh_symmetry_bisect(Main *bmain, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+
+ Mesh *mesh_bisect, *mesh_bisect_temp;
+ mesh_bisect = BKE_mesh_copy(bmain, mesh);
+
+ int axis;
+ float plane_co[3], plane_no[3];
+ zero_v3(plane_co);
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_BISECT_AXIS_X << i;
+ zero_v3(plane_no);
+ plane_no[axis] = -1.0f;
+ mesh_bisect_temp = mesh_bisect;
+ mesh_bisect = BKE_mirror_bisect_on_mirror_plane(&mmd, mesh_bisect, axis, plane_co, plane_no);
+ if (mesh_bisect_temp != mesh_bisect) {
+ BKE_id_free(bmain, mesh_bisect_temp);
+ }
+ }
+ }
+
+ BKE_id_free(bmain, mesh);
+
+ return mesh_bisect;
+}
+
+static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+ Mesh *mesh_mirror, *mesh_mirror_temp;
+
+ mesh_mirror = mesh;
+
+ int axis;
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_AXIS_X << i;
+ mesh_mirror_temp = mesh_mirror;
+ mesh_mirror = BKE_mirror_apply_mirror_on_axis(&mmd, NULL, ob, mesh_mirror, axis);
+ if (mesh_mirror_temp != mesh_mirror) {
+ BKE_id_free(NULL, mesh_mirror_temp);
+ }
+ }
+ }
+
+ return mesh_mirror;
+}
+
static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
{
QuadriFlowJob *qj = customdata;
@@ -235,16 +380,33 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
Object *ob = qj->owner;
Mesh *mesh = ob->data;
Mesh *new_mesh;
+ Mesh *bisect_mesh;
+
+ /* Check if the mesh is manifold. Quadriflow requires manifold meshes */
+ if (!mesh_is_manifold_consistent(mesh)) {
+ qj->success = -2;
+ return;
+ }
+
+ /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without
+ * freeing the original ID */
+ bisect_mesh = BKE_mesh_copy(qj->bmain, mesh);
- new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(mesh,
+ /* Bisect the input mesh using the paint symmetry settings */
+ bisect_mesh = remesh_symmetry_bisect(qj->bmain, bisect_mesh, qj->symmetry_axes);
+
+ new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(bisect_mesh,
qj->target_faces,
qj->seed,
qj->use_preserve_sharp,
- qj->use_preserve_boundary,
+ qj->use_preserve_boundary ||
+ qj->use_paint_symmetry,
qj->use_mesh_curvature,
quadriflow_update_job,
(void *)qj);
+ BKE_id_free(qj->bmain, bisect_mesh);
+
if (!new_mesh) {
*do_update = true;
*stop = 0;
@@ -255,28 +417,26 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
return;
}
+ /* Mirror the Quadriflow result to build the final mesh */
+ if (new_mesh) {
+ new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes);
+ }
+
if (ob->mode == OB_MODE_SCULPT) {
ED_sculpt_undo_geometry_begin(ob);
}
- Mesh *obj_mesh_copy = NULL;
if (qj->preserve_paint_mask) {
- obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0);
- CustomData_copy(
- &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert);
- for (int i = 0; i < mesh->totvert; i++) {
- copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co);
- }
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_remesh_reproject_paint_mask(new_mesh, mesh);
}
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
- if (qj->preserve_paint_mask) {
- BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy);
- BKE_mesh_free(obj_mesh_copy);
- }
-
if (qj->smooth_normals) {
+ if (qj->use_paint_symmetry) {
+ BKE_mesh_calc_normals(ob->data);
+ }
BKE_mesh_smooth_flag_set(ob->data, true);
}
@@ -298,17 +458,22 @@ static void quadriflow_end_job(void *customdata)
WM_set_locked_interface(G_MAIN->wm.first, false);
- if (qj->success > 0) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!");
- }
- else {
- if (qj->success == 0) {
+ switch (qj->success) {
+ case 1:
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!");
+ break;
+ case 0:
WM_reportf(RPT_ERROR, "QuadriFlow: remeshing failed!");
- }
- else {
+ break;
+ case -1:
WM_report(RPT_WARNING, "QuadriFlow: remeshing canceled!");
- }
+ break;
+ case -2:
+ WM_report(RPT_WARNING,
+ "QuadriFlow: The mesh needs to be manifold and have face normals that point in a "
+ "consistent direction.");
+ break;
}
}
@@ -317,10 +482,13 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
job->owner = CTX_data_active_object(C);
+ job->bmain = CTX_data_main(C);
job->target_faces = RNA_int_get(op->ptr, "target_faces");
job->seed = RNA_int_get(op->ptr, "seed");
+ job->use_paint_symmetry = RNA_boolean_get(op->ptr, "use_paint_symmetry");
+
job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp");
job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary");
@@ -329,6 +497,22 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask");
job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals");
+ /* Update the target face count if symmetry is enabled */
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ if (sd && job->use_paint_symmetry) {
+ job->symmetry_axes = (eSymmetryAxes)(sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL);
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (job->symmetry_axes & symm_it) {
+ job->target_faces = job->target_faces / 2;
+ }
+ }
+ }
+ else {
+ job->use_paint_symmetry = false;
+ job->symmetry_axes = 0;
+ }
+
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
CTX_wm_window(C),
CTX_data_scene(C),
@@ -453,6 +637,12 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna,
+ "use_paint_symmetry",
+ true,
+ "Use Paint Symmetry",
+ "Generates a symmetrycal mesh using the paint symmetry configuration");
+
+ RNA_def_boolean(ot->srna,
"use_preserve_sharp",
false,
"Preserve Sharp",
@@ -485,7 +675,7 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
RNA_def_enum(ot->srna,
"mode",
mode_type_items,
- 0,
+ QUADRIFLOW_REMESH_FACES,
"Mode",
"How to specify the amount of detail for the new mesh");
@@ -511,7 +701,7 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
prop = RNA_def_int(ot->srna,
"target_faces",
- 1,
+ 4000,
1,
INT_MAX,
"Number of Faces",
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 28242b986f1..40fa11994f4 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -214,7 +214,7 @@ bool ED_object_base_deselect_all(ViewLayer *view_layer, View3D *v3d, int action)
static int get_base_select_priority(Base *base)
{
- if (base->flag & BASE_VISIBLE) {
+ if (base->flag & BASE_VISIBLE_DEPSGRAPH) {
if (base->flag & BASE_SELECTABLE) {
return 3;
}
@@ -288,7 +288,7 @@ bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_
if (!(base->flag & BASE_SELECTED)) {
ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT);
- if (base->flag & BASE_VISIBLE) {
+ if (BASE_VISIBLE(v3d, base)) {
ED_object_base_select(base, BA_SELECT);
}
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 1cd16b1b0bf..b534e1b9683 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1715,8 +1715,9 @@ static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.obact == NULL || !object_is_target_compat(vc.obact)) {
/* Falls back to texture space transform. */
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 2047ecb9e0a..f16a372cb3c 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -93,6 +93,7 @@
bool PE_poll(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -100,7 +101,7 @@ bool PE_poll(bContext *C)
return false;
}
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit == NULL) {
return false;
}
@@ -113,6 +114,7 @@ bool PE_poll(bContext *C)
bool PE_hair_poll(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -120,7 +122,7 @@ bool PE_hair_poll(bContext *C)
return false;
}
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit == NULL || edit->psys == NULL) {
return false;
}
@@ -149,8 +151,7 @@ void PE_free_ptcache_edit(PTCacheEdit *edit)
}
if (edit->points) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->keys) {
MEM_freeN(point->keys);
}
@@ -356,9 +357,9 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o
return edit;
}
-PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
+PTCacheEdit *PE_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- return pe_get_current(NULL, scene, ob, 0);
+ return pe_get_current(depsgraph, scene, ob, 0);
}
PTCacheEdit *PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
@@ -380,10 +381,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
KEY_K;
if (pset->flag & PE_FADE_TIME && pset->selectmode == SCE_SELECT_POINT) {
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
if (fabsf(cfra - *key->time) < pset->fade_frames) {
key->flag &= ~PEK_HIDE;
}
@@ -395,10 +394,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
}
}
else {
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
key->flag &= ~PEK_HIDE;
}
}
@@ -466,14 +463,14 @@ static void PE_set_data(bContext *C, PEData *data)
data->view_layer = CTX_data_view_layer(C);
data->ob = CTX_data_active_object(C);
data->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- data->edit = PE_get_current(data->scene, data->ob);
+ data->edit = PE_get_current(data->depsgraph, data->scene, data->ob);
}
static void PE_set_view3d_data(bContext *C, PEData *data)
{
PE_set_data(C, data);
- ED_view3d_viewcontext_init(C, &data->vc);
+ ED_view3d_viewcontext_init(C, &data->vc, data->depsgraph);
if (!XRAY_ENABLED(data->vc.v3d)) {
if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
@@ -633,8 +630,7 @@ static bool point_is_selected(PTCacheEditPoint *point)
return 0;
}
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
return 1;
}
@@ -684,8 +680,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic
nearest_point = -1;
nearest_key = -1;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) {
/* only do end keys */
@@ -707,8 +702,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic
}
else {
/* do all keys */
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (flag & PSEL_NEAREST) {
if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
nearest_point = p;
@@ -745,8 +739,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele
selected = 0;
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) {
/* only do end keys */
@@ -762,8 +755,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele
}
else {
/* do all keys */
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (selected == 0 || key->flag & PEK_SELECT) {
float mouse_distance;
if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
@@ -823,8 +815,7 @@ static void foreach_mouse_hit_key_iter(void *__restrict iter_data_v,
/* do all keys */
PTCacheEditKey *key;
int k;
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (selected == 0 || key->flag & PEK_SELECT) {
float mouse_distance;
if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
@@ -866,8 +857,7 @@ static void foreach_selected_point(PEData *data, ForPointFunc func)
PTCacheEdit *edit = data->edit;
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
func(data, p);
}
}
@@ -878,10 +868,8 @@ static void foreach_selected_key(PEData *data, ForKeyFunc func)
POINT_P;
KEY_K;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
func(data, p, k, true);
}
}
@@ -892,8 +880,7 @@ static void foreach_point(PEData *data, ForPointFunc func)
PTCacheEdit *edit = data->edit;
POINT_P;
- LOOP_POINTS
- {
+ LOOP_POINTS {
func(data, p);
}
}
@@ -905,11 +892,9 @@ static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
KEY_K;
int sel = 0;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
sel++;
}
}
@@ -1117,8 +1102,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
/* we delay settings the PARS_EDIT_RECALC for mirrored particles
* to avoid doing mirror twice */
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
@@ -1128,8 +1112,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
if (edit->mirror_cache[p] != -1) {
edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
@@ -1173,13 +1156,11 @@ static void deflect_emitter_iter(void *__restrict iter_data_v,
psys_mat_hair_to_object(
object, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, hairmat);
- LOOP_KEYS
- {
+ LOOP_KEYS {
mul_m4_v3(hairmat, key->co);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
dist_1st = len_v3v3((key + 1)->co, key->co);
dist_1st *= dist * emitterdist;
@@ -1215,8 +1196,7 @@ static void deflect_emitter_iter(void *__restrict iter_data_v,
invert_m4_m4(hairimat, hairmat);
- LOOP_KEYS
- {
+ LOOP_KEYS {
mul_m4_v3(hairimat, key->co);
}
}
@@ -1268,8 +1248,7 @@ static void apply_lengths_iter(void *__restrict iter_data_v,
}
PTCacheEditKey *key;
int k;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k) {
float dv1[3];
sub_v3_v3v3(dv1, key->co, (key - 1)->co);
@@ -1387,8 +1366,7 @@ void recalc_lengths(PTCacheEdit *edit)
return;
}
- LOOP_EDITED_POINTS
- {
+ LOOP_EDITED_POINTS {
key = point->keys;
for (k = 0; k < point->totkey - 1; k++, key++) {
key->length = len_v3v3(key->co, (key + 1)->co);
@@ -1461,15 +1439,14 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
HairKey *hkey;
POINT_P;
KEY_K;
/* flag all particles to be updated if not using flag */
if (!useflag) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag |= PEP_EDIT_RECALC;
}
}
@@ -1477,11 +1454,9 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
/* flush edit key flag to hair key flag to preserve selection
* on save */
if (edit->psys) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
hkey = edit->psys->particles[p].hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
hkey->editflag = key->flag;
hkey++;
}
@@ -1491,8 +1466,7 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_EDIT_RECALC;
}
@@ -1511,15 +1485,13 @@ void update_world_cos(Object *ob, PTCacheEdit *edit)
return;
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, hairmat);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
copy_v3_v3(key->world_co, key->co);
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
mul_m4_v3(hairmat, key->world_co);
@@ -1541,10 +1513,8 @@ static void update_velocities(PTCacheEdit *edit)
frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
- LOOP_EDITED_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_EDITED_POINTS {
+ LOOP_KEYS {
if (k == 0) {
dfra = *(key + 1)->time - *key->time;
@@ -1596,7 +1566,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
/* use this to do partial particle updates, not usable when adding or
* removing, then a full redo is necessary and calling this may crash */
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
if (!edit) {
@@ -1605,8 +1575,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
/* flag all particles to be updated if not using flag */
if (!useflag) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag |= PEP_EDIT_RECALC;
}
}
@@ -1624,14 +1593,19 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
if (pset->flag & PE_AUTO_VELOCITY) {
update_velocities(edit);
}
- PE_hide_keys_time(scene, edit, CFRA);
+
+ /* Only do this for emitter particles because drawing PE_FADE_TIME is not respected in 2.8 yet
+ * and flagging with PEK_HIDE will prevent selection. This might get restored once this is
+ * supported in drawing (but doesn't make much sense for hair anyways). */
+ if (edit->psys->part->type == PART_EMITTER) {
+ PE_hide_keys_time(scene, edit, CFRA);
+ }
/* regenerate path caches */
psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_EDIT_RECALC;
}
@@ -1686,8 +1660,7 @@ static void select_keys(PEData *data,
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (data->select) {
key->flag |= PEK_SELECT;
}
@@ -1780,17 +1753,15 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
KEY_K;
int action = RNA_enum_get(op->ptr, "action");
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
action = SEL_DESELECT;
break;
}
@@ -1802,10 +1773,8 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
}
bool changed = false;
- LOOP_VISIBLE_POINTS
- {
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
changed |= select_action_apply(point, key, action);
}
}
@@ -1841,26 +1810,26 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele
PEData data;
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
POINT_P;
KEY_K;
+ PE_set_view3d_data(C, &data);
+
+ PTCacheEdit *edit = PE_get_current(data.depsgraph, scene, ob);
+
if (!PE_start_edit(edit)) {
return false;
}
if (!extend && !deselect && !toggle) {
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
key->flag &= ~PEK_SELECT;
point->flag |= PEP_EDIT_RECALC;
}
}
}
- PE_set_view3d_data(C, &data);
data.mval = mval;
data.rad = ED_view3d_select_dist_px();
@@ -2048,26 +2017,22 @@ static int select_random_exec(bContext *C, wmOperator *op)
PE_set_data(C, &data);
data.select_action = SEL_SELECT;
- edit = PE_get_current(data.scene, data.ob);
+ edit = PE_get_current(data.depsgraph, data.scene, data.ob);
rng = BLI_rng_new_srandom(seed);
switch (type) {
case RAN_HAIR:
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
- LOOP_KEYS
- {
+ LOOP_KEYS {
data.is_changed |= select_action_apply(point, key, flag);
}
}
break;
case RAN_POINTS:
- LOOP_VISIBLE_POINTS
- {
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
data.is_changed |= select_action_apply(point, key, flag);
}
@@ -2166,10 +2131,8 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
POINT_P;
KEY_K;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
if ((key->flag & PEK_SELECT) != 0) {
key->flag &= ~PEK_SELECT;
point->flag |= PEP_EDIT_RECALC;
@@ -2182,9 +2145,10 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
bool PE_deselect_all_visible(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (!PE_start_edit(edit)) {
return false;
}
@@ -2193,9 +2157,10 @@ bool PE_deselect_all_visible(bContext *C)
bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PEData data;
if (!PE_start_edit(edit)) {
@@ -2229,9 +2194,10 @@ bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float rad)
{
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PEData data;
if (!PE_start_edit(edit)) {
@@ -2260,11 +2226,12 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra
int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ARegion *ar = CTX_wm_region(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
POINT_P;
@@ -2287,16 +2254,14 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
data.is_changed |= PE_deselect_all_visible_ex(edit);
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
}
if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_KEYS
- {
+ LOOP_VISIBLE_KEYS {
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
const bool is_select = key->flag & PEK_SELECT;
@@ -2350,30 +2315,26 @@ static int hide_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
KEY_K;
if (RNA_boolean_get(op->ptr, "unselected")) {
- LOOP_UNSELECTED_POINTS
- {
+ LOOP_UNSELECTED_POINTS {
point->flag |= PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->flag &= ~PEK_SELECT;
}
}
}
else {
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
point->flag |= PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->flag &= ~PEK_SELECT;
}
}
@@ -2410,19 +2371,17 @@ static int reveal_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
const bool select = RNA_boolean_get(op->ptr, "select");
POINT_P;
KEY_K;
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_HIDE) {
point->flag &= ~PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
SET_FLAG_FROM_TEST(key->flag, select, PEK_SELECT);
}
}
@@ -2460,8 +2419,7 @@ static void select_less_keys(PEData *data, int point_index)
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
if (k == 0) {
if (((key + 1)->flag & PEK_SELECT) == 0) {
key->flag |= PEK_TAG;
@@ -2479,8 +2437,7 @@ static void select_less_keys(PEData *data, int point_index)
}
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT)) {
key->flag &= ~(PEK_TAG | PEK_SELECT);
point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
@@ -2525,8 +2482,7 @@ static void select_more_keys(PEData *data, int point_index)
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (key->flag & PEK_SELECT) {
continue;
}
@@ -2548,8 +2504,7 @@ static void select_more_keys(PEData *data, int point_index)
}
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT) == 0) {
key->flag &= ~PEK_TAG;
key->flag |= PEK_SELECT;
@@ -2694,7 +2649,8 @@ void PARTICLE_OT_rekey(wmOperatorType *ot)
static void rekey_particle_to_time(
const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys;
ParticleSimulationData sim = {0};
ParticleData *pa;
@@ -2709,7 +2665,7 @@ static void rekey_particle_to_time(
psys = edit->psys;
- sim.depsgraph = CTX_data_depsgraph_pointer(C);
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
@@ -2758,14 +2714,12 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
/* mirror tags */
psmd_eval = edit->psmd_eval;
- LOOP_TAGGED_POINTS
- {
+ LOOP_TAGGED_POINTS {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
}
}
- LOOP_TAGGED_POINTS
- {
+ LOOP_TAGGED_POINTS {
new_totpart--;
removed++;
}
@@ -2850,21 +2804,17 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)modifier_get_evaluated(
depsgraph, ob, &psmd->modifier);
- LOOP_POINTS
- {
- LOOP_TAGGED_KEYS
- {
+ LOOP_POINTS {
+ LOOP_TAGGED_KEYS {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
break;
}
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
new_totkey = point->totkey;
- LOOP_TAGGED_KEYS
- {
+ LOOP_TAGGED_KEYS {
new_totkey--;
}
/* we can't have elements with less than two keys*/
@@ -2874,13 +2824,11 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
}
remove_tagged_particles(ob, psys, pe_x_mirror(ob));
- LOOP_POINTS
- {
+ LOOP_POINTS {
pa = psys->particles + p;
new_totkey = pa->totkey;
- LOOP_TAGGED_KEYS
- {
+ LOOP_TAGGED_KEYS {
new_totkey--;
}
@@ -2889,8 +2837,7 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
nkey = new_keys = MEM_callocN(new_totkey * sizeof(PTCacheEditKey), "particle edit keys");
hkey = pa->hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
key++;
hkey++;
@@ -3062,9 +3009,10 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot)
static int remove_doubles_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd_eval;
KDTree_3d *tree;
@@ -3087,8 +3035,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
tree = BLI_kdtree_3d_new(psys->totpart);
/* insert particles into kd tree */
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
psys_mat_hair_to_object(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
@@ -3099,8 +3046,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
BLI_kdtree_3d_balance(tree);
/* tag particles to be removed */
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
psys_mat_hair_to_object(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
@@ -3130,7 +3076,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved);
+ BKE_reportf(op->reports, RPT_INFO, "Removed %d double particle(s)", totremoved);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
@@ -3166,10 +3112,11 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
static int weight_set_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ParticleEditSettings *pset = PE_settings(scene);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
POINT_P;
KEY_K;
@@ -3181,12 +3128,10 @@ static int weight_set_exec(bContext *C, wmOperator *op)
weight = brush->strength;
edit = psys->edit;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
ParticleData *pa = psys->particles + p;
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
hkey = pa->hair + k;
hkey->weight = interpf(weight, hkey->weight, factor);
}
@@ -3315,6 +3260,7 @@ static int delete_exec(bContext *C, wmOperator *op)
}
DEG_id_tag_update(&data.ob->id, ID_RECALC_GEOMETRY);
+ BKE_particle_batch_cache_dirty_tag(data.edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -3346,11 +3292,11 @@ void PARTICLE_OT_delete(wmOperatorType *ot)
/*************************** mirror operator **************************/
-static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
+static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagged)
{
Mesh *me = (Mesh *)(ob->data);
ParticleSystemModifierData *psmd_eval;
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleData *pa, *newpa, *new_pars;
PTCacheEditPoint *newpoint, *new_points;
@@ -3386,8 +3332,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
totpart = psys->totpart;
newtotpart = psys->totpart;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
pa = psys->particles + p;
if (!tagged) {
@@ -3503,8 +3448,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_TAG;
}
@@ -3513,14 +3457,18 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
- PE_mirror_x(scene, ob, 0);
+ PE_mirror_x(depsgraph, scene, ob, 0);
update_world_cos(ob, edit);
+ psys_free_path_cache(NULL, edit);
+
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
return OPERATOR_FINISHED;
@@ -3681,8 +3629,7 @@ static void brush_length(PEData *data, int point_index, float UNUSED(mouse_dista
KEY_K;
float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f};
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
copy_v3_v3(pvec, key->co);
}
@@ -3731,8 +3678,7 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance)
unit_m4(imat);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
float kco[3];
if (k == 0) {
@@ -4504,10 +4450,11 @@ typedef struct BrushEdit {
static int brush_edit_init(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ARegion *ar = CTX_wm_region(C);
BrushEdit *bedit;
float min[3], max[3];
@@ -4518,7 +4465,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
/* set the 'distance factor' for grabbing (used in comb etc) */
INIT_MINMAX(min, max);
- PE_minmax(scene, view_layer, min, max);
+ PE_minmax(depsgraph, scene, view_layer, min, max);
mid_v3_v3v3(min, min, max);
bedit = MEM_callocN(sizeof(BrushEdit), "BrushEdit");
@@ -4744,7 +4691,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob)) {
- PE_mirror_x(scene, ob, 1);
+ PE_mirror_x(depsgraph, scene, ob, 1);
}
update_world_cos(ob, edit);
@@ -4993,10 +4940,11 @@ static void shape_cut(PEData *data, int pa_index)
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
Object *shapeob = pset->shape_object;
int selected = count_selected_keys(scene, edit);
int lock_root = pset->flag & PE_LOCK_FIRST;
@@ -5074,10 +5022,11 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
/************************ utilities ******************************/
-int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
+int PE_minmax(
+ Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
{
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys;
ParticleSystemModifierData *psmd_eval = NULL;
POINT_P;
@@ -5096,15 +5045,13 @@ int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
unit_m4(mat);
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (psys) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
}
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
DO_MINMAX(co, min, max);
@@ -5181,15 +5128,13 @@ void PE_create_particle_edit(
BLI_listbase_clear(&edit->pathcachebufs);
pa = psys->particles;
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->totkey = pa->totkey;
point->keys = MEM_callocN(point->totkey * sizeof(PTCacheEditKey), "ParticleEditKeys");
point->flag |= PEP_EDIT_RECALC;
hkey = pa->hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
key->flag = hkey->editflag;
@@ -5217,8 +5162,7 @@ void PE_create_particle_edit(
}
for (pm = cache->mem_cache.first; pm; pm = pm->next) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (BKE_ptcache_mem_pointers_seek(p, pm) == 0) {
continue;
}
@@ -5421,8 +5365,7 @@ static float calculate_point_length(PTCacheEditPoint *point)
{
float length = 0.0f;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k > 0) {
length += len_v3v3((key - 1)->co, key->co);
}
@@ -5435,8 +5378,7 @@ static float calculate_average_length(PTCacheEdit *edit)
int num_selected = 0;
float total_length = 0;
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
total_length += calculate_point_length(point);
num_selected++;
}
@@ -5450,8 +5392,7 @@ static void scale_point_factor(PTCacheEditPoint *point, float factor)
{
float orig_prev_co[3], prev_co[3];
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
copy_v3_v3(orig_prev_co, key->co);
copy_v3_v3(prev_co, key->co);
@@ -5484,8 +5425,7 @@ static void scale_point_to_length(PTCacheEditPoint *point, float length)
static void scale_points_to_length(PTCacheEdit *edit, float length)
{
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
scale_point_to_length(point, length);
}
recalc_lengths(edit);
@@ -5497,7 +5437,7 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
float average_length = calculate_average_length(edit);
if (average_length == 0.0f) {
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 40d90676487..aee79523c87 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -109,8 +109,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
POINT_P;
KEY_K;
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (psys && psys->particles[p].hair) {
MEM_freeN(psys->particles[p].hair);
}
@@ -133,8 +132,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
edit->points = MEM_dupallocN(undo->points);
edit->totpoint = undo->totpoint;
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->keys = MEM_dupallocN(point->keys);
}
@@ -143,13 +141,11 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
psys->totpart = undo->totpoint;
- LOOP_POINTS
- {
+ LOOP_POINTS {
pa = psys->particles + p;
hkey = pa->hair = MEM_dupallocN(pa->hair);
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
hkey++;
@@ -174,10 +170,8 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
}
BKE_ptcache_mem_pointers_init(pm);
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
if ((int)key->ftime == (int)pm->frame) {
key->co = pm->cur[BPHYS_DATA_LOCATION];
key->vel = pm->cur[BPHYS_DATA_VELOCITY];
@@ -228,10 +222,11 @@ typedef struct ParticleUndoStep {
static bool particle_undosys_poll(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
return (edit != NULL);
}
@@ -240,11 +235,12 @@ static bool particle_undosys_step_encode(struct bContext *C,
struct Main *UNUSED(bmain),
UndoStep *us_p)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
ViewLayer *view_layer = CTX_data_view_layer(C);
us->scene_ref.ptr = CTX_data_scene(C);
us->object_ref.ptr = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr);
+ PTCacheEdit *edit = PE_get_current(depsgraph, us->scene_ref.ptr, us->object_ref.ptr);
undoptcache_from_editcache(&us->data, edit);
return true;
}
@@ -255,6 +251,7 @@ static void particle_undosys_step_decode(struct bContext *C,
int UNUSED(dir),
bool UNUSED(is_final))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
/* TODO(campbell): undo_system: use low-level API to set mode. */
ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
BLI_assert(particle_undosys_poll(C));
@@ -262,7 +259,7 @@ static void particle_undosys_step_decode(struct bContext *C,
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
Scene *scene = us->scene_ref.ptr;
Object *ob = us->object_ref.ptr;
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit) {
undoptcache_to_editcache(&us->data, edit);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 5a2009845f8..cfb3a400f47 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1017,13 +1017,11 @@ static void copy_particle_edit(Depsgraph *depsgraph,
edit->points = MEM_dupallocN(edit_from->points);
pa = psys->particles;
- LOOP_POINTS
- {
+ LOOP_POINTS {
HairKey *hkey = pa->hair;
point->keys = MEM_dupallocN(point->keys);
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
key->flag = hkey->editflag;
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index 4b1d51ee6c2..303a0714388 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -115,13 +115,7 @@ bool ED_rigidbody_constraint_add(
void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
{
- RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
-
- BKE_rigidbody_remove_constraint(scene, ob);
- if (rbw) {
- BKE_collection_object_remove(bmain, rbw->constraints, ob, false);
- DEG_id_tag_update(&rbw->constraints->id, ID_RECALC_COPY_ON_WRITE);
- }
+ BKE_rigidbody_remove_constraint(bmain, scene, ob, false);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index bc8a1799fa0..43ca421b9d0 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -105,7 +105,7 @@ bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, Re
void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
{
- BKE_rigidbody_remove_object(bmain, scene, ob);
+ BKE_rigidbody_remove_object(bmain, scene, ob, false);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 053ca3d8f9f..7106af25a82 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -859,7 +859,7 @@ static void screen_render_cancel(bContext *C, wmOperator *op)
static void clean_viewport_memory_base(Base *base)
{
- if ((base->flag & BASE_VISIBLE) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
return;
}
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 3e001ef25b5..6dc3a1ec1ac 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -115,7 +115,7 @@ ImBuf *get_brush_icon(Brush *brush)
// first use the path directly to try and load the file
BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath));
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
/* use default colorspaces for brushes */
brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
@@ -474,7 +474,7 @@ static Scene *preview_prepare_scene(
}
}
else if (base->object->type == OB_LAMP) {
- base->flag |= BASE_VISIBLE;
+ base->flag |= BASE_VISIBLE_DEPSGRAPH;
}
}
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 9f13431f25a..7970d491877 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -103,15 +103,17 @@ static Object **object_array_for_shading(bContext *C, uint *r_objects_len)
ScrArea *sa = CTX_wm_area(C);
SpaceProperties *sbuts = NULL;
View3D *v3d = NULL;
- if (sa->spacetype == SPACE_PROPERTIES) {
- sbuts = sa->spacedata.first;
- }
- else if (sa->spacetype == SPACE_VIEW3D) {
- v3d = sa->spacedata.first;
+ if (sa != NULL) {
+ if (sa->spacetype == SPACE_PROPERTIES) {
+ sbuts = sa->spacedata.first;
+ }
+ else if (sa->spacetype == SPACE_VIEW3D) {
+ v3d = sa->spacedata.first;
+ }
}
Object **objects;
- if (sbuts && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) {
+ if (sbuts != NULL && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) {
objects = MEM_mallocN(sizeof(*objects), __func__);
objects[0] = (Object *)sbuts->pinid;
*r_objects_len = 1;
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 3154d5d0985..a54701f8725 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -36,6 +36,8 @@
#include "BKE_screen.h"
#include "BKE_report.h"
+#include "BLT_translation.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -137,11 +139,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
SpaceImage *sima;
bool area_was_image = false;
- if (scene->r.displaymode == R_OUTPUT_NONE) {
+ if (U.render_display_type == USER_RENDER_DISPLAY_NONE) {
return NULL;
}
- if (scene->r.displaymode == R_OUTPUT_WINDOW) {
+ if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100;
int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100;
@@ -154,14 +156,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
/* changes context! */
- if (WM_window_open_temp(C, mx, my, sizex, sizey, WM_WINDOW_RENDER) == NULL) {
+ if (WM_window_open_temp(
+ C, IFACE_("Blender Render"), mx, my, sizex, sizey, SPACE_IMAGE, false) == NULL) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
return NULL;
}
sa = CTX_wm_area(C);
}
- else if (scene->r.displaymode == R_OUTPUT_SCREEN) {
+ else if (U.render_display_type == USER_RENDER_DISPLAY_SCREEN) {
sa = CTX_wm_area(C);
/* if the active screen is already in fullscreen mode, skip this and
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 84d6610242a..7705278443f 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -29,21 +29,16 @@
#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_library.h"
-#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "BLT_translation.h"
-#include "DNA_object_types.h"
-#include "DNA_workspace_types.h"
-
#include "ED_object.h"
#include "ED_render.h"
#include "ED_scene.h"
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index cb87b076d79..9957fe0515c 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -30,6 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
@@ -60,7 +61,6 @@
#include "BLF_api.h"
-#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
@@ -543,20 +543,20 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
region_draw_azones(sa, ar);
/* for debugging unneeded area redraws and partial redraw */
-#if 0
- GPU_blend(true);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4f(drand48(), drand48(), drand48(), 0.1f);
- immRectf(pos,
- ar->drawrct.xmin - ar->winrct.xmin,
- ar->drawrct.ymin - ar->winrct.ymin,
- ar->drawrct.xmax - ar->winrct.xmin,
- ar->drawrct.ymax - ar->winrct.ymin);
- immUnbindProgram();
- GPU_blend(false);
-#endif
+ if (G.debug_value == 888) {
+ GPU_blend(true);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(BLI_thread_frand(0), BLI_thread_frand(0), BLI_thread_frand(0), 0.1f);
+ immRectf(pos,
+ ar->drawrct.xmin - ar->winrct.xmin,
+ ar->drawrct.ymin - ar->winrct.ymin,
+ ar->drawrct.xmax - ar->winrct.xmin,
+ ar->drawrct.ymax - ar->winrct.ymin);
+ immUnbindProgram();
+ GPU_blend(false);
+ }
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
@@ -1827,7 +1827,7 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar)
if (WM_cursor_set_from_tool(win, sa, ar)) {
return;
}
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
@@ -2869,7 +2869,7 @@ void ED_region_info_draw(ARegion *ar,
float fill_color[4],
const bool full_redraw)
{
- ED_region_info_draw_multiline(ar, (const char * [2]){text, NULL}, fill_color, full_redraw);
+ ED_region_info_draw_multiline(ar, (const char *[2]){text, NULL}, fill_color, full_redraw);
}
#define MAX_METADATA_STR 1024
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 420d70e63fb..46559efc614 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -28,8 +28,6 @@
#include "RNA_types.h"
-#include "WM_api.h"
-
#include "ED_screen.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 1a99210b73d..61fb9d5a3a8 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -28,7 +28,6 @@
#include "RNA_access.h"
#include "RNA_types.h"
-#include "WM_api.h"
#include "WM_message.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index d8926bfc460..dc435efd86b 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -24,8 +24,6 @@
#include <stdio.h>
#include <string.h>
-#include "MEM_guardedalloc.h"
-
#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 6f8b25f782b..f7742c5e50a 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -29,36 +29,28 @@
#include "DNA_object_types.h"
#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
#include "BLI_utildefines.h"
-#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_paint.h"
#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_sequencer.h"
-#include "BKE_workspace.h"
-
-#include "DEG_depsgraph.h"
#include "RNA_access.h"
#include "ED_armature.h"
#include "ED_gpencil.h"
#include "ED_anim_api.h"
-#include "ED_uvedit.h"
#include "WM_api.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index db744df02e7..a6b8bba73e3 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -21,7 +21,7 @@
#include "ED_screen.h"
#include "GPU_batch_presets.h"
-#include "GPU_extensions.h"
+#include "GPU_platform.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
@@ -32,9 +32,7 @@
#include "BLI_rect.h"
#include "WM_api.h"
-#include "WM_types.h"
-#include "UI_interface.h"
#include "UI_resources.h"
#include "screen_intern.h"
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index b37aa47aba6..bbdddfadc30 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -41,20 +41,18 @@
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
+#include "BKE_sound.h"
#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_object.h"
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_clip.h"
#include "ED_node.h"
-#include "ED_render.h"
#include "UI_interface.h"
@@ -518,6 +516,17 @@ void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *scree
}
}
+/**
+ * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
+ * slightly differently, see #ui_region_temp_remove().
+ */
+void ED_region_remove(bContext *C, ScrArea *sa, ARegion *ar)
+{
+ ED_region_exit(C, ar);
+ BKE_area_region_free(sa->type, ar);
+ BLI_freelinkN(&sa->regionbase, ar);
+}
+
/* *********** exit calls are for closing running stuff ******** */
void ED_region_exit(bContext *C, ARegion *ar)
@@ -583,6 +592,11 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
if (screen->animtimer) {
WM_event_remove_timer(wm, window, screen->animtimer);
+
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = WM_window_get_active_scene(prevwin);
+ Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
+ BKE_sound_stop_scene(scene_eval);
}
screen->animtimer = NULL;
screen->scrubbing = false;
@@ -630,14 +644,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
if (sa) {
if (az->type == AZONE_AREA) {
- WM_cursor_set(win, CURSOR_EDIT);
+ WM_cursor_set(win, WM_CURSOR_EDIT);
}
else if (az->type == AZONE_REGION) {
if (az->edge == AE_LEFT_TO_TOPRIGHT || az->edge == AE_RIGHT_TO_TOPLEFT) {
- WM_cursor_set(win, CURSOR_X_MOVE);
+ WM_cursor_set(win, WM_CURSOR_X_MOVE);
}
else {
- WM_cursor_set(win, CURSOR_Y_MOVE);
+ WM_cursor_set(win, WM_CURSOR_Y_MOVE);
}
}
}
@@ -646,14 +660,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
if (actedge) {
if (screen_geom_edge_is_horizontal(actedge)) {
- WM_cursor_set(win, CURSOR_Y_MOVE);
+ WM_cursor_set(win, WM_CURSOR_Y_MOVE);
}
else {
- WM_cursor_set(win, CURSOR_X_MOVE);
+ WM_cursor_set(win, WM_CURSOR_X_MOVE);
}
}
else {
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
}
@@ -1346,6 +1360,54 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
return sc->areabase.first;
}
+/**
+ * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
+ * by \a display_type.
+ *
+ * \param title: Title to set for the window, if a window is spawned.
+ * \param x, y: Position of the window, if a window is spawned.
+ * \param sizex, sizey: Dimensions of the window, if a window is spawned.
+ */
+ScrArea *ED_screen_temp_space_open(bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ eSpace_Type space_type,
+ int display_type,
+ bool dialog)
+{
+ ScrArea *sa = NULL;
+
+ switch (display_type) {
+ case USER_TEMP_SPACE_DISPLAY_WINDOW:
+ if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type, dialog)) {
+ sa = CTX_wm_area(C);
+ }
+ break;
+ case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: {
+ ScrArea *ctx_sa = CTX_wm_area(C);
+
+ if (ctx_sa->full) {
+ sa = ctx_sa;
+ ED_area_newspace(C, ctx_sa, space_type, true);
+ /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
+ sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
+ }
+ else if (ctx_sa->spacetype == space_type) {
+ sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED);
+ }
+ else {
+ sa = ED_screen_full_newspace(C, ctx_sa, (int)space_type);
+ }
+ break;
+ }
+ }
+
+ return sa;
+}
+
/* update frame rate info for viewport drawing */
void ED_refresh_viewport_fps(bContext *C)
{
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index f29535a7f0b..cc1f53eabde 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -38,7 +38,6 @@
#include "DNA_lattice_types.h"
#include "DNA_object_types.h"
#include "DNA_curve_types.h"
-#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
@@ -48,7 +47,6 @@
#include "DNA_userdef_types.h"
#include "BKE_context.h"
-#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -1043,28 +1041,28 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
/* Same area, so possible split. */
WM_cursor_set(
- win, (ELEM(sad->gesture_dir, 'n', 's')) ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR);
+ win, (ELEM(sad->gesture_dir, 'n', 's')) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
is_gesture = (delta_max > split_threshold);
}
else {
/* Different area, so possible join. */
if (sad->gesture_dir == 'n') {
- WM_cursor_set(win, BC_N_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (sad->gesture_dir == 's') {
- WM_cursor_set(win, BC_S_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (sad->gesture_dir == 'e') {
- WM_cursor_set(win, BC_E_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else {
- WM_cursor_set(win, BC_W_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
is_gesture = (delta_max > join_threshold);
}
}
else {
- WM_cursor_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_CROSS);
is_gesture = false;
}
}
@@ -1229,7 +1227,7 @@ static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
/* add modal handler */
- WM_cursor_modal_set(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_SWAP_AREA);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2121,7 +2119,7 @@ static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
{
wmWindow *win = CTX_wm_window(C);
int dir = RNA_enum_get(op->ptr, "direction");
- WM_cursor_set(win, (dir == 'n' || dir == 's') ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR);
+ WM_cursor_set(win, (dir == 'n' || dir == 's') ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
}
/* UI callback, adds new handler */
@@ -3420,19 +3418,19 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (dir == 1) {
- WM_cursor_set(win, BC_N_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (dir == 3) {
- WM_cursor_set(win, BC_S_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (dir == 2) {
- WM_cursor_set(win, BC_E_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else if (dir == 0) {
- WM_cursor_set(win, BC_W_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
else {
- WM_cursor_set(win, BC_STOPCURSOR);
+ WM_cursor_set(win, WM_CURSOR_STOP);
}
break;
@@ -3848,10 +3846,7 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
for (ar = sa->regionbase.first; ar; ar = arn) {
arn = ar->next;
if (ar->alignment == RGN_ALIGN_QSPLIT) {
- ED_region_exit(C, ar);
- BKE_area_region_free(sa->type, ar);
- BLI_remlink(&sa->regionbase, ar);
- MEM_freeN(ar);
+ ED_region_remove(C, sa, ar);
}
}
ED_area_tag_redraw(sa);
@@ -3951,7 +3946,7 @@ static int region_toggle_exec(bContext *C, wmOperator *op)
region = CTX_wm_region(C);
}
- if (region) {
+ if (region && (region->alignment != RGN_ALIGN_NONE)) {
ED_region_toggle_hidden(C, region);
}
ED_region_tag_redraw(region);
@@ -4833,7 +4828,14 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
int sizey = 520 * UI_DPI_FAC;
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_USERPREFS) != NULL) {
+ if (WM_window_open_temp(C,
+ IFACE_("Blender Preferences"),
+ event->x,
+ event->y,
+ sizex,
+ sizey,
+ SPACE_USERPREF,
+ false) != NULL) {
/* The header only contains the editor switcher and looks empty.
* So hiding in the temp window makes sense. */
ScrArea *area = CTX_wm_area(C);
@@ -4882,7 +4884,16 @@ static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent
but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_DRIVERS) != NULL) {
+ if (WM_window_open_temp(C,
+ IFACE_("Blender Drivers Editor"),
+ event->x,
+ event->y,
+ sizex,
+ sizey,
+ SPACE_GRAPH,
+ false) != NULL) {
+ ED_drivers_editor_init(C, CTX_wm_area(C));
+
/* activate driver F-Curve for the property under the cursor */
if (but) {
FCurve *fcu;
@@ -4938,7 +4949,14 @@ static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
int shift_y = 480;
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y + shift_y, sizex, sizey, WM_WINDOW_INFO) != NULL) {
+ if (WM_window_open_temp(C,
+ IFACE_("Blender Info Log"),
+ event->x,
+ event->y + shift_y,
+ sizex,
+ sizey,
+ SPACE_INFO,
+ false) != NULL) {
return OPERATOR_FINISHED;
}
else {
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 26849edeb44..661c17f55d2 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -52,27 +52,43 @@
#include "RNA_access.h"
/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
+static const char *screen_menu_context_string(const bContext *C, const SpaceLink *sl)
+{
+ if (sl->spacetype == SPACE_NODE) {
+ const SpaceNode *snode = (const SpaceNode *)sl;
+ return snode->tree_idname;
+ }
+ return CTX_data_mode_string(C);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Menu Type
* \{ */
bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
{
SpaceLink *sl = CTX_wm_space_data(C);
- const char *context = CTX_data_mode_string(C);
if (sl == NULL) {
*r_len = 0;
return NULL;
}
+ const char *context_mode = CTX_data_mode_string(C);
+ const char *context = screen_menu_context_string(C, sl);
uint array_len = 3;
bUserMenu **um_array = MEM_calloc_arrayN(array_len, sizeof(*um_array), __func__);
um_array[0] = BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
um_array[1] = (sl->spacetype != SPACE_TOPBAR) ?
- BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context) :
+ BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context_mode) :
NULL;
um_array[2] = (sl->spacetype == SPACE_VIEW3D) ?
- BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context) :
+ BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context_mode) :
NULL;
*r_len = array_len;
@@ -82,7 +98,7 @@ bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
bUserMenu *ED_screen_user_menu_ensure(bContext *C)
{
SpaceLink *sl = CTX_wm_space_data(C);
- const char *context = CTX_data_mode_string(C);
+ const char *context = screen_menu_context_string(C, sl);
return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
}
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 61b737589c8..bbb959c27ff 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -29,18 +29,13 @@
#include "BKE_appdir.h"
#include "BKE_blendfile.h"
#include "BKE_context.h"
-#include "BKE_idcode.h"
-#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
#include "BLO_readfile.h"
-#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
@@ -49,13 +44,9 @@
#include "ED_object.h"
#include "ED_screen.h"
-#include "MEM_guardedalloc.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
-#include "DEG_depsgraph.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
@@ -63,7 +54,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "WM_toolsystem.h"
#include "screen_intern.h"
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 752a5c36010..a5cc262ddcd 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/atomic
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
@@ -47,7 +48,6 @@ set(SRC
paint_image.c
paint_image_2d.c
paint_image_proj.c
- paint_image_undo.c
paint_mask.c
paint_ops.c
paint_stroke.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 5c83bdf0012..c59ab6279cd 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -91,6 +91,7 @@ typedef struct CursorSnapshot {
GLuint overlay_texture;
int size;
int zoom;
+ int curve_preset;
} CursorSnapshot;
static TexSnapshot primary_snap = {0};
@@ -409,7 +410,7 @@ static void load_tex_cursor_task_cb(void *__restrict userdata,
if (len <= 1.0f) {
float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */
- buffer[index] = 255 - (GLubyte)(255 * avg);
+ buffer[index] = (GLubyte)(255 * avg);
}
else {
buffer[index] = 0;
@@ -426,7 +427,8 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
int size;
const bool refresh = !cursor_snap.overlay_texture ||
- (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom;
+ (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom ||
+ cursor_snap.curve_preset != br->curve_preset;
init = (cursor_snap.overlay_texture != 0);
@@ -506,6 +508,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ cursor_snap.curve_preset = br->curve_preset;
BKE_paint_reset_overlay_invalid(PAINT_OVERLAY_INVALID_CURVE);
return 1;
@@ -1093,17 +1096,15 @@ static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush)
return true;
}
-static void cursor_draw_point_screen_space(const uint gpuattr,
- const ARegion *ar,
- const float true_location[3],
- const float obmat[4][4])
+static void cursor_draw_point_screen_space(
+ const uint gpuattr, const ARegion *ar, float true_location[3], float obmat[4][4], int size)
{
float translation_vertex_cursor[3], location[3];
copy_v3_v3(location, true_location);
mul_m4_v3(obmat, location);
ED_view3d_project(ar, location, translation_vertex_cursor);
imm_draw_circle_fill_3d(
- gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], 3, 10);
+ gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10);
}
static void cursor_draw_tiling_preview(const uint gpuattr,
@@ -1145,7 +1146,7 @@ static void cursor_draw_tiling_preview(const uint gpuattr,
for (dim = 0; dim < 3; dim++) {
location[dim] = cur[dim] * step[dim] + orgLoc[dim];
}
- cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
}
}
}
@@ -1166,7 +1167,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
/* Axis Symmetry */
flip_v3_v3(location, true_location, (char)i);
- cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
/* Tiling */
cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
@@ -1181,7 +1182,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
mul_m4_v3(symm_rot_mat, location);
cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
- cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
}
}
}
@@ -1191,7 +1192,13 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession *ss)
{
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f);
- GPU_depth_test(true);
+
+ /* Cursor normally draws on top, but for this part we need depth tests. */
+ const bool depth_test = GPU_depth_test_enabled();
+ if (!depth_test) {
+ GPU_depth_test(true);
+ }
+
GPU_line_width(1.0f);
if (ss->preview_vert_index_count > 0) {
immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count);
@@ -1200,10 +1207,24 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession
}
immEnd();
}
+
+ /* Restore depth test value. */
+ if (!depth_test) {
+ GPU_depth_test(false);
+ }
+}
+
+static bool paint_use_2d_cursor(ePaintMode mode)
+{
+ if (mode >= PAINT_MODE_TEXTURE_3D) {
+ return true;
+ }
+ return false;
}
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -1211,6 +1232,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
Brush *brush = BKE_paint_brush(paint);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ /* 2d or 3d painting? */
+ const bool use_2d_cursor = paint_use_2d_cursor(mode);
+
/* check that brush drawing is enabled */
if (ommit_cursor_drawing(paint, mode, brush)) {
return;
@@ -1219,7 +1243,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* can't use stroke vc here because this will be called during
* mouse over too, not just during a stroke */
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
return;
@@ -1237,7 +1261,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* set various defaults */
const float *outline_col = brush->add_col;
- const float outline_alpha = 0.5f;
+ const float outline_alpha = 0.7f;
float translation[2] = {x, y};
float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
@@ -1251,33 +1275,6 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* draw overlay */
bool alpha_overlay_active = paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
- /* TODO: as sculpt and other paint modes are unified, this
- * special mode of drawing will go away */
- if ((mode == PAINT_MODE_SCULPT) && vc.obact->sculpt) {
- float location[3];
- int pixel_radius;
-
- /* test if brush is over the mesh */
- bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
-
- if (BKE_brush_use_locked_size(scene, brush)) {
- BKE_brush_size_set(scene, brush, pixel_radius);
- }
-
- /* check if brush is subtracting, use different color then */
- /* TODO: no way currently to know state of pen flip or
- * invert key modifier without starting a stroke */
- if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
- BKE_brush_sculpt_has_secondary_color(brush)) {
- outline_col = brush->sub_col;
- }
-
- /* only do if brush is over the mesh */
- if (hit) {
- paint_cursor_on_hit(ups, brush, &vc, location);
- }
- }
-
if (ups->draw_anchored) {
final_radius = ups->anchored_size;
copy_v2_fl2(translation,
@@ -1290,148 +1287,239 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
GPU_blend(true); /* TODO: also set blend mode? */
GPU_line_smooth(true);
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ if (use_2d_cursor) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* set brush color */
- immUniformColor3fvAlpha(outline_col, outline_alpha);
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
- /* draw brush outline */
- if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
- /* inner at full alpha */
- imm_draw_circle_wire_2d(
- pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
- /* outer at half alpha */
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ /* draw brush outline */
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ imm_draw_circle_wire_2d(
+ pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ }
+
+ GPU_line_width(1.0f);
+ imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
}
+ else { /* 3d painting */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* TODO: as sculpt and other paint modes are unified, this
+ * special mode of drawing will go away */
+ Object *obact = vc.obact;
+ SculptSession *ss = obact ? obact->sculpt : NULL;
+ if ((mode == PAINT_MODE_SCULPT) && ss) {
+ float location[3];
+ int pixel_radius;
+
+ /* test if brush is over the mesh */
+ bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
+
+ if (BKE_brush_use_locked_size(scene, brush)) {
+ BKE_brush_size_set(scene, brush, pixel_radius);
+ }
- /* Only sculpt mode cursor for now */
+ /* check if brush is subtracting, use different color then */
+ /* TODO: no way currently to know state of pen flip or
+ * invert key modifier without starting a stroke */
+ if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
+ BKE_brush_sculpt_has_secondary_color(brush)) {
+ outline_col = brush->sub_col;
+ }
- /* Disable for PBVH_GRIDS */
- SculptSession *ss = vc.obact->sculpt;
- bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
+ /* only do if brush is over the mesh */
+ if (hit) {
+ paint_cursor_on_hit(ups, brush, &vc, location);
+ }
+ }
- if ((mode == PAINT_MODE_SCULPT) && ss && !is_multires &&
- !(brush->falloff_shape & BRUSH_AIRBRUSH)) {
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- wmWindow *win = CTX_wm_window(C);
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
- /* Update WM mouse cursor, disable when the 3D brush cursor is enabled */
- if (sd->paint.brush->overlay_flags & BRUSH_OVERLAY_CURSOR) {
- WM_cursor_set(win, CURSOR_STD);
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ imm_draw_circle_wire_3d(
+ pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
}
- else {
- WM_cursor_set(win, CURSOR_EDIT);
+
+ /* Only sculpt mode cursor for now */
+ /* Disable for PBVH_GRIDS */
+ bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
+
+ SculptCursorGeometryInfo gi;
+ float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin};
+ int prev_active_vertex_index = -1;
+ bool is_cursor_over_mesh = false;
+
+ /* Update the active vertex */
+ if ((mode == PAINT_MODE_SCULPT) && ss && !ups->stroke_active) {
+ prev_active_vertex_index = ss->active_vertex_index;
+ is_cursor_over_mesh = sculpt_cursor_geometry_info_update(
+ C, &gi, mouse, (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
}
+ /* Use special paint crosshair cursor in all paint modes*/
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, WM_CURSOR_PAINT);
- if (!ups->stroke_active) {
- SculptCursorGeometryInfo gi;
- float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin};
- if (sculpt_cursor_geometry_info_update(C, &gi, mouse, true) && !alpha_overlay_active) {
+ if ((mode == PAINT_MODE_SCULPT) && ss &&
+ (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)) {
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- float rds;
- if (!BKE_brush_use_locked_size(scene, brush)) {
- rds = paint_calc_object_space_radius(&vc, gi.location, BKE_brush_size_get(scene, brush));
- }
- else {
- rds = BKE_brush_unprojected_radius_get(scene, brush);
- }
+ if (!ups->stroke_active) {
+ bool update_previews = false;
+ if (is_cursor_over_mesh && !alpha_overlay_active) {
- wmViewport(&ar->winrct);
+ if (prev_active_vertex_index != ss->active_vertex_index) {
+ update_previews = true;
+ }
- /* Draw 3D active vertex preview with symmetry*/
- if (len_v3v3(gi.active_vertex_co, gi.location) < rds) {
- cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds);
- }
+ float rds;
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ rds = paint_calc_object_space_radius(
+ &vc, gi.location, BKE_brush_size_get(scene, brush));
+ }
+ else {
+ rds = BKE_brush_unprojected_radius_get(scene, brush);
+ }
- /* Draw 3D brush cursor */
- GPU_matrix_push_projection();
- ED_view3d_draw_setup_view(CTX_wm_window(C),
- CTX_data_depsgraph_pointer(C),
- CTX_data_scene(C),
- ar,
- CTX_wm_view3d(C),
- NULL,
- NULL,
- NULL);
-
- float cursor_trans[4][4], cursor_rot[4][4];
- float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
- float quat[4];
-
- copy_m4_m4(cursor_trans, vc.obact->obmat);
- translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]);
- rotation_between_vecs_to_quat(quat, z_axis, gi.normal);
- quat_to_mat4(cursor_rot, quat);
-
- GPU_matrix_push();
- GPU_matrix_mul(cursor_trans);
- GPU_matrix_mul(cursor_rot);
- imm_draw_circle_wire_3d(pos, 0, 0, rds, 40);
- GPU_matrix_pop();
-
- /* Update and draw dynamic mesh preview lines */
- GPU_matrix_push();
- GPU_matrix_mul(vc.obact->obmat);
- if (brush->sculpt_tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) {
- sculpt_geometry_preview_lines_update(C, ss, rds);
- sculpt_geometry_preview_lines_draw(pos, ss);
+ wmViewport(&ar->winrct);
+
+ /* Draw 3D active vertex preview with symmetry*/
+ if (len_v3v3(gi.active_vertex_co, gi.location) < rds) {
+ cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds);
+ }
+
+ /* Draw pose brush origin */
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ if (update_previews) {
+ BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false);
+ sculpt_pose_calc_pose_data(
+ sd, vc.obact, ss, gi.location, rds, brush->pose_offset, ss->pose_origin, NULL);
+ }
+ cursor_draw_point_screen_space(pos, ar, ss->pose_origin, vc.obact->obmat, 5);
+ }
+
+ /* Draw 3D brush cursor */
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(CTX_wm_window(C),
+ CTX_data_depsgraph_pointer(C),
+ CTX_data_scene(C),
+ ar,
+ CTX_wm_view3d(C),
+ NULL,
+ NULL,
+ NULL);
+
+ float cursor_trans[4][4], cursor_rot[4][4];
+ float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float quat[4];
+
+ copy_m4_m4(cursor_trans, vc.obact->obmat);
+ translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]);
+ rotation_between_vecs_to_quat(quat, z_axis, gi.normal);
+ quat_to_mat4(cursor_rot, quat);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(cursor_trans);
+ GPU_matrix_mul(cursor_rot);
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
+ GPU_line_width(2.0f);
+ imm_draw_circle_wire_3d(pos, 0, 0, rds, 80);
+ GPU_line_width(1.0f);
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ imm_draw_circle_wire_3d(pos, 0, 0, rds * clamp_f(brush->alpha, 0.0f, 1.0f), 80);
+ GPU_matrix_pop();
+
+ /* Update and draw dynamic mesh preview lines */
+ GPU_matrix_push();
+ GPU_matrix_mul(vc.obact->obmat);
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
+ !is_multires) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) {
+ sculpt_geometry_preview_lines_update(C, ss, rds);
+ sculpt_geometry_preview_lines_draw(pos, ss);
+ }
+ }
+
+ /* Draw pose brush line preview */
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ GPU_line_width(2.0f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, ss->pose_origin);
+ immVertex3fv(pos, gi.location);
+ immEnd();
}
- }
- GPU_matrix_pop();
- GPU_matrix_pop_projection();
+ GPU_matrix_pop();
- wmWindowViewport(win);
+ GPU_matrix_pop_projection();
+
+ wmWindowViewport(win);
+ }
+ else {
+ /* Draw default cursor when the mouse is not over the mesh or there are no supported
+ * overlays active */
+ GPU_line_width(1.0f);
+ /* Reduce alpha to increase the contrast when the cursor is over the mesh */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.8);
+ imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 80);
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.35f);
+ imm_draw_circle_wire_3d(pos,
+ translation[0],
+ translation[1],
+ final_radius * clamp_f(brush->alpha, 0.0f, 1.0f),
+ 80);
+ }
}
else {
- /* Draw default cursor when the mouse is not over the mesh or there are no supported
- * overlays active */
- GPU_line_width(1.0f);
- imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
- }
- }
- else {
- if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) {
- /* Draw cursor location preview when the stroke is active using the data from StrokeCache
- */
- float cursor_location[3];
- wmViewport(&ar->winrct);
- copy_v3_v3(cursor_location, ss->cache->true_location);
- if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) {
- add_v3_v3(cursor_location, ss->cache->grab_delta);
- }
- cursor_draw_point_with_symmetry(pos, ar, cursor_location, sd, vc.obact, ss->cache->radius);
-
- /* Draw cached dynamic mesh preview lines */
- if (brush->sculpt_tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) {
- GPU_matrix_push_projection();
- ED_view3d_draw_setup_view(CTX_wm_window(C),
- CTX_data_depsgraph_pointer(C),
- CTX_data_scene(C),
- ar,
- CTX_wm_view3d(C),
- NULL,
- NULL,
- NULL);
- GPU_matrix_push();
- GPU_matrix_mul(vc.obact->obmat);
- sculpt_geometry_preview_lines_draw(pos, ss);
- GPU_matrix_pop();
- GPU_matrix_pop_projection();
+ if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) {
+ /* Draw cursor location preview when the stroke is active using the data from StrokeCache
+ */
+ float cursor_location[3];
+ wmViewport(&ar->winrct);
+ copy_v3_v3(cursor_location, ss->cache->true_location);
+ if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) {
+ add_v3_v3(cursor_location, ss->cache->grab_delta);
+ }
+ cursor_draw_point_with_symmetry(
+ pos, ar, cursor_location, sd, vc.obact, ss->cache->radius);
+
+ /* Draw cached dynamic mesh preview lines */
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
+ !is_multires) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) {
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(CTX_wm_window(C),
+ CTX_data_depsgraph_pointer(C),
+ CTX_data_scene(C),
+ ar,
+ CTX_wm_view3d(C),
+ NULL,
+ NULL,
+ NULL);
+ GPU_matrix_push();
+ GPU_matrix_mul(vc.obact->obmat);
+ sculpt_geometry_preview_lines_draw(pos, ss);
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
+ }
}
- }
- wmWindowViewport(win);
+ wmWindowViewport(win);
+ }
}
}
- }
- else {
- /* Draw default cursor in unsupported modes */
- GPU_line_width(1.0f);
- imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
+ else {
+ /* Draw default cursor in unsupported modes */
+ GPU_line_width(1.0f);
+ imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
+ }
}
immUnbindProgram();
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index d9fd194e96f..62c31c91f8d 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -35,8 +35,6 @@
#include "BKE_main.h"
#include "BKE_paint.h"
-#include "DEG_depsgraph.h"
-
#include "ED_view3d.h"
#include "ED_paint.h"
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index bd62a59e73f..c14ccd27804 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -35,7 +35,6 @@
#include "ED_undo.h"
#include "WM_api.h"
-#include "WM_types.h"
#include "paint_intern.h"
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 5852012891d..026dc39c668 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -37,7 +37,6 @@
#include "BKE_ccg.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_subsurf.h"
@@ -135,7 +134,6 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
float planes[4][4])
{
CCGElem **grids;
- CCGKey key;
BLI_bitmap **grid_hidden;
int *grid_indices, totgrid, i;
bool any_changed = false, any_visible = false;
@@ -143,7 +141,7 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
/* get PBVH data */
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids);
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
- BKE_pbvh_get_grid_key(pbvh, &key);
+ CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
@@ -299,15 +297,17 @@ static void rect_from_props(rcti *rect, PointerRNA *ptr)
rect->ymax = RNA_int_get(ptr, "ymax");
}
-static void clip_planes_from_rect(bContext *C, float clip_planes[4][4], const rcti *rect)
+static void clip_planes_from_rect(bContext *C,
+ Depsgraph *depsgraph,
+ float clip_planes[4][4],
+ const rcti *rect)
{
ViewContext vc;
BoundBox bb;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect);
- negate_m4(clip_planes);
}
/* If mode is inside, get all PBVH nodes that lie at least partially
@@ -322,17 +322,18 @@ static void get_pbvh_nodes(
/* select search callback */
switch (mode) {
case PARTIALVIS_INSIDE:
- cb = BKE_pbvh_node_planes_contain_AABB;
+ cb = BKE_pbvh_node_frustum_contain_AABB;
break;
case PARTIALVIS_OUTSIDE:
- cb = BKE_pbvh_node_planes_exclude_AABB;
+ cb = BKE_pbvh_node_frustum_exclude_AABB;
break;
case PARTIALVIS_ALL:
case PARTIALVIS_MASKED:
break;
}
- BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
+ PBVHFrustumPlanes frustum = {.planes = clip_planes, .num_planes = 4};
+ BKE_pbvh_search_gather(pbvh, cb, &frustum, nodes, totnode);
}
static int hide_show_exec(bContext *C, wmOperator *op)
@@ -355,7 +356,7 @@ static int hide_show_exec(bContext *C, wmOperator *op)
area = RNA_enum_get(op->ptr, "area");
rect_from_props(&rect, op->ptr);
- clip_planes_from_rect(C, clip_planes, &rect);
+ clip_planes_from_rect(C, depsgraph, clip_planes, &rect);
pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
BLI_assert(ob->sculpt->pbvh == pbvh);
@@ -363,6 +364,8 @@ static int hide_show_exec(bContext *C, wmOperator *op)
get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
pbvh_type = BKE_pbvh_type(pbvh);
+ negate_m4(clip_planes);
+
/* start undo */
switch (action) {
case PARTIALVIS_HIDE:
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index f3a6cfa0d5c..b4388f6c324 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -113,10 +113,10 @@ void imapaint_region_tiles(
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
- *tw = ((x + w - 1) >> IMAPAINT_TILE_BITS);
- *th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
- *tx = (x >> IMAPAINT_TILE_BITS);
- *ty = (y >> IMAPAINT_TILE_BITS);
+ *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
+ *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
}
void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
@@ -147,11 +147,12 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
- image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
+ ED_image_paint_tile_push(
+ undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
}
}
@@ -467,12 +468,13 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda
static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2])
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
int mode = RNA_enum_get(op->ptr, "mode");
- ED_view3d_viewcontext_init(C, &pop->vc);
+ ED_view3d_viewcontext_init(C, &pop->vc, depsgraph);
copy_v2_v2(pop->prevmouse, mouse);
copy_v2_v2(pop->startmouse, mouse);
@@ -538,7 +540,7 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po
RNA_float_get_array(itemptr, "mouse", mouse);
pressure = RNA_float_get(itemptr, "pressure");
eraser = RNA_boolean_get(itemptr, "pen_flip");
- size = max_ff(1.0f, RNA_float_get(itemptr, "size"));
+ size = RNA_float_get(itemptr, "size");
/* stroking with fill tool only acts on stroke end */
if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
@@ -699,7 +701,7 @@ static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -1022,7 +1024,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
!RNA_boolean_get(op->ptr, "merged");
paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
- WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 8f1156295a3..9c95a3cee4d 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -374,25 +374,65 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
/* create a mask with the falloff strength */
static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
int diameter,
- float radius)
+ float radius,
+ const float pos[2])
{
Brush *brush = painter->brush;
- int xoff = -radius;
- int yoff = -radius;
+ int offset = (int)floorf(diameter / 2.0f);
unsigned short *mask, *m;
- int x, y;
mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
m = mask;
- for (y = 0; y < diameter; y++) {
- for (x = 0; x < diameter; x++, m++) {
- float xy[2] = {x + xoff, y + yoff};
- float len = len_v2(xy);
+ int aa_samples = 1.0f / (radius * 0.20f);
+ aa_samples = clamp_i(aa_samples, 3, 16);
- *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius));
+ /* Temporal until we have the brush properties */
+ const float hardness = 1.0f;
+ const float rotation = 0.0f;
+
+ float aa_offset = 1.0f / (2.0f * (float)aa_samples);
+ float aa_step = 1.0f / (float)aa_samples;
+
+ float bpos[2];
+ bpos[0] = pos[0] - floorf(pos[0]) + offset + aa_offset;
+ bpos[1] = pos[1] - floorf(pos[1]) + offset + aa_offset;
+
+ const float co = cosf(DEG2RADF(rotation));
+ const float si = sinf(DEG2RADF(rotation));
+
+ float norm_factor = 65535.0f / (float)(aa_samples * aa_samples);
+
+ for (int y = 0; y < diameter; y++) {
+ for (int x = 0; x < diameter; x++, m++) {
+ float total_samples = 0;
+ for (int i = 0; i < aa_samples; i++) {
+ for (int j = 0; j < aa_samples; j++) {
+ float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)};
+ float xy_rot[2];
+ sub_v2_v2(pixel_xy, bpos);
+
+ xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1];
+ xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1];
+
+ float len = len_v2(xy_rot);
+ float p = len / radius;
+ if (hardness < 1.0f) {
+ p = (p - hardness) / (1 - hardness);
+ p = 1.0f - p;
+ CLAMP(p, 0, 1);
+ }
+ else {
+ p = 1.0;
+ }
+ float hardness_factor = 3.0f * p * p - 2.0f * p * p * p;
+ float curve = BKE_brush_curve_strength_clamped(brush, len, radius);
+ total_samples += curve * hardness_factor;
+ }
+ }
+ *m = (unsigned short)(total_samples * norm_factor);
}
}
@@ -721,7 +761,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Brush *brush = painter->brush;
BrushPainterCache *cache = &painter->cache;
- const int diameter = 2 * size;
+ /* Adding 4 pixels of padding for brush antialiasing */
+ const int diameter = MAX2(1, size * 2) + 4;
bool do_random = false;
bool do_partial_update = false;
@@ -802,15 +843,13 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
/* curve mask can only change if the size changes */
- if (diameter != cache->lastdiameter) {
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- cache->curve_mask = NULL;
- }
-
- cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size);
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
+ cache->curve_mask = NULL;
}
+ cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos);
+
/* detect if we need to recreate image brush buffer */
if ((diameter != cache->lastdiameter) || (tex_rotation != cache->last_tex_rotation) ||
do_random || update_color) {
@@ -1197,23 +1236,24 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
int tileh)
{
ImBuf tmpbuf;
- IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+ IMB_initImBuf(&tmpbuf, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, 0);
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
for (int ty = tiley; ty <= tileh; ty++) {
for (int tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
unsigned short *mask;
- int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
- int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
+ int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE;
+ int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE;
if (s->canvas->rect_float) {
- tmpbuf.rect_float = image_undo_find_tile(
+ tmpbuf.rect_float = ED_image_paint_tile_find(
undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
}
else {
- tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ tmpbuf.rect = ED_image_paint_tile_find(
+ undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
}
IMB_rectblend(s->canvas,
@@ -1454,8 +1494,6 @@ static void paint_2d_canvas_free(ImagePaintState *s)
paint_delete_blur_kernel(s->blurkernel);
MEM_freeN(s->blurkernel);
}
-
- image_undo_remove_masks();
}
void paint_2d_stroke(void *ps,
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 04a54ad5137..4c7e5e18257 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -77,15 +77,11 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "UI_interface.h"
-
#include "ED_object.h"
-#include "ED_mesh.h"
#include "ED_node.h"
#include "ED_paint.h"
#include "ED_screen.h"
@@ -93,6 +89,7 @@
#include "ED_view3d.h"
#include "GPU_extensions.h"
+#include "GPU_init_exit.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -105,7 +102,6 @@
#include "IMB_colormanagement.h"
-#include "bmesh.h"
//#include "bmesh_tools.h"
#include "paint_intern.h"
@@ -1812,31 +1808,31 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
}
if (generate_tile) {
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
volatile void *undorect;
if (tinf->masked) {
- undorect = image_undo_push_tile(undo_tiles,
- pjIma->ima,
- pjIma->ibuf,
- tinf->tmpibuf,
- tx,
- ty,
- &pjIma->maskRect[tile_index],
- &pjIma->valid[tile_index],
- true,
- false);
+ undorect = ED_image_paint_tile_push(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ &pjIma->maskRect[tile_index],
+ &pjIma->valid[tile_index],
+ true,
+ false);
}
else {
- undorect = image_undo_push_tile(undo_tiles,
- pjIma->ima,
- pjIma->ibuf,
- tinf->tmpibuf,
- tx,
- ty,
- NULL,
- &pjIma->valid[tile_index],
- true,
- false);
+ undorect = ED_image_paint_tile_push(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ NULL,
+ &pjIma->valid[tile_index],
+ true,
+ false);
}
BKE_image_mark_dirty(pjIma->ima, pjIma->ibuf);
@@ -1885,14 +1881,14 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
/* calculate the undo tile offset of the pixel, used to store the original
* pixel color and accumulated mask if any */
- x_tile = x_px >> IMAPAINT_TILE_BITS;
- y_tile = y_px >> IMAPAINT_TILE_BITS;
+ x_tile = x_px >> ED_IMAGE_UNDO_TILE_BITS;
+ y_tile = y_px >> ED_IMAGE_UNDO_TILE_BITS;
- x_round = x_tile * IMAPAINT_TILE_SIZE;
- y_round = y_tile * IMAPAINT_TILE_SIZE;
+ x_round = x_tile * ED_IMAGE_UNDO_TILE_SIZE;
+ y_round = y_tile * ED_IMAGE_UNDO_TILE_SIZE;
// memset(projPixel, 0, size);
- tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE;
+ tile_offset = (x_px - x_round) + (y_px - y_round) * ED_IMAGE_UNDO_TILE_SIZE;
tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
/* other thread may be initializing the tile so wait here */
@@ -1900,8 +1896,9 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
/* pass */
}
- BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y)));
- BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE));
+ BLI_assert(tile_index <
+ (ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x) * ED_IMAGE_UNDO_TILE_NUMBER(ibuf->y)));
+ BLI_assert(tile_offset < (ED_IMAGE_UNDO_TILE_SIZE * ED_IMAGE_UNDO_TILE_SIZE));
projPixel->valid = projima->valid[tile_index];
@@ -2979,7 +2976,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
TileInfo tinf = {
ps->tile_lock,
ps->do_masking,
- IMAPAINT_TILE_NUMBER(ibuf->x),
+ ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x),
tmpibuf,
ps->projImages + image_index,
};
@@ -3931,7 +3928,7 @@ static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_th
BLI_spin_init(ps->tile_lock);
}
- image_undo_init_locks();
+ ED_image_paint_tile_lock_init();
}
for (a = 0; a < ps->thread_tot; a++) {
@@ -4249,8 +4246,8 @@ static void project_paint_build_proj_ima(ProjPaintState *ps,
projIma->ima = node->link;
projIma->touch = 0;
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
- size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) *
- IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
+ size = sizeof(void **) * ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->x) *
+ ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->y);
projIma->partRedrawRect = BLI_memarena_alloc(
arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
partial_redraw_array_init(projIma->partRedrawRect);
@@ -4540,8 +4537,6 @@ static void project_paint_end(ProjPaintState *ps)
{
int a;
- image_undo_remove_masks();
-
/* dereference used image buffers */
if (ps->is_shared_user == false) {
ProjPaintImage *projIma;
@@ -4583,7 +4578,7 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN((void *)ps->tile_lock);
}
- image_undo_end_locks();
+ ED_image_paint_tile_lock_end();
#ifndef PROJ_DEBUG_NOSEAMBLEED
if (ps->seam_bleed_px > 0.0f) {
@@ -6143,6 +6138,9 @@ static bool texture_paint_image_from_view_poll(bContext *C)
CTX_wm_operator_poll_msg_set(C, "No 3D viewport found to create image from");
return false;
}
+ if (!GPU_is_initialized()) {
+ return false;
+ }
return true;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
deleted file mode 100644
index 93dcd3ad0f6..00000000000
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ /dev/null
@@ -1,625 +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.
- *
- * 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 edsculpt
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_threads.h"
-
-#include "DNA_image_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_object_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "BKE_context.h"
-#include "BKE_image.h"
-#include "BKE_paint.h"
-#include "BKE_undo_system.h"
-
-#include "DEG_depsgraph.h"
-
-#include "ED_paint.h"
-#include "ED_undo.h"
-#include "ED_util.h"
-#include "ED_object.h"
-
-#include "GPU_draw.h"
-
-#include "WM_api.h"
-
-#include "paint_intern.h"
-
-/* -------------------------------------------------------------------- */
-/** \name Undo Conversion
- * \{ */
-
-typedef struct UndoImageTile {
- struct UndoImageTile *next, *prev;
-
- char ibufname[IMB_FILENAME_SIZE];
-
- union {
- float *fp;
- unsigned int *uint;
- void *pt;
- } rect;
-
- unsigned short *mask;
-
- int x, y;
-
- /* TODO(campbell): avoid storing the ID per tile,
- * adds unnecessary overhead restoring undo steps when most tiles share the same image. */
- UndoRefID_Image image_ref;
-
- short source;
- bool use_float;
- char gen_type;
- bool valid;
-
- size_t undo_size;
-} UndoImageTile;
-
-/* this is a static resource for non-globality,
- * Maybe it should be exposed as part of the
- * paint operation, but for now just give a public interface */
-static SpinLock undolock;
-
-void image_undo_init_locks(void)
-{
- BLI_spin_init(&undolock);
-}
-
-void image_undo_end_locks(void)
-{
- BLI_spin_end(&undolock);
-}
-
-/* UNDO */
-typedef enum {
- COPY = 0,
- RESTORE = 1,
- RESTORE_COPY = 2,
-} CopyMode;
-
-static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
-{
- if (mode == COPY) {
- /* copy or swap contents of tile->rect and region in ibuf->rect */
- IMB_rectcpy(tmpibuf,
- ibuf,
- 0,
- 0,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
-
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- else {
- if (mode == RESTORE_COPY) {
- IMB_rectcpy(tmpibuf,
- ibuf,
- 0,
- 0,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
- }
- /* swap to the tmpbuf for easy copying */
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
-
- IMB_rectcpy(ibuf,
- tmpibuf,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- 0,
- 0,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
-
- if (mode == RESTORE) {
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- }
-}
-
-void *image_undo_find_tile(ListBase *undo_tiles,
- Image *ima,
- ImBuf *ibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool validate)
-{
- UndoImageTile *tile;
- const bool use_float = (ibuf->rect_float != NULL);
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type &&
- ima->source == tile->source) {
- if (tile->use_float == use_float) {
- if (STREQ(tile->ibufname, ibuf->name)) {
- if (mask) {
- /* allocate mask if requested */
- if (!tile->mask) {
- tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE *
- IMAPAINT_TILE_SIZE,
- "UndoImageTile.mask");
- }
-
- *mask = tile->mask;
- }
- if (validate) {
- tile->valid = true;
- }
- return tile->rect.pt;
- }
- }
- }
- }
-
- return NULL;
-}
-
-void *image_undo_push_tile(ListBase *undo_tiles,
- Image *ima,
- ImBuf *ibuf,
- ImBuf **tmpibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool **valid,
- bool proj,
- bool find_prev)
-{
- UndoImageTile *tile;
- int allocsize;
- const bool use_float = (ibuf->rect_float != NULL);
- void *data;
-
- /* check if tile is already pushed */
-
- /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
- if (find_prev) {
- data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true);
- if (data) {
- return data;
- }
- }
-
- if (*tmpibuf == NULL) {
- *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
- }
-
- tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
- tile->x = x_tile;
- tile->y = y_tile;
-
- /* add mask explicitly here */
- if (mask) {
- *mask = tile->mask = MEM_callocN(
- sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, "UndoImageTile.mask");
- }
- allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
- allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
- tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
-
- BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
-
- tile->gen_type = ima->gen_type;
- tile->source = ima->source;
- tile->use_float = use_float;
- tile->valid = true;
- tile->image_ref.ptr = ima;
-
- if (valid) {
- *valid = &tile->valid;
- }
- undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
-
- if (proj) {
- BLI_spin_lock(&undolock);
- }
- BLI_addtail(undo_tiles, tile);
-
- if (proj) {
- BLI_spin_unlock(&undolock);
- }
- return tile->rect.pt;
-}
-
-void image_undo_remove_masks(void)
-{
- ListBase *undo_tiles = ED_image_undo_get_tiles();
- UndoImageTile *tile;
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->mask) {
- MEM_freeN(tile->mask);
- tile->mask = NULL;
- }
- }
-}
-
-static void image_undo_restore_runtime(ListBase *lb)
-{
- ImBuf *ibuf, *tmpibuf;
- UndoImageTile *tile;
-
- tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
- for (tile = lb->first; tile; tile = tile->next) {
- Image *ima = tile->image_ref.ptr;
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
-
- GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-static void image_undo_restore_list(ListBase *lb)
-{
- ImBuf *tmpibuf = IMB_allocImBuf(
- IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
- for (UndoImageTile *tile = lb->first; tile; tile = tile->next) {
-
- Image *ima = tile->image_ref.ptr;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
- /* current ImBuf filename was changed, probably current frame
- * was changed when painting on image sequence, rather than storing
- * full image user (which isn't so obvious, btw) try to find ImBuf with
- * matched file name in list of already loaded images */
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
- }
-
- if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- if (ima->gen_type != tile->gen_type || ima->source != tile->source) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- const bool use_float = (ibuf->rect_float != NULL);
-
- if (use_float != tile->use_float) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
-
- BKE_image_mark_dirty(ima, ibuf);
- GPU_free_image(ima); /* force OpenGL reload */
-
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- DEG_id_tag_update(&ima->id, 0);
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-static void image_undo_free_list(ListBase *lb)
-{
- for (UndoImageTile *tile = lb->first, *tile_next; tile; tile = tile_next) {
- tile_next = tile->next;
- MEM_freeN(tile->rect.pt);
- MEM_freeN(tile);
- }
-}
-
-static void image_undo_invalidate(void)
-{
- UndoImageTile *tile;
- ListBase *lb = ED_image_undo_get_tiles();
-
- for (tile = lb->first; tile; tile = tile->next) {
- tile->valid = false;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Implements ED Undo System
- * \{ */
-
-typedef struct ImageUndoStep {
- UndoStep step;
- ListBase tiles;
- bool is_encode_init;
- ePaintMode paint_mode;
-} ImageUndoStep;
-
-static bool image_undosys_poll(bContext *C)
-{
- Object *obact = CTX_data_active_object(C);
-
- ScrArea *sa = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_IMAGE)) {
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
- if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
- return true;
- }
- }
- else {
- if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
- return true;
- }
- }
- return false;
-}
-
-static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* dummy, memory is cleared anyway. */
- us->is_encode_init = true;
- BLI_listbase_clear(&us->tiles);
-}
-
-static bool image_undosys_step_encode(struct bContext *C,
- struct Main *UNUSED(bmain),
- UndoStep *us_p)
-{
- /* dummy, encoding is done along the way by adding tiles
- * to the current 'ImageUndoStep' added by encode_init. */
- ImageUndoStep *us = (ImageUndoStep *)us_p;
-
- BLI_assert(us->step.data_size == 0);
-
- int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
-
- if (us->is_encode_init) {
- /* first dispose of invalid tiles (may happen due to drag dot for instance) */
- for (UndoImageTile *tile = us->tiles.first; tile;) {
- if (!tile->valid) {
- UndoImageTile *tmp_tile = tile->next;
- MEM_freeN(tile->rect.pt);
- BLI_freelinkN(&us->tiles, tile);
- tile = tmp_tile;
- }
- else {
- us->step.data_size += allocsize * (tile->use_float ? sizeof(float) : sizeof(char));
- tile = tile->next;
- }
- }
- }
- else {
- /* Happens when switching modes. */
- ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
- }
-
- us_p->is_applied = true;
-
- return true;
-}
-
-static void image_undosys_step_decode_undo_impl(ImageUndoStep *us)
-{
- BLI_assert(us->step.is_applied == true);
- image_undo_restore_list(&us->tiles);
- us->step.is_applied = false;
-}
-
-static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
-{
- BLI_assert(us->step.is_applied == false);
- image_undo_restore_list(&us->tiles);
- us->step.is_applied = true;
-}
-
-static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
-{
- ImageUndoStep *us_iter = us;
- while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
- if (us_iter->step.next->is_applied == false) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
- while (us_iter != us || (!is_final && us_iter == us)) {
- image_undosys_step_decode_undo_impl(us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
-}
-
-static void image_undosys_step_decode_redo(ImageUndoStep *us)
-{
- ImageUndoStep *us_iter = us;
- while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
- if (us_iter->step.prev->is_applied == true) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
- while (us_iter && (us_iter->step.is_applied == false)) {
- image_undosys_step_decode_redo_impl(us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
-}
-
-static void image_undosys_step_decode(
- struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- if (dir < 0) {
- image_undosys_step_decode_undo(us, is_final);
- }
- else {
- image_undosys_step_decode_redo(us);
- }
-
- if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
- ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
- }
-
- /* Refresh texture slots. */
- ED_editors_init_for_undo(bmain);
-}
-
-static void image_undosys_step_free(UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- image_undo_free_list(&us->tiles);
-}
-
-static void image_undosys_foreach_ID_ref(UndoStep *us_p,
- UndoTypeForEachIDRefFn foreach_ID_ref_fn,
- void *user_data)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&tile->image_ref));
- }
-}
-
-/* Export for ED_undo_sys. */
-void ED_image_undosys_type(UndoType *ut)
-{
- ut->name = "Image";
- ut->poll = image_undosys_poll;
- ut->step_encode_init = image_undosys_step_encode_init;
- ut->step_encode = image_undosys_step_encode;
- ut->step_decode = image_undosys_step_decode;
- ut->step_free = image_undosys_step_free;
-
- ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
-
- ut->use_context = true;
-
- ut->step_size = sizeof(ImageUndoStep);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Utilities
- * \{ */
-
-ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- return &us->tiles;
-}
-
-ListBase *ED_image_undo_get_tiles(void)
-{
- UndoStack *ustack = ED_undo_stack_get();
- UndoStep *us_prev = ustack->step_init;
- UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* We should always have an undo push started when accessing tiles,
- * not doing this means we won't have paint_mode correctly set. */
- BLI_assert(us_p == us_prev);
- if (us_p != us_prev) {
- /* Fallback value until we can be sure this never happens. */
- us->paint_mode = PAINT_MODE_TEXTURE_2D;
- }
- return ED_image_undosys_step_get_tiles(us_p);
-}
-
-/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
-void ED_image_undo_restore(UndoStep *us)
-{
- ListBase *lb = ED_image_undosys_step_get_tiles(us);
- image_undo_restore_runtime(lb);
- image_undo_invalidate();
-}
-
-void ED_image_undo_push_begin(const char *name, int paint_mode)
-{
- UndoStack *ustack = ED_undo_stack_get();
- bContext *C = NULL; /* special case, we never read from this. */
- UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
-}
-
-void ED_image_undo_push_end(void)
-{
- UndoStack *ustack = ED_undo_stack_get();
- BKE_undosys_step_push(ustack, NULL, NULL);
- WM_file_tag_modified();
-}
-
-/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 5efedf69fe4..19380fb9022 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -29,7 +29,6 @@ struct Brush;
struct ColorManagedDisplay;
struct ColorSpace;
struct ImagePool;
-struct ListBase;
struct MTex;
struct Object;
struct Paint;
@@ -37,7 +36,6 @@ struct PaintStroke;
struct PointerRNA;
struct RegionView3D;
struct Scene;
-struct UndoStep;
struct VPaint;
struct ViewContext;
struct bContext;
@@ -70,7 +68,7 @@ struct PaintStroke *paint_stroke_new(struct bContext *C,
StrokeRedraw redraw,
StrokeDone done,
int event_type);
-void paint_stroke_data_free(struct wmOperator *op);
+void paint_stroke_free(struct bContext *C, struct wmOperator *op);
bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode);
bool paint_supports_dynamic_size(struct Brush *br, enum ePaintMode mode);
@@ -184,10 +182,6 @@ typedef struct ImagePaintPartialRedraw {
int enabled;
} ImagePaintPartialRedraw;
-#define IMAPAINT_TILE_BITS 6
-#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
-#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
-
bool image_texture_paint_poll(struct bContext *C);
void imapaint_image_update(struct SpaceImage *sima,
struct Image *image,
@@ -252,31 +246,6 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
-/* paint_image_undo.c */
-void *image_undo_find_tile(ListBase *undo_tiles,
- struct Image *ima,
- struct ImBuf *ibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool validate);
-void *image_undo_push_tile(ListBase *undo_tiles,
- struct Image *ima,
- struct ImBuf *ibuf,
- struct ImBuf **tmpibuf,
- int x_tile,
- int y_tile,
- unsigned short **,
- bool **valid,
- bool proj,
- bool find_prev);
-void image_undo_remove_masks(void);
-void image_undo_init_locks(void);
-void image_undo_end_locks(void);
-
-struct ListBase *ED_image_undosys_step_get_tiles(struct UndoStep *us_p);
-struct ListBase *ED_image_undo_get_tiles(void);
-
/* sculpt_uv.c */
void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 0e8d4d75360..d160fba4013 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -109,6 +109,7 @@ static void mask_flood_fill_task_cb(void *__restrict userdata,
const PaintMaskFloodMode mode = data->mode;
const float value = data->value;
+ bool redraw = false;
PBVHVertexIter vi;
@@ -116,13 +117,19 @@ static void mask_flood_fill_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
{
+ float prevmask = *vi.mask;
mask_flood_fill_set_elem(vi.mask, mode, value);
+ if (prevmask != *vi.mask) {
+ redraw = true;
+ }
}
BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_redraw(node);
- if (data->multires) {
- BKE_pbvh_node_mark_normals_update(node);
+ if (redraw) {
+ BKE_pbvh_node_mark_update_mask(node);
+ if (data->multires) {
+ BKE_pbvh_node_mark_normals_update(node);
+ }
}
}
@@ -159,17 +166,16 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
.value = value,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
-
- 0, totnode, &data, mask_flood_fill_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings);
if (multires) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
if (nodes) {
@@ -255,24 +261,32 @@ static void mask_box_select_task_cb(void *__restrict userdata,
PBVHVertexIter vi;
bool any_masked = false;
+ bool redraw = false;
BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
{
if (is_effected(clip_planes_final, vi.co)) {
+ float prevmask = *vi.mask;
if (!any_masked) {
any_masked = true;
sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
- BKE_pbvh_node_mark_redraw(node);
if (data->multires) {
BKE_pbvh_node_mark_normals_update(node);
}
}
mask_flood_fill_set_elem(vi.mask, mode, value);
+ if (prevmask != *vi.mask) {
+ redraw = true;
+ }
}
}
BKE_pbvh_vertex_iter_end;
+
+ if (redraw) {
+ BKE_pbvh_node_mark_update_mask(node);
+ }
}
bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select)
@@ -297,7 +311,6 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
/* transform the clip planes in object space */
ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect);
- negate_m4(clip_planes);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
pbvh = ob->sculpt->pbvh;
@@ -315,8 +328,10 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
flip_plane(clip_planes_final[j], clip_planes[j], symmpass);
}
- BKE_pbvh_search_gather(
- pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+ PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4};
+ BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode);
+
+ negate_m4(clip_planes_final);
MaskTaskData data = {
.ob = ob,
@@ -328,11 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
.clip_planes_final = clip_planes_final,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
if (nodes) {
MEM_freeN(nodes);
@@ -344,6 +357,8 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
ED_region_tag_redraw(ar);
@@ -462,7 +477,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* Calculations of individual vertices are done in 2D screen space to diminish the amount of
* calculations done. Bounding box PBVH collision is not computed against enclosing rectangle
* of lasso */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
/* lasso data calculations */
data.vc = &vc;
@@ -483,7 +498,6 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
&data);
ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect);
- negate_m4(clip_planes);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
pbvh = ob->sculpt->pbvh;
@@ -505,8 +519,11 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* gather nodes inside lasso's enclosing rectangle
* (should greatly help with bigger meshes) */
+ PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4};
BKE_pbvh_search_gather(
- pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+ pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode);
+
+ negate_m4(clip_planes_final);
data.task_data.ob = ob;
data.task_data.pbvh = pbvh;
@@ -515,11 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.task_data.mode = mode;
data.task_data.value = value;
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- (totnode > SCULPT_THREADED_LIMIT));
- BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
if (nodes) {
MEM_freeN(nodes);
@@ -531,6 +546,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
ED_region_tag_redraw(vc.ar);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index f58afcdadc1..97455d479dc 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -29,32 +29,22 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
-#include "DNA_gpencil_types.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_gpencil.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_paint.h"
-#include "BKE_report.h"
-
-#include "DEG_depsgraph.h"
#include "ED_paint.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
#include "ED_image.h"
-#include "ED_gpencil.h"
-#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index c764933fcf0..36418045551 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -43,7 +43,6 @@
#include "BKE_curve.h"
#include "BKE_colortools.h"
#include "BKE_image.h"
-#include "BKE_mesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -257,6 +256,7 @@ static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode m
SCULPT_TOOL_GRAB,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_POSE)) {
return false;
@@ -669,7 +669,7 @@ static float paint_space_stroke_spacing(bContext *C,
return max_ff(0.001f, size_clamp * spacing / 50.f);
}
else {
- return max_ff(1.0, size_clamp * spacing / 50.0f);
+ return max_ff(stroke->zoom_2d, size_clamp * spacing / 50.0f);
}
}
@@ -808,7 +808,7 @@ static int paint_space_stroke(bContext *C,
while (length > 0.0f) {
float spacing = paint_space_stroke_spacing_variable(
C, scene, stroke, pressure, dpressure, length);
- float mouse[2];
+ float mouse[3];
if (length >= spacing) {
if (use_scene_spacing) {
@@ -857,14 +857,16 @@ PaintStroke *paint_stroke_new(bContext *C,
StrokeDone done,
int event_type)
{
+ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
ToolSettings *toolsettings = CTX_data_tool_settings(C);
UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
Paint *p = BKE_paint_get_active_from_context(C);
Brush *br = stroke->brush = BKE_paint_brush(p);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
float zoomx, zoomy;
- ED_view3d_viewcontext_init(C, &stroke->vc);
+ ED_view3d_viewcontext_init(C, &stroke->vc, depsgraph);
stroke->get_location = get_location;
stroke->test_start = test_start;
@@ -887,6 +889,10 @@ PaintStroke *paint_stroke_new(bContext *C,
ups->overlap_factor = 1.0;
ups->stroke_active = true;
+ if (rv3d) {
+ rv3d->rflag |= RV3D_PAINTING;
+ }
+
zero_v3(ups->average_stroke_accum);
ups->average_stroke_counter = 0;
@@ -901,20 +907,46 @@ PaintStroke *paint_stroke_new(bContext *C,
return stroke;
}
-void paint_stroke_data_free(struct wmOperator *op)
+void paint_stroke_free(bContext *C, wmOperator *op)
{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d) {
+ rv3d->rflag &= ~RV3D_PAINTING;
+ }
+
BKE_paint_set_overlay_override(0);
+
+ PaintStroke *stroke = op->customdata;
+ if (stroke == NULL) {
+ return;
+ }
+
+ UnifiedPaintSettings *ups = stroke->ups;
+ ups->draw_anchored = false;
+ ups->stroke_active = false;
+
+ if (stroke->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
+ }
+
+ if (stroke->rng) {
+ BLI_rng_free(stroke->rng);
+ }
+
+ if (stroke->stroke_cursor) {
+ WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+ }
+
+ BLI_freelistN(&stroke->line);
+
MEM_SAFE_FREE(op->customdata);
}
-static void stroke_done(struct bContext *C, struct wmOperator *op)
+static void stroke_done(bContext *C, wmOperator *op)
{
- struct PaintStroke *stroke = op->customdata;
+ PaintStroke *stroke = op->customdata;
UnifiedPaintSettings *ups = stroke->ups;
- ups->draw_anchored = false;
- ups->stroke_active = false;
-
/* reset rotation here to avoid doing so in cursor display */
if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
ups->brush_rotation = 0.0f;
@@ -934,21 +966,7 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
}
}
- if (stroke->timer) {
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
- }
-
- if (stroke->rng) {
- BLI_rng_free(stroke->rng);
- }
-
- if (stroke->stroke_cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
- }
-
- BLI_freelistN(&stroke->line);
-
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
}
/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
@@ -962,6 +980,7 @@ static bool sculpt_is_grab_tool(Brush *br)
return ELEM(br->sculpt_tool,
SCULPT_TOOL_GRAB,
SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK);
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 6459325e6ee..a014fe7fdff 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -46,7 +46,6 @@
#include "BKE_image.h"
#include "BKE_material.h"
#include "BKE_mesh_runtime.h"
-#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
@@ -145,7 +144,6 @@ void paint_calc_redraw_planes(float planes[4][4],
rect.ymax += 2;
ED_view3d_clipping_calc(&bb, planes, ar, ob, &rect);
- negate_m4(planes);
}
float paint_calc_object_space_radius(ViewContext *vc, const float center[3], float pixel_radius)
@@ -506,7 +504,7 @@ void paint_sample_color(
unsigned int totpoly = me->totpoly;
if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
view3d_operator_needs_opengl(C);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 12da8790b91..77c95c6acb3 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -34,7 +34,6 @@
#include "BLI_array_utils.h"
#include "BLI_task.h"
-#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
@@ -42,7 +41,6 @@
#include "DNA_object_types.h"
#include "RNA_access.h"
-#include "RNA_define.h"
#include "BKE_brush.h"
#include "BKE_context.h"
@@ -195,17 +193,12 @@ static bool vertex_paint_use_fast_update_check(Object *ob)
return false;
}
-static void paint_last_stroke_update(Scene *scene, ARegion *ar, const float mval[2])
+static void paint_last_stroke_update(Scene *scene, const float location[3])
{
- const int mval_i[2] = {mval[0], mval[1]};
- float world[3];
-
- if (ED_view3d_autodist_simple(ar, mval_i, world, 0, NULL)) {
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- ups->average_stroke_counter++;
- add_v3_v3(ups->average_stroke_accum, world);
- ups->last_stroke_valid = true;
- }
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ ups->average_stroke_counter++;
+ add_v3_v3(ups->average_stroke_accum, location);
+ ups->last_stroke_valid = true;
}
/* polling - retrieve whether cursor should be set or operator should be done */
@@ -260,7 +253,7 @@ static bool weight_paint_poll_ex(bContext *C, bool check_tool)
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
(sa = CTX_wm_area(C)) && (sa->spacetype == SPACE_VIEW3D)) {
ARegion *ar = CTX_wm_region(C);
- if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_HUD)) {
if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
return 1;
}
@@ -1610,7 +1603,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* make mode data storage */
wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
paint_stroke_set_mode_data(stroke, wpd);
- ED_view3d_viewcontext_init(C, &wpd->vc);
+ ED_view3d_viewcontext_init(C, &wpd->vc, depsgraph);
view_angle_limits_init(&wpd->normal_angle_precalc,
vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
@@ -2079,11 +2072,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data,
struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) &&
- totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
uint accum_len = 0;
double accum_weight = 0.0;
@@ -2128,24 +2119,23 @@ static void wpaint_paint_leaves(bContext *C,
/* Use this so average can modify its weight without touching the brush. */
data.strength = BKE_brush_weight_get(scene, brush);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
/* NOTE: current mirroring code cannot be run in parallel */
- settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode);
switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
case WPAINT_TOOL_AVERAGE:
calculate_average_weight(&data, nodes, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
case WPAINT_TOOL_SMEAR:
- BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
break;
case WPAINT_TOOL_BLUR:
- BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
break;
case WPAINT_TOOL_DRAW:
- BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
@@ -2351,7 +2341,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, ss->cache->mouse);
+ paint_last_stroke_update(scene, ss->cache->location);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -2446,7 +2436,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -2597,11 +2587,6 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
* - revise whether op->customdata should be added in object, in set_vpaint
*/
-typedef struct PolyFaceMap {
- struct PolyFaceMap *next, *prev;
- int facenr;
-} PolyFaceMap;
-
struct VPaintData {
ViewContext vc;
struct NormalAnglePrecalc normal_angle_precalc;
@@ -2655,7 +2640,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
/* make mode data storage */
vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
paint_stroke_set_mode_data(stroke, vpd);
- ED_view3d_viewcontext_init(C, &vpd->vc);
+ ED_view3d_viewcontext_init(C, &vpd->vc, depsgraph);
view_angle_limits_init(&vpd->normal_angle_precalc,
vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
@@ -3141,9 +3126,9 @@ static void calculate_average_color(SculptThreadedTaskData *data,
struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BKE_pbvh_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
uint accum_len = 0;
uint accum_value[3] = {0};
@@ -3187,21 +3172,21 @@ static void vpaint_paint_leaves(bContext *C,
.lcol = (uint *)me->mloopcol,
.me = me,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
case VPAINT_TOOL_AVERAGE:
calculate_average_color(&data, nodes, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
case VPAINT_TOOL_BLUR:
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
break;
case VPAINT_TOOL_SMEAR:
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
break;
case VPAINT_TOOL_DRAW:
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
@@ -3331,7 +3316,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, ss->cache->mouse);
+ paint_last_stroke_update(scene, ss->cache->location);
ED_region_tag_redraw(vc->ar);
@@ -3388,7 +3373,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index 068c36abdaa..71865d0de73 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -20,13 +20,9 @@
* Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`.
*/
-#include "MEM_guardedalloc.h"
-
-#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BLI_math_base.h"
#include "BLI_math_color.h"
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index 4aa9dc8a295..f0fe2d4ebdc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -24,13 +24,8 @@
#include "BLI_math.h"
#include "BLI_bitmap.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_colormanagement.h"
-
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_particle_types.h"
#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -44,7 +39,6 @@
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
-#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object_deform.h"
@@ -178,11 +172,12 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot)
/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Mesh *me;
bool changed = false;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
@@ -308,10 +303,11 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
if (C) {
wmWindow *win = CTX_wm_window(C);
if (win && win->eventstate) {
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ViewContext vc;
Mesh *me;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
@@ -379,8 +375,9 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
static int weight_sample_group_exec(bContext *C, wmOperator *op)
{
int type = RNA_enum_get(op->ptr, "group");
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
BLI_assert(type + 1 >= 0);
vc.obact->actdef = type + 1;
@@ -885,7 +882,7 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index c71315872f6..28699b45add 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -20,16 +20,12 @@
* Intended for use by `paint_vertex.c` & `paint_vertex_weight_ops.c`.
*/
-#include "MEM_guardedalloc.h"
-
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "BKE_action.h"
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 351e4c0482b..06fa03ccbc6 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -27,13 +27,11 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_dial_2d.h"
-#include "BLI_hash.h"
#include "BLI_gsqueue.h"
-#include "BLI_stack.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.h"
#include "BLI_task.h"
-#include "BLI_stack.h"
#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
#include "BLT_translation.h"
@@ -66,10 +64,10 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -96,21 +94,13 @@
#include <stdlib.h>
#include <string.h>
-/* Sculpt PBVH abstraction API */
-
-/* Do not use these functions while working with PBVH_GRIDS data in SculptSession */
-
-float *sculpt_vertex_co_get(SculptSession *ss, int index)
-{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- return ss->mvert[index].co;
- case PBVH_BMESH:
- return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co;
- default:
- return NULL;
- }
-}
+/* Sculpt PBVH abstraction API
+ *
+ * This is read-only, for writing use PBVH vertex iterators. There vd.index matches
+ * the indices used here.
+ *
+ * For multires, the same vertex in multiple grids is counted multiple times, with
+ * different index for each grid. */
static void sculpt_vertex_random_access_init(SculptSession *ss)
{
@@ -119,28 +109,36 @@ static void sculpt_vertex_random_access_init(SculptSession *ss)
}
}
-static int sculpt_active_vertex_get(SculptSession *ss)
+static int sculpt_vertex_count_get(SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- return ss->active_vertex_index;
+ return ss->totvert;
case PBVH_BMESH:
- return ss->active_vertex_index;
- default:
- return 0;
+ return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT);
+ case PBVH_GRIDS:
+ return BKE_pbvh_get_grid_num_vertices(ss->pbvh);
}
+
+ return 0;
}
-static int sculpt_vertex_count_get(SculptSession *ss)
+const float *sculpt_vertex_co_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- return ss->totvert;
+ return ss->mvert[index].co;
case PBVH_BMESH:
- return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT);
- default:
- return 0;
+ return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index));
+ }
}
+ return NULL;
}
static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3])
@@ -152,27 +150,14 @@ static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3])
case PBVH_BMESH:
copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
break;
- default:
- zero_v3(no);
- return;
- }
-}
-
-static void sculpt_vertex_mask_set(SculptSession *ss, int index, float mask)
-{
- BMVert *v;
- float *mask_p;
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- ss->vmask[index] = mask;
- return;
- case PBVH_BMESH:
- v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
- mask_p = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
- *(mask_p) = mask;
- return;
- default:
- return;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ copy_v3_v3(no, CCG_elem_no(key, CCG_elem_offset(key, elem, vertex_index)));
+ break;
+ }
}
}
@@ -187,49 +172,58 @@ static float sculpt_vertex_mask_get(SculptSession *ss, int index)
v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
return *mask;
- default:
- return 0;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index));
+ }
}
+
+ return 0.0f;
}
-static void UNUSED_FUNCTION(sculpt_vertex_co_set)(SculptSession *ss, int index, float co[3])
+static int sculpt_active_vertex_get(SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- copy_v3_v3(ss->mvert[index].co, co);
- return;
+ return ss->active_vertex_index;
case PBVH_BMESH:
- copy_v3_v3(BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co, co);
- return;
- default:
- return;
+ return ss->active_vertex_index;
+ case PBVH_GRIDS:
+ return ss->active_vertex_index;
}
+
+ return 0;
}
-static void UNUSED_FUNCTION(sculpt_vertex_tag_update)(SculptSession *ss, int index)
+static const float *sculpt_active_vertex_co_get(SculptSession *ss)
{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- ss->mvert[index].flag |= ME_VERT_PBVH_UPDATE;
- return;
- case PBVH_BMESH:
- return;
- default:
- return;
- }
+ return sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss));
+}
+
+static void sculpt_active_vertex_normal_get(SculptSession *ss, float normal[3])
+{
+ sculpt_vertex_normal_get(ss, sculpt_active_vertex_get(ss), normal);
}
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
typedef struct SculptVertexNeighborIter {
+ /* Storage */
int *neighbors;
int size;
int capacity;
-
int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
- int index;
+ /* Internal iterator. */
+ int num_duplicates;
int i;
+
+ /* Public */
+ int index;
+ bool is_duplicate;
} SculptVertexNeighborIter;
static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index)
@@ -265,6 +259,7 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
BMIter liter;
BMLoop *l;
iter->size = 0;
+ iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
@@ -287,6 +282,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
int i;
MeshElemMap *vert_map = &ss->pmap[(int)index];
iter->size = 0;
+ iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
@@ -296,18 +292,52 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
if (poly_get_adj_loops_from_vert(p, ss->mloop, (int)index, f_adj_v) != -1) {
int j;
for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
- if (f_adj_v[j] != (int)index) {
- sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
- }
+ if (f_adj_v[j] != (int)index) {
+ sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
}
}
}
}
}
+static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
+ const int index,
+ const bool include_duplicates,
+ SculptVertexNeighborIter *iter)
+{
+ /* TODO: optimize this. We could fill SculptVertexNeighborIter directly,
+ * maybe provide coordinate and mask pointers directly rather than converting
+ * back and forth between CCGElem and global index. */
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+
+ SubdivCCGCoord coord = {.grid_index = grid_index,
+ .x = vertex_index % key->grid_size,
+ .y = vertex_index / key->grid_size};
+
+ SubdivCCGNeighbors neighbors;
+ BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, include_duplicates, &neighbors);
+
+ iter->size = 0;
+ iter->num_duplicates = neighbors.num_duplicates;
+ iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
+ iter->neighbors = iter->neighbors_fixed;
+
+ for (int i = 0; i < neighbors.size; i++) {
+ sculpt_vertex_neighbor_add(iter,
+ neighbors.coords[i].grid_index * key->grid_area +
+ neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x);
+ }
+
+ if (neighbors.coords != neighbors.coords_fixed) {
+ MEM_freeN(neighbors.coords);
+ }
+}
+
static void sculpt_vertex_neighbors_get(SculptSession *ss,
- int index,
+ const int index,
+ const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
switch (BKE_pbvh_type(ss->pbvh)) {
@@ -317,17 +347,29 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss,
case PBVH_BMESH:
sculpt_vertex_neighbors_get_bmesh(ss, index, iter);
return;
- default:
- break;
+ case PBVH_GRIDS:
+ sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter);
+ return;
}
}
+/* Iterator over neighboring vertices. */
#define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
- sculpt_vertex_neighbors_get(ss, v_index, &neighbor_iterator); \
+ sculpt_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
neighbor_iterator.index = ni.neighbors[ni.i];
+/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
+ * first since they are nearest for floodfill. */
+#define sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
+ sculpt_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
+ for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
+ neighbor_iterator.i--) { \
+ neighbor_iterator.index = ni.neighbors[ni.i]; \
+ neighbor_iterator.is_duplicate = (ni.i >= \
+ neighbor_iterator.size - neighbor_iterator.num_duplicates);
+
#define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \
} \
if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
@@ -336,17 +378,6 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss,
((void)0)
/* Utils */
-static void sculpt_vertex_mask_clamp(SculptSession *ss, int index, float min, float max)
-{
- float mask = sculpt_vertex_mask_get(ss, index);
- if (mask > max) {
- sculpt_vertex_mask_set(ss, index, max);
- }
- else if (mask < min) {
- sculpt_vertex_mask_set(ss, index, min);
- }
-}
-
static bool check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
{
bool is_in_symmetry_area = true;
@@ -366,37 +397,46 @@ static bool check_vertex_pivot_symmetry(const float vco[3], const float pco[3],
return is_in_symmetry_area;
}
+typedef struct NearestVertexTLSData {
+ int nearest_vertex_index;
+ float nearest_vertex_distance_squared;
+} NearestVertexTLSData;
+
static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
+ NearestVertexTLSData *nvtd = tls->userdata_chunk;
PBVHVertexIter vd;
- int node_nearest_vertex_index = -1;
- float node_nearest_vertex_distance_squared = FLT_MAX;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co);
- if (distance_squared < node_nearest_vertex_distance_squared &&
+ if (distance_squared < nvtd->nearest_vertex_distance_squared &&
distance_squared < data->max_distance_squared) {
- node_nearest_vertex_index = vd.index;
- node_nearest_vertex_distance_squared = distance_squared;
+ nvtd->nearest_vertex_index = vd.index;
+ nvtd->nearest_vertex_distance_squared = distance_squared;
}
}
BKE_pbvh_vertex_iter_end;
+}
- BLI_mutex_lock(&data->mutex);
- if (data->nearest_vertex_index == -1) {
- data->nearest_vertex_index = node_nearest_vertex_index;
+static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ NearestVertexTLSData *join = chunk_join;
+ NearestVertexTLSData *nvtd = chunk;
+ if (join->nearest_vertex_index == -1) {
+ join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
- else if (node_nearest_vertex_distance_squared <
- len_squared_v3v3(data->nearest_vertex_search_co,
- sculpt_vertex_co_get(ss, data->nearest_vertex_index))) {
- data->nearest_vertex_index = node_nearest_vertex_index;
+ else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) {
+ join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
- BLI_mutex_unlock(&data->mutex);
}
static int sculpt_nearest_vertex_get(
@@ -422,19 +462,23 @@ static int sculpt_nearest_vertex_get(
.ob = ob,
.nodes = nodes,
.max_distance_squared = max_distance * max_distance,
- .nearest_vertex_index = -1,
};
copy_v3_v3(task_data.nearest_vertex_search_co, co);
+ NearestVertexTLSData nvtd;
+ nvtd.nearest_vertex_index = -1;
+ nvtd.nearest_vertex_distance_squared = FLT_MAX;
- BLI_mutex_init(&task_data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
- BLI_mutex_end(&task_data.mutex);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_reduce = nearest_vertex_get_reduce;
+ settings.userdata_chunk = &nvtd;
+ settings.userdata_chunk_size = sizeof(NearestVertexTLSData);
+ BKE_pbvh_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
- return task_data.nearest_vertex_index;
+ MEM_SAFE_FREE(nodes);
+
+ return nvtd.nearest_vertex_index;
}
static bool is_symmetry_iteration_valid(char i, char symm)
@@ -443,7 +487,7 @@ static bool is_symmetry_iteration_valid(char i, char symm)
}
/* Checks if a vertex is inside the brush radius from any of its mirrored axis */
-static bool sculpt_is_vertex_inside_brush_radius_symm(float vertex[3],
+static bool sculpt_is_vertex_inside_brush_radius_symm(const float vertex[3],
const float br_co[3],
float radius,
char symm)
@@ -460,6 +504,85 @@ static bool sculpt_is_vertex_inside_brush_radius_symm(float vertex[3],
return false;
}
+/* Sculpt Flood Fill API
+ *
+ * Iterate over connected vertices, starting from one or more initial vertices. */
+
+typedef struct SculptFloodFill {
+ GSQueue *queue;
+ char *visited_vertices;
+} SculptFloodFill;
+
+static void sculpt_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
+{
+ int vertex_count = sculpt_vertex_count_get(ss);
+ sculpt_vertex_random_access_init(ss);
+
+ flood->queue = BLI_gsqueue_new(sizeof(int));
+ flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+}
+
+static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index)
+{
+ BLI_gsqueue_push(flood->queue, &index);
+}
+
+static void sculpt_floodfill_add_active(
+ Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, float radius)
+{
+ /* Add active vertex and symmetric vertices to the queue. */
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ for (char i = 0; i <= symm; ++i) {
+ if (is_symmetry_iteration_valid(i, symm)) {
+ int v = -1;
+ if (i == 0) {
+ v = sculpt_active_vertex_get(ss);
+ }
+ else if (radius > 0.0f) {
+ float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
+ float location[3];
+ flip_v3_v3(location, sculpt_active_vertex_co_get(ss), i);
+ v = sculpt_nearest_vertex_get(sd, ob, location, radius_squared, false);
+ }
+ if (v != -1) {
+ sculpt_floodfill_add_initial(flood, v);
+ }
+ }
+ }
+}
+
+static void sculpt_floodfill_execute(
+ SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
+ void *userdata)
+{
+ while (!BLI_gsqueue_is_empty(flood->queue)) {
+ int from_v;
+ BLI_gsqueue_pop(flood->queue, &from_v);
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni)
+ {
+ const int to_v = ni.index;
+ if (flood->visited_vertices[to_v] == 0) {
+ flood->visited_vertices[to_v] = 1;
+
+ if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) {
+ BLI_gsqueue_push(flood->queue, &to_v);
+ }
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ }
+}
+
+static void sculpt_floodfill_free(SculptFloodFill *flood)
+{
+ MEM_SAFE_FREE(flood->visited_vertices);
+ BLI_gsqueue_free(flood->queue);
+ flood->queue = NULL;
+}
+
/** \name Tool Capabilities
*
* Avoid duplicate checks, internal logic only,
@@ -814,15 +937,11 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm &&
- totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
}
/*** BVH Tree ***/
@@ -1003,9 +1122,8 @@ bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float loca
local_co[1] = fabsf(local_co[1]);
local_co[2] = fabsf(local_co[2]);
+ const float p = 8.0f;
if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
- float p = 4.0f;
-
test->dist = ((powf(local_co[0], p) + powf(local_co[1], p) + powf(local_co[2], p)) /
powf(side, p));
@@ -1100,11 +1218,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br)
{
- // REMOVE WITH PBVH_GRIDS
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return false;
- }
-
if (sculpt_stroke_is_dynamic_topology(ss, br)) {
return false;
}
@@ -1134,21 +1247,38 @@ static void sculpt_automasking_end(Object *ob)
static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
{
+ /* 2D falloff is not constrained by radius */
+ if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ return false;
+ }
+
if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
return true;
}
return false;
}
-typedef struct VertexTopologyIterator {
- int v;
- int it;
- float edge_factor;
-} VertexTopologyIterator;
+typedef struct AutomaskFloodFillData {
+ float *automask_factor;
+ float radius;
+ bool use_radius;
+ float location[3];
+ char symm;
+} AutomaskFloodFillData;
-static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+static bool automask_floodfill_cb(
+ SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
{
+ AutomaskFloodFillData *data = userdata;
+ data->automask_factor[to_v] = 1.0f;
+ return (!data->use_radius ||
+ sculpt_is_vertex_inside_brush_radius_symm(
+ sculpt_vertex_co_get(ss, to_v), data->location, data->radius, data->symm));
+}
+
+static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -1161,63 +1291,21 @@ static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *au
return NULL;
}
- bool *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(bool),
- "visited vertices");
-
- BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator),
- "not vertices stack");
-
- VertexTopologyIterator mevit;
-
- /* Add active vertex and symmetric vertices to the stack. */
- float location[3];
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- for (char i = 0; i <= symm; ++i) {
- if (is_symmetry_iteration_valid(i, symm)) {
- flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), i);
- if (i == 0) {
- mevit.v = sculpt_active_vertex_get(ss);
- }
- else {
- mevit.v = sculpt_nearest_vertex_get(
- sd, ob, location, ss->cache->radius * ss->cache->radius, false);
- }
- if (mevit.v != -1) {
- mevit.it = 1;
- BLI_stack_push(not_visited_vertices, &mevit);
- }
- }
- }
+ /* Flood fill automask to connected vertices. Limited to vertices inside
+ * the brush radius if the tool requires it */
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, ss->cache->radius);
- copy_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
- bool use_radius = sculpt_automasking_is_constrained_by_radius(brush);
-
- /* Flood fill automask to connected vertices. Limited to vertices inside the brush radius if the
- * tool requires it */
- while (!BLI_stack_is_empty(not_visited_vertices)) {
- VertexTopologyIterator c_mevit;
- BLI_stack_pop(not_visited_vertices, &c_mevit);
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
- {
- if (!visited_vertices[(int)ni.index]) {
- VertexTopologyIterator new_entry;
- new_entry.v = ni.index;
- automask_factor[new_entry.v] = 1.0f;
- visited_vertices[(int)ni.index] = true;
- if (!use_radius ||
- sculpt_is_vertex_inside_brush_radius_symm(
- sculpt_vertex_co_get(ss, new_entry.v), location, ss->cache->radius, symm)) {
- BLI_stack_push(not_visited_vertices, &new_entry);
- }
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- }
-
- BLI_stack_free(not_visited_vertices);
-
- MEM_freeN(visited_vertices);
+ AutomaskFloodFillData fdata = {
+ .automask_factor = automask_factor,
+ .radius = ss->cache->radius,
+ .use_radius = sculpt_automasking_is_constrained_by_radius(brush),
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ };
+ copy_v3_v3(fdata.location, sculpt_active_vertex_co_get(ss));
+ sculpt_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
return automask_factor;
}
@@ -1324,21 +1412,26 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* \note These are all _very_ similar, when changing one, check others.
* \{ */
+typedef struct AreaNormalCenterTLSData {
+ /* 0=towards view, 1=flipped */
+ float area_cos[2][3];
+ float area_nos[2][3];
+ int area_count[2];
+} AreaNormalCenterTLSData;
+
static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- float(*area_nos)[3] = data->area_nos;
- float(*area_cos)[3] = data->area_cos;
+ AreaNormalCenterTLSData *anctd = tls->userdata_chunk;
+ const bool use_area_nos = data->use_area_nos;
+ const bool use_area_cos = data->use_area_cos;
PBVHVertexIter vd;
SculptUndoNode *unode = NULL;
- float private_co[2][3] = {{0.0f}};
- float private_no[2][3] = {{0.0f}};
- int private_count[2] = {0};
bool use_original = false;
if (ss->cache && ss->cache->original) {
@@ -1353,7 +1446,10 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
/* Update the test radius to sample the normal using the normal radius of the brush */
if (data->brush->ob_mode == OB_MODE_SCULPT) {
float test_radius = sqrtf(test.radius_squared);
- test_radius *= data->brush->normal_radius_factor;
+ /* Layer brush produces artifacts with normal radius */
+ if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) {
+ test_radius *= data->brush->normal_radius_factor;
+ }
test.radius_squared = test_radius * test_radius;
}
@@ -1384,13 +1480,13 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
normal_tri_v3(no, UNPACK3(co_tri));
flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- if (area_cos) {
- add_v3_v3(private_co[flip_index], co);
+ if (use_area_cos) {
+ add_v3_v3(anctd->area_cos[flip_index], co);
}
- if (area_nos) {
- add_v3_v3(private_no[flip_index], no);
+ if (use_area_nos) {
+ add_v3_v3(anctd->area_nos[flip_index], no);
}
- private_count[flip_index] += 1;
+ anctd->area_count[flip_index] += 1;
}
}
}
@@ -1436,37 +1532,37 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
flip_index = (dot_v3v3(ss->cache ? ss->cache->view_normal : ss->cursor_view_normal, no) <=
0.0f);
- if (area_cos) {
- add_v3_v3(private_co[flip_index], co);
+ if (use_area_cos) {
+ add_v3_v3(anctd->area_cos[flip_index], co);
}
- if (area_nos) {
- add_v3_v3(private_no[flip_index], no);
+ if (use_area_nos) {
+ add_v3_v3(anctd->area_nos[flip_index], no);
}
- private_count[flip_index] += 1;
+ anctd->area_count[flip_index] += 1;
}
}
BKE_pbvh_vertex_iter_end;
}
+}
- BLI_mutex_lock(&data->mutex);
+static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ AreaNormalCenterTLSData *join = chunk_join;
+ AreaNormalCenterTLSData *anctd = chunk;
/* for flatten center */
- if (area_cos) {
- add_v3_v3(area_cos[0], private_co[0]);
- add_v3_v3(area_cos[1], private_co[1]);
- }
+ add_v3_v3(join->area_cos[0], anctd->area_cos[0]);
+ add_v3_v3(join->area_cos[1], anctd->area_cos[1]);
/* for area normal */
- if (area_nos) {
- add_v3_v3(area_nos[0], private_no[0]);
- add_v3_v3(area_nos[1], private_no[1]);
- }
+ add_v3_v3(join->area_nos[0], anctd->area_nos[0]);
+ add_v3_v3(join->area_nos[1], anctd->area_nos[1]);
/* weights */
- data->count[0] += private_count[0];
- data->count[1] += private_count[1];
-
- BLI_mutex_unlock(&data->mutex);
+ join->area_count[0] += anctd->area_count[0];
+ join->area_count[1] += anctd->area_count[1];
}
static void calc_area_center(
@@ -1477,11 +1573,6 @@ static void calc_area_center(
const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
int n;
- /* 0=towards view, 1=flipped */
- float area_cos[2][3] = {{0.0f}};
-
- int count[2] = {0};
-
/* Intentionally set 'sd' to NULL since we share logic with vertex paint. */
SculptThreadedTaskData data = {
.sd = NULL,
@@ -1490,23 +1581,22 @@ static void calc_area_center(
.nodes = nodes,
.totnode = totnode,
.has_bm_orco = has_bm_orco,
- .area_cos = area_cos,
- .area_nos = NULL,
- .count = count,
+ .use_area_cos = true,
};
- BLI_mutex_init(&data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ AreaNormalCenterTLSData anctd = {{{0}}};
- BLI_mutex_end(&data.mutex);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_reduce = calc_area_normal_and_center_reduce;
+ settings.userdata_chunk = &anctd;
+ settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
+ BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
- if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
+ for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
+ if (anctd.area_count[n] != 0) {
+ mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.area_count[n]);
break;
}
}
@@ -1519,7 +1609,7 @@ static void calc_area_normal(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
- bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT;
+ bool use_threading = (sd->flags & SCULPT_USE_OPENMP);
sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no);
}
@@ -1534,11 +1624,6 @@ bool sculpt_pbvh_calc_area_normal(const Brush *brush,
SculptSession *ss = ob->sculpt;
const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
- /* 0=towards view, 1=flipped */
- float area_nos[2][3] = {{0.0f}};
-
- int count[2] = {0};
-
/* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
SculptThreadedTaskData data = {
.sd = NULL,
@@ -1547,23 +1632,22 @@ bool sculpt_pbvh_calc_area_normal(const Brush *brush,
.nodes = nodes,
.totnode = totnode,
.has_bm_orco = has_bm_orco,
- .area_cos = NULL,
- .area_nos = area_nos,
- .count = count,
+ .use_area_nos = true,
.any_vertex_sampled = false,
};
- BLI_mutex_init(&data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = use_threading;
- BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ AreaNormalCenterTLSData anctd = {{{0}}};
- BLI_mutex_end(&data.mutex);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode);
+ settings.func_reduce = calc_area_normal_and_center_reduce;
+ settings.userdata_chunk = &anctd;
+ settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
+ BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* for area normal */
- for (int i = 0; i < ARRAY_SIZE(area_nos); i++) {
- if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) {
+ for (int i = 0; i < ARRAY_SIZE(anctd.area_nos); i++) {
+ if (normalize_v3_v3(r_area_no, anctd.area_nos[i]) != 0.0f) {
break;
}
}
@@ -1581,12 +1665,6 @@ static void calc_area_normal_and_center(
const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
int n;
- /* 0=towards view, 1=flipped */
- float area_cos[2][3] = {{0.0f}};
- float area_nos[2][3] = {{0.0f}};
-
- int count[2] = {0};
-
/* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
SculptThreadedTaskData data = {
.sd = NULL,
@@ -1595,23 +1673,23 @@ static void calc_area_normal_and_center(
.nodes = nodes,
.totnode = totnode,
.has_bm_orco = has_bm_orco,
- .area_cos = area_cos,
- .area_nos = area_nos,
- .count = count,
+ .use_area_cos = true,
+ .use_area_nos = true,
};
- BLI_mutex_init(&data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ AreaNormalCenterTLSData anctd = {{{0}}};
- BLI_mutex_end(&data.mutex);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_reduce = calc_area_normal_and_center_reduce;
+ settings.userdata_chunk = &anctd;
+ settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
+ BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
- if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
+ for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
+ if (anctd.area_count[n] != 0) {
+ mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.area_count[n]);
break;
}
}
@@ -1620,8 +1698,8 @@ static void calc_area_normal_and_center(
}
/* for area normal */
- for (n = 0; n < ARRAY_SIZE(area_nos); n++) {
- if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) {
+ for (n = 0; n < ARRAY_SIZE(anctd.area_nos); n++) {
+ if (normalize_v3_v3(r_area_no, anctd.area_nos[n]) != 0.0f) {
break;
}
}
@@ -1655,11 +1733,13 @@ static float brush_strength(const Sculpt *sd,
switch (brush->sculpt_tool) {
case SCULPT_TOOL_CLAY:
- case SCULPT_TOOL_CLAY_STRIPS:
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_DRAW_SHARP:
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
+ case SCULPT_TOOL_CLAY_STRIPS:
+ /* Clay Strips needs extra strength to compensate for its default normal radius */
+ return alpha * flip * pressure * overlap * feather * 1.3f;
case SCULPT_TOOL_MASK:
overlap = (1 + overlap) / 2;
@@ -1831,6 +1911,12 @@ bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
float t[3], bb_min[3], bb_max[3];
int i;
+ if (data->ignore_fully_masked) {
+ if (BKE_pbvh_node_fully_masked_get(node)) {
+ return false;
+ }
+ }
+
if (data->original) {
BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
}
@@ -1861,6 +1947,12 @@ bool sculpt_search_circle_cb(PBVHNode *node, void *data_v)
SculptSearchCircleData *data = data_v;
float bb_min[3], bb_max[3];
+ if (data->ignore_fully_masked) {
+ if (BKE_pbvh_node_fully_masked_get(node)) {
+ return false;
+ }
+ }
+
if (data->original) {
BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
}
@@ -1894,6 +1986,25 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
}
}
+static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob,
+ Sculpt *sd,
+ bool use_original,
+ int *r_totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes = NULL;
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = ss->cursor_radius,
+ .original = use_original,
+ .ignore_fully_masked = false,
+ .center = NULL,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
+ return nodes;
+}
+
static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
Sculpt *sd,
const Brush *brush,
@@ -1910,8 +2021,9 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
SculptSearchSphereData data = {
.ss = ss,
.sd = sd,
- .radius_squared = ss->cache ? SQUARE(ss->cache->radius * radius_scale) : ss->cursor_radius,
+ .radius_squared = SQUARE(ss->cache->radius * radius_scale),
.original = use_original,
+ .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
.center = NULL,
};
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
@@ -1926,6 +2038,7 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
.radius_squared = ss->cache ? SQUARE(ss->cache->radius * radius_scale) : ss->cursor_radius,
.original = use_original,
.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
+ .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
};
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
}
@@ -1969,9 +2082,15 @@ static void update_sculpt_normal(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
{
const Brush *brush = BKE_paint_brush(&sd->paint);
StrokeCache *cache = ob->sculpt->cache;
+ /* Grab brush does not update the sculpt normal during a stroke */
+ const bool update_normal = !(brush->flag & BRUSH_ORIGINAL_NORMAL) &&
+ !(brush->sculpt_tool == SCULPT_TOOL_GRAB) &&
+ !(brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) &&
+ !(brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK &&
+ cache->normal_weight > 0.0f);
if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0 &&
- (cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ (cache->first_time || update_normal)) {
calc_sculpt_normal(sd, ob, nodes, totnode, cache->sculpt_normal);
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
project_plane_v3_v3v3(cache->sculpt_normal, cache->sculpt_normal, cache->view_normal);
@@ -2160,92 +2279,51 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v)
copy_v3_v3(avg, v->co);
}
-/* For bmesh: average only the four most aligned (parallel and perpendicular) edges
- * relative to a direction. Naturally converges to a quad-like tessellation. */
+/* For bmesh: Average surrounding verts based on an orthogonality measure.
+ * Naturally converges to a quad-like structure. */
static void bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
{
- /* Logic for 3 or more is identical. */
- const int vfcount = BM_vert_face_count_at_most(v, 3);
-
- /* Don't modify corner vertices. */
- if (vfcount < 2) {
- copy_v3_v3(avg, v->co);
- return;
- }
-
- /* Project the direction to the vertex normal and create an additional
- * parallel vector. */
- float dir_a[3], dir_b[3];
- cross_v3_v3v3(dir_a, direction, v->no);
- cross_v3_v3v3(dir_b, dir_a, v->no);
-
- /* The four vectors which will be used for smoothing.
- * Occasionally less than 4 verts match the requirements in that case
- * use 'v' as fallback. */
- BMVert *pos_a = v;
- BMVert *neg_a = v;
- BMVert *pos_b = v;
- BMVert *neg_b = v;
-
- float pos_score_a = 0.0f;
- float neg_score_a = 0.0f;
- float pos_score_b = 0.0f;
- float neg_score_b = 0.0f;
-
- BMIter liter;
- BMLoop *l;
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[2] = {l->prev->v, l->next->v};
-
- for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
- BMVert *v_other = adj_v[i];
-
- if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
- float vec[3];
- sub_v3_v3v3(vec, v_other->co, v->co);
- normalize_v3(vec);
+ float avg_co[3] = {0, 0, 0};
+ float tot_co = 0;
- /* The score is a measure of how orthogonal the edge is. */
- float score = dot_v3v3(vec, dir_a);
+ BMIter eiter;
+ BMEdge *e;
- if (score >= pos_score_a) {
- pos_a = v_other;
- pos_score_a = score;
- }
- else if (score < neg_score_a) {
- neg_a = v_other;
- neg_score_a = score;
- }
- /* The same scoring but for the perpendicular direction. */
- score = dot_v3v3(vec, dir_b);
-
- if (score >= pos_score_b) {
- pos_b = v_other;
- pos_score_b = score;
- }
- else if (score < neg_score_b) {
- neg_b = v_other;
- neg_score_b = score;
- }
- }
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_edge_is_boundary(e)) {
+ copy_v3_v3(avg, v->co);
+ return;
}
+ BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
+ float vec[3];
+ sub_v3_v3v3(vec, v_other->co, v->co);
+ madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
+ normalize_v3(vec);
+
+ /* fac is a measure of how orthogonal or parallel the edge is
+ * relative to the direction */
+ float fac = dot_v3v3(vec, direction);
+ fac = fac * fac - 0.5f;
+ fac *= fac;
+ madd_v3_v3fl(avg_co, v_other->co, fac);
+ tot_co += fac;
}
- /* Average everything together. */
- zero_v3(avg);
- add_v3_v3(avg, pos_a->co);
- add_v3_v3(avg, neg_a->co);
- add_v3_v3(avg, pos_b->co);
- add_v3_v3(avg, neg_b->co);
- mul_v3_fl(avg, 0.25f);
+ /* In case vert has no Edge s */
+ if (tot_co > 0) {
+ mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
- /* Preserve volume. */
- float vec[3];
- sub_v3_v3(avg, v->co);
- mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
- sub_v3_v3(avg, vec);
- add_v3_v3(avg, v->co);
+ /* Preserve volume. */
+ float vec[3];
+ sub_v3_v3(avg, v->co);
+ mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
+ sub_v3_v3(avg, vec);
+ add_v3_v3(avg, v->co);
+ }
+ else {
+ zero_v3(avg);
+ }
}
/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
@@ -2277,6 +2355,48 @@ static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offse
}
}
+static void grids_neighbor_average(SculptSession *ss, float result[3], int index)
+{
+ float avg[3] = {0.0f, 0.0f, 0.0f};
+ int total = 0;
+
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, index, ni)
+ {
+ add_v3_v3(avg, sculpt_vertex_co_get(ss, ni.index));
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ mul_v3_v3fl(result, avg, 1.0f / (float)total);
+ }
+ else {
+ copy_v3_v3(result, sculpt_vertex_co_get(ss, index));
+ }
+}
+
+static float grids_neighbor_average_mask(SculptSession *ss, int index)
+{
+ float avg = 0.0f;
+ int total = 0;
+
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, index, ni)
+ {
+ avg += sculpt_vertex_mask_get(ss, ni.index);
+ total++;
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+
+ if (total > 0) {
+ return avg / (float)total;
+ }
+ else {
+ return sculpt_vertex_mask_get(ss, index);
+ }
+}
+
/* Note: uses after-struct allocated mem to store actual cache... */
typedef struct SculptDoBrushSmoothGridDataChunk {
size_t tmpgrid_size;
@@ -2442,6 +2562,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(
tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
sub_v3_v3(direction, tmp);
+ normalize_v3(direction);
/* Cancel if there's no grab data. */
if (is_zero_v3(direction)) {
@@ -2502,7 +2623,6 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
float bstrength = data->strength;
CCGElem **griddata, *gddata;
- CCGKey key;
float(*tmpgrid_co)[3] = NULL;
float tmprow_co[2][3];
@@ -2521,7 +2641,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
BKE_pbvh_node_get_grids(
ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata);
- BKE_pbvh_get_grid_key(ss->pbvh, &key);
+ CCGKey key = *BKE_pbvh_get_grid_key(ss->pbvh);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
@@ -2681,9 +2801,8 @@ static void smooth(Sculpt *sd,
.strength = strength,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
switch (type) {
case PBVH_GRIDS: {
@@ -2700,16 +2819,16 @@ static void smooth(Sculpt *sd,
settings.userdata_chunk = data_chunk;
settings.userdata_chunk_size = size;
- BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
MEM_freeN(data_chunk);
break;
}
case PBVH_FACES:
- BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
break;
case PBVH_BMESH:
- BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
break;
}
@@ -2741,11 +2860,10 @@ static void bmesh_topology_rake(
.nodes = nodes,
.strength = factor,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
}
}
@@ -2799,10 +2917,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
}
static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2887,10 +3004,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.offset = offset,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
}
static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
@@ -2964,10 +3080,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.offset = offset,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
}
/**
@@ -3081,10 +3196,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.flippedbstrength = flippedbstrength,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
}
static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
@@ -3144,10 +3258,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
}
static void do_grab_brush_task_cb_ex(void *__restrict userdata,
@@ -3217,10 +3330,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.grab_delta = grab_delta,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
}
/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
@@ -3459,6 +3571,10 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
@@ -3467,10 +3583,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
.grab_delta = grab_delta,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
}
static void do_pose_brush_task_cb_ex(void *__restrict userdata,
@@ -3522,10 +3637,6 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float pose_initial_co[3];
float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4];
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return;
- }
-
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
copy_v3_v3(pose_origin, ss->cache->pose_origin);
@@ -3561,39 +3672,115 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.transform_trans_inv = transform_trans_inv,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
}
-static void pose_brush_init_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+typedef struct PoseGrowFactorTLSData {
+ float pos_avg[3];
+ int pos_count;
+} PoseGrowFactorTLSData;
+
+static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
+ PoseGrowFactorTLSData *gftd = tls->userdata_chunk;
SculptSession *ss = data->ob->sculpt;
+ const char symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const float *active_co = sculpt_active_vertex_co_get(ss);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SculptVertexNeighborIter ni;
- float avg = 0;
- int total = 0;
+ float max = 0.0f;
sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
{
- avg += ss->cache->pose_factor[ni.index];
- total++;
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f > max) {
+ max = vmask_f;
+ }
}
sculpt_vertex_neighbors_iter_end(ni);
-
- if (total > 0) {
- ss->cache->pose_factor[vd.index] = avg / (float)total;
+ if (max != data->prev_mask[vd.index]) {
+ data->pose_factor[vd.index] = max;
+ if (check_vertex_pivot_symmetry(vd.co, active_co, symm)) {
+ add_v3_v3(gftd->pos_avg, vd.co);
+ gftd->pos_count++;
+ }
}
}
+
BKE_pbvh_vertex_iter_end;
}
-static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3],
+static void pose_brush_grow_factor_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ PoseGrowFactorTLSData *join = chunk_join;
+ PoseGrowFactorTLSData *gftd = chunk;
+ add_v3_v3(join->pos_avg, gftd->pos_avg);
+ join->pos_count += gftd->pos_count;
+}
+
+/* Grow the factor until its boundary is near to the offset pose origin */
+static void sculpt_pose_grow_pose_factor(
+ Sculpt *sd, Object *ob, SculptSession *ss, float pose_origin[3], float *pose_factor)
+{
+ PBVHNode **nodes;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ int totnode;
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .totnode = totnode,
+ .pose_factor = pose_factor,
+ };
+ PBVHParallelSettings settings;
+ PoseGrowFactorTLSData gftd;
+ gftd.pos_count = 0;
+ zero_v3(gftd.pos_avg);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_reduce = pose_brush_grow_factor_reduce;
+ settings.userdata_chunk = &gftd;
+ settings.userdata_chunk_size = sizeof(PoseGrowFactorTLSData);
+
+ bool grow_next_iteration = true;
+ float prev_len = FLT_MAX;
+ data.prev_mask = MEM_mallocN(sculpt_vertex_count_get(ss) * sizeof(float), "prev mask");
+ while (grow_next_iteration) {
+ zero_v3(gftd.pos_avg);
+ gftd.pos_count = 0;
+ memcpy(data.prev_mask, pose_factor, sculpt_vertex_count_get(ss) * sizeof(float));
+ BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
+ if (gftd.pos_count != 0) {
+ mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count);
+ float len = len_v3v3(gftd.pos_avg, pose_origin);
+ if (len < prev_len) {
+ prev_len = len;
+ grow_next_iteration = true;
+ }
+ else {
+ grow_next_iteration = false;
+ memcpy(pose_factor, data.prev_mask, sculpt_vertex_count_get(ss) * sizeof(float));
+ }
+ }
+ else {
+ grow_next_iteration = false;
+ }
+ }
+ MEM_freeN(data.prev_mask);
+
+ MEM_SAFE_FREE(nodes);
+}
+
+static bool sculpt_pose_brush_is_vertex_inside_brush_radius(const float vertex[3],
const float br_co[3],
float radius,
char symm)
@@ -3610,85 +3797,123 @@ static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3],
return false;
}
-static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br)
+/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush
+ *
+ * r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't
+ * be calculated. */
+typedef struct PoseFloodFillData {
+ float pose_initial_co[3];
+ float radius;
+ int symm;
+
+ float *pose_factor;
+ float pose_origin[3];
+ int tot_co;
+} PoseFloodFillData;
+
+static bool pose_floodfill_cb(
+ SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
{
- sculpt_vertex_random_access_init(ss);
+ PoseFloodFillData *data = userdata;
- ss->cache->pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
+ if (data->pose_factor) {
+ data->pose_factor[to_v] = 1.0f;
+ }
- copy_v3_v3(ss->cache->pose_initial_co, ss->cache->location);
+ const float *co = sculpt_vertex_co_get(ss, to_v);
+ if (sculpt_pose_brush_is_vertex_inside_brush_radius(
+ co, data->pose_initial_co, data->radius, data->symm)) {
+ return true;
+ }
+ else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) {
+ if (!is_duplicate) {
+ add_v3_v3(data->pose_origin, co);
+ data->tot_co++;
+ }
+ }
- char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char),
- "Visited vertices");
- BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator),
- "not visited vertices stack");
+ return false;
+}
- float tot_co = 0;
- zero_v3(ss->cache->pose_origin);
+void sculpt_pose_calc_pose_data(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor)
+{
+ sculpt_vertex_random_access_init(ss);
- VertexTopologyIterator mevit;
+ /* Calculate the pose rotation point based on the boundaries of the brush factor. */
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, (r_pose_factor) ? radius : 0.0f);
- /* Add active vertex and symmetric vertices to the stack. */
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- for (char i = 0; i <= symm; ++i) {
- if (is_symmetry_iteration_valid(i, symm)) {
- float location[3];
- flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), (char)i);
- if (i == 0) {
- mevit.v = sculpt_active_vertex_get(ss);
- }
- else {
- mevit.v = sculpt_nearest_vertex_get(
- sd, ob, location, ss->cache->radius * ss->cache->radius, false);
- }
- if (mevit.v != -1) {
- mevit.it = 1;
- BLI_stack_push(not_visited_vertices, &mevit);
- }
- }
+ PoseFloodFillData fdata = {
+ .radius = radius,
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ .pose_factor = r_pose_factor,
+ .tot_co = 0,
+ };
+ zero_v3(fdata.pose_origin);
+ copy_v3_v3(fdata.pose_initial_co, initial_location);
+ sculpt_floodfill_execute(ss, &flood, pose_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
+
+ if (fdata.tot_co > 0) {
+ mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co);
}
- /* Flood fill the internal pose brush factor. Calculate the pose rotation point based on the
- * boundaries of the brush factor*/
- while (!BLI_stack_is_empty(not_visited_vertices)) {
- VertexTopologyIterator c_mevit;
- BLI_stack_pop(not_visited_vertices, &c_mevit);
+ /* Offset the pose origin */
+ float pose_d[3];
+ sub_v3_v3v3(pose_d, fdata.pose_origin, fdata.pose_initial_co);
+ normalize_v3(pose_d);
+ madd_v3_v3fl(fdata.pose_origin, pose_d, radius * pose_offset);
+ copy_v3_v3(r_pose_origin, fdata.pose_origin);
+
+ if (pose_offset != 0.0f && r_pose_factor) {
+ sculpt_pose_grow_pose_factor(sd, ob, ss, fdata.pose_origin, r_pose_factor);
+ }
+}
+
+static void pose_brush_init_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
+ float avg = 0;
+ int total = 0;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
{
- if (visited_vertices[(int)ni.index] == 0) {
- VertexTopologyIterator new_entry;
- new_entry.v = ni.index;
- new_entry.it = c_mevit.it + 1;
- ss->cache->pose_factor[new_entry.v] = 1.0f;
- visited_vertices[(int)ni.index] = 1;
- if (sculpt_pose_brush_is_vertex_inside_brush_radius(sculpt_vertex_co_get(ss, new_entry.v),
- ss->cache->pose_initial_co,
- ss->cache->radius,
- symm)) {
- BLI_stack_push(not_visited_vertices, &new_entry);
- }
- else {
- if (check_vertex_pivot_symmetry(
- sculpt_vertex_co_get(ss, new_entry.v), ss->cache->pose_initial_co, symm)) {
- tot_co++;
- add_v3_v3(ss->cache->pose_origin, sculpt_vertex_co_get(ss, new_entry.v));
- }
- }
- }
+ avg += ss->cache->pose_factor[ni.index];
+ total++;
}
sculpt_vertex_neighbors_iter_end(ni);
- }
- BLI_stack_free(not_visited_vertices);
+ if (total > 0) {
+ ss->cache->pose_factor[vd.index] = avg / (float)total;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
- MEM_freeN(visited_vertices);
+static void sculpt_pose_brush_init(
+ Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, float initial_location[3], float radius)
+{
+ float *pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
- if (tot_co > 0) {
- mul_v3_fl(ss->cache->pose_origin, 1.0f / (float)tot_co);
- }
+ sculpt_pose_calc_pose_data(
+ sd, ob, ss, initial_location, radius, br->pose_offset, ss->cache->pose_origin, pose_factor);
- /* Smooth the pose brush factor for cleaner deformation */
+ copy_v3_v3(ss->cache->pose_initial_co, initial_location);
+ ss->cache->pose_factor = pose_factor;
PBVHNode **nodes;
PBVH *pbvh = ob->sculpt->pbvh;
@@ -3703,12 +3928,14 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br
.nodes = nodes,
};
+ /* Smooth the pose brush factor for cleaner deformation */
for (int i = 0; i < 4; i++) {
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
}
+
+ MEM_SAFE_FREE(nodes);
}
static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
@@ -3773,10 +4000,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
}
static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
@@ -3895,10 +4121,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.grab_delta = grab_delta,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
}
static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
@@ -3968,10 +4193,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
}
static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
@@ -4042,10 +4266,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.angle = angle,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
}
static void do_layer_brush_task_cb_ex(void *__restrict userdata,
@@ -4140,10 +4363,9 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
};
BLI_mutex_init(&data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
BLI_mutex_end(&data.mutex);
}
@@ -4209,10 +4431,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
}
static void calc_sculpt_plane(
@@ -4223,7 +4444,8 @@ static void calc_sculpt_plane(
if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 &&
ss->cache->tile_pass == 0 &&
- (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_PLANE) ||
+ !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
copy_v3_v3(r_area_no, ss->cache->true_view_normal);
@@ -4260,10 +4482,20 @@ static void calc_sculpt_plane(
}
/* for area normal */
- copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+ }
+ else {
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ }
/* for flatten center */
- copy_v3_v3(ss->cache->last_center, r_area_co);
+ if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_PLANE)) {
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+ }
+ else {
+ copy_v3_v3(ss->cache->last_center, r_area_co);
+ }
}
else {
/* for area normal */
@@ -4408,10 +4640,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.area_co = area_co,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
static void do_clay_brush_task_cb_ex(void *__restrict userdata,
@@ -4507,10 +4738,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
}
static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
@@ -4638,10 +4868,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
.mat = mat,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
}
static void do_fill_brush_task_cb_ex(void *__restrict userdata,
@@ -4732,10 +4961,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
}
static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
@@ -4825,10 +5053,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.area_co = area_co,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
static void do_gravity_task_cb_ex(void *__restrict userdata,
@@ -4895,10 +5122,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
.offset = offset,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
@@ -4999,7 +5225,7 @@ static void sculpt_topology_update(Sculpt *sd,
(brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE));
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* update average stroke position */
copy_v3_v3(location, ss->cache->true_location);
@@ -5017,7 +5243,12 @@ static void do_brush_action_task_cb(void *__restrict userdata,
data->nodes[n],
data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(data->nodes[n]);
+ if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ BKE_pbvh_node_mark_update_mask(data->nodes[n]);
+ }
+ else {
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+ }
}
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
@@ -5030,18 +5261,27 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* These brushes need to update all nodes as they are not constrained by the brush radius */
if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ }
+ else if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ float final_radius = ss->cache->radius * (1 + brush->pose_offset);
SculptSearchSphereData data = {
.ss = ss,
.sd = sd,
- .radius_squared = FLT_MAX,
+ .radius_squared = final_radius * final_radius,
.original = true,
};
- BKE_pbvh_search_gather(ss->pbvh, NULL, &data, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
}
else {
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
ss->cache->original;
- const float radius_scale = 1.0f;
+ float radius_scale = 1.0f;
+ /* With these options enabled not all required nodes are inside the original brush radius, so
+ * the brush can produce artifacts in some situations */
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW && brush->flag & BRUSH_ORIGINAL_NORMAL) {
+ radius_scale = 2.0f;
+ }
nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
}
@@ -5056,10 +5296,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
if (sculpt_brush_needs_normal(ss, brush)) {
update_sculpt_normal(sd, ob, nodes, totnode);
@@ -5077,9 +5316,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time &&
ss->cache->mirror_symmetry_pass == 0) {
- if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
- sculpt_pose_brush_init(sd, ob, ss, brush);
- }
+ sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius);
}
/* Apply one type of brush action */
@@ -5168,7 +5405,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
do_gravity(sd, ob, nodes, totnode, sd->gravity_factor);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* update average stroke position */
copy_v3_v3(location, ss->cache->true_location);
@@ -5196,7 +5433,7 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
copy_v3_v3(ss->deform_cos[index], vd->co);
copy_v3_v3(ss->orig_cos[index], newco);
- if (!ss->kb) {
+ if (!ss->shapekey_active) {
copy_v3_v3(me->mvert[index].co, newco);
}
}
@@ -5252,7 +5489,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
sculpt_clip(sd, ss, vd.co, val);
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
sculpt_flush_pbvhvert_deform(ob, &vd);
}
}
@@ -5279,15 +5516,12 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
}
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
}
/* copy the modified vertices from bvh to the active key */
@@ -5306,7 +5540,7 @@ static void sculpt_update_keyblock(Object *ob)
}
if (vertCos) {
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos);
if (vertCos != ss->orig_cos) {
MEM_freeN(vertCos);
@@ -5352,7 +5586,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use
PBVHNode **nodes;
float(*vertCos)[3] = NULL;
- if (ss->kb) {
+ if (ss->shapekey_active) {
vertCos = MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts");
/* mesh could have isolated verts which wouldn't be in BVH,
@@ -5372,24 +5606,23 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use
.vertCos = vertCos,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings);
if (vertCos) {
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos);
MEM_freeN(vertCos);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* Modifiers could depend on mesh normals, so we should update them/
* Note, then if sculpting happens on locked key, normals should be re-calculated
* after applying coords from keyblock on base mesh */
BKE_mesh_calc_normals(me);
}
- else if (ss->kb) {
+ else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
}
}
@@ -5676,6 +5909,9 @@ void sculpt_cache_free(StrokeCache *cache)
if (cache->dial) {
MEM_freeN(cache->dial);
}
+ if (cache->pose_factor) {
+ MEM_freeN(cache->pose_factor);
+ }
MEM_freeN(cache);
}
@@ -5869,12 +6105,21 @@ static void sculpt_update_cache_invariants(
/* Make copies of the mesh vertex locations and normals for some tools */
if (brush->flag & BRUSH_ANCHORED) {
- cache->original = 1;
+ cache->original = true;
+ }
+
+ /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it
+ * should work the opposite way. */
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
+ cache->original = true;
}
if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) {
- cache->original = 1;
+ cache->original = true;
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
+ cache->original = false;
+ }
}
}
@@ -5911,8 +6156,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
if (cache->first_time) {
if (tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
- copy_v3_v3(cache->orig_grab_location,
- sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
+ copy_v3_v3(cache->orig_grab_location, sculpt_active_vertex_co_get(ss));
}
else {
copy_v3_v3(cache->orig_grab_location, cache->true_location);
@@ -6125,9 +6369,9 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
/* Returns true if any of the smoothing modes are active (currently
* one of smooth brush, autosmooth, mask smooth, or shift-key
* smooth) */
-static bool sculpt_needs_conectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode)
+static bool sculpt_needs_connectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode)
{
- if (ss && sculpt_automasking_enabled(ss, brush)) {
+ if (ss && ss->pbvh && sculpt_automasking_enabled(ss, brush)) {
return true;
}
return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss && ss->cache && ss->cache->alt_smooth) ||
@@ -6141,8 +6385,9 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const B
SculptSession *ss = ob->sculpt;
View3D *v3d = CTX_wm_view3d(C);
- bool need_pmap = sculpt_needs_conectivity_info(brush, ss, 0);
- if (ss->kb || ss->modifiers_active || (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) {
+ bool need_pmap = sculpt_needs_connectivity_info(brush, ss, 0);
+ if (ss->shapekey_active || ss->deform_modifiers_active ||
+ (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) {
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false);
}
@@ -6272,6 +6517,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
const float mouse[2],
bool use_sampled_normal)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Sculpt *sd = scene->toolsettings->sculpt;
Object *ob;
@@ -6284,15 +6530,15 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
int totnode;
bool original = false, hit = false;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ob = vc.obact;
ss = ob->sculpt;
if (!ss->pbvh) {
- copy_v3_fl(out->location, 0.0f);
- copy_v3_fl(out->normal, 0.0f);
- copy_v3_fl(out->active_vertex_co, 0.0f);
+ zero_v3(out->location);
+ zero_v3(out->normal);
+ zero_v3(out->active_vertex_co);
return false;
}
@@ -6314,16 +6560,16 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
/* Cursor is not over the mesh, return default values */
if (!srd.hit) {
- copy_v3_fl(out->location, 0.0f);
- copy_v3_fl(out->normal, 0.0f);
- copy_v3_fl(out->active_vertex_co, 0.0f);
+ zero_v3(out->location);
+ zero_v3(out->normal);
+ zero_v3(out->active_vertex_co);
return false;
}
/* Update the active vertex of the SculptSession */
ss->active_vertex_index = srd.active_vertex_index;
+ copy_v3_v3(out->active_vertex_co, sculpt_active_vertex_co_get(ss));
- copy_v3_v3(out->active_vertex_co, sculpt_vertex_co_get(ss, srd.active_vertex_index));
copy_v3_v3(out->location, ray_normal);
mul_v3_fl(out->location, srd.depth);
add_v3_v3(out->location, ray_start);
@@ -6335,7 +6581,6 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
}
/* Sampled normal calculation */
- const float radius_scale = 1.0f;
float radius;
/* Update cursor data in SculptSession */
@@ -6357,11 +6602,11 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
}
ss->cursor_radius = radius;
- PBVHNode **nodes = sculpt_pbvh_gather_generic(ob, sd, brush, original, radius_scale, &totnode);
+ PBVHNode **nodes = sculpt_pbvh_gather_cursor_update(ob, sd, original, &totnode);
/* In case there are no nodes under the cursor, return the face normal */
if (!totnode) {
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
copy_v3_v3(out->normal, srd.face_normal);
return true;
}
@@ -6374,7 +6619,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
/* Use face normal when there are no vertices to sample inside the cursor radius */
copy_v3_v3(out->normal, srd.face_normal);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
return true;
}
@@ -6384,6 +6629,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
*/
bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob;
SculptSession *ss;
StrokeCache *cache;
@@ -6391,13 +6637,13 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
bool original;
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ob = vc.obact;
ss = ob->sculpt;
cache = ss->cache;
- original = (cache) ? cache->original : 0;
+ original = (cache) ? cache->original : false;
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
@@ -6453,10 +6699,6 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
}
}
- if (cache && hit) {
- copy_v3_v3(cache->true_location, out);
- }
-
return hit;
}
@@ -6496,7 +6738,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
view3d_operator_needs_opengl(C);
sculpt_brush_init_tex(scene, sd, ss);
- is_smooth = sculpt_needs_conectivity_info(brush, ss, mode);
+ is_smooth = sculpt_needs_connectivity_info(brush, ss, mode);
BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask);
}
@@ -6526,7 +6768,7 @@ void sculpt_update_object_bounding_box(Object *ob)
}
}
-static void sculpt_flush_update_step(bContext *C)
+static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
@@ -6534,6 +6776,12 @@ static void sculpt_flush_update_step(bContext *C)
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ if (rv3d) {
+ /* Mark for faster 3D viewport redraws. */
+ rv3d->rflag |= RV3D_PAINTING;
+ }
if (mmd != NULL) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
@@ -6554,11 +6802,13 @@ static void sculpt_flush_update_step(bContext *C)
* only the part of the 3D viewport where changes happened. */
rcti r;
- BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
- /* Update the object's bounding box too so that the object
- * doesn't get incorrectly clipped during drawing in
- * draw_mesh_object(). [#33790] */
- sculpt_update_object_bounding_box(ob);
+ if (update_flags & SCULPT_UPDATE_COORDS) {
+ BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
+ /* Update the object's bounding box too so that the object
+ * doesn't get incorrectly clipped during drawing in
+ * draw_mesh_object(). [#33790] */
+ sculpt_update_object_bounding_box(ob);
+ }
if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
if (ss->cache) {
@@ -6578,16 +6828,21 @@ static void sculpt_flush_update_step(bContext *C)
}
}
-static void sculpt_flush_update_done(const bContext *C, Object *ob)
+static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
{
/* After we are done drawing the stroke, check if we need to do a more
* expensive depsgraph tag to update geometry. */
wmWindowManager *wm = CTX_wm_manager(C);
View3D *current_v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
SculptSession *ss = ob->sculpt;
Mesh *mesh = ob->data;
bool need_tag = (mesh->id.us > 1); /* Always needed for linked duplicates. */
+ if (rv3d) {
+ rv3d->rflag &= ~RV3D_PAINTING;
+ }
+
for (wmWindow *win = wm->windows.first; win; win = win->next) {
bScreen *screen = WM_window_get_active_screen(win);
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
@@ -6597,11 +6852,26 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob)
if (v3d != current_v3d) {
need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, v3d);
}
+
+ /* Tag all 3D viewports for redraw now that we are done. Others
+ * viewports did not get a full redraw, and anti-aliasing for the
+ * current viewport was deactivated. */
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ ED_region_tag_redraw(ar);
+ }
+ }
}
}
}
- BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB);
+ if (update_flags & SCULPT_UPDATE_COORDS) {
+ BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB);
+ }
+
+ if (update_flags & SCULPT_UPDATE_MASK) {
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ }
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BKE_pbvh_bmesh_after_stroke(ss->pbvh);
@@ -6610,7 +6880,7 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob)
/* optimization: if there is locked key and active modifiers present in */
/* the stack, keyblock is updating at each step. otherwise we could update */
/* keyblock only when stroke is finished */
- if (ss->kb && !ss->modifiers_active) {
+ if (ss->shapekey_active && !ss->deform_modifiers_active) {
sculpt_update_keyblock(ob);
}
@@ -6703,17 +6973,22 @@ static void sculpt_stroke_update_step(bContext *C,
* Same applies to the DEG_id_tag_update() invoked from
* sculpt_flush_update_step().
*/
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
sculpt_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool));
}
- else if (ss->kb) {
+ else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
}
ss->cache->first_time = false;
/* Cleanup */
- sculpt_flush_update_step(C);
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ }
+ else {
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+ }
}
static void sculpt_brush_exit_tex(Sculpt *sd)
@@ -6766,7 +7041,12 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ }
+ else {
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ }
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
@@ -6797,12 +7077,12 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_PASS_THROUGH;
}
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -6931,8 +7211,19 @@ void sculpt_pbvh_clear(Object *ob)
/* Clear out any existing DM and PBVH */
if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
+ ss->pbvh = NULL;
+ }
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
}
- ss->pbvh = NULL;
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
+ }
+
BKE_object_free_derived_caches(ob);
/* Tag to rebuild PBVH in depsgraph. */
@@ -7502,13 +7793,11 @@ void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scen
const int mode_flag = OB_MODE_SCULPT;
Mesh *me = BKE_mesh_from_object(ob);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- if (mmd) {
- multires_force_update(ob);
- }
+ multires_flush_sculpt_updates(ob);
/* Not needed for now. */
#if 0
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
#endif
@@ -7653,7 +7942,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
sculpt_undo_push_end();
/* force rebuild of pbvh for better BB placement */
@@ -7694,8 +7983,9 @@ static void sample_detail(bContext *C, int mx, int my)
CTX_wm_area_set(C, sa);
CTX_wm_region_set(C, ar);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
/* Pick sample detail. */
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -7738,7 +8028,7 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
{
ED_workspace_status_text(C, TIP_("Click on the mesh to set the detail"));
- WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -7859,43 +8149,36 @@ static void filter_cache_init_task_cb(void *__restrict userdata,
const TaskParallelTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
PBVHNode *node = data->nodes[i];
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- if (!vd.mask || (vd.mask && *vd.mask < 1.0f)) {
- data->node_mask[i] = 1;
- }
- }
- BKE_pbvh_vertex_iter_end;
-
- if (data->node_mask[i] == 1) {
- sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
- }
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
}
static void sculpt_filter_cache_init(Object *ob, Sculpt *sd)
{
SculptSession *ss = ob->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
ss->filter_cache->random_seed = rand();
+ float center[3] = {0.0f};
SculptSearchSphereData search_data = {
.original = true,
- };
- BKE_pbvh_search_gather(pbvh, NULL, &search_data, &nodes, &totnode);
+ .center = center,
+ .radius_squared = FLT_MAX,
+ .ignore_fully_masked = true,
- int *node_mask = MEM_callocN((unsigned int)totnode * sizeof(int), "node mask");
+ };
+ BKE_pbvh_search_gather(pbvh,
+ sculpt_search_sphere_cb,
+ &search_data,
+ &ss->filter_cache->nodes,
+ &ss->filter_cache->totnode);
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_normals_update(nodes[i]);
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_normals_update(ss->filter_cache->nodes[i]);
}
/* mesh->runtime.subdiv_ccg is not available. Updating of the normals is done during drawing.
@@ -7907,45 +8190,14 @@ static void sculpt_filter_cache_init(Object *ob, Sculpt *sd)
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
- .nodes = nodes,
- .node_mask = node_mask,
+ .nodes = ss->filter_cache->nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, filter_cache_init_task_cb, &settings);
-
- int tot_active_nodes = 0;
- int active_node_index = 0;
- PBVHNode **active_nodes;
-
- /* Count number of PBVH nodes that are not fully masked */
- for (int i = 0; i < totnode; i++) {
- if (node_mask[i] == 1) {
- tot_active_nodes++;
- }
- }
-
- /* Create the final list of nodes that is going to be processed in the filter */
- active_nodes = MEM_callocN(tot_active_nodes * sizeof(PBVHNode *), "active nodes");
-
- for (int i = 0; i < totnode; i++) {
- if (node_mask[i] == 1) {
- active_nodes[active_node_index] = nodes[i];
- active_node_index++;
- }
- }
-
- ss->filter_cache->nodes = active_nodes;
- ss->filter_cache->totnode = tot_active_nodes;
-
- if (nodes) {
- MEM_freeN(nodes);
- }
- if (node_mask) {
- MEM_freeN(node_mask);
- }
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BKE_pbvh_parallel_range(
+ 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings);
}
static void sculpt_filter_cache_free(SculptSession *ss)
@@ -8017,15 +8269,25 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1 - fade;
fade *= data->filter_strength;
+
+ if (fade == 0.0f) {
+ continue;
+ }
+
copy_v3_v3(orig_co, orig_data.co);
switch (filter_type) {
case MESH_FILTER_SMOOTH:
CLAMP(fade, -1.0f, 1.0f);
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- neighbor_average(ss, avg, vd.index);
- }
- else if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- bmesh_neighbor_average(avg, vd.bm_vert);
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ neighbor_average(ss, avg, vd.index);
+ break;
+ case PBVH_BMESH:
+ bmesh_neighbor_average(avg, vd.bm_vert);
+ break;
+ case PBVH_GRIDS:
+ grids_neighbor_average(ss, avg, vd.index);
+ break;
}
sub_v3_v3v3(val, avg, orig_co);
madd_v3_v3v3fl(val, orig_co, val, fade);
@@ -8064,11 +8326,16 @@ static void mesh_filter_task_cb(void *__restrict userdata,
mid_v3_v3v3(disp, disp, disp2);
break;
- case MESH_FILTER_RANDOM:
+ case MESH_FILTER_RANDOM: {
normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_fl(normal, BLI_hash_int_01(vd.index ^ ss->filter_cache->random_seed) - 0.5f);
+ /* Index is not unique for multires, so hash by vertex coordinates. */
+ const uint *hash_co = (const uint *)orig_co;
+ const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
+ BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed);
+ mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f);
mul_v3_v3fl(disp, normal, fade);
break;
+ }
}
for (int it = 0; it < 3; it++) {
@@ -8079,8 +8346,9 @@ static void mesh_filter_task_cb(void *__restrict userdata,
add_v3_v3v3(final_pos, orig_co, disp);
copy_v3_v3(vd.co, final_pos);
- if (vd.mvert)
+ if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
}
BKE_pbvh_vertex_iter_end;
@@ -8100,7 +8368,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
sculpt_filter_cache_free(ss);
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
return OPERATOR_FINISHED;
}
@@ -8124,17 +8392,16 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
.filter_strength = filter_strength,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
- if (ss->modifiers_active || ss->kb) {
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
sculpt_flush_stroke_deform(sd, ob, true);
}
- sculpt_flush_update_step(C);
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
return OPERATOR_RUNNING_MODAL;
}
@@ -8148,10 +8415,6 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
SculptSession *ss = ob->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
int deform_axis = RNA_enum_get(op->ptr, "deform_axis");
if (deform_axis == 0) {
return OPERATOR_CANCELLED;
@@ -8260,35 +8523,42 @@ static void mask_filter_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
- float val;
float delta, gain, offset, max, min;
float prev_val = *vd.mask;
SculptVertexNeighborIter ni;
switch (mode) {
case MASK_FILTER_SMOOTH:
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- val = neighbor_average_mask(ss, vd.index) - *vd.mask;
+ case MASK_FILTER_SHARPEN: {
+ float val = 0.0f;
+
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ val = neighbor_average_mask(ss, vd.index);
+ break;
+ case PBVH_BMESH:
+ val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset);
+ break;
+ case PBVH_GRIDS:
+ val = grids_neighbor_average_mask(ss, vd.index);
+ break;
}
- else {
- val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
- }
- *vd.mask += val;
- break;
- case MASK_FILTER_SHARPEN:
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- val = neighbor_average_mask(ss, vd.index) - *vd.mask;
- }
- else {
- val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
- }
- if (*vd.mask > 0.5f) {
- *vd.mask += 0.05f;
+
+ val -= *vd.mask;
+
+ if (mode == MASK_FILTER_SMOOTH) {
+ *vd.mask += val;
}
- else {
- *vd.mask -= 0.05f;
+ else if (mode == MASK_FILTER_SHARPEN) {
+ if (*vd.mask > 0.5f) {
+ *vd.mask += 0.05f;
+ }
+ else {
+ *vd.mask -= 0.05f;
+ }
+ *vd.mask += val / 2;
}
- *vd.mask += val / 2;
break;
+ }
case MASK_FILTER_GROW:
max = 0.0f;
sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
@@ -8339,7 +8609,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
if (update) {
- BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_update_mask(node);
}
}
@@ -8355,10 +8625,6 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
int totnode;
int filter_type = RNA_enum_get(op->ptr, "filter_type");
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
sculpt_vertex_random_access_init(ss);
@@ -8380,16 +8646,16 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
int iterations = RNA_int_get(op->ptr, "iterations");
/* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
- * avoid adding an unnecesary ammount of undo steps when using the operator from a shortcut. One
- * iteration per 50000 vertices in the mesh should be fine in most cases. Maybe we want this to
- * be configurable */
+ * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
+ * One iteration per 50000 vertices in the mesh should be fine in most cases.
+ * Maybe we want this to be configurable. */
if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
iterations = (int)(num_verts / 50000.0f) + 1;
}
for (int i = 0; i < iterations; i++) {
if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
- prev_mask = MEM_mallocN((unsigned long)num_verts * sizeof(float), "prevmask");
+ prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask");
for (int j = 0; j < num_verts; j++) {
prev_mask[j] = sculpt_vertex_mask_get(ss, j);
}
@@ -8403,19 +8669,16 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
.prev_mask = prev_mask,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
MEM_freeN(prev_mask);
}
}
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
sculpt_undo_push_end();
@@ -8461,17 +8724,17 @@ static void SCULPT_OT_mask_filter(struct wmOperatorType *ot)
"Use a automatic number of iterations based on the number of vertices of the sculpt");
}
-static float neighbor_dirty_mask(SculptSession *ss, const int vert)
+static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
{
int total = 0;
float avg[3];
zero_v3(avg);
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, vert, ni)
+ sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni)
{
float normalized[3];
- sub_v3_v3v3(normalized, sculpt_vertex_co_get(ss, ni.index), sculpt_vertex_co_get(ss, vert));
+ sub_v3_v3v3(normalized, sculpt_vertex_co_get(ss, ni.index), vd->co);
normalize_v3(normalized);
add_v3_v3(avg, normalized);
total++;
@@ -8481,7 +8744,12 @@ static float neighbor_dirty_mask(SculptSession *ss, const int vert)
if (total > 0) {
mul_v3_fl(avg, 1.0f / total);
float normal[3];
- sculpt_vertex_normal_get(ss, vert, normal);
+ if (vd->no) {
+ normal_short_to_float_v3(normal, vd->no);
+ }
+ else {
+ copy_v3_v3(normal, vd->fno);
+ }
float dot = dot_v3v3(avg, normal);
float angle = max_ff(saacosf(dot), 0.0f);
return angle;
@@ -8489,25 +8757,75 @@ static float neighbor_dirty_mask(SculptSession *ss, const int vert)
return 0;
}
-static void dirty_mask_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
+typedef struct DirtyMaskRangeData {
+ float min, max;
+} DirtyMaskRangeData;
+
+static void dirty_mask_compute_range_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ DirtyMaskRangeData *range = tls->userdata_chunk;
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float dirty_mask = neighbor_dirty_mask(ss, &vd);
+ range->min = min_ff(dirty_mask, range->min);
+ range->max = max_ff(dirty_mask, range->max);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void dirty_mask_compute_range_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ DirtyMaskRangeData *join = chunk_join;
+ DirtyMaskRangeData *range = chunk;
+ join->min = min_ff(range->min, join->min);
+ join->max = max_ff(range->max, join->max);
+}
+
+static void dirty_mask_apply_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
PBVHNode *node = data->nodes[i];
PBVHVertexIter vd;
+
+ const bool dirty_only = data->dirty_mask_dirty_only;
+ const float min = data->dirty_mask_min;
+ const float max = data->dirty_mask_max;
+
+ float range = max - min;
+ if (range < 0.0001f) {
+ range = 0;
+ }
+ else {
+ range = 1.0f / range;
+ }
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
- float val;
- val = neighbor_dirty_mask(ss, vd.index);
- data->prev_mask[vd.index] = val;
+ float dirty_mask = neighbor_dirty_mask(ss, &vd);
+ float mask = *vd.mask + (1 - ((dirty_mask - min) * range));
+ if (dirty_only) {
+ mask = fminf(mask, 0.5f) * 2.0f;
+ }
+ *vd.mask = CLAMPIS(mask, 0.0f, 1.0f);
+
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_update_mask(node);
}
static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
@@ -8521,10 +8839,6 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
int totnode;
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
sculpt_vertex_random_access_init(ss);
@@ -8533,8 +8847,6 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- int num_verts = sculpt_vertex_count_get(ss);
-
BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
sculpt_undo_push_begin("Dirty Mask");
@@ -8542,59 +8854,32 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
}
- float *prev_mask = NULL;
-
- prev_mask = MEM_mallocN((unsigned long)num_verts * sizeof(float), "prevmask");
- for (int j = 0; j < num_verts; j++) {
- prev_mask[j] = sculpt_vertex_mask_get(ss, j);
- }
-
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.nodes = nodes,
- .prev_mask = prev_mask,
+ .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"),
+ };
+ DirtyMaskRangeData range = {
+ .min = FLT_MAX,
+ .max = -FLT_MAX,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, dirty_mask_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- float min = FLT_MAX;
- float max = FLT_MIN;
- for (int i = 0; i < num_verts; i++) {
- float val = prev_mask[i];
- if (val < min) {
- min = val;
- }
- if (val > max) {
- max = val;
- }
- }
+ settings.func_reduce = dirty_mask_compute_range_reduce;
+ settings.userdata_chunk = &range;
+ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData);
- float range = max - min;
- if (range < 0.0001f) {
- range = 0;
- }
- else {
- range = 1.0f / range;
- }
+ BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings);
+ data.dirty_mask_min = range.min;
+ data.dirty_mask_max = range.max;
+ BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings);
- bool dirty_only = RNA_boolean_get(op->ptr, "dirty_only");
- for (int i = 0; i < num_verts; i++) {
- sculpt_vertex_mask_set(
- ss, i, sculpt_vertex_mask_get(ss, i) + (1 - ((prev_mask[i] - min) * range)));
- if (dirty_only) {
- sculpt_vertex_mask_set(ss, i, fminf(sculpt_vertex_mask_get(ss, i), 0.5f) * 2.0f);
- }
- sculpt_vertex_mask_clamp(ss, i, 0.0f, 1.0f);
- }
- MEM_freeN(prev_mask);
+ MEM_SAFE_FREE(nodes);
- if (nodes) {
- MEM_freeN(nodes);
- }
+ BKE_pbvh_update_vertex_data(pbvh, SCULPT_UPDATE_MASK);
sculpt_undo_push_end();
@@ -8630,19 +8915,22 @@ static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
MEM_freeN(op->customdata);
- int vert_count = sculpt_vertex_count_get(ss);
- for (int i = 0; i < vert_count; i++) {
- sculpt_vertex_mask_set(ss, i, ss->filter_cache->prev_mask[i]);
- }
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHNode *node = ss->filter_cache->nodes[n];
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ *vd.mask = ss->filter_cache->prev_mask[vd.index];
+ }
+ BKE_pbvh_vertex_iter_end;
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ BKE_pbvh_node_mark_redraw(node);
}
- sculpt_flush_update_step(C);
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
sculpt_filter_cache_free(ss);
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
ED_workspace_status_text(C, NULL);
}
@@ -8692,7 +8980,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
*vd.mask = final_mask;
- BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_update_mask(node);
}
}
BKE_pbvh_vertex_iter_end;
@@ -8724,8 +9012,11 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
if ((event->type == ESCKEY && event->val == KM_PRESS) ||
(event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ /* Returning OPERATOR_CANCELLED will leak memory due to not finishing
+ * undo. Better solution could be to make paint_mesh_restore_co work
+ * for this case. */
sculpt_mask_expand_cancel(C, op);
- return OPERATOR_CANCELLED;
+ return OPERATOR_FINISHED;
}
if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
@@ -8743,30 +9034,36 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
for (int i = 0; i < smooth_iterations; i++) {
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings);
}
/* Pivot position */
if (RNA_boolean_get(op->ptr, "update_pivot")) {
const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const float threshold = 0.2f;
float avg[3];
int total = 0;
- float threshold = 0.2f;
zero_v3(avg);
- int vertex_count = sculpt_vertex_count_get(ss);
- for (int i = 0; i < vertex_count; i++) {
- if (sculpt_vertex_mask_get(ss, i) < (0.5f + threshold) &&
- sculpt_vertex_mask_get(ss, i) > (0.5f - threshold) &&
- check_vertex_pivot_symmetry(
- sculpt_vertex_co_get(ss, i), ss->filter_cache->mask_expand_initial_co, symm)) {
- total++;
- add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
+
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
+ if (check_vertex_pivot_symmetry(
+ vd.co, ss->filter_cache->mask_expand_initial_co, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
}
+ BKE_pbvh_vertex_iter_end;
}
+
if (total > 0) {
mul_v3_fl(avg, 1.0f / total);
copy_v3_v3(ss->pivot_pos, avg);
@@ -8783,7 +9080,7 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
sculpt_filter_cache_free(ss);
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
ED_workspace_status_text(C, NULL);
return OPERATOR_FINISHED;
}
@@ -8806,20 +9103,60 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
.mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
.mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
-
- BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
ss->filter_cache->mask_update_current_it = mask_expand_update_it;
}
- sculpt_flush_update_step(C);
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
return OPERATOR_RUNNING_MODAL;
}
+typedef struct MaskExpandFloodFillData {
+ float original_normal[3];
+ float edge_sensitivity;
+ bool use_normals;
+} MaskExpandFloodFillData;
+
+static bool mask_expand_floodfill_cb(
+ SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+ MaskExpandFloodFillData *data = userdata;
+
+ if (!is_duplicate) {
+ int to_it = ss->filter_cache->mask_update_it[from_v] + 1;
+ ss->filter_cache->mask_update_it[to_v] = to_it;
+ if (to_it > ss->filter_cache->mask_update_last_it) {
+ ss->filter_cache->mask_update_last_it = to_it;
+ }
+
+ if (data->use_normals) {
+ float current_normal[3], prev_normal[3];
+ sculpt_vertex_normal_get(ss, to_v, current_normal);
+ sculpt_vertex_normal_get(ss, from_v, prev_normal);
+ const float from_edge_factor = ss->filter_cache->edge_factor[from_v];
+ ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) *
+ from_edge_factor;
+ ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) *
+ powf(from_edge_factor, data->edge_sensitivity);
+ CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f);
+ }
+ }
+ else {
+ /* PBVH_GRIDS duplicate handling */
+ ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v];
+ if (data->use_normals) {
+ ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v];
+ ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v];
+ }
+ }
+
+ return true;
+}
+
static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -8827,20 +9164,14 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
- float original_normal[3];
bool use_normals = RNA_boolean_get(op->ptr, "use_normals");
- int edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity");
SculptCursorGeometryInfo sgi;
float mouse[2];
mouse[0] = event->mval[0];
mouse[1] = event->mval[1];
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
sculpt_vertex_random_access_init(ss);
op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");
@@ -8854,16 +9185,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
- SculptSearchSphereData searchdata = {
- .ss = ss,
- .sd = sd,
- .radius_squared = FLT_MAX,
- };
- BKE_pbvh_search_gather(pbvh,
- sculpt_search_sphere_cb,
- &searchdata,
- &ss->filter_cache->nodes,
- &ss->filter_cache->totnode);
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode);
sculpt_undo_push_begin("Mask Expand");
@@ -8877,6 +9199,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
if (use_normals) {
ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count,
"mask update normal factor");
+ ss->filter_cache->edge_factor = MEM_callocN(sizeof(float) * vertex_count,
+ "mask update normal factor");
+ for (int i = 0; i < vertex_count; i++) {
+ ss->filter_cache->edge_factor[i] = 1.0f;
+ }
}
ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask");
@@ -8886,68 +9213,21 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
ss->filter_cache->mask_update_last_it = 1;
ss->filter_cache->mask_update_current_it = 1;
- ss->filter_cache->mask_update_it[(int)sculpt_active_vertex_get(ss)] = 1;
-
- copy_v3_v3(ss->filter_cache->mask_expand_initial_co,
- sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
-
- char *visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+ ss->filter_cache->mask_update_it[sculpt_active_vertex_get(ss)] = 1;
- sculpt_vertex_normal_get(ss, sculpt_active_vertex_get(ss), original_normal);
+ copy_v3_v3(ss->filter_cache->mask_expand_initial_co, sculpt_active_vertex_co_get(ss));
- GSQueue *queue = BLI_gsqueue_new(sizeof(VertexTopologyIterator));
- VertexTopologyIterator mevit;
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, FLT_MAX);
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- for (char i = 0; i <= symm; ++i) {
- if (is_symmetry_iteration_valid(i, symm)) {
- float location[3];
- flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), i);
- if (i == 0) {
- mevit.v = sculpt_active_vertex_get(ss);
- mevit.edge_factor = 1.0f;
- }
- else {
- mevit.v = sculpt_nearest_vertex_get(sd, ob, location, FLT_MAX, false);
- mevit.edge_factor = 1.0f;
- }
- if (mevit.v != -1) {
- sculpt_vertex_mask_set(ss, mevit.v, 1.0f);
- mevit.it = 0;
- BLI_gsqueue_push(queue, &mevit);
- }
- }
- }
-
- while (!BLI_gsqueue_is_empty(queue)) {
- VertexTopologyIterator c_mevit;
- BLI_gsqueue_pop(queue, &c_mevit);
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
- {
- if (visited_vertices[(int)ni.index] == 0) {
- VertexTopologyIterator new_entry;
- new_entry.v = ni.index;
- new_entry.it = c_mevit.it + 1;
- ss->filter_cache->mask_update_it[(int)new_entry.v] = new_entry.it;
- visited_vertices[(int)ni.index] = 1;
- if (ss->filter_cache->mask_update_last_it < new_entry.it) {
- ss->filter_cache->mask_update_last_it = new_entry.it;
- }
- if (use_normals) {
- float current_normal[3], prev_normal[3];
- sculpt_vertex_normal_get(ss, ni.index, current_normal);
- sculpt_vertex_normal_get(ss, c_mevit.v, prev_normal);
- new_entry.edge_factor = dot_v3v3(current_normal, prev_normal) * c_mevit.edge_factor;
- ss->filter_cache->normal_factor[ni.index] = dot_v3v3(original_normal, current_normal) *
- powf(c_mevit.edge_factor, edge_sensitivity);
- CLAMP(ss->filter_cache->normal_factor[ni.index], 0, 1);
- }
- BLI_gsqueue_push(queue, &new_entry);
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- }
+ MaskExpandFloodFillData fdata = {
+ .use_normals = use_normals,
+ .edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity"),
+ };
+ sculpt_active_vertex_normal_get(ss, fdata.original_normal);
+ sculpt_floodfill_execute(ss, &flood, mask_expand_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
if (use_normals) {
for (int repeat = 0; repeat < 2; repeat++) {
@@ -8962,11 +9242,9 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
ss->filter_cache->normal_factor[i] = avg / ni.size;
}
}
- }
-
- BLI_gsqueue_free(queue);
- MEM_freeN(visited_vertices);
+ MEM_SAFE_FREE(ss->filter_cache->edge_factor);
+ }
SculptThreadedTaskData data = {
.sd = sd,
@@ -8977,19 +9255,17 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
.mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
.mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
-
- BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
const char *status_str = TIP_(
"Move the mouse to expand the mask from the active vertex. LBM: confirm mask, ESC/RMB: "
"cancel");
ED_workspace_status_text(C, status_str);
- sculpt_flush_update_step(C);
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -9061,46 +9337,47 @@ void sculpt_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
}
float brush_co[3];
- copy_v3_v3(brush_co, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
+ copy_v3_v3(brush_co, sculpt_active_vertex_co_get(ss));
char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char),
"visited vertices");
+ /* Assuming an average of 6 edges per vertex in a triangulated mesh */
+ const int max_preview_vertices = sculpt_vertex_count_get(ss) * 3 * 2;
+
if (ss->preview_vert_index_list == NULL) {
- ss->preview_vert_index_list = MEM_callocN(4 * sizeof(int) * sculpt_vertex_count_get(ss),
- "preview lines");
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
}
- BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator),
- "Not visited vertices stack");
- VertexTopologyIterator mevit;
- mevit.v = sculpt_active_vertex_get(ss);
- BLI_stack_push(not_visited_vertices, &mevit);
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
+ int active_v = sculpt_active_vertex_get(ss);
+ BLI_gsqueue_push(not_visited_vertices, &active_v);
- while (!BLI_stack_is_empty(not_visited_vertices)) {
- VertexTopologyIterator c_mevit;
- BLI_stack_pop(not_visited_vertices, &c_mevit);
+ while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
+ int from_v;
+ BLI_gsqueue_pop(not_visited_vertices, &from_v);
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
+ sculpt_vertex_neighbors_iter_begin(ss, from_v, ni)
{
- VertexTopologyIterator new_entry;
- new_entry.v = ni.index;
- new_entry.it = c_mevit.it + 1;
- ss->preview_vert_index_list[totpoints] = c_mevit.v;
- totpoints++;
- ss->preview_vert_index_list[totpoints] = new_entry.v;
- totpoints++;
- if (visited_vertices[(int)ni.index] == 0) {
- visited_vertices[(int)ni.index] = 1;
- if (len_squared_v3v3(brush_co, sculpt_vertex_co_get(ss, new_entry.v)) < radius * radius) {
- BLI_stack_push(not_visited_vertices, &new_entry);
+ if (totpoints + (ni.size * 2) < max_preview_vertices) {
+ int to_v = ni.index;
+ ss->preview_vert_index_list[totpoints] = from_v;
+ totpoints++;
+ ss->preview_vert_index_list[totpoints] = to_v;
+ totpoints++;
+ if (visited_vertices[to_v] == 0) {
+ visited_vertices[to_v] = 1;
+ const float *co = sculpt_vertex_co_get(ss, to_v);
+ if (len_squared_v3v3(brush_co, co) < radius * radius) {
+ BLI_gsqueue_push(not_visited_vertices, &to_v);
+ }
}
}
}
sculpt_vertex_neighbors_iter_end(ni);
}
- BLI_stack_free(not_visited_vertices);
+ BLI_gsqueue_free(not_visited_vertices);
MEM_freeN(visited_vertices);
@@ -9234,8 +9511,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
}
BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_redraw(node);
- BKE_pbvh_node_mark_normals_update(node);
+ BKE_pbvh_node_mark_update(node);
}
void ED_sculpt_update_modal_transform(struct bContext *C)
@@ -9295,18 +9571,17 @@ void ED_sculpt_update_modal_transform(struct bContext *C)
mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
}
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BKE_pbvh_parallel_range(
0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
- if (ss->modifiers_active || ss->kb) {
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
sculpt_flush_stroke_deform(sd, ob, true);
}
- sculpt_flush_update_step(C);
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
}
void ED_sculpt_end_transform(struct bContext *C)
@@ -9317,7 +9592,7 @@ void ED_sculpt_end_transform(struct bContext *C)
sculpt_filter_cache_free(ss);
}
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
}
typedef enum eSculptPivotPositionModes {
@@ -9366,73 +9641,80 @@ static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const w
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
int mode = RNA_enum_get(op->ptr, "mode");
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
- int vert_count = sculpt_vertex_count_get(ss);
-
/* Pivot to center */
if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
zero_v3(ss->pivot_pos);
}
+ /* Pivot to active vertex */
+ else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
+ copy_v3_v3(ss->pivot_pos, sculpt_active_vertex_co_get(ss));
+ }
+ /* Pivot to raycast surface */
+ else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
+ float stroke_location[3];
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ if (sculpt_stroke_get_location(C, stroke_location, mouse)) {
+ copy_v3_v3(ss->pivot_pos, stroke_location);
+ }
+ }
+ else {
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- /* Pivot to unmasked */
- if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
float avg[3];
int total = 0;
zero_v3(avg);
- for (int i = 0; i < vert_count; i++) {
- if (sculpt_vertex_mask_get(ss, i) < 1.0f &&
- check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) {
- total++;
- add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
+
+ /* Pivot to unmasked */
+ if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
+ for (int n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < 1.0f) {
+ if (check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
}
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- copy_v3_v3(ss->pivot_pos, avg);
- }
- }
+ /* Pivot to mask border */
+ else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
+ const float threshold = 0.2f;
- /* Pivot to mask border */
- if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
- float avg[3];
- int total = 0;
- float threshold = 0.2f;
- zero_v3(avg);
- for (int i = 0; i < vert_count; i++) {
- if (sculpt_vertex_mask_get(ss, i) < (0.5f + threshold) &&
- sculpt_vertex_mask_get(ss, i) > (0.5f - threshold) &&
- check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) {
- total++;
- add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
+ for (int n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
+ if (check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
}
+
if (total > 0) {
mul_v3_fl(avg, 1.0f / total);
copy_v3_v3(ss->pivot_pos, avg);
}
- }
- /* Pivot to active vertex */
- if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
- copy_v3_v3(ss->pivot_pos, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
- }
-
- /* Pivot to raycast surface */
- if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
- float stroke_location[3];
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- if (sculpt_stroke_get_location(C, stroke_location, mouse)) {
- copy_v3_v3(ss->pivot_pos, stroke_location);
- }
+ MEM_SAFE_FREE(nodes);
}
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index b814e87fcb0..93e4a777569 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -44,6 +44,13 @@ bool sculpt_mode_poll_view3d(struct bContext *C);
bool sculpt_poll(struct bContext *C);
bool sculpt_poll_view3d(struct bContext *C);
+/* Updates */
+
+typedef enum SculptUpdateType {
+ SCULPT_UPDATE_COORDS = 1 << 0,
+ SCULPT_UPDATE_MASK = 1 << 1,
+} SculptUpdateType;
+
/* Stroke */
typedef struct SculptCursorGeometryInfo {
@@ -58,9 +65,17 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
const float mouse[2],
bool use_sampled_normal);
void sculpt_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
+void sculpt_pose_calc_pose_data(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor);
/* Sculpt PBVH abstraction API */
-float *sculpt_vertex_co_get(struct SculptSession *ss, int index);
+const float *sculpt_vertex_co_get(struct SculptSession *ss, int index);
/* Dynamic topology */
void sculpt_pbvh_clear(Object *ob);
@@ -179,23 +194,20 @@ typedef struct SculptThreadedTaskData {
int filter_type;
float filter_strength;
- int *node_mask;
- /* 0=towards view, 1=flipped */
- float (*area_cos)[3];
- float (*area_nos)[3];
- int *count;
+ bool use_area_cos;
+ bool use_area_nos;
bool any_vertex_sampled;
float *prev_mask;
float *pose_origin;
float *pose_initial_co;
+ float *pose_factor;
float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4];
float max_distance_squared;
float nearest_vertex_search_co[3];
- int nearest_vertex_index;
int mask_expand_update_it;
bool mask_expand_invert_mask;
@@ -204,6 +216,10 @@ typedef struct SculptThreadedTaskData {
float transform_mats[8][4][4];
+ float dirty_mask_min;
+ float dirty_mask_max;
+ bool dirty_mask_dirty_only;
+
ThreadMutex mutex;
} SculptThreadedTaskData;
@@ -233,6 +249,7 @@ typedef struct {
float radius_squared;
float *center;
bool original;
+ bool ignore_fully_masked;
} SculptSearchSphereData;
typedef struct {
@@ -240,6 +257,7 @@ typedef struct {
struct SculptSession *ss;
float radius_squared;
bool original;
+ bool ignore_fully_masked;
struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
@@ -392,6 +410,7 @@ typedef struct FilterCache {
int mask_update_last_it;
int *mask_update_it;
float *normal_factor;
+ float *edge_factor;
float *prev_mask;
float mask_expand_initial_co[3];
} FilterCache;
@@ -413,6 +432,4 @@ void sculpt_update_object_bounding_box(struct Object *ob);
bool sculpt_get_redraw_rect(struct ARegion *ar, struct RegionView3D *rv3d, Object *ob, rcti *rect);
-#define SCULPT_THREADED_LIMIT 4
-
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 3783eb17562..5d95cc80280 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -39,8 +39,6 @@
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
@@ -49,7 +47,6 @@
#include "BKE_paint.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
#include "BKE_subdiv_ccg.h"
@@ -62,13 +59,11 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_paint.h"
#include "ED_object.h"
#include "ED_sculpt.h"
#include "ED_undo.h"
#include "bmesh.h"
-#include "paint_intern.h"
#include "sculpt_intern.h"
typedef struct UndoSculpt {
@@ -91,6 +86,7 @@ static void update_cb(PBVHNode *node, void *rebuild)
struct PartialUpdateData {
PBVH *pbvh;
bool rebuild;
+ char *modified_grids;
};
/**
@@ -99,8 +95,24 @@ struct PartialUpdateData {
static void update_cb_partial(PBVHNode *node, void *userdata)
{
struct PartialUpdateData *data = userdata;
- if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) {
- update_cb(node, &(data->rebuild));
+ if (BKE_pbvh_type(data->pbvh) == PBVH_GRIDS) {
+ int *node_grid_indices;
+ int totgrid;
+ bool update = false;
+ BKE_pbvh_node_get_grids(data->pbvh, node, &node_grid_indices, &totgrid, NULL, NULL, NULL);
+ for (int i = 0; i < totgrid; i++) {
+ if (data->modified_grids[node_grid_indices[i]] == 1) {
+ update = true;
+ }
+ }
+ if (update) {
+ update_cb(node, &(data->rebuild));
+ }
+ }
+ else {
+ if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) {
+ update_cb(node, &(data->rebuild));
+ }
}
}
@@ -140,7 +152,7 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
if (unode->maxvert) {
/* regular mesh restore */
- if (ss->kb && !STREQ(ss->kb->name, unode->shapeName)) {
+ if (ss->shapekey_active && !STREQ(ss->shapekey_active->name, unode->shapeName)) {
/* shape key has been changed before calling undo operator */
Key *key = BKE_key_from_object(ob);
@@ -162,12 +174,12 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
index = unode->index;
mvert = ss->mvert;
- if (ss->kb) {
+ if (ss->shapekey_active) {
float(*vertCos)[3];
- vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
+ vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active);
if (unode->orig_co) {
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
for (int i = 0; i < unode->totvert; i++) {
sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
}
@@ -185,36 +197,33 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
}
/* propagate new coords to keyblock */
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos);
/* pbvh uses it's own mvert array, so coords should be */
/* propagated to pbvh here */
- BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, ss->kb->totelem);
+ BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, ss->shapekey_active->totelem);
MEM_freeN(vertCos);
}
else {
if (unode->orig_co) {
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
for (int i = 0; i < unode->totvert; i++) {
- if (sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co)) {
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
+ sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- if (test_swap_v3_v3(mvert[index[i]].co, unode->orig_co[i])) {
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
+ swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- if (test_swap_v3_v3(mvert[index[i]].co, unode->co[i])) {
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
+ swap_v3_v3(mvert[index[i]].co, unode->co[i]);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
@@ -351,10 +360,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(
0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings);
if (nodes) {
@@ -491,7 +499,6 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
SculptUndoNode *unode;
bool update = false, rebuild = false;
bool need_mask = false;
- bool partial_update = true;
for (unode = lb->first; unode; unode = unode->next) {
/* restore pivot */
@@ -533,6 +540,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
return;
}
+ char *undo_modified_grids = NULL;
+ bool use_multires_undo = false;
+
for (unode = lb->first; unode; unode = unode->next) {
if (!STREQ(unode->idname, ob->id.name)) {
@@ -552,8 +562,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
continue;
}
- /* multi-res can't do partial updates since it doesn't flag edited vertices */
- partial_update = false;
+ use_multires_undo = true;
}
switch (unode->type) {
@@ -583,21 +592,29 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
}
+ if (use_multires_undo) {
+ int max_grid;
+ unode = lb->first;
+ max_grid = unode->maxgrid;
+ undo_modified_grids = MEM_callocN(sizeof(char) * max_grid, "undo_grids");
+ for (unode = lb->first; unode; unode = unode->next) {
+ for (int i = 0; i < unode->totgrid; i++) {
+ undo_modified_grids[unode->grids[i]] = 1;
+ }
+ }
+ }
+
if (update || rebuild) {
bool tag_update = false;
/* we update all nodes still, should be more clever, but also
* needs to work correct when exiting/entering sculpt mode and
* the nodes get recreated, though in that case it could do all */
- if (partial_update) {
- struct PartialUpdateData data = {
- .rebuild = rebuild,
- .pbvh = ss->pbvh,
- };
- BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
- }
- else {
- BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
- }
+ struct PartialUpdateData data = {
+ .rebuild = rebuild,
+ .pbvh = ss->pbvh,
+ .modified_grids = undo_modified_grids,
+ };
+ BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw);
if (BKE_sculpt_multires_active(scene, ob)) {
@@ -611,7 +628,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
tag_update |= ((Mesh *)ob->data)->id.us > 1 || !BKE_sculptsession_use_pbvh_draw(ob, v3d);
- if (ss->kb || ss->modifiers_active) {
+ if (ss->shapekey_active || ss->deform_modifiers_active) {
Mesh *mesh = ob->data;
BKE_mesh_calc_normals(mesh);
@@ -626,6 +643,8 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
sculpt_update_object_bounding_box(ob);
}
}
+
+ MEM_SAFE_FREE(undo_modified_grids);
}
static void sculpt_undo_free_list(ListBase *lb)
@@ -812,7 +831,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index");
}
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
unode->orig_co = MEM_callocN(allvert * sizeof(*unode->orig_co), "undoSculpt orig_cos");
}
@@ -834,7 +853,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
normal_float_to_short_v3(unode->no[vd.i], vd.fno);
}
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]);
}
}
@@ -1063,8 +1082,8 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
copy_v3_v3(unode->pivot_rot, ss->pivot_rot);
/* store active shape key */
- if (ss->kb) {
- BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
+ if (ss->shapekey_active) {
+ BLI_strncpy(unode->shapeName, ss->shapekey_active->name, sizeof(ss->shapekey_active->name));
}
else {
unode->shapeName[0] = '\0';
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index de03fea7bb1..8fbaf3396bd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -38,7 +38,6 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "BKE_main.h"
#include "BKE_mesh_mapping.h"
#include "BKE_paint.h"
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 4e710d31cbb..69745663c02 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -273,8 +273,11 @@ static void sound_update_animation_flags(Scene *scene)
static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Scene *scene = CTX_data_scene(C);
+
BKE_main_id_tag_idcode(CTX_data_main(C), ID_SCE, LIB_TAG_DOIT, false);
sound_update_animation_flags(CTX_data_scene(C));
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 944a0c74f4c..242acfd0261 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -1663,7 +1663,7 @@ static const EnumPropertyItem prop_actkeys_snap_types[] = {
{ACTKEYS_SNAP_CFRA,
"CFRA",
0,
- "Current frame",
+ "Current Frame",
"Snap selected keyframes to the current frame"},
{ACTKEYS_SNAP_NEAREST_FRAME,
"NEAREST_FRAME",
@@ -1789,17 +1789,17 @@ static const EnumPropertyItem prop_actkeys_mirror_types[] = {
{ACTKEYS_MIRROR_CFRA,
"CFRA",
0,
- "By Times over Current frame",
+ "By Times Over Current Frame",
"Flip times of selected keyframes using the current frame as the mirror line"},
{ACTKEYS_MIRROR_XAXIS,
"XAXIS",
0,
- "By Values over Value=0",
+ "By Values Over Value=0",
"Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
{ACTKEYS_MIRROR_MARKER,
"MARKER",
0,
- "By Times over First Selected Marker",
+ "By Times Over First Selected Marker",
"Flip times of selected keyframes using the first selected marker as the reference point"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 912cd0407e3..ca6efb5f69e 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -153,7 +153,8 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac,
float region_x,
float *r_selx,
float *r_frame,
- bool *r_found)
+ bool *r_found,
+ bool *r_is_selected)
{
*r_found = false;
@@ -182,6 +183,7 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac,
*r_selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP);
*r_frame = ak->cfra;
*r_found = true;
+ *r_is_selected = (ak->sel & SELECT) != 0;
break;
}
}
@@ -197,14 +199,16 @@ static void actkeys_find_key_at_position(bAnimContext *ac,
bAnimListElem **r_ale,
float *r_selx,
float *r_frame,
- bool *r_found)
+ bool *r_found,
+ bool *r_is_selected)
{
*r_found = false;
*r_ale = actkeys_find_list_element_at_position(ac, filter, region_x, region_y);
if (*r_ale != NULL) {
- actkeys_find_key_in_list_element(ac, *r_ale, region_x, r_selx, r_frame, r_found);
+ actkeys_find_key_in_list_element(
+ ac, *r_ale, region_x, r_selx, r_frame, r_found, r_is_selected);
}
}
@@ -213,9 +217,11 @@ static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float r
bAnimListElem *ale;
float selx, frame;
bool found;
+ bool is_selected;
int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS;
- actkeys_find_key_at_position(ac, filter, region_x, region_y, &ale, &selx, &frame, &found);
+ actkeys_find_key_at_position(
+ ac, filter, region_x, region_y, &ale, &selx, &frame, &found, &is_selected);
if (ale != NULL) {
MEM_freeN(ale);
@@ -339,7 +345,9 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -572,7 +580,9 @@ static int actkeys_box_select_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -805,7 +815,9 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -871,7 +883,9 @@ static int action_circle_select_exec(bContext *C, wmOperator *op)
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1099,7 +1113,9 @@ static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1159,7 +1175,9 @@ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1243,7 +1261,9 @@ static int actkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1278,7 +1298,9 @@ static int actkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1665,20 +1687,29 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
/* ------------------- */
-static void mouse_action_keys(bAnimContext *ac,
- const int mval[2],
- short select_mode,
- const bool deselect_all,
- const bool column,
- const bool same_channel)
+static int mouse_action_keys(bAnimContext *ac,
+ const int mval[2],
+ short select_mode,
+ const bool deselect_all,
+ const bool column,
+ const bool same_channel,
+ bool wait_to_deselect_others)
{
int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS;
bAnimListElem *ale = NULL;
bool found = false;
+ bool is_selected = false;
float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
float selx = 0.0f; /* frame of keyframe under mouse */
- actkeys_find_key_at_position(ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found);
+ int ret_value = OPERATOR_FINISHED;
+
+ actkeys_find_key_at_position(
+ ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found, &is_selected);
+
+ if (select_mode != SELECT_REPLACE) {
+ wait_to_deselect_others = false;
+ }
/* For replacing selection, if we have something to select, we have to clear existing selection.
* The same goes if we found nothing to select, and deselect_all is true
@@ -1687,56 +1718,61 @@ static void mouse_action_keys(bAnimContext *ac,
/* reset selection mode for next steps */
select_mode = SELECT_ADD;
- /* deselect all keyframes */
- deselect_action_keys(ac, 0, SELECT_SUBTRACT);
-
- /* highlight channel clicked on */
- if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {
- /* deselect all other channels first */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
-
- /* Highlight Action-Group or F-Curve? */
- if (ale != NULL && ale->data) {
- if (ale->type == ANIMTYPE_GROUP) {
- bActionGroup *agrp = ale->data;
-
- agrp->flag |= AGRP_SELECTED;
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
- }
- else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
- FCurve *fcu = ale->data;
-
- fcu->flag |= FCURVE_SELECTED;
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
+ if (wait_to_deselect_others && is_selected) {
+ ret_value = OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ /* deselect all keyframes */
+ deselect_action_keys(ac, 0, SELECT_SUBTRACT);
+
+ /* highlight channel clicked on */
+ if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {
+ /* deselect all other channels first */
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+
+ /* Highlight Action-Group or F-Curve? */
+ if (ale != NULL && ale->data) {
+ if (ale->type == ANIMTYPE_GROUP) {
+ bActionGroup *agrp = ale->data;
+
+ agrp->flag |= AGRP_SELECTED;
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
+ }
+ else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
+ FCurve *fcu = ale->data;
+
+ fcu->flag |= FCURVE_SELECTED;
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
+ }
}
}
- }
- else if (ac->datatype == ANIMCONT_GPENCIL) {
- /* deselect all other channels first */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
-
- /* Highlight GPencil Layer */
- if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) {
- bGPdata *gpd = (bGPdata *)ale->id;
- bGPDlayer *gpl = ale->data;
-
- gpl->flag |= GP_LAYER_SELECT;
- /* Update other layer status. */
- if (BKE_gpencil_layer_getactive(gpd) != gpl) {
- BKE_gpencil_layer_setactive(gpd, gpl);
- BKE_gpencil_layer_autolock_set(gpd, false);
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ else if (ac->datatype == ANIMCONT_GPENCIL) {
+ /* deselect all other channels first */
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+
+ /* Highlight GPencil Layer */
+ if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) {
+ bGPdata *gpd = (bGPdata *)ale->id;
+ bGPDlayer *gpl = ale->data;
+
+ gpl->flag |= GP_LAYER_SELECT;
+ /* Update other layer status. */
+ if (BKE_gpencil_layer_getactive(gpd) != gpl) {
+ BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_autolock_set(gpd, false);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
}
}
- }
- else if (ac->datatype == ANIMCONT_MASK) {
- /* deselect all other channels first */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ else if (ac->datatype == ANIMCONT_MASK) {
+ /* deselect all other channels first */
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
- if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) {
- MaskLayer *masklay = ale->data;
+ if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = ale->data;
- masklay->flag |= MASK_LAYERFLAG_SELECT;
+ masklay->flag |= MASK_LAYERFLAG_SELECT;
+ }
}
}
}
@@ -1771,12 +1807,15 @@ static void mouse_action_keys(bAnimContext *ac,
/* free this channel */
MEM_freeN(ale);
}
+
+ return ret_value;
}
/* handle clicking */
-static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int actkeys_clickselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+ int ret_value;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
@@ -1789,20 +1828,26 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent
/* select mode is either replace (deselect all, then add) or add/extend */
const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE;
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
+ int mval[2];
/* column selection */
const bool column = RNA_boolean_get(op->ptr, "column");
const bool channel = RNA_boolean_get(op->ptr, "channel");
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
+
/* select keyframe(s) based upon mouse position*/
- mouse_action_keys(&ac, event->mval, selectmode, deselect_all, column, channel);
+ ret_value = mouse_action_keys(
+ &ac, mval, selectmode, deselect_all, column, channel, wait_to_deselect_others);
/* set notifier that keyframe selection (and channels too) have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
/* for tweak grab to work */
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ return ret_value | OPERATOR_PASS_THROUGH;
}
void ACTION_OT_clickselect(wmOperatorType *ot)
@@ -1815,13 +1860,16 @@ void ACTION_OT_clickselect(wmOperatorType *ot)
ot->description = "Select keyframes by clicking on them";
/* callbacks */
- ot->invoke = actkeys_clickselect_invoke;
ot->poll = ED_operator_action_active;
+ ot->exec = actkeys_clickselect_exec;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
+ WM_operator_properties_generic_select(ot);
prop = RNA_def_boolean(
ot->srna,
"extend",
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index e96dc91cedb..80b58954c8f 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -161,7 +161,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
/* cache background */
ED_region_cache_draw_background(ar);
- /* cached segments -- could be usefu lto debug caching strategies */
+ /* cached segments -- could be useful to debug caching strategies */
BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points);
ED_region_cache_draw_cached_segments(ar, totseg, points, sfra, efra);
@@ -404,177 +404,185 @@ static void draw_stabilization_border(
}
}
-static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
-{
-#define MAX_STATIC_PATH 64
- int count = sc->path_length;
- int i, a, b, curindex = -1;
- float path_static[(MAX_STATIC_PATH + 1) * 2][2];
- float(*path)[2];
- int tiny = sc->flag & SC_SHOW_TINY_MARKER, framenr, start_frame;
- MovieTrackingMarker *marker;
+enum {
+ PATH_POINT_FLAG_KEYFRAME = (1 << 0),
+};
- if (count == 0) {
- return;
- }
+typedef struct TrachPathPoint {
+ float co[2];
+ uchar flag;
+} TrackPathPoint;
- start_frame = framenr = ED_space_clip_get_clip_frame_number(sc);
-
- marker = BKE_tracking_marker_get(track, framenr);
- if (marker->framenr != framenr || marker->flag & MARKER_DISABLED) {
- return;
- }
-
- if (count < MAX_STATIC_PATH) {
- path = path_static;
- }
- else {
- path = MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path");
+static void marker_to_path_point(SpaceClip *sc,
+ const MovieTrackingTrack *track,
+ const MovieTrackingMarker *marker,
+ TrackPathPoint *point)
+{
+ add_v2_v2v2(point->co, marker->pos, track->offset);
+ ED_clip_point_undistorted_pos(sc, point->co, point->co);
+ point->flag = 0;
+ if ((marker->flag & MARKER_TRACKED) == 0) {
+ point->flag |= PATH_POINT_FLAG_KEYFRAME;
}
+}
- a = count;
- i = framenr - 1;
- while (i >= framenr - count) {
- marker = BKE_tracking_marker_get(track, i);
-
- if (!marker || marker->flag & MARKER_DISABLED) {
+static int track_to_path_segment(SpaceClip *sc,
+ MovieTrackingTrack *track,
+ int direction,
+ TrackPathPoint *path)
+{
+ const int count = sc->path_length;
+ int current_frame = ED_space_clip_get_clip_frame_number(sc);
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, current_frame);
+ /* Check whether there is marker at exact current frame.
+ * If not, we don't have anything to be put to path. */
+ if (marker == NULL || (marker->flag & MARKER_DISABLED)) {
+ return 0;
+ }
+ /* Index inside of path array where we write data to. */
+ int point_index = count;
+ int path_length = 0;
+ for (int i = 0; i < count; ++i) {
+ marker_to_path_point(sc, track, marker, &path[point_index]);
+ /* Move to the next marker along the path segment. */
+ path_length++;
+ point_index += direction;
+ current_frame += direction;
+ marker = BKE_tracking_marker_get_exact(track, current_frame);
+ if (marker == NULL || (marker->flag & MARKER_DISABLED)) {
+ /* Reached end of tracked segment. */
break;
}
+ }
+ return path_length;
+}
- if (marker->framenr == i) {
- add_v2_v2v2(path[--a], marker->pos, track->offset);
- ED_clip_point_undistorted_pos(sc, path[a], path[a]);
+static void draw_track_path_points(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ if (num_points == 0) {
+ return;
+ }
+ immBegin(GPU_PRIM_POINTS, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ immVertex2fv(position_attribute, point->co);
+ }
+ immEnd();
+}
- if (marker->framenr == start_frame) {
- curindex = a;
- }
- }
- else {
- break;
+static void draw_track_path_keyframe_points(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ immBeginAtMost(GPU_PRIM_POINTS, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ if (point->flag & PATH_POINT_FLAG_KEYFRAME) {
+ immVertex2fv(position_attribute, point->co);
}
+ }
+ immEnd();
+}
- i--;
+static void draw_track_path_lines(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ if (num_points < 2) {
+ return;
+ }
+ immBegin(GPU_PRIM_LINE_STRIP, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ immVertex2fv(position_attribute, point->co);
}
+ immEnd();
+}
- b = count;
- i = framenr;
- while (i <= framenr + count) {
- marker = BKE_tracking_marker_get(track, i);
+static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
+{
+#define MAX_STATIC_PATH 64
- if (!marker || marker->flag & MARKER_DISABLED) {
- break;
- }
+ const int count = sc->path_length;
+ TrackPathPoint path_static[(MAX_STATIC_PATH + 1) * 2];
+ TrackPathPoint *path;
+ const bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0;
- if (marker->framenr == i) {
- if (marker->framenr == start_frame) {
- curindex = b;
- }
+ if (count == 0) {
+ /* Early output, nothing to bother about here. */
+ return;
+ }
- add_v2_v2v2(path[b++], marker->pos, track->offset);
- ED_clip_point_undistorted_pos(sc, path[b - 1], path[b - 1]);
- }
- else {
- break;
- }
+ /* Try to use stack allocated memory when possibly, only use heap allocation
+ * for really long paths. */
+ path = (count < MAX_STATIC_PATH) ? path_static :
+ MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path");
+ /* Collect path information. */
+ const int num_points_before = track_to_path_segment(sc, track, -1, path);
+ const int num_points_after = track_to_path_segment(sc, track, 1, path);
+ if (num_points_before == 0 && num_points_after == 0) {
+ return;
+ }
- i++;
+ int num_all_points = num_points_before + num_points_after;
+ /* If both leading and trailing parts of the path are there the center point is counted twice. */
+ if (num_points_before != 0 && num_points_after != 0) {
+ num_all_points -= 1;
}
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const int path_start_index = count - num_points_before + 1;
+ const int path_center_index = count;
+ const uint position_attribute = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* Draw path outline. */
if (!tiny) {
immUniformThemeColor(TH_MARKER_OUTLINE);
-
if (TRACK_VIEW_SELECTED(sc, track)) {
- if ((b - a - 1) >= 1) {
- GPU_point_size(5.0f);
-
- immBegin(GPU_PRIM_POINTS, b - a - 1);
-
- for (i = a; i < b; i++) {
- if (i != curindex) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
- }
-
- immEnd();
- }
- }
-
- if ((b - a) >= 2) {
- GPU_line_width(3.0f);
-
- immBegin(GPU_PRIM_LINE_STRIP, b - a);
-
- for (i = a; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
+ GPU_point_size(5.0f);
+ draw_track_path_points(path, position_attribute, path_start_index, num_all_points);
+ GPU_point_size(7.0f);
+ draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_all_points);
}
+ /* Draw darker outline for actual path, all line segments at once. */
+ GPU_line_width(3.0f);
+ draw_track_path_lines(path, position_attribute, path_start_index, num_all_points);
}
- if (TRACK_VIEW_SELECTED(sc, track)) {
- GPU_point_size(3.0f);
-
- if ((curindex - a) >= 1) {
- immUniformThemeColor(TH_PATH_BEFORE);
-
- immBegin(GPU_PRIM_POINTS, curindex - a);
-
- for (i = a; i < curindex; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
-
- if ((b - curindex - 1) >= 1) {
- immUniformThemeColor(TH_PATH_AFTER);
-
- immBegin(GPU_PRIM_POINTS, b - curindex - 1);
-
- for (i = curindex + 1; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
- }
+ /* Draw all points. */
+ GPU_point_size(3.0f);
+ immUniformThemeColor(TH_PATH_BEFORE);
+ draw_track_path_points(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_AFTER);
+ draw_track_path_points(path, position_attribute, path_center_index, num_points_after);
+ /* Connect points with color coded segments. */
GPU_line_width(1);
+ immUniformThemeColor(TH_PATH_BEFORE);
+ draw_track_path_lines(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_AFTER);
+ draw_track_path_lines(path, position_attribute, path_center_index, num_points_after);
+
+ /* Draw all bigger points corresponding to keyframes. */
+ GPU_point_size(5.0f);
+ immUniformThemeColor(TH_PATH_KEYFRAME_BEFORE);
+ draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_KEYFRAME_AFTER);
+ draw_track_path_keyframe_points(path, position_attribute, path_center_index, num_points_after);
- if ((curindex - a + 1) >= 2) {
- immUniformThemeColor(TH_PATH_BEFORE);
-
- immBegin(GPU_PRIM_LINE_STRIP, curindex - a + 1);
-
- for (i = a; i <= curindex; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
-
- if ((b - curindex) >= 2) {
- immUniformThemeColor(TH_PATH_AFTER);
-
- immBegin(GPU_PRIM_LINE_STRIP, b - curindex);
-
- for (i = curindex; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
+ if (path != path_static) {
+ MEM_freeN(path);
}
immUnbindProgram();
- if (path != path_static) {
- MEM_freeN(path);
- }
#undef MAX_STATIC_PATH
}
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 1fae4c91a48..bd54d4f0016 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -94,6 +94,7 @@ void CLIP_OT_view_zoom_out(struct wmOperatorType *ot);
void CLIP_OT_view_zoom_ratio(struct wmOperatorType *ot);
void CLIP_OT_view_all(struct wmOperatorType *ot);
void CLIP_OT_view_selected(struct wmOperatorType *ot);
+void CLIP_OT_view_center_cursor(struct wmOperatorType *ot);
void CLIP_OT_change_frame(wmOperatorType *ot);
void CLIP_OT_rebuild_proxy(struct wmOperatorType *ot);
void CLIP_OT_mode_set(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index da534cf9b40..192449a219d 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -78,7 +78,9 @@
#include "clip_intern.h" // own include
-/******************** view navigation utilities *********************/
+/* -------------------------------------------------------------------- */
+/** \name View Navigation Utilities
+ * \{ */
static void sclip_zoom_set(const bContext *C,
float zoom,
@@ -162,7 +164,11 @@ static void sclip_zoom_set_factor_exec(bContext *C, const wmEvent *event, float
ED_region_tag_redraw(ar);
}
-/******************** open clip operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Open Clip Operator
+ * \{ */
static void clip_filesel(bContext *C, wmOperator *op, const char *path)
{
@@ -326,7 +332,11 @@ void CLIP_OT_open(wmOperatorType *ot)
FILE_SORT_ALPHA);
}
-/******************* reload clip operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reload Clip Operator
+ * \{ */
static int reload_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -355,7 +365,11 @@ void CLIP_OT_reload(wmOperatorType *ot)
ot->exec = reload_exec;
}
-/********************** view pan operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Pan Operator
+ * \{ */
typedef struct ViewPanData {
float x, y;
@@ -376,7 +390,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->x = event->x;
@@ -525,7 +539,11 @@ void CLIP_OT_view_pan(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Operator
+ * \{ */
typedef struct ViewZoomData {
float x, y;
@@ -549,7 +567,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
if (U.viewzoom == USER_ZOOM_CONT) {
@@ -729,7 +747,11 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
WM_operator_properties_use_cursor_init(ot);
}
-/********************** view zoom in/out operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom In/Out Operator
+ * \{ */
static int view_zoom_in_exec(bContext *C, wmOperator *op)
{
@@ -845,7 +867,11 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/********************** view zoom ratio operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Ratio Operator
+ * \{ */
static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
{
@@ -887,8 +913,11 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
-FLT_MAX,
FLT_MAX);
}
+/** \} */
-/********************** view all operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name View All Operator
+ * \{ */
static int view_all_exec(bContext *C, wmOperator *op)
{
@@ -961,8 +990,41 @@ void CLIP_OT_view_all(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Center View To Cursor Operator
+ * \{ */
+
+static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ clip_view_center_to_point(sc, sc->cursor[0], sc->cursor[1]);
-/********************** view selected operator *********************/
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_view_center_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Center View to Cursor";
+ ot->description = "Center the view so that the cursor is in the middle of the view";
+ ot->idname = "CLIP_OT_view_center_cursor";
+
+ /* api callbacks */
+ ot->exec = view_center_cursor_exec;
+ ot->poll = ED_space_clip_maskedit_poll;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ * \{ */
static int view_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -992,8 +1054,11 @@ void CLIP_OT_view_selected(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+/** \} */
-/********************** change frame operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Change Frame Operator
+ * \{ */
static bool change_frame_poll(bContext *C)
{
@@ -1109,8 +1174,11 @@ void CLIP_OT_change_frame(wmOperatorType *ot)
/* rna */
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
}
+/** \} */
-/********************** rebuild proxies operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Rebuild Proxies Operator
+ * \{ */
typedef struct ProxyBuildJob {
Scene *scene;
@@ -1521,8 +1589,11 @@ void CLIP_OT_rebuild_proxy(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
}
+/** \} */
-/********************** mode set operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Mode Set Operator
+ * \{ */
static int mode_set_exec(bContext *C, wmOperator *op)
{
@@ -1558,7 +1629,12 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
}
#ifdef WITH_INPUT_NDOF
-/********************** NDOF operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Operator
+ * \{ */
/* Combined pan/zoom from a 3D mouse device.
* Z zooms, XY pans
@@ -1608,9 +1684,14 @@ void CLIP_OT_view_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+
+/** \} */
+
#endif /* WITH_INPUT_NDOF */
-/********************** Prefetch operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Prefetch Operator
+ * \{ */
static int clip_prefetch_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
@@ -1650,8 +1731,11 @@ void CLIP_OT_prefetch(wmOperatorType *ot)
ot->invoke = clip_prefetch_invoke;
ot->modal = clip_prefetch_modal;
}
+/** \} */
-/********************** Set scene frames *********************/
+/* -------------------------------------------------------------------- */
+/** \name Set Scene Frames Operator
+ * \{ */
static int clip_set_scene_frames_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1686,8 +1770,11 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
ot->exec = clip_set_scene_frames_exec;
}
+/** \} */
-/******************** set 3d cursor operator ********************/
+/* -------------------------------------------------------------------- */
+/** \name Set 3d Cursor Operator
+ * \{ */
static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
@@ -1748,7 +1835,11 @@ void CLIP_OT_cursor_set(wmOperatorType *ot)
10.0f);
}
-/********************** Toggle lock to selection operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Lock To Selection Operator
+ * \{ */
static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1773,7 +1864,11 @@ void CLIP_OT_lock_selection_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_LOCK_BYPASS;
}
-/********************** macros *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Macros
+ * \{ */
void ED_operatormacros_clip(void)
{
@@ -1797,3 +1892,5 @@ void ED_operatormacros_clip(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "release_confirm", true);
}
+
+/** \} */
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 2964a95648a..16305a9b17b 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -443,6 +443,7 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_view_zoom_ratio);
WM_operatortype_append(CLIP_OT_view_all);
WM_operatortype_append(CLIP_OT_view_selected);
+ WM_operatortype_append(CLIP_OT_view_center_cursor);
WM_operatortype_append(CLIP_OT_change_frame);
WM_operatortype_append(CLIP_OT_rebuild_proxy);
WM_operatortype_append(CLIP_OT_mode_set);
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 68198acfe52..f1bce00ea0b 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -2090,7 +2090,7 @@ static int keyframe_insert_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_keyframe_insert(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Insert keyframe";
+ ot->name = "Insert Keyframe";
ot->description = "Insert a keyframe to selected tracks at current frame";
ot->idname = "CLIP_OT_keyframe_insert";
@@ -2113,7 +2113,7 @@ static int keyframe_delete_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_keyframe_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete keyframe";
+ ot->name = "Delete Keyframe";
ot->description = "Delete a keyframe from selected tracks at current frame";
ot->idname = "CLIP_OT_keyframe_delete";
diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c
index 1d2fc239a89..7e2671382b9 100644
--- a/source/blender/editors/space_clip/tracking_ops_solve.c
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -118,7 +118,11 @@ static void solve_camera_freejob(void *scv)
MovieClip *clip = scj->clip;
int solved;
- WM_set_locked_interface(scj->wm, false);
+ /* WindowManager is missing in the job when initialization is incomplete.
+ * In this case the interface is not locked either. */
+ if (scj->wm != NULL) {
+ WM_set_locked_interface(scj->wm, false);
+ }
if (!scj->context) {
/* job weren't fully initialized due to some error */
diff --git a/source/blender/editors/space_clip/tracking_ops_utils.c b/source/blender/editors/space_clip/tracking_ops_utils.c
index 3970f1381bf..7579c9a49c6 100644
--- a/source/blender/editors/space_clip/tracking_ops_utils.c
+++ b/source/blender/editors/space_clip/tracking_ops_utils.c
@@ -57,11 +57,11 @@ void clip_tracking_clear_invisible_track_selection(SpaceClip *sc, MovieClip *cli
void clip_tracking_hide_cursor(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- WM_cursor_set(win, CURSOR_NONE);
+ WM_cursor_set(win, WM_CURSOR_NONE);
}
void clip_tracking_show_cursor(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index f5c02dbd724..5cc2f00413a 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -149,11 +149,11 @@ static void console_main_region_init(wmWindowManager *wm, ARegion *ar)
static void console_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
SpaceText *st = sa->spacedata.first;
- int wmcursor = BC_TEXTEDITCURSOR;
+ int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text &&
BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
- wmcursor = CURSOR_STD;
+ wmcursor = WM_CURSOR_DEFAULT;
}
WM_cursor_set(win, wmcursor);
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 4b86f38f8e4..b0ff67844d8 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -32,10 +32,6 @@ struct FileSelectParams;
struct SpaceFile;
struct View2D;
-/* file_ops.c */
-struct ARegion *file_tools_region(struct ScrArea *sa);
-struct ARegion *file_tool_props_region(struct ScrArea *sa);
-
/* file_draw.c */
#define TILE_BORDER_X (UI_UNIT_X / 4)
#define TILE_BORDER_Y (UI_UNIT_Y / 4)
@@ -86,7 +82,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot);
void FILE_OT_previous(struct wmOperatorType *ot);
void FILE_OT_next(struct wmOperatorType *ot);
void FILE_OT_refresh(struct wmOperatorType *ot);
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot);
void FILE_OT_filenum(struct wmOperatorType *ot);
void FILE_OT_delete(struct wmOperatorType *ot);
void FILE_OT_rename(struct wmOperatorType *ot);
@@ -112,6 +107,7 @@ void file_sfile_to_operator_ex(bContext *C,
struct SpaceFile *sfile,
char *filepath);
void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile);
+
void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 127196cca74..3cdcc07f081 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1506,14 +1506,11 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
bool file_draw_check_exists(SpaceFile *sfile)
{
if (sfile->op) { /* fails on reload */
- PropertyRNA *prop;
- if ((prop = RNA_struct_find_property(sfile->op->ptr, "check_existing"))) {
- if (RNA_property_boolean_get(sfile->op->ptr, prop)) {
- char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
- if (BLI_is_file(filepath)) {
- return true;
- }
+ if (sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING)) {
+ char filepath[FILE_MAX];
+ BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
+ if (BLI_is_file(filepath)) {
+ return true;
}
}
}
@@ -2152,6 +2149,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
+ char old_dir[sizeof(sfile->params->dir)];
+
+ BLI_strncpy(old_dir, sfile->params->dir, sizeof(old_dir));
+
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
@@ -2185,8 +2186,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
if (filelist_is_dir(sfile->files, sfile->params->dir)) {
- /* if directory exists, enter it immediately */
- ED_file_change_dir(C);
+ if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
+ /* if directory exists, enter it immediately */
+ ED_file_change_dir(C);
+ }
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -2318,78 +2321,6 @@ void FILE_OT_hidedot(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
}
-ARegion *file_tools_region(ScrArea *sa)
-{
- ARegion *ar, *arnew;
-
- if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) {
- return ar;
- }
-
- /* add subdiv level; after header */
- ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
-
- /* is error! */
- if (ar == NULL) {
- return NULL;
- }
-
- arnew = MEM_callocN(sizeof(ARegion), "tools for file");
- BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_TOOLS;
- arnew->alignment = RGN_ALIGN_LEFT;
-
- return arnew;
-}
-
-ARegion *file_tool_props_region(ScrArea *sa)
-{
- ARegion *ar, *arnew;
-
- if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) {
- return ar;
- }
-
- /* add subdiv level; after execute region */
- ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE);
-
- /* is error! */
- if (ar == NULL) {
- return NULL;
- }
-
- arnew = MEM_callocN(sizeof(ARegion), "tool props for file");
- BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_TOOL_PROPS;
- arnew->alignment = RGN_ALIGN_RIGHT;
-
- return arnew;
-}
-
-static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
-{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = file_tools_region(sa);
-
- if (ar) {
- ED_region_toggle_hidden(C, ar);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Bookmarks";
- ot->description = "Toggle bookmarks display";
- ot->idname = "FILE_OT_bookmark_toggle";
-
- /* api callbacks */
- ot->exec = file_bookmark_toggle_exec;
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
-}
-
static bool file_filenum_poll(bContext *C)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -2398,7 +2329,7 @@ static bool file_filenum_poll(bContext *C)
return false;
}
- return sfile->params && (sfile->params->action_type == FILE_SAVE);
+ return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING);
}
/**
@@ -2464,60 +2395,49 @@ void FILE_OT_filenum(struct wmOperatorType *ot)
RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
}
-static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
+static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected)
{
- ScrArea *sa = CTX_wm_area(C);
- SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
+ const int numfiles = filelist_files_ensure(sfile->files);
- if (sfile->params) {
- int idx = sfile->params->highlight_file;
- int numfiles = filelist_files_ensure(sfile->files);
- if ((0 <= idx) && (idx < numfiles)) {
- FileDirEntry *file = filelist_file(sfile->files, idx);
+ if ((file_idx >= 0) && (file_idx < numfiles)) {
+ FileDirEntry *file = filelist_file(sfile->files, file_idx);
+
+ if ((require_selected == false) ||
+ (filelist_entry_select_get(sfile->files, file, CHECK_ALL) & FILE_SEL_SELECTED)) {
filelist_entry_select_index_set(
- sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
+ sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
BLI_strncpy(sfile->params->renamefile, file->relpath, FILE_MAXFILE);
/* We can skip the pending state,
* as we can directly set FILE_SEL_EDITING on the expected entry here. */
sfile->params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
}
+ }
+}
+
+static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+{
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
+
+ if (sfile->params) {
+ file_rename_state_activate(sfile, sfile->params->active_file, true);
ED_area_tag_redraw(sa);
}
return OPERATOR_FINISHED;
}
-static bool file_rename_poll(bContext *C)
+static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
{
- bool poll = ED_operator_file_active(C);
- SpaceFile *sfile = CTX_wm_space_file(C);
-
- if (sfile && sfile->params) {
- int idx = sfile->params->highlight_file;
- int numfiles = filelist_files_ensure(sfile->files);
-
- if ((0 <= idx) && (idx < numfiles)) {
- FileDirEntry *file = filelist_file(sfile->files, idx);
- if (FILENAME_IS_CURRPAR(file->relpath)) {
- poll = false;
- }
- }
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
- if (sfile->params->highlight_file < 0) {
- poll = false;
- }
- else {
- char dir[FILE_MAX_LIBEXTRA];
- if (filelist_islibrary(sfile->files, dir, NULL)) {
- poll = false;
- }
- }
- }
- else {
- poll = false;
+ if (sfile->params) {
+ file_rename_state_activate(sfile, sfile->params->highlight_file, false);
+ ED_area_tag_redraw(sa);
}
- return poll;
+ return OPERATOR_FINISHED;
}
void FILE_OT_rename(struct wmOperatorType *ot)
@@ -2528,8 +2448,9 @@ void FILE_OT_rename(struct wmOperatorType *ot)
ot->idname = "FILE_OT_rename";
/* api callbacks */
+ ot->invoke = file_rename_invoke;
ot->exec = file_rename_exec;
- ot->poll = file_rename_poll;
+ ot->poll = ED_operator_file_active;
}
static bool file_delete_poll(bContext *C)
@@ -2573,23 +2494,29 @@ int file_delete_exec(bContext *C, wmOperator *op)
int numfiles = filelist_files_ensure(sfile->files);
int i;
+ const char *error_message = NULL;
bool report_error = false;
errno = 0;
for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
file = filelist_file(sfile->files, i);
BLI_make_file_string(BKE_main_blendfile_path(bmain), str, sfile->params->dir, file->relpath);
- if (BLI_delete(str, false, false) != 0 || BLI_exists(str)) {
+ if (BLI_delete_soft(str, &error_message) != 0 || BLI_exists(str)) {
report_error = true;
}
}
}
if (report_error) {
- BKE_reportf(op->reports,
- RPT_ERROR,
- "Could not delete file: %s",
- errno ? strerror(errno) : "unknown error");
+ if (error_message != NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "Could not delete file or directory: %s", error_message);
+ }
+ else {
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "Could not delete file or directory: %s",
+ errno ? strerror(errno) : "unknown error");
+ }
}
ED_fileselect_clear(wm, sa, sfile);
@@ -2602,7 +2529,7 @@ void FILE_OT_delete(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Delete Selected Files";
- ot->description = "Delete selected files";
+ ot->description = "Move selected files to the trash or recycle bin";
ot->idname = "FILE_OT_delete";
/* api callbacks */
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index b0fed1fafd4..9ba098fcf45 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -110,18 +110,22 @@ void file_tool_props_region_panels_register(ARegionType *art)
BLI_addtail(&art->paneltypes, pt);
}
-static void file_panel_execution_cancel_button(uiBlock *block)
+static void file_panel_execution_cancel_button(uiLayout *layout)
{
- uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_cancel",
- WM_OP_EXEC_REGION_WIN,
- IFACE_("Cancel"),
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- "");
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ uiItemO(row, IFACE_("Cancel"), ICON_NONE, "FILE_OT_cancel");
+}
+
+static void file_panel_execution_execute_button(uiLayout *layout, const char *title)
+{
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ /* Just a display hint. */
+ uiLayoutSetActiveDefault(row, true);
+ uiItemO(row, title, ICON_NONE, "FILE_OT_execute");
}
static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
@@ -145,7 +149,6 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &params_rna_ptr);
row = uiLayoutRow(pa->layout, false);
- uiLayoutSetScaleX(row, 1.3f);
uiLayoutSetScaleY(row, 1.3f);
/* callbacks for operator check functions */
@@ -176,7 +179,7 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
* immediate ui_apply_but_func but only after button deactivates */
UI_but_funcN_set(but, file_filename_enter_handle, NULL, but);
- if (params->action_type == FILE_SAVE) {
+ if (params->flag & FILE_CHECK_EXISTING) {
but_extra_rna_ptr = UI_but_extra_operator_icon_add(
but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_ADD);
RNA_int_set(but_extra_rna_ptr, "increment", 1);
@@ -192,23 +195,16 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
UI_block_func_set(block, NULL, NULL, NULL);
{
- if (windows_layout == false) {
- file_panel_execution_cancel_button(block);
- }
- but = uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_execute",
- WM_OP_EXEC_REGION_WIN,
- params->title,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- "");
- /* Just a display hint. */
- UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
+ uiLayout *sub = uiLayoutRow(row, false);
+ uiLayoutSetOperatorContext(sub, WM_OP_EXEC_REGION_WIN);
+
if (windows_layout) {
- file_panel_execution_cancel_button(block);
+ file_panel_execution_execute_button(sub, params->title);
+ file_panel_execution_cancel_button(sub);
+ }
+ else {
+ file_panel_execution_cancel_button(sub);
+ file_panel_execution_execute_button(sub, params->title);
}
}
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 27cccf6bab1..d29233618de 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -831,7 +831,7 @@ void filelist_setfilter_options(FileList *filelist,
}
if ((filelist->filter_data.filter != filter) || (filelist->filter_data.filter_id != filter_id)) {
filelist->filter_data.filter = filter;
- filelist->filter_data.filter_id = filter_id;
+ filelist->filter_data.filter_id = (filter & FILE_TYPE_BLENDERLIB) ? filter_id : FILTER_ID_ALL;
update = true;
}
if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) {
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index e54f13e9356..bb3906a961b 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -49,6 +49,8 @@
#include "BLI_utildefines.h"
#include "BLI_fnmatch.h"
+#include "BLO_readfile.h"
+
#include "BLT_translation.h"
#include "BKE_appdir.h"
@@ -101,10 +103,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
sizeof(sfile->params->dir),
sizeof(sfile->params->file));
sfile->params->filter_glob[0] = '\0';
- /* set the default thumbnails size */
- sfile->params->thumbnail_size = 128;
- /* Show size column by default. */
- sfile->params->details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME;
+ sfile->params->thumbnail_size = U_default.file_space_data.thumbnail_size;
+ sfile->params->details_flags = U_default.file_space_data.details_flags;
+ sfile->params->filter_id = U_default.file_space_data.filter_id;
}
params = sfile->params;
@@ -167,6 +168,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->flag &= ~FILE_DIRSEL_ONLY;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "check_existing"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_CHECK_EXISTING : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "hide_props_region"))) {
params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_HIDE_TOOL_PROPS : 0;
}
@@ -241,15 +245,6 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
}
- /* For now, always init filterid to 'all true' */
- params->filter_id = FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU |
- FILTER_ID_GD | FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS |
- FILTER_ID_LT | FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME |
- FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA |
- FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK |
- FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO |
- FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP;
-
if (U.uiflag & USER_HIDE_DOT) {
params->flag |= FILE_HIDE_DOT;
}
@@ -271,30 +266,11 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->sort = RNA_property_enum_get(op->ptr, prop);
}
else {
- params->sort = FILE_SORT_ALPHA;
- }
-
- if ((prop = RNA_struct_find_property(op->ptr, "action_type"))) {
- params->action_type = RNA_property_enum_get(op->ptr, prop);
+ params->sort = U_default.file_space_data.sort_type;
}
if (params->display == FILE_DEFAULTDISPLAY) {
- if (params->display_previous == FILE_DEFAULTDISPLAY) {
- if (U.uiflag & USER_SHOW_THUMBNAILS) {
- if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT)) {
- params->display = FILE_IMGDISPLAY;
- }
- else {
- params->display = FILE_VERTICALDISPLAY;
- }
- }
- else {
- params->display = FILE_VERTICALDISPLAY;
- }
- }
- else {
- params->display = params->display_previous;
- }
+ params->display = U_default.file_space_data.display_type;
}
if (is_relative_path) {
@@ -308,10 +284,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
else {
/* default values, if no operator */
params->type = FILE_UNIX;
- params->flag |= FILE_HIDE_DOT;
+ params->flag |= U_default.file_space_data.flag;
params->flag &= ~FILE_DIRSEL_ONLY;
params->display = FILE_VERTICALDISPLAY;
- params->display_previous = FILE_DEFAULTDISPLAY;
params->sort = FILE_SORT_ALPHA;
params->filter = 0;
params->filter_glob[0] = '\0';
@@ -347,6 +322,65 @@ short ED_fileselect_set_params(SpaceFile *sfile)
return 1;
}
+/* The subset of FileSelectParams.flag items we store into preferences. */
+#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT | FILE_SORT_INVERT)
+
+void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
+{
+ wmOperator *op = sfile->op;
+ UserDef_FileSpaceData *sfile_udata = &U.file_space_data;
+
+ ED_fileselect_set_params(sfile);
+
+ if (!op) {
+ return;
+ }
+
+ if (!RNA_struct_property_is_set(op->ptr, "display_type")) {
+ sfile->params->display = sfile_udata->display_type;
+ }
+ if (!RNA_struct_property_is_set(op->ptr, "sort_method")) {
+ sfile->params->sort = sfile_udata->sort_type;
+ }
+ sfile->params->thumbnail_size = sfile_udata->thumbnail_size;
+ sfile->params->details_flags = sfile_udata->details_flags;
+ sfile->params->filter_id = sfile_udata->filter_id;
+
+ /* Combine flags we take from params with the flags we take from userdef. */
+ sfile->params->flag = (sfile->params->flag & ~PARAMS_FLAGS_REMEMBERED) |
+ (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED);
+}
+
+/**
+ * Update the user-preference data for the file space. In fact, this also contains some
+ * non-FileSelectParams data, but we can safely ignore this.
+ *
+ * \param temp_win_size: If the browser was opened in a temporary window,
+ * pass its size here so we can store that in the preferences. Otherwise NULL.
+ */
+void ED_fileselect_params_to_userdef(SpaceFile *sfile, int temp_win_size[2])
+{
+ UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data;
+ UserDef_FileSpaceData sfile_udata_old = U.file_space_data;
+
+ sfile_udata_new->display_type = sfile->params->display;
+ sfile_udata_new->thumbnail_size = sfile->params->thumbnail_size;
+ sfile_udata_new->sort_type = sfile->params->sort;
+ sfile_udata_new->details_flags = sfile->params->details_flags;
+ sfile_udata_new->flag = sfile->params->flag & PARAMS_FLAGS_REMEMBERED;
+ sfile_udata_new->filter_id = sfile->params->filter_id;
+
+ if (temp_win_size) {
+ sfile_udata_new->temp_win_sizex = temp_win_size[0];
+ sfile_udata_new->temp_win_sizey = temp_win_size[1];
+ }
+
+ /* Tag prefs as dirty if something has changed. */
+ if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) {
+ U.runtime.is_dirty = true;
+ }
+}
+
void ED_fileselect_reset_params(SpaceFile *sfile)
{
sfile->params->type = FILE_UNIX;
@@ -767,7 +801,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->tile_border_x * 2;
layout->flag = FILE_LAYOUT_HOR;
}
- params->display_previous = params->display;
layout->dirty = false;
}
@@ -924,6 +957,17 @@ void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile)
return;
}
if (sfile->op) {
+ wmWindow *temp_win = WM_window_is_temp_screen(wm->winactive) ? wm->winactive : NULL;
+ int win_size[2];
+
+ if (temp_win) {
+ /* Get DPI/pixelsize independent size to be stored in preferences. */
+ WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */
+ win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC;
+ win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC;
+ }
+ ED_fileselect_params_to_userdef(sfile, temp_win ? win_size : NULL);
+
WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL);
sfile->op = NULL;
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index d6a4eafc658..d63fcf402de 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -55,6 +55,40 @@
#include "filelist.h"
#include "GPU_framebuffer.h"
+static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE)) != NULL) {
+ return ar;
+ }
+
+ ar = MEM_callocN(sizeof(ARegion), "execute region for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_EXECUTE;
+ ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->flag = RGN_FLAG_DYNAMIC_SIZE;
+
+ return ar;
+}
+
+static ARegion *file_tool_props_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) {
+ return ar;
+ }
+
+ /* add subdiv level; after execute region */
+ ar = MEM_callocN(sizeof(ARegion), "tool props for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_TOOL_PROPS;
+ ar->alignment = RGN_ALIGN_RIGHT;
+
+ return ar;
+}
+
/* ******************** default callbacks for file space ***************** */
static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
@@ -72,40 +106,20 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen
/* Ignore user preference "USER_HEADER_BOTTOM" here (always show top for new types). */
ar->alignment = RGN_ALIGN_TOP;
- /* ui list region */
- ar = MEM_callocN(sizeof(ARegion), "ui region for file");
- BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_UI;
- ar->alignment = RGN_ALIGN_TOP;
- ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
-
/* Tools region */
ar = MEM_callocN(sizeof(ARegion), "tools region for file");
BLI_addtail(&sfile->regionbase, ar);
ar->regiontype = RGN_TYPE_TOOLS;
ar->alignment = RGN_ALIGN_LEFT;
- /* Tools region (lower split region) */
- ar = MEM_callocN(sizeof(ARegion), "lower tools region for file");
- BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_TOOLS;
- ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
- ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
- /* Execute region */
- ar = MEM_callocN(sizeof(ARegion), "execute region for file");
+ /* ui list region */
+ ar = MEM_callocN(sizeof(ARegion), "ui region for file");
BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_EXECUTE;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->regiontype = RGN_TYPE_UI;
+ ar->alignment = RGN_ALIGN_TOP;
ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
- /* Tool props region is added as needed. */
-#if 0
- /* Tool props (aka operator) region */
- ar = MEM_callocN(sizeof(ARegion), "tool props region for file");
- BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_TOOL_PROPS;
- ar->alignment = RGN_ALIGN_RIGHT;
-#endif
+ /* Tool props and execute region are added as needed, see file_refresh(). */
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for file");
@@ -218,6 +232,46 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
return (SpaceLink *)sfilen;
}
+static void file_ensure_valid_region_state(bContext *C,
+ wmWindowManager *wm,
+ wmWindow *win,
+ ScrArea *sa,
+ SpaceFile *sfile,
+ FileSelectParams *params)
+{
+ ARegion *ar_ui = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS);
+ ARegion *ar_execute = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE);
+ bool needs_init = false; /* To avoid multiple ED_area_initialize() calls. */
+
+ /* If there's an file-operation, ensure we have the option and execute region */
+ if (sfile->op && (ar_props == NULL)) {
+ ar_execute = file_execute_region_ensure(sa, ar_ui);
+ ar_props = file_tool_props_region_ensure(sa, ar_execute);
+
+ if (params->flag & FILE_HIDE_TOOL_PROPS) {
+ ar_props->flag |= RGN_FLAG_HIDDEN;
+ }
+ else {
+ ar_props->flag &= ~RGN_FLAG_HIDDEN;
+ }
+
+ needs_init = true;
+ }
+ /* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */
+ else if ((sfile->op == NULL) && (ar_props != NULL)) {
+ BLI_assert(ar_execute != NULL);
+
+ ED_region_remove(C, sa, ar_props);
+ ED_region_remove(C, sa, ar_execute);
+ needs_init = true;
+ }
+
+ if (needs_init) {
+ ED_area_initialize(wm, win, sa);
+ }
+}
+
static void file_refresh(const bContext *C, ScrArea *sa)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -287,21 +341,8 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
/* Might be called with NULL sa, see file_main_region_draw() below. */
- if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) {
- /* Create TOOLS region. */
- file_tools_region(sa);
-
- ED_area_initialize(wm, win, sa);
- }
- if (sa && sfile->op && BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS) == NULL) {
- /* Create TOOL_PROPS region. */
- ARegion *region_props = file_tool_props_region(sa);
-
- if (params->flag & FILE_HIDE_TOOL_PROPS) {
- region_props->flag |= RGN_FLAG_HIDDEN;
- }
-
- ED_area_initialize(wm, win, sa);
+ if (sa) {
+ file_ensure_valid_region_state((bContext *)C, wm, win, sa, sfile, params);
}
ED_area_tag_redraw(sa);
@@ -495,7 +536,6 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_previous);
WM_operatortype_append(FILE_OT_next);
WM_operatortype_append(FILE_OT_refresh);
- WM_operatortype_append(FILE_OT_bookmark_toggle);
WM_operatortype_append(FILE_OT_bookmark_add);
WM_operatortype_append(FILE_OT_bookmark_delete);
WM_operatortype_append(FILE_OT_bookmark_cleanup);
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 708d91a82bb..33cb1cb0075 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -862,7 +862,11 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
sub = uiLayoutColumn(layout, true);
uiItemR(sub, &dtar_ptr, "transform_type", 0, NULL, ICON_NONE);
- if (ELEM(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) {
+ if (ELEM(dtar->transChan,
+ DTAR_TRANSCHAN_ROTX,
+ DTAR_TRANSCHAN_ROTY,
+ DTAR_TRANSCHAN_ROTZ,
+ DTAR_TRANSCHAN_ROTW)) {
uiItemR(sub, &dtar_ptr, "rotation_mode", 0, IFACE_("Mode"), ICON_NONE);
}
@@ -1152,8 +1156,12 @@ static void graph_draw_driver_settings_panel(uiLayout *layout,
if ((dvar->type == DVAR_TYPE_ROT_DIFF) ||
(dvar->type == DVAR_TYPE_TRANSFORM_CHAN &&
- dvar->targets[0].transChan >= DTAR_TRANSCHAN_ROTX &&
- dvar->targets[0].transChan < DTAR_TRANSCHAN_SCALEX)) {
+ ELEM(dvar->targets[0].transChan,
+ DTAR_TRANSCHAN_ROTX,
+ DTAR_TRANSCHAN_ROTY,
+ DTAR_TRANSCHAN_ROTZ,
+ DTAR_TRANSCHAN_ROTW) &&
+ dvar->targets[0].rotation_mode != DTAR_ROTMODE_QUATERNION)) {
BLI_snprintf(
valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval));
}
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index c94f1f1d79f..42a1566629a 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -879,10 +879,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
float offset;
float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
- /* for now, only show when debugging driver... */
- // if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
- // return;
-
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 329067de545..59cf5f63de3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -2506,28 +2506,28 @@ static const EnumPropertyItem prop_graphkeys_mirror_types[] = {
{GRAPHKEYS_MIRROR_CFRA,
"CFRA",
0,
- "By Times over Current Frame",
+ "By Times Over Current Frame",
"Flip times of selected keyframes using the current frame as the mirror line"},
{GRAPHKEYS_MIRROR_VALUE,
"VALUE",
0,
- "By Values over Cursor Value",
+ "By Values Over Cursor Value",
"Flip values of selected keyframes using the cursor value (Y/Horizontal component) as the "
"mirror line"},
{GRAPHKEYS_MIRROR_YAXIS,
"YAXIS",
0,
- "By Times over Time=0",
+ "By Times Over Time=0",
"Flip times of selected keyframes, effectively reversing the order they appear in"},
{GRAPHKEYS_MIRROR_XAXIS,
"XAXIS",
0,
- "By Values over Value=0",
+ "By Values Over Value=0",
"Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
{GRAPHKEYS_MIRROR_MARKER,
"MARKER",
0,
- "By Times over First Selected Marker",
+ "By Times Over First Selected Marker",
"Flip times of selected keyframes using the first selected marker as the reference point"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 61e6b065cba..5abcff436f1 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
@@ -42,6 +43,7 @@ set(SRC
image_draw.c
image_edit.c
image_ops.c
+ image_undo.c
space_image.c
image_intern.h
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index ccd0a2bfd79..ec2b1cc7fbe 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -301,6 +301,18 @@ void ED_image_mouse_pos(SpaceImage *sima, ARegion *ar, const int mval[2], float
co[1] = ((mval[1] - sy) / zoomy) / height;
}
+void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
+{
+ int width, height;
+ float aspx, aspy;
+
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_aspect(sima, &aspx, &aspy);
+
+ sima->xof = (x - 0.5f) * width * aspx;
+ sima->yof = (y - 0.5f) * height * aspy;
+}
+
void ED_image_point_pos(SpaceImage *sima, ARegion *ar, float x, float y, float *xr, float *yr)
{
int sx, sy, width, height;
@@ -476,3 +488,9 @@ bool ED_space_image_maskedit_mask_poll(bContext *C)
return false;
}
+
+bool ED_space_image_cursor_poll(bContext *C)
+{
+ return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
+ ED_space_image_paint_curve(C);
+}
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 1abb6715fdb..f8ce065d46c 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -44,10 +44,12 @@ void draw_image_sample_line(struct SpaceImage *sima);
/* image_ops.c */
bool space_image_main_region_poll(struct bContext *C);
+bool space_image_view_center_cursor_poll(struct bContext *C);
void IMAGE_OT_view_all(struct wmOperatorType *ot);
void IMAGE_OT_view_pan(struct wmOperatorType *ot);
void IMAGE_OT_view_selected(struct wmOperatorType *ot);
+void IMAGE_OT_view_center_cursor(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot);
@@ -70,6 +72,7 @@ void IMAGE_OT_pack(struct wmOperatorType *ot);
void IMAGE_OT_unpack(struct wmOperatorType *ot);
void IMAGE_OT_invert(struct wmOperatorType *ot);
+void IMAGE_OT_resize(struct wmOperatorType *ot);
void IMAGE_OT_cycle_render_slot(struct wmOperatorType *ot);
void IMAGE_OT_clear_render_slot(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index e338a450db6..a8dfad85232 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -103,7 +103,9 @@
#include "image_intern.h"
-/******************** view navigation utilities *********************/
+/* -------------------------------------------------------------------- */
+/** \name View Navigation Utilities
+ * \{ */
static void sima_zoom_set(
SpaceImage *sima, ARegion *ar, float zoom, const float location[2], const bool zoom_to_pos)
@@ -211,7 +213,7 @@ static ImageUser *image_user_from_context(const bContext *C)
}
}
-static bool image_buffer_exists_from_context(bContext *C)
+static bool image_from_context_has_data_poll(bContext *C)
{
Image *ima = image_from_context(C);
ImageUser *iuser = image_user_from_context(C);
@@ -227,6 +229,16 @@ static bool image_buffer_exists_from_context(bContext *C)
return has_buffer;
}
+/**
+ * Use this when the image buffer is accessed without the image user.
+ */
+static bool image_from_contect_has_data_poll_no_image_user(bContext *C)
+{
+ Image *ima = image_from_context(C);
+
+ return BKE_image_has_ibuf(ima, NULL);
+}
+
static bool image_not_packed_poll(bContext *C)
{
/* Do not run 'replace' on packed images, it does not give user expected results at all. */
@@ -280,7 +292,12 @@ static bool image_sample_poll(bContext *C)
return true;
}
-/********************** view pan operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Pan Operator
+ * \{ */
typedef struct ViewPanData {
float x, y;
@@ -300,7 +317,7 @@ static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *even
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->x = event->x;
@@ -423,7 +440,11 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Operator
+ * \{ */
typedef struct ViewZoomData {
float origx, origy;
@@ -453,7 +474,7 @@ static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *eve
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->origx = event->x;
@@ -671,7 +692,12 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
}
#ifdef WITH_INPUT_NDOF
-/********************** NDOF operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Operator
+ * \{ */
/* Combined pan/zoom from a 3D mouse device.
* Z zooms, XY pans
@@ -721,9 +747,14 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+
+/** \} */
+
#endif /* WITH_INPUT_NDOF */
-/********************** view all operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name View All Operator
+ * \{ */
/* Updates the fields of the View2D member of the SpaceImage struct.
* Default behavior is to reset the position of the image and set the zoom to 1
@@ -800,7 +831,41 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/********************** view selected operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Center View To Cursor Operator
+ * \{ */
+
+static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ ED_image_view_center_to_point(sima, sima->cursor[0], sima->cursor[1]);
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_view_center_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Center View to Cursor";
+ ot->description = "Center the view so that the cursor is in the middle of the view";
+ ot->idname = "IMAGE_OT_view_center_cursor";
+
+ /* api callbacks */
+ ot->exec = view_center_cursor_exec;
+ ot->poll = ED_space_image_cursor_poll;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ * \{ */
static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -866,7 +931,11 @@ void IMAGE_OT_view_selected(wmOperatorType *ot)
ot->poll = image_view_selected_poll;
}
-/********************** view zoom in/out operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom In/Out Operator
+ * \{ */
static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
{
@@ -984,7 +1053,11 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/********************** view zoom ratio operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Ratio Operator
+ * \{ */
static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
{
@@ -1028,7 +1101,11 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view border-zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Border-Zoom Operator
+ * \{ */
static int image_view_zoom_border_exec(bContext *C, wmOperator *op)
{
@@ -1084,14 +1161,18 @@ void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
WM_operator_properties_gesture_box_zoom(ot);
}
-/**************** load/replace/save callbacks ******************/
+/* load/replace/save callbacks */
static void image_filesel(bContext *C, wmOperator *op, const char *path)
{
RNA_string_set(op->ptr, "filepath", path);
WM_event_add_fileselect(C, op);
}
-/******************** open image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Open Image Operator
+ * \{ */
typedef struct ImageOpenData {
PropertyPointerRNA pprop;
@@ -1525,7 +1606,12 @@ void IMAGE_OT_open(wmOperatorType *ot)
"Automatically detect animated sequences in selected images (based on file names)");
}
-/******************** Match movie length operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Match Movie Length Operator
+ * \{ */
+
static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1571,7 +1657,11 @@ void IMAGE_OT_match_movie_length(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
}
-/******************** replace image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Replace Image Operator
+ * \{ */
static int image_replace_exec(bContext *C, wmOperator *op)
{
@@ -1656,7 +1746,11 @@ void IMAGE_OT_replace(wmOperatorType *ot)
FILE_SORT_ALPHA);
}
-/******************** save image as operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Image As Operator
+ * \{ */
static char imtype_best_depth(ImBuf *ibuf, const char imtype)
{
@@ -1970,7 +2064,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
static bool image_save_as_poll(bContext *C)
{
- if (!image_buffer_exists_from_context(C)) {
+ if (!image_from_context_has_data_poll(C)) {
return false;
}
@@ -2021,12 +2115,16 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
}
-/******************** save image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Image Operator
+ * \{ */
static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser)
{
@@ -2067,7 +2165,7 @@ static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser)
static bool image_save_poll(bContext *C)
{
/* Can't save if there are no pixels. */
- if (image_buffer_exists_from_context(C) == false) {
+ if (image_from_context_has_data_poll(C) == false) {
return false;
}
@@ -2147,7 +2245,11 @@ void IMAGE_OT_save(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************* save sequence operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Sequence Operator
+ * \{ */
static int image_save_sequence_exec(bContext *C, wmOperator *op)
{
@@ -2233,13 +2335,17 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_save_sequence_exec;
- ot->poll = image_buffer_exists_from_context;
+ ot->poll = image_from_context_has_data_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** save all operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save All Operator
+ * \{ */
static bool image_should_be_saved_when_modified(Image *ima)
{
@@ -2389,7 +2495,11 @@ void IMAGE_OT_save_all_modified(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************** reload image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reload Image Operator
+ * \{ */
static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2426,7 +2536,12 @@ void IMAGE_OT_reload(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
}
-/********************** new image operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name New Image Operator
+ * \{ */
+
#define IMA_DEF_NAME N_("Untitled")
enum {
@@ -2642,22 +2757,18 @@ void IMAGE_OT_new(wmOperatorType *ot)
#undef IMA_DEF_NAME
-/********************* invert operators *********************/
-
-static bool image_invert_poll(bContext *C)
-{
- Image *ima = image_from_context(C);
+/** \} */
- return BKE_image_has_ibuf(ima, NULL);
-}
+/* -------------------------------------------------------------------- */
+/** \name Invert Operators
+ * \{ */
static int image_invert_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
- /* undo is supported only on image paint mode currently */
- bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
+ const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
/* flags indicate if this channel should be inverted */
const bool r = RNA_boolean_get(op->ptr, "invert_r");
@@ -2672,14 +2783,12 @@ static int image_invert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (support_undo) {
- ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
- /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
- * but better do this right in case someone copies this for a tool that uses partial
- * redraw better */
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf);
+
+ if (is_paint) {
ED_imapaint_clear_partial_redraw();
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
}
+
/* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
if (ibuf->rect_float) {
@@ -2733,9 +2842,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
ibuf->userflags |= IB_MIPMAP_INVALID;
}
- if (support_undo) {
- ED_image_undo_push_end();
- }
+ ED_image_undo_push_end();
/* force GPU reupload, all image is invalid */
GPU_free_image(ima);
@@ -2758,7 +2865,7 @@ void IMAGE_OT_invert(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_invert_exec;
- ot->poll = image_invert_poll;
+ ot->poll = image_from_contect_has_data_poll_no_image_user;
/* properties */
prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
@@ -2771,10 +2878,96 @@ void IMAGE_OT_invert(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scale Operator
+ * \{ */
+
+static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Image *ima = image_from_context(C);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ const int size[2] = {ibuf->x, ibuf->y};
+ RNA_property_int_set_array(op->ptr, prop, size);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ return WM_operator_props_dialog_popup(C, op, 200, 200);
+}
+
+static int image_scale_exec(bContext *C, wmOperator *op)
+{
+ Image *ima = image_from_context(C);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
+
+ if (ibuf == NULL) {
+ /* TODO: this should actually never happen, but does for render-results -> cleanup */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (is_paint) {
+ ED_imapaint_clear_partial_redraw();
+ }
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
+ int size[2];
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_int_get_array(op->ptr, prop, size);
+ }
+ else {
+ size[0] = ibuf->x;
+ size[1] = ibuf->y;
+ RNA_property_int_set_array(op->ptr, prop, size);
+ }
+
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf);
+
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ IMB_scaleImBuf(ibuf, size[0], size[1]);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ ED_image_undo_push_end();
+
+ /* force GPU reupload, all image is invalid */
+ GPU_free_image(ima);
+
+ DEG_id_tag_update(&ima->id, 0);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+
+ return OPERATOR_FINISHED;
}
-/********************* pack operator *********************/
+void IMAGE_OT_resize(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Resize Image";
+ ot->idname = "IMAGE_OT_resize";
+ ot->description = "Resize the image";
+
+ /* api callbacks */
+ ot->invoke = image_scale_invoke;
+ ot->exec = image_scale_exec;
+ ot->poll = image_from_contect_has_data_poll_no_image_user;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pack Operator
+ * \{ */
static bool image_pack_test(bContext *C, wmOperator *op)
{
@@ -2827,7 +3020,11 @@ void IMAGE_OT_pack(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************* unpack operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unpack Operator
+ * \{ */
static int image_unpack_exec(bContext *C, wmOperator *op)
{
@@ -2926,7 +3123,11 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
}
-/******************** sample image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Image Operator
+ * \{ */
typedef struct ImageSampleInfo {
ARegionType *art;
@@ -3339,7 +3540,12 @@ void IMAGE_OT_sample(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/******************** sample line operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Line Operator
+ * \{ */
+
static int image_sample_line_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -3421,10 +3627,14 @@ void IMAGE_OT_sample_line(wmOperatorType *ot)
/* flags */
ot->flag = 0; /* no undo/register since this operates on the space */
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
}
-/******************** set curve point operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Curve Point Operator
+ * \{ */
void IMAGE_OT_curves_point_set(wmOperatorType *ot)
{
@@ -3458,7 +3668,11 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/********************* cycle render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cycle Render Slot Operator
+ * \{ */
static bool image_cycle_render_slot_poll(bContext *C)
{
@@ -3504,7 +3718,11 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
}
-/********************* clear render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Render Slot Operator
+ * \{ */
static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3535,7 +3753,11 @@ void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************* add render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Render Slot Operator
+ * \{ */
static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3564,7 +3786,11 @@ void IMAGE_OT_add_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************* remove render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Render Slot Operator
+ * \{ */
static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3595,7 +3821,11 @@ void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************** change frame operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Change Frame Operator
+ * \{ */
static bool change_frame_poll(bContext *C)
{
@@ -3746,7 +3976,11 @@ void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
ot->flag = 0;
}
-/* ********************* Render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Render Border Operator
+ * \{ */
static int render_border_exec(bContext *C, wmOperator *op)
{
@@ -3815,7 +4049,11 @@ void IMAGE_OT_render_border(wmOperatorType *ot)
WM_operator_properties_border(ot);
}
-/* ********************* Clear render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Render Border Operator
+ * \{ */
static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3840,3 +4078,5 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
new file mode 100644
index 00000000000..577c4e24b11
--- /dev/null
+++ b/source/blender/editors/space_image/image_undo.c
@@ -0,0 +1,1058 @@
+/*
+ * 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.
+ *
+ * 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 spimage
+ *
+ * Overview
+ * ========
+ *
+ * - Each undo step is a #ImageUndoStep
+ * - Each #ImageUndoStep stores a list of #UndoImageHandle
+ * - Each #UndoImageHandle stores a list of #UndoImageBuf
+ * (this is the undo systems equivalent of an #ImBuf).
+ * - Each #UndoImageBuf stores an array of #UndoImageTile
+ * The tiles are shared between #UndoImageBuf's to avoid duplication.
+ *
+ * When the undo system manages an image, there will always be a full copy (as a #UndoImageBuf)
+ * each new undo step only stores modified tiles.
+ */
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_threads.h"
+
+#include "DNA_image_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_paint.h"
+#include "BKE_undo_system.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_paint.h"
+#include "ED_undo.h"
+#include "ED_util.h"
+#include "ED_object.h"
+
+#include "GPU_draw.h"
+
+#include "WM_api.h"
+
+static CLG_LogRef LOG = {"ed.image.undo"};
+
+/* -------------------------------------------------------------------- */
+/** \name Thread Locking
+ * \{ */
+
+/* This is a non-global static resource,
+ * Maybe it should be exposed as part of the
+ * paint operation, but for now just give a public interface */
+static SpinLock paint_tiles_lock;
+
+void ED_image_paint_tile_lock_init(void)
+{
+ BLI_spin_init(&paint_tiles_lock);
+}
+
+void ED_image_paint_tile_lock_end(void)
+{
+ BLI_spin_end(&paint_tiles_lock);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Tiles
+ *
+ * Created on demand while painting,
+ * use to access the previous state for some paint operations.
+ *
+ * These buffers are also used for undo when available.
+ *
+ * \{ */
+
+static ImBuf *imbuf_alloc_temp_tile(void)
+{
+ return IMB_allocImBuf(
+ ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, IB_rectfloat | IB_rect);
+}
+
+typedef struct PaintTile {
+ struct PaintTile *next, *prev;
+ Image *image;
+ ImBuf *ibuf;
+ union {
+ float *fp;
+ uint *uint;
+ void *pt;
+ } rect;
+ ushort *mask;
+ bool valid;
+ bool use_float;
+ int x, y;
+} PaintTile;
+
+static void ptile_free(PaintTile *ptile)
+{
+ if (ptile->rect.pt) {
+ MEM_freeN(ptile->rect.pt);
+ }
+ if (ptile->mask) {
+ MEM_freeN(ptile->mask);
+ }
+ MEM_freeN(ptile);
+}
+
+static void ptile_free_list(ListBase *paint_tiles)
+{
+ for (PaintTile *ptile = paint_tiles->first, *ptile_next; ptile; ptile = ptile_next) {
+ ptile_next = ptile->next;
+ ptile_free(ptile);
+ }
+ BLI_listbase_clear(paint_tiles);
+}
+
+static void ptile_invalidate_list(ListBase *paint_tiles)
+{
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ ptile->valid = false;
+ }
+}
+
+void *ED_image_paint_tile_find(ListBase *paint_tiles,
+ Image *image,
+ ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ ushort **r_mask,
+ bool validate)
+{
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ if (ptile->x == x_tile && ptile->y == y_tile) {
+ if (ptile->image == image && ptile->ibuf == ibuf) {
+ if (r_mask) {
+ /* allocate mask if requested. */
+ if (!ptile->mask) {
+ ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "UndoImageTile.mask");
+ }
+ *r_mask = ptile->mask;
+ }
+ if (validate) {
+ ptile->valid = true;
+ }
+ return ptile->rect.pt;
+ }
+ }
+ }
+ return NULL;
+}
+
+void *ED_image_paint_tile_push(ListBase *paint_tiles,
+ Image *image,
+ ImBuf *ibuf,
+ ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ ushort **r_mask,
+ bool **r_valid,
+ bool use_thread_lock,
+ bool find_prev)
+{
+ const bool has_float = (ibuf->rect_float != NULL);
+
+ /* check if tile is already pushed */
+
+ /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
+ if (find_prev) {
+ void *data = ED_image_paint_tile_find(paint_tiles, image, ibuf, x_tile, y_tile, r_mask, true);
+ if (data) {
+ return data;
+ }
+ }
+
+ if (*tmpibuf == NULL) {
+ *tmpibuf = imbuf_alloc_temp_tile();
+ }
+
+ PaintTile *ptile = MEM_callocN(sizeof(PaintTile), "PaintTile");
+
+ ptile->image = image;
+ ptile->ibuf = ibuf;
+
+ ptile->x = x_tile;
+ ptile->y = y_tile;
+
+ /* add mask explicitly here */
+ if (r_mask) {
+ *r_mask = ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.mask");
+ }
+
+ ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
+ SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.rect");
+
+ ptile->use_float = has_float;
+ ptile->valid = true;
+
+ if (r_valid) {
+ *r_valid = &ptile->valid;
+ }
+
+ IMB_rectcpy(*tmpibuf,
+ ibuf,
+ 0,
+ 0,
+ x_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ y_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, (*tmpibuf)->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, (*tmpibuf)->rect);
+ }
+
+ if (use_thread_lock) {
+ BLI_spin_lock(&paint_tiles_lock);
+ }
+ BLI_addtail(paint_tiles, ptile);
+
+ if (use_thread_lock) {
+ BLI_spin_unlock(&paint_tiles_lock);
+ }
+ return ptile->rect.pt;
+}
+
+static void ptile_restore_runtime_list(ListBase *paint_tiles)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ Image *image = ptile->image;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ const bool has_float = (ibuf->rect_float != NULL);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ }
+
+ IMB_rectcpy(
+ ibuf, tmpibuf, ptile->x, ptile->y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ }
+
+ GPU_free_image(image); /* force OpenGL reload (maybe partial update will operate better?) */
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Tile
+ * \{ */
+
+static uint index_from_xy(uint tile_x, uint tile_y, const uint tiles_dims[2])
+{
+ BLI_assert(tile_x < tiles_dims[0] && tile_y < tiles_dims[1]);
+ return (tile_y * tiles_dims[0]) + tile_x;
+}
+
+typedef struct UndoImageTile {
+ union {
+ float *fp;
+ uint *uint;
+ void *pt;
+ } rect;
+ int users;
+} UndoImageTile;
+
+static UndoImageTile *utile_alloc(bool has_float)
+{
+ UndoImageTile *utile = MEM_callocN(sizeof(*utile), "ImageUndoTile");
+ if (has_float) {
+ utile->rect.fp = MEM_mallocN(sizeof(float[4]) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ }
+ else {
+ utile->rect.uint = MEM_mallocN(sizeof(uint) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ }
+ return utile;
+}
+
+static void utile_init_from_imbuf(
+ UndoImageTile *utile, const uint x, const uint y, const ImBuf *ibuf, ImBuf *tmpibuf)
+{
+ const bool has_float = ibuf->rect_float;
+
+ if (has_float) {
+ SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ }
+
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, x, y, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ }
+}
+
+static void utile_restore(
+ const UndoImageTile *utile, const uint x, const uint y, ImBuf *ibuf, ImBuf *tmpibuf)
+{
+ const bool has_float = ibuf->rect_float;
+ float *prev_rect_float = tmpibuf->rect_float;
+ uint *prev_rect = tmpibuf->rect;
+
+ if (has_float) {
+ tmpibuf->rect_float = utile->rect.fp;
+ }
+ else {
+ tmpibuf->rect = utile->rect.uint;
+ }
+
+ IMB_rectcpy(ibuf, tmpibuf, x, y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ tmpibuf->rect_float = prev_rect_float;
+ tmpibuf->rect = prev_rect;
+}
+
+static void utile_decref(UndoImageTile *utile)
+{
+ utile->users -= 1;
+ BLI_assert(utile->users >= 0);
+ if (utile->users == 0) {
+ MEM_freeN(utile->rect.pt);
+ MEM_freeN(utile);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Buffer
+ * \{ */
+
+typedef struct UndoImageBuf {
+ struct UndoImageBuf *next, *prev;
+
+ /**
+ * The buffer after the undo step has executed.
+ */
+ struct UndoImageBuf *post;
+
+ char ibuf_name[IMB_FILENAME_SIZE];
+
+ UndoImageTile **tiles;
+
+ /** Can calculate these from dims, just for convenience. */
+ uint tiles_len;
+ uint tiles_dims[2];
+
+ uint image_dims[2];
+
+ /** Store variables from the image. */
+ struct {
+ short source;
+ bool use_float;
+ char gen_type;
+ } image_state;
+
+} UndoImageBuf;
+
+static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf)
+{
+ UndoImageBuf *ubuf = MEM_callocN(sizeof(*ubuf), __func__);
+
+ ubuf->image_dims[0] = ibuf->x;
+ ubuf->image_dims[1] = ibuf->y;
+
+ ubuf->tiles_dims[0] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[0]);
+ ubuf->tiles_dims[1] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[1]);
+
+ ubuf->tiles_len = ubuf->tiles_dims[0] * ubuf->tiles_dims[1];
+ ubuf->tiles = MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__);
+
+ BLI_strncpy(ubuf->ibuf_name, ibuf->name, sizeof(ubuf->ibuf_name));
+ ubuf->image_state.gen_type = image->gen_type;
+ ubuf->image_state.source = image->source;
+ ubuf->image_state.use_float = ibuf->rect_float != NULL;
+
+ return ubuf;
+}
+
+static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ const bool has_float = ibuf->rect_float;
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+
+ BLI_assert(ubuf->tiles[i] == NULL);
+ UndoImageTile *utile = utile_alloc(has_float);
+ utile->users = 1;
+ utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
+ ubuf->tiles[i] = utile;
+
+ i += 1;
+ }
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+/** Ensure we can copy the ubuf into the ibuf. */
+static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf)
+{
+ /* We could have both float and rect buffers,
+ * in this case free the float buffer if it's unused. */
+ if ((ibuf->rect_float != NULL) && (ubuf->image_state.use_float == false)) {
+ imb_freerectfloatImBuf(ibuf);
+ }
+
+ if (ibuf->x == ubuf->image_dims[0] && ibuf->y == ubuf->image_dims[1] &&
+ (ubuf->image_state.use_float ? (void *)ibuf->rect_float : (void *)ibuf->rect)) {
+ return;
+ }
+
+ imb_freerectImbuf_all(ibuf);
+ IMB_rect_size_set(ibuf, ubuf->image_dims);
+
+ if (ubuf->image_state.use_float) {
+ imb_addrectfloatImBuf(ibuf);
+ }
+ else {
+ imb_addrectImBuf(ibuf);
+ }
+}
+
+static void ubuf_free(UndoImageBuf *ubuf)
+{
+ UndoImageBuf *ubuf_post = ubuf->post;
+ for (uint i = 0; i < ubuf->tiles_len; i++) {
+ UndoImageTile *utile = ubuf->tiles[i];
+ utile_decref(utile);
+ }
+ MEM_freeN(ubuf->tiles);
+ MEM_freeN(ubuf);
+ if (ubuf_post) {
+ ubuf_free(ubuf_post);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Handle
+ * \{ */
+
+typedef struct UndoImageHandle {
+ struct UndoImageHandle *next, *prev;
+
+ /** Each undo handle refers to a single image which may have multiple buffers. */
+ UndoRefID_Image image_ref;
+
+ /**
+ * List of #UndoImageBuf's to support multiple buffers per image.
+ *
+ * \note To properly support multiple buffers per image
+ * we would need to store an #ImageUser for each #UndoImageBuf.
+ * since when restoring the image we use:
+ * `BKE_image_acquire_ibuf(image, NULL, NULL)`.
+ */
+ ListBase buffers;
+
+} UndoImageHandle;
+
+static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ /* Tiles only added to second set of tiles. */
+ Image *image = uh->image_ref.ptr;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ if (UNLIKELY(ibuf == NULL)) {
+ CLOG_ERROR(&LOG, "Unable to get buffer for image '%s'", image->id.name + 2);
+ continue;
+ }
+ bool changed = false;
+ for (UndoImageBuf *ubuf_iter = uh->buffers.first; ubuf_iter; ubuf_iter = ubuf_iter->next) {
+ UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post;
+ ubuf_ensure_compat_ibuf(ubuf, ibuf);
+
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+ utile_restore(ubuf->tiles[i], x, y, ibuf, tmpibuf);
+ changed = true;
+ i += 1;
+ }
+ }
+ }
+
+ if (changed) {
+ BKE_image_mark_dirty(image, ibuf);
+ GPU_free_image(image); /* force OpenGL reload */
+
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ DEG_id_tag_update(&image->id, 0);
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+static void uhandle_free_list(ListBase *undo_handles)
+{
+ LISTBASE_FOREACH_MUTABLE (UndoImageHandle *, uh, undo_handles) {
+ LISTBASE_FOREACH_MUTABLE (UndoImageBuf *, ubuf, &uh->buffers) {
+ ubuf_free(ubuf);
+ }
+ MEM_freeN(uh);
+ }
+ BLI_listbase_clear(undo_handles);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Internal Utilities
+ * \{ */
+
+/** #UndoImageHandle utilities */
+
+static UndoImageBuf *uhandle_lookup_ubuf(UndoImageHandle *uh,
+ const Image *UNUSED(image),
+ const char *ibuf_name)
+{
+ for (UndoImageBuf *ubuf = uh->buffers.first; ubuf; ubuf = ubuf->next) {
+ if (STREQ(ubuf->ibuf_name, ibuf_name)) {
+ return ubuf;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageBuf *uhandle_add_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
+{
+ BLI_assert(uhandle_lookup_ubuf(uh, image, ibuf->name) == NULL);
+ UndoImageBuf *ubuf = ubuf_from_image_no_tiles(image, ibuf);
+ BLI_addtail(&uh->buffers, ubuf);
+
+ ubuf->post = NULL;
+
+ return ubuf;
+}
+
+static UndoImageBuf *uhandle_ensure_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
+{
+ UndoImageBuf *ubuf = uhandle_lookup_ubuf(uh, image, ibuf->name);
+ if (ubuf == NULL) {
+ ubuf = uhandle_add_ubuf(uh, image, ibuf);
+ }
+ return ubuf;
+}
+
+static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles, const Image *image)
+{
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ if (STREQ(image->id.name + 2, uh->image_ref.name + 2)) {
+ return uh;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image)
+{
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ if (image == uh->image_ref.ptr) {
+ return uh;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image)
+{
+ BLI_assert(uhandle_lookup(undo_handles, image) == NULL);
+ UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
+ uh->image_ref.ptr = image;
+ BLI_addtail(undo_handles, uh);
+ return uh;
+}
+
+static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image)
+{
+ UndoImageHandle *uh = uhandle_lookup(undo_handles, image);
+ if (uh == NULL) {
+ uh = uhandle_add(undo_handles, image);
+ }
+ return uh;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct ImageUndoStep {
+ UndoStep step;
+
+ /** #UndoImageHandle */
+ ListBase handles;
+
+ /**
+ * #PaintTile
+ * Run-time only data (active during a paint stroke).
+ */
+ ListBase paint_tiles;
+
+ bool is_encode_init;
+ ePaintMode paint_mode;
+
+} ImageUndoStep;
+
+/**
+ * Find the previous undo buffer from this one.
+ * \note We could look into undo steps even further back.
+ */
+static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev,
+ const Image *image,
+ const UndoImageBuf *ubuf)
+{
+ /* Use name lookup because because the pointer is cleared for previous steps. */
+ UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image);
+ if (uh_prev != NULL) {
+ UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
+ if (ubuf_reference) {
+ ubuf_reference = ubuf_reference->post;
+ if ((ubuf_reference->image_dims[0] == ubuf->image_dims[0]) &&
+ (ubuf_reference->image_dims[1] == ubuf->image_dims[1])) {
+ return ubuf_reference;
+ }
+ }
+ }
+ return NULL;
+}
+
+static bool image_undosys_poll(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && (sa->spacetype == SPACE_IMAGE)) {
+ SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
+ return true;
+ }
+ }
+ else {
+ if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ us->is_encode_init = true;
+ BLI_listbase_clear(&us->handles);
+ BLI_listbase_clear(&us->paint_tiles);
+}
+
+static bool image_undosys_step_encode(struct bContext *C,
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p)
+{
+ /* Encoding is done along the way by adding tiles
+ * to the current 'ImageUndoStep' added by encode_init.
+ *
+ * This function ensures there are previous and current states of the image in the undo buffer.
+ */
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+
+ BLI_assert(us->step.data_size == 0);
+
+ if (us->is_encode_init) {
+
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
+ us_reference = (ImageUndoStep *)us_reference->step.prev;
+ }
+
+ /* Initialize undo tiles from ptiles (if they exist). */
+ for (PaintTile *ptile = us->paint_tiles.first, *ptile_next; ptile; ptile = ptile_next) {
+ if (ptile->valid) {
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image);
+ UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf);
+
+ UndoImageTile *utile = MEM_callocN(sizeof(*utile), "UndoImageTile");
+ utile->users = 1;
+ utile->rect.pt = ptile->rect.pt;
+ ptile->rect.pt = NULL;
+ const uint tile_index = index_from_xy(ptile->x, ptile->y, ubuf_pre->tiles_dims);
+
+ BLI_assert(ubuf_pre->tiles[tile_index] == NULL);
+ ubuf_pre->tiles[tile_index] = utile;
+ }
+ ptile_next = ptile->next;
+ ptile_free(ptile);
+ }
+ BLI_listbase_clear(&us->paint_tiles);
+
+ for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
+ for (UndoImageBuf *ubuf_pre = uh->buffers.first; ubuf_pre; ubuf_pre = ubuf_pre->next) {
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, NULL, NULL);
+
+ const bool has_float = ibuf->rect_float;
+
+ BLI_assert(ubuf_pre->post == NULL);
+ ubuf_pre->post = ubuf_from_image_no_tiles(uh->image_ref.ptr, ibuf);
+ UndoImageBuf *ubuf_post = ubuf_pre->post;
+
+ if (ubuf_pre->image_dims[0] != ubuf_post->image_dims[0] ||
+ ubuf_pre->image_dims[1] != ubuf_post->image_dims[1]) {
+ ubuf_from_image_all_tiles(ubuf_post, ibuf);
+ }
+ else {
+ /* Search for the previous buffer. */
+ UndoImageBuf *ubuf_reference = (us_reference ?
+ ubuf_lookup_from_reference(
+ us_reference, uh->image_ref.ptr, ubuf_post) :
+ NULL);
+
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf_pre->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf_pre->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+
+ if ((ubuf_reference != NULL) && ((ubuf_pre->tiles[i] == NULL) ||
+ /* In this case the paint stroke as has added a tile
+ * which we have a duplicate reference available. */
+ (ubuf_pre->tiles[i]->users == 1))) {
+ if (ubuf_pre->tiles[i] != NULL) {
+ /* If we have a reference, re-use this single use tile for the post state. */
+ BLI_assert(ubuf_pre->tiles[i]->users == 1);
+ ubuf_post->tiles[i] = ubuf_pre->tiles[i];
+ ubuf_pre->tiles[i] = NULL;
+ utile_init_from_imbuf(ubuf_post->tiles[i], x, y, ibuf, tmpibuf);
+ }
+ else {
+ BLI_assert(ubuf_post->tiles[i] == NULL);
+ ubuf_post->tiles[i] = ubuf_reference->tiles[i];
+ ubuf_post->tiles[i]->users += 1;
+ }
+ BLI_assert(ubuf_pre->tiles[i] == NULL);
+ ubuf_pre->tiles[i] = ubuf_reference->tiles[i];
+ ubuf_pre->tiles[i]->users += 1;
+
+ BLI_assert(ubuf_pre->tiles[i] != NULL);
+ BLI_assert(ubuf_post->tiles[i] != NULL);
+ }
+ else {
+ UndoImageTile *utile = utile_alloc(has_float);
+ utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
+
+ if (ubuf_pre->tiles[i] != NULL) {
+ ubuf_post->tiles[i] = utile;
+ utile->users = 1;
+ }
+ else {
+ ubuf_pre->tiles[i] = utile;
+ ubuf_post->tiles[i] = utile;
+ utile->users = 2;
+ }
+ }
+ BLI_assert(ubuf_pre->tiles[i] != NULL);
+ BLI_assert(ubuf_post->tiles[i] != NULL);
+ i += 1;
+ }
+ }
+ }
+ BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, NULL);
+ }
+ }
+
+ IMB_freeImBuf(tmpibuf);
+
+ /* Useful to debug tiles are stored correctly. */
+ if (false) {
+ uhandle_restore_list(&us->handles, false);
+ }
+ }
+ else {
+ /* Happens when switching modes. */
+ ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
+ }
+
+ us_p->is_applied = true;
+
+ return true;
+}
+
+static void image_undosys_step_decode_undo_impl(ImageUndoStep *us, bool is_final)
+{
+ BLI_assert(us->step.is_applied == true);
+ uhandle_restore_list(&us->handles, !is_final);
+ us->step.is_applied = false;
+}
+
+static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
+{
+ BLI_assert(us->step.is_applied == false);
+ uhandle_restore_list(&us->handles, false);
+ us->step.is_applied = true;
+}
+
+static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
+{
+ ImageUndoStep *us_iter = us;
+ while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
+ if (us_iter->step.next->is_applied == false) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
+ while (us_iter != us || (!is_final && us_iter == us)) {
+
+ image_undosys_step_decode_undo_impl(us_iter, is_final);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
+}
+
+static void image_undosys_step_decode_redo(ImageUndoStep *us)
+{
+ ImageUndoStep *us_iter = us;
+ while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
+ if (us_iter->step.prev->is_applied == true) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
+ while (us_iter && (us_iter->step.is_applied == false)) {
+ image_undosys_step_decode_redo_impl(us_iter);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
+}
+
+static void image_undosys_step_decode(
+ struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ if (dir < 0) {
+ image_undosys_step_decode_undo(us, is_final);
+ }
+ else {
+ image_undosys_step_decode_redo(us);
+ }
+
+ if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
+ ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
+ }
+
+ /* Refresh texture slots. */
+ ED_editors_init_for_undo(bmain);
+}
+
+static void image_undosys_step_free(UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ uhandle_free_list(&us->handles);
+
+ /* Typically this list will have been cleared. */
+ ptile_free_list(&us->paint_tiles);
+}
+
+static void image_undosys_foreach_ID_ref(UndoStep *us_p,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn,
+ void *user_data)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref));
+ }
+}
+
+/* Export for ED_undo_sys. */
+void ED_image_undosys_type(UndoType *ut)
+{
+ ut->name = "Image";
+ ut->poll = image_undosys_poll;
+ ut->step_encode_init = image_undosys_step_encode_init;
+ ut->step_encode = image_undosys_step_encode;
+ ut->step_decode = image_undosys_step_decode;
+ ut->step_free = image_undosys_step_free;
+
+ ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
+
+ ut->use_context = true;
+
+ ut->step_size = sizeof(ImageUndoStep);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+ListBase *ED_image_paint_tile_list_get(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us_prev = ustack->step_init;
+ UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* We should always have an undo push started when accessing tiles,
+ * not doing this means we won't have paint_mode correctly set. */
+ BLI_assert(us_p == us_prev);
+ if (us_p != us_prev) {
+ /* Fallback value until we can be sure this never happens. */
+ us->paint_mode = PAINT_MODE_TEXTURE_2D;
+ }
+ return &us->paint_tiles;
+}
+
+/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
+void ED_image_undo_restore(UndoStep *us)
+{
+ ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles;
+ ptile_restore_runtime_list(paint_tiles);
+ ptile_invalidate_list(paint_tiles);
+}
+
+static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
+ return us;
+}
+
+void ED_image_undo_push_begin(const char *name, int paint_mode)
+{
+ image_undo_push_begin(name, paint_mode);
+}
+
+void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf)
+{
+ ImageUndoStep *us = image_undo_push_begin(name, PAINT_MODE_TEXTURE_2D);
+
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, image);
+ UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf);
+ BLI_assert(ubuf_pre->post == NULL);
+
+ ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
+ us_reference = (ImageUndoStep *)us_reference->step.prev;
+ }
+ UndoImageBuf *ubuf_reference = (us_reference ?
+ ubuf_lookup_from_reference(us_reference, image, ubuf_pre) :
+ NULL);
+
+ if (ubuf_reference) {
+ memcpy(ubuf_pre->tiles, ubuf_reference->tiles, sizeof(*ubuf_pre->tiles) * ubuf_pre->tiles_len);
+ for (uint i = 0; i < ubuf_pre->tiles_len; i++) {
+ UndoImageTile *utile = ubuf_pre->tiles[i];
+ utile->users += 1;
+ }
+ }
+ else {
+ ubuf_from_image_all_tiles(ubuf_pre, ibuf);
+ }
+}
+
+void ED_image_undo_push_end(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
+ WM_file_tag_modified();
+}
+
+/** \} */
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 5fa4fe3e077..a88ecc91868 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -207,6 +207,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_view_all);
WM_operatortype_append(IMAGE_OT_view_pan);
WM_operatortype_append(IMAGE_OT_view_selected);
+ WM_operatortype_append(IMAGE_OT_view_center_cursor);
WM_operatortype_append(IMAGE_OT_view_zoom);
WM_operatortype_append(IMAGE_OT_view_zoom_in);
WM_operatortype_append(IMAGE_OT_view_zoom_out);
@@ -229,6 +230,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_unpack);
WM_operatortype_append(IMAGE_OT_invert);
+ WM_operatortype_append(IMAGE_OT_resize);
WM_operatortype_append(IMAGE_OT_cycle_render_slot);
WM_operatortype_append(IMAGE_OT_clear_render_slot);
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index 1abf1a64263..938e7f09881 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -597,13 +597,19 @@ void NLA_OT_select_leftright(wmOperatorType *ot)
/* ******************** Mouse-Click Select Operator *********************** */
/* select strip directly under mouse */
-static void mouse_nla_strips(
- bContext *C, bAnimContext *ac, const int mval[2], short select_mode, const bool deselect_all)
+static int mouse_nla_strips(bContext *C,
+ bAnimContext *ac,
+ const int mval[2],
+ short select_mode,
+ const bool deselect_all,
+ bool wait_to_deselect_others)
{
Scene *scene = ac->scene;
bAnimListElem *ale = NULL;
NlaStrip *strip = NULL;
+ int ret_value = OPERATOR_FINISHED;
+
nlaedit_strip_at_region_position(ac, mval[0], mval[1], &ale, &strip);
/* if currently in tweakmode, exit tweakmode before changing selection states
@@ -613,6 +619,10 @@ static void mouse_nla_strips(
WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL);
}
+ if (select_mode != SELECT_REPLACE) {
+ wait_to_deselect_others = false;
+ }
+
/* For replacing selection, if we have something to select, we have to clear existing selection.
* The same goes if we found nothing to select, and deselect_all is true
* (deselect on nothing behavior). */
@@ -620,11 +630,16 @@ static void mouse_nla_strips(
/* reset selection mode for next steps */
select_mode = SELECT_ADD;
- /* deselect all strips */
- deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
+ if (strip && wait_to_deselect_others && (strip->flag & DESELECT_STRIPS_CLEARACTIVE)) {
+ ret_value = OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ /* deselect all strips */
+ deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
- /* deselect all other channels first */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ /* deselect all other channels first */
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ }
}
/* only select strip if we clicked on a valid channel and hit something */
@@ -658,14 +673,17 @@ static void mouse_nla_strips(
/* free this channel */
MEM_freeN(ale);
}
+
+ return ret_value;
}
/* ------------------- */
/* handle clicking */
-static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int nlaedit_clickselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+ int ret_value;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
@@ -675,15 +693,19 @@ static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent
/* select mode is either replace (deselect all, then add) or add/extend */
const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE;
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
+ int mval[2];
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
/* select strips based upon mouse position */
- mouse_nla_strips(C, &ac, event->mval, selectmode, deselect_all);
+ ret_value = mouse_nla_strips(C, &ac, mval, selectmode, deselect_all, wait_to_deselect_others);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_SELECTED, NULL);
/* for tweak grab to work */
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ return ret_value | OPERATOR_PASS_THROUGH;
}
void NLA_OT_click_select(wmOperatorType *ot)
@@ -695,14 +717,17 @@ void NLA_OT_click_select(wmOperatorType *ot)
ot->idname = "NLA_OT_click_select";
ot->description = "Handle clicks to select NLA Strips";
- /* api callbacks - absolutely no exec() this yet... */
- ot->invoke = nlaedit_clickselect_invoke;
+ /* callbacks */
ot->poll = ED_operator_nla_active;
+ ot->exec = nlaedit_clickselect_exec;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
+ WM_operator_properties_generic_select(ot);
prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 93121a6bef9..a5b18ff7589 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -47,6 +47,7 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
+#include "GPU_platform.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -815,51 +816,8 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- PointerRNA imaptr = RNA_pointer_get(ptr, "image");
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
- Image *ima = imaptr.data;
-
- uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateID(layout,
- C,
- ptr,
- "image",
- "IMAGE_OT_new",
- "IMAGE_OT_open",
- NULL,
- UI_TEMPLATE_ID_FILTER_ALL,
- false);
-
- if (!ima) {
- return;
- }
-
- uiItemR(layout, &imaptr, "source", 0, IFACE_("Source"), ICON_NONE);
-
- if (!(ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER))) {
- uiLayout *row = uiLayoutRow(layout, true);
- const bool is_packed = BKE_image_has_packedfile(ima);
-
- if (is_packed) {
- uiItemO(row, "", ICON_PACKAGE, "image.unpack");
- }
- else {
- uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
- }
-
- row = uiLayoutRow(row, true);
- uiLayoutSetEnabled(row, !is_packed);
- uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
- uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
- }
-
- /* multilayer? */
- if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) {
- uiTemplateImageLayers(layout, C, ima, iuserptr.data);
- }
- else if (ima->source != IMA_SRC_GENERATED) {
- uiTemplateImageInfo(layout, C, ima, iuserptr.data);
- }
+ uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0);
uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE);
uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE);
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 01a30f677a3..664349b3c3b 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -309,7 +309,7 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_CROSSCURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_CROSS, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
/* ****************** Add File Node Operator ******************* */
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 770e6dd2a9e..2081c69a1a4 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -1456,16 +1456,16 @@ static void node_draw_hidden(const bContext *C,
int node_get_resize_cursor(int directions)
{
if (directions == 0) {
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
else if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0) {
- return CURSOR_Y_MOVE;
+ return WM_CURSOR_Y_MOVE;
}
else if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0) {
- return CURSOR_X_MOVE;
+ return WM_CURSOR_X_MOVE;
}
else {
- return CURSOR_EDIT;
+ return WM_CURSOR_EDIT;
}
}
@@ -1474,7 +1474,7 @@ void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2])
bNodeTree *ntree = snode->edittree;
bNode *node;
bNodeSocket *sock;
- int wmcursor = CURSOR_STD;
+ int wmcursor = WM_CURSOR_DEFAULT;
if (ntree) {
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) {
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 588fc4d4307..5d020ff5ab4 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -241,6 +241,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
node->flag |= NODE_SELECT;
}
+ bNodeLink *glinks_first = ntree->links.last;
+
/* Add internal links to the ntree */
for (link = wgroup->links.first; link; link = linkn) {
linkn = link->next;
@@ -248,6 +250,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
BLI_addtail(&ntree->links, link);
}
+ bNodeLink *glinks_last = ntree->links.last;
+
/* and copy across the animation,
* note that the animation data's action can be NULL here */
if (wgroup->adt) {
@@ -280,70 +284,64 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
BKE_id_free(bmain, wgroup);
/* restore external links to and from the gnode */
- /* note: the nodes have been copied to intermediate wgroup first (so need to use new_node),
- * then transferred to ntree (new_node pointers remain valid).
- */
/* input links */
- for (link = ngroup->links.first; link; link = link->next) {
- if (link->fromnode->type == NODE_GROUP_INPUT) {
- const char *identifier = link->fromsock->identifier;
- int num_external_links = 0;
-
- /* find external links to this input */
- for (tlink = ntree->links.first; tlink; tlink = tlink->next) {
- if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
- nodeAddLink(ntree,
- tlink->fromnode,
- tlink->fromsock,
- link->tonode->new_node,
- link->tosock->new_sock);
- num_external_links++;
+ if (glinks_first != NULL) {
+ for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ if (link->fromnode->type == NODE_GROUP_INPUT) {
+ const char *identifier = link->fromsock->identifier;
+ int num_external_links = 0;
+
+ /* find external links to this input */
+ for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
+ num_external_links++;
+ }
}
- }
- /* if group output is not externally linked,
- * convert the constant input value to ensure somewhat consistent behavior */
- if (num_external_links == 0) {
- /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier);
- BLI_assert(sock);*/
+ /* if group output is not externally linked,
+ * convert the constant input value to ensure somewhat consistent behavior */
+ if (num_external_links == 0) {
+ /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier);
+ BLI_assert(sock);*/
- /* XXX TODO
- * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node,
- * ntree, sock, gnode);*/
+ /* XXX TODO
+ * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node,
+ * ntree, sock, gnode);*/
+ }
}
}
- }
- /* output links */
- for (link = ntree->links.first; link; link = link->next) {
- if (link->fromnode == gnode) {
- const char *identifier = link->fromsock->identifier;
- int num_internal_links = 0;
-
- /* find internal links to this output */
- for (tlink = ngroup->links.first; tlink; tlink = tlink->next) {
- /* only use active output node */
- if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) {
- if (STREQ(tlink->tosock->identifier, identifier)) {
- nodeAddLink(ntree,
- tlink->fromnode->new_node,
- tlink->fromsock->new_sock,
- link->tonode,
- link->tosock);
- num_internal_links++;
+ /* Also iterate over new links to cover passthrough links. */
+ glinks_last = ntree->links.last;
+
+ /* output links */
+ for (link = ntree->links.first; link != glinks_first->next; link = link->next) {
+ if (link->fromnode == gnode) {
+ const char *identifier = link->fromsock->identifier;
+ int num_internal_links = 0;
+
+ /* find internal links to this output */
+ for (tlink = glinks_first->next; tlink != glinks_last->next; tlink = tlink->next) {
+ /* only use active output node */
+ if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) {
+ if (STREQ(tlink->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
+ num_internal_links++;
+ }
}
}
- }
- /* if group output is not internally linked,
- * convert the constant output value to ensure somewhat consistent behavior */
- if (num_internal_links == 0) {
- /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier);
- BLI_assert(sock);*/
+ /* if group output is not internally linked,
+ * convert the constant output value to ensure somewhat consistent behavior */
+ if (num_internal_links == 0) {
+ /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier);
+ BLI_assert(sock);*/
- /* XXX TODO
- * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */
+ /* XXX TODO
+ * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */
+ }
}
}
}
@@ -717,7 +715,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ListBase anim_basepaths = {NULL, NULL};
float min[2], max[2], center[2];
int totselect;
- bool expose_all = false;
+ bool expose_visible = false;
bNode *input_node, *output_node;
/* XXX rough guess, not nice but we don't have access to UI constants here ... */
@@ -735,7 +733,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
/* auto-add interface for "solo" nodes */
if (totselect == 1) {
- expose_all = true;
+ expose_visible = true;
}
/* move nodes over */
@@ -879,8 +877,8 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
}
- /* expose all unlinked sockets too */
- if (expose_all) {
+ /* expose all unlinked sockets too but only the visible ones*/
+ if (expose_visible) {
for (node = ngroup->nodes.first; node; node = node->next) {
if (node_group_make_use_node(node, gnode)) {
for (sock = node->inputs.first; sock; sock = sock->next) {
@@ -892,6 +890,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
break;
}
}
+ if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
+ skip = true;
+ }
if (skip) {
continue;
}
@@ -913,6 +914,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
skip = true;
}
}
+ if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
+ skip = true;
+ }
if (skip) {
continue;
}
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index eef3f85319c..357ef31c51f 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -1103,7 +1103,7 @@ void NODE_OT_links_cut(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_KNIFE, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
/* ********************** Detach links operator ***************** */
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 450cf28cce1..e22ef389516 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -430,11 +430,9 @@ void node_select_single(bContext *C, bNode *node)
}
static int node_mouse_select(bContext *C,
+ wmOperator *op,
const int mval[2],
- const bool extend,
- const bool socket_select,
- const bool deselect_all,
- const bool wait_to_deselect_others)
+ bool wait_to_deselect_others)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
@@ -445,8 +443,15 @@ static int node_mouse_select(bContext *C,
float cursor[2];
int ret_value = OPERATOR_CANCELLED;
- /* Waiting to deselect others is only allowed for basic selection. */
- BLI_assert(!(extend || socket_select) || !wait_to_deselect_others);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ /* always do socket_select when extending selection. */
+ const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+
+ /* These cases are never modal. */
+ if (extend || socket_select) {
+ wait_to_deselect_others = false;
+ }
/* get mouse coordinates in view2d space */
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
@@ -552,115 +557,40 @@ static int node_mouse_select(bContext *C,
static int node_select_exec(bContext *C, wmOperator *op)
{
- int mval[2];
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
/* get settings from RNA properties for operator */
+ int mval[2];
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
/* perform the select */
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false);
+ const int ret_value = node_mouse_select(C, op, mval, wait_to_deselect_others);
/* allow tweak event to work too */
return ret_value | OPERATOR_PASS_THROUGH;
}
-static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- const short init_event_type = (short)POINTER_AS_INT(op->customdata);
-
- /* get settings from RNA properties for operator */
- int mval[2];
- mval[0] = RNA_int_get(op->ptr, "mouse_x");
- mval[1] = RNA_int_get(op->ptr, "mouse_y");
-
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
- /* These cases are never modal. */
- if (extend || socket_select) {
- return node_select_exec(C, op);
- }
-
- if (init_event_type == 0) {
- if (event->val == KM_PRESS) {
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, true);
-
- op->customdata = POINTER_FROM_INT((int)event->type);
- if (ret_value & OPERATOR_RUNNING_MODAL) {
- WM_event_add_modal_handler(C, op);
- }
- return ret_value | OPERATOR_PASS_THROUGH;
- }
- else {
- /* If we are in init phase, and cannot validate init of modal operations,
- * just fall back to basic exec.
- */
- return node_select_exec(C, op);
- }
- }
- else if (event->type == init_event_type && event->val == KM_RELEASE) {
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false);
- return ret_value | OPERATOR_PASS_THROUGH;
- }
- else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- const int drag_delta[2] = {
- mval[0] - event->mval[0],
- mval[1] - event->mval[1],
- };
- /* If user moves mouse more than defined threshold, we consider select operator as
- * finished. Otherwise, it is still running until we get an 'release' event. In any
- * case, we pass through event, but select op is not finished yet. */
- if (WM_event_drag_test_with_delta(event, drag_delta)) {
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
- }
- else {
- /* Important not to return anything other than PASS_THROUGH here,
- * otherwise it prevents underlying tweak detection code to work properly. */
- return OPERATOR_PASS_THROUGH;
- }
- }
-
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
-}
-
-static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
- RNA_int_set(op->ptr, "mouse_y", event->mval[1]);
-
- op->customdata = POINTER_FROM_INT(0);
-
- return node_select_modal(C, op, event);
-}
-
void NODE_OT_select(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Select";
ot->idname = "NODE_OT_select";
ot->description = "Select the node under the cursor";
/* api callbacks */
- ot->invoke = node_select_invoke;
ot->exec = node_select_exec;
- ot->modal = node_select_modal;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
ot->poll = ED_operator_node_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- PropertyRNA *prop;
- RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX);
+ WM_operator_properties_generic_select(ot);
RNA_def_boolean(ot->srna, "extend", false, "Extend", "");
RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", "");
prop = RNA_def_boolean(ot->srna,
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index 309446db83b..03606282fcd 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -965,7 +965,7 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
if (extend) {
- BKE_layer_collection_isolate(scene, view_layer, layer_collection, true);
+ BKE_layer_collection_isolate_global(scene, view_layer, layer_collection, true);
}
else {
PointerRNA ptr;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index a2ca3254b30..3b86e04308e 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -2419,7 +2419,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case OB_GPENCIL:
data.icon = ICON_OUTLINER_OB_GREASEPENCIL;
break;
- break;
}
}
else {
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 943993cb810..c55140db46f 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -674,7 +674,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Outliner ID data Remap";
+ ot->name = "Outliner ID Data Remap";
ot->idname = "OUTLINER_OT_id_remap";
/* callbacks */
@@ -770,7 +770,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op)
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_save(bmain, str, op->reports);
- BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-blocks", num_ids);
+ BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids);
return OPERATOR_FINISHED;
}
@@ -804,7 +804,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
- BKE_reportf(op->reports, RPT_INFO, "%d data-blocks pasted", num_pasted);
+ BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
return OPERATOR_FINISHED;
}
@@ -2257,7 +2257,7 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
BKE_id_multi_tagged_delete(bmain);
- BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-blocks", num_tagged[INDEX_ID_NULL]);
+ BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-block(s)", num_tagged[INDEX_ID_NULL]);
/* XXX: tree management normally happens from draw_outliner(), but when
* you're clicking to fast on Delete object from context menu in
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 44e67fa1508..f1e884adc3d 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -263,7 +263,8 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer,
for (base = FIRSTBASE(view_layer); base; base = base->next) {
Object *ob = base->object;
- if ((((base->flag & BASE_VISIBLE) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) {
+ if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) &&
+ BKE_object_is_child_recursive(ob_parent, ob))) {
ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
}
}
@@ -1198,7 +1199,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
if ((ob != NULL) && (ob->data == tselem->id)) {
Base *base = BKE_view_layer_base_find(view_layer, ob);
- if ((base != NULL) && (base->flag & BASE_VISIBLE)) {
+ if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
do_outliner_activate_obdata(C, scene, view_layer, base, extend);
}
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index fd6a052b84d..7f7cfff12ef 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1365,7 +1365,7 @@ static void outliner_add_layer_collection_objects(
TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0);
te_object->directdata = base;
- if (!(base->flag & BASE_VISIBLE)) {
+ if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) {
te_object->flag |= TE_DISABLED;
}
}
@@ -1398,7 +1398,7 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops,
tselem->flag &= ~TSE_CLOSED;
}
- if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) {
+ if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER) == 0) {
ten->flag |= TE_DISABLED;
}
}
@@ -2085,12 +2085,12 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
}
if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) {
- if ((base->flag & BASE_VISIBLE) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
return false;
}
}
else if (exclude_filter & SO_FILTER_OB_STATE_HIDDEN) {
- if ((base->flag & BASE_VISIBLE) != 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) {
return false;
}
}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 79880c68120..68eea4f278b 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -229,6 +229,11 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
ED_region_tag_redraw(ar);
}
break;
+ case NC_TEXT:
+ if (ELEM(wmn->action, NA_ADDED, NA_REMOVED)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index 48248fe1dd2..2be05785d2b 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -106,6 +106,7 @@ static bool script_test_modal_operators(bContext *C)
static int script_reload_exec(bContext *C, wmOperator *op)
{
+
#ifdef WITH_PYTHON
/* clear running operators */
@@ -114,6 +115,8 @@ static int script_reload_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ WM_script_tag_reload();
+
/* TODO, this crashes on netrender and keying sets, need to look into why
* disable for now unless running in debug mode */
WM_cursor_wait(1);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index b24f8e8d00f..8a15c05dd4a 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -336,7 +336,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
seq->scene = sce_seq;
@@ -420,7 +420,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = clip;
id_us_ensure_real(&seq->clip->id);
@@ -504,7 +504,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = mask;
id_us_ensure_real(&seq->mask->id);
@@ -1091,8 +1091,14 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
if (seq->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
RNA_float_get_array(op->ptr, "color", colvars->col);
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
+ }
+ else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
+ seq->blend_mode = SEQ_TYPE_CROSS;
+ }
+ else if (seq->type == SEQ_TYPE_TEXT) {
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
}
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
/* an unset channel is a special case where we automatically go above
* the other strips. */
@@ -1169,7 +1175,7 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
- SEQ_TYPE_ALPHAOVER,
+ SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
RNA_def_float_vector(ot->srna,
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index 6740c2baad2..7bec913900d 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -117,5 +117,6 @@ void sequencer_buttons_register(ARegionType *art)
pt->poll = metadata_panel_context_poll;
pt->draw = metadata_panel_context_draw;
pt->flag |= PNL_DEFAULT_CLOSED;
+ pt->order = 10;
BLI_addtail(&art->paneltypes, pt);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index bf555e8fe09..1a788237e6e 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -334,7 +334,7 @@ static void drawseqwave(View2D *v2d,
value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4];
}
- if (fcu) {
+ if (fcu && !BKE_fcurve_is_empty(fcu)) {
float evaltime = x1_offset + (i * stepsize);
volume = evaluate_fcurve(fcu, evaltime);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 22b73c32bfe..865dfb45278 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1600,6 +1600,7 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
if (success) {
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
return OPERATOR_FINISHED;
}
else {
@@ -1693,6 +1694,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
if (sa) {
ED_area_status_text(sa, NULL);
}
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
@@ -3894,7 +3896,7 @@ void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
- SEQ_TYPE_ALPHAOVER,
+ SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
}
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index affb6d3fd88..4c20fc1707a 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -319,7 +319,7 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int sequencer_select_exec(bContext *C, wmOperator *op)
{
View2D *v2d = UI_view2d_fromcontext(C);
Scene *scene = CTX_data_scene(C);
@@ -328,7 +328,13 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
+ bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
int left_right = RNA_enum_get(op->ptr, "left_right");
+ int mval[2];
+ int ret_value = OPERATOR_CANCELLED;
+
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
Sequence *seq, *neighbor, *act_orig;
int hand, sel_side;
@@ -338,9 +344,13 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
return OPERATOR_CANCELLED;
}
+ if (extend) {
+ wait_to_deselect_others = false;
+ }
+
marker = find_nearest_marker(SCE_MARKERS, 1); // XXX - dummy function for now
- seq = find_nearest_seq(scene, v2d, &hand, event->mval);
+ seq = find_nearest_seq(scene, v2d, &hand, mval);
// XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE)) {
@@ -364,6 +374,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* deselect_markers(0, 0); */
marker->flag |= SELECT;
}
+
+ ret_value = OPERATOR_FINISHED;
}
else if (left_right != SEQ_SELECT_LR_NONE) {
/* use different logic for this */
@@ -374,7 +386,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
switch (left_right) {
case SEQ_SELECT_LR_MOUSE:
- x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
+ x = UI_view2d_region_to_view_x(v2d, mval[0]);
break;
case SEQ_SELECT_LR_LEFT:
x = CFRA - 1.0f;
@@ -409,13 +421,27 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
}
}
+
+ ret_value = OPERATOR_FINISHED;
}
else {
act_orig = ed->act_seq;
if (seq) {
- if (!extend && !linked_handle) {
+ /* Are we trying to select a handle that's already selected? */
+ const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) ||
+ ((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL));
+
+ if (wait_to_deselect_others && (seq->flag & SELECT) &&
+ (hand == SEQ_SIDE_NONE || handle_selected)) {
+ ret_value = OPERATOR_RUNNING_MODAL;
+ }
+ else if (!extend && !linked_handle) {
ED_sequencer_deselect_all(scene);
+ ret_value = OPERATOR_FINISHED;
+ }
+ else {
+ ret_value = OPERATOR_FINISHED;
}
BKE_sequencer_active_set(scene, seq);
@@ -509,6 +535,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
}
}
+
+ ret_value = OPERATOR_FINISHED;
}
else {
if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
@@ -525,6 +553,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
seq->flag ^= SEQ_RIGHTSEL;
break;
}
+ ret_value = OPERATOR_FINISHED;
}
else {
seq->flag |= SELECT;
@@ -542,9 +571,12 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
if (linked_time) {
select_linked_time(ed->seqbasep, seq);
}
+
+ BLI_assert((ret_value & OPERATOR_CANCELLED) == 0);
}
else if (deselect_all) {
ED_sequencer_deselect_all(scene);
+ ret_value = OPERATOR_FINISHED;
}
}
@@ -552,8 +584,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
- /* allowing tweaks */
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ return ret_value;
}
void SEQUENCER_OT_select(wmOperatorType *ot)
@@ -565,6 +596,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
{SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"},
{0, NULL, 0, NULL, NULL},
};
+ PropertyRNA *prop;
/* identifiers */
ot->name = "Select";
@@ -572,14 +604,16 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
ot->description = "Select a strip (last selected becomes the \"active strip\")";
/* api callbacks */
- ot->invoke = sequencer_select_invoke;
+ ot->exec = sequencer_select_exec;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
ot->poll = ED_operator_sequencer_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- PropertyRNA *prop;
+ WM_operator_properties_generic_select(ot);
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
prop = RNA_def_boolean(ot->srna,
"deselect_all",
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 9f39313b9ab..088f06e9da8 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -311,11 +311,11 @@ static void text_main_region_draw(const bContext *C, ARegion *ar)
static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
SpaceText *st = sa->spacedata.first;
- int wmcursor = BC_TEXTEDITCURSOR;
+ int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text &&
BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
- wmcursor = CURSOR_STD;
+ wmcursor = WM_CURSOR_DEFAULT;
}
WM_cursor_set(win, wmcursor);
diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c
index 347d46a4234..935e288c7be 100644
--- a/source/blender/editors/space_text/text_format_lua.c
+++ b/source/blender/editors/space_text/text_format_lua.c
@@ -48,7 +48,7 @@ static int txtfmt_lua_find_keyword(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "do", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "else", len)) { i = len;
@@ -66,8 +66,7 @@ static int txtfmt_lua_find_keyword(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "then", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "until", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0; }
/* clang-format on */
@@ -96,7 +95,7 @@ static int txtfmt_lua_find_specialvar(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "collectgarbage", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "dofile", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "error", len)) { i = len;
@@ -124,8 +123,7 @@ static int txtfmt_lua_find_specialvar(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "unpack", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "_VERSION", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "xpcall", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0; }
/* clang-format on */
@@ -140,18 +138,13 @@ static int txtfmt_lua_find_bool(const char *string)
{
int i, len;
- if (STR_LITERAL_STARTSWITH(string, "nil", len)) {
- i = len;
- }
- else if (STR_LITERAL_STARTSWITH(string, "true", len)) {
- i = len;
- }
- else if (STR_LITERAL_STARTSWITH(string, "false", len)) {
- i = len;
- }
- else {
- i = 0;
- }
+ /* Keep aligned args for readability. */
+ /* clang-format off */
+
+ if (STR_LITERAL_STARTSWITH(string, "nil", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
+ } else { i = 0; }
/* clang-format on */
@@ -169,10 +162,9 @@ static char txtfmt_lua_format_identifier(const char *str)
/* Keep aligned args for readability. */
/* clang-format off */
- if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
+ if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
} else if ((txtfmt_lua_find_keyword(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
- } else { fmt = FMT_TYPE_DEFAULT;
-}
+ } else { fmt = FMT_TYPE_DEFAULT; }
/* clang-format on */
diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c
index fb9ddcb09cb..2da4488e901 100644
--- a/source/blender/editors/space_text/text_format_osl.c
+++ b/source/blender/editors/space_text/text_format_osl.c
@@ -40,7 +40,7 @@ static int txtfmt_osl_find_builtinfunc(const char *string)
/* list is from
* https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
*/
- if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "closure", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "color", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len;
@@ -86,7 +86,7 @@ static int txtfmt_osl_find_reserved(const char *string)
/* list is from...
* https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
*/
- if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "catch", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "char", len)) { i = len;
@@ -149,7 +149,7 @@ static int txtfmt_osl_find_specialvar(const char *string)
/* clang-format off */
/* OSL shader types */
- if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "surface", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "volume", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) { i = len;
@@ -189,7 +189,7 @@ static char txtfmt_osl_format_identifier(const char *str)
/* Keep aligned args for readability. */
/* clang-format off */
- if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
+ if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
} else if ((txtfmt_osl_find_builtinfunc(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
} else if ((txtfmt_osl_find_reserved(str)) != -1) { fmt = FMT_TYPE_RESERVED;
} else if ((txtfmt_osl_find_preprocessor(str)) != -1) { fmt = FMT_TYPE_DIRECTIVE;
@@ -323,7 +323,7 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_
/* Special vars(v) or built-in keywords(b) */
/* keep in sync with 'txtfmt_osl_format_identifier()' */
- if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
+ if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_osl_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
} else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) { prev = FMT_TYPE_DIRECTIVE;
diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c
index a5e1a3845cf..21df7b5b76a 100644
--- a/source/blender/editors/space_text/text_format_pov.c
+++ b/source/blender/editors/space_text/text_format_pov.c
@@ -48,7 +48,7 @@ static int txtfmt_pov_find_keyword(const char *string)
int i, len;
/* Language Directives */
- if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "persistent", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "version", len)) { i = len;
@@ -101,7 +101,7 @@ static int txtfmt_pov_find_reserved_keywords(const char *string)
/* clang-format off */
/* Float Functions */
- if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) { i = len;
@@ -261,7 +261,7 @@ static int txtfmt_pov_find_reserved_builtins(const char *string)
/* clang-format off */
/* Language Keywords */
- if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) { i = len;
@@ -500,7 +500,7 @@ static int txtfmt_pov_find_specialvar(const char *string)
{
int i, len;
/* Modifiers */
- if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "double_illuminate", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) { i = len;
@@ -710,7 +710,7 @@ static int txtfmt_pov_find_bool(const char *string)
/* clang-format off */
/* Built-in Constants */
- if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "no", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "off", len)) { i = len;
diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c
index 04f4b992cc6..b349b38e551 100644
--- a/source/blender/editors/space_text/text_format_pov_ini.c
+++ b/source/blender/editors/space_text/text_format_pov_ini.c
@@ -49,7 +49,7 @@ static int txtfmt_ini_find_keyword(const char *string)
/* clang-format off */
/* Language Directives */
- if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "declare", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "default", len)) { i = len;
@@ -111,7 +111,7 @@ static int txtfmt_ini_find_reserved(const char *string)
* list is from...
* http://www.povray.org/documentation/view/3.7.0/212/
*/
- if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) { i = len;
@@ -321,7 +321,7 @@ static int txtfmt_ini_find_bool(const char *string)
/* clang-format off */
/* Built-in Constants */
- if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "no", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "off", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len;
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
index 98eeee61c3a..d84beb79be6 100644
--- a/source/blender/editors/space_text/text_format_py.c
+++ b/source/blender/editors/space_text/text_format_py.c
@@ -58,11 +58,11 @@ static int txtfmt_py_find_builtinfunc(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "async", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "await", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "del", len)) { i = len;
@@ -114,7 +114,7 @@ static int txtfmt_py_find_specialvar(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "class", len)) { i = len;
} else { i = 0;
}
@@ -155,7 +155,7 @@ static int txtfmt_py_find_bool(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "True", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "False", len)) { i = len;
} else { i = 0;
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index caefb5070fb..f9557225b6b 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -443,6 +443,8 @@ static int text_reload_exec(bContext *C, wmOperator *op)
text_drawcache_tag_update(CTX_wm_space_text(C), 1);
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
+ text->flags &= ~TXT_ISDIRTY;
+
/* return to scroll position */
st->top = orig_top;
txt_screen_clamp(st, ar);
@@ -3482,7 +3484,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
}
else {
if (!found) {
- BKE_reportf(op->reports, RPT_ERROR, "Text not found: %s", st->findstr);
+ BKE_reportf(op->reports, RPT_WARNING, "Text not found: %s", st->findstr);
}
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index b32bb0baec9..c7f13ce0e51 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -311,13 +311,6 @@ static void view3d_free(SpaceLink *sl)
MEM_freeN(vd->runtime.properties_storage);
}
- if (vd->fx_settings.ssao) {
- MEM_freeN(vd->fx_settings.ssao);
- }
- if (vd->fx_settings.dof) {
- MEM_freeN(vd->fx_settings.dof);
- }
-
if (vd->shading.prop) {
IDP_FreeProperty(vd->shading.prop);
vd->shading.prop = NULL;
@@ -341,19 +334,20 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
v3dn->runtime.properties_storage = NULL;
}
+ v3dn->local_collections_uuid = 0;
+ v3dn->flag &= ~V3D_LOCAL_COLLECTIONS;
+
if (v3dn->shading.type == OB_RENDER) {
v3dn->shading.type = OB_SOLID;
}
+ if (v3dn->shading.prop) {
+ v3dn->shading.prop = IDP_CopyProperty(v3do->shading.prop);
+ }
+
/* copy or clear inside new stuff */
v3dn->runtime.properties_storage = NULL;
- if (v3dn->fx_settings.dof) {
- v3dn->fx_settings.dof = MEM_dupallocN(v3do->fx_settings.dof);
- }
- if (v3dn->fx_settings.ssao) {
- v3dn->fx_settings.ssao = MEM_dupallocN(v3do->fx_settings.ssao);
- }
return (SpaceLink *)v3dn;
}
@@ -577,7 +571,7 @@ static void view3d_lightcache_update(bContext *C)
Scene *scene = CTX_data_scene(C);
- if (strcmp(scene->r.engine, RE_engine_id_BLENDER_EEVEE) != 0) {
+ if (!BKE_scene_uses_blender_eevee(scene)) {
/* Only do auto bake if eevee is the active engine */
return;
}
@@ -1039,10 +1033,10 @@ static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (obedit) {
- WM_cursor_set(win, CURSOR_EDIT);
+ WM_cursor_set(win, WM_CURSOR_EDIT);
}
else {
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
@@ -1093,6 +1087,9 @@ static void view3d_header_region_listener(wmWindow *UNUSED(win),
if (wmn->data & ND_GPENCIL_EDITMODE) {
ED_region_tag_redraw(ar);
}
+ else if (wmn->action == NA_EDITED) {
+ ED_region_tag_redraw(ar);
+ }
break;
case NC_BRUSH:
ED_region_tag_redraw(ar);
@@ -1457,7 +1454,7 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
if (view_layer->basact) {
Object *ob = view_layer->basact->object;
/* if hidden but in edit mode, we still display, can happen with animation */
- if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT)) {
+ if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 || (ob->mode & OB_MODE_EDIT)) {
CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact);
}
}
@@ -1469,7 +1466,8 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
if (view_layer->basact) {
Object *ob = view_layer->basact->object;
/* if hidden but in edit mode, we still display, can happen with animation */
- if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT) != 0) {
+ if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 ||
+ (ob->mode & OB_MODE_EDIT) != 0) {
CTX_data_id_pointer_set(result, &ob->id);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index aafd36a5bb8..3ee9755cb06 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1422,18 +1422,24 @@ static void draw_grid_unit_name(
{
if (!rv3d->is_persp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
const char *grid_unit = NULL;
+ int font_id = BLF_default();
ED_view3d_grid_view_scale(scene, v3d, rv3d, &grid_unit);
if (grid_unit) {
char numstr[32] = "";
- UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
if (v3d->grid != 1.0f) {
BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
}
*yoffset -= U.widget_unit;
+ BLF_enable(font_id, BLF_SHADOW);
+ BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
+ BLF_shadow_offset(font_id, 1, -1);
BLF_draw_default_ascii(
xoffset, *yoffset, 0.0f, numstr[0] ? numstr : grid_unit, sizeof(numstr));
+
+ BLF_disable(font_id, BLF_SHADOW);
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index f77a42fb1c1..17b575cedae 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -179,7 +179,7 @@ static void validate_object_select_id(
return;
}
- if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) {
+ if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
Base *base = BKE_view_layer_base_find(view_layer, obact);
DRW_select_buffer_context_create(&base, 1, -1);
}
@@ -226,7 +226,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc)
ARegion *ar = vc->ar;
Object *obact_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
- if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) {
+ if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
DRW_draw_depth_object(vc->ar, viewport, obact_eval);
}
@@ -383,6 +383,14 @@ void ED_view3d_datamask(const bContext *C,
r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
r_cddata_masks->vmask |= CD_MASK_ORCO;
}
+ else if (v3d->shading.type == OB_SOLID) {
+ if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) {
+ r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
+ }
+ if (v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR) {
+ r_cddata_masks->lmask |= CD_MASK_MLOOPCOL;
+ }
+ }
if ((CTX_data_mode_enum(C) == CTX_MODE_EDIT_MESH) &&
(v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT)) {
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 4bc74ab8fba..3ad194a5d2b 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -2997,7 +2997,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ok = paintface_minmax(ob_eval, min, max);
}
else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) {
- ok = PE_minmax(scene, CTX_data_view_layer(C), min, max);
+ ok = PE_minmax(depsgraph, scene, CTX_data_view_layer(C), min, max);
}
else if (ob_eval && (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT |
OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
index 615589347da..dbad06da5ec 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
@@ -25,6 +25,7 @@
#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "DNA_object_types.h"
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c
index 42931d5abb5..ba5ca5fbd15 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_camera.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c
@@ -24,6 +24,7 @@
#include "BKE_camera.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "DNA_object_types.h"
#include "DNA_camera_types.h"
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_empty.c b/source/blender/editors/space_view3d/view3d_gizmo_empty.c
index b37f1e41294..793aec42dcd 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_empty.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c
@@ -22,6 +22,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "BKE_image.h"
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
index 44ad1d14dba..90b1539c8a7 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
@@ -21,6 +21,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "DNA_object_types.h"
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_light.c b/source/blender/editors/space_view3d/view3d_gizmo_light.c
index 35677b2e4c2..890de0ae611 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_light.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_light.c
@@ -22,6 +22,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
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 b5b924c7f4a..d6d3a3dc563 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -518,9 +518,9 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
static int gizmo_axis_cursor_get(wmGizmo *gz)
{
if (gz->highlight_part > 0) {
- return CURSOR_EDIT;
+ return WM_CURSOR_EDIT;
}
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index 2189191ad53..a5b7fac624d 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -407,6 +407,17 @@ static bool view3d_ruler_item_mousemove(RulerInfo *ruler_info,
/** \name Ruler/Grease Pencil Conversion
* \{ */
+/* Helper: Find the layer created as ruler. */
+static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd)
+{
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_IS_RULER) {
+ return gpl;
+ }
+ }
+ return NULL;
+}
+
#define RULER_ID "RulerData3D"
static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
{
@@ -427,12 +438,12 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
}
gpd = scene->gpd;
- gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ gpl = view3d_ruler_layer_get(gpd);
if (gpl == NULL) {
gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false);
copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
gpl->thickness = 1;
- gpl->flag |= GP_LAYER_HIDE;
+ gpl->flag |= GP_LAYER_HIDE | GP_LAYER_IS_RULER;
}
gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
@@ -485,8 +496,7 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup)
if (scene->gpd) {
bGPDlayer *gpl;
- const char *ruler_name = RULER_ID;
- gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ gpl = view3d_ruler_layer_get(scene->gpd);
if (gpl) {
bGPDframe *gpf;
gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV);
@@ -1013,9 +1023,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
static int gizmo_ruler_cursor_get(wmGizmo *gz)
{
if (gz->highlight_part == PART_LINE) {
- return BC_CROSSCURSOR;
+ return WM_CURSOR_CROSS;
}
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_ruler_item(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index e5a145b0411..cfdd3dcbb6f 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -79,7 +79,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_save(bmain, str, op->reports);
- BKE_reportf(op->reports, RPT_INFO, "Copied %d selected objects", num_copied);
+ BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied);
return OPERATOR_FINISHED;
}
@@ -118,7 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
- BKE_reportf(op->reports, RPT_INFO, "%d objects pasted", num_pasted);
+ BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index bcffad454fe..3eee76277e8 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -120,13 +120,13 @@ float ED_view3d_select_dist_px(void)
}
/* TODO: should return whether there is valid context to continue */
-void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
+void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph)
{
memset(vc, 0, sizeof(ViewContext));
vc->C = C;
vc->ar = CTX_wm_region(C);
vc->bmain = CTX_data_main(C);
- vc->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ vc->depsgraph = depsgraph;
vc->scene = CTX_data_scene(C);
vc->view_layer = CTX_data_view_layer(C);
vc->v3d = CTX_wm_view3d(C);
@@ -1020,10 +1020,12 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
is_ignore_flag |= BONESEL_TIP;
}
- if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) ||
- BLI_lasso_is_edge_inside(
- data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
- is_inside_flag |= BONESEL_BONE;
+ if (is_ignore_flag == 0) {
+ if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) ||
+ BLI_lasso_is_edge_inside(
+ data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
+ is_inside_flag |= BONESEL_BONE;
+ }
}
ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16);
@@ -1344,11 +1346,12 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op);
@@ -1889,6 +1892,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
/* mval comes from event->mval, only use within region handlers */
Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Base *basact = NULL;
uint buffer[MAXPICKBUF];
@@ -1897,7 +1901,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
const int hits = mixed_bones_object_selectbuffer(
@@ -1955,9 +1959,10 @@ static bool ed_object_select_pick(bContext *C,
bool enumerate,
bool object)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -3203,6 +3208,7 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e
static int view3d_box_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
bool changed_multi = false;
@@ -3214,7 +3220,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
BKE_object_update_select_id(CTX_data_main(C));
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
WM_operator_properties_border_to_rcti(op, &rect);
@@ -4004,6 +4010,7 @@ static bool object_circle_select(ViewContext *vc,
/* not a real operator, only for circle test */
static int view3d_circle_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
const int radius = RNA_int_get(op->ptr, "radius");
const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")};
@@ -4016,7 +4023,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
WM_gesture_is_modal_first(gesture));
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
Object *obact = vc.obact;
Object *obedit = vc.obedit;
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index e5e1b1297f6..d7af307bc53 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -196,8 +196,8 @@ void ED_view3d_smooth_view_ex(
sms.to_camera = true; /* restore view3d values in end */
}
- /* skip smooth viewing for render engine draw */
- if (smooth_viewtx && v3d->shading.type != OB_RENDER) {
+ /* skip smooth viewing for external render engine draw */
+ if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) {
bool changed = false; /* zero means no difference */
if (sview->camera_old != sview->camera) {
@@ -508,7 +508,7 @@ static bool view3d_camera_to_view_poll(bContext *C)
void VIEW3D_OT_camera_to_view(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Align Camera To View";
+ ot->name = "Align Camera to View";
ot->description = "Set camera view to active view";
ot->idname = "VIEW3D_OT_camera_to_view";
@@ -1583,7 +1583,13 @@ static uint free_localcollection_bit(Main *bmain,
static void local_collections_reset_uuid(LayerCollection *layer_collection,
const unsigned short local_view_bit)
{
- layer_collection->local_collections_bits |= local_view_bit;
+ if (layer_collection->flag & LAYER_COLLECTION_HIDE) {
+ layer_collection->local_collections_bits &= ~local_view_bit;
+ }
+ else {
+ layer_collection->local_collections_bits |= local_view_bit;
+ }
+
LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
local_collections_reset_uuid(child, local_view_bit);
}
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 91c05f5cac6..a7402a622d5 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -204,6 +204,8 @@ typedef struct WalkInfo {
* (this would need to un-key all previous frames).
*/
bool anim_playing;
+ bool need_rotation_keyframe;
+ bool need_translation_keyframe;
/** Previous 2D mouse values. */
int prev_mval[2];
@@ -538,6 +540,8 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
#endif
walk->anim_playing = ED_screen_animation_playing(wm);
+ walk->need_rotation_keyframe = false;
+ walk->need_translation_keyframe = false;
walk->time_lastdraw = PIL_check_seconds_timer();
@@ -577,7 +581,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->ar->winrct.ymin + walk->center_mval[1]);
/* remove the mouse cursor temporarily */
- WM_cursor_modal_set(win, CURSOR_NONE);
+ WM_cursor_modal_set(win, WM_CURSOR_NONE);
return 1;
}
@@ -930,9 +934,12 @@ static void walkMoveCamera(bContext *C,
/* we only consider autokeying on playback or if user confirmed walk on the same frame
* otherwise we get a keyframe even if the user cancels. */
const bool use_autokey = is_confirm || walk->anim_playing;
-
ED_view3d_cameracontrol_update(
walk->v3d_camera_control, use_autokey, C, do_rotate, do_translate);
+ if (use_autokey) {
+ walk->need_rotation_keyframe = false;
+ walk->need_translation_keyframe = false;
+ }
}
static float getFreeFallDistance(const float gravity, const float time)
@@ -1280,9 +1287,10 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
add_v3_v3(rv3d->ofs, dvec_tmp);
if (rv3d->persp == RV3D_CAMOB) {
- const bool do_rotate = (moffset[0] || moffset[1]);
- const bool do_translate = (walk->speed != 0.0f);
- walkMoveCamera(C, walk, do_rotate, do_translate, is_confirm);
+ walk->need_rotation_keyframe |= (moffset[0] || moffset[1]);
+ walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON);
+ walkMoveCamera(
+ C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);
}
}
else {
@@ -1322,7 +1330,10 @@ static void walkApply_ndof(bContext *C, WalkInfo *walk, bool is_confirm)
walk->redraw = true;
if (walk->rv3d->persp == RV3D_CAMOB) {
- walkMoveCamera(C, walk, has_rotate, has_translate, is_confirm);
+ walk->need_rotation_keyframe |= has_rotate;
+ walk->need_translation_keyframe |= has_translate;
+ walkMoveCamera(
+ C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);
}
}
}
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index a95c7cf7456..b98c14150d5 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -2299,7 +2299,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if (t->options & CTX_SCULPT) {
+ if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
ED_sculpt_end_transform(C);
}
@@ -2346,9 +2346,11 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
- Object *ob = CTX_data_active_object(C);
- if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) {
- options |= CTX_SCULPT;
+ if (CTX_wm_view3d(C) != NULL) {
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) {
+ options |= CTX_SCULPT;
+ }
}
t->options = options;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index b90fff29a84..ff2afbc0cd7 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -267,7 +267,6 @@ typedef struct TransDataNla {
int handle;
} TransDataNla;
-struct GHash;
struct LinkNode;
/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 1e783e0e7b8..64ad8b2091e 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -429,7 +429,7 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
bone->flag |= BONE_TRANSFORM_CHILD;
}
else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
}
bone_children_clear_transflag(mode, around, &bone->childbase);
@@ -455,14 +455,14 @@ int count_set_pose_transflags(Object *ob,
bone->flag |= BONE_TRANSFORM;
}
else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
}
bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
bone->flag &= ~BONE_TRANSFORM_CHILD;
}
else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
}
}
@@ -1542,8 +1542,8 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t
}
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & (BONE_TRANSFORM | BONE_TRANSFORM_MIRROR)) {
-
+ if ((pchan->bone->flag & BONE_TRANSFORM) ||
+ ((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) {
ListBase dsources = {NULL, NULL};
/* clear any 'unkeyed' flag it may have */
@@ -2237,9 +2237,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* Update motion paths once for all transformed bones in an object. */
GSetIterator gs_iter;
GSET_ITER (gs_iter, motionpath_updates) {
- bool current_frame_only = canceled;
+ const ePosePathCalcRange range = canceled ? POSE_PATH_CALC_RANGE_CURRENT_FRAME :
+ POSE_PATH_CALC_RANGE_CHANGED;
ob = BLI_gsetIterator_getKey(&gs_iter);
- ED_pose_recalculate_paths(C, t->scene, ob, current_frame_only);
+ ED_pose_recalculate_paths(C, t->scene, ob, range);
}
BLI_gset_free(motionpath_updates, NULL);
}
@@ -2250,7 +2251,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* pass */
}
else if ((t->view_layer->basact) && (ob = t->view_layer->basact->object) &&
- (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, ob)) {
+ (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->depsgraph, t->scene, ob)) {
/* do nothing */
}
else if (t->flag & T_CURSOR) {
@@ -2320,8 +2321,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
if (motionpath_update) {
/* Update motion paths once for all transformed objects. */
- bool current_frame_only = canceled;
- ED_objects_recalculate_paths(C, t->scene, current_frame_only);
+ const eObjectPathCalcRange range = canceled ? OBJECT_PATH_CALC_RANGE_CURRENT_FRAME :
+ OBJECT_PATH_CALC_RANGE_CHANGED;
+ ED_objects_recalculate_paths(C, t->scene, range);
}
}
@@ -2399,7 +2401,7 @@ void createTransData(bContext *C, TransInfo *t)
}
countAndCleanTransDataContainer(t);
}
- else if (t->options & CTX_SCULPT) {
+ else if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
createTransSculpt(t);
countAndCleanTransDataContainer(t);
}
@@ -2666,7 +2668,8 @@ void createTransData(bContext *C, TransInfo *t)
}
}
}
- else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
+ else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) &&
+ PE_start_edit(PE_get_current(t->depsgraph, scene, ob))) {
createTransParticleVerts(C, t);
countAndCleanTransDataContainer(t);
t->flag |= T_POINTS;
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index 3eb4d220cb0..f3d7592127c 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -621,10 +621,10 @@ void flushTransGraphData(TransInfo *t)
float inv_unit_scale = 1.0f / tdg->unit_scale;
- /* handle snapping for time values
- * - we should still be in NLA-mapping timespace
- * - only apply to keyframes (but never to handles)
- * - don't do this when canceling, or else these changes won't go away
+ /* Handle snapping for time values:
+ * - We should still be in NLA-mapping time-space.
+ * - Only apply to keyframes (but never to handles).
+ * - Don't do this when canceling, or else these changes won't go away.
*/
if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) {
switch (sipo->autosnap) {
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 9c46094ee83..f1928433491 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1044,7 +1044,6 @@ void trans_mesh_customdata_correction_init(TransInfo *t)
* accidentally break uv maps or vertex colors then */
(bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) {
use_origfaces = true;
- cd_loop_mdisp_offset = cd_loop_mdisp_offset;
}
else {
use_origfaces = false;
@@ -1452,7 +1451,7 @@ void createTransUVs(bContext *C, TransInfo *t)
const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
if (elementmap == NULL) {
- return;
+ continue;
}
if (is_prop_connected) {
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 6142e9628a4..6e85f6b9bf0 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -501,8 +501,12 @@ static void set_trans_object_base_deps_flag_cb(ID *id,
static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
{
object->id.tag |= LIB_TAG_DOIT;
- DEG_foreach_dependent_ID_component(
- depsgraph, &object->id, DEG_OB_COMP_TRANSFORM, set_trans_object_base_deps_flag_cb, NULL);
+ DEG_foreach_dependent_ID_component(depsgraph,
+ &object->id,
+ DEG_OB_COMP_TRANSFORM,
+ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS,
+ set_trans_object_base_deps_flag_cb,
+ NULL);
}
static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *view_layer)
@@ -930,11 +934,13 @@ void createTransTexspace(TransInfo *t)
normalize_m3(td->axismtx);
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
- if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size, &td->ext->rot)) {
+ if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size)) {
ob->dtx |= OB_TEXSPACE;
*texflag &= ~ME_AUTOSPACE;
}
+ zero_v3(td->ext->rot);
+
copy_v3_v3(td->iloc, td->loc);
copy_v3_v3(td->ext->irot, td->ext->rot);
copy_v3_v3(td->ext->isize, td->ext->size);
diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c
index 3b11e604cab..2a961da018b 100644
--- a/source/blender/editors/transform/transform_convert_particle.c
+++ b/source/blender/editors/transform/transform_convert_particle.c
@@ -51,7 +51,7 @@ void createTransParticleVerts(bContext *C, TransInfo *t)
TransDataExtension *tx;
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(t->scene);
- PTCacheEdit *edit = PE_get_current(t->scene, ob);
+ PTCacheEdit *edit = PE_get_current(t->depsgraph, t->scene, ob);
ParticleSystem *psys = NULL;
PTCacheEditPoint *point;
PTCacheEditKey *key;
@@ -200,7 +200,7 @@ void flushTransParticles(TransInfo *t)
Scene *scene = t->scene;
ViewLayer *view_layer = t->view_layer;
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(t->depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
PTCacheEditPoint *point;
PTCacheEditKey *key;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 76f699e3dc4..2e4f4344481 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -794,6 +794,12 @@ static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid)
for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig;
pchan_orig = pchan_orig->next) {
+ /* Clear the MIRROR flag from previous runs */
+ pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+ }
+
+ for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig;
+ pchan_orig = pchan_orig->next) {
/* no layer check, correct mirror is more important */
if (pchan_orig->bone->flag & BONE_TRANSFORM) {
bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name);
@@ -1088,12 +1094,12 @@ static void recalcData_objects(TransInfo *t)
GSetIterator gs_iter;
GSET_ITER (gs_iter, motionpath_updates) {
Object *ob = BLI_gsetIterator_getKey(&gs_iter);
- ED_pose_recalculate_paths(t->context, t->scene, ob, true);
+ ED_pose_recalculate_paths(t->context, t->scene, ob, POSE_PATH_CALC_RANGE_CURRENT_FRAME);
}
BLI_gset_free(motionpath_updates, NULL);
}
else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) &&
- PE_get_current(t->scene, base->object)) {
+ PE_get_current(t->depsgraph, t->scene, base->object)) {
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
@@ -1146,7 +1152,7 @@ static void recalcData_objects(TransInfo *t)
if (motionpath_update) {
/* Update motion paths once for all transformed objects. */
- ED_objects_recalculate_paths(t->context, t->scene, true);
+ ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED);
}
if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
@@ -1707,7 +1713,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
else {
- if (ISMOUSE(t->launch_event) && (U.flag & USER_RELEASECONFIRM)) {
+ /* Release confirms preference should not affect node editor (T69288, T70504). */
+ if (ISMOUSE(t->launch_event) &&
+ ((U.flag & USER_RELEASECONFIRM) || (t->spacetype == SPACE_NODE))) {
/* Global "release confirm" on mouse bindings */
t->flag |= T_RELEASE_CONFIRM;
}
@@ -1832,7 +1840,7 @@ static void freeTransCustomData(TransInfo *t, TransDataContainer *tc, TransCusto
custom_data->data = NULL;
}
/* In case modes are switched in the same transform session. */
- custom_data->free_cb = false;
+ custom_data->free_cb = NULL;
custom_data->use_free = false;
}
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 25cf0fbbba2..157cf96a85e 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -516,9 +516,15 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags)
}
/* for pose mode */
-static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
+static void protectflag_to_drawflags_pchan(RegionView3D *rv3d,
+ const bPoseChannel *pchan,
+ short orientation_type)
{
- protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
+ /* Protect-flags apply to local space in pose mode, so only let them influence axis
+ * visibility if we show the global orientation, otherwise it's confusing. */
+ if (orientation_type == V3D_ORIENT_LOCAL) {
+ protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
+ }
}
/* for editmode*/
@@ -742,7 +748,14 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
bGPdata *gpd = CTX_data_gpencil_data(C);
const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
int a, totsel = 0;
+
const int pivot_point = scene->toolsettings->transform_pivot_point;
+ const short orientation_type = params->orientation_type ?
+ (params->orientation_type - 1) :
+ scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
+ const short orientation_index_custom =
+ params->orientation_type ? params->orientation_index_custom :
+ scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
/* transform widget matrix */
unit_m4(rv3d->twmat);
@@ -756,12 +769,6 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
/* global, local or normal orientation?
* if we could check 'totsel' now, this should be skipped with no selection. */
if (ob) {
- const short orientation_type = params->orientation_type ?
- (params->orientation_type - 1) :
- scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
- const short orientation_index_custom =
- params->orientation_type ? params->orientation_index_custom :
- scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
float mat[3][3];
ED_transform_calc_orientation_from_type_ex(
C, mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point);
@@ -888,7 +895,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
calc_tw_center_with_matrix(tbounds, ebo->head, use_mat_local, mat_local);
totsel++;
}
- if (ebo->flag & BONE_SELECTED) {
+ if (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
protectflag_to_drawflags_ebone(rv3d, ebo);
}
}
@@ -1038,7 +1045,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
Bone *bone = pchan->bone;
if (bone && (bone->flag & BONE_TRANSFORM)) {
calc_tw_center_with_matrix(tbounds, pchan->pose_head, use_mat_local, mat_local);
- protectflag_to_drawflags_pchan(rv3d, pchan);
+ protectflag_to_drawflags_pchan(rv3d, pchan, orientation_type);
}
}
totsel += totsel_iter;
@@ -1063,7 +1070,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
}
}
else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PTCacheEditPoint *point;
PTCacheEditKey *ek;
int k;
@@ -1122,7 +1129,12 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
calc_tw_center(tbounds, co);
}
}
- protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
+
+ /* Protect-flags apply to world space in object mode, so only let them influence axis
+ * visibility if we show the global orientation, otherwise it's confusing. */
+ if (orientation_type == V3D_ORIENT_GLOBAL) {
+ protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
+ }
totsel++;
}
@@ -1168,16 +1180,20 @@ static void gizmo_prepare_mat(const bContext *C,
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
bGPdata *gpd = CTX_data_gpencil_data(C);
- Object *ob = OBACT(view_layer);
if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
/* pass */
}
- else if (ob->sculpt) {
- SculptSession *ss = ob->sculpt;
- copy_v3_v3(rv3d->twmat[3], ss->pivot_pos);
- }
- else if (ob != NULL) {
- ED_object_calc_active_center(ob, false, rv3d->twmat[3]);
+ else {
+ Object *ob = OBACT(view_layer);
+ if (ob != NULL) {
+ if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
+ SculptSession *ss = ob->sculpt;
+ copy_v3_v3(rv3d->twmat[3], ss->pivot_pos);
+ }
+ else {
+ ED_object_calc_active_center(ob, false, rv3d->twmat[3]);
+ }
+ }
}
}
break;
@@ -1293,7 +1309,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
PointerRNA toolsettings_ptr;
RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
- if (type_fn == VIEW3D_GGT_xform_gizmo) {
+ if (ELEM(type_fn, VIEW3D_GGT_xform_gizmo, VIEW3D_GGT_xform_shear)) {
extern PropertyRNA rna_ToolSettings_transform_pivot_point;
const PropertyRNA *props[] = {
&rna_ToolSettings_transform_pivot_point,
@@ -1334,6 +1350,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
}
WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_gz_tag_refresh);
+ WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh);
}
void drawDial3d(const TransInfo *t)
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index e771fe43bd8..2821277ffa0 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -389,7 +389,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
/* INPUT_VECTOR, INPUT_CUSTOM_RATIO, INPUT_CUSTOM_RATIO_FLIP */
if (t->flag & T_MODAL) {
t->flag |= T_MODAL_CURSOR_SET;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
break;
case HLP_SPRING:
@@ -400,7 +400,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
case HLP_CARROW:
if (t->flag & T_MODAL) {
t->flag |= T_MODAL_CURSOR_SET;
- WM_cursor_modal_set(win, CURSOR_NONE);
+ WM_cursor_modal_set(win, WM_CURSOR_NONE);
}
break;
default:
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 1c264ba48ae..b2d8671fbce 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -302,11 +302,11 @@ static void TRANSFORM_OT_create_orientation(struct wmOperatorType *ot)
WM_operatortype_props_advanced_begin(ot);
RNA_def_boolean(
- ot->srna, "use", false, "Use after creation", "Select orientation after its creation");
+ ot->srna, "use", false, "Use After Creation", "Select orientation after its creation");
RNA_def_boolean(ot->srna,
"overwrite",
false,
- "Overwrite previous",
+ "Overwrite Previous",
"Overwrite previously created orientation with same name");
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index cbe9505d3f2..3159464072e 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -44,6 +44,7 @@
#include "BKE_curve.h"
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_workspace.h"
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 9c2642a46c1..f35a2808f22 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -47,6 +47,7 @@
#include "BKE_object.h"
#include "BKE_anim.h" /* for duplis */
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_tracking.h"
#include "BKE_context.h"
@@ -1717,7 +1718,7 @@ static short snapCurve(SnapData *snapdata,
if (use_obedit == false) {
/* Test BoundBox */
- BoundBox *bb = BKE_curve_texspace_get(cu, NULL, NULL, NULL);
+ BoundBox *bb = BKE_curve_boundbox_get(ob);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return 0;
@@ -2367,6 +2368,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
if (treedata_vert && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BLI_bvhtree_find_nearest_projected(treedata_vert->tree,
lpmat,
snapdata->win_size,
@@ -2382,6 +2384,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
int last_index = nearest.index;
nearest.index = -1;
BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
+ BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT);
BLI_bvhtree_find_nearest_projected(treedata_edge->tree,
lpmat,
snapdata->win_size,
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index c2566d111cf..f5548119e0a 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -245,7 +245,7 @@ bool ED_editors_flush_edits(Main *bmain, bool for_render)
* may cause a flush on saving: T53986. */
if ((ob->sculpt && ob->sculpt->cache) == 0) {
/* flush multires changes (for sculpt) */
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
has_edited = true;
if (for_render) {
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index bd941968418..fafd54804c0 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -177,6 +177,7 @@ static void uvedit_get_batches(Object *ob,
float *tot_area,
float *tot_area_uv)
{
+ float *tmp_tot_area, *tmp_tot_area_uv;
int drawfaces = draw_uvs_face_check(scene->toolsettings);
const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
@@ -193,7 +194,8 @@ static void uvedit_get_batches(Object *ob,
}
if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
- batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(ob->data, NULL, NULL);
+ batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(
+ ob->data, &tmp_tot_area, &tmp_tot_area_uv);
}
else if (draw_stretch) {
batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob->data);
@@ -207,11 +209,11 @@ static void uvedit_get_batches(Object *ob,
DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
- /* after create_requested we can load the actual areas */
- float tmp_tot_area, tmp_tot_area_uv;
- DRW_mesh_batch_cache_get_edituv_faces_stretch_area(ob->data, &tmp_tot_area, &tmp_tot_area_uv);
- *tot_area += tmp_tot_area;
- *tot_area_uv += tmp_tot_area_uv;
+ if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
+ /* after create_requested we can load the actual areas */
+ *tot_area += *tmp_tot_area;
+ *tot_area_uv += *tmp_tot_area_uv;
+ }
}
static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 57e2a84d248..0d258ba542b 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -4872,12 +4872,6 @@ static void UV_OT_reveal(wmOperatorType *ot)
/** \name Set 2D Cursor Operator
* \{ */
-static bool uv_set_2d_cursor_poll(bContext *C)
-{
- return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
- ED_space_image_paint_curve(C);
-}
-
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -4923,7 +4917,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = uv_set_2d_cursor_exec;
ot->invoke = uv_set_2d_cursor_invoke;
- ot->poll = uv_set_2d_cursor_poll;
+ ot->poll = ED_space_image_cursor_poll;
/* properties */
RNA_def_float_vector(ot->srna,
diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h
index f4fd2b132e8..263b5429161 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.h
+++ b/source/blender/freestyle/intern/stroke/Stroke.h
@@ -590,7 +590,8 @@ class Stroke : public Interface1D {
/*! Resampling method.
* Resamples the curve so that it eventually has iNPoints. That means it is going to add
* iNPoints-vertices_size, if vertices_size is the number of points we already have. If
- * vertices_size >= iNPoints, no resampling is done. \param iNPoints: The number of vertices we
+ * vertices_size >= iNPoints, no resampling is done.
+ * \param iNPoints: The number of vertices we
* eventually want in our stroke.
*/
int Resample(int iNPoints);
@@ -840,8 +841,10 @@ class Stroke : public Interface1D {
vertex_iterator vertices_end();
/*! Returns a StrokeVertexIterator pointing on the first StrokeVertex of the Stroke. One can
- * specify a sampling value to resample the Stroke on the fly if needed. \param t: The resampling
- * value with which we want our Stroke to be resampled. If 0 is specified, no resampling is done.
+ * specify a sampling value to resample the Stroke on the fly if needed.
+ *
+ * \param t: The resampling value with which we want our Stroke to be resampled.
+ * If 0 is specified, no resampling is done.
*/
StrokeInternal::StrokeVertexIterator strokeVerticesBegin(float t = 0.0f);
diff --git a/source/blender/freestyle/intern/view_map/Interface1D.h b/source/blender/freestyle/intern/view_map/Interface1D.h
index 7a72a176902..ab489bff4c9 100644
--- a/source/blender/freestyle/intern/view_map/Interface1D.h
+++ b/source/blender/freestyle/intern/view_map/Interface1D.h
@@ -156,15 +156,17 @@ class Interface1D {
/*! Returns an iterator over the Interface1D points, pointing to the first point. The difference
* with verticesBegin() is that here we can iterate over points of the 1D element at a any given
- * sampling. Indeed, for each iteration, a virtual point is created. \param t: The sampling with
- * which we want to iterate over points of this 1D element.
+ * sampling. Indeed, for each iteration, a virtual point is created.
+ *
+ * \param t: The sampling with which we want to iterate over points of this 1D element.
*/
virtual Interface0DIterator pointsBegin(float t = 0.0f);
/*! Returns an iterator over the Interface1D points, pointing after the last point. The
* difference with verticesEnd() is that here we can iterate over points of the 1D element at a
- * any given sampling. Indeed, for each iteration, a virtual point is created. \param t: The
- * sampling with which we want to iterate over points of this 1D element.
+ * any given sampling. Indeed, for each iteration, a virtual point is created.
+ *
+ * \param t: The sampling with which we want to iterate over points of this 1D element.
*/
virtual Interface0DIterator pointsEnd(float t = 0.0f);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 72385fd2f2c..b3321b693a4 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -80,15 +80,15 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
bool is_stroke_affected_by_modifier(Object *ob,
char *mlayername,
char *mmaterialname,
- int mpassindex,
- int gpl_passindex,
- int minpoints,
+ const int mpassindex,
+ const int gpl_passindex,
+ const int minpoints,
bGPDlayer *gpl,
bGPDstroke *gps,
- bool inv1,
- bool inv2,
- bool inv3,
- bool inv4)
+ const bool inv1,
+ const bool inv2,
+ const bool inv3,
+ const bool inv4)
{
Material *ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
MaterialGPencilStyle *gp_style = ma->gp_style;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index 7f00e072cda..2b1f8dbc71a 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -35,15 +35,15 @@ struct bGPDstroke;
bool is_stroke_affected_by_modifier(struct Object *ob,
char *mlayername,
char *mmaterialname,
- int mpassindex,
- int gpl_passindex,
- int minpoints,
+ const int mpassindex,
+ const int gpl_passindex,
+ const int minpoints,
bGPDlayer *gpl,
bGPDstroke *gps,
- bool inv1,
- bool inv2,
- bool inv3,
- bool inv4);
+ const bool inv1,
+ const bool inv2,
+ const bool inv3,
+ const bool inv4);
float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
index 1f2f0554dd5..27c8175af3f 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -203,5 +203,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Armature = {
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
index c311497ffbb..bb70b548675 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
@@ -317,14 +317,6 @@ static void foreachObjectLink(GpencilModifierData *md,
walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
-static int getDuplicationFactor(GpencilModifierData *md)
-{
- ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md;
- int t = mmd->count;
- CLAMP_MIN(t, 1);
- return t;
-}
-
GpencilModifierTypeInfo modifierType_Gpencil_Array = {
/* name */ "Array",
/* structName */ "ArrayGpencilModifierData",
@@ -347,5 +339,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Array = {
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ getDuplicationFactor,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index d72ace7a191..e3e7168330d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -550,5 +550,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Build = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
index cb429b874a2..cbe2d9a4c4f 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -168,5 +168,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
index 810a2ba7e25..bc62d0d69bb 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -63,8 +63,8 @@ struct GPHookData_cb {
float falloff_sq;
float fac_orig;
- unsigned int use_falloff : 1;
- unsigned int use_uniform : 1;
+ uint use_falloff : 1;
+ uint use_uniform : 1;
float cent[3];
@@ -357,5 +357,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Hook = {
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
index 6b74f96ce31..9dbf7b35bc5 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -219,5 +219,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = {
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
index e391adde829..ef06e14b3d7 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -203,21 +203,6 @@ static void foreachObjectLink(GpencilModifierData *md,
walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
-static int getDuplicationFactor(GpencilModifierData *md)
-{
- MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
- int factor = 1;
- /* create a duplication for each axis */
- for (int xi = 0; xi < 3; xi++) {
- if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
- factor++;
- }
- }
- CLAMP_MIN(factor, 1);
-
- return factor;
-}
-
GpencilModifierTypeInfo modifierType_Gpencil_Mirror = {
/* name */ "Mirror",
/* structName */ "MirrorGpencilModifierData",
@@ -240,5 +225,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Mirror = {
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ getDuplicationFactor,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index b286b55829e..f34477aaab2 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -274,5 +274,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
index 08f67eedc86..70d463fff76 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -148,5 +148,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Offset = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index 22610771045..c0892a1d91a 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -206,5 +206,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
index 25a56c4385c..9594fc8581e 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -144,5 +144,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Simplify = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
index 5ec7fe4ff18..68060711681 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -155,5 +155,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
index 741555722b5..89d6565d0dd 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
@@ -65,12 +65,16 @@ static void deformStroke(GpencilModifierData *md,
{
SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+ /* It makes sense when adding points to a straight line */
+ /* e.g. for creating thickness variation in later modifiers. */
+ const int minimum_vert = (mmd->flag & GP_SUBDIV_SIMPLE) ? 2 : 3;
+
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
mmd->materialname,
mmd->pass_index,
mmd->layer_pass,
- 3,
+ minimum_vert,
gpl,
gps,
mmd->flag & GP_SUBDIV_INVERT_LAYER,
@@ -99,14 +103,6 @@ static void bakeModifier(struct Main *UNUSED(bmain),
}
}
-static int getDuplicationFactor(GpencilModifierData *md)
-{
- SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
- int t = (mmd->level + 1) * (mmd->level + 1);
- CLAMP_MIN(t, 2);
- return t;
-}
-
GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
/* name */ "Subdivision",
/* structName */ "SubdivGpencilModifierData",
@@ -129,5 +125,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ getDuplicationFactor,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
index cc38df141d1..111b02a3a9d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -220,5 +220,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Thick = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
index 296e01d6d31..01bb0ae2b93 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
@@ -182,5 +182,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Time = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
index f6ddcf89bcf..f03bc489521 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -174,5 +174,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
- /* getDuplicationFactor */ NULL,
};
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 8d2355ff5ac..9320e849194 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -69,6 +69,7 @@ set(SRC
intern/gpu_init_exit.c
intern/gpu_material.c
intern/gpu_matrix.c
+ intern/gpu_platform.c
intern/gpu_primitive.c
intern/gpu_select.c
intern/gpu_select_pick.c
@@ -101,6 +102,7 @@ set(SRC
GPU_legacy_stubs.h
GPU_material.h
GPU_matrix.h
+ GPU_platform.h
GPU_primitive.h
GPU_select.h
GPU_shader.h
@@ -330,6 +332,8 @@ data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC)
+
if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 175033f70d9..d7218e97bf0 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -193,6 +193,19 @@ GPUBatch *create_BatchInGeneral(GPUPrimType, VertexBufferStuff, ElementListStuff
#endif /* future plans */
+/**
+ * #GPUDrawList is an API to do lots of similar draw-calls very fast using multi-draw-indirect.
+ * There is a fallback if the feature is not supported.
+ */
+typedef struct GPUDrawList GPUDrawList;
+
+GPUDrawList *GPU_draw_list_create(int length);
+void GPU_draw_list_discard(GPUDrawList *list);
+void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch);
+void GPU_draw_list_command_add(
+ GPUDrawList *list, int v_first, int v_count, int i_first, int i_count);
+void GPU_draw_list_submit(GPUDrawList *list);
+
void gpu_batch_init(void);
void gpu_batch_exit(void);
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 9009c134837..6d2b0ad3be3 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -31,6 +31,7 @@ struct CCGElem;
struct CCGKey;
struct DMFlagMat;
struct GSet;
+struct Mesh;
struct MLoop;
struct MLoopCol;
struct MLoopTri;
@@ -41,21 +42,28 @@ struct PBVH;
/* Buffers for drawing from PBVH grids. */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
-/* build */
+/* Build must be called once before using the other functions, used every time
+ * mesh topology changes. Threaded. */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
const struct MPoly *mpoly,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
const struct MVert *verts,
const int *face_indices,
- const int face_indices_len);
+ const int face_indices_len,
+ const struct Mesh *mesh);
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_hidden);
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
-/* update */
+/* Free part of data for update. Not thread safe, must run in OpenGL main thread. */
+void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers);
+void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
+ const struct DMFlagMat *grid_flag_mats,
+ int *grid_indices);
+/* Update mesh buffers without topology changes. Threaded. */
enum {
GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1),
GPU_PBVH_BUFFERS_SHOW_VCOL = (1 << 1),
@@ -85,6 +93,12 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
const struct CCGKey *key,
const int update_flags);
+/* Finish update. Not thread safe, must run in OpenGL main thread. */
+void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers);
+
+/* Free buffers. Not thread safe, must run in OpenGL main thread. */
+void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
+
/* draw */
struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires);
@@ -92,8 +106,4 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers);
bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers);
-void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
-
-void GPU_pbvh_fix_linking(void);
-
#endif
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 023cbb804d9..245f7f47510 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -55,34 +55,6 @@ void GPU_mem_stats_get(int *totalmem, int *freemem);
void GPU_code_generate_glsl_lib(void);
-/* GPU Types */
-
-typedef enum eGPUDeviceType {
- GPU_DEVICE_NVIDIA = (1 << 0),
- GPU_DEVICE_ATI = (1 << 1),
- GPU_DEVICE_INTEL = (1 << 2),
- GPU_DEVICE_INTEL_UHD = (1 << 3),
- GPU_DEVICE_SOFTWARE = (1 << 4),
- GPU_DEVICE_UNKNOWN = (1 << 5),
- GPU_DEVICE_ANY = (0xff),
-} eGPUDeviceType;
-
-typedef enum eGPUOSType {
- GPU_OS_WIN = (1 << 8),
- GPU_OS_MAC = (1 << 9),
- GPU_OS_UNIX = (1 << 10),
- GPU_OS_ANY = (0xff00),
-} eGPUOSType;
-
-typedef enum eGPUDriverType {
- GPU_DRIVER_OFFICIAL = (1 << 16),
- GPU_DRIVER_OPENSOURCE = (1 << 17),
- GPU_DRIVER_SOFTWARE = (1 << 18),
- GPU_DRIVER_ANY = (0xff0000),
-} eGPUDriverType;
-
-bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h
new file mode 100644
index 00000000000..f199a748cb5
--- /dev/null
+++ b/source/blender/gpu/GPU_platform.h
@@ -0,0 +1,75 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_PLATFORM_H__
+#define __GPU_PLATFORM_H__
+
+#include "BLI_sys_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GPU platform support */
+
+/* GPU Types */
+typedef enum eGPUDeviceType {
+ GPU_DEVICE_NVIDIA = (1 << 0),
+ GPU_DEVICE_ATI = (1 << 1),
+ GPU_DEVICE_INTEL = (1 << 2),
+ GPU_DEVICE_INTEL_UHD = (1 << 3),
+ GPU_DEVICE_SOFTWARE = (1 << 4),
+ GPU_DEVICE_UNKNOWN = (1 << 5),
+ GPU_DEVICE_ANY = (0xff),
+} eGPUDeviceType;
+
+typedef enum eGPUOSType {
+ GPU_OS_WIN = (1 << 8),
+ GPU_OS_MAC = (1 << 9),
+ GPU_OS_UNIX = (1 << 10),
+ GPU_OS_ANY = (0xff00),
+} eGPUOSType;
+
+typedef enum eGPUDriverType {
+ GPU_DRIVER_OFFICIAL = (1 << 16),
+ GPU_DRIVER_OPENSOURCE = (1 << 17),
+ GPU_DRIVER_SOFTWARE = (1 << 18),
+ GPU_DRIVER_ANY = (0xff0000),
+} eGPUDriverType;
+
+typedef enum eGPUSupportLevel {
+ GPU_SUPPORT_LEVEL_SUPPORTED,
+ GPU_SUPPORT_LEVEL_LIMITED,
+ GPU_SUPPORT_LEVEL_UNSUPPORTED,
+} eGPUSupportLevel;
+
+bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver);
+eGPUSupportLevel GPU_platform_support_level(void);
+const char *GPU_platform_support_level_key(void);
+const char *GPU_platform_gpu_name(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GPU_PLATFORM_H__ */
diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h
index ec97e1b085e..e336aa53d24 100644
--- a/source/blender/gpu/GPU_shader_interface.h
+++ b/source/blender/gpu/GPU_shader_interface.h
@@ -45,13 +45,12 @@ typedef enum {
GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
- GPU_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */
+ GPU_UNIFORM_ORCO, /* vec4 OrcoTexCoFactors[] */
GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
- GPU_UNIFORM_COLOR, /* vec4 color */
- GPU_UNIFORM_CALLID, /* int callId */
- GPU_UNIFORM_OBJECT_INFO, /* vec3 objectInfo */
- GPU_UNIFORM_OBJECT_COLOR, /* vec4 objectColor */
+ GPU_UNIFORM_COLOR, /* vec4 color */
+ GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
+ GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index e7600279d6f..4bbcb6a4335 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -37,14 +37,20 @@ typedef struct GPUViewport GPUViewport;
/* Contains memory pools information */
typedef struct ViewportMemoryPool {
- struct BLI_memblock *calls;
- struct BLI_memblock *states;
+ struct BLI_memblock *commands;
+ struct BLI_memblock *commands_small;
+ struct BLI_memblock *callbuffers;
+ struct BLI_memblock *obmats;
+ struct BLI_memblock *obinfos;
struct BLI_memblock *cullstates;
struct BLI_memblock *shgroups;
struct BLI_memblock *uniforms;
struct BLI_memblock *views;
struct BLI_memblock *passes;
struct BLI_memblock *images;
+ struct GPUUniformBuffer **matrices_ubo;
+ struct GPUUniformBuffer **obinfos_ubo;
+ uint ubo_len;
} ViewportMemoryPool;
/* All FramebufferLists are just the same pointers with different names */
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
index e0c0aea576c..168d741f92a 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -29,6 +29,7 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
#include "GPU_extensions.h"
+#include "GPU_platform.h"
#include "GPU_matrix.h"
#include "GPU_shader.h"
@@ -39,8 +40,9 @@
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
-static void batch_update_program_bindings(GPUBatch *batch, uint v_first);
+static void batch_update_program_bindings(GPUBatch *batch, uint i_first);
void GPU_batch_vao_cache_clear(GPUBatch *batch)
{
@@ -211,7 +213,9 @@ int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
if (batch->verts[v] == NULL) {
#if TRUST_NO_ONE
/* for now all VertexBuffers must have same vertex_len */
- assert(verts->vertex_len == batch->verts[0]->vertex_len);
+ if (batch->verts[0] != NULL) {
+ assert(verts->vertex_len == batch->verts[0]->vertex_len);
+ }
#endif
batch->verts[v] = verts;
/* TODO: mark dirty so we can keep attribute bindings up-to-date */
@@ -446,16 +450,16 @@ static void create_bindings(GPUVertBuf *verts,
}
}
-static void batch_update_program_bindings(GPUBatch *batch, uint v_first)
+static void batch_update_program_bindings(GPUBatch *batch, uint i_first)
{
/* Reverse order so first vbos have more prevalence (in term of attrib override). */
for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) {
if (batch->verts[v] != NULL) {
- create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
+ create_bindings(batch->verts[v], batch->interface, 0, false);
}
}
if (batch->inst) {
- create_bindings(batch->inst, batch->interface, v_first, true);
+ create_bindings(batch->inst, batch->interface, i_first, true);
}
if (batch->elem) {
GPU_indexbuf_use(batch->elem);
@@ -618,12 +622,18 @@ void GPU_batch_draw(GPUBatch *batch)
GPU_batch_program_use_end(batch);
}
+#if GPU_TRACK_INDEX_RANGE
+# define BASE_INDEX(el) ((el)->base_index)
+# define INDEX_TYPE(el) ((el)->gl_index_type)
+#else
+# define BASE_INDEX(el) 0
+# define INDEX_TYPE(el) GL_UNSIGNED_INT
+#endif
+
void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count)
{
-#if TRUST_NO_ONE
BLI_assert(batch->program_in_use);
/* TODO could assert that VAO is bound. */
-#endif
if (v_count == 0) {
v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len;
@@ -632,8 +642,21 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
i_count = (batch->inst) ? batch->inst->vertex_len : 1;
}
+ if (v_count == 0 || i_count == 0) {
+ /* Nothing to draw. */
+ return;
+ }
+
+ /* Verify there is enough data do draw. */
+ /* TODO(fclem) Nice to have but this is invalid when using procedural drawcalls.
+ * The right assert would be to check if there is an enabled attrib from each VBO
+ * and check their length. */
+ // BLI_assert(i_first + i_count <= (batch->inst ? batch->inst->vertex_len : INT_MAX));
+ // BLI_assert(v_first + v_count <=
+ // (batch->elem ? batch->elem->index_len : batch->verts[0]->vertex_len));
+
if (!GPU_arb_base_instance_is_supported()) {
- if (i_first > 0 && i_count > 0) {
+ if (i_first > 0) {
/* If using offset drawing with instancing, we must
* use the default VAO and redo bindings. */
glBindVertexArray(GPU_vao_default());
@@ -648,13 +671,8 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
if (batch->elem) {
const GPUIndexBuf *el = batch->elem;
-#if GPU_TRACK_INDEX_RANGE
- GLenum index_type = el->gl_index_type;
- GLint base_index = el->base_index;
-#else
- GLenum index_type = GL_UNSIGNED_INT;
- GLint base_index = 0;
-#endif
+ GLenum index_type = INDEX_TYPE(el);
+ GLint base_index = BASE_INDEX(el);
void *v_first_ofs = elem_offset(el, v_first);
if (GPU_arb_base_instance_is_supported()) {
@@ -697,6 +715,192 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count)
}
/* -------------------------------------------------------------------- */
+/** \name Indirect Draw Calls
+ * \{ */
+
+#if 0
+# define USE_MULTI_DRAW_INDIRECT 0
+#else
+/* TODO: partial workaround for NVIDIA driver bug on recent GTX/RTX cards,
+ * that breaks instancing when using indirect draw-call (see T70011). */
+# define USE_MULTI_DRAW_INDIRECT \
+ (GL_ARB_multi_draw_indirect && GPU_arb_base_instance_is_supported() && \
+ !GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL))
+#endif
+
+typedef struct GPUDrawCommand {
+ uint v_count;
+ uint i_count;
+ uint v_first;
+ uint i_first;
+} GPUDrawCommand;
+
+typedef struct GPUDrawCommandIndexed {
+ uint v_count;
+ uint i_count;
+ uint v_first;
+ uint base_index;
+ uint i_first;
+} GPUDrawCommandIndexed;
+
+struct GPUDrawList {
+ GPUBatch *batch;
+ uint base_index; /* Avoid dereferencing batch. */
+ uint cmd_offset; /* in bytes, offset inside indirect command buffer. */
+ uint cmd_len; /* Number of used command for the next call. */
+ uint buffer_size; /* in bytes, size of indirect command buffer. */
+ GLuint buffer_id; /* Draw Indirect Buffer id */
+ union {
+ GPUDrawCommand *commands;
+ GPUDrawCommandIndexed *commands_indexed;
+ };
+};
+
+GPUDrawList *GPU_draw_list_create(int length)
+{
+ GPUDrawList *list = MEM_callocN(sizeof(GPUDrawList), "GPUDrawList");
+ /* Alloc the biggest possible command list which is indexed. */
+ list->buffer_size = sizeof(GPUDrawCommandIndexed) * length;
+ if (USE_MULTI_DRAW_INDIRECT) {
+ list->buffer_id = GPU_buf_alloc();
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
+ }
+ else {
+ list->commands = MEM_mallocN(list->buffer_size, "GPUDrawList data");
+ }
+ return list;
+}
+
+void GPU_draw_list_discard(GPUDrawList *list)
+{
+ if (list->buffer_id) {
+ GPU_buf_free(list->buffer_id);
+ }
+ else {
+ MEM_SAFE_FREE(list->commands);
+ }
+ MEM_freeN(list);
+}
+
+void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch)
+{
+ BLI_assert(batch->phase == GPU_BATCH_READY_TO_DRAW);
+ list->batch = batch;
+ list->base_index = batch->elem ? BASE_INDEX(batch->elem) : UINT_MAX;
+ list->cmd_len = 0;
+
+ if (USE_MULTI_DRAW_INDIRECT) {
+ if (list->commands == NULL) {
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ if (list->cmd_offset >= list->buffer_size) {
+ /* Orphan buffer data and start fresh. */
+ glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW);
+ list->cmd_offset = 0;
+ }
+ GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
+ list->commands = glMapBufferRange(
+ GL_DRAW_INDIRECT_BUFFER, list->cmd_offset, list->buffer_size - list->cmd_offset, flags);
+ }
+ }
+ else {
+ list->cmd_offset = 0;
+ }
+}
+
+void GPU_draw_list_command_add(
+ GPUDrawList *list, int v_first, int v_count, int i_first, int i_count)
+{
+ BLI_assert(list->commands);
+
+ if (v_count == 0 || i_count == 0) {
+ return;
+ }
+
+ if (list->base_index != UINT_MAX) {
+ GPUDrawCommandIndexed *cmd = list->commands_indexed + list->cmd_len;
+ cmd->v_first = v_first;
+ cmd->v_count = v_count;
+ cmd->i_count = i_count;
+ cmd->base_index = list->base_index;
+ cmd->i_first = i_first;
+ }
+ else {
+ GPUDrawCommand *cmd = list->commands + list->cmd_len;
+ cmd->v_first = v_first;
+ cmd->v_count = v_count;
+ cmd->i_count = i_count;
+ cmd->i_first = i_first;
+ }
+
+ list->cmd_len++;
+ uint offset = list->cmd_offset + list->cmd_len * sizeof(GPUDrawCommandIndexed);
+
+ if (offset == list->buffer_size) {
+ GPU_draw_list_submit(list);
+ GPU_draw_list_init(list, list->batch);
+ }
+}
+
+void GPU_draw_list_submit(GPUDrawList *list)
+{
+ GPUBatch *batch = list->batch;
+
+ if (list->cmd_len == 0) {
+ return;
+ }
+
+ BLI_assert(list->commands);
+ BLI_assert(batch->program_in_use);
+ /* TODO could assert that VAO is bound. */
+
+ /* TODO We loose a bit of memory here if we only draw arrays. Fix that. */
+ uintptr_t offset = list->cmd_offset;
+ uint cmd_len = list->cmd_len;
+ size_t bytes_used = cmd_len * sizeof(GPUDrawCommandIndexed);
+ list->cmd_len = 0; /* Avoid reuse. */
+
+ /* Only do multi-draw indirect if doing more than 2 drawcall.
+ * This avoids the overhead of buffer mapping if scene is
+ * not very instance friendly. */
+ if (USE_MULTI_DRAW_INDIRECT && cmd_len > 2) {
+ GLenum prim = batch->gl_prim_type;
+
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id);
+ glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, bytes_used);
+ glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
+ list->commands = NULL; /* Unmapped */
+ list->cmd_offset += bytes_used;
+
+ if (batch->elem) {
+ glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch->elem), (void *)offset, cmd_len, 0);
+ }
+ else {
+ glMultiDrawArraysIndirect(prim, (void *)offset, cmd_len, 0);
+ }
+ }
+ else {
+ /* Fallback */
+ if (batch->elem) {
+ GPUDrawCommandIndexed *cmd = list->commands_indexed;
+ for (int i = 0; i < cmd_len; i++, cmd++) {
+ /* Index start was added by Draw manager. Avoid counting it twice. */
+ cmd->v_first -= batch->elem->index_start;
+ GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ }
+ else {
+ GPUDrawCommand *cmd = list->commands;
+ for (int i = 0; i < cmd_len; i++, cmd++) {
+ GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count);
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c
index 3a8b392ef1d..825f72e175b 100644
--- a/source/blender/gpu/intern/gpu_batch_utils.c
+++ b/source/blender/gpu/intern/gpu_batch_utils.c
@@ -164,7 +164,6 @@ GPUBatch *GPU_batch_wire_from_poly_2d_encoded(const uchar *polys_flat,
BLI_assert(polys_step_len >= 2);
for (uint i_prev = polys_step_len - 1, i = 0; i < polys_step_len; i_prev = i++) {
union {
- uint8_t as_u8[4];
uint16_t as_u16[2];
uint32_t as_u32;
} data;
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 3511c7438cb..2c74afd2d8e 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -45,6 +45,8 @@
#include "GPU_buffers.h"
#include "GPU_batch.h"
+#include "gpu_private.h"
+
#include "bmesh.h"
/* XXX: the rest of the code in this file is used for optimized PBVH
@@ -78,6 +80,7 @@ struct GPU_PBVH_Buffers {
int totgrid;
bool use_bmesh;
+ bool clear_bmesh_on_flush;
uint tot_tri, tot_quad;
@@ -91,8 +94,9 @@ struct GPU_PBVH_Buffers {
};
static struct {
+ GPUVertFormat format;
uint pos, nor, msk, col;
-} g_vbo_id = {0};
+} g_vbo_id = {{0}};
/** \} */
@@ -100,6 +104,27 @@ static struct {
/** \name PBVH Utils
* \{ */
+void gpu_pbvh_init()
+{
+ /* Initialize vertex buffer (match 'VertexBufferFormat'). */
+ if (g_vbo_id.format.attr_len == 0) {
+ g_vbo_id.pos = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ g_vbo_id.nor = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
+ g_vbo_id.msk = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ g_vbo_id.col = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+}
+
+void gpu_pbvh_exit()
+{
+ /* Nothing to do. */
+}
+
/* Allocates a non-initialized buffer to be sent to GPU.
* Return is false it indicates that the memory map failed. */
static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
@@ -110,14 +135,7 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
#if 0
if (buffers->vert_buf == NULL) {
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DYNAMIC);
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
}
else if (vert_len != buffers->vert_buf->vertex_len) {
@@ -126,30 +144,16 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
#else
if (buffers->vert_buf == NULL) {
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
- g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- g_vbo_id.col = GPU_vertformat_attr_add(
- &format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STATIC);
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC);
}
GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
#endif
+
return buffers->vert_buf->data != NULL;
}
static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim)
{
- /* force flushing to the GPU */
- if (buffers->vert_buf->data) {
- GPU_vertbuf_use(buffers->vert_buf);
- }
-
if (buffers->triangles == NULL) {
buffers->triangles = GPU_batch_create(prim,
buffers->vert_buf,
@@ -180,6 +184,7 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim)
/** \name Mesh PBVH
* \{ */
+/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
const int *vert_indices,
@@ -189,8 +194,8 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int (*face_vert_indices)[3],
const int update_flags)
{
- const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
- const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
+ const bool show_vcol = vcol && (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
bool empty_mask = true;
{
@@ -198,30 +203,38 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Build VBO */
if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
+ GPUVertBufRaw pos_step = {0};
+ GPUVertBufRaw nor_step = {0};
+ GPUVertBufRaw msk_step = {0};
+ GPUVertBufRaw col_step = {0};
+
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step);
+ if (show_mask) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step);
+ }
+ if (show_vcol) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step);
+ }
+
/* Vertex data is shared if smooth-shaded, but separate
* copies are made for flat shading because normals
* shouldn't be shared. */
if (buffers->smooth) {
for (uint i = 0; i < totvert; i++) {
- const MVert *v = &mvert[vert_indices[i]];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, i, v->co);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, i, v->no);
- }
-
- if (vmask && show_mask) {
- for (uint i = 0; i < buffers->face_indices_len; i++) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- for (uint j = 0; j < 3; j++) {
- int vidx = face_vert_indices[i][j];
- int v_index = buffers->mloop[lt->tri[j]].v;
- float fmask = vmask[v_index];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vidx, &fmask);
- empty_mask = empty_mask && (fmask == 0.0f);
- }
+ const int vidx = vert_indices[i];
+ const MVert *v = &mvert[vidx];
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
+ copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), v->no);
+
+ if (show_mask) {
+ float mask = vmask[vidx];
+ *(float *)GPU_vertbuf_raw_step(&msk_step) = mask;
+ empty_mask = empty_mask && (mask == 0.0f);
}
}
- if (vcol && show_vcol) {
+ if (show_vcol) {
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
for (int j = 0; j < 3; j++) {
@@ -236,8 +249,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
else {
/* calculate normal for each polygon only once */
uint mpoly_prev = UINT_MAX;
- short no[3];
- int vbo_index = 0;
+ short no[3] = {0, 0, 0};
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
@@ -261,27 +273,26 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
}
float fmask = 0.0f;
- if (vmask && show_mask) {
+ if (show_mask) {
fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
}
for (uint j = 0; j < 3; j++) {
const MVert *v = &mvert[vtri[j]];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, v->co);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &fmask);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
+ copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
+ if (show_mask) {
+ *(float *)GPU_vertbuf_raw_step(&msk_step) = fmask;
+ empty_mask = empty_mask && (fmask == 0.0f);
+ }
- if (vcol && show_vcol) {
+ if (show_vcol) {
const uint loop_index = lt->tri[j];
const uchar *elem = &vcol[loop_index].r;
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, elem);
+ memcpy(GPU_vertbuf_raw_step(&col_step), elem, sizeof(uchar) * 4);
}
-
- vbo_index++;
}
-
- empty_mask = empty_mask && (fmask == 0.0f);
}
}
@@ -298,16 +309,19 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->mvert = mvert;
}
+/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
const MPoly *mpoly,
const MLoop *mloop,
const MLoopTri *looptri,
const MVert *mvert,
const int *face_indices,
- const int face_indices_len)
+ const int face_indices_len,
+ const struct Mesh *mesh)
{
GPU_PBVH_Buffers *buffers;
int i, tottri;
+ int tot_real_edges = 0;
buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers");
@@ -320,6 +334,13 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
for (i = 0, tottri = 0; i < face_indices_len; i++) {
const MLoopTri *lt = &looptri[face_indices[i]];
if (!paint_is_face_hidden(lt, mvert, mloop)) {
+ int r_edges[3];
+ BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges);
+ for (int j = 0; j < 3; j++) {
+ if (r_edges[j] != -1) {
+ tot_real_edges++;
+ }
+ }
tottri++;
}
}
@@ -336,11 +357,6 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
return buffers;
}
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
-
/* An element index buffer is used for smooth shading, but flat
* shading requires separate vertex normals so an index buffer
* can't be used there. */
@@ -348,7 +364,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
/* Fill the triangle and line buffers. */
GPUIndexBufBuilder elb, elb_lines;
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, INT_MAX);
- GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX);
+ GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX);
for (i = 0; i < face_indices_len; i++) {
const MLoopTri *lt = &looptri[face_indices[i]];
@@ -359,11 +375,18 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
}
GPU_indexbuf_add_tri_verts(&elb, UNPACK3(face_vert_indices[i]));
+ int r_edges[3];
+ BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges);
- /* TODO skip "non-real" edges. */
- GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][0], face_vert_indices[i][1]);
- GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][1], face_vert_indices[i][2]);
- GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][2], face_vert_indices[i][0]);
+ if (r_edges[0] != -1) {
+ GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][0], face_vert_indices[i][1]);
+ }
+ if (r_edges[1] != -1) {
+ GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][1], face_vert_indices[i][2]);
+ }
+ if (r_edges[2] != -1) {
+ GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][2], face_vert_indices[i][0]);
+ }
}
buffers->index_buf = GPU_indexbuf_build(&elb);
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
@@ -371,7 +394,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
else {
/* Fill the only the line buffer. */
GPUIndexBufBuilder elb_lines;
- GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX);
+ GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX);
int vert_idx = 0;
for (i = 0; i < face_indices_len; i++) {
@@ -382,10 +405,18 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
continue;
}
- /* TODO skip "non-real" edges. */
- GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1);
- GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2);
- GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0);
+ int r_edges[3];
+ BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges);
+ if (r_edges[0] != -1) {
+ GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1);
+ }
+ if (r_edges[1] != -1) {
+ GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2);
+ }
+ if (r_edges[2] != -1) {
+ GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0);
+ }
+
vert_idx++;
}
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
@@ -537,6 +568,27 @@ static void gpu_pbvh_grid_fill_index_buffers(
buffers->index_lines_buf_fast = GPU_indexbuf_build(&elb_lines_fast);
}
+void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
+ const struct DMFlagMat *grid_flag_mats,
+ int *grid_indices)
+{
+ const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
+
+ if (buffers->smooth != smooth) {
+ buffers->smooth = smooth;
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines_fast);
+
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast);
+ }
+}
+
+/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
CCGElem **grids,
const DMFlagMat *grid_flag_mats,
@@ -550,26 +602,13 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
bool empty_mask = true;
int i, j, k, x, y;
- const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
-
/* Build VBO */
const int has_mask = key->has_mask;
- uint vert_per_grid = (smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4);
- uint vert_count = totgrid * vert_per_grid;
-
- if (buffers->smooth != smooth) {
- buffers->smooth = smooth;
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_BATCH_DISCARD_SAFE(buffers->lines_fast);
+ buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast);
- }
+ uint vert_per_grid = (buffers->smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4);
+ uint vert_count = totgrid * vert_per_grid;
if (buffers->index_buf == NULL) {
uint visible_quad_len = BKE_pbvh_count_grid_quads(
@@ -692,6 +731,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->show_mask = !empty_mask;
}
+/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden)
{
GPU_PBVH_Buffers *buffers;
@@ -713,47 +753,36 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid
/** \name BMesh PBVH
* \{ */
-/* Output a BMVert into a VertexBufferFormat array
- *
- * The vertex is skipped if hidden, otherwise the output goes into
- * index '*v_index' in the 'vert_data' array and '*v_index' is
- * incremented.
- */
-static void gpu_bmesh_vert_to_buffer_copy__gwn(BMVert *v,
- GPUVertBuf *vert_buf,
- int *v_index,
- const float fno[3],
- const float *fmask,
- const int cd_vert_mask_offset,
- const bool show_mask,
- const bool show_vcol,
- bool *empty_mask)
+/* Output a BMVert into a VertexBufferFormat array at v_index. */
+static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
+ GPUVertBuf *vert_buf,
+ int v_index,
+ const float fno[3],
+ const float *fmask,
+ const int cd_vert_mask_offset,
+ const bool show_mask,
+ const bool show_vcol,
+ bool *empty_mask)
{
- if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ /* Vertex should always be visible if it's used by a visible face. */
+ BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN));
- /* Set coord, normal, and mask */
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, *v_index, v->co);
+ /* Set coord, normal, and mask */
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co);
- short no_short[3];
- normal_float_to_short_v3(no_short, fno ? fno : v->no);
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, *v_index, no_short);
+ short no_short[3];
+ normal_float_to_short_v3(no_short, fno ? fno : v->no);
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short);
- if (show_mask) {
- float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, *v_index, &effective_mask);
- *empty_mask = *empty_mask && (effective_mask == 0.0f);
- }
-
- if (show_vcol) {
- static char vcol[4] = {255, 255, 255, 255};
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, *v_index, &vcol);
- }
-
- /* Assign index for use in the triangle index buffer */
- /* note: caller must set: bm->elem_index_dirty |= BM_VERT; */
- BM_elem_index_set(v, (*v_index)); /* set_dirty! */
+ if (show_mask) {
+ float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &effective_mask);
+ *empty_mask = *empty_mask && (effective_mask == 0.0f);
+ }
- (*v_index)++;
+ if (show_vcol) {
+ static char vcol[4] = {255, 255, 255, 255};
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol);
}
}
@@ -796,8 +825,24 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces)
return totface;
}
+void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
+{
+ if (buffers->smooth) {
+ /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ }
+ else {
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ }
+}
+
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
- * shading, an element index buffer. */
+ * shading, an element index buffer.
+ * Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
GSet *bm_faces,
@@ -807,7 +852,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
{
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
- int tottri, totvert, maxvert = 0;
+ int tottri, totvert;
bool empty_mask = true;
BMFace *f = NULL;
@@ -815,17 +860,10 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
tottri = gpu_bmesh_face_visible_count(bm_faces);
if (buffers->smooth) {
- /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
/* Count visible vertices */
totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts);
}
else {
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
totvert = tottri * 3;
}
@@ -834,9 +872,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Node is just hidden. */
}
else {
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+ buffers->clear_bmesh_on_flush = true;
}
buffers->tot_tri = 0;
return;
@@ -846,135 +882,118 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
/* Fill vertex buffer */
- if (gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
- int v_index = 0;
-
- if (buffers->smooth) {
- GSetIterator gs_iter;
-
- /* Vertices get an index assigned for use in the triangle
- * index buffer */
- bm->elem_index_dirty |= BM_VERT;
-
- GSET_ITER (gs_iter, bm_unique_verts) {
- gpu_bmesh_vert_to_buffer_copy__gwn(BLI_gsetIterator_getKey(&gs_iter),
- buffers->vert_buf,
- &v_index,
- NULL,
- NULL,
- cd_vert_mask_offset,
- show_mask,
- show_vcol,
- &empty_mask);
- }
-
- GSET_ITER (gs_iter, bm_other_verts) {
- gpu_bmesh_vert_to_buffer_copy__gwn(BLI_gsetIterator_getKey(&gs_iter),
- buffers->vert_buf,
- &v_index,
- NULL,
- NULL,
- cd_vert_mask_offset,
- show_mask,
- show_vcol,
- &empty_mask);
- }
+ if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
+ /* Memory map failed */
+ return;
+ }
- maxvert = v_index;
- }
- else {
- GSetIterator gs_iter;
+ int v_index = 0;
- GPUIndexBufBuilder elb_lines;
- GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert);
+ if (buffers->smooth) {
+ /* Fill the vertex and triangle buffer in one pass over faces. */
+ GPUIndexBufBuilder elb, elb_lines;
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert);
+ GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert);
- GSET_ITER (gs_iter, bm_faces) {
- f = BLI_gsetIterator_getKey(&gs_iter);
+ GHash *bm_vert_to_index = BLI_ghash_int_new_ex("bm_vert_to_index", totvert);
- BLI_assert(f->len == 3);
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, bm_faces) {
+ f = BLI_gsetIterator_getKey(&gs_iter);
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BMVert *v[3];
- float fmask = 0.0f;
- int i;
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ BMVert *v[3];
+ BM_face_as_array_vert_tri(f, v);
- BM_face_as_array_vert_tri(f, v);
+ uint idx[3];
+ for (int i = 0; i < 3; i++) {
+ void **idx_p;
+ if (!BLI_ghash_ensure_p(bm_vert_to_index, v[i], &idx_p)) {
+ /* Add vertex to the vertex buffer each time a new one is encountered */
+ *idx_p = POINTER_FROM_UINT(v_index);
- /* Average mask value */
- for (i = 0; i < 3; i++) {
- fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset);
+ gpu_bmesh_vert_to_buffer_copy(v[i],
+ buffers->vert_buf,
+ v_index,
+ NULL,
+ NULL,
+ cd_vert_mask_offset,
+ show_mask,
+ show_vcol,
+ &empty_mask);
+
+ idx[i] = v_index;
+ v_index++;
}
- fmask /= 3.0f;
-
- GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
- GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
- GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
-
- for (i = 0; i < 3; i++) {
- gpu_bmesh_vert_to_buffer_copy__gwn(v[i],
- buffers->vert_buf,
- &v_index,
- f->no,
- &fmask,
- cd_vert_mask_offset,
- show_mask,
- show_vcol,
- &empty_mask);
+ else {
+ /* Vertex already in the vertex buffer, just get the index. */
+ idx[i] = POINTER_AS_UINT(*idx_p);
}
}
- }
- buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
- buffers->tot_tri = tottri;
+ GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
+
+ GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]);
+ GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]);
+ GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]);
+ }
}
- /* gpu_bmesh_vert_to_buffer_copy sets dirty index values */
- bm->elem_index_dirty |= BM_VERT;
+ BLI_ghash_free(bm_vert_to_index, NULL, NULL);
+
+ buffers->tot_tri = tottri;
+ if (buffers->index_buf == NULL) {
+ buffers->index_buf = GPU_indexbuf_build(&elb);
+ }
+ else {
+ GPU_indexbuf_build_in_place(&elb, buffers->index_buf);
+ }
+ buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
}
else {
- /* Memory map failed */
- return;
- }
+ GSetIterator gs_iter;
- if (buffers->smooth) {
- /* Fill the triangle buffer */
- GPUIndexBufBuilder elb, elb_lines;
- GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, maxvert);
- GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, maxvert);
-
- /* Fill triangle index buffer */
- {
- GSetIterator gs_iter;
+ GPUIndexBufBuilder elb_lines;
+ GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
- GSET_ITER (gs_iter, bm_faces) {
- f = BLI_gsetIterator_getKey(&gs_iter);
+ GSET_ITER (gs_iter, bm_faces) {
+ f = BLI_gsetIterator_getKey(&gs_iter);
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BMVert *v[3];
+ BLI_assert(f->len == 3);
- BM_face_as_array_vert_tri(f, v);
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ BMVert *v[3];
+ float fmask = 0.0f;
+ int i;
- const uint idx[3] = {
- BM_elem_index_get(v[0]), BM_elem_index_get(v[1]), BM_elem_index_get(v[2])};
- GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
+ BM_face_as_array_vert_tri(f, v);
- GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]);
- GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]);
- GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]);
+ /* Average mask value */
+ for (i = 0; i < 3; i++) {
+ fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset);
+ }
+ fmask /= 3.0f;
+
+ GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
+ GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
+ GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
+
+ for (i = 0; i < 3; i++) {
+ gpu_bmesh_vert_to_buffer_copy(v[i],
+ buffers->vert_buf,
+ v_index++,
+ f->no,
+ &fmask,
+ cd_vert_mask_offset,
+ show_mask,
+ show_vcol,
+ &empty_mask);
}
}
-
- buffers->tot_tri = tottri;
-
- if (buffers->index_buf == NULL) {
- buffers->index_buf = GPU_indexbuf_build(&elb);
- }
- else {
- GPU_indexbuf_build_in_place(&elb, buffers->index_buf);
- }
-
- buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
}
+
+ buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
+ buffers->tot_tri = tottri;
}
/* Get material index from the last face we iterated on. */
@@ -991,6 +1010,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/** \name Generic
* \{ */
+/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
{
GPU_PBVH_Buffers *buffers;
@@ -1023,6 +1043,22 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers)
return buffers->material_index;
}
+void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers)
+{
+ /* Free empty bmesh node buffers. */
+ if (buffers->clear_bmesh_on_flush) {
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+ buffers->clear_bmesh_on_flush = false;
+ }
+
+ /* Force flushing to the GPU. */
+ if (buffers->vert_buf && buffers->vert_buf->data) {
+ GPU_vertbuf_use(buffers->vert_buf);
+ }
+}
+
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
{
if (buffers) {
@@ -1041,7 +1077,3 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
}
/** \} */
-
-void GPU_pbvh_fix_linking()
-{
-}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 7483be74e01..410e23c9576 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -55,6 +55,12 @@
#include <string.h>
#include <stdarg.h>
+extern char datatoc_gpu_shader_material_glsl[];
+extern char datatoc_gpu_shader_geometry_glsl[];
+
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
/* -------------------- GPUPass Cache ------------------ */
/**
* Internal shader cache: This prevent the shader recompilation / stall when
@@ -778,6 +784,12 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
else if (input->builtin == GPU_OBJECT_MATRIX) {
BLI_dynstr_append(ds, "objmat");
}
+ else if (input->builtin == GPU_OBJECT_INFO) {
+ BLI_dynstr_append(ds, "ObjectInfo");
+ }
+ else if (input->builtin == GPU_OBJECT_COLOR) {
+ BLI_dynstr_append(ds, "ObjectColor");
+ }
else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) {
BLI_dynstr_append(ds, "objinv");
}
@@ -840,6 +852,10 @@ static char *code_generate_fragment(GPUMaterial *material,
codegen_set_unique_ids(nodes);
*rbuiltins = builtins = codegen_process_uniforms_functions(material, ds, nodes);
+ if (builtins & (GPU_OBJECT_INFO | GPU_OBJECT_COLOR)) {
+ BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
+ }
+
if (builtins & GPU_BARYCENTRIC_TEXCO) {
BLI_dynstr_append(ds, "in vec2 barycentricTexCo;\n");
}
@@ -988,7 +1004,7 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
/* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
if (input->attr_type == CD_ORCO) {
/* OPTI : orco is computed from local positions, but only if no modifier is present. */
- BLI_dynstr_append(ds, "uniform vec3 OrcoTexCoFactors[2];\n");
+ BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n");
}
else if (input->attr_name[0] == '\0') {
@@ -1070,6 +1086,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds, "\n");
+ BLI_dynstr_append(ds, use_geom ? "RESOURCE_ID_VARYING_GEOM\n" : "RESOURCE_ID_VARYING\n");
+
BLI_dynstr_append(ds,
"#define USE_ATTR\n"
"vec3 srgb_to_linear_attr(vec3 c) {\n"
@@ -1099,6 +1117,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds, "void pass_attr(in vec3 position) {\n");
+ BLI_dynstr_append(ds, use_geom ? "\tPASS_RESOURCE_ID_GEOM\n" : "\tPASS_RESOURCE_ID\n");
+
BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
if (builtins & GPU_BARYCENTRIC_TEXCO) {
@@ -1125,8 +1145,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_ORCO) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0] + (ModelMatrixInverse * "
- "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1];\n",
+ "\tvar%d%s = OrcoTexCoFactors[0].xyz + (ModelMatrixInverse * "
+ "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1].xyz;\n",
input->attr_id,
use_geom ? "g" : "");
/* TODO: fix ORCO with modifiers. */
@@ -1181,7 +1201,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
}
else if (input->attr_type == CD_ORCO) {
BLI_dynstr_appendf(ds,
- "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n",
+ "\tvar%d%s = OrcoTexCoFactors[0].xyz + position *"
+ " OrcoTexCoFactors[1].xyz;\n",
input->attr_id,
use_geom ? "g" : "");
/* See mesh_create_loop_orco() for explanation. */
@@ -1296,6 +1317,8 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "out vec3 worldNormal;\n");
BLI_dynstr_append(ds, "out vec3 viewNormal;\n");
+ BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
+
BLI_dynstr_append(ds, "void main(){\n");
if (builtins & GPU_BARYCENTRIC_DIST) {
@@ -1340,9 +1363,13 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
BLI_dynstr_append(ds, "}\n");
}
+ BLI_dynstr_append(ds, "RESOURCE_ID_VARYING\n");
+
/* Generate varying assignments. */
BLI_dynstr_append(ds, "void pass_attr(in int vert) {\n");
+ BLI_dynstr_append(ds, "\tPASS_RESOURCE_ID(vert)\n");
+
/* XXX HACK: Eevee specific. */
if (geom_code == NULL) {
BLI_dynstr_append(ds, "\tworldPosition = worldPositiong[vert];\n");
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index c9ae6c60293..7fa2eb6424c 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -66,6 +66,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
+#include "GPU_platform.h"
#include "GPU_texture.h"
#include "PIL_time.h"
diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c
index 166a6236893..518829d1c78 100644
--- a/source/blender/gpu/intern/gpu_element.c
+++ b/source/blender/gpu/intern/gpu_element.c
@@ -243,7 +243,7 @@ GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uin
{
GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
BLI_assert(elem_src && !elem_src->is_subrange);
- BLI_assert(start + length <= elem_src->index_len);
+ BLI_assert((length == 0) || (start + length <= elem_src->index_len));
#if GPU_TRACK_INDEX_RANGE
elem->index_type = elem_src->index_type;
elem->gl_index_type = elem_src->gl_index_type;
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 4164db2c469..33f918559f7 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -35,6 +35,7 @@
#include "GPU_framebuffer.h"
#include "GPU_glew.h"
#include "GPU_texture.h"
+#include "GPU_platform.h"
#include "intern/gpu_private.h"
@@ -68,9 +69,6 @@ static struct GPUGlobal {
GLint maxubosize;
GLint maxubobinds;
int samples_color_texture_max;
- eGPUDeviceType device;
- eGPUOSType os;
- eGPUDriverType driver;
float line_width_range[2];
/* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
* calculate dfdy in shader differently when drawing to an offscreen buffer. First
@@ -126,13 +124,6 @@ static void gpu_detect_mip_render_workaround(void)
GPU_texture_free(tex);
}
-/* GPU Types */
-
-bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
-{
- return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
-}
-
/* GPU Extensions */
int GPU_max_texture_size(void)
@@ -266,11 +257,7 @@ void gpu_extensions_init(void)
const char *renderer = (const char *)glGetString(GL_RENDERER);
const char *version = (const char *)glGetString(GL_VERSION);
- if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) {
- GG.device = GPU_DEVICE_ATI;
- GG.driver = GPU_DRIVER_OFFICIAL;
-
-#ifdef _WIN32
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL)) {
if (strstr(version, "4.5.13399") || strstr(version, "4.5.13417") ||
strstr(version, "4.5.13422")) {
/* The renderers include:
@@ -282,76 +269,15 @@ void gpu_extensions_init(void)
GG.unused_fb_slot_workaround = true;
}
-#endif
+ }
-#if defined(__APPLE__)
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) {
if (strstr(renderer, "AMD Radeon Pro") || strstr(renderer, "AMD Radeon R9") ||
strstr(renderer, "AMD Radeon RX")) {
GG.depth_blitting_workaround = true;
}
-#endif
- }
- else if (strstr(vendor, "NVIDIA")) {
- GG.device = GPU_DEVICE_NVIDIA;
- GG.driver = GPU_DRIVER_OFFICIAL;
- }
- else if (strstr(vendor, "Intel") ||
- /* src/mesa/drivers/dri/intel/intel_context.c */
- strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) {
- GG.device = GPU_DEVICE_INTEL;
- GG.driver = GPU_DRIVER_OFFICIAL;
-
- if (strstr(renderer, "UHD Graphics") ||
- /* Not UHD but affected by the same bugs. */
- strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) {
- GG.device |= GPU_DEVICE_INTEL_UHD;
- }
- }
- else if ((strstr(renderer, "Mesa DRI R")) ||
- (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) ||
- (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) ||
- (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) ||
- (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) {
- GG.device = GPU_DEVICE_ATI;
- GG.driver = GPU_DRIVER_OPENSOURCE;
- }
- else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
- GG.device = GPU_DEVICE_NVIDIA;
- GG.driver = GPU_DRIVER_OPENSOURCE;
- }
- else if (strstr(vendor, "Mesa")) {
- GG.device = GPU_DEVICE_SOFTWARE;
- GG.driver = GPU_DRIVER_SOFTWARE;
- }
- else if (strstr(vendor, "Microsoft")) {
- GG.device = GPU_DEVICE_SOFTWARE;
- GG.driver = GPU_DRIVER_SOFTWARE;
- }
- else if (strstr(renderer, "Apple Software Renderer")) {
- GG.device = GPU_DEVICE_SOFTWARE;
- GG.driver = GPU_DRIVER_SOFTWARE;
- }
- else if (strstr(renderer, "llvmpipe")) {
- GG.device = GPU_DEVICE_SOFTWARE;
- GG.driver = GPU_DRIVER_SOFTWARE;
- }
- else {
- printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
- printf("Detected OpenGL configuration:\n");
- printf("Vendor: %s\n", vendor);
- printf("Renderer: %s\n", renderer);
- GG.device = GPU_DEVICE_ANY;
- GG.driver = GPU_DRIVER_ANY;
}
-#ifdef _WIN32
- GG.os = GPU_OS_WIN;
-#elif defined(__APPLE__)
- GG.os = GPU_OS_MAC;
-#else
- GG.os = GPU_OS_UNIX;
-#endif
-
GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance;
gpu_detect_mip_render_workaround();
@@ -365,18 +291,19 @@ void gpu_extensions_init(void)
GG.mip_render_workaround = true;
GG.depth_blitting_workaround = true;
GG.unused_fb_slot_workaround = true;
- GG.context_local_shaders_workaround = true;
+ GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary;
}
/* df/dy calculation factors, those are dependent on driver */
GG.dfdyfactors[0] = 1.0;
GG.dfdyfactors[1] = 1.0;
- if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) &&
+ strstr(version, "3.3.10750")) {
GG.dfdyfactors[0] = 1.0;
GG.dfdyfactors[1] = -1.0;
}
- else if ((GG.device == GPU_DEVICE_INTEL) && (GG.os == GPU_OS_WIN)) {
+ else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) {
if (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
strstr(version, "4.0.0 - Build 9.18.10.3186") ||
strstr(version, "4.0.0 - Build 9.18.10.3165") ||
@@ -395,6 +322,16 @@ void gpu_extensions_init(void)
GG.glew_arb_base_instance_is_supported = false;
GG.context_local_shaders_workaround = true;
}
+
+ if (strstr(version, "Build 20.19.15.4285")) {
+ /* Somehow fixes armature display issues (see T69743). */
+ GG.context_local_shaders_workaround = true;
+ }
+ }
+ else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) {
+ /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the
+ * Mesa driver */
+ GG.unused_fb_slot_workaround = true;
}
GPU_invalid_tex_init();
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index 1b68e4c85f7..a531c22365c 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -132,9 +132,11 @@ static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
const char *err = "unknown";
#define FORMAT_STATUS(X) \
- case GL_FRAMEBUFFER_##X: \
+ case GL_FRAMEBUFFER_##X: { \
err = "GL_FRAMEBUFFER_" #X; \
- break;
+ break; \
+ } \
+ ((void)0)
switch (status) {
/* success */
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 2f84a1cbd27..7b6016e11cb 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -46,7 +46,7 @@ void GPU_init(void)
}
initialized = true;
-
+ gpu_platform_init();
gpu_extensions_init(); /* must come first */
gpu_codegen_init();
@@ -62,11 +62,13 @@ void GPU_init(void)
immInit();
}
- GPU_pbvh_fix_linking();
+ gpu_pbvh_init();
}
void GPU_exit(void)
{
+ gpu_pbvh_exit();
+
if (!G.background) {
immDestroy();
}
@@ -80,7 +82,8 @@ void GPU_exit(void)
gpu_framebuffer_module_exit();
gpu_codegen_exit();
- gpu_extensions_exit(); /* must come last */
+ gpu_extensions_exit();
+ gpu_platform_exit(); /* must come last */
initialized = false;
}
diff --git a/source/blender/gpu/intern/gpu_platform.c b/source/blender/gpu/intern/gpu_platform.c
new file mode 100644
index 00000000000..871052bb070
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_platform.c
@@ -0,0 +1,229 @@
+/*
+ * 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) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Wrap OpenGL features such as textures, shaders and GLSL
+ * with checks for drivers and GPU support.
+ */
+#include "GPU_platform.h"
+#include "GPU_glew.h"
+#include "gpu_private.h"
+
+#include <string.h>
+
+#include "BLI_dynstr.h"
+#include "BLI_string.h"
+
+#include "MEM_guardedalloc.h"
+
+static struct GPUPlatformGlobal {
+ bool initialized;
+ eGPUDeviceType device;
+ eGPUOSType os;
+ eGPUDriverType driver;
+ eGPUSupportLevel support_level;
+ char *support_key;
+ char *gpu_name;
+} GPG = {false};
+
+typedef struct GPUPlatformSupportTest {
+ eGPUSupportLevel support_level;
+ eGPUDeviceType device;
+ eGPUOSType os;
+ eGPUDriverType driver;
+ const char *vendor;
+ const char *renderer;
+ const char *version;
+} GPUPlatformSupportTest;
+
+eGPUSupportLevel GPU_platform_support_level(void)
+{
+ return GPG.support_level;
+}
+
+const char *GPU_platform_support_level_key(void)
+{
+ return GPG.support_key;
+}
+
+const char *GPU_platform_gpu_name(void)
+{
+ return GPG.gpu_name;
+}
+
+/* GPU Types */
+bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
+{
+ return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver);
+}
+
+static char *gpu_platform_create_key(eGPUSupportLevel support_level,
+ const char *vendor,
+ const char *renderer,
+ const char *version)
+{
+ DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_append(ds, "{");
+ BLI_dynstr_append(ds, vendor);
+ BLI_dynstr_append(ds, "/");
+ BLI_dynstr_append(ds, renderer);
+ BLI_dynstr_append(ds, "/");
+ BLI_dynstr_append(ds, version);
+ BLI_dynstr_append(ds, "}");
+ BLI_dynstr_append(ds, "=");
+ if (support_level == GPU_SUPPORT_LEVEL_SUPPORTED) {
+ BLI_dynstr_append(ds, "SUPPORTED");
+ }
+ else if (support_level == GPU_SUPPORT_LEVEL_LIMITED) {
+ BLI_dynstr_append(ds, "LIMITED");
+ }
+ else {
+ BLI_dynstr_append(ds, "UNSUPPORTED");
+ }
+
+ char *support_key = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ BLI_str_replace_char(support_key, '\n', ' ');
+ BLI_str_replace_char(support_key, '\r', ' ');
+ return support_key;
+}
+
+static char *gpu_platform_create_gpu_name(const char *vendor,
+ const char *renderer,
+ const char *version)
+{
+ DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_append(ds, vendor);
+ BLI_dynstr_append(ds, " ");
+ BLI_dynstr_append(ds, renderer);
+ BLI_dynstr_append(ds, " ");
+ BLI_dynstr_append(ds, version);
+
+ char *gpu_name = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ BLI_str_replace_char(gpu_name, '\n', ' ');
+ BLI_str_replace_char(gpu_name, '\r', ' ');
+ return gpu_name;
+}
+
+void gpu_platform_init(void)
+{
+ if (GPG.initialized) {
+ return;
+ }
+
+#ifdef _WIN32
+ GPG.os = GPU_OS_WIN;
+#elif defined(__APPLE__)
+ GPG.os = GPU_OS_MAC;
+#else
+ GPG.os = GPU_OS_UNIX;
+#endif
+
+ const char *vendor = (const char *)glGetString(GL_VENDOR);
+ const char *renderer = (const char *)glGetString(GL_RENDERER);
+ const char *version = (const char *)glGetString(GL_VERSION);
+
+ if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) {
+ GPG.device = GPU_DEVICE_ATI;
+ GPG.driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "NVIDIA")) {
+ GPG.device = GPU_DEVICE_NVIDIA;
+ GPG.driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "Intel") ||
+ /* src/mesa/drivers/dri/intel/intel_context.c */
+ strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) {
+ GPG.device = GPU_DEVICE_INTEL;
+ GPG.driver = GPU_DRIVER_OFFICIAL;
+
+ if (strstr(renderer, "UHD Graphics") ||
+ /* Not UHD but affected by the same bugs. */
+ strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) {
+ GPG.device |= GPU_DEVICE_INTEL_UHD;
+ }
+ }
+ else if ((strstr(renderer, "Mesa DRI R")) ||
+ (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) ||
+ (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) ||
+ (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) ||
+ (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) {
+ GPG.device = GPU_DEVICE_ATI;
+ GPG.driver = GPU_DRIVER_OPENSOURCE;
+ }
+ else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
+ GPG.device = GPU_DEVICE_NVIDIA;
+ GPG.driver = GPU_DRIVER_OPENSOURCE;
+ }
+ else if (strstr(vendor, "Mesa")) {
+ GPG.device = GPU_DEVICE_SOFTWARE;
+ GPG.driver = GPU_DRIVER_SOFTWARE;
+ }
+ else if (strstr(vendor, "Microsoft")) {
+ GPG.device = GPU_DEVICE_SOFTWARE;
+ GPG.driver = GPU_DRIVER_SOFTWARE;
+ }
+ else if (strstr(renderer, "Apple Software Renderer")) {
+ GPG.device = GPU_DEVICE_SOFTWARE;
+ GPG.driver = GPU_DRIVER_SOFTWARE;
+ }
+ else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) {
+ GPG.device = GPU_DEVICE_SOFTWARE;
+ GPG.driver = GPU_DRIVER_SOFTWARE;
+ }
+ else {
+ printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
+ printf("Detected OpenGL configuration:\n");
+ printf("Vendor: %s\n", vendor);
+ printf("Renderer: %s\n", renderer);
+ GPG.device = GPU_DEVICE_ANY;
+ GPG.driver = GPU_DRIVER_ANY;
+ }
+
+ /* Detect support level */
+ if (!GLEW_VERSION_3_3) {
+ GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED;
+ }
+ else {
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) {
+ /* Old Intel drivers with known bugs that cause material properties to crash.
+ * Version Build 10.18.14.5067 is the latest available and appears to be working
+ * ok with our workarounds, so excluded from this list. */
+ if (strstr(version, "Build 7.14") || strstr(version, "Build 7.15") ||
+ strstr(version, "Build 8.15") || strstr(version, "Build 9.17") ||
+ strstr(version, "Build 9.18") || strstr(version, "Build 10.18.10.3") ||
+ strstr(version, "Build 10.18.10.4") || strstr(version, "Build 10.18.10.5") ||
+ strstr(version, "Build 10.18.14.4")) {
+ GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED;
+ }
+ }
+ }
+ GPG.support_key = gpu_platform_create_key(GPG.support_level, vendor, renderer, version);
+ GPG.gpu_name = gpu_platform_create_gpu_name(vendor, renderer, version);
+ GPG.initialized = true;
+}
+
+void gpu_platform_exit(void)
+{
+ MEM_SAFE_FREE(GPG.support_key);
+ MEM_SAFE_FREE(GPG.gpu_name);
+}
diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h
index 43b2da13e28..7846bff87f4 100644
--- a/source/blender/gpu/intern/gpu_private.h
+++ b/source/blender/gpu/intern/gpu_private.h
@@ -22,6 +22,10 @@
#define __GPU_PRIVATE_H__
/* call this before running any of the functions below */
+void gpu_platform_init(void);
+void gpu_platform_exit(void);
+
+/* call this before running any of the functions below */
void gpu_extensions_init(void);
void gpu_extensions_exit(void);
@@ -33,4 +37,8 @@ void gpu_debug_exit(void);
void gpu_framebuffer_module_init(void);
void gpu_framebuffer_module_exit(void);
+/* gpu_pbvh.c */
+void gpu_pbvh_init(void);
+void gpu_pbvh_exit(void);
+
#endif /* __GPU_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 42c21626c05..5df73d1a0c6 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -36,6 +36,7 @@
#include "DNA_space_types.h"
#include "GPU_extensions.h"
+#include "GPU_platform.h"
#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -248,6 +249,9 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
/* a #version 400 feature, but we use #version 330 maximum so use extension */
strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
}
+ if (GLEW_ARB_shader_draw_parameters) {
+ strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n");
+ }
}
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
@@ -255,6 +259,9 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
/* some useful defines to detect GPU type */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_ATI\n");
+ if (GPU_crappy_amd_driver()) {
+ strcat(defines, "#define GPU_DEPRECATED_AMD_DRIVER\n");
+ }
}
else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
strcat(defines, "#define GPU_NVIDIA\n");
diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c
index 083c5bf2b60..983c5dfc27a 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.c
+++ b/source/blender/gpu/intern/gpu_shader_interface.c
@@ -65,9 +65,8 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u)
[GPU_UNIFORM_CLIPPLANES] = "WorldClipPlanes",
[GPU_UNIFORM_COLOR] = "color",
- [GPU_UNIFORM_CALLID] = "callId",
- [GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo",
- [GPU_UNIFORM_OBJECT_COLOR] = "unfobjectcolor",
+ [GPU_UNIFORM_BASE_INSTANCE] = "baseInstance",
+ [GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk",
[GPU_UNIFORM_CUSTOM] = NULL,
[GPU_NUM_UNIFORMS] = NULL,
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index a54d90f37f5..497fc13a2c8 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -38,6 +38,7 @@
#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_framebuffer.h"
+#include "GPU_platform.h"
#include "GPU_texture.h"
#include "gpu_context_private.h"
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index fcb1a008226..615af57c1bd 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -39,6 +39,7 @@
#include "GPU_immediate.h"
#include "GPU_texture.h"
#include "GPU_viewport.h"
+#include "GPU_uniformbuffer.h"
#include "DRW_engine.h"
@@ -619,11 +620,20 @@ void GPU_viewport_free(GPUViewport *viewport)
MEM_freeN(viewport->fbl);
MEM_freeN(viewport->txl);
- if (viewport->vmempool.calls != NULL) {
- BLI_memblock_destroy(viewport->vmempool.calls, NULL);
+ if (viewport->vmempool.commands != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.commands, NULL);
}
- if (viewport->vmempool.states != NULL) {
- BLI_memblock_destroy(viewport->vmempool.states, NULL);
+ if (viewport->vmempool.commands_small != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.commands_small, NULL);
+ }
+ if (viewport->vmempool.callbuffers != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.callbuffers, NULL);
+ }
+ if (viewport->vmempool.obmats != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.obmats, NULL);
+ }
+ if (viewport->vmempool.obinfos != NULL) {
+ BLI_memblock_destroy(viewport->vmempool.obinfos, NULL);
}
if (viewport->vmempool.cullstates != NULL) {
BLI_memblock_destroy(viewport->vmempool.cullstates, NULL);
@@ -650,6 +660,13 @@ void GPU_viewport_free(GPUViewport *viewport)
BLI_memblock_destroy(viewport->vmempool.images, NULL);
}
+ for (int i = 0; i < viewport->vmempool.ubo_len; i++) {
+ GPU_uniformbuffer_free(viewport->vmempool.matrices_ubo[i]);
+ GPU_uniformbuffer_free(viewport->vmempool.obinfos_ubo[i]);
+ }
+ MEM_SAFE_FREE(viewport->vmempool.matrices_ubo);
+ MEM_SAFE_FREE(viewport->vmempool.obinfos_ubo);
+
DRW_instance_data_list_free(viewport->idatalist);
MEM_freeN(viewport->idatalist);
diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
new file mode 100644
index 00000000000..aa1d437c307
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
@@ -0,0 +1,19 @@
+
+/* Need to be included after common_view_lib.glsl for resource_id. */
+#ifndef GPU_OBINFOS_UBO
+#define GPU_OBINFOS_UBO
+struct ObjectInfos {
+ vec4 drw_OrcoTexCoFactors[2];
+ vec4 drw_ObjectColor;
+ vec4 drw_Infos;
+};
+
+layout(std140) uniform infoBlock
+{
+ /* DRW_RESOURCE_CHUNK_LEN = 512 */
+ ObjectInfos drw_infos[512];
+};
+#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
+#define ObjectInfo (drw_infos[resource_id].drw_Infos)
+#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
+#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
index 31b359dbe6d..f32c47bcec3 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
@@ -1,8 +1,5 @@
uniform mat4 ViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
/* ---- Instantiated Attrs ---- */
in float pos;
@@ -47,11 +44,12 @@ void main()
pPos = vec3(0.0);
}
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pPos, 1.0);
+ vec4 wPos = InstanceModelMatrix * vec4(pPos, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
finalColor = vec4(color, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * vec4(pPos, 1.0)).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
index d9a0ffbbdac..5bd29c55e42 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
@@ -18,13 +18,14 @@ void main()
{
float len = end - start;
vec3 sta = vec3(0.0, 0.0, -start);
- vec4 pos_4d = vec4(pos * -len + sta, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * -len + sta, 1.0);
+
+ gl_Position = ViewProjectionMatrix * wPos;
gl_PointSize = size;
finalColor = vec4(color, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
index 3e52e43beae..10228a1e985 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
@@ -1,6 +1,5 @@
uniform mat4 ViewProjectionMatrix;
-uniform mat4 ModelMatrix;
/* ---- Instantiated Attrs ---- */
in vec3 pos;
@@ -20,10 +19,10 @@ void main()
{
finalColor = color;
- vec4 pos_4d = vec4(pos * size, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
index 130f46e1e33..32db8d17572 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
@@ -1,8 +1,6 @@
uniform mat4 ViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
+
uniform int baseId;
/* ---- Instantiated Attrs ---- */
@@ -21,11 +19,11 @@ flat out uint finalId;
void main()
{
- vec4 pos_4d = vec4(pos * size, 1.0);
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d;
+ vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0);
+ gl_Position = ViewProjectionMatrix * wPos;
finalId = uint(baseId + callId);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance(wPos.xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
index eeca6e972fa..b8d31f5540a 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
@@ -9,5 +9,5 @@ in mat4 InstanceModelMatrix;
void main()
{
- gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0);
+ gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
index abe6081489d..e089aec1d92 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
@@ -92,14 +92,14 @@ void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = min(col1.rgb, col2.rgb * fac);
+ outcol.rgb = mix(col1.rgb, min(col1.rgb, col2.rgb), fac);
outcol.a = col1.a;
}
void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = max(col1.rgb, col2.rgb * fac);
+ outcol.rgb = mix(col1.rgb, max(col1.rgb, col2.rgb), fac);
outcol.a = col1.a;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
index 140213a9ed9..7af409dd410 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -113,14 +113,14 @@ void node_bsdf_principled(vec4 base_color,
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_refr;
result.radiance += out_diff * out_sheen; /* Coarse approx. */
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
mixed_ss_base_color *= alpha * (1.0 - transmission);
closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
- result.radiance += emission.rgb;
- result.radiance *= alpha;
result.transmittance = vec3(1.0 - alpha);
}
@@ -169,9 +169,11 @@ void node_bsdf_principled_dielectric(vec4 base_color,
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_diff * (diffuse + out_sheen);
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
result.radiance *= alpha;
+
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+
result.transmittance = vec3(1.0 - alpha);
}
@@ -213,9 +215,11 @@ void node_bsdf_principled_metallic(vec4 base_color,
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
result.radiance *= alpha;
+
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+
result.transmittance = vec3(1.0 - alpha);
}
@@ -267,9 +271,11 @@ void node_bsdf_principled_clearcoat(vec4 base_color,
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
result.radiance *= alpha;
+
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+
result.transmittance = vec3(1.0 - alpha);
}
@@ -333,14 +339,15 @@ void node_bsdf_principled_subsurface(vec4 base_color,
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
+ result.radiance += out_diff * out_sheen;
+ result.radiance += emission.rgb;
+ result.radiance *= alpha;
+
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
mixed_ss_base_color *= alpha * (1.0 - transmission);
closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
- result.radiance += out_diff * out_sheen;
- result.radiance += emission.rgb;
- result.radiance *= alpha;
result.transmittance = vec3(1.0 - alpha);
}
@@ -402,9 +409,9 @@ void node_bsdf_principled_glass(vec4 base_color,
result = CLOSURE_DEFAULT;
result.radiance = mix(out_refr, out_spec, fresnel);
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.radiance += emission.rgb;
result.radiance *= alpha;
+ closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
result.transmittance = vec3(1.0 - alpha);
}
#else
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 7e7e489a6c3..173c8135f96 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -218,15 +218,20 @@ typedef enum IMB_BlendMode {
} IMB_BlendMode;
void IMB_blend_color_byte(unsigned char dst[4],
- unsigned char src1[4],
- unsigned char src2[4],
+ const unsigned char src1[4],
+ const unsigned char src2[4],
IMB_BlendMode mode);
-void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode);
+void IMB_blend_color_float(float dst[4],
+ const float src1[4],
+ const float src2[4],
+ IMB_BlendMode mode);
void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop);
+void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2]);
+
void IMB_rectclip(struct ImBuf *dbuf,
- struct ImBuf *sbuf,
+ const struct ImBuf *sbuf,
int *destx,
int *desty,
int *srcx,
@@ -234,7 +239,7 @@ void IMB_rectclip(struct ImBuf *dbuf,
int *width,
int *height);
void IMB_rectcpy(struct ImBuf *drect,
- struct ImBuf *srect,
+ const struct ImBuf *srect,
int destx,
int desty,
int srcx,
@@ -242,11 +247,11 @@ void IMB_rectcpy(struct ImBuf *drect,
int width,
int height);
void IMB_rectblend(struct ImBuf *dbuf,
- struct ImBuf *obuf,
- struct ImBuf *sbuf,
+ const struct ImBuf *obuf,
+ const struct ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *mmask,
+ const unsigned short *curvemask,
+ const unsigned short *mmask,
float mask_max,
int destx,
int desty,
@@ -259,11 +264,11 @@ void IMB_rectblend(struct ImBuf *dbuf,
IMB_BlendMode mode,
bool accumulate);
void IMB_rectblend_threaded(struct ImBuf *dbuf,
- struct ImBuf *obuf,
- struct ImBuf *sbuf,
+ const struct ImBuf *obuf,
+ const struct ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *mmask,
+ const unsigned short *curvemask,
+ const unsigned short *mmask,
float mask_max,
int destx,
int desty,
@@ -477,7 +482,7 @@ int imb_get_anim_type(const char *name);
*
* \attention Defined in util.c
*/
-bool IMB_isfloat(struct ImBuf *ibuf);
+bool IMB_isfloat(const struct ImBuf *ibuf);
/* Do byte/float and colorspace conversions need to take alpha into account? */
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
@@ -695,6 +700,8 @@ void imb_freemipmapImBuf(struct ImBuf *ibuf);
bool imb_addtilesImBuf(struct ImBuf *ibuf);
void imb_freetilesImBuf(struct ImBuf *ibuf);
+void imb_freerectImbuf_all(struct ImBuf *ibuf);
+
/* threaded processors */
void IMB_processor_apply_threaded(
int buffer_lines,
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index 065c7e64d07..9ad88f24693 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -89,7 +89,7 @@ struct anim {
int ib_flags;
int curtype;
int curposition; /* index 0 = 1e, 1 = 2e, enz. */
- int duration;
+ int duration_in_frames;
int frs_sec;
double frs_sec_base;
int x, y;
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 5048414ac65..52db0b80441 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -33,7 +33,7 @@ typedef struct ImFileType {
int (*is_a)(const unsigned char *buf);
int (*is_a_filepath)(const char *name);
- int (*ftype)(const struct ImFileType *type, struct ImBuf *ibuf);
+ int (*ftype)(const struct ImFileType *type, const struct ImBuf *ibuf);
struct ImBuf *(*load)(const unsigned char *mem,
size_t size,
int flags,
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 75db3fd3c73..381de9de610 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -197,6 +197,17 @@ void IMB_freezbuffloatImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_zbuffloat;
}
+/** Free all pixel data (assosiated with image size). */
+void imb_freerectImbuf_all(ImBuf *ibuf)
+{
+ imb_freerectImBuf(ibuf);
+ imb_freerectfloatImBuf(ibuf);
+ imb_freetilesImBuf(ibuf);
+ IMB_freezbufImBuf(ibuf);
+ IMB_freezbuffloatImBuf(ibuf);
+ freeencodedbufferImBuf(ibuf);
+}
+
void IMB_freeImBuf(ImBuf *ibuf)
{
if (ibuf) {
@@ -212,12 +223,7 @@ void IMB_freeImBuf(ImBuf *ibuf)
BLI_spin_unlock(&refcounter_spin);
if (needs_free) {
- imb_freerectImBuf(ibuf);
- imb_freerectfloatImBuf(ibuf);
- imb_freetilesImBuf(ibuf);
- IMB_freezbufImBuf(ibuf);
- IMB_freezbuffloatImBuf(ibuf);
- freeencodedbufferImBuf(ibuf);
+ imb_freerectImbuf_all(ibuf);
IMB_metadata_free(ibuf->metadata);
colormanage_cache_free(ibuf);
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 52d8db95054..232a9998ebf 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -199,7 +199,7 @@ static void free_anim_avi(struct anim *anim)
}
# endif
- anim->duration = 0;
+ anim->duration_in_frames = 0;
}
#endif /* WITH_AVI */
@@ -408,7 +408,7 @@ static int startavi(struct anim *anim)
return -1;
}
- anim->duration = anim->avi->header->TotalFrames;
+ anim->duration_in_frames = anim->avi->header->TotalFrames;
anim->params = NULL;
anim->x = anim->avi->header->Width;
@@ -426,7 +426,7 @@ static int startavi(struct anim *anim)
anim->y,
anim->framesize,
anim->interlacing,
- anim->duration);
+ anim->duration_in_frames);
# endif
return 0;
@@ -493,12 +493,13 @@ BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim)
static int startffmpeg(struct anim *anim)
{
- int i, videoStream;
+ int i, video_stream_index;
AVCodec *pCodec;
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *pCodecCtx;
AVRational frame_rate;
+ AVStream *video_stream;
int frs_num;
double frs_den;
int streamcount;
@@ -528,7 +529,7 @@ static int startffmpeg(struct anim *anim)
av_dump_format(pFormatCtx, 0, anim->name, 0);
/* Find the video stream */
- videoStream = -1;
+ video_stream_index = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
@@ -536,17 +537,18 @@ static int startffmpeg(struct anim *anim)
streamcount--;
continue;
}
- videoStream = i;
+ video_stream_index = i;
break;
}
}
- if (videoStream == -1) {
+ if (video_stream_index == -1) {
avformat_close_input(&pFormatCtx);
return -1;
}
- pCodecCtx = pFormatCtx->streams[videoStream]->codec;
+ video_stream = pFormatCtx->streams[video_stream_index];
+ pCodecCtx = video_stream->codec;
/* Find the decoder for the video stream */
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
@@ -567,12 +569,29 @@ static int startffmpeg(struct anim *anim)
return -1;
}
- frame_rate = av_get_r_frame_rate_compat(pFormatCtx, pFormatCtx->streams[videoStream]);
- if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
- anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
+ frame_rate = av_guess_frame_rate(pFormatCtx, video_stream, NULL);
+ anim->duration_in_frames = 0;
+
+ /* Take from the stream if we can. */
+ if (video_stream->nb_frames != 0) {
+ anim->duration_in_frames = video_stream->nb_frames;
+
+ /* Sanity check on the detected duration. This is to work around corruption like reported in
+ * T68091. */
+ if (frame_rate.den != 0 && pFormatCtx->duration > 0) {
+ double stream_sec = anim->duration_in_frames * av_q2d(frame_rate);
+ double container_sec = pFormatCtx->duration / (double)AV_TIME_BASE;
+ if (stream_sec > 4.0 * container_sec) {
+ /* The stream is significantly longer than the container duration, which is
+ * suspicious. */
+ anim->duration_in_frames = 0;
+ }
+ }
}
- else {
- anim->duration = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE + 0.5f);
+ /* Fall back to the container. */
+ if (anim->duration_in_frames == 0) {
+ anim->duration_in_frames = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE +
+ 0.5f);
}
frs_num = frame_rate.num;
@@ -596,7 +615,7 @@ static int startffmpeg(struct anim *anim)
anim->pFormatCtx = pFormatCtx;
anim->pCodecCtx = pCodecCtx;
anim->pCodec = pCodec;
- anim->videoStream = videoStream;
+ anim->videoStream = video_stream_index;
anim->interlacing = 0;
anim->orientation = 0;
@@ -1038,7 +1057,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
v_st = anim->pFormatCtx->streams[anim->videoStream];
- frame_rate = av_q2d(av_get_r_frame_rate_compat(anim->pFormatCtx, v_st));
+ frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
st_time = anim->pFormatCtx->start_time;
pts_time_base = av_q2d(v_st->time_base);
@@ -1222,7 +1241,7 @@ static void free_anim_ffmpeg(struct anim *anim)
av_free_packet(&anim->next_packet);
}
}
- anim->duration = 0;
+ anim->duration_in_frames = 0;
}
#endif
@@ -1259,7 +1278,7 @@ static ImBuf *anim_getnew(struct anim *anim)
ibuf = IMB_loadiffname(anim->name, anim->ib_flags, anim->colorspace);
if (ibuf) {
BLI_strncpy(anim->first, anim->name, sizeof(anim->first));
- anim->duration = 1;
+ anim->duration_in_frames = 1;
}
break;
case ANIM_MOVIE:
@@ -1297,7 +1316,7 @@ struct ImBuf *IMB_anim_previewframe(struct anim *anim)
ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (ibuf) {
IMB_freeImBuf(ibuf);
- position = anim->duration / 2;
+ position = anim->duration_in_frames / 2;
ibuf = IMB_anim_absolute(anim, position, IMB_TC_NONE, IMB_PROXY_NONE);
}
return ibuf;
@@ -1333,7 +1352,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
if (position < 0) {
return (NULL);
}
- if (position >= anim->duration) {
+ if (position >= anim->duration_in_frames) {
return (NULL);
}
}
@@ -1398,12 +1417,12 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
{
struct anim_index *idx;
if (tc == IMB_TC_NONE) {
- return anim->duration;
+ return anim->duration_in_frames;
}
idx = IMB_anim_open_index(anim, tc);
if (!idx) {
- return anim->duration;
+ return anim->duration_in_frames;
}
return IMB_indexer_get_duration(idx);
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index d1b3bf21e23..c6f8bab325b 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -40,11 +40,11 @@
# include "dds/dds_api.h"
#endif
-static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_default(const ImFileType *type, const ImBuf *ibuf)
{
return (ibuf->ftype == type->filetype);
}
-static int imb_ftype_iris(const ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_iris(const ImFileType *type, const ImBuf *ibuf)
{
(void)type;
return (ibuf->ftype == IMB_FTYPE_IMAGIC);
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 49e9c4c54d2..ec03a0a07b8 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -401,11 +401,6 @@ typedef struct ScanlineGlobalData {
int total_scanlines;
} ScanlineGlobalData;
-typedef struct ScanlineTask {
- int start_scanline;
- int num_scanlines;
-} ScanlineTask;
-
static void processor_apply_scanline_func(TaskPool *__restrict pool,
void *taskdata,
int UNUSED(threadid))
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 66e0a681f8f..97a0cc85301 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -900,7 +900,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
stream_size = avio_size(context->iFormatCtx->pb);
- context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iFormatCtx, context->iStream));
+ context->frame_rate = av_q2d(av_guess_frame_rate(context->iFormatCtx, context->iStream, NULL));
context->pts_time_base = av_q2d(context->iStream->time_base);
while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 3bf97cb851f..e361df1304a 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -83,7 +83,7 @@ static OPJ_CODEC_FORMAT format_from_header(const unsigned char mem[JP2_FILEHEADE
int imb_is_a_jp2(const unsigned char *buf)
{
- return check_jp2(buf);
+ return (check_jp2(buf) || check_j2k(buf));
}
/**
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 76918c216f7..7150e41841b 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -39,8 +39,8 @@
#include "MEM_guardedalloc.h"
void IMB_blend_color_byte(unsigned char dst[4],
- unsigned char src1[4],
- unsigned char src2[4],
+ const unsigned char src1[4],
+ const unsigned char src2[4],
IMB_BlendMode mode)
{
switch (mode) {
@@ -126,7 +126,10 @@ void IMB_blend_color_byte(unsigned char dst[4],
}
}
-void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode)
+void IMB_blend_color_float(float dst[4],
+ const float src1[4],
+ const float src2[4],
+ IMB_BlendMode mode)
{
switch (mode) {
case IMB_BLEND_MIX:
@@ -259,7 +262,7 @@ void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
BLI_rcti_size_x(crop) + 1,
BLI_rcti_size_y(crop) + 1,
};
- BLI_assert(size_dst[0] > 0 && size_dst[0] > 0);
+ BLI_assert(size_dst[0] > 0 && size_dst[1] > 0);
BLI_assert(crop->xmin >= 0 && crop->ymin >= 0);
BLI_assert(crop->xmax < ibuf->x && crop->ymax < ibuf->y);
@@ -276,10 +279,49 @@ void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
ibuf->y = size_dst[1];
}
+/** Re-alloc buffers at a new size */
+
+static void rect_realloc_4bytes(void **buf_p, const uint size[2])
+{
+ if (*buf_p == NULL) {
+ return;
+ }
+ MEM_freeN(*buf_p);
+ *buf_p = MEM_mallocN(sizeof(uint) * size[0] * size[1], __func__);
+}
+
+static void rect_realloc_16bytes(void **buf_p, const uint size[2])
+{
+ if (*buf_p == NULL) {
+ return;
+ }
+ MEM_freeN(*buf_p);
+ *buf_p = MEM_mallocN(sizeof(uint[4]) * size[0] * size[1], __func__);
+}
+
+/**
+ * In-place size setting (caller must fill in buffer contents).
+ */
+void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
+{
+ BLI_assert(size[0] > 0 && size[1] > 0);
+ if ((size[0] == ibuf->x) && (size[1] == ibuf->y)) {
+ return;
+ }
+
+ rect_realloc_4bytes((void **)&ibuf->rect, size);
+ rect_realloc_4bytes((void **)&ibuf->zbuf, size);
+ rect_realloc_4bytes((void **)&ibuf->zbuf_float, size);
+ rect_realloc_16bytes((void **)&ibuf->rect_float, size);
+
+ ibuf->x = size[0];
+ ibuf->y = size[1];
+}
+
/* clipping */
void IMB_rectclip(ImBuf *dbuf,
- ImBuf *sbuf,
+ const ImBuf *sbuf,
int *destx,
int *desty,
int *srcx,
@@ -341,8 +383,8 @@ void IMB_rectclip(ImBuf *dbuf,
}
static void imb_rectclip3(ImBuf *dbuf,
- ImBuf *obuf,
- ImBuf *sbuf,
+ const ImBuf *obuf,
+ const ImBuf *sbuf,
int *destx,
int *desty,
int *origx,
@@ -435,8 +477,14 @@ static void imb_rectclip3(ImBuf *dbuf,
/* copy and blend */
-void IMB_rectcpy(
- ImBuf *dbuf, ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height)
+void IMB_rectcpy(ImBuf *dbuf,
+ const ImBuf *sbuf,
+ int destx,
+ int desty,
+ int srcx,
+ int srcy,
+ int width,
+ int height)
{
IMB_rectblend(dbuf,
dbuf,
@@ -463,11 +511,11 @@ typedef void (*IMB_blend_func)(unsigned char *dst,
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
void IMB_rectblend(ImBuf *dbuf,
- ImBuf *obuf,
- ImBuf *sbuf,
+ const ImBuf *obuf,
+ const ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *texmask,
+ const unsigned short *curvemask,
+ const unsigned short *texmask,
float mask_max,
int destx,
int desty,
@@ -482,9 +530,9 @@ void IMB_rectblend(ImBuf *dbuf,
{
unsigned int *drect = NULL, *orect = NULL, *srect = NULL, *dr, * or, *sr;
float *drectf = NULL, *orectf = NULL, *srectf = NULL, *drf, *orf, *srf;
- unsigned short *cmaskrect = curvemask, *cmr;
+ const unsigned short *cmaskrect = curvemask, *cmr;
unsigned short *dmaskrect = dmask, *dmr;
- unsigned short *texmaskrect = texmask, *tmr;
+ const unsigned short *texmaskrect = texmask, *tmr;
int do_float, do_char, srcskip, destskip, origskip, x;
IMB_blend_func func = NULL;
IMB_blend_func_float func_float = NULL;
@@ -924,8 +972,10 @@ void IMB_rectblend(ImBuf *dbuf,
}
typedef struct RectBlendThreadData {
- ImBuf *dbuf, *obuf, *sbuf;
- unsigned short *dmask, *curvemask, *texmask;
+ ImBuf *dbuf;
+ const ImBuf *obuf, *sbuf;
+ unsigned short *dmask;
+ const unsigned short *curvemask, *texmask;
float mask_max;
int destx, desty, origx, origy;
int srcx, srcy, width;
@@ -956,11 +1006,11 @@ static void rectblend_thread_do(void *data_v, int start_scanline, int num_scanli
}
void IMB_rectblend_threaded(ImBuf *dbuf,
- ImBuf *obuf,
- ImBuf *sbuf,
+ const ImBuf *obuf,
+ const ImBuf *sbuf,
unsigned short *dmask,
- unsigned short *curvemask,
- unsigned short *texmask,
+ const unsigned short *curvemask,
+ const unsigned short *texmask,
float mask_max,
int destx,
int desty,
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index ff7cb87960e..27b566e25a2 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -252,6 +252,8 @@ static int isffmpeg(const char *filename)
if (BLI_path_extension_check_n(filename,
".swf",
".jpg",
+ ".jp2",
+ ".j2c",
".png",
".dds",
".tga",
@@ -389,7 +391,7 @@ bool IMB_isanim(const char *filename)
return (type && type != ANIM_SEQUENCE);
}
-bool IMB_isfloat(ImBuf *ibuf)
+bool IMB_isfloat(const ImBuf *ibuf)
{
const ImFileType *type;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index a1bc71ade62..f303f7720c3 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -477,6 +477,10 @@ enum {
/* The datablock structure is a sub-object of a different one.
* Direct persistent references are not allowed. */
LIB_PRIVATE_DATA = 1 << 10,
+ /* Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT
+ * tag set. But the current .blend file also has a weak pointer to it that
+ * we want to restore if possible, and silently drop if it's missing. */
+ LIB_INDIRECT_WEAK_LINK = 1 << 11,
};
/**
@@ -693,6 +697,14 @@ enum {
FILTER_ID_LP = (1u << 31),
};
+#define FILTER_ID_ALL \
+ (FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | FILTER_ID_GD | \
+ FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA | \
+ FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | \
+ FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO | \
+ FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | \
+ FILTER_ID_LP)
+
/* IMPORTANT: this enum matches the order currently use in set_listbasepointers,
* keep them in sync! */
enum {
diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h
index cf4e74dfd41..714c205cda2 100644
--- a/source/blender/makesdna/DNA_brush_defaults.h
+++ b/source/blender/makesdna/DNA_brush_defaults.h
@@ -40,7 +40,7 @@
/* BRUSH SCULPT TOOL SETTINGS */ \
.weight = 1.0f, /* weight of brush 0 - 1.0 */ \
.size = 35, /* radius of the brush in pixels */ \
- .alpha = 0.5f, /* brush strength/intensity probably variable should be renamed? */ \
+ .alpha = 1.0f, /* brush strength/intensity probably variable should be renamed? */ \
.autosmooth_factor = 0.0f, \
.topology_rake_factor = 0.0f, \
.crease_pinch_factor = 0.5f, \
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index a503d3b6739..fc8763f1519 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -321,11 +321,12 @@ typedef struct Brush {
int curve_preset;
int automasking_flags;
- char _pad1[4];
-
int elastic_deform_type;
float elastic_deform_volume_preservation;
+ /* pose */
+ float pose_offset;
+
/* overlay */
int texture_overlay_alpha;
int mask_overlay_alpha;
@@ -406,7 +407,7 @@ typedef enum eBrushFlags {
BRUSH_SIZE_PRESSURE = (1 << 3),
BRUSH_JITTER_PRESSURE = (1 << 4),
BRUSH_SPACING_PRESSURE = (1 << 5),
- BRUSH_FLAG_UNUSED_6 = (1 << 6), /* cleared */
+ BRUSH_ORIGINAL_PLANE = (1 << 6),
BRUSH_GRAB_ACTIVE_VERTEX = (1 << 7),
BRUSH_ANCHORED = (1 << 8),
BRUSH_DIR_IN = (1 << 9),
@@ -498,9 +499,11 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_CLAY, \
SCULPT_TOOL_CLAY_STRIPS, \
SCULPT_TOOL_ROTATE, \
+ SCULPT_TOOL_SCRAPE, \
SCULPT_TOOL_FLATTEN)
-#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK)
+#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) \
+ ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_ELASTIC_DEFORM)
#define SCULPT_TOOL_HAS_RAKE(t) ELEM(t, SCULPT_TOOL_SNAKE_HOOK)
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index bdb3db94c89..759029ad618 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -32,7 +32,6 @@
#define MAXTEXTBOX 256 /* used in readfile.c and editfont.c */
struct AnimData;
-struct BoundBox;
struct EditFont;
struct GHash;
struct Ipo;
@@ -212,8 +211,6 @@ typedef struct Curve {
/** Animation data (must be immediately after id for utilities to use it). */
struct AnimData *adt;
- struct BoundBox *bb;
-
/** Actual data, called splines in rna. */
ListBase nurb;
@@ -229,14 +226,13 @@ typedef struct Curve {
/* texture space, copied as one block in editobject.c */
float loc[3];
float size[3];
- float rot[3];
/** Creation-time type of curve datablock. */
short type;
/** Keep a short because of BKE_object_obdata_texspace_get(). */
short texflag;
- char _pad0[2];
+ char _pad0[6];
short twist_mode;
float twist_smooth, smallcaps_scale;
@@ -308,6 +304,7 @@ typedef struct Curve {
/* Curve.texflag */
enum {
CU_AUTOSPACE = 1,
+ CU_AUTOSPACE_EVALUATED = 2,
};
#if 0 /* Moved to overlay options in 2.8 */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 58962dd9469..3241e0e3cdb 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -404,6 +404,8 @@ typedef enum eGPDlayer_Flag {
GP_LAYER_USE_MASK = (1 << 13),
/* Flag used to display in Paint mode only layers with keyframe */
GP_LAYER_SOLO_MODE = (1 << 4),
+ /* Ruler Layer */
+ GP_LAYER_IS_RULER = (1 << 14),
} eGPDlayer_Flag;
/* bGPDlayer->onion_flag */
diff --git a/source/blender/makesdna/DNA_gpu_types.h b/source/blender/makesdna/DNA_gpu_types.h
index 8cab90b0a46..7d56baf86a4 100644
--- a/source/blender/makesdna/DNA_gpu_types.h
+++ b/source/blender/makesdna/DNA_gpu_types.h
@@ -24,6 +24,7 @@
#ifndef __DNA_GPU_TYPES_H__
#define __DNA_GPU_TYPES_H__
+/* Keep for 'Camera' versioning. */
/** Properties for dof effect. */
typedef struct GPUDOFSettings {
/** Focal distance for depth of field. */
@@ -37,29 +38,4 @@ typedef struct GPUDOFSettings {
int high_quality;
} GPUDOFSettings;
-/** Properties for SSAO effect. */
-typedef struct GPUSSAOSettings {
- float factor;
- float color[3];
- float distance_max;
- float attenuation;
- /** Ray samples, we use presets here for easy control instead of. */
- int samples;
- char _pad[4];
-} GPUSSAOSettings;
-
-typedef struct GPUFXSettings {
- GPUDOFSettings *dof;
- GPUSSAOSettings *ssao;
- /** #eGPUFXFlags. */
- char fx_flag;
- char _pad[7];
-} GPUFXSettings;
-
-/* shaderfx enables */
-typedef enum eGPUFXFlags {
- GPU_FX_FLAG_DOF = (1 << 0),
- GPU_FX_FLAG_SSAO = (1 << 1),
-} eGPUFXFlags;
-
#endif /* __DNA_GPU_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 3af1da46f80..4de98e0b684 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -118,13 +118,13 @@ enum {
BASE_HIDDEN = (1 << 8), /* Object is hidden for editing. */
/* Runtime evaluated flags. */
- BASE_VISIBLE = (1 << 1), /* Object is enabled and visible. */
- BASE_SELECTABLE = (1 << 2), /* Object can be selected. */
- BASE_FROM_DUPLI = (1 << 3), /* Object comes from duplicator. */
- /* BASE_DEPRECATED = (1 << 4), */
- BASE_FROM_SET = (1 << 5), /* Object comes from set. */
- BASE_ENABLED_VIEWPORT = (1 << 6), /* Object is enabled in viewport. */
- BASE_ENABLED_RENDER = (1 << 7), /* Object is enabled in final render */
+ BASE_VISIBLE_DEPSGRAPH = (1 << 1), /* Object is enabled and visible for the depsgraph. */
+ BASE_SELECTABLE = (1 << 2), /* Object can be selected. */
+ BASE_FROM_DUPLI = (1 << 3), /* Object comes from duplicator. */
+ BASE_VISIBLE_VIEWLAYER = (1 << 4), /* Object is enabled and visible for the viewlayer. */
+ BASE_FROM_SET = (1 << 5), /* Object comes from set. */
+ BASE_ENABLED_VIEWPORT = (1 << 6), /* Object is enabled in viewport. */
+ BASE_ENABLED_RENDER = (1 << 7), /* Object is enabled in final render */
/* BASE_DEPRECATED = (1 << 9), */
BASE_HOLDOUT = (1 << 10), /* Object masked out from render */
BASE_INDIRECT_ONLY = (1 << 11), /* Object only contributes indirectly to render */
@@ -142,10 +142,13 @@ enum {
LAYER_COLLECTION_HIDE = (1 << 7),
};
-/* Layer Collection->runtime_flag */
+/* Layer Collection->runtime_flag
+ Keep it synced with base->flag based on g_base_collection_flags. */
enum {
LAYER_COLLECTION_HAS_OBJECTS = (1 << 0),
- LAYER_COLLECTION_VISIBLE = (1 << 1),
+ LAYER_COLLECTION_VISIBLE_DEPSGRAPH = (1 << 1),
+ LAYER_COLLECTION_RESTRICT_VIEWPORT = (1 << 2),
+ LAYER_COLLECTION_VISIBLE_VIEW_LAYER = (1 << 4),
};
/* ViewLayer->flag */
diff --git a/source/blender/makesdna/DNA_mesh_defaults.h b/source/blender/makesdna/DNA_mesh_defaults.h
index 40b8e2c9247..f605827d120 100644
--- a/source/blender/makesdna/DNA_mesh_defaults.h
+++ b/source/blender/makesdna/DNA_mesh_defaults.h
@@ -34,6 +34,8 @@
.smoothresh = DEG2RADF(30), \
.texflag = ME_AUTOSPACE, \
.remesh_voxel_size = 0.1f, \
+ .remesh_voxel_adaptivity = 0.0f, \
+ .flag = ME_REMESH_FIX_POLES | ME_REMESH_REPROJECT_VOLUME, \
}
/** \} */
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 070180d0a24..fb9e522dfa9 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -116,8 +116,6 @@ typedef struct Mesh {
/** Animation data (must be immediately after id for utilities to use it). */
struct AnimData *adt;
- struct BoundBox *bb;
-
/** Old animation system, deprecated for 2.5. */
struct Ipo *ipo DNA_DEPRECATED;
struct Key *key;
@@ -177,7 +175,6 @@ typedef struct Mesh {
/* texture space, copied as one block in editobject.c */
float loc[3];
float size[3];
- float rot[3];
short texflag, flag;
float smoothresh;
@@ -193,6 +190,7 @@ typedef struct Mesh {
short totcol;
float remesh_voxel_size;
+ float remesh_voxel_adaptivity;
char remesh_mode;
char _pad1[3];
/** Deprecated multiresolution modeling data, only keep for loading old files. */
@@ -218,6 +216,7 @@ typedef struct TFace {
/* texflag */
enum {
ME_AUTOSPACE = 1,
+ ME_AUTOSPACE_EVALUATED = 2,
};
/* me->editflag */
@@ -253,6 +252,8 @@ enum {
ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10,
ME_REMESH_SMOOTH_NORMALS = 1 << 11,
ME_REMESH_REPROJECT_PAINT_MASK = 1 << 12,
+ ME_REMESH_FIX_POLES = 1 << 13,
+ ME_REMESH_REPROJECT_VOLUME = 1 << 14,
};
/* me->cd_flag */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 5d71d33733d..505853dbbeb 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -1598,6 +1598,19 @@ enum {
MOD_LAPLACIANSMOOTH_NORMALIZED = (1 << 5),
};
+typedef struct CorrectiveSmoothDeltaCache {
+ /* delta's between the original positions and the smoothed positions */
+ float (*deltas)[3];
+ unsigned int totverts;
+
+ /* Value of settings when creating the cache.
+ * These are used to check if the cache should be recomputed. */
+ float lambda;
+ short repeat, flag;
+ char smooth_type, rest_source;
+ char _pad[2];
+} CorrectiveSmoothDeltaCache;
+
typedef struct CorrectiveSmoothModifierData {
ModifierData modifier;
@@ -1616,11 +1629,8 @@ typedef struct CorrectiveSmoothModifierData {
/** MAX_VGROUP_NAME. */
char defgrp_name[64];
- /* runtime-only cache (delta's between),
- * delta's between the original positions and the smoothed positions */
- float (*delta_cache)[3];
- unsigned int delta_cache_num;
- char _pad2[4];
+ /* runtime-only cache */
+ CorrectiveSmoothDeltaCache delta_cache;
} CorrectiveSmoothModifierData;
enum {
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index efda24d6e0e..8de79d9ea2b 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -97,7 +97,7 @@ typedef struct MovieClip {
struct MovieTracking tracking;
/**
* Context of tracking job used to synchronize data
- * like framenumber in SpaceClip clip user.
+ * like frame-number in SpaceClip clip user.
*/
void *tracking_context;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 0287a1510fe..7eecf23195a 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -277,7 +277,9 @@ typedef struct bNode {
/** Used at runtime when going through the tree. Initialize before use. */
short tmp_flag;
/** Used at runtime to tag derivatives branches. EEVEE only. */
- short branch_tag;
+ char branch_tag;
+ /** Used at runtime when iterating over node branches. */
+ char iter_flag;
/** Runtime during drawing. */
struct uiBlock *block;
@@ -433,7 +435,7 @@ typedef struct bNodeTree {
int flag;
/** Update flags. */
int update;
- /** Flag to prevent reentrant update calls. */
+ /** Flag to prevent re-entrant update calls. */
short is_updating;
/** Generic temporary flag for recursion check (DFS/BFS). */
short done;
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index a49da9e3761..8d77e57c959 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -93,7 +93,7 @@
.frs_sec = 24, \
.frs_sec_base = 1, \
\
- /* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used, \
+ /* OCIO_TODO: for forwards compatibility only, so if no tone-curve are used, \
* images would look in the same way as in current blender \
* \
* perhaps at some point should be completely deprecated? \
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 1f70fb7175d..50712db3e04 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -39,7 +39,6 @@ extern "C" {
#include "DNA_listBase.h"
#include "DNA_ID.h"
#include "DNA_freestyle_types.h"
-#include "DNA_gpu_types.h"
#include "DNA_collection_types.h"
#include "DNA_layer_types.h"
#include "DNA_material_types.h"
@@ -2062,14 +2061,7 @@ extern const char *RE_engine_id_CYCLES;
#define MINAFRAME -1048574
#define MINAFRAMEF -1048574.0f
-#define BASE_VISIBLE(v3d, base) \
- (((v3d == NULL) || ((v3d)->localvd == NULL) || \
- ((v3d)->local_view_uuid & (base)->local_view_bits)) && \
- ((v3d == NULL) || (((v3d)->flag & V3D_LOCAL_COLLECTIONS) == 0) || \
- ((v3d)->local_collections_uuid & (base)->local_collections_bits)) && \
- ((v3d == NULL) || \
- (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0)) && \
- (((base)->flag & BASE_VISIBLE) != 0))
+#define BASE_VISIBLE(v3d, base) BKE_base_is_visible(v3d, base)
#define BASE_SELECTABLE(v3d, base) \
(BASE_VISIBLE(v3d, base) && \
((v3d == NULL) || (((1 << (base)->object->type) & (v3d)->object_type_exclude_select) == 0)) && \
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 2740d27e1af..8587a2854fe 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -678,11 +678,9 @@ typedef struct FileSelectParams {
short sort;
/** Display mode flag. */
short display;
- short display_previous;
/** Details toggles (file size, creation date, etc.) */
char details_flags;
- /* The type of file action (opening or saving) */
- char action_type; /* eFileSel_Action */
+ char _pad2[3];
/** Filter when (flags & FILE_FILTER) is true. */
int filter;
@@ -799,7 +797,8 @@ typedef enum eFileSel_Params_Flag {
FILE_PARAMS_FLAG_UNUSED_9 = (1 << 9), /* cleared */
FILE_GROUP_INSTANCE = (1 << 10),
FILE_SORT_INVERT = (1 << 11),
- FILE_HIDE_TOOL_PROPS = (1 << 12)
+ FILE_HIDE_TOOL_PROPS = (1 << 12),
+ FILE_CHECK_EXISTING = (1 << 13),
} eFileSel_Params_Flag;
/* sfile->params->rename_flag */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 6e44c51970d..c726c5e132e 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -345,6 +345,7 @@ typedef struct ThemeSpace {
lock_marker[4];
unsigned char bundle_solid[4];
unsigned char path_before[4], path_after[4];
+ unsigned char path_keyframe_before[4], path_keyframe_after[4];
unsigned char camera_path[4];
unsigned char _pad1[2];
@@ -393,6 +394,8 @@ typedef struct ThemeSpace {
/** NLA - warning color for duplicate instances of tweaking strip. */
unsigned char nla_tweakdupli[4];
+ /** NLA "Track" */
+ unsigned char nla_track[4];
/** NLA "Transition" strips. */
unsigned char nla_transition[4], nla_transition_sel[4];
/** NLA "Meta" strips. */
@@ -413,7 +416,6 @@ typedef struct ThemeSpace {
unsigned char metadatabg[4];
unsigned char metadatatext[4];
- char _pad2[4];
} ThemeSpace;
/* set of colors for use as a custom color set for Objects/Bones wire drawing */
@@ -576,6 +578,23 @@ typedef struct UserDef_SpaceData {
char _pad0[6];
} UserDef_SpaceData;
+/**
+ * Storage for UI data that to keep it even after the window was closed. (Similar to
+ * #UserDef_SpaceData.)
+ */
+typedef struct UserDef_FileSpaceData {
+ int display_type; /* FileSelectParams.display */
+ int thumbnail_size; /* FileSelectParams.thumbnail_size */
+ int sort_type; /* FileSelectParams.sort */
+ int details_flags; /* FileSelectParams.details_flags */
+ int flag; /* FileSelectParams.flag */
+ int filter_id; /* FileSelectParams.filter_id */
+
+ /** Info used when creating the file browser in a temporary window. */
+ int temp_win_sizex;
+ int temp_win_sizey;
+} UserDef_FileSpaceData;
+
typedef struct UserDef {
/** UserDef has separate do-version handling, and can be read from other files. */
int versionfile, subversionfile;
@@ -587,7 +606,8 @@ typedef struct UserDef {
/** #eUserPref_PrefFlag preferences for the preferences. */
char pref_flag;
char savetime;
- char _pad4[4];
+ char mouse_emulate_3_button_modifier;
+ char _pad4[3];
/** FILE_MAXDIR length. */
char tempdir[768];
char fontdir[768];
@@ -707,11 +727,13 @@ typedef struct UserDef {
short curssize;
/** #eColorPicker_Types. */
short color_picker_type;
+ /** Curve smoothing type for newly added F-Curves. */
+ char auto_smoothing_new;
/** Interpolation mode for newly added F-Curves. */
char ipo_new;
/** Handle types for newly added keyframes. */
char keyhandles_new;
- char _pad11[3];
+ char _pad11[2];
/** #eZoomFrame_Mode. */
char view_frame_type;
@@ -814,12 +836,15 @@ typedef struct UserDef {
char viewport_aa;
- char _pad5[6];
+ char render_display_type; /* eUserpref_RenderDisplayType */
+ char filebrowser_display_type; /* eUserpref_TempSpaceDisplayType */
+ char _pad5[4];
struct WalkNavigation walk_navigation;
/** The UI for the user preferences. */
UserDef_SpaceData space_data;
+ UserDef_FileSpaceData file_space_data;
/** Runtime data (keep last). */
UserDef_Runtime runtime;
@@ -969,7 +994,11 @@ typedef enum eUserpref_UI_Flag {
USER_ZOOM_HORIZ = (1 << 26), /* for CONTINUE and DOLLY zoom */
USER_SPLASH_DISABLE = (1 << 27),
USER_HIDE_RECENT = (1 << 28),
- USER_SHOW_THUMBNAILS = (1 << 29),
+#ifdef DNA_DEPRECATED
+ USER_SHOW_THUMBNAILS =
+ (1 << 29), /* deprecated - We're just trying if there's much desire for this feature, or if
+ we can make it go for good. Should be cleared if so - Julian, Oct. 2019 */
+#endif
USER_SAVE_PROMPT = (1 << 30),
USER_HIDE_SYSTEM_BOOKMARKS = (1u << 31),
} eUserpref_UI_Flag;
@@ -1202,6 +1231,23 @@ typedef enum eUserpref_FactorDisplay {
USER_FACTOR_AS_PERCENTAGE = 1,
} eUserpref_FactorDisplay;
+typedef enum eUserpref_RenderDisplayType {
+ USER_RENDER_DISPLAY_NONE = 0,
+ USER_RENDER_DISPLAY_SCREEN = 1,
+ USER_RENDER_DISPLAY_AREA = 2,
+ USER_RENDER_DISPLAY_WINDOW = 3
+} eUserpref_RenderDisplayType;
+
+typedef enum eUserpref_TempSpaceDisplayType {
+ USER_TEMP_SPACE_DISPLAY_FULLSCREEN,
+ USER_TEMP_SPACE_DISPLAY_WINDOW,
+} eUserpref_TempSpaceDisplayType;
+
+typedef enum eUserpref_EmulateMMBMod {
+ USER_EMU_MMB_MOD_ALT = 0,
+ USER_EMU_MMB_MOD_OSKEY = 1,
+} eUserpref_EmulateMMBMod;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 10c61446d9d..7b832f1b646 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -38,7 +38,6 @@ struct wmTimer;
#include "DNA_image_types.h"
#include "DNA_object_types.h"
#include "DNA_movieclip_types.h"
-#include "DNA_gpu_types.h"
typedef struct RegionView3D {
@@ -301,10 +300,6 @@ typedef struct View3D {
/** Actually only used to define the opacity of the grease pencil vertex in edit mode. */
float vertex_opacity;
- /* note, 'fx_settings.dof' is currently _not_ allocated,
- * instead set (temporarily) from camera */
- struct GPUFXSettings fx_settings;
-
/* XXX deprecated? */
/** Grease-Pencil Data (annotation layers). */
struct bGPdata *gpd DNA_DEPRECATED;
@@ -351,6 +346,7 @@ typedef struct View3D {
#define RV3D_CLIPPING (1 << 2)
#define RV3D_NAVIGATING (1 << 3)
#define RV3D_GPULIGHT_UPDATE (1 << 4)
+#define RV3D_PAINTING (1 << 5)
/*#define RV3D_IS_GAME_ENGINE (1 << 5) */ /* UNUSED */
/**
* Disable zbuffer offset, skip calls to #ED_view3d_polygon_offset.
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index 76d076a8638..260f1cd20f6 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -250,6 +250,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(UserDef),
SDNA_DEFAULT_DECL(bTheme),
SDNA_DEFAULT_DECL_EX(UserDef_SpaceData, UserDef.space_data),
+ SDNA_DEFAULT_DECL_EX(UserDef_FileSpaceData, UserDef.file_space_data),
SDNA_DEFAULT_DECL_EX(WalkNavigation, UserDef.walk_navigation),
/* DNA_view3d_defaults.h */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 0b60d1fa344..5d29ea24d90 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -267,6 +267,7 @@ extern StructRNA RNA_FreestyleLineStyle;
extern StructRNA RNA_FreestyleModuleSettings;
extern StructRNA RNA_FreestyleSettings;
extern StructRNA RNA_Function;
+extern StructRNA RNA_GPUFXSettings;
extern StructRNA RNA_GPencilFrame;
extern StructRNA RNA_GPencilInterpolateSettings;
extern StructRNA RNA_GPencilLayer;
@@ -400,6 +401,7 @@ extern StructRNA RNA_MeshFloatPropertyLayer;
extern StructRNA RNA_MeshIntProperty;
extern StructRNA RNA_MeshIntPropertyLayer;
extern StructRNA RNA_MeshLoop;
+extern StructRNA RNA_MeshLoopColor;
extern StructRNA RNA_MeshLoopColorLayer;
extern StructRNA RNA_MeshLoopTriangle;
extern StructRNA RNA_MeshPolygon;
@@ -413,6 +415,7 @@ extern StructRNA RNA_MeshTextureFace;
extern StructRNA RNA_MeshTextureFaceLayer;
extern StructRNA RNA_MeshTexturePoly;
extern StructRNA RNA_MeshTexturePolyLayer;
+extern StructRNA RNA_MeshUVLoop;
extern StructRNA RNA_MeshVertex;
extern StructRNA RNA_MessageSensor;
extern StructRNA RNA_MetaBall;
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index e72a55b5a9e..458f031ceae 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -90,6 +90,7 @@ extern const EnumPropertyItem rna_enum_color_sets_items[];
extern const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[];
extern const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[];
extern const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[];
+extern const EnumPropertyItem rna_enum_fcurve_auto_smoothing_items[];
extern const EnumPropertyItem rna_enum_keyframe_handle_type_items[];
extern const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[];
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 6e98b5f4727..aeb6d528cdb 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -393,7 +393,7 @@ bool RNA_struct_idprops_check(StructRNA *srna)
return (srna && srna->idproperties);
}
-static IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name)
+IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name)
{
IDProperty *group = RNA_struct_idprops(ptr, 0);
@@ -2058,18 +2058,18 @@ int RNA_property_ui_icon(PropertyRNA *prop)
return rna_ensure_property(prop)->icon;
}
-bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
+bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig)
{
ID *id = ptr->owner_id;
int flag;
const char *dummy_info;
- prop = rna_ensure_property(prop);
+ PropertyRNA *prop = rna_ensure_property(prop_orig);
flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0 &&
(!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) &&
- (!id->override_library || RNA_property_overridable_get(ptr, prop)))));
+ (!id->override_library || RNA_property_overridable_get(ptr, prop_orig)))));
}
/**
@@ -2081,15 +2081,15 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
ID *id = ptr->owner_id;
int flag;
- prop = rna_ensure_property(prop);
+ PropertyRNA *prop_type = rna_ensure_property(prop);
*r_info = "";
/* get flag */
- if (prop->editable) {
- flag = prop->editable(ptr, r_info);
+ if (prop_type->editable) {
+ flag = prop_type->editable(ptr, r_info);
}
else {
- flag = prop->flag;
+ flag = prop_type->flag;
if ((flag & PROP_EDITABLE) == 0 || (flag & PROP_REGISTER)) {
*r_info = N_("This property is for internal use only and can't be edited");
}
@@ -2097,17 +2097,21 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
/* property from linked data-block */
if (id) {
- if (ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
+ if (ID_IS_LINKED(id) && (prop_type->flag & PROP_LIB_EXCEPTION) == 0) {
if (!(*r_info)[0]) {
*r_info = N_("Can't edit this property from a linked data-block");
}
return false;
}
- if (id->override_library != NULL && !RNA_property_overridable_get(ptr, prop)) {
- if (!(*r_info)[0]) {
- *r_info = N_("Can't edit this property from an override data-block");
+ if (id->override_library != NULL) {
+ /* We need the real data property in case of IDProperty here... */
+ PropertyRNA *real_prop = rna_ensure_property_realdata(&prop, ptr);
+ if (real_prop == NULL || !RNA_property_overridable_get(ptr, real_prop)) {
+ if (!(*r_info)[0]) {
+ *r_info = N_("Can't edit this property from an override data-block");
+ }
+ return false;
}
- return false;
}
}
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index b0a83ea38c6..18fbe7886e9 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -76,8 +76,8 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
}
else {
/* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */
- return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
- (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_LIBRARY);
+ IDProperty *idprop = (IDProperty *)prop;
+ return (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0;
}
}
@@ -400,9 +400,39 @@ static bool rna_property_override_operation_store(Main *bmain,
return changed;
}
- BLI_assert(prop_local->override_store == prop_reference->override_store &&
- (!ptr_storage || prop_local->override_store == prop_storage->override_store) &&
- prop_local->override_store != NULL);
+ RNAPropOverrideStore override_store = NULL;
+ /* Special case for IDProps, we use default callback then. */
+ if (prop_local->magic != RNA_MAGIC) {
+ override_store = rna_property_override_store_default;
+ if (prop_reference->magic == RNA_MAGIC && prop_reference->override_store != override_store) {
+ override_store = NULL;
+ }
+ }
+ else if (prop_reference->magic != RNA_MAGIC) {
+ override_store = rna_property_override_store_default;
+ if (prop_local->override_store != override_store) {
+ override_store = NULL;
+ }
+ }
+ else if (prop_local->override_store == prop_reference->override_store) {
+ override_store = prop_local->override_store;
+ }
+
+ if (ptr_storage != NULL && prop_storage->magic == RNA_MAGIC &&
+ prop_storage->override_store != override_store) {
+ override_store = NULL;
+ }
+
+ if (override_store == NULL) {
+#ifndef NDEBUG
+ printf("'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d).\n",
+ op->rna_path,
+ prop_local->magic == RNA_MAGIC,
+ prop_reference->magic == RNA_MAGIC);
+#endif
+ BLI_assert(0);
+ return changed;
+ }
for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
/* Only needed for diff operations. */
@@ -413,17 +443,17 @@ static bool rna_property_override_operation_store(Main *bmain,
continue;
}
- if (prop_local->override_store(bmain,
- ptr_local,
- ptr_reference,
- ptr_storage,
- prop_local,
- prop_reference,
- prop_storage,
- len_local,
- len_reference,
- len_storage,
- opop)) {
+ if (override_store(bmain,
+ ptr_local,
+ ptr_reference,
+ ptr_storage,
+ prop_local,
+ prop_reference,
+ prop_storage,
+ len_local,
+ len_reference,
+ len_storage,
+ opop)) {
changed = true;
}
}
@@ -595,6 +625,21 @@ bool RNA_struct_override_matches(Main *bmain,
prop_local = rna_ensure_property_realdata(&prop_local, ptr_local);
prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference);
+ /* IDProps (custom properties) are even more of a PITA here, we cannot use
+ * `rna_ensure_property_realdata()` to deal with them, we have to use the path generated from
+ * `prop_local` (which is valid) to access to the actual reference counterpart... */
+ if (prop_local != NULL && prop_local->magic != RNA_MAGIC && prop_local == prop_reference) {
+ /* We could also use (lower in this code, after rna_path has been computed):
+ * RNA_path_resolve_property(ptr_reference, rna_path, &some_rna_ptr, &prop_reference);
+ * But that would be much more costly, and would also fail when ptr_reference
+ * is not an ID pointer itself, so we'd need to rebuild it from its owner_id, then check that
+ * generated some_rna_ptr and ptr_reference do point to the same data, etc.
+ * For now, let's try that simple access, it won't cover all cases but should handle fine
+ * most basic custom properties situations. */
+ prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference,
+ ((IDProperty *)prop_local)->name);
+ }
+
if (ELEM(NULL, prop_local, prop_reference)) {
continue;
}
diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h
index 28ec504e376..c7995746d08 100644
--- a/source/blender/makesrna/intern/rna_access_internal.h
+++ b/source/blender/makesrna/intern/rna_access_internal.h
@@ -30,5 +30,6 @@ struct IDProperty;
PropertyRNA *rna_ensure_property(PropertyRNA *prop);
void rna_idproperty_touch(struct IDProperty *idprop);
+struct IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name);
#endif /* __ACCESS_RNA_INTERNAL_H__ */
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 24f8d5c4e3d..6eaf303ce2d 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -306,6 +306,11 @@ bool rna_Action_actedit_assign_poll(PointerRNA *ptr, PointerRNA value)
return 0;
}
+static char *rna_DopeSheet_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("dopesheet");
+}
+
#else
static void rna_def_dopesheet(BlenderRNA *brna)
@@ -315,6 +320,7 @@ static void rna_def_dopesheet(BlenderRNA *brna)
srna = RNA_def_struct(brna, "DopeSheet", NULL);
RNA_def_struct_sdna(srna, "bDopeSheet");
+ RNA_def_struct_path_func(srna, "rna_DopeSheet_path");
RNA_def_struct_ui_text(
srna, "Dope Sheet", "Settings for filtering the channels shown in animation editors");
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 6157ec41f19..e1a24326474 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -668,8 +668,7 @@ static FCurve *rna_Driver_new(
return NULL;
}
- short add_mode = 1;
- FCurve *fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode);
+ FCurve *fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_KEYFRAMES);
BLI_assert(fcu != NULL);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index 17a58a61fb5..f539da488ce 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -144,7 +144,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "line_thickness");
RNA_def_property_range(prop, 1, 6);
- RNA_def_property_ui_text(prop, "Line thickness", "Line thickness for drawing path");
+ RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness for drawing path");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* Settings */
@@ -164,7 +164,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
/* Use custom color */
prop = RNA_def_property(srna, "use_custom_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM);
- RNA_def_property_ui_text(prop, "Custom colors", "Use custom color for this motion path");
+ RNA_def_property_ui_text(prop, "Custom Colors", "Use custom color for this motion path");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* Draw lines between keyframes */
diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c
index 722b7b12271..01d1d1ddddb 100644
--- a/source/blender/makesrna/intern/rna_boid.c
+++ b/source/blender/makesrna/intern/rna_boid.c
@@ -355,7 +355,7 @@ static void rna_def_boidrule_avoid(BlenderRNA *brna)
prop = RNA_def_property(srna, "fear_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_text(
- prop, "Fear factor", "Avoid object if danger from it is above this threshold");
+ prop, "Fear Factor", "Avoid object if danger from it is above this threshold");
RNA_def_property_update(prop, 0, "rna_Boids_reset");
}
@@ -379,7 +379,7 @@ static void rna_def_boidrule_avoid_collision(BlenderRNA *brna)
prop = RNA_def_property(srna, "look_ahead", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_text(prop, "Look ahead", "Time to look ahead in seconds");
+ RNA_def_property_ui_text(prop, "Look Ahead", "Time to look ahead in seconds");
RNA_def_property_update(prop, 0, "rna_Boids_reset");
}
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 716e8526071..57a3d889437 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -70,6 +70,7 @@ static const EnumPropertyItem sculpt_stroke_method_items[] = {
const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_DRAW, "DRAW", ICON_BRUSH_SCULPT_DRAW, "Draw", ""},
+ {SCULPT_TOOL_DRAW_SHARP, "DRAW_SHARP", ICON_BRUSH_SCULPT_DRAW, "Draw Sharp", ""},
{SCULPT_TOOL_CLAY, "CLAY", ICON_BRUSH_CLAY, "Clay", ""},
{SCULPT_TOOL_CLAY_STRIPS, "CLAY_STRIPS", ICON_BRUSH_CLAY_STRIPS, "Clay Strips", ""},
{SCULPT_TOOL_LAYER, "LAYER", ICON_BRUSH_LAYER, "Layer", ""},
@@ -84,16 +85,15 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""},
{0, "", 0, NULL, NULL},
{SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""},
+ {SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""},
{SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""},
{SCULPT_TOOL_THUMB, "THUMB", ICON_BRUSH_THUMB, "Thumb", ""},
+ {SCULPT_TOOL_POSE, "POSE", ICON_BRUSH_GRAB, "Pose", ""},
{SCULPT_TOOL_NUDGE, "NUDGE", ICON_BRUSH_NUDGE, "Nudge", ""},
{SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""},
{0, "", 0, NULL, NULL},
{SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""},
{SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
- {SCULPT_TOOL_DRAW_SHARP, "DRAW_SHARP", ICON_BRUSH_SCULPT_DRAW, "Draw Sharp", ""},
- {SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""},
- {SCULPT_TOOL_POSE, "POSE", ICON_BRUSH_GRAB, "Pose", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1298,7 +1298,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_smooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "active_smooth");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Active Smooth", "Amount of smoothing while drawing ");
+ RNA_def_property_ui_text(prop, "Active Smooth", "Amount of smoothing while drawing");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1306,7 +1306,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "era_strength_f");
RNA_def_property_range(prop, 0.0, 100.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1);
- RNA_def_property_ui_text(prop, "Affect Stroke Strength", "Amount of erasing for strength ");
+ RNA_def_property_ui_text(prop, "Affect Stroke Strength", "Amount of erasing for strength");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1314,7 +1314,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "era_thickness_f");
RNA_def_property_range(prop, 0.0, 100.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1);
- RNA_def_property_ui_text(prop, "Affect Stroke Thickness", "Amount of erasing for thickness ");
+ RNA_def_property_ui_text(prop, "Affect Stroke Thickness", "Amount of erasing for thickness");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1452,81 +1452,77 @@ static void rna_def_brush(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem prop_blend_items[] = {
- {IMB_BLEND_MIX, "MIX", 0, "Mix", "Use mix blending mode while painting"},
+ {IMB_BLEND_MIX, "MIX", 0, "Mix", "Use Mix blending mode while painting"},
{0, "", ICON_NONE, NULL, NULL},
- {IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use darken blending mode while painting"},
- {IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use multiply blending mode while painting"},
+ {IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use Darken blending mode while painting"},
+ {IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use Multiply blending mode while painting"},
{IMB_BLEND_COLORBURN,
"COLORBURN",
0,
- "Color burn",
- "Use color burn blending mode while painting"},
+ "Color Burn",
+ "Use Color Burn blending mode while painting"},
{IMB_BLEND_LINEARBURN,
"LINEARBURN",
0,
- "Linear burn",
- "Use linear burn blending mode while painting"},
+ "Linear Burn",
+ "Use Linear Burn blending mode while painting"},
{0, "", ICON_NONE, NULL, NULL},
- {IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use lighten blending mode while painting"},
- {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use screen blending mode while painting"},
+ {IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use Lighten blending mode while painting"},
+ {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use Screen blending mode while painting"},
{IMB_BLEND_COLORDODGE,
"COLORDODGE",
0,
- "Color dodge",
- "Use color dodge blending mode while painting"},
- {IMB_BLEND_ADD, "ADD", 0, "Add", "Use add blending mode while painting"},
+ "Color Dodge",
+ "Use Color Dodge blending mode while painting"},
+ {IMB_BLEND_ADD, "ADD", 0, "Add", "Use Add blending mode while painting"},
{0, "", ICON_NONE, NULL, NULL},
- {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use overlay blending mode while painting"},
+ {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use Overlay blending mode while painting"},
{IMB_BLEND_SOFTLIGHT,
"SOFTLIGHT",
0,
- "Soft light",
- "Use softlight blending mode while painting"},
+ "Soft Light",
+ "Use Soft Light blending mode while painting"},
{IMB_BLEND_HARDLIGHT,
"HARDLIGHT",
0,
- "Hard light",
- "Use hard light blending mode while painting"},
+ "Hard Light",
+ "Use Hard Light blending mode while painting"},
{IMB_BLEND_VIVIDLIGHT,
"VIVIDLIGHT",
0,
- "Vivid light",
- "Use vividlight blending mode while painting"},
+ "Vivid Light",
+ "Use Vivid Light blending mode while painting"},
{IMB_BLEND_LINEARLIGHT,
"LINEARLIGHT",
0,
- "Linear light",
- "Use linearlight blending mode while painting"},
+ "Linear Light",
+ "Use Linear Light blending mode while painting"},
{IMB_BLEND_PINLIGHT,
"PINLIGHT",
0,
- "Pin light",
- "Use pinlight blending mode while painting"},
+ "Pin Light",
+ "Use Pin Light blending mode while painting"},
{0, "", ICON_NONE, NULL, NULL},
{IMB_BLEND_DIFFERENCE,
"DIFFERENCE",
0,
"Difference",
- "Use difference blending mode while painting"},
+ "Use Difference blending mode while painting"},
{IMB_BLEND_EXCLUSION,
"EXCLUSION",
0,
"Exclusion",
- "Use exclusion blending mode while painting"},
- {IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use subtract blending mode while painting"},
+ "Use Exclusion blending mode while painting"},
+ {IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use Subtract blending mode while painting"},
{0, "", ICON_NONE, NULL, NULL},
- {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use hue blending mode while painting"},
+ {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use Hue blending mode while painting"},
{IMB_BLEND_SATURATION,
"SATURATION",
0,
"Saturation",
- "Use saturation blending mode while painting"},
- {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use color blending mode while painting"},
- {IMB_BLEND_LUMINOSITY,
- "LUMINOSITY",
- 0,
- "Luminosity",
- "Use luminosity blending mode while painting"},
+ "Use Saturation blending mode while painting"},
+ {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use Color blending mode while painting"},
+ {IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Value", "Use Value blending mode while painting"},
{0, "", ICON_NONE, NULL, NULL},
{IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"},
{IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"},
@@ -1610,15 +1606,11 @@ static void rna_def_brush(BlenderRNA *brna)
};
static const EnumPropertyItem brush_elastic_deform_type_items[] = {
- {BRUSH_ELASTIC_DEFORM_GRAB, "ELASTIC_DEFORM_GRAB", 0, "Grab", ""},
- {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "ELASTIC_DEFORM_GRAB_BISCALE", 0, "Bi-scale Grab", ""},
- {BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE,
- "ELASTIC_DEFORM_GRAB_TRISCALE",
- 0,
- "Tri-scale Grab",
- ""},
- {BRUSH_ELASTIC_DEFORM_SCALE, "ELASTIC_DEFORM_SCALE", 0, "Scale", ""},
- {BRUSH_ELASTIC_DEFORM_TWIST, "ELASTIC_DEFORM_TWIST", 0, "Twist", ""},
+ {BRUSH_ELASTIC_DEFORM_GRAB, "GRAB", 0, "Grab", ""},
+ {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "GRAB_BISCALE", 0, "Bi-scale Grab", ""},
+ {BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE, "GRAB_TRISCALE", 0, "Tri-scale Grab", ""},
+ {BRUSH_ELASTIC_DEFORM_SCALE, "SCALE", 0, "Scale", ""},
+ {BRUSH_ELASTIC_DEFORM_TWIST, "TWIST", 0, "Twist", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1630,7 +1622,7 @@ static void rna_def_brush(BlenderRNA *brna)
/* enums */
prop = RNA_def_property(srna, "blend", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_blend_items);
- RNA_def_property_ui_text(prop, "Blending mode", "Brush blending mode");
+ RNA_def_property_ui_text(prop, "Blending Mode", "Brush blending mode");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/**
@@ -1718,7 +1710,7 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "unprojected_radius", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_funcs(prop, NULL, "rna_Brush_set_unprojected_radius", NULL);
RNA_def_property_range(prop, 0.001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001, 1, 0, -1);
+ RNA_def_property_ui_range(prop, 0.001, 1, 1, -1);
RNA_def_property_ui_text(prop, "Unprojected Radius", "Radius of brush in Blender units");
RNA_def_property_update(prop, 0, "rna_Brush_size_update");
@@ -1863,6 +1855,13 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Crease Brush Pinch Factor", "How much the crease brush pinches");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "pose_offset", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "pose_offset");
+ RNA_def_property_range(prop, 0.0f, 2.0f);
+ RNA_def_property_ui_text(
+ prop, "Pose Origin Offset", "Offset of the pose origin in relation to the brush radius");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "auto_smooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor");
RNA_def_property_float_default(prop, 0);
@@ -1886,8 +1885,8 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "normal_radius_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "normal_radius_factor");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
+ RNA_def_property_range(prop, 0.0f, 2.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 2.0f, 0.001, 3);
RNA_def_property_ui_text(prop,
"Normal Radius",
"Ratio between the brush radius and the radius that is going to be "
@@ -1960,7 +1959,7 @@ static void rna_def_brush(BlenderRNA *brna)
/* flag */
/* This is an enum but its unlikely we add other shapes, so expose as a boolean. */
prop = RNA_def_property(srna, "use_projected", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "falloff_shape", BRUSH_AIRBRUSH);
+ RNA_def_property_boolean_sdna(prop, NULL, "falloff_shape", PAINT_FALLOFF_SHAPE_TUBE);
RNA_def_property_ui_text(
prop, "2D Falloff", "Apply brush influence in 2D circle instead of a sphere");
RNA_def_property_update(prop, 0, "rna_Brush_update");
@@ -1978,6 +1977,14 @@ static void rna_def_brush(BlenderRNA *brna)
"When locked keep using normal of surface where stroke was initiated");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_original_plane", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ORIGINAL_PLANE);
+ RNA_def_property_ui_text(
+ prop,
+ "Original Plane",
+ "When locked keep using the plane origin of surface where stroke was initiated");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY);
RNA_def_property_ui_text(prop,
@@ -2404,7 +2411,7 @@ static void rna_def_operator_stroke_element(BlenderRNA *brna)
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_text(prop, "Brush Size", "Brush Size in screen space");
+ RNA_def_property_ui_text(prop, "Brush Size", "Brush size in screen space");
prop = RNA_def_property(srna, "pen_flip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 7732bf531d8..c0211799192 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -1045,6 +1045,7 @@ static void rna_def_constraint_armature_deform(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, NULL, "targets", NULL);
RNA_def_property_struct_type(prop, "ConstraintTargetBone");
RNA_def_property_ui_text(prop, "Targets", "Target Bones");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
rna_def_constraint_armature_deform_targets(brna, prop);
prop = RNA_def_property(srna, "use_deform_preserve_volume", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index a7dac4100db..6a3ab632fd4 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -291,9 +291,7 @@ static void rna_Curve_texspace_loc_get(PointerRNA *ptr, float *values)
{
Curve *cu = (Curve *)ptr->data;
- if (!cu->bb) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
copy_v3_v3(values, cu->loc);
}
@@ -309,9 +307,7 @@ static void rna_Curve_texspace_size_get(PointerRNA *ptr, float *values)
{
Curve *cu = (Curve *)ptr->data;
- if (!cu->bb) {
- BKE_curve_texspace_calc(cu);
- }
+ BKE_curve_texspace_ensure(cu);
copy_v3_v3(values, cu->size);
}
@@ -1761,15 +1757,6 @@ static void rna_def_curve(BlenderRNA *brna)
prop, "rna_Curve_texspace_size_get", "rna_Curve_texspace_size_set", NULL);
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
- /* not supported yet */
-# if 0
- prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
- RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Curve_update_data");
-# endif
-
prop = RNA_def_property(srna, "use_uv_as_generated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_UV_ORCO);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 758fbd07f85..fc22e9e6c74 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -1688,6 +1688,11 @@ void RNA_def_property_ui_range(
DefRNA.error = 1;
}
+ if (step == 0) {
+ CLOG_ERROR(&LOG, "\"%s.%s\", step is zero.", srna->identifier, prop->identifier);
+ DefRNA.error = 1;
+ }
+
if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) {
CLOG_ERROR(&LOG, "\"%s.%s\", precision outside range.", srna->identifier, prop->identifier);
DefRNA.error = 1;
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index ebd9bd8e925..2072b07ecb3 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -261,8 +261,13 @@ static void rna_Depsgraph_debug_stats(Depsgraph *depsgraph, char *result)
outer);
}
-static void rna_Depsgraph_update(Depsgraph *depsgraph, Main *bmain)
+static void rna_Depsgraph_update(Depsgraph *depsgraph, Main *bmain, ReportList *reports)
{
+ if (DEG_is_evaluating(depsgraph)) {
+ BKE_report(reports, RPT_ERROR, "Dependency graph update requested during evaluation");
+ return;
+ }
+
# ifdef WITH_PYTHON
/* Allow drivers to be evaluated */
BPy_BEGIN_ALLOW_THREADS;
@@ -654,7 +659,7 @@ static void rna_def_depsgraph(BlenderRNA *brna)
func,
"Re-evaluate any modified data-blocks, for example for animation or modifiers. "
"This invalidates all references to evaluated data-blocks from this dependency graph.");
- RNA_def_function_flag(func, FUNC_USE_MAIN);
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
/* Queries for original datablockls (the ones depsgraph is built for). */
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index 30a68a4919e..d7e34ff139c 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -472,7 +472,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_ANTIALIAS);
- RNA_def_property_ui_text(prop, "Anti-aliasing", "Use 5x multisampling to smooth paint edges");
+ RNA_def_property_ui_text(prop, "Anti-Aliasing", "Use 5x multisampling to smooth paint edges");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_DynamicPaintSurface_reset");
prop = RNA_def_property(srna, "brush_influence_scale", PROP_FLOAT, PROP_FACTOR);
@@ -610,7 +610,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_MULALPHA);
RNA_def_property_ui_text(
- prop, "Premultiply alpha", "Multiply color by alpha (recommended for Blender input)");
+ prop, "Premultiply Alpha", "Multiply color by alpha (recommended for Blender input)");
prop = RNA_def_property(srna, "image_output_path", PROP_STRING, PROP_DIRPATH);
RNA_def_property_string_sdna(prop, NULL, "image_output_path");
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 254f3bc3710..424bb4a492f 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -76,6 +76,22 @@ const EnumPropertyItem rna_enum_fmodifier_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_fcurve_auto_smoothing_items[] = {
+ {FCURVE_SMOOTH_NONE,
+ "NONE",
+ 0,
+ "None",
+ "Automatic handles only take immediately adjacent keys into account"},
+ {FCURVE_SMOOTH_CONT_ACCEL,
+ "CONT_ACCEL",
+ 0,
+ "Continuous Acceleration",
+ "Automatic handles are adjusted to avoid jumps in acceleration, resulting "
+ "in smoother curves. However, key changes may affect interpolation over a "
+ "larger stretch of the curve"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[] = {
{BEZT_KEYTYPE_KEYFRAME,
"KEYFRAME",
@@ -2258,19 +2274,6 @@ static void rna_def_fcurve(BlenderRNA *brna)
"Use custom hand-picked color for F-Curve"},
{0, NULL, 0, NULL, NULL},
};
- static EnumPropertyItem prop_mode_smoothing_items[] = {
- {FCURVE_SMOOTH_NONE,
- "NONE",
- 0,
- "None",
- "Auto handles only take adjacent keys into account (legacy mode)"},
- {FCURVE_SMOOTH_CONT_ACCEL,
- "CONT_ACCEL",
- 0,
- "Continuous Acceleration",
- "Auto handles are placed to avoid jumps in acceleration"},
- {0, NULL, 0, NULL, NULL},
- };
srna = RNA_def_struct(brna, "FCurve", NULL);
RNA_def_struct_ui_text(srna, "F-Curve", "F-Curve defining values of a period of time");
@@ -2350,7 +2353,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
prop = RNA_def_property(srna, "auto_smoothing", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, prop_mode_smoothing_items);
+ RNA_def_property_enum_items(prop, rna_enum_fcurve_auto_smoothing_items);
RNA_def_property_ui_text(
prop, "Auto Handle Smoothing", "Algorithm used to compute automatic handles");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FCurve_update_data");
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 5d21e718934..2f09b90a81e 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -447,7 +447,7 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
prop,
- "Remove air bubbles",
+ "Remove Air Bubbles",
"Removes the air gap between fluid surface and obstacles - WARNING: Can result "
"in a dissolving surface in other areas");
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 3ad18fcc7a3..2601600c6ee 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -1457,6 +1457,12 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop, "Solo Mode", "In Paint mode display only layers with keyframe in current frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Layer is used as Ruler. */
+ prop = RNA_def_property(srna, "is_ruler", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_IS_RULER);
+ RNA_def_property_ui_text(prop, "Ruler", "This is a special ruler layer");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
/* exposed as layers.active */
# if 0
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 4a0cf4d7ce2..4e7be7c9429 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -1387,7 +1387,7 @@ static void rna_def_modifier_gpencilinstance(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_KEEP_ONTOP);
RNA_def_property_ui_text(
prop,
- "Keep On Top",
+ "Keep on Top",
"Keep the original stroke in front of new instances (only affect by layer)");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
@@ -1763,7 +1763,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_VGROUP);
- RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_ui_text(prop, "Inverse Vertex Group", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
@@ -1799,7 +1799,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
- RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Light Falloff Curve");
+ RNA_def_property_ui_text(prop, "Falloff Curve", "Custom light falloff curve");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index bab7375f01b..40c6229f9b1 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -123,18 +123,13 @@ static IDProperty *rna_ViewLayer_idprops(PointerRNA *ptr, bool create)
static bool rna_LayerCollection_visible_get(LayerCollection *layer_collection, bContext *C)
{
View3D *v3d = CTX_wm_view3d(C);
- const bool runtime_visible = (layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE) != 0;
- if (v3d == NULL) {
- return runtime_visible;
- }
-
- if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) {
- return runtime_visible;
+ if ((v3d == NULL) || ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0)) {
+ return (layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER) != 0;
}
if (v3d->local_collections_uuid & layer_collection->local_collections_bits) {
- return true;
+ return (layer_collection->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) == 0;
}
return false;
@@ -192,15 +187,24 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po
iter, &view_layer->object_bases, rna_ViewLayer_objects_selected_skip);
}
-static void rna_ViewLayer_update_tagged(ID *id_ptr, ViewLayer *view_layer, Main *bmain)
+static void rna_ViewLayer_update_tagged(ID *id_ptr,
+ ViewLayer *view_layer,
+ Main *bmain,
+ ReportList *reports)
{
+ Scene *scene = (Scene *)id_ptr;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
+
+ if (DEG_is_evaluating(depsgraph)) {
+ BKE_report(reports, RPT_ERROR, "Dependency graph update requested during evaluation");
+ return;
+ }
+
# ifdef WITH_PYTHON
/* Allow drivers to be evaluated */
BPy_BEGIN_ALLOW_THREADS;
# endif
- Scene *scene = (Scene *)id_ptr;
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
/* NOTE: This is similar to CTX_data_depsgraph_pointer(). Ideally such access would be
* de-duplicated across all possible cases, but for now this is safest and easiest way to go.
*
@@ -415,12 +419,12 @@ static void rna_def_layer_collection(BlenderRNA *brna)
/* Run-time flags. */
prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE_VIEW_LAYER);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(
- prop,
- "Visible",
- "Whether this collection is visible, take into account the collection parent");
+ RNA_def_property_ui_text(prop,
+ "Visible",
+ "Whether this collection is visible for the viewlayer, take into "
+ "account the collection parent");
func = RNA_def_function(srna, "has_objects", "rna_LayerCollection_has_objects");
RNA_def_function_ui_description(func, "");
@@ -573,7 +577,7 @@ void RNA_def_view_layer(BlenderRNA *brna)
/* debug update routine */
func = RNA_def_function(srna, "update", "rna_ViewLayer_update_tagged");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
RNA_def_function_ui_description(
func, "Update data tagged to be updated from previous access to data or operators");
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index f6cfc33c82e..f5730885193 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -2179,7 +2179,7 @@ static void rna_def_linestyle(BlenderRNA *brna)
prop = RNA_def_property(srna, "texture_spacing", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "texstep");
RNA_def_property_range(prop, 0.01f, 100.0f);
- RNA_def_property_ui_text(prop, "Texture spacing", "Spacing for textures along stroke length");
+ RNA_def_property_ui_text(prop, "Texture Spacing", "Spacing for textures along stroke length");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
/* anim */
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index fec991e16da..2c42dba9131 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -461,8 +461,6 @@ static VFont *rna_Main_fonts_load(Main *bmain,
"Cannot read '%s': %s",
filepath,
errno ? strerror(errno) : TIP_("unsupported font format"));
-
- id_us_min((ID *)font);
}
return font;
}
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index dd26b91de7f..efae4785a69 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -43,7 +43,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = {
{0, "", ICON_NONE, NULL, NULL},
{MA_RAMP_LIGHT, "LIGHTEN", 0, "Lighten", ""},
{MA_RAMP_SCREEN, "SCREEN", 0, "Screen", ""},
- {MA_RAMP_DODGE, "DODGE", 0, "Dodge", ""},
+ {MA_RAMP_DODGE, "DODGE", 0, "Color Dodge", ""},
{MA_RAMP_ADD, "ADD", 0, "Add", ""},
{0, "", ICON_NONE, NULL, NULL},
{MA_RAMP_OVERLAY, "OVERLAY", 0, "Overlay", ""},
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 21df0510941..72cba6f19ea 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -503,9 +503,7 @@ static void rna_Mesh_texspace_size_get(PointerRNA *ptr, float values[3])
{
Mesh *me = (Mesh *)ptr->data;
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
copy_v3_v3(values, me->size);
}
@@ -514,9 +512,7 @@ static void rna_Mesh_texspace_loc_get(PointerRNA *ptr, float values[3])
{
Mesh *me = (Mesh *)ptr->data;
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ BKE_mesh_texspace_ensure(me);
copy_v3_v3(values, me->loc);
}
@@ -547,7 +543,7 @@ static void rna_MeshVertex_undeformed_co_get(PointerRNA *ptr, float values[3])
/* orco is normalized to 0..1, we do inverse to match mvert->co */
float loc[3], size[3];
- BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size);
+ BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size);
madd_v3_v3v3v3(values, loc, orco[(mvert - me->mvert)], size);
}
else {
@@ -2211,15 +2207,6 @@ void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable)
RNA_def_property_editable_func(prop, texspace_editable);
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
- /* not supported yet */
-# if 0
- prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
- RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-# endif
-
/* materials */
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
@@ -2245,13 +2232,13 @@ static void rna_def_mesh_vertices(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_sdna(srna, "Mesh");
RNA_def_struct_ui_text(srna, "Mesh Vertices", "Collection of mesh vertices");
- func = RNA_def_function(srna, "add", "ED_mesh_vertices_add");
+ func = RNA_def_function(srna, "add", "ED_mesh_verts_add");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(
func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add", 0, INT_MAX);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
# if 0 /* BMESH_TODO Remove until BMesh merge */
- func = RNA_def_function(srna, "remove", "ED_mesh_vertices_remove");
+ func = RNA_def_function(srna, "remove", "ED_mesh_verts_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to remove", 0, INT_MAX);
# endif
@@ -2427,7 +2414,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_pointer_funcs(
prop, "rna_Mesh_uv_layer_active_get", "rna_Mesh_uv_layer_active_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
- RNA_def_property_ui_text(prop, "Active UV loop layer", "Active UV loop layer");
+ RNA_def_property_ui_text(prop, "Active UV Loop Layer", "Active UV loop layer");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
@@ -2435,7 +2422,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
"rna_Mesh_uv_layer_active_index_get",
"rna_Mesh_uv_layer_active_index_set",
"rna_Mesh_uv_layer_index_range");
- RNA_def_property_ui_text(prop, "Active UV loop layer Index", "Active UV loop layer index");
+ RNA_def_property_ui_text(prop, "Active UV Loop Layer Index", "Active UV loop layer index");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
@@ -2815,28 +2802,28 @@ static void rna_def_mesh(BlenderRNA *brna)
prop, "rna_Mesh_uv_layer_clone_get", "rna_Mesh_uv_layer_clone_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
- prop, "Clone UV loop layer", "UV loop layer to be used as cloning source");
+ prop, "Clone UV Loop Layer", "UV loop layer to be used as cloning source");
prop = RNA_def_property(srna, "uv_layer_clone_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_Mesh_uv_layer_clone_index_get",
"rna_Mesh_uv_layer_clone_index_set",
"rna_Mesh_uv_layer_index_range");
- RNA_def_property_ui_text(prop, "Clone UV loop layer Index", "Clone UV loop layer index");
+ RNA_def_property_ui_text(prop, "Clone UV Loop Layer Index", "Clone UV loop layer index");
prop = RNA_def_property(srna, "uv_layer_stencil", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshUVLoopLayer");
RNA_def_property_pointer_funcs(
prop, "rna_Mesh_uv_layer_stencil_get", "rna_Mesh_uv_layer_stencil_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Mask UV loop layer", "UV loop layer to mask the painted area");
+ RNA_def_property_ui_text(prop, "Mask UV Loop Layer", "UV loop layer to mask the painted area");
prop = RNA_def_property(srna, "uv_layer_stencil_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_Mesh_uv_layer_stencil_index_get",
"rna_Mesh_uv_layer_stencil_index_set",
"rna_Mesh_uv_layer_index_range");
- RNA_def_property_ui_text(prop, "Mask UV loop layer Index", "Mask UV loop layer index");
+ RNA_def_property_ui_text(prop, "Mask UV Loop Layer Index", "Mask UV loop layer index");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
/* Vertex colors */
@@ -3008,11 +2995,35 @@ static void rna_def_mesh(BlenderRNA *brna)
"values preserve finer details");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ prop = RNA_def_property(srna, "remesh_voxel_adaptivity", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "remesh_voxel_adaptivity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 4);
+ RNA_def_property_ui_text(
+ prop,
+ "Adaptivity",
+ "Reduces the final face count by simplifying geometry where detail is not needed, "
+ "generating triangles. A value greater than 0 disables Fix Poles");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
prop = RNA_def_property(srna, "remesh_smooth_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_SMOOTH_NORMALS);
RNA_def_property_ui_text(prop, "Smooth Normals", "Smooth the normals of the remesher result");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ prop = RNA_def_property(srna, "remesh_fix_poles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_FIX_POLES);
+ RNA_def_property_ui_text(prop, "Fix Poles", "Produces less poles and a better topology flow");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "remesh_preserve_volume", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_VOLUME);
+ RNA_def_property_ui_text(
+ prop,
+ "Preserve Volume",
+ "Projects the mesh to preserve the volume and details of the original mesh");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
prop = RNA_def_property(srna, "remesh_preserve_paint_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_PAINT_MASK);
RNA_def_property_boolean_default(prop, false);
@@ -3084,15 +3095,6 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
# endif
- /* not supported yet */
-# if 0
- prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
- RNA_def_property_editable_func(prop, texspace_editable);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-# endif
-
/* editflag */
prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_X);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 18cf57c5624..7a3ca7e9dd8 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -929,7 +929,7 @@ static void rna_MultiresModifier_type_set(PointerRNA *ptr, int value)
Object *ob = (Object *)ptr->owner_id;
MultiresModifierData *mmd = (MultiresModifierData *)ptr->data;
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
mmd->simple = value;
}
@@ -1401,7 +1401,7 @@ static void rna_CorrectiveSmoothModifier_update(Main *bmain, Scene *scene, Point
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
rna_Modifier_update(bmain, scene, ptr);
}
@@ -3100,7 +3100,7 @@ static void rna_def_modifier_cast(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_transform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CAST_USE_OB_TRANSFORM);
RNA_def_property_ui_text(
- prop, "Use transform", "Use object transform to control projection shape");
+ prop, "Use Transform", "Use object transform to control projection shape");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
@@ -5922,7 +5922,7 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 2.0f, 16.0f);
RNA_def_property_ui_text(
- prop, "Interpolation falloff", "Controls how much nearby polygons influence deformation");
+ prop, "Interpolation Falloff", "Controls how much nearby polygons influence deformation");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "is_bound", PROP_BOOLEAN, PROP_NONE);
@@ -6217,7 +6217,7 @@ void RNA_def_modifier(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_ApplyOnSpline);
RNA_def_property_ui_text(
prop,
- "Apply on spline",
+ "Apply on Spline",
"Apply this and all preceding deformation modifiers on splines' points rather than "
"on filled curve/surface");
RNA_def_property_ui_icon(prop, ICON_SURFACE_DATA, 0);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 913324e4997..287c7502c41 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -1482,7 +1482,7 @@ static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int
node->typeinfo->ext.call(NULL, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "label", &ret);
- rlabel = *(char **)ret;
+ rlabel = (char *)ret;
BLI_strncpy(label, rlabel != NULL ? rlabel : "", maxlen);
RNA_parameter_list_free(&list);
@@ -3986,7 +3986,7 @@ static void def_mix_rgb(StructRNA *srna)
prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
- RNA_def_property_ui_text(prop, "Blend Type", "");
+ RNA_def_property_ui_text(prop, "Blending Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE);
@@ -4431,7 +4431,7 @@ static void def_sh_tex_voronoi(StructRNA *srna)
"DISTANCE_TO_EDGE",
0,
"Distance To Edge",
- "Computes the distance to the edge of the vornoi cell"},
+ "Computes the distance to the edge of the voronoi cell"},
{SHD_VORONOI_N_SPHERE_RADIUS,
"N_SPHERE_RADIUS",
0,
@@ -5719,7 +5719,7 @@ static void def_cmp_dilate_erode(StructRNA *srna)
prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "custom2");
RNA_def_property_range(prop, -5000, 5000);
- RNA_def_property_ui_range(prop, -100, 100, 0, -1);
+ RNA_def_property_ui_range(prop, -100, 100, 1, -1);
RNA_def_property_ui_text(prop, "Distance", "Distance to grow/shrink (number of iterations)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -6955,7 +6955,7 @@ static void def_cmp_boxmask(StructRNA *srna)
prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_masktype_items);
- RNA_def_property_ui_text(prop, "Mask type", "");
+ RNA_def_property_ui_text(prop, "Mask Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeBoxMask", "storage");
@@ -7002,7 +7002,7 @@ static void def_cmp_ellipsemask(StructRNA *srna)
prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_masktype_items);
- RNA_def_property_ui_text(prop, "Mask type", "");
+ RNA_def_property_ui_text(prop, "Mask Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeEllipseMask", "storage");
@@ -7117,7 +7117,7 @@ static void def_cmp_bokehimage(StructRNA *srna)
RNA_def_property_float_sdna(prop, NULL, "lensshift");
RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_range(prop, -1.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Lens shift", "Shift of the lens components");
+ RNA_def_property_ui_text(prop, "Lens Shift", "Shift of the lens components");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 3054e32d558..68859aaf1de 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -2764,7 +2764,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "parentinv");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(
- prop, "Matrix", "Inverse of object's parent matrix at time of parenting");
+ prop, "Parent Inverse Matrix", "Inverse of object's parent matrix at time of parenting");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
/* modifiers */
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 56d25f5bebf..babf388bfc7 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -70,6 +70,7 @@ static const EnumPropertyItem space_items[] = {
# include "BKE_customdata.h"
# include "BKE_font.h"
# include "BKE_global.h"
+# include "BKE_layer.h"
# include "BKE_main.h"
# include "BKE_mesh.h"
# include "BKE_mball.h"
@@ -283,6 +284,11 @@ static void rna_Object_local_view_set(Object *ob,
}
}
+static bool rna_Object_visible_in_viewport_get(Object *ob, View3D *v3d)
+{
+ return BKE_object_is_visible_in_viewport(v3d, ob);
+}
+
/* Convert a given matrix from a space to another (using the object and/or a bone as
* reference). */
static void rna_Object_mat_convert_space(Object *ob,
@@ -825,6 +831,15 @@ void RNA_api_object(StructRNA *srna)
parm = RNA_def_boolean(func, "state", 0, "", "Local view state to define");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* Viewport */
+ func = RNA_def_function(srna, "visible_in_viewport_get", "rna_Object_visible_in_viewport_get");
+ RNA_def_function_ui_description(
+ func, "Check for local view and local collections for this viewport and object");
+ parm = RNA_def_pointer(func, "viewport", "SpaceView3D", "", "Viewport in local collections");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "result", 0, "", "Object viewport visibility");
+ RNA_def_function_return(func, parm);
+
/* Matrix space conversion */
func = RNA_def_function(srna, "convert_space", "rna_Object_mat_convert_space");
RNA_def_function_ui_description(
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 430059c7a18..87b14b56504 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -1943,7 +1943,7 @@ static void rna_def_softbody(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_estimate_matrix", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "solverflags", SBSO_ESTIMATEIPO);
- RNA_def_property_ui_text(prop, "Estimate matrix", "Estimate matrix... split to COM, ROT, SCALE");
+ RNA_def_property_ui_text(prop, "Estimate Matrix", "Estimate matrix... split to COM, ROT, SCALE");
/***********************************************************************************/
/* these are not exactly settings, but reading calculated results*/
@@ -1952,7 +1952,7 @@ static void rna_def_softbody(BlenderRNA *brna)
/* translation */
prop = RNA_def_property(srna, "location_mass_center", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "lcom");
- RNA_def_property_ui_text(prop, "Center of mass", "Location of Center of mass");
+ RNA_def_property_ui_text(prop, "Center of Mass", "Location of center of mass");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
/* matrix */
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 98ecb053641..211d9e19ab4 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -1891,7 +1891,7 @@ static void rna_def_fluid_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "viscosity_beta");
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Stiff viscosity", "Creates viscosity for expanding fluid");
+ RNA_def_property_ui_text(prop, "Stiff Viscosity", "Creates viscosity for expanding fluid");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
/* Double density relaxation */
@@ -2398,7 +2398,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_DIE_ON_COL);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
- prop, "Die on hit", "Particles die when they collide with a deflector object");
+ prop, "Die on Hit", "Particles die when they collide with a deflector object");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "use_size_deflect", PROP_BOOLEAN, PROP_NONE);
@@ -3297,7 +3297,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "keyed_loops");
RNA_def_property_range(prop, 1.0f, 10000.0f);
RNA_def_property_ui_range(prop, 1.0f, 100.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Loop count", "Number of times the keys are looped");
+ RNA_def_property_ui_text(prop, "Loop Count", "Number of times the keys are looped");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
/* modified dm support */
@@ -3594,7 +3594,7 @@ static void rna_def_particle_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_keyed_timing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_KEYED_TIMING);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Keyed timing", "Use key times");
+ RNA_def_property_ui_text(prop, "Keyed Timing", "Use key times");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index e514fd82aca..8c4b7dd52d9 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -648,7 +648,7 @@ bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain),
/* Remember that insertion operations are defined and stored in correct order, which means that
* even if we insert several items in a row, we always insert first one, then second one, etc.
- * So we should always find 'anchor' constraint in both _src *and* _dst> */
+ * So we should always find 'anchor' constraint in both _src *and* _dst */
bConstraint *con_anchor = NULL;
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
con_anchor = BLI_findstring(
@@ -669,7 +669,11 @@ bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain),
}
con_src = con_src ? con_src->next : pchan_src->constraints.first;
- BLI_assert(con_src != NULL);
+ if (con_src == NULL) {
+ printf("%s: Could not find constraint to insert, doing nothing...\n", __func__);
+ BLI_assert(0);
+ return false;
+ }
bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true);
@@ -1299,7 +1303,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Custom Object", "Object that defines custom draw type for this bone");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
- RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_dependency_update");
prop = RNA_def_property(srna, "custom_shape_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "custom_scale");
@@ -1457,7 +1461,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
prop = RNA_def_property(srna, "step_count", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "numstep");
RNA_def_property_range(prop, 1.f, 50.f);
- RNA_def_property_ui_text(prop, "Num steps", "Divide the frame interval into this many steps");
+ RNA_def_property_ui_text(prop, "Num Steps", "Divide the frame interval into this many steps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
@@ -1478,7 +1482,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_auto_step", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ITASC_AUTO_STEP);
RNA_def_property_ui_text(prop,
- "Auto step",
+ "Auto Step",
"Automatically determine the optimal number of steps for best "
"performance/accuracy trade off");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
@@ -1487,14 +1491,14 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "minstep");
RNA_def_property_range(prop, 0.0f, 0.1f);
RNA_def_property_ui_text(
- prop, "Min step", "Lower bound for timestep in second in case of automatic substeps");
+ prop, "Min Step", "Lower bound for timestep in second in case of automatic substeps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "step_max", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "maxstep");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(
- prop, "Max step", "Higher bound for timestep in second in case of automatic substeps");
+ prop, "Max Step", "Higher bound for timestep in second in case of automatic substeps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "feedback", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 6e21d02c0b3..4db702b215f 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -613,7 +613,10 @@ static bool rna_Property_overridable_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY) != 0;
+ IDProperty *idprop = rna_idproperty_check(&prop, ptr);
+
+ return idprop != NULL ? (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0 :
+ (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY) != 0;
}
static bool rna_Property_use_output_get(PointerRNA *ptr)
@@ -1154,20 +1157,21 @@ static bool rna_property_override_diff_propptr_validate_diffing(PointerRNA *prop
*r_is_id = *r_is_null = *r_is_type_diff = false;
/* Beware, PointerRNA_NULL has no type and is considered a 'blank page'! */
- if (propptr_a->type == NULL) {
- if (propptr_b == NULL || propptr_b->type == NULL) {
+ if (ELEM(NULL, propptr_a->type, propptr_a->data)) {
+ if (ELEM(NULL, propptr_b, propptr_b->type, propptr_b->data)) {
*r_is_null = true;
}
else {
*r_is_id = RNA_struct_is_ID(propptr_b->type);
*r_is_null = true;
- *r_is_type_diff = true;
+ *r_is_type_diff = propptr_a->type != propptr_b->type;
}
is_valid_for_diffing = false;
}
else {
*r_is_id = RNA_struct_is_ID(propptr_a->type);
- *r_is_null = *r_is_type_diff = (ELEM(NULL, propptr_b, propptr_b->type));
+ *r_is_null = (ELEM(NULL, propptr_b, propptr_b->type, propptr_b->data));
+ *r_is_type_diff = (propptr_b == NULL || propptr_b->type != propptr_a->type);
is_valid_for_diffing = !(*r_is_id || *r_is_null);
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 193383637d0..5841d90f3ce 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3422,7 +3422,7 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
prop, NULL, "rna_UnifiedPaintSettings_unprojected_radius_set", NULL);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 0.001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001, 1, 0, -1);
+ RNA_def_property_ui_range(prop, 0.001, 1, 1, -1);
RNA_def_property_ui_text(prop, "Unprojected Radius", "Radius of brush in Blender units");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_radius_update");
@@ -4861,66 +4861,6 @@ static void rna_def_bake_data(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
-static void rna_def_gpu_ssao_fx(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "GPUSSAOSettings", NULL);
- RNA_def_struct_ui_text(
- srna, "GPU SSAO", "Settings for GPU based screen space ambient occlusion");
-
- prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_text(prop, "Strength", "Strength of the SSAO effect");
- RNA_def_property_range(prop, 0.0f, 250.0f);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "distance_max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_text(
- prop, "Distance", "Distance of object that contribute to the SSAO effect");
- RNA_def_property_range(prop, 0.0f, 100000.0f);
- RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "attenuation", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant");
- RNA_def_property_range(prop, 1.0f, 100000.0f);
- RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
- RNA_def_property_ui_text(prop, "Samples", "Number of samples");
- RNA_def_property_range(prop, 1, 500);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_ui_text(prop, "Color", "Color for screen space ambient occlusion effect");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-}
-
-static void rna_def_gpu_fx(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- rna_def_gpu_ssao_fx(brna);
-
- srna = RNA_def_struct(brna, "GPUFXSettings", NULL);
- RNA_def_struct_ui_text(srna, "GPU FX Settings", "Settings for GPU based compositing");
-
- prop = RNA_def_property(srna, "ssao", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "GPUSSAOSettings");
- RNA_def_property_ui_text(prop, "Screen Space Ambient Occlusion settings", "");
-
- prop = RNA_def_property(srna, "use_ssao", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "fx_flag", GPU_FX_FLAG_SSAO);
- RNA_def_property_ui_text(
- prop, "SSAO", "Use screen space ambient occlusion of field on viewport");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-}
-
static void rna_def_view_layers(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -5456,7 +5396,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 500);
RNA_def_property_int_default(prop, 25);
RNA_def_property_ui_text(prop,
- "Keyframe interval",
+ "Keyframe Interval",
"Distance between key frames, also known as GOP size; "
"influences file size and seekability");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -5467,14 +5407,14 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 16);
RNA_def_property_ui_text(
prop,
- "Max B-frames",
+ "Max B-Frames",
"Maximum number of B-frames between non-B-frames; influences file size and seekability");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_max_b_frames", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FFMPEG_USE_MAX_B_FRAMES);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Use max B-frames", "Set a maximum number of B-frames");
+ RNA_def_property_ui_text(prop, "Use Max B-Frames", "Set a maximum number of B-frames");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "buffersize", PROP_INT, PROP_NONE);
@@ -5498,7 +5438,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_default(prop, FFM_CRF_MEDIUM);
RNA_def_property_ui_text(
prop,
- "Output quality",
+ "Output Quality",
"Constant Rate Factor (CRF); tradeoff between video quality and file size");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -5508,7 +5448,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, ffmpeg_preset_items);
RNA_def_property_enum_default(prop, FFM_PRESET_GOOD);
RNA_def_property_ui_text(
- prop, "Encoding speed", "Tradeoff between encoding speed and compression ratio");
+ prop, "Encoding Speed", "Tradeoff between encoding speed and compression ratio");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_autosplit", PROP_BOOLEAN, PROP_NONE);
@@ -5568,22 +5508,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem display_mode_items[] = {
- {R_OUTPUT_SCREEN,
- "SCREEN",
- 0,
- "Full Screen",
- "Images are rendered in a maximized Image Editor"},
- {R_OUTPUT_AREA, "AREA", 0, "Image Editor", "Images are rendered in an Image Editor"},
- {R_OUTPUT_WINDOW, "WINDOW", 0, "New Window", "Images are rendered in a new window"},
- {R_OUTPUT_NONE,
- "NONE",
- 0,
- "Keep User Interface",
- "Images are rendered without changing the user interface"},
- {0, NULL, 0, NULL, NULL},
- };
-
/* Bake */
static const EnumPropertyItem bake_mode_items[] = {
//{RE_BAKE_AO, "AO", 0, "Ambient Occlusion", "Bake ambient occlusion"},
@@ -5758,7 +5682,8 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "frs_sec_base");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 1e-5f, 1e6f);
- RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, -1);
+ /* Important to show at least 3 decimal points because multiple presets set this to 1.001. */
+ RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, 3);
RNA_def_property_ui_text(prop, "FPS Base", "Framerate base");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update");
@@ -5980,13 +5905,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"(this solves anti-aliasing issues with compositing)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "displaymode");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_items(prop, display_mode_items);
- RNA_def_property_ui_text(prop, "Display", "Select where rendered images will be displayed");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "use_lock_interface", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_lock_interface", 1);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -6068,7 +5986,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_bake_user_scale", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_USERSCALE);
- RNA_def_property_ui_text(prop, "User scale", "Use a user scale for the derivative map");
+ RNA_def_property_ui_text(prop, "User Scale", "Use a user scale for the derivative map");
prop = RNA_def_property(srna, "bake_user_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bake_user_scale");
@@ -7930,7 +7848,6 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_define_animate_sdna(true);
/* *** Animated *** */
rna_def_scene_render_data(brna);
- rna_def_gpu_fx(brna);
rna_def_scene_render_view(brna);
/* Scene API */
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 2b1b23a40f4..8a06d594c1f 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -88,7 +88,11 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
BPy_END_ALLOW_THREADS;
# endif
- BKE_scene_camera_switch_update(scene);
+ if (BKE_scene_camera_switch_update(scene)) {
+ for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
+ BKE_screen_view3d_scene_sync(sc, scene);
+ }
+ }
/* don't do notifier when we're rendering, avoid some viewport crashes
* redrawing while the data is being modified for render */
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 728ef3fb706..1637f8cfed5 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -272,7 +272,7 @@ static void rna_Area_ui_type_update(bContext *C, PointerRNA *ptr)
sa->butspacetype_subtype = 0;
}
-static void rna_View2D_region_to_view(struct View2D *v2d, int x, int y, float result[2])
+static void rna_View2D_region_to_view(struct View2D *v2d, float x, float y, float result[2])
{
UI_view2d_region_to_view(v2d, x, y, &result[0], &result[1]);
}
@@ -406,9 +406,9 @@ static void rna_def_view2d_api(StructRNA *srna)
func = RNA_def_function(srna, "region_to_view", "rna_View2D_region_to_view");
RNA_def_function_ui_description(func, "Transform region coordinates to 2D view");
- parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000);
+ parm = RNA_def_float(func, "x", 0, -FLT_MAX, FLT_MAX, "x", "Region x coordinate", -10000, 10000);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000);
+ parm = RNA_def_float(func, "y", 0, -FLT_MAX, FLT_MAX, "y", "Region y coordinate", -10000, 10000);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_array(func,
"result",
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index ef550a079ad..1457bbfd3c3 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -204,10 +204,11 @@ static PointerRNA rna_ParticleBrush_curve_get(PointerRNA *ptr)
static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (!edit) {
return;
@@ -259,8 +260,9 @@ static const EnumPropertyItem *rna_ParticleEdit_tool_itemf(bContext *C,
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
# if 0
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit ? edit->psys : NULL;
# else
/* use this rather than PE_get_current() - because the editing cache is
@@ -285,14 +287,14 @@ static bool rna_ParticleEdit_editable_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
- return (pset->object && pset->scene && PE_get_current(pset->scene, pset->object));
+ return (pset->object && pset->scene && PE_get_current(NULL, pset->scene, pset->object));
}
static bool rna_ParticleEdit_hair_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
if (pset->scene) {
- PTCacheEdit *edit = PE_get_current(pset->scene, pset->object);
+ PTCacheEdit *edit = PE_get_current(NULL, pset->scene, pset->object);
return (edit && edit->psys);
}
@@ -646,7 +648,7 @@ static void rna_def_paint(BlenderRNA *brna)
prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "num_input_samples");
- RNA_def_property_ui_range(prop, 1, PAINT_MAX_INPUT_SAMPLES, 0, -1);
+ RNA_def_property_ui_range(prop, 1, PAINT_MAX_INPUT_SAMPLES, 1, -1);
RNA_def_property_ui_text(
prop, "Input Samples", "Average multiple input samples together to smooth the brush stroke");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
@@ -1021,7 +1023,7 @@ static void rna_def_image_paint(BlenderRNA *brna)
/* integers */
prop = RNA_def_property(srna, "seam_bleed", PROP_INT, PROP_PIXEL);
- RNA_def_property_ui_range(prop, 0, 8, 0, -1);
+ RNA_def_property_ui_range(prop, 0, 8, 1, -1);
RNA_def_property_ui_text(
prop, "Bleed", "Extend paint beyond the faces UVs to reduce seams (in pixels, slower)");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 31bc9927026..31ead989f25 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -1462,7 +1462,7 @@ static const EnumPropertyItem blend_mode_items[] = {
{0, "", ICON_NONE, NULL, NULL},
{SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""},
{SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""},
- {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""},
+ {SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""},
{SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
{0, "", ICON_NONE, NULL, NULL},
{SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
@@ -1723,7 +1723,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "blend_mode");
RNA_def_property_enum_items(prop, blend_mode_items);
RNA_def_property_ui_text(
- prop, "Blend Mode", "Method for controlling how the strip combines with other strips");
+ prop, "Blending Mode", "Method for controlling how the strip combines with other strips");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -1740,7 +1740,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_float_sdna(prop, NULL, "effect_fader");
- RNA_def_property_ui_text(prop, "Effect fader position", "Custom fade value");
+ RNA_def_property_ui_text(prop, "Effect Fader Position", "Custom fade value");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -1758,7 +1758,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "speed_fader");
RNA_def_property_ui_text(
prop,
- "Speed factor",
+ "Speed Factor",
"Multiply the current speed of the sequence with this number or remap current frame "
"to this frame");
RNA_def_property_update(
@@ -1944,7 +1944,7 @@ static void rna_def_editor(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, SEQ_CACHE_COST_MAX, 0.1f, 1);
RNA_def_property_float_sdna(prop, NULL, "recycle_max_cost");
RNA_def_property_ui_text(
- prop, "Recycle Up To Cost", "Only frames with cost lower than this value will be recycled");
+ prop, "Recycle Up to Cost", "Only frames with cost lower than this value will be recycled");
}
static void rna_def_filter_video(StructRNA *srna)
@@ -2225,7 +2225,7 @@ static void rna_def_scene(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "Sequence");
prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_ui_text(prop, "Scene", "Scene that this sequence uses");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
@@ -2639,8 +2639,7 @@ static void rna_def_solid_color(StructRNA *srna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "col");
RNA_def_property_ui_text(prop, "Color", "Effect Strip color");
- RNA_def_property_update(
- prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
}
static void rna_def_speed_control(StructRNA *srna)
@@ -2661,14 +2660,14 @@ static void rna_def_speed_control(StructRNA *srna)
prop = RNA_def_property(srna, "use_as_speed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_INTEGRATE);
RNA_def_property_ui_text(
- prop, "Use as speed", "Interpret the value as speed instead of a frame number");
+ prop, "Use as Speed", "Interpret the value as speed instead of a frame number");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "use_scale_to_length", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y);
RNA_def_property_ui_text(
- prop, "Scale to length", "Scale values from 0.0 to 1.0 to target sequence length");
+ prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
}
@@ -2786,27 +2785,31 @@ static void rna_def_text(StructRNA *srna)
static void rna_def_color_mix(StructRNA *srna)
{
static EnumPropertyItem blend_color_items[] = {
- {SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
- {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
+ {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""},
{SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
+ {SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""},
+ {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""},
- {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""},
{SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""},
+ {SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""},
+ {SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
- {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""},
- {SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""},
- {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
{SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
{SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""},
- {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
- {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
{SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""},
- {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
+ {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
+ {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
+ {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
+ {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{SEQ_TYPE_HUE, "HUE", 0, "Hue", ""},
{SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""},
+ {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
{SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""},
- {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
- {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -2818,7 +2821,7 @@ static void rna_def_color_mix(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "blend_effect");
RNA_def_property_enum_items(prop, blend_color_items);
RNA_def_property_ui_text(
- prop, "Blend Effect", "Method for controlling how the strip combines with other strips");
+ prop, "Blending Mode", "Method for controlling how the strip combines with other strips");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -3015,7 +3018,7 @@ static void rna_def_whitebalance_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "white_value", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "white_value");
- RNA_def_property_ui_text(prop, "White value", "This color defines white in the strip");
+ RNA_def_property_ui_text(prop, "White Value", "This color defines white in the strip");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
}
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
index acf525e1788..cd4e027ce7c 100644
--- a/source/blender/makesrna/intern/rna_shader_fx.c
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -260,14 +260,14 @@ static void rna_def_shader_fx_colorize(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "low_color");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Low color", "First color used for effect");
+ RNA_def_property_ui_text(prop, "Low Color", "First color used for effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "high_color");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Height color", "Second color used for effect");
+ RNA_def_property_ui_text(prop, "High Color", "Second color used for effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index fa0297ac306..c00cc789eff 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -588,7 +588,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_high_resolution", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGHRES);
- RNA_def_property_ui_text(prop, "High res", "Enable high resolution (using amplification)");
+ RNA_def_property_ui_text(prop, "High Res", "Enable high resolution (using amplification)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
@@ -668,7 +668,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE_LOG);
- RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x ");
+ RNA_def_property_ui_text(prop, "Logarithmic Dissolve", "Using 1/x ");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
@@ -1204,7 +1204,7 @@ static void rna_def_smoke_coll_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, smoke_coll_type_items);
- RNA_def_property_ui_text(prop, "Collision type", "Collision type");
+ RNA_def_property_ui_text(prop, "Collision Type", "Collision type");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index bbddf1b8310..e4a81e20942 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -587,7 +587,7 @@ static void rna_Space_bool_from_region_flag_set_by_type(PointerRNA *ptr,
{
ScrArea *sa = rna_area_from_space(ptr);
ARegion *ar = BKE_area_find_region_type(sa, region_type);
- if (ar) {
+ if (ar && (ar->alignment != RGN_ALIGN_NONE)) {
SET_FLAG_FROM_TEST(ar->flag, value, region_flag);
}
ED_region_tag_redraw(ar);
@@ -785,13 +785,18 @@ static void rna_Space_view2d_sync_update(Main *UNUSED(bmain),
static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
+ bool changed = false;
/* need set all caches as dirty to recalculate onion skinning */
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
if (ob->type == OB_GPENCIL) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ changed = true;
}
}
- WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ if (changed) {
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ }
}
/* Space 3D View */
@@ -1103,7 +1108,7 @@ static const EnumPropertyItem *rna_View3DShading_color_type_itemf(bContext *UNUS
}
else {
/* Solid mode, or lookdev mode for workbench engine. */
- r_free = false;
+ *r_free = false;
return rna_enum_shading_color_type_items;
}
}
@@ -1272,6 +1277,11 @@ static char *rna_View3DOverlay_path(PointerRNA *UNUSED(ptr))
/* Space Image Editor */
+static char *rna_SpaceUVEditor_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("uv_editor");
+}
+
static PointerRNA rna_SpaceImageEditor_uvedit_get(PointerRNA *ptr)
{
return rna_pointer_inherit_refine(ptr, &RNA_SpaceUVEditor, ptr->data);
@@ -2192,6 +2202,11 @@ static void rna_SpaceClipEditor_view_type_update(Main *UNUSED(bmain),
/* File browser. */
+static char *rna_FileSelectParams_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("params");
+}
+
int rna_FileSelectParams_filename_editable(struct PointerRNA *ptr, const char **r_info)
{
FileSelectParams *params = ptr->data;
@@ -2706,6 +2721,7 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceUVEditor", NULL);
RNA_def_struct_sdna(srna, "SpaceImage");
RNA_def_struct_nested(brna, srna, "SpaceImageEditor");
+ RNA_def_struct_path_func(srna, "rna_SpaceUVEditor_path");
RNA_def_struct_ui_text(srna, "Space UV Editor", "UV editor data for the image editor space");
/* selection */
@@ -3970,10 +3986,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop, "Show 3D Marker Names", "Show names for reconstructed tracks objects");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "fx_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
prop = RNA_def_property(srna, "use_local_collections", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_LOCAL_COLLECTIONS);
RNA_def_property_ui_text(
@@ -4292,7 +4304,7 @@ static void rna_def_space_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "sample_histogram", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "sample_line_hist");
RNA_def_property_struct_type(prop, "Histogram");
- RNA_def_property_ui_text(prop, "Line sample", "Sampled colors along line");
+ RNA_def_property_ui_text(prop, "Line Sample", "Sampled colors along line");
prop = RNA_def_property(srna, "zoom", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 2);
@@ -4729,7 +4741,7 @@ static void rna_def_space_text(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_match_case", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", ST_MATCH_CASE);
RNA_def_property_ui_text(
- prop, "Match case", "Search string is sensitive to uppercase and lowercase letters");
+ prop, "Match Case", "Search string is sensitive to uppercase and lowercase letters");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
prop = RNA_def_property(srna, "find_text", PROP_STRING, PROP_NONE);
@@ -5293,7 +5305,11 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{FILTER_ID_TXT, "TEXT", ICON_TEXT, "Texts", "Show/hide Text data-blocks"},
{FILTER_ID_VF, "FONT", ICON_FONT_DATA, "Fonts", "Show/hide Font data-blocks"},
{FILTER_ID_WO, "WORLD", ICON_WORLD_DATA, "Worlds", "Show/hide World data-blocks"},
- {FILTER_ID_WS, "WORK_SPACE", ICON_NONE, "Workspaces", "Show/hide workspace data-blocks"},
+ {FILTER_ID_WS,
+ "WORK_SPACE",
+ ICON_WORKSPACE,
+ "Workspaces",
+ "Show/hide workspace data-blocks"},
{0, NULL, 0, NULL, NULL},
};
@@ -5335,6 +5351,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
};
srna = RNA_def_struct(brna, "FileSelectParams", NULL);
+ RNA_def_struct_path_func(srna, "rna_FileSelectParams_path");
RNA_def_struct_ui_text(srna, "File Select Parameters", "File Select Parameters");
prop = RNA_def_property(srna, "title", PROP_STRING, PROP_NONE);
@@ -5424,7 +5441,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_filter_backup", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_BLENDER_BACKUP);
RNA_def_property_ui_text(
- prop, "Filter BlenderBackup files", "Show .blend1, .blend2, etc. files");
+ prop, "Filter Blender Backup Files", "Show .blend1, .blend2, etc. files");
RNA_def_property_ui_icon(prop, ICON_FILE_BACKUP, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -5476,7 +5493,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_enum_items(prop, file_filter_idtypes_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(
- prop, "Filter ID types", "Which ID types to show/hide, when browsing a library");
+ prop, "Filter ID Types", "Which ID types to show/hide, when browsing a library");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "filter_id_category", PROP_ENUM, PROP_NONE);
@@ -5484,7 +5501,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_enum_items(prop, file_filter_idcategories_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(
- prop, "Filter ID categories", "Which ID categories to show/hide, when browsing a library");
+ prop, "Filter ID Categories", "Which ID categories to show/hide, when browsing a library");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "filter_glob", PROP_STRING, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c
index 64a23dfa985..778e817c73e 100644
--- a/source/blender/makesrna/intern/rna_text.c
+++ b/source/blender/makesrna/intern/rna_text.c
@@ -87,8 +87,60 @@ static int rna_Text_current_line_index_get(PointerRNA *ptr)
static void rna_Text_current_line_index_set(PointerRNA *ptr, int value)
{
- Text *text = (Text *)ptr->data;
- txt_move_toline(text, value, 0);
+ Text *text = ptr->data;
+ TextLine *line = BLI_findlink(&text->lines, value);
+ if (line == NULL) {
+ line = text->lines.last;
+ }
+ text->curl = line;
+ text->curc = 0;
+}
+
+static int rna_Text_select_end_line_index_get(PointerRNA *ptr)
+{
+ Text *text = ptr->data;
+ return BLI_findindex(&text->lines, text->sell);
+}
+
+static void rna_Text_select_end_line_index_set(PointerRNA *ptr, int value)
+{
+ Text *text = ptr->data;
+ TextLine *line = BLI_findlink(&text->lines, value);
+ if (line == NULL) {
+ line = text->lines.last;
+ }
+ text->sell = line;
+ text->selc = 0;
+}
+
+static int rna_Text_current_character_get(PointerRNA *ptr)
+{
+ Text *text = ptr->data;
+ return BLI_str_utf8_offset_to_index(text->curl->line, text->curc);
+}
+
+static void rna_Text_current_character_set(PointerRNA *ptr, int index)
+{
+ Text *text = ptr->data;
+ TextLine *line = text->curl;
+ const int len_utf8 = BLI_strlen_utf8(line->line);
+ CLAMP_MAX(index, len_utf8);
+ text->curc = BLI_str_utf8_offset_from_index(line->line, index);
+}
+
+static int rna_Text_select_end_character_get(PointerRNA *ptr)
+{
+ Text *text = ptr->data;
+ return BLI_str_utf8_offset_to_index(text->sell->line, text->selc);
+}
+
+static void rna_Text_select_end_character_set(PointerRNA *ptr, int index)
+{
+ Text *text = ptr->data;
+ TextLine *line = text->sell;
+ const int len_utf8 = BLI_strlen_utf8(line->line);
+ CLAMP_MAX(index, len_utf8);
+ text->selc = BLI_str_utf8_offset_from_index(line->line, index);
}
static void rna_TextLine_body_get(PointerRNA *ptr, char *value)
@@ -209,12 +261,14 @@ static void rna_def_text(BlenderRNA *brna)
prop, "Current Line", "Current line, and start line of selection if one exists");
prop = RNA_def_property(srna, "current_character", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "curc");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_ui_text(prop,
"Current Character",
"Index of current character in current line, and also start index of "
"character in selection if one exists");
+ RNA_def_property_int_funcs(
+ prop, "rna_Text_current_character_get", "rna_Text_current_character_set", NULL);
+ RNA_def_property_update(prop, NC_TEXT | ND_CURSOR, NULL);
prop = RNA_def_property(srna, "current_line_index", PROP_INT, PROP_NONE);
RNA_def_property_int_funcs(
@@ -230,12 +284,20 @@ static void rna_def_text(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "TextLine");
RNA_def_property_ui_text(prop, "Selection End Line", "End line of selection");
+ prop = RNA_def_property(srna, "select_end_line_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(
+ prop, "rna_Text_select_end_line_index_get", "rna_Text_select_end_line_index_set", NULL);
+ RNA_def_property_ui_text(prop, "Select End Line Index", "Index of last TextLine in selection");
+ RNA_def_property_update(prop, NC_TEXT | ND_CURSOR, NULL);
+
prop = RNA_def_property(srna, "select_end_character", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "selc");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_ui_text(prop,
"Selection End Character",
"Index of character after end of selection in the selection end line");
+ RNA_def_property_int_funcs(
+ prop, "rna_Text_select_end_character_get", "rna_Text_select_end_character_set", NULL);
+ RNA_def_property_update(prop, NC_TEXT | ND_CURSOR, NULL);
RNA_api_text(srna);
}
diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c
index 524dcfa9ad7..000076eccec 100644
--- a/source/blender/makesrna/intern/rna_text_api.c
+++ b/source/blender/makesrna/intern/rna_text_api.c
@@ -46,6 +46,18 @@ static void rna_Text_write(Text *text, const char *str)
WM_main_add_notifier(NC_TEXT | NA_EDITED, text);
}
+static void rna_Text_select_set(Text *text, int startl, int startc, int endl, int endc)
+{
+ txt_sel_set(text, startl, startc, endl, endc);
+ WM_main_add_notifier(NC_TEXT | NA_EDITED, text);
+}
+
+static void rna_Text_cursor_set(Text *text, int line, int ch, bool select)
+{
+ txt_move_to(text, line, ch, select);
+ WM_main_add_notifier(NC_TEXT | NA_EDITED, text);
+}
+
#else
void RNA_api_text(StructRNA *srna)
@@ -69,6 +81,25 @@ void RNA_api_text(StructRNA *srna)
RNA_def_function_ui_description(func,
"Returns True if the editor supports syntax highlighting "
"for the current text datablock");
+
+ func = RNA_def_function(srna, "select_set", "rna_Text_select_set");
+ RNA_def_function_ui_description(func, "Set selection range by line and character index");
+ parm = RNA_def_int(func, "line_start", 0, INT_MIN, INT_MAX, "Start Line", "", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(
+ func, "char_start", 0, INT_MIN, INT_MAX, "Start Character", "", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "line_end", 0, INT_MIN, INT_MAX, "End Line", "", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "char_end", 0, INT_MIN, INT_MAX, "End Character", "", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "cursor_set", "rna_Text_cursor_set");
+ RNA_def_function_ui_description(func, "Set cursor by line and (optionally) character index");
+ parm = RNA_def_int(func, "line", 0, 0, INT_MAX, "Line", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "character", 0, 0, INT_MAX, "Character", "", 0, INT_MAX);
+ RNA_def_boolean(func, "select", false, "", "Select when moving the cursor");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 0a824b3c67a..4b232251770 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -1037,7 +1037,7 @@ static void rna_def_trackingSettings(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, tracker_motion_model);
- RNA_def_property_ui_text(prop, "Motion model", "Default motion model to use for tracking");
+ RNA_def_property_ui_text(prop, "Motion Model", "Default motion model to use for tracking");
/* default_use_brute */
prop = RNA_def_property(srna, "use_default_brute", PROP_BOOLEAN, PROP_NONE);
@@ -1470,7 +1470,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, tracker_motion_model);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Motion model", "Default motion model to use for tracking");
+ RNA_def_property_ui_text(prop, "Motion Model", "Default motion model to use for tracking");
/* minimum correlation */
prop = RNA_def_property(srna, "correlation_min", PROP_FLOAT, PROP_NONE);
@@ -1849,7 +1849,7 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_2d_stabilization", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_2D_STABILIZATION);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Use 2D stabilization", "Use 2D stabilization for footage");
+ RNA_def_property_ui_text(prop, "Use 2D Stabilization", "Use 2D stabilization for footage");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* use_stabilize_rotation */
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 548111500ad..07ce07710b1 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -424,6 +424,17 @@ static void rna_userdef_timecode_style_set(PointerRNA *ptr, int value)
}
}
+static int rna_UserDef_mouse_emulate_3_button_modifier_get(PointerRNA *ptr)
+{
+# if !defined(WIN32)
+ UserDef *userdef = ptr->data;
+ return userdef->mouse_emulate_3_button_modifier;
+# else
+ UNUSED_VARS(ptr);
+ return USER_EMU_MMB_MOD_ALT;
+# endif
+}
+
static PointerRNA rna_UserDef_view_get(PointerRNA *ptr)
{
return rna_pointer_inherit_refine(ptr, &RNA_PreferencesView, ptr->data);
@@ -3190,6 +3201,18 @@ static void rna_def_userdef_theme_space_nla(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "View Sliders", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "dopesheet_channel", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "ds_channel");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Channel", "Nonlinear Animation Channel");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ prop = RNA_def_property(srna, "nla_track", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "nla_track");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Track", "Nonlinear Animation Track");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
prop = RNA_def_property(srna, "active_action", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "anim_active");
RNA_def_property_array(prop, 4);
@@ -3397,6 +3420,16 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Path After", "Color of path after current frame");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "path_keyframe_before", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Path Before", "Color of path before current frame");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "path_keyframe_after", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Path After", "Color of path after current frame");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "cframe");
RNA_def_property_array(prop, 3);
@@ -4044,6 +4077,43 @@ static void rna_def_userdef_view(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem render_display_types[] = {
+ {USER_RENDER_DISPLAY_NONE,
+ "NONE",
+ 0,
+ "Keep User Interface",
+ "Images are rendered without changing the user interface"},
+ {USER_RENDER_DISPLAY_SCREEN,
+ "SCREEN",
+ 0,
+ "Full Screen",
+ "Images are rendered in a maximized Image Editor"},
+ {USER_RENDER_DISPLAY_AREA,
+ "AREA",
+ 0,
+ "Image Editor",
+ "Images are rendered in an Image Editor"},
+ {USER_RENDER_DISPLAY_WINDOW,
+ "WINDOW",
+ 0,
+ "New Window",
+ "Images are rendered in a new window"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ static const EnumPropertyItem temp_space_display_types[] = {
+ {USER_TEMP_SPACE_DISPLAY_FULLSCREEN,
+ "SCREEN", /* Could be FULLSCREEN, but keeping it consistent with render_display_types */
+ 0,
+ "Full Screen",
+ "Open the temporary editor in a maximized screen"},
+ {USER_TEMP_SPACE_DISPLAY_WINDOW,
+ "WINDOW",
+ 0,
+ "New Window",
+ "Open the temporary editor in a new window"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
PropertyRNA *prop;
StructRNA *srna;
@@ -4172,7 +4242,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_MENUOPENAUTO);
RNA_def_property_ui_text(
prop,
- "Open On Mouse Over",
+ "Open on Mouse Over",
"Open menu buttons and pulldowns automatically when the mouse is hovering");
prop = RNA_def_property(srna, "open_toplevel_delay", PROP_INT, PROP_NONE);
@@ -4268,6 +4338,17 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Header Position", "Default header position for new space-types");
RNA_def_property_update(prop, 0, "rna_userdef_screen_update_header_default");
+ prop = RNA_def_property(srna, "render_display_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, render_display_types);
+ RNA_def_property_ui_text(
+ prop, "Render Display Type", "Default location where rendered images will be displayed in");
+
+ prop = RNA_def_property(srna, "filebrowser_display_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, temp_space_display_types);
+ RNA_def_property_ui_text(prop,
+ "File Browser Display Type",
+ "Default location where the File Editor will be displayed in");
+
static const EnumPropertyItem text_hinting_items[] = {
{0, "AUTO", 0, "Auto", ""},
{USER_TEXT_HINTING_NONE, "NONE", 0, "None", ""},
@@ -4360,7 +4441,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_enum_items(prop, zoom_frame_modes);
RNA_def_property_enum_sdna(prop, NULL, "view_frame_type");
RNA_def_property_ui_text(
- prop, "Zoom To Frame Type", "How zooming to frame focuses around current frame");
+ prop, "Zoom to Frame Type", "How zooming to frame focuses around current frame");
prop = RNA_def_property(srna, "view_frame_keyframes", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 500);
@@ -4576,6 +4657,13 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
"Color for newly added transformation F-Curves (Location, Rotation, Scale) "
"and also Color is based on the transform axis");
+ prop = RNA_def_property(srna, "fcurve_new_auto_smoothing", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_fcurve_auto_smoothing_items);
+ RNA_def_property_enum_sdna(prop, NULL, "auto_smoothing_new");
+ RNA_def_property_ui_text(prop,
+ "New Curve Smoothing Mode",
+ "Auto Handle Smoothing mode used for newly added F-Curves");
+
prop = RNA_def_property(srna, "keyframe_new_interpolation_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_mode_items);
RNA_def_property_enum_sdna(prop, NULL, "ipo_new");
@@ -5204,7 +5292,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_zoom_to_mouse", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ZOOM_TO_MOUSEPOS);
RNA_def_property_ui_text(prop,
- "Zoom To Mouse Position",
+ "Zoom to Mouse Position",
"Zoom in towards the mouse pointer's position in the 3D view, "
"rather than the 2D window center");
@@ -5429,6 +5517,21 @@ static void rna_def_userdef_input(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_userdef_keyconfig_reload_update");
+ static const EnumPropertyItem mouse_emulate_3_button_modifier[] = {
+ {USER_EMU_MMB_MOD_ALT, "ALT", 0, "Alt", ""},
+ {USER_EMU_MMB_MOD_OSKEY, "OSKEY", 0, "OS-Key", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ prop = RNA_def_property(srna, "mouse_emulate_3_button_modifier", PROP_ENUM, PROP_NONE);
+ /* Only needed because of WIN32 inability to support the option. */
+ RNA_def_property_enum_funcs(prop, "rna_UserDef_mouse_emulate_3_button_modifier_get", NULL, NULL);
+ RNA_def_property_enum_items(prop, mouse_emulate_3_button_modifier);
+ RNA_def_property_ui_text(
+ prop, "Emulate 3 Button Modifier", "Hold this modifier to emulate the middle mouse button");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, 0, "rna_userdef_keyconfig_reload_update");
+
prop = RNA_def_property(srna, "use_emulate_numpad", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_NONUMPAD);
RNA_def_property_ui_text(
@@ -5515,11 +5618,6 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Hide System Bookmarks", "Hide system bookmarks in the file selector");
- prop = RNA_def_property(srna, "show_thumbnails", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_THUMBNAILS);
- RNA_def_property_ui_text(
- prop, "Show Thumbnails", "Open in thumbnail view for images and movies");
-
prop = RNA_def_property(srna, "use_relative_paths", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_RELPATHS);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index b705f98a3de..886258ee45f 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -41,24 +41,27 @@
#include "rna_internal.h" /* own include */
-/* confusingm 2 enums mixed up here */
+/* confusing 2 enums mixed up here */
const EnumPropertyItem rna_enum_window_cursor_items[] = {
- {CURSOR_STD, "DEFAULT", 0, "Default", ""},
- {CURSOR_NONE, "NONE", 0, "None", ""},
- {CURSOR_WAIT, "WAIT", 0, "Wait", ""},
- {CURSOR_EDIT, "CROSSHAIR", 0, "Crosshair", ""},
- {CURSOR_X_MOVE, "MOVE_X", 0, "Move-X", ""},
- {CURSOR_Y_MOVE, "MOVE_Y", 0, "Move-Y", ""},
+ {WM_CURSOR_DEFAULT, "DEFAULT", 0, "Default", ""},
+ {WM_CURSOR_NONE, "NONE", 0, "None", ""},
+ {WM_CURSOR_WAIT, "WAIT", 0, "Wait", ""},
+ {WM_CURSOR_EDIT, "CROSSHAIR", 0, "Crosshair", ""},
+ {WM_CURSOR_X_MOVE, "MOVE_X", 0, "Move-X", ""},
+ {WM_CURSOR_Y_MOVE, "MOVE_Y", 0, "Move-Y", ""},
/* new */
- {BC_KNIFECURSOR, "KNIFE", 0, "Knife", ""},
- {BC_TEXTEDITCURSOR, "TEXT", 0, "Text", ""},
- {BC_PAINTBRUSHCURSOR, "PAINT_BRUSH", 0, "Paint Brush", ""},
- {BC_HANDCURSOR, "HAND", 0, "Hand", ""},
- {BC_EW_SCROLLCURSOR, "SCROLL_X", 0, "Scroll-X", ""},
- {BC_NS_SCROLLCURSOR, "SCROLL_Y", 0, "Scroll-Y", ""},
- {BC_NSEW_SCROLLCURSOR, "SCROLL_XY", 0, "Scroll-XY", ""},
- {BC_EYEDROPPER_CURSOR, "EYEDROPPER", 0, "Eyedropper", ""},
+ {WM_CURSOR_KNIFE, "KNIFE", 0, "Knife", ""},
+ {WM_CURSOR_TEXT_EDIT, "TEXT", 0, "Text", ""},
+ {WM_CURSOR_PAINT_BRUSH, "PAINT_BRUSH", 0, "Paint Brush", ""},
+ {WM_CURSOR_PAINT, "PAINT_CROSS", 0, "Paint Cross", ""},
+ {WM_CURSOR_DOT, "DOT", 0, "Dot Cursor", ""},
+ {WM_CURSOR_ERASER, "ERASER", 0, "Eraser", ""},
+ {WM_CURSOR_HAND, "HAND", 0, "Hand", ""},
+ {WM_CURSOR_EW_SCROLL, "SCROLL_X", 0, "Scroll-X", ""},
+ {WM_CURSOR_NS_SCROLL, "SCROLL_Y", 0, "Scroll-Y", ""},
+ {WM_CURSOR_NSEW_SCROLL, "SCROLL_XY", 0, "Scroll-XY", ""},
+ {WM_CURSOR_EYEDROPPER, "EYEDROPPER", 0, "Eyedropper", ""},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_workspace_api.c b/source/blender/makesrna/intern/rna_workspace_api.c
index b8c6a25ace8..f22c86b3ff2 100644
--- a/source/blender/makesrna/intern/rna_workspace_api.c
+++ b/source/blender/makesrna/intern/rna_workspace_api.c
@@ -110,7 +110,7 @@ void RNA_api_workspace(StructRNA *srna)
FunctionRNA *func;
PropertyRNA *parm;
- func = RNA_def_function(srna, "status_text_set", "ED_workspace_status_text");
+ func = RNA_def_function(srna, "status_text_set_internal", "ED_workspace_status_text");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
RNA_def_function_ui_description(
func, "Set the status bar text, typically key shortcuts for modal operators");
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 3c3aae8fda6..644ac3a10e8 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -269,8 +269,8 @@ static void dm_mvert_map_doubles(int *doubles_map,
static void mesh_merge_transform(Mesh *result,
Mesh *cap_mesh,
const float cap_offset[4][4],
- unsigned int cap_verts_index,
- unsigned int cap_edges_index,
+ uint cap_verts_index,
+ uint cap_edges_index,
int cap_loops_index,
int cap_polys_index,
int cap_nverts,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index a05b7023392..0c00bb572be 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -212,7 +212,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
spread,
mesh->smoothresh);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
/* Make sure we never alloc'd these. */
BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL);
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index e55eeddbfa5..9868395c0e8 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -316,7 +316,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEM_freeN(looptris);
}
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 3d43c6de88e..56e84423db4 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -118,7 +118,7 @@ static void deformVerts(ModifierData *md,
if (mesh_src) {
float current_time = 0;
- unsigned int mvert_num = 0;
+ uint mvert_num = 0;
BKE_mesh_vert_coords_apply(mesh_src, vertexCos);
BKE_mesh_calc_normals(mesh_src);
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index a234f468e45..ff241550bdc 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -70,7 +70,7 @@ static void initData(ModifierData *md)
csmd->defgrp_name[0] = '\0';
- csmd->delta_cache = NULL;
+ csmd->delta_cache.deltas = NULL;
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
@@ -84,14 +84,14 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
}
- tcsmd->delta_cache = NULL;
- tcsmd->delta_cache_num = 0;
+ tcsmd->delta_cache.deltas = NULL;
+ tcsmd->delta_cache.totverts = 0;
}
static void freeBind(CorrectiveSmoothModifierData *csmd)
{
MEM_SAFE_FREE(csmd->bind_coords);
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
csmd->bind_coords_num = 0;
}
@@ -117,11 +117,11 @@ static void requiredDataMask(Object *UNUSED(ob),
/* check individual weights for changes and cache values */
static void mesh_get_weights(MDeformVert *dvert,
const int defgrp_index,
- const unsigned int numVerts,
+ const uint numVerts,
const bool use_invert_vgroup,
float *smooth_weights)
{
- unsigned int i;
+ uint i;
for (i = 0; i < numVerts; i++, dvert++) {
const float w = defvert_find_weight(dvert, defgrp_index);
@@ -140,11 +140,11 @@ static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
const MPoly *mpoly = mesh->mpoly;
const MLoop *mloop = mesh->mloop;
const MEdge *medge = mesh->medge;
- unsigned int mpoly_num, medge_num, i;
- unsigned short *boundaries;
+ uint mpoly_num, medge_num, i;
+ ushort *boundaries;
- mpoly_num = (unsigned int)mesh->totpoly;
- medge_num = (unsigned int)mesh->totedge;
+ mpoly_num = (uint)mesh->totpoly;
+ medge_num = (uint)mesh->totedge;
boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__);
@@ -176,14 +176,14 @@ static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
const float *smooth_weights,
- unsigned int iterations)
+ uint iterations)
{
const float lambda = csmd->lambda;
- unsigned int i;
+ uint i;
- const unsigned int numEdges = (unsigned int)mesh->totedge;
+ const uint numEdges = (uint)mesh->totedge;
const MEdge *edges = mesh->medge;
float *vertex_edge_count_div;
@@ -252,18 +252,18 @@ static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd,
static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
const float *smooth_weights,
- unsigned int iterations)
+ uint iterations)
{
const float eps = FLT_EPSILON * 10.0f;
- const unsigned int numEdges = (unsigned int)mesh->totedge;
+ const uint numEdges = (uint)mesh->totedge;
/* note: the way this smoothing method works, its approx half as strong as the simple-smooth,
* and 2.0 rarely spikes, double the value for consistent behavior. */
const float lambda = csmd->lambda * 2.0f;
const MEdge *edges = mesh->medge;
float *vertex_edge_count;
- unsigned int i;
+ uint i;
struct SmoothingData_Weighted {
float delta[3];
@@ -346,9 +346,9 @@ static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd,
static void smooth_iter(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
const float *smooth_weights,
- unsigned int iterations)
+ uint iterations)
{
switch (csmd->smooth_type) {
case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT:
@@ -367,7 +367,7 @@ static void smooth_verts(CorrectiveSmoothModifierData *csmd,
MDeformVert *dvert,
const int defgrp_index,
float (*vertexCos)[3],
- unsigned int numVerts)
+ uint numVerts)
{
float *smooth_weights = NULL;
@@ -391,7 +391,7 @@ static void smooth_verts(CorrectiveSmoothModifierData *csmd,
}
}
- smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat);
+ smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (uint)csmd->repeat);
if (smooth_weights) {
MEM_freeN(smooth_weights);
@@ -454,13 +454,13 @@ static void calc_tangent_loop_accum(const float v_dir_prev[3],
static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tangent_spaces)[3][3])
{
- const unsigned int mpoly_num = (unsigned int)mesh->totpoly;
+ const uint mpoly_num = (uint)mesh->totpoly;
#ifndef USE_TANGENT_CALC_INLINE
- const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+ const uint mvert_num = (uint)dm->getNumVerts(dm);
#endif
const MPoly *mpoly = mesh->mpoly;
const MLoop *mloop = mesh->mloop;
- unsigned int i;
+ uint i;
for (i = 0; i < mpoly_num; i++) {
const MPoly *mp = &mpoly[i];
@@ -502,6 +502,23 @@ static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tan
#endif
}
+static void store_cache_settings(CorrectiveSmoothModifierData *csmd)
+{
+ csmd->delta_cache.lambda = csmd->lambda;
+ csmd->delta_cache.repeat = csmd->repeat;
+ csmd->delta_cache.flag = csmd->flag;
+ csmd->delta_cache.smooth_type = csmd->smooth_type;
+ csmd->delta_cache.rest_source = csmd->rest_source;
+}
+
+static bool cache_settings_equal(CorrectiveSmoothModifierData *csmd)
+{
+ return (csmd->delta_cache.lambda == csmd->lambda && csmd->delta_cache.repeat == csmd->repeat &&
+ csmd->delta_cache.flag == csmd->flag &&
+ csmd->delta_cache.smooth_type == csmd->smooth_type &&
+ csmd->delta_cache.rest_source == csmd->rest_source);
+}
+
/**
* This calculates #CorrectiveSmoothModifierData.delta_cache
* It's not run on every update (during animation for example).
@@ -511,22 +528,22 @@ static void calc_deltas(CorrectiveSmoothModifierData *csmd,
MDeformVert *dvert,
const int defgrp_index,
const float (*rest_coords)[3],
- unsigned int numVerts)
+ uint numVerts)
{
float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
float(*tangent_spaces)[3][3];
- unsigned int i;
+ uint i;
tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
- if (csmd->delta_cache_num != numVerts) {
- MEM_SAFE_FREE(csmd->delta_cache);
+ if (csmd->delta_cache.totverts != numVerts) {
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
}
/* allocate deltas if they have not yet been allocated, otherwise we will just write over them */
- if (!csmd->delta_cache) {
- csmd->delta_cache_num = numVerts;
- csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
+ if (!csmd->delta_cache.deltas) {
+ csmd->delta_cache.totverts = numVerts;
+ csmd->delta_cache.deltas = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
}
smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts);
@@ -544,7 +561,7 @@ static void calc_deltas(CorrectiveSmoothModifierData *csmd,
if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
transpose_m3_m3(imat, tangent_spaces[i]);
}
- mul_v3_m3v3(csmd->delta_cache[i], imat, delta);
+ mul_v3_m3v3(csmd->delta_cache.deltas[i], imat, delta);
}
MEM_freeN(tangent_spaces);
@@ -556,13 +573,14 @@ static void correctivesmooth_modifier_do(ModifierData *md,
Object *ob,
Mesh *mesh,
float (*vertexCos)[3],
- unsigned int numVerts,
+ uint numVerts,
struct BMEditMesh *em)
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
const bool force_delta_cache_update =
/* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
+ !cache_settings_equal(csmd) ||
((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
(((ID *)ob->data)->recalc & ID_RECALC_ALL));
@@ -575,7 +593,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
/* if rest bind_coords not are defined, set them (only run during bind) */
if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
/* signal to recalculate, whoever sets MUST also free bind coords */
- (csmd->bind_coords_num == (unsigned int)-1)) {
+ (csmd->bind_coords_num == (uint)-1)) {
if (DEG_is_active(depsgraph)) {
BLI_assert(csmd->bind_coords == NULL);
csmd->bind_coords = MEM_dupallocN(vertexCos);
@@ -617,8 +635,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
goto error;
}
else {
- unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert :
- ((Mesh *)ob->data)->totvert);
+ uint me_numVerts = (uint)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);
if (me_numVerts != numVerts) {
modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
@@ -628,10 +645,13 @@ static void correctivesmooth_modifier_do(ModifierData *md,
}
/* check to see if our deltas are still valid */
- if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
+ if (!csmd->delta_cache.deltas || (csmd->delta_cache.totverts != numVerts) ||
+ force_delta_cache_update) {
const float(*rest_coords)[3];
bool is_rest_coords_alloc = false;
+ store_cache_settings(csmd);
+
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
/* caller needs to do sanity check here */
csmd->bind_coords_num = numVerts;
@@ -642,7 +662,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
rest_coords = em ? BKE_editmesh_vert_coords_alloc_orco(em, &me_numVerts) :
BKE_mesh_vert_coords_alloc(ob->data, &me_numVerts);
- BLI_assert((unsigned int)me_numVerts == numVerts);
+ BLI_assert((uint)me_numVerts == numVerts);
is_rest_coords_alloc = true;
}
@@ -662,7 +682,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
/* this could be a check, but at this point it _must_ be valid */
- BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
+ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache.deltas);
}
#ifdef DEBUG_TIME
@@ -673,7 +693,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
{
- unsigned int i;
+ uint i;
float(*tangent_spaces)[3][3];
@@ -689,7 +709,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
calc_tangent_ortho(tangent_spaces[i]);
#endif
- mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
+ mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache.deltas[i]);
add_v3_v3(vertexCos[i], delta);
}
@@ -704,8 +724,8 @@ static void correctivesmooth_modifier_do(ModifierData *md,
/* when the modifier fails to execute */
error:
- MEM_SAFE_FREE(csmd->delta_cache);
- csmd->delta_cache_num = 0;
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
+ csmd->delta_cache.totverts = 0;
}
static void deformVerts(ModifierData *md,
@@ -717,7 +737,7 @@ static void deformVerts(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
correctivesmooth_modifier_do(
- md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL);
+ md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, NULL);
if (mesh_src != mesh) {
BKE_id_free(NULL, mesh_src);
@@ -735,7 +755,7 @@ static void deformVertsEM(ModifierData *md,
ctx->object, editData, mesh, NULL, numVerts, false, false);
correctivesmooth_modifier_do(
- md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, editData);
+ md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData);
if (mesh_src != mesh) {
BKE_id_free(NULL, mesh_src);
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index cff700e8d45..c113a2767a0 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -140,8 +140,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MOD_get_vgroup(ctx->object, mesh, dmd->defgrp_name, &dvert, &defgrp_index);
if (dvert) {
- const unsigned int vert_tot = mesh->totvert;
- unsigned int i;
+ const uint vert_tot = mesh->totvert;
+ uint i;
vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__);
@@ -199,7 +199,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
updateFaceCount(ctx, dmd, bm->totface);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
/* make sure we never alloc'd these */
BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL);
BLI_assert(bm->vtable == NULL && bm->etable == NULL && bm->ftable == NULL);
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index ac0d72214c8..9cb694be88b 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -294,6 +294,11 @@ static void displaceModifier_do(DisplaceModifierData *dmd,
mvert = mesh->mvert;
MOD_get_vgroup(ob, mesh, dmd->defgrp_name, &dvert, &defgrp_index);
+ if (defgrp_index >= 0 && dvert == NULL) {
+ /* There is a vertex group, but it has no vertices. */
+ return;
+ }
+
Tex *tex_target = dmd->texture;
if (tex_target != NULL) {
tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co), "displaceModifier_do tex_co");
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 904d600164a..a4686e07daf 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -97,7 +97,7 @@ static Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd)
/* BM_mesh_validate(bm); */ /* for troubleshooting */
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 4ed787810a8..5f0bbc8ecf1 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -201,7 +201,7 @@ static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *p
BLI_rng_free(rng);
}
-static int edgecut_get(EdgeHash *edgehash, unsigned int v1, unsigned int v2)
+static int edgecut_get(EdgeHash *edgehash, uint v1, uint v2)
{
return POINTER_AS_INT(BLI_edgehash_lookup(edgehash, v1, v2));
}
@@ -649,7 +649,7 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
int i, v1, v2, v3, v4, esplit, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */
uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */
int numlayer;
- unsigned int ed_v1, ed_v2;
+ uint ed_v1, ed_v2;
edgehash = BLI_edgehash_new(__func__);
@@ -906,7 +906,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
const int *facepa = emd->facepa;
int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0;
int i, v, u;
- unsigned int ed_v1, ed_v2, mindex = 0;
+ uint ed_v1, ed_v2, mindex = 0;
MTFace *mtface = NULL, *mtf;
totface = mesh->totface;
@@ -938,10 +938,13 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
continue;
}
}
+ else {
+ pa = NULL;
+ }
/* do mindex + totvert to ensure the vertex index to be the first
* with BLI_edgehashIterator_getKey */
- if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) {
+ if (pa == NULL || cfra < pa->time) {
mindex = totvert + totpart;
}
else {
@@ -1022,6 +1025,9 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
mul_m4_v3(imat, vertco);
}
+ else {
+ pa = NULL;
+ }
}
BLI_edgehashIterator_free(ehi);
@@ -1043,13 +1049,17 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
continue;
}
}
+ else {
+ pa = NULL;
+ }
source = mesh->mface[i];
mf = &explode->mface[u];
orig_v4 = source.v4;
- if (facepa[i] != totpart && cfra < pa->time) {
+ /* Same as above in the first loop over mesh's faces. */
+ if (pa == NULL || cfra < pa->time) {
mindex = totvert + totpart;
}
else {
@@ -1069,7 +1079,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* override uv channel for particle age */
if (mtface) {
- float age = (cfra - pa->time) / pa->lifetime;
+ float age = (pa != NULL) ? (cfra - pa->time) / pa->lifetime : 0.0f;
/* Clamp to this range to avoid flipping to the other side of the coordinates. */
CLAMP(age, 0.001f, 0.999f);
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index 587aa108fd1..748bf4db4e2 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -513,6 +513,12 @@ static Mesh *fluidsim_read_cache(
return NULL;
}
+ BKE_mesh_copy_settings(newmesh, orgmesh);
+
+ /* Fluid simulation has a texture space that based on the bounds of the fluid mesh.
+ * This does not seem particularly useful, but it's backwards compatible. */
+ BKE_mesh_texspace_calc(newmesh);
+
/* load vertex velocities, if they exist...
* TODO? use generate flag as loading flag as well?
* warning, needs original .bobj.gz mesh loading filename */
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 2f902db9340..1a62010abe7 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -136,8 +136,8 @@ struct HookData_cb {
float falloff_sq;
float fac_orig;
- unsigned int use_falloff : 1;
- unsigned int use_uniform : 1;
+ uint use_falloff : 1;
+ uint use_uniform : 1;
float cent[3];
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index c9e0171c9f2..0fc2e0971da 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -66,7 +66,7 @@ typedef struct LaplacianSystem {
float (*co)[3]; /* Original vertex coordinates */
float (*no)[3]; /* Original vertex normal */
float (*delta)[3]; /* Differential Coordinates */
- unsigned int (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */
+ uint (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */
int *index_anchors; /* Static vertex index list */
int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */
int *ringf_indices; /* Indices of faces per vertex */
@@ -153,7 +153,7 @@ static void createFaceRingMap(const int mvert_tot,
for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
for (j = 0; j < 3; j++) {
- const unsigned int v_index = mloop[mlt->tri[j]].v;
+ const uint v_index = mloop[mlt->tri[j]].v;
map[v_index].count++;
totalr++;
}
@@ -167,7 +167,7 @@ static void createFaceRingMap(const int mvert_tot,
}
for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
for (j = 0; j < 3; j++) {
- const unsigned int v_index = mloop[mlt->tri[j]].v;
+ const uint v_index = mloop[mlt->tri[j]].v;
map[v_index].indices[map[v_index].count] = i;
map[v_index].count++;
}
@@ -253,7 +253,7 @@ static void initLaplacianMatrix(LaplacianSystem *sys)
int idv[3];
for (ti = 0; ti < sys->total_tris; ti++) {
- const unsigned int *vidt = sys->tris[ti];
+ const uint *vidt = sys->tris[ti];
const float *co[3];
co[0] = sys->co[vidt[0]];
@@ -352,7 +352,7 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys)
zero_v3(ni);
num_fni = sys->ringf_map[i].count;
for (fi = 0; fi < num_fni; fi++) {
- const unsigned int *vin;
+ const uint *vin;
fidn = sys->ringf_map[i].indices;
vin = sys->tris[fidn[fi]];
for (j = 0; j < 3; j++) {
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 4a86c26cdeb..86d4124e5db 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -199,7 +199,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
float w1, w2, w3;
float areaf;
int i;
- unsigned int idv1, idv2;
+ uint idv1, idv2;
for (i = 0; i < sys->numEdges; i++) {
idv1 = sys->medges[i].v1;
@@ -233,7 +233,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
const float *v_prev = sys->vertexCos[l_prev->v];
const float *v_curr = sys->vertexCos[l_curr->v];
const float *v_next = sys->vertexCos[l_next->v];
- const unsigned int l_curr_index = l_curr - sys->mloop;
+ const uint l_curr_index = l_curr - sys->mloop;
sys->numNeFa[l_curr->v] += 1;
@@ -274,7 +274,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
static void fill_laplacian_matrix(LaplacianSystem *sys)
{
int i;
- unsigned int idv1, idv2;
+ uint idv1, idv2;
for (i = 0; i < sys->numPolys; i++) {
const MPoly *mp = &sys->mpoly[i];
@@ -284,7 +284,7 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
const MLoop *l_curr = l_term - 1;
for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) {
- const unsigned int l_curr_index = l_curr - sys->mloop;
+ const uint l_curr_index = l_curr - sys->mloop;
/* Is ring if number of faces == number of edges around vertice*/
if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) {
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index df8f68862e6..cf7d227e898 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -160,7 +160,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
* (including selected matches only):
* key = oldindex, value = newindex
*/
- vertHash = BLI_ghash_int_new_ex("mask vert gh", (unsigned int)maxVerts);
+ vertHash = BLI_ghash_int_new_ex("mask vert gh", (uint)maxVerts);
/* add vertices which exist in vertexgroups into vertHash for filtering
* - dv = for each vertex, what vertexgroups does it belong to
@@ -204,7 +204,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
- vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (unsigned int)maxVerts);
+ vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (uint)maxVerts);
/* add vertices which exist in vertexgroup into ghash for filtering */
for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
@@ -220,8 +220,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
- edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (unsigned int)maxEdges);
- polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (unsigned int)maxPolys);
+ edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (uint)maxEdges);
+ polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (uint)maxPolys);
mvert_src = mesh->mvert;
medge_src = mesh->medge;
diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
index 16a118522c5..a3ab0120ff9 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
@@ -168,7 +168,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
if (factor >= 1.0f) {
#if 1
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
fread(vco, sizeof(float) * 3, 1, fp);
@@ -192,7 +192,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
else {
const float ifactor = 1.0f - factor;
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
float tvec[3];
fread(tvec, sizeof(float) * 3, 1, fp);
diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
index 97a8635ac9e..7b8ad0bd705 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
@@ -153,7 +153,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
if (factor >= 1.0f) {
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
fread(vco, sizeof(float) * 3, 1, fp);
@@ -167,7 +167,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
else {
const float ifactor = 1.0f - factor;
float *vco = *vertexCos;
- unsigned int i;
+ uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
float tvec[3];
fread(tvec, sizeof(float) * 3, 1, fp);
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 21ec3505dc9..47f8528ee94 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -30,6 +30,7 @@
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh.h"
+#include "BKE_mirror.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
@@ -68,377 +69,6 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
-static Mesh *doBiscetOnMirrorPlane(MirrorModifierData *mmd,
- const Mesh *mesh,
- int axis,
- const float plane_co[3],
- float plane_no[3])
-{
- bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) ||
- (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) ||
- (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z));
-
- const float bisect_distance = 0.001f;
-
- Mesh *result;
- BMesh *bm;
- BMIter viter;
- BMVert *v, *v_next;
-
- bm = BKE_mesh_to_bmesh_ex(mesh,
- &(struct BMeshCreateParams){0},
- &(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
- .emask = CD_MASK_ORIGINDEX,
- .pmask = CD_MASK_ORIGINDEX},
- });
-
- /* Define bisecting plane (aka mirror plane). */
- float plane[4];
- if (!do_bisect_flip_axis) {
- /* That reversed condition is a tad weird, but for some reason that's how you keep
- * the part of the mesh which is on the non-mirrored side when flip option is disabled,
- * think that that is the expected behavior. */
- negate_v3(plane_no);
- }
- plane_from_point_normal_v3(plane, plane_co, plane_no);
-
- BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
-
- /* Plane definitions for vert killing. */
- float plane_offset[4];
- copy_v3_v3(plane_offset, plane);
- plane_offset[3] = plane[3] - bisect_distance;
-
- /* Delete verts across the mirror plane. */
- BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
- if (plane_point_side_v3(plane_offset, v->co) > 0.0f) {
- BM_vert_kill(bm, v);
- }
- }
-
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
- BM_mesh_free(bm);
-
- return result;
-}
-
-static Mesh *doMirrorOnAxis(MirrorModifierData *mmd,
- const ModifierEvalContext *UNUSED(ctx),
- Object *ob,
- const Mesh *mesh,
- int axis)
-{
- const float tolerance_sq = mmd->tolerance * mmd->tolerance;
- const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
- int tot_vtargetmap = 0; /* total merge vertices */
-
- const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) ||
- (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) ||
- (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z));
-
- Mesh *result;
- MVert *mv, *mv_prev;
- MEdge *me;
- MLoop *ml;
- MPoly *mp;
- float mtx[4][4];
- float plane_co[3], plane_no[3];
- int i;
- int a, totshape;
- int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL;
-
- /* mtx is the mirror transformation */
- unit_m4(mtx);
- mtx[axis][axis] = -1.0f;
-
- Object *mirror_ob = mmd->mirror_ob;
- if (mirror_ob != NULL) {
- float tmp[4][4];
- float itmp[4][4];
-
- /* tmp is a transform from coords relative to the object's own origin,
- * to coords relative to the mirror object origin */
- invert_m4_m4(tmp, mirror_ob->obmat);
- mul_m4_m4m4(tmp, tmp, ob->obmat);
-
- /* itmp is the reverse transform back to origin-relative coordinates */
- invert_m4_m4(itmp, tmp);
-
- /* combine matrices to get a single matrix that translates coordinates into
- * mirror-object-relative space, does the mirror, and translates back to
- * origin-relative space */
- mul_m4_series(mtx, itmp, mtx, tmp);
-
- if (do_bisect) {
- copy_v3_v3(plane_co, itmp[3]);
- copy_v3_v3(plane_no, itmp[axis]);
- }
- }
- else if (do_bisect) {
- copy_v3_v3(plane_co, mtx[3]);
- /* Need to negate here, since that axis is inverted (for mirror transform). */
- negate_v3_v3(plane_no, mtx[axis]);
- }
-
- Mesh *mesh_bisect = NULL;
- if (do_bisect) {
- mesh_bisect = doBiscetOnMirrorPlane(mmd, mesh, axis, plane_co, plane_no);
- mesh = mesh_bisect;
- }
-
- const int maxVerts = mesh->totvert;
- const int maxEdges = mesh->totedge;
- const int maxLoops = mesh->totloop;
- const int maxPolys = mesh->totpoly;
-
- result = BKE_mesh_new_nomain_from_template(
- mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
-
- /*copy customdata to original geometry*/
- CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts);
- CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges);
- CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops);
- CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys);
-
- /* Subsurf for eg won't have mesh data in the custom data arrays.
- * now add mvert/medge/mpoly layers. */
- if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
- memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
- }
- if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
- memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
- }
- if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
- memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
- memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
- }
-
- /* copy customdata to new geometry,
- * copy from its self because this data may have been created in the checks above */
- CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
- CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
- /* loops are copied later */
- CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys);
-
- if (do_vtargetmap) {
- /* second half is filled with -1 */
- vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap");
-
- vtmap_a = vtargetmap;
- vtmap_b = vtargetmap + maxVerts;
- }
-
- /* mirror vertex coordinates */
- mv_prev = result->mvert;
- mv = mv_prev + maxVerts;
- for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
- mul_m4_v3(mtx, mv->co);
-
- if (do_vtargetmap) {
- /* compare location of the original and mirrored vertex, to see if they
- * should be mapped for merging */
- if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
- *vtmap_a = maxVerts + i;
- tot_vtargetmap++;
-
- /* average location */
- mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
- copy_v3_v3(mv_prev->co, mv->co);
- }
- else {
- *vtmap_a = -1;
- }
-
- *vtmap_b = -1; /* fill here to avoid 2x loops */
-
- vtmap_a++;
- vtmap_b++;
- }
- }
-
- /* handle shape keys */
- totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY);
- for (a = 0; a < totshape; a++) {
- float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a);
- for (i = maxVerts; i < result->totvert; i++) {
- mul_m4_v3(mtx, cos[i]);
- }
- }
-
- /* adjust mirrored edge vertex indices */
- me = result->medge + maxEdges;
- for (i = 0; i < maxEdges; i++, me++) {
- me->v1 += maxVerts;
- me->v2 += maxVerts;
- }
-
- /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
- mp = result->mpoly + maxPolys;
- ml = result->mloop;
- for (i = 0; i < maxPolys; i++, mp++) {
- MLoop *ml2;
- int j, e;
-
- /* reverse the loop, but we keep the first vertex in the face the same,
- * to ensure that quads are split the same way as on the other side */
- CustomData_copy_data(
- &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1);
-
- for (j = 1; j < mp->totloop; j++) {
- CustomData_copy_data(&result->ldata,
- &result->ldata,
- mp->loopstart + j,
- mp->loopstart + maxLoops + mp->totloop - j,
- 1);
- }
-
- ml2 = ml + mp->loopstart + maxLoops;
- e = ml2[0].e;
- for (j = 0; j < mp->totloop - 1; j++) {
- ml2[j].e = ml2[j + 1].e;
- }
- ml2[mp->totloop - 1].e = e;
-
- mp->loopstart += maxLoops;
- }
-
- /* adjust mirrored loop vertex and edge indices */
- ml = result->mloop + maxLoops;
- for (i = 0; i < maxLoops; i++, ml++) {
- ml->v += maxVerts;
- ml->e += maxEdges;
- }
-
- /* handle uvs,
- * let tessface recalc handle updating the MTFace data */
- if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) ||
- (is_zero_v2(mmd->uv_offset_copy) == false)) {
- const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
- const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
-
- const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
-
- for (a = 0; a < totuv; a++) {
- MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a);
- int j = maxLoops;
- dmloopuv += j; /* second set of loops only */
- for (; j-- > 0; dmloopuv++) {
- if (do_mirr_u) {
- dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
- }
- if (do_mirr_v) {
- dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
- }
- dmloopuv->uv[0] += mmd->uv_offset_copy[0];
- dmloopuv->uv[1] += mmd->uv_offset_copy[1];
- }
- }
- }
-
- /* handle custom split normals */
- if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) &&
- CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) {
- const int totloop = result->totloop;
- const int totpoly = result->totpoly;
- float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__);
- CustomData *ldata = &result->ldata;
- short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
- MLoopNorSpaceArray lnors_spacearr = {NULL};
- float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
-
- /* calculate custom normals into loop_normals, then mirror first half into second half */
-
- BKE_mesh_calc_normals_poly(result->mvert,
- NULL,
- result->totvert,
- result->mloop,
- result->mpoly,
- totloop,
- totpoly,
- poly_normals,
- false);
-
- BKE_mesh_normals_loop_split(result->mvert,
- result->totvert,
- result->medge,
- result->totedge,
- result->mloop,
- loop_normals,
- totloop,
- result->mpoly,
- poly_normals,
- totpoly,
- true,
- mesh->smoothresh,
- &lnors_spacearr,
- clnors,
- NULL);
-
- /* mirroring has to account for loops being reversed in polys in second half */
- mp = result->mpoly;
- for (i = 0; i < maxPolys; i++, mp++) {
- MPoly *mpmirror = result->mpoly + maxPolys + i;
- int j;
-
- for (j = mp->loopstart; j < mp->loopstart + mp->totloop; j++) {
- int mirrorj = mpmirror->loopstart;
- if (j > mp->loopstart) {
- mirrorj += mpmirror->totloop - (j - mp->loopstart);
- }
- copy_v3_v3(loop_normals[mirrorj], loop_normals[j]);
- loop_normals[mirrorj][axis] = -loop_normals[j][axis];
- BKE_lnor_space_custom_normal_to_data(
- lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]);
- }
- }
-
- MEM_freeN(poly_normals);
- MEM_freeN(loop_normals);
- BKE_lnor_spacearr_free(&lnors_spacearr);
- }
-
- /* handle vgroup stuff */
- if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) {
- MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) +
- maxVerts;
- int *flip_map = NULL, flip_map_len = 0;
-
- flip_map = defgroup_flip_map(ob, &flip_map_len, false);
-
- if (flip_map) {
- for (i = 0; i < maxVerts; dvert++, i++) {
- /* merged vertices get both groups, others get flipped */
- if (do_vtargetmap && (vtargetmap[i] != -1)) {
- defvert_flip_merged(dvert, flip_map, flip_map_len);
- }
- else {
- defvert_flip(dvert, flip_map, flip_map_len);
- }
- }
-
- MEM_freeN(flip_map);
- }
- }
-
- if (do_vtargetmap) {
- /* slow - so only call if one or more merge verts are found,
- * users may leave this on and not realize there is nothing to merge - campbell */
- if (tot_vtargetmap) {
- result = BKE_mesh_merge_verts(
- result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED);
- }
- MEM_freeN(vtargetmap);
- }
-
- if (mesh_bisect != NULL) {
- BKE_id_free(NULL, mesh_bisect);
- }
-
- return result;
-}
-
static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
const ModifierEvalContext *ctx,
Object *ob,
@@ -448,11 +78,11 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
/* check which axes have been toggled and mirror accordingly */
if (mmd->flag & MOD_MIR_AXIS_X) {
- result = doMirrorOnAxis(mmd, ctx, ob, result, 0);
+ result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 0);
}
if (mmd->flag & MOD_MIR_AXIS_Y) {
Mesh *tmp = result;
- result = doMirrorOnAxis(mmd, ctx, ob, result, 1);
+ result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 1);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
@@ -460,7 +90,7 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
}
if (mmd->flag & MOD_MIR_AXIS_Z) {
Mesh *tmp = result;
- result = doMirrorOnAxis(mmd, ctx, ob, result, 2);
+ result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 2);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index dd7c001931c..883c17aa1e1 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -38,6 +38,7 @@
#include "BKE_paint.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_deform.h"
#include "BKE_subdiv_mesh.h"
#include "BKE_subsurf.h"
@@ -227,6 +228,42 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
return result;
}
+static void deformMatrices(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh,
+ float (*vertex_cos)[3],
+ float (*deform_matrices)[3][3],
+ int num_verts)
+
+{
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return;
+#endif
+
+ /* Subsurf does not require extra space mapping, keep matrices as is. */
+ (void)deform_matrices;
+
+ MultiresModifierData *mmd = (MultiresModifierData *)md;
+ SubdivSettings subdiv_settings;
+ BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
+ if (subdiv_settings.level == 0) {
+ return;
+ }
+ BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh);
+ MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd);
+ Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, ut also on empty input mesh. */
+ return;
+ }
+ BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
+ BKE_subdiv_deform_coarse_vertices(subdiv, mesh, vertex_cos, num_verts);
+ if (subdiv != runtime_data->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
+}
+
ModifierTypeInfo modifierType_Multires = {
/* name */ "Multires",
/* structName */ "MultiresModifierData",
@@ -238,7 +275,7 @@ ModifierTypeInfo modifierType_Multires = {
/* copyData */ copyData,
/* deformVerts */ NULL,
- /* deformMatrices */ NULL,
+ /* deformMatrices */ deformMatrices,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index aff5b8b071b..97be42367d4 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -268,7 +268,7 @@ static void generate_ocean_geometry_uvs(void *__restrict userdata,
}
}
-static Mesh *generate_ocean_geometry(OceanModifierData *omd)
+static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig)
{
Mesh *result;
@@ -296,6 +296,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd)
gogd.sy /= gogd.ry;
result = BKE_mesh_new_nomain(num_verts, 0, 0, num_polys * 4, num_polys);
+ BKE_mesh_copy_settings(result, mesh_orig);
gogd.mverts = result->mvert;
gogd.mpolys = result->mpoly;
@@ -377,7 +378,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
}
if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
- result = generate_ocean_geometry(omd);
+ result = generate_ocean_geometry(omd, mesh);
BKE_mesh_ensure_normals(result);
}
else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index a7c7c207cd6..67a64921bbc 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -168,7 +168,7 @@ static void deformVerts(ModifierData *md,
if (em) {
/* In edit mode get directly from the edit mesh. */
- psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, mesh);
}
else {
/* Otherwise get regular mesh. */
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 631401d9d9e..df84f3db55c 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -185,6 +185,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(c
}
}
+ BKE_mesh_copy_settings(result, mesh);
BKE_mesh_calc_edges(result, true, false);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index ac47422fe2f..773cbf72d5b 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -46,18 +46,18 @@
/* used for gathering edge connectivity */
typedef struct ScrewVertConnect {
- float dist; /* distance from the center axis */
- float co[3]; /* location relative to the transformed axis */
- float no[3]; /* calc normal of the vertex */
- unsigned int v[2]; /* 2 verts on either side of this one */
- MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */
+ float dist; /* distance from the center axis */
+ float co[3]; /* location relative to the transformed axis */
+ float no[3]; /* calc normal of the vertex */
+ uint v[2]; /* 2 verts on either side of this one */
+ MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */
char flag;
} ScrewVertConnect;
typedef struct ScrewVertIter {
ScrewVertConnect *v_array;
ScrewVertConnect *v_poin;
- unsigned int v, v_other;
+ uint v, v_other;
MEdge *e;
} ScrewVertIter;
@@ -67,8 +67,8 @@ typedef struct ScrewVertIter {
static void screwvert_iter_init(ScrewVertIter *iter,
ScrewVertConnect *array,
- unsigned int v_init,
- unsigned int dir)
+ uint v_init,
+ uint dir)
{
iter->v_array = array;
iter->v = v_init;
@@ -187,10 +187,10 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
int *origindex;
int mpoly_index = 0;
- unsigned int step;
- unsigned int i, j;
- unsigned int i1, i2;
- unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
+ uint step;
+ uint i, j;
+ uint i1, i2;
+ uint step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0;
const int quad_ord[4] = {
@@ -206,17 +206,16 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
3,
};
- unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
- const unsigned int totvert = (unsigned int)mesh->totvert;
- const unsigned int totedge = (unsigned int)mesh->totedge;
- const unsigned int totpoly = (unsigned int)mesh->totpoly;
+ uint maxVerts = 0, maxEdges = 0, maxPolys = 0;
+ const uint totvert = (uint)mesh->totvert;
+ const uint totedge = (uint)mesh->totedge;
+ const uint totpoly = (uint)mesh->totpoly;
- unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */
- unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */
+ uint *edge_poly_map = NULL; /* orig edge to orig poly */
+ uint *vert_loop_map = NULL; /* orig vert to orig loop */
/* UV Coords */
- const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&mesh->ldata,
- CD_MLOOPUV);
+ const uint mloopuv_layers_tot = (uint)CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot);
float uv_u_scale;
float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX};
@@ -235,11 +234,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
float mtx_tx_inv[4][4]; /* inverted */
float mtx_tmp_a[4][4];
- unsigned int vc_tot_linked = 0;
+ uint vc_tot_linked = 0;
short other_axis_1, other_axis_2;
const float *tmpf1, *tmpf2;
- unsigned int edge_offset;
+ uint edge_offset;
MPoly *mpoly_orig, *mpoly_new, *mp_new;
MLoop *mloop_orig, *mloop_new, *ml_new;
@@ -409,7 +408,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (mloopuv_layers_tot) {
- unsigned int uv_lay;
+ uint uv_lay;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, (int)uv_lay);
}
@@ -460,18 +459,18 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert);
for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) {
- unsigned int loopstart = (unsigned int)mp_orig->loopstart;
- unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop;
+ uint loopstart = (uint)mp_orig->loopstart;
+ uint loopend = loopstart + (uint)mp_orig->totloop;
MLoop *ml_orig = &mloop_orig[loopstart];
- unsigned int k;
+ uint k;
for (k = loopstart; k < loopend; k++, ml_orig++) {
edge_poly_map[ml_orig->e] = i;
vert_loop_map[ml_orig->v] = k;
/* also order edges based on faces */
if (medge_new[ml_orig->e].v1 != ml_orig->v) {
- SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
+ SWAP(uint, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
}
}
}
@@ -596,7 +595,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
* so resulting faces are flipped the right way */
vc_tot_linked = 0; /* count the number of linked verts for this loop */
if (vc->flag == 0) {
- unsigned int v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */
+ uint v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */
ScrewVertIter lt_iter;
float fl = -1.0f;
@@ -731,7 +730,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (lt_iter.v == lt_iter.e->v1) {
if (ed_loop_flip == 0) {
/*printf("\t\t\tFlipping 0\n");*/
- SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
+ SWAP(uint, lt_iter.e->v1, lt_iter.e->v2);
}
#if 0
else {
@@ -742,7 +741,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
else if (lt_iter.v == lt_iter.e->v2) {
if (ed_loop_flip == 1) {
/*printf("\t\t\tFlipping 1\n");*/
- SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
+ SWAP(uint, lt_iter.e->v1, lt_iter.e->v2);
}
#if 0
else {
@@ -851,7 +850,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* Add Faces */
for (step = 1; step < step_tot; step++) {
- const unsigned int varray_stride = totvert * step;
+ const uint varray_stride = totvert * step;
float step_angle;
float nor_tx[3];
float mat[4][4];
@@ -921,7 +920,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (close) {
/* last loop of edges, previous loop doesn't account for the last set of edges */
- const unsigned int varray_stride = (step_tot - 1) * totvert;
+ const uint varray_stride = (step_tot - 1) * totvert;
for (i = 0; i < totvert; i++) {
med_new->v1 = i;
@@ -942,12 +941,12 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1)));
for (i = 0; i < totedge; i++, med_new_firstloop++) {
- const unsigned int step_last = step_tot - (close ? 1 : 2);
- const unsigned int mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX;
+ const uint step_last = step_tot - (close ? 1 : 2);
+ const uint mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX;
const bool has_mpoly_orig = (mpoly_index_orig != UINT_MAX);
float uv_v_offset_a, uv_v_offset_b;
- const unsigned int mloop_index_orig[2] = {
+ const uint mloop_index_orig[2] = {
vert_loop_map ? vert_loop_map[medge_new[i].v1] : UINT_MAX,
vert_loop_map ? vert_loop_map[medge_new[i].v2] : UINT_MAX,
};
@@ -1006,7 +1005,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
&mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 3, 1);
if (mloopuv_layers_tot) {
- unsigned int uv_lay;
+ uint uv_lay;
const float uv_u_offset_a = (float)(step)*uv_u_scale;
const float uv_u_offset_b = (float)(step + 1) * uv_u_scale;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
@@ -1023,7 +1022,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (mloopuv_layers_tot) {
int l_index = (int)(ml_new - mloop_new);
- unsigned int uv_lay;
+ uint uv_lay;
const float uv_u_offset_a = (float)(step)*uv_u_scale;
const float uv_u_offset_b = (float)(step + 1) * uv_u_scale;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
@@ -1094,7 +1093,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
unsigned i = 0;
printf("\n");
for (; i < maxPolys * 4; i += 4) {
- unsigned int ii;
+ uint ii;
ml_new = mloop_new + i;
ii = findEd(medge_new, maxEdges, ml_new[0].v, ml_new[1].v);
printf("%d %d -- ", ii, ml_new[0].e);
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index f11e4e4d77a..6e7a0b0dbae 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -103,7 +103,7 @@ typedef struct Frame {
int corner;
/* checked to avoid chaining.
* (merging when we're already been referenced), see T39775 */
- unsigned int is_target : 1;
+ uint is_target : 1;
} merge[4];
/* For hull frames, whether each vertex is detached or not */
@@ -1871,7 +1871,7 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd)
return NULL;
}
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, origmesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index 59d5b2ccbd2..c8bc3aaa484 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -54,16 +54,15 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
bool UNUSED(useRenderParams))
{
SmoothModifierData *smd = (SmoothModifierData *)md;
- short flag;
- flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z);
+ const short flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z);
/* disable if modifier is off for X, Y and Z or if factor is 0 */
- if ((smd->fac == 0.0f) || flag == 0) {
- return 1;
+ if (smd->fac == 0.0f || flag == 0) {
+ return true;
}
- return 0;
+ return false;
}
static void requiredDataMask(Object *UNUSED(ob),
@@ -81,134 +80,105 @@ static void requiredDataMask(Object *UNUSED(ob),
static void smoothModifier_do(
SmoothModifierData *smd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- MDeformVert *dvert = NULL;
- MEdge *medges = NULL;
-
- int i, j, numDMEdges, defgrp_index;
- unsigned char *uctmp;
- float *ftmp, fac, facm;
+ if (mesh == NULL) {
+ return;
+ }
- ftmp = (float *)MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "smoothmodifier_f");
- if (!ftmp) {
+ float(*accumulated_vecs)[3] = MEM_calloc_arrayN(
+ (size_t)numVerts, sizeof(*accumulated_vecs), __func__);
+ if (!accumulated_vecs) {
return;
}
- uctmp = (unsigned char *)MEM_calloc_arrayN(numVerts, sizeof(unsigned char), "smoothmodifier_uc");
- if (!uctmp) {
- if (ftmp) {
- MEM_freeN(ftmp);
+
+ uint *num_accumulated_vecs = MEM_calloc_arrayN(
+ (size_t)numVerts, sizeof(*num_accumulated_vecs), __func__);
+ if (!num_accumulated_vecs) {
+ if (accumulated_vecs) {
+ MEM_freeN(accumulated_vecs);
}
return;
}
- fac = smd->fac;
- facm = 1 - fac;
+ const float fac_new = smd->fac;
+ const float fac_orig = 1.0f - fac_new;
- if (mesh != NULL) {
- medges = mesh->medge;
- numDMEdges = mesh->totedge;
- }
- else {
- medges = NULL;
- numDMEdges = 0;
- }
+ MEdge *medges = mesh->medge;
+ const int num_edges = mesh->totedge;
+ MDeformVert *dvert;
+ int defgrp_index;
MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
- /* NOTICE: this can be optimized a little bit by moving the
- * if (dvert) out of the loop, if needed */
- for (j = 0; j < smd->repeat; j++) {
- for (i = 0; i < numDMEdges; i++) {
- float fvec[3];
- float *v1, *v2;
- unsigned int idx1, idx2;
-
- idx1 = medges[i].v1;
- idx2 = medges[i].v2;
+ for (int j = 0; j < smd->repeat; j++) {
+ if (j != 0) {
+ memset(accumulated_vecs, 0, sizeof(*accumulated_vecs) * (size_t)numVerts);
+ memset(num_accumulated_vecs, 0, sizeof(*num_accumulated_vecs) * (size_t)numVerts);
+ }
- v1 = vertexCos[idx1];
- v2 = vertexCos[idx2];
+ for (int i = 0; i < num_edges; i++) {
+ float fvec[3];
+ const uint idx1 = medges[i].v1;
+ const uint idx2 = medges[i].v2;
- mid_v3_v3v3(fvec, v1, v2);
+ mid_v3_v3v3(fvec, vertexCos[idx1], vertexCos[idx2]);
- v1 = &ftmp[idx1 * 3];
- v2 = &ftmp[idx2 * 3];
+ num_accumulated_vecs[idx1]++;
+ add_v3_v3(accumulated_vecs[idx1], fvec);
- if (uctmp[idx1] < 255) {
- uctmp[idx1]++;
- add_v3_v3(v1, fvec);
- }
- if (uctmp[idx2] < 255) {
- uctmp[idx2]++;
- add_v3_v3(v2, fvec);
- }
+ num_accumulated_vecs[idx2]++;
+ add_v3_v3(accumulated_vecs[idx2], fvec);
}
+ const short flag = smd->flag;
if (dvert) {
MDeformVert *dv = dvert;
- for (i = 0; i < numVerts; i++, dv++) {
- float f, fm, facw, *fp, *v;
- short flag = smd->flag;
-
- v = vertexCos[i];
- fp = &ftmp[i * 3];
-
- f = defvert_find_weight(dv, defgrp_index);
- if (f <= 0.0f) {
- continue;
+ for (int i = 0; i < numVerts; i++, dv++) {
+ float *vco_orig = vertexCos[i];
+ if (num_accumulated_vecs[0] > 0) {
+ mul_v3_fl(accumulated_vecs[i], 1.0f / (float)num_accumulated_vecs[i]);
}
+ float *vco_new = accumulated_vecs[i];
- f *= fac;
- fm = 1.0f - f;
-
- /* fp is the sum of uctmp[i] verts, so must be averaged */
- facw = 0.0f;
- if (uctmp[i]) {
- facw = f / (float)uctmp[i];
+ const float f_new = defvert_find_weight(dv, defgrp_index) * fac_new;
+ if (f_new <= 0.0f) {
+ continue;
}
+ const float f_orig = 1.0f - f_new;
if (flag & MOD_SMOOTH_X) {
- v[0] = fm * v[0] + facw * fp[0];
+ vco_orig[0] = f_orig * vco_orig[0] + f_new * vco_new[0];
}
if (flag & MOD_SMOOTH_Y) {
- v[1] = fm * v[1] + facw * fp[1];
+ vco_orig[1] = f_orig * vco_orig[1] + f_new * vco_new[1];
}
if (flag & MOD_SMOOTH_Z) {
- v[2] = fm * v[2] + facw * fp[2];
+ vco_orig[2] = f_orig * vco_orig[2] + f_new * vco_new[2];
}
}
}
else { /* no vertex group */
- for (i = 0; i < numVerts; i++) {
- float facw, *fp, *v;
- short flag = smd->flag;
-
- v = vertexCos[i];
- fp = &ftmp[i * 3];
-
- /* fp is the sum of uctmp[i] verts, so must be averaged */
- facw = 0.0f;
- if (uctmp[i]) {
- facw = fac / (float)uctmp[i];
+ for (int i = 0; i < numVerts; i++) {
+ float *vco_orig = vertexCos[i];
+ if (num_accumulated_vecs[0] > 0) {
+ mul_v3_fl(accumulated_vecs[i], 1.0f / (float)num_accumulated_vecs[i]);
}
+ float *vco_new = accumulated_vecs[i];
if (flag & MOD_SMOOTH_X) {
- v[0] = facm * v[0] + facw * fp[0];
+ vco_orig[0] = fac_orig * vco_orig[0] + fac_new * vco_new[0];
}
if (flag & MOD_SMOOTH_Y) {
- v[1] = facm * v[1] + facw * fp[1];
+ vco_orig[1] = fac_orig * vco_orig[1] + fac_new * vco_new[1];
}
if (flag & MOD_SMOOTH_Z) {
- v[2] = facm * v[2] + facw * fp[2];
+ vco_orig[2] = fac_orig * vco_orig[2] + fac_new * vco_new[2];
}
}
}
-
- memset(ftmp, 0, 3 * sizeof(float) * numVerts);
- memset(uctmp, 0, sizeof(unsigned char) * numVerts);
}
- MEM_freeN(ftmp);
- MEM_freeN(uctmp);
+ MEM_freeN(accumulated_vecs);
+ MEM_freeN(num_accumulated_vecs);
}
static void deformVerts(ModifierData *md,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 05bcc7f695d..292e659fe03 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -198,11 +198,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEdge *ed, *medge, *orig_medge;
MLoop *ml, *mloop, *orig_mloop;
MPoly *mp, *mpoly, *orig_mpoly;
- const unsigned int numVerts = (unsigned int)mesh->totvert;
- const unsigned int numEdges = (unsigned int)mesh->totedge;
- const unsigned int numPolys = (unsigned int)mesh->totpoly;
- const unsigned int numLoops = (unsigned int)mesh->totloop;
- unsigned int newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
+ const uint numVerts = (uint)mesh->totvert;
+ const uint numEdges = (uint)mesh->totedge;
+ const uint numPolys = (uint)mesh->totpoly;
+ const uint numLoops = (uint)mesh->totloop;
+ uint newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
/* only use material offsets if we have 2 or more materials */
const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0;
@@ -211,16 +211,16 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* use for edges */
/* over-alloc new_vert_arr, old_vert_arr */
- unsigned int *new_vert_arr = NULL;
+ uint *new_vert_arr = NULL;
STACK_DECLARE(new_vert_arr);
- unsigned int *new_edge_arr = NULL;
+ uint *new_edge_arr = NULL;
STACK_DECLARE(new_edge_arr);
- unsigned int *old_vert_arr = MEM_calloc_arrayN(
+ uint *old_vert_arr = MEM_calloc_arrayN(
numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify");
- unsigned int *edge_users = NULL;
+ uint *edge_users = NULL;
char *edge_order = NULL;
float(*vert_nors)[3] = NULL;
@@ -244,7 +244,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
int defgrp_index;
/* array size is doubled in case of using a shell */
- const unsigned int stride = do_shell ? 2 : 1;
+ const uint stride = do_shell ? 2 : 1;
MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
@@ -272,11 +272,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (smd->flag & MOD_SOLIDIFY_RIM) {
BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
- unsigned int eidx;
- unsigned int i;
+ uint eidx;
+ uint i;
-#define INVALID_UNUSED ((unsigned int)-1)
-#define INVALID_PAIR ((unsigned int)-2)
+#define INVALID_UNUSED ((uint)-1)
+#define INVALID_PAIR ((uint)-2)
new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__);
new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__);
@@ -442,13 +442,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* flip normals */
if (do_shell) {
- unsigned int i;
+ uint i;
mp = mpoly + numPolys;
for (i = 0; i < mesh->totpoly; i++, mp++) {
const int loop_end = mp->totloop - 1;
MLoop *ml2;
- unsigned int e;
+ uint e;
int j;
/* reverses the loop direction (MLoop.v as well as custom-data)
@@ -512,7 +512,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
const float offset_sq = offset * offset;
if (do_clamp) {
- unsigned int i;
+ uint i;
vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
@@ -524,7 +524,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_new != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
@@ -532,7 +532,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
INIT_VERT_ARRAY_OFFSETS(false);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (dvert) {
MDeformVert *dv = &dvert[i];
if (defgrp_invert) {
@@ -559,7 +559,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_orig != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
@@ -568,7 +568,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
INIT_VERT_ARRAY_OFFSETS(true);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (dvert) {
MDeformVert *dv = &dvert[i];
if (defgrp_invert) {
@@ -606,8 +606,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
float *vert_angles = MEM_calloc_arrayN(
numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */
float *vert_accum = vert_angles + numVerts;
- unsigned int vidx;
- unsigned int i;
+ uint vidx;
+ uint i;
if (vert_nors == NULL) {
vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno");
@@ -707,13 +707,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_new != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
INIT_VERT_ARRAY_OFFSETS(false);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (vert_accum[i_other]) { /* zero if unselected */
madd_v3_v3fl(
mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
@@ -722,14 +722,14 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (ofs_orig != 0.0f) {
- unsigned int i_orig, i_end;
+ uint i_orig, i_end;
bool do_shell_align;
/* same as above but swapped, intentional use of 'ofs_new' */
INIT_VERT_ARRAY_OFFSETS(true);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (vert_accum[i_other]) { /* zero if unselected */
madd_v3_v3fl(
mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
@@ -749,7 +749,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
else if (do_shell) {
- unsigned int i;
+ uint i;
/* flip vertex normals for copied verts */
mv = mvert + numVerts;
for (i = 0; i < numVerts; i++, mv++) {
@@ -758,7 +758,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (smd->flag & MOD_SOLIDIFY_RIM) {
- unsigned int i;
+ uint i;
/* bugger, need to re-calculate the normals for the new edge faces.
* This could be done in many ways, but probably the quickest way
@@ -781,13 +781,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
NULL;
float nor[3];
#endif
- const unsigned char crease_rim = smd->crease_rim * 255.0f;
- const unsigned char crease_outer = smd->crease_outer * 255.0f;
- const unsigned char crease_inner = smd->crease_inner * 255.0f;
+ const uchar crease_rim = smd->crease_rim * 255.0f;
+ const uchar crease_outer = smd->crease_outer * 255.0f;
+ const uchar crease_inner = smd->crease_inner * 255.0f;
int *origindex_edge;
int *orig_ed;
- unsigned int j;
+ uint j;
if (crease_rim || crease_outer || crease_inner) {
result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
@@ -817,8 +817,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
ml = mloop + (numLoops * stride);
j = 0;
for (i = 0; i < newPolys; i++, mp++) {
- unsigned int eidx = new_edge_arr[i];
- unsigned int pidx = edge_users[eidx];
+ uint eidx = new_edge_arr[i];
+ uint pidx = edge_users[eidx];
int k1, k2;
bool flip;
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 08a884fa879..4a5887c3122 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -35,6 +35,7 @@
#include "BKE_scene.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_deform.h"
#include "BKE_subdiv_mesh.h"
#include "BKE_subsurf.h"
@@ -240,6 +241,40 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
return result;
}
+static void deformMatrices(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh,
+ float (*vertex_cos)[3],
+ float (*deform_matrices)[3][3],
+ int num_verts)
+{
+#if !defined(WITH_OPENSUBDIV)
+ modifier_setError(md, "Disabled, built without OpenSubdiv");
+ return;
+#endif
+
+ /* Subsurf does not require extra space mapping, keep matrices as is. */
+ (void)deform_matrices;
+
+ SubsurfModifierData *smd = (SubsurfModifierData *)md;
+ SubdivSettings subdiv_settings;
+ subdiv_settings_init(&subdiv_settings, smd);
+ if (subdiv_settings.level == 0) {
+ return;
+ }
+ BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh);
+ SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
+ Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, but also on empty input mesh. */
+ return;
+ }
+ BKE_subdiv_deform_coarse_vertices(subdiv, mesh, vertex_cos, num_verts);
+ if (subdiv != runtime_data->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
+}
+
ModifierTypeInfo modifierType_Subsurf = {
/* name */ "Subdivision",
/* structName */ "SubsurfModifierData",
@@ -252,7 +287,7 @@ ModifierTypeInfo modifierType_Subsurf = {
/* copyData */ copyData,
/* deformVerts */ NULL,
- /* deformMatrices */ NULL,
+ /* deformMatrices */ deformMatrices,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 840914aa313..97e6bb9e804 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -125,7 +125,7 @@ static void deformVerts(ModifierData *md,
}
if (surmd->mesh) {
- unsigned int numverts = 0, i = 0;
+ uint numverts = 0, i = 0;
int init = 0;
float *vec;
MVert *x, *v;
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index b34688d27d6..de32b90a5e3 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -45,16 +45,16 @@
typedef struct SDefAdjacency {
struct SDefAdjacency *next;
- unsigned int index;
+ uint index;
} SDefAdjacency;
typedef struct SDefAdjacencyArray {
SDefAdjacency *first;
- unsigned int num; /* Careful, this is twice the number of polygons (avoids an extra loop) */
+ uint num; /* Careful, this is twice the number of polygons (avoids an extra loop) */
} SDefAdjacencyArray;
typedef struct SDefEdgePolys {
- unsigned int polys[2], num;
+ uint polys[2], num;
} SDefEdgePolys;
typedef struct SDefBindCalcData {
@@ -90,20 +90,20 @@ typedef struct SDefBindPoly {
float point_edgemid_angles[2];
float corner_edgemid_angles[2];
float dominant_angle_weight;
- unsigned int index;
- unsigned int numverts;
- unsigned int loopstart;
- unsigned int edge_inds[2];
- unsigned int edge_vert_inds[2];
- unsigned int corner_ind;
- unsigned int dominant_edge;
+ uint index;
+ uint numverts;
+ uint loopstart;
+ uint edge_inds[2];
+ uint edge_vert_inds[2];
+ uint corner_ind;
+ uint dominant_edge;
bool inside;
} SDefBindPoly;
typedef struct SDefBindWeightData {
SDefBindPoly *bind_polys;
- unsigned int numpoly;
- unsigned int numbinds;
+ uint numpoly;
+ uint numbinds;
} SDefBindWeightData;
typedef struct SDefDeformData {
@@ -217,8 +217,8 @@ static void freeAdjacencyMap(SDefAdjacencyArray *const vert_edges,
static int buildAdjacencyMap(const MPoly *poly,
const MEdge *edge,
const MLoop *const mloop,
- const unsigned int numpoly,
- const unsigned int numedges,
+ const uint numpoly,
+ const uint numedges,
SDefAdjacencyArray *const vert_edges,
SDefAdjacency *adj,
SDefEdgePolys *const edge_polys)
@@ -263,10 +263,10 @@ static int buildAdjacencyMap(const MPoly *poly,
return MOD_SDEF_BIND_RESULT_SUCCESS;
}
-BLI_INLINE void sortPolyVertsEdge(unsigned int *indices,
+BLI_INLINE void sortPolyVertsEdge(uint *indices,
const MLoop *const mloop,
- const unsigned int edge,
- const unsigned int num)
+ const uint edge,
+ const uint num)
{
bool found = false;
@@ -287,10 +287,10 @@ BLI_INLINE void sortPolyVertsEdge(unsigned int *indices,
}
}
-BLI_INLINE void sortPolyVertsTri(unsigned int *indices,
+BLI_INLINE void sortPolyVertsTri(uint *indices,
const MLoop *const mloop,
- const unsigned int loopstart,
- const unsigned int num)
+ const uint loopstart,
+ const uint num)
{
for (int i = loopstart; i < num; i++) {
*indices = mloop[i].v;
@@ -303,7 +303,7 @@ BLI_INLINE void sortPolyVertsTri(unsigned int *indices,
}
}
-BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float point_co[3])
+BLI_INLINE uint nearestVert(SDefBindCalcData *const data, const float point_co[3])
{
BVHTreeNearest nearest = {
.dist_sq = FLT_MAX,
@@ -315,7 +315,7 @@ BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float po
float t_point[3];
float max_dist = FLT_MAX;
float dist;
- unsigned int index = 0;
+ uint index = 0;
mul_v3_m4v3(t_point, data->imat, point_co);
@@ -346,7 +346,7 @@ BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float po
}
}
-BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr)
+BLI_INLINE int isPolyValid(const float coords[][2], const uint nr)
{
float prev_co[2];
float curr_vec[2], prev_vec[2];
@@ -408,7 +408,7 @@ BLI_INLINE float computeAngularWeight(const float point_angle, const float edgem
BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
const float point_co[3])
{
- const unsigned int nearest = nearestVert(data, point_co);
+ const uint nearest = nearestVert(data, point_co);
const SDefAdjacency *const vert_edges = data->vert_edges[nearest].first;
const SDefEdgePolys *const edge_polys = data->edge_polys;
@@ -444,7 +444,7 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
/* Loop over all adjacent edges,
* and build the SDefBindPoly data for each poly adjacent to those. */
for (vedge = vert_edges; vedge; vedge = vedge->next) {
- unsigned int edge_ind = vedge->index;
+ uint edge_ind = vedge->index;
for (int i = 0; i < edge_polys[edge_ind].num; i++) {
{
@@ -603,8 +603,8 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
SDefBindPoly *bpolys[2];
const SDefEdgePolys *epolys;
float ang_weights[2];
- unsigned int edge_ind = vedge->index;
- unsigned int edge_on_poly[2];
+ uint edge_ind = vedge->index;
+ uint edge_on_poly[2];
epolys = &edge_polys[edge_ind];
@@ -981,9 +981,9 @@ static void bindVert(void *__restrict userdata,
static bool surfacedeformBind(SurfaceDeformModifierData *smd,
float (*vertexCos)[3],
- unsigned int numverts,
- unsigned int tnumpoly,
- unsigned int tnumverts,
+ uint numverts,
+ uint tnumpoly,
+ uint tnumverts,
Mesh *target)
{
BVHTreeFromMesh treeData = {NULL};
@@ -991,7 +991,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd,
const MPoly *mpoly = target->mpoly;
const MEdge *medge = target->medge;
const MLoop *mloop = target->mloop;
- unsigned int tnumedges = target->totedge;
+ uint tnumedges = target->totedge;
int adj_result;
SDefAdjacencyArray *vert_edges;
SDefAdjacency *adj_array;
@@ -1173,12 +1173,12 @@ static void deformVert(void *__restrict userdata,
static void surfacedeformModifier_do(ModifierData *md,
const ModifierEvalContext *ctx,
float (*vertexCos)[3],
- unsigned int numverts,
+ uint numverts,
Object *ob)
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
Mesh *target;
- unsigned int tnumverts, tnumpoly;
+ uint tnumverts, tnumpoly;
/* Exit function if bind flag is not set (free bind data if any). */
if (!(smd->flags & MOD_SDEF_BIND)) {
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 1582c27960e..7fba7e864ae 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -65,7 +65,7 @@ static Mesh *triangulate_mesh(Mesh *mesh,
BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, false, NULL, NULL, NULL);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks, mesh);
BM_mesh_free(bm);
if (keep_clnors) {
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 84ab8afa18a..31df8185dc1 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -109,11 +109,11 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd,
/* verts are given the UV from the first face that uses them */
for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
if (!BLI_BITMAP_TEST(done, vidx)) {
/* remap UVs from [0, 1] to [-1, 1] */
@@ -182,7 +182,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
else if (ob->type == OB_MESH) {
if (em) {
- mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data);
}
else {
/* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index b31e0832123..9698e150850 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -225,19 +225,19 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
if (num_projectors == 1) {
if (projectors[0].uci) {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
} while (fidx--);
}
else {
/* apply transformed coords as UVs */
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
} while (fidx--);
}
@@ -268,18 +268,18 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
}
if (best_projector->uci) {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
} while (fidx--);
}
else {
- unsigned int fidx = mp->totloop - 1;
+ uint fidx = mp->totloop - 1;
do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
+ uint lidx = mp->loopstart + fidx;
+ uint vidx = mloop[lidx].v;
mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]);
} while (fidx--);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 95b15b4a924..7e23289433f 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -215,7 +215,7 @@ static void get_vert2ob_distance(
{
/* Vertex and ref object coordinates. */
float v_wco[3];
- unsigned int i = numVerts;
+ uint i = numVerts;
while (i-- > 0) {
/* Get world-coordinates of the vertex (constraints and anim included). */
@@ -241,7 +241,7 @@ static void do_map(
Object *ob, float *weights, const int nidx, const float min_d, const float max_d, short mode)
{
const float range_inv = 1.0f / (max_d - min_d); /* invert since multiplication is faster */
- unsigned int i = nidx;
+ uint i = nidx;
if (max_d == min_d) {
while (i-- > 0) {
weights[i] = (weights[i] >= max_d) ? 1.0f : 0.0f; /* "Step" behavior... */
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 7af9ef6f5b6..3dd6e00c3a5 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -91,7 +91,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
MAX2(ob->totcol - 1, 0),
false);
- result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 57a4ace997c..f618f964b22 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -206,9 +206,9 @@ set(SRC
shader/nodes/node_shader_valToRgb.c
shader/nodes/node_shader_value.c
shader/nodes/node_shader_vectTransform.c
- shader/nodes/node_shader_vertex_color.c
shader/nodes/node_shader_vector_displacement.c
shader/nodes/node_shader_vector_math.c
+ shader/nodes/node_shader_vertex_color.c
shader/nodes/node_shader_volume_absorption.c
shader/nodes/node_shader_volume_info.c
shader/nodes/node_shader_volume_principled.c
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 9caa76377fd..4bcd77496c1 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -32,6 +32,7 @@
#include "DNA_linestyle_types.h"
#include "DNA_workspace_types.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -212,115 +213,6 @@ void register_node_tree_type_sh(void)
/* GPU material from shader nodes */
-static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
- bNode *node_from,
- bNodeSocket *socket_from,
- bNode *displacement_node,
- bNodeSocket *displacement_socket);
-
-static bNodeSocket *ntree_shader_node_find_input(bNode *node, const char *identifier);
-
-static bNode *ntree_group_output_node(bNodeTree *ntree);
-
-static bNode *ntree_shader_relink_output_from_group(bNodeTree *ntree,
- bNode *group_node,
- bNode *sh_output_node,
- int target)
-{
- int i;
- bNodeTree *group_ntree = (bNodeTree *)group_node->id;
-
- int sock_len = BLI_listbase_count(&sh_output_node->inputs);
- bNodeSocket **group_surface_sockets = BLI_array_alloca(group_surface_sockets, sock_len);
-
- /* Create output sockets to plug output connection to. */
- i = 0;
- for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, i++) {
- group_surface_sockets[i] = ntreeAddSocketInterface(
- group_ntree, SOCK_OUT, sock->typeinfo->idname, sock->name);
- }
-
- bNode *group_output_node = ntree_group_output_node(group_ntree);
-
- /* If no group output node is present, we need to create one. */
- if (group_output_node == NULL) {
- group_output_node = nodeAddStaticNode(NULL, group_ntree, NODE_GROUP_OUTPUT);
- }
-
- /* Need to update tree so all node instances nodes gets proper sockets. */
- node_group_update(ntree, group_node);
- node_group_output_update(group_ntree, group_output_node);
- ntreeUpdateTree(G.main, group_ntree);
-
- /* Remove other shader output nodes so that only the new one can be selected as active. */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT)) {
- ntreeFreeLocalNode(ntree, node);
- }
- }
-
- /* Create new shader output node outside the group. */
- bNode *new_output_node = nodeAddStaticNode(NULL, ntree, sh_output_node->type);
- new_output_node->custom1 = target;
-
- i = 0;
- for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, i++) {
- if (sock->link != NULL) {
- /* Link the shader output node incoming link to the group output sockets */
- bNodeSocket *group_output_node_surface_input_sock = nodeFindSocket(
- group_output_node, SOCK_IN, group_surface_sockets[i]->identifier);
- nodeAddLink(group_ntree,
- sock->link->fromnode,
- sock->link->fromsock,
- group_output_node,
- group_output_node_surface_input_sock);
-
- /* Link the group output sockets to the new shader output node. */
- bNodeSocket *group_node_surface_output = nodeFindSocket(
- group_node, SOCK_OUT, group_surface_sockets[i]->identifier);
- bNodeSocket *output_node_surface_input = ntree_shader_node_find_input(new_output_node,
- sock->name);
-
- nodeAddLink(ntree,
- group_node,
- group_node_surface_output,
- new_output_node,
- output_node_surface_input);
- }
- }
-
- ntreeUpdateTree(G.main, group_ntree);
- ntreeUpdateTree(G.main, ntree);
-
- return new_output_node;
-}
-
-static bNode *ntree_shader_output_node_from_group(bNodeTree *ntree, int target)
-{
- bNode *output_node = NULL;
-
- /* Search if node groups do not contain valid output nodes (recursively). */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (!ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
- continue;
- }
- if (node->id != NULL) {
- output_node = ntree_shader_output_node_from_group((bNodeTree *)node->id, target);
-
- if (output_node == NULL) {
- output_node = ntreeShaderOutputNode((bNodeTree *)node->id, target);
- }
-
- if (output_node != NULL) {
- /* Output is inside this group node. Create relink to make the output outside the group. */
- output_node = ntree_shader_relink_output_from_group(ntree, node, output_node, target);
- break;
- }
- }
- }
- return output_node;
-}
-
/* Find an output node of the shader tree.
*
* NOTE: it will only return output which is NOT in the group, which isn't how
@@ -368,28 +260,6 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
return output_node;
}
-/* Find the active output node of a group nodetree.
- *
- * Does not return the shading output node but the group output node.
- */
-static bNode *ntree_group_output_node(bNodeTree *ntree)
-{
- /* Make sure we only have single node tagged as output. */
- ntreeSetOutput(ntree);
-
- /* Find output node that matches type and target. If there are
- * multiple, we prefer exact target match and active nodes. */
- bNode *output_node = NULL;
-
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if ((node->type == NODE_GROUP_OUTPUT) && (node->flag & NODE_DO_OUTPUT)) {
- output_node = node;
- }
- }
-
- return output_node;
-}
-
/* Find socket with a specified identifier. */
static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets, const char *identifier)
{
@@ -520,6 +390,109 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
}
}
+static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
+{
+ bNodeLink *link, *linkn, *tlink;
+ bNode *node, *nextnode;
+ bNodeTree *ngroup;
+ LinkNode *group_interface_nodes = NULL;
+
+ ngroup = (bNodeTree *)gnode->id;
+
+ /* Add the nodes into the ntree */
+ for (node = ngroup->nodes.first; node; node = nextnode) {
+ nextnode = node->next;
+ /* Remove interface nodes.
+ * This also removes remaining links to and from interface nodes.
+ * We must delay removal since sockets will reference this node. see: T52092 */
+ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ BLI_linklist_prepend(&group_interface_nodes, node);
+ }
+ /* migrate node */
+ BLI_remlink(&ngroup->nodes, node);
+ BLI_addtail(&ntree->nodes, node);
+ /* ensure unique node name in the node tree */
+ /* This is very slow and it has no use for GPU nodetree. (see T70609) */
+ // nodeUniqueName(ntree, node);
+ }
+
+ /* Save first and last link to iterate over flattened group links. */
+ bNodeLink *glinks_first = ntree->links.last;
+
+ /* Add internal links to the ntree */
+ for (link = ngroup->links.first; link; link = linkn) {
+ linkn = link->next;
+ BLI_remlink(&ngroup->links, link);
+ BLI_addtail(&ntree->links, link);
+ }
+
+ bNodeLink *glinks_last = ntree->links.last;
+
+ /* restore external links to and from the gnode */
+ if (glinks_first != NULL) {
+ /* input links */
+ for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ if (link->fromnode->type == NODE_GROUP_INPUT) {
+ const char *identifier = link->fromsock->identifier;
+ /* find external links to this input */
+ for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
+ }
+ }
+ }
+ }
+ /* Also iterate over the new links to cover passthrough links. */
+ glinks_last = ntree->links.last;
+ /* output links */
+ for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ if (tlink->fromnode == gnode) {
+ const char *identifier = tlink->fromsock->identifier;
+ /* find internal links to this output */
+ for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ /* only use active output node */
+ if (link->tonode->type == NODE_GROUP_OUTPUT && (link->tonode->flag & NODE_DO_OUTPUT)) {
+ if (STREQ(link->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, link->fromnode, link->fromsock, tlink->tonode, tlink->tosock);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ while (group_interface_nodes) {
+ node = BLI_linklist_pop(&group_interface_nodes);
+ ntreeFreeLocalNode(ntree, node);
+ }
+
+ ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+}
+
+/* Flatten group to only have a simple single tree */
+static void ntree_shader_groups_flatten(bNodeTree *localtree)
+{
+ /* This is effectively recursive as the flattened groups will add
+ * nodes at the end of the list, which will also get evaluated. */
+ for (bNode *node = localtree->nodes.first, *node_next; node; node = node_next) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) {
+ flatten_group_do(localtree, node);
+ /* Continue even on new flattened nodes. */
+ node_next = node->next;
+ /* delete the group instance and its localtree. */
+ bNodeTree *ngroup = (bNodeTree *)node->id;
+ ntreeFreeLocalNode(localtree, node);
+ ntreeFreeTree(ngroup);
+ MEM_freeN(ngroup);
+ }
+ else {
+ node_next = node->next;
+ }
+ }
+
+ ntreeUpdateTree(G.main, localtree);
+}
+
/* Check whether shader has a displacement.
*
* Will also return a node and it's socket which is connected to a displacement
@@ -576,53 +549,10 @@ static void ntree_shader_relink_node_normal(bNodeTree *ntree,
}
}
-static void ntree_shader_link_builtin_group_normal(bNodeTree *ntree,
- bNode *group_node,
- bNode *node_from,
- bNodeSocket *socket_from,
- bNode *displacement_node,
- bNodeSocket *displacement_socket)
-{
- bNodeTree *group_ntree = (bNodeTree *)group_node->id;
- /* Create input socket to plug displacement connection to. */
- bNodeSocket *group_normal_socket = ntreeAddSocketInterface(
- group_ntree, SOCK_IN, "NodeSocketVector", "Normal");
- /* Need to update tree so all node instances nodes gets proper sockets. */
- bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT);
- node_group_update(ntree, group_node);
- if (group_input_node) {
- node_group_input_update(group_ntree, group_input_node);
- }
- ntreeUpdateTree(G.main, group_ntree);
- /* Assumes sockets are always added at the end. */
- bNodeSocket *group_node_normal_socket = group_node->inputs.last;
- if (displacement_node == group_node) {
- /* This should never happen as all displacement nodes are duplicated and tagged. */
- BLI_assert(0);
- }
- else if (group_input_node) {
- /* Connect group node normal input. */
- nodeAddLink(ntree, node_from, socket_from, group_node, group_node_normal_socket);
- BLI_assert(group_input_node != NULL);
- bNodeSocket *group_input_node_normal_socket = nodeFindSocket(
- group_input_node, SOCK_OUT, group_normal_socket->identifier);
- BLI_assert(group_input_node_normal_socket != NULL);
- /* Relink normals inside of the instanced tree. */
- ntree_shader_link_builtin_normal(group_ntree,
- group_input_node,
- group_input_node_normal_socket,
- displacement_node,
- displacement_socket);
- ntreeUpdateTree(G.main, group_ntree);
- }
-}
-
/* Use specified node and socket as an input for unconnected normal sockets. */
static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
bNode *node_from,
- bNodeSocket *socket_from,
- bNode *displacement_node,
- bNodeSocket *displacement_socket)
+ bNodeSocket *socket_from)
{
for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
if (node == node_from) {
@@ -633,16 +563,6 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
/* This node is used inside the displacement tree. Skip to avoid cycles. */
continue;
}
- if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) {
- /* Special re-linking for group nodes. */
- ntree_shader_link_builtin_group_normal(
- ntree, node, node_from, socket_from, displacement_node, displacement_socket);
- continue;
- }
- if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
- /* Group inputs and outputs needs nothing special. */
- continue;
- }
ntree_shader_relink_node_normal(ntree, node, node_from, socket_from);
}
}
@@ -670,36 +590,17 @@ static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bN
static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
{
/* Bypass bump links inside copied nodes */
- bNodeLink *link, *link_next;
- for (link = ntree->links.first; link; link = link_next) {
- /* link might be freed by ntree_shader_bypass_bump_link. */
- link_next = link->next;
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
bNode *node = link->fromnode;
/* If node is a copy. */
if (node->tmp_flag == -2 && node->type == SH_NODE_BUMP) {
ntree_shader_bypass_bump_link(ntree, node, link);
}
}
- /* Do the same inside nodegroups. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* If node is a copy. */
- if (node->tmp_flag == -2 && ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
- bNodeTree *group_ntree = (bNodeTree *)node->id;
- /* Tag all nodes inside this group as copies. */
- LISTBASE_FOREACH (bNode *, group_node, &group_ntree->nodes) {
- group_node->tmp_flag = -2;
- }
- /* Recursive. */
- ntree_shader_bypass_tagged_bump_nodes(group_ntree);
- }
- }
ntreeUpdateTree(G.main, ntree);
}
-static bool ntree_branch_count_and_tag_nodes(bNode *fromnode,
- bNode *tonode,
- void *userdata,
- const bool UNUSED(reversed))
+static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
{
int *node_count = (int *)userdata;
if (fromnode->tmp_flag == -1) {
@@ -728,7 +629,7 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
/* Count and tag all nodes inside the displacement branch of the tree. */
start_node->tmp_flag = 0;
int node_count = 1;
- nodeChainIter(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, true);
+ nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, 1);
/* Make a full copy of the branch */
bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -736,9 +637,6 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
int id = node->tmp_flag;
nodes_copy[id] = BKE_node_copy_ex(ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT);
nodes_copy[id]->tmp_flag = -2; /* Copy */
- if (ELEM(nodes_copy[id]->type, NODE_GROUP, NODE_CUSTOM_GROUP) && nodes_copy[id]->id) {
- nodes_copy[id]->id = (ID *)ntreeLocalize((bNodeTree *)nodes_copy[id]->id);
- }
/* Make sure to clear all sockets links as they are invalid. */
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) {
sock->link = NULL;
@@ -850,8 +748,7 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
ntreeUpdateTree(G.main, ntree);
/* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */
- ntree_shader_link_builtin_normal(
- ntree, bump_node, bump_output_socket, displacement_node, displacement_socket);
+ ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
/* We modified the tree, it needs to be updated now. */
ntreeUpdateTree(G.main, ntree);
}
@@ -866,16 +763,13 @@ static void node_tag_branch_as_derivative(bNode *node, int dx)
}
}
-static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode),
- bNode *tonode,
- void *userdata,
- const bool UNUSED(reversed))
+static bool ntree_shader_bump_branches(bNode *fromnode, bNode *UNUSED(tonode), void *userdata)
{
bNodeTree *ntree = (bNodeTree *)userdata;
- if (tonode->type == SH_NODE_BUMP) {
+ if (fromnode->type == SH_NODE_BUMP) {
bNodeSocket *height_dx_sock, *height_dy_sock, *bump_socket, *bump_dx_socket, *bump_dy_socket;
- bNode *bump = tonode;
+ bNode *bump = fromnode;
bump_socket = ntree_shader_node_find_input(bump, "Height");
bump_dx_socket = ntree_shader_node_find_input(bump, "Height_dx");
bump_dy_socket = ntree_shader_node_find_input(bump, "Height_dy");
@@ -897,27 +791,9 @@ static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode),
return true;
}
-static bool ntree_tag_bsdf_cb(bNode *fromnode,
- bNode *UNUSED(tonode),
- void *userdata,
- const bool UNUSED(reversed))
+static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata)
{
- /* Don't evaluate nodes more than once. */
- if (fromnode->tmp_flag) {
- return true;
- }
- fromnode->tmp_flag = 1;
-
switch (fromnode->type) {
- case NODE_GROUP:
- case NODE_CUSTOM_GROUP:
- /* Recursive */
- if (fromnode->id != NULL) {
- bNodeTree *ntree = (bNodeTree *)fromnode->id;
- bNode *group_output = ntree_group_output_node(ntree);
- ntree_shader_tag_nodes(ntree, group_output, (nTreeTags *)userdata);
- }
- break;
case SH_NODE_BSDF_ANISOTROPIC:
case SH_NODE_EEVEE_SPECULAR:
case SH_NODE_BSDF_GLOSSY:
@@ -956,12 +832,7 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag
/* Make sure sockets links pointers are correct. */
ntreeUpdateTree(G.main, ntree);
- /* Reset visit flag. */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- node->tmp_flag = 0;
- }
-
- nodeChainIter(ntree, output_node, ntree_tag_bsdf_cb, tags, true);
+ nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0);
}
/* This one needs to work on a local tree. */
@@ -972,13 +843,17 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
{
bNodeTreeExec *exec;
- /* Extract output nodes from inside nodegroups. */
- ntree_shader_output_node_from_group(localtree, SHD_OUTPUT_EEVEE);
-
bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
ntree_shader_groups_expand_inputs(localtree);
+ ntree_shader_groups_flatten(localtree);
+
+ if (output == NULL) {
+ /* Search again, now including flattened nodes. */
+ output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
+ }
+
/* Perform all needed modifications on the tree in order to support
* displacement/bump mapping.
*/
@@ -986,7 +861,7 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
/* Duplicate bump height branches for manual derivatives.
*/
- nodeChainIter(localtree, output, ntree_shader_bump_branches, localtree, true);
+ nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree, 0);
/* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
nTreeTags tags = {
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index c92ae28f2e6..ecb8c53c312 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -67,7 +67,14 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
}
else {
GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name);
- return GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
+ GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
+
+ /* for each output. */
+ for (int i = 0; sh_node_attribute_out[i].type != -1; i++) {
+ node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
+ }
+
+ return 1;
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
index 595ddf27d0a..3340054396d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -120,6 +120,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[20].link);
}
+#if 0 /* Not used at the moment. */
/* Tangents */
if (!in[21].link) {
GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
@@ -131,6 +132,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPU_builtin(GPU_OBJECT_MATRIX),
&in[21].link);
}
+#endif
bool use_diffuse = socket_not_one(4) && socket_not_one(15);
bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c
index df9a8ac8318..3798cfbbfac 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c
@@ -41,21 +41,38 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
{
/* HACK: Don't request GPU_BARYCENTRIC_TEXCO if not used because it will
* trigger the use of geometry shader (and the performance penalty it implies). */
- float val[2] = {0.0f, 0.0f};
+ float val[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPUNodeLink *bary_link = (!out[5].hasoutput) ? GPU_constant(val) :
GPU_builtin(GPU_BARYCENTRIC_TEXCO);
+ /* Opti: don't request orco if not needed. */
+ GPUNodeLink *orco_link = (!out[2].hasoutput) ? GPU_constant(val) : GPU_attribute(CD_ORCO, "");
- return GPU_stack_link(mat,
- node,
- "node_geometry",
- in,
- out,
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_builtin(GPU_WORLD_NORMAL),
- GPU_attribute(CD_ORCO, ""),
- GPU_builtin(GPU_OBJECT_MATRIX),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
- bary_link);
+ const bool success = GPU_stack_link(mat,
+ node,
+ "node_geometry",
+ in,
+ out,
+ GPU_builtin(GPU_VIEW_POSITION),
+ GPU_builtin(GPU_WORLD_NORMAL),
+ orco_link,
+ GPU_builtin(GPU_OBJECT_MATRIX),
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
+ bary_link);
+
+ /* for each output */
+ for (int i = 0; sh_node_geometry_out[i].type != -1; i++) {
+ node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
+ /* Normalize some vectors after dFdx/dFdy offsets.
+ * This is the case for interpolated, non linear functions.
+ * The resulting vector can still be a bit wrong but not as much.
+ * (see T70644) */
+ if (node->branch_tag != 0 && ELEM(i, 1, 2, 4)) {
+ GPU_link(
+ mat, "vector_math_normalize", out[i].link, out[i].link, out[i].link, &out[i].link, NULL);
+ }
+ }
+
+ return success;
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index 9a0a132b311..9f93dfd837b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -61,8 +61,6 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[5].link);
}
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
-
if (node->sss_id > 0) {
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
bNodeSocketValueRGBA *socket_data = socket->default_value;
@@ -71,6 +69,10 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
/* For some reason it seems that the socket value is in ARGB format. */
GPU_material_sss_profile_create(
mat, &socket_data->value[1], &node->original->custom1, &socket_data_sharp->value);
+
+ /* sss_id is 0 only the node is not connected to any output.
+ * In this case flagging the material would trigger a bug (see T68736). */
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
}
return GPU_stack_link(
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
index 637aeb3c182..8bb17acc4d3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
@@ -45,14 +45,17 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) :
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
- /* TODO only request orco if needed. */
- GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
+ /* Opti: don't request orco if not needed. */
+ GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant((float[4]){0.0f, 0.0f, 0.0f, 0.0f}) :
+ GPU_attribute(CD_ORCO, "");
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, "");
GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION);
GPUNodeLink *worldnor = GPU_builtin(GPU_WORLD_NORMAL);
GPUNodeLink *texcofacs = GPU_builtin(GPU_CAMERA_TEXCO_FACTORS);
- GPU_link(mat, "generated_from_orco", orco, &orco);
+ if (out[0].hasoutput) {
+ GPU_link(mat, "generated_from_orco", orco, &orco);
+ }
GPU_stack_link(
mat, node, "node_tex_coord", in, out, viewpos, worldnor, inv_obmat, texcofacs, orco, mtface);
@@ -60,6 +63,14 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
/* for each output. */
for (int i = 0; sh_node_tex_coord_out[i].type != -1; i++) {
node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
+ /* Normalize some vectors after dFdx/dFdy offsets.
+ * This is the case for interpolated, non linear functions.
+ * The resulting vector can still be a bit wrong but not as much.
+ * (see T70644) */
+ if (node->branch_tag != 0 && ELEM(i, 1, 6)) {
+ GPU_link(
+ mat, "vector_math_normalize", out[i].link, out[i].link, out[i].link, &out[i].link, NULL);
+ }
}
return 1;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index daf4053f182..56e102a118d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -136,8 +136,8 @@ static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *nod
tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
tex->musgrave_type != SHD_MUSGRAVE_FBM);
nodeSetSocketAvailability(inGainSock,
- tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL &&
- tex->musgrave_type != SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
+ tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL ||
+ tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
}
void register_node_type_sh_tex_musgrave(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
index 73fb022e476..a2e47735490 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
@@ -43,7 +43,11 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
NodeShaderUVMap *attr = node->storage;
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->uv_map);
- return GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
+ GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
+
+ node_shader_gpu_bump_tex_coord(mat, node, &out[0].link);
+
+ return 1;
}
/* node type definition */
diff --git a/source/blender/python/bmesh/bmesh_py_ops.c b/source/blender/python/bmesh/bmesh_py_ops.c
index fd37c8521c1..b6ba119f695 100644
--- a/source/blender/python/bmesh/bmesh_py_ops.c
+++ b/source/blender/python/bmesh/bmesh_py_ops.c
@@ -166,10 +166,10 @@ static PyTypeObject bmesh_op_Type = {
sizeof(BPy_BMeshOpFunc), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- NULL, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_dealloc */
+ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in python 3.0! */
(reprfunc)bpy_bmesh_op_repr, /* tp_repr */
@@ -282,10 +282,10 @@ static PyTypeObject bmesh_ops_fakemod_Type = {
0, /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- NULL, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_dealloc */
+ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in python 3.0! */
NULL, /* tp_repr */
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 23be0d68fb0..1b6466dee68 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -1366,6 +1366,7 @@ BGL_Wrap(GenVertexArrays, void, (GLsizei, GLuintP));
BGL_Wrap(GetStringi, GLstring, (GLenum, GLuint));
BGL_Wrap(IsVertexArray, GLboolean, (GLuint));
BGL_Wrap(RenderbufferStorage, void, (GLenum, GLenum, GLsizei, GLsizei));
+BGL_Wrap(VertexAttribIPointer, void, (GLuint, GLint, GLenum, GLsizei, GLvoidP));
/* GL_VERSION_3_1 */
BGL_Wrap(BindBufferBase, void, (GLenum, GLuint, GLuint));
@@ -1709,6 +1710,7 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(GetStringi);
PY_MOD_ADD_METHOD(IsVertexArray);
PY_MOD_ADD_METHOD(RenderbufferStorage);
+ PY_MOD_ADD_METHOD(VertexAttribIPointer);
}
/* GL_VERSION_3_1 */
diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c
index b90483e89b9..62f5a568ee1 100644
--- a/source/blender/python/generic/blf_py_api.c
+++ b/source/blender/python/generic/blf_py_api.c
@@ -20,6 +20,9 @@
* This file defines the 'bgl' module, used for drawing text in OpenGL.
*/
+/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
+#define PY_SSIZE_T_CLEAN
+
#include <Python.h>
#include "blf_py_api.h"
@@ -176,7 +179,7 @@ PyDoc_STRVAR(py_blf_draw_doc,
static PyObject *py_blf_draw(PyObject *UNUSED(self), PyObject *args)
{
const char *text;
- int text_length;
+ Py_ssize_t text_length;
int fontid;
if (!PyArg_ParseTuple(args, "is#:blf.draw", &fontid, &text, &text_length)) {
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index d10d281c1f9..1ea7795a0e3 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -688,6 +688,7 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
/* Preserve prev/next links!!! See T42593. */
prop->prev = prop_exist->prev;
prop->next = prop_exist->next;
+ prop->flag = prop_exist->flag;
IDP_FreePropertyContent(prop_exist);
*prop_exist = *prop;
@@ -896,7 +897,7 @@ static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *args)
pyform = BPy_IDGroup_MapDataToPy(idprop);
if (pyform == NULL) {
- /* ok something bad happened with the pyobject,
+ /* ok something bad happened with the #PyObject,
* so don't remove the prop from the group. if pyform is
* NULL, then it already should have raised an exception.*/
return NULL;
@@ -1171,7 +1172,7 @@ PyTypeObject BPy_IDGroup_Type = {
/* Methods to implement standard operations */
NULL, /* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* cmpfunc tp_compare; */
@@ -1576,7 +1577,7 @@ PyTypeObject BPy_IDArray_Type = {
/* Methods to implement standard operations */
NULL, /* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* cmpfunc tp_compare; */
@@ -1691,7 +1692,7 @@ PyTypeObject BPy_IDGroup_Iter_Type = {
/* Methods to implement standard operations */
NULL, /* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* cmpfunc tp_compare; */
diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c
index 22be0429ea5..d35fc027f43 100644
--- a/source/blender/python/generic/imbuf_py_api.c
+++ b/source/blender/python/generic/imbuf_py_api.c
@@ -88,21 +88,37 @@ PyDoc_STRVAR(py_imbuf_resize_doc,
"\n"
" :arg size: New size.\n"
" :type size: pair of ints\n"
- " :arg method: Method of resizing (TODO)\n"
+ " :arg method: Method of resizing ('FAST', 'BILINEAR')\n"
" :type method: str\n");
static PyObject *py_imbuf_resize(Py_ImBuf *self, PyObject *args, PyObject *kw)
{
PY_IMBUF_CHECK_OBJ(self);
uint size[2];
- char *method = NULL;
+
+ enum { FAST, BILINEAR };
+ const struct PyC_StringEnumItems method_items[] = {
+ {FAST, "FAST"},
+ {BILINEAR, "BILINEAR"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum method = {method_items, FAST};
static const char *_keywords[] = {"size", "method", NULL};
- static _PyArg_Parser _parser = {"(II)|s:resize", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &size[0], &size[1], &method)) {
+ static _PyArg_Parser _parser = {"(II)|O&:resize", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser, &size[0], &size[1], PyC_ParseStringEnum, &method)) {
return NULL;
}
- IMB_scaleImBuf(self->ibuf, UNPACK2(size));
+ if (method.value_found == FAST) {
+ IMB_scalefastImBuf(self->ibuf, UNPACK2(size));
+ }
+ else if (method.value_found == BILINEAR) {
+ IMB_scaleImBuf(self->ibuf, UNPACK2(size));
+ }
+ else {
+ BLI_assert(0);
+ }
Py_RETURN_NONE;
}
@@ -227,6 +243,51 @@ static int py_imbuf_ppm_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closur
return 0;
}
+PyDoc_STRVAR(py_imbuf_filepath_doc, "filepath associated with this image.\n\n:type: string");
+static PyObject *py_imbuf_filepath_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *ibuf = self->ibuf;
+ return PyC_UnicodeFromByte(ibuf->name);
+}
+
+static int py_imbuf_filepath_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_INT(self);
+
+ if (!PyUnicode_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, "expected a string!");
+ return -1;
+ }
+
+ ImBuf *ibuf = self->ibuf;
+ Py_ssize_t value_str_len_max = sizeof(ibuf->name);
+ Py_ssize_t value_str_len;
+ const char *value_str = _PyUnicode_AsStringAndSize(value, &value_str_len);
+ if (value_str_len >= value_str_len_max) {
+ PyErr_Format(PyExc_TypeError, "filepath length over %zd", value_str_len_max - 1);
+ return -1;
+ }
+ memcpy(ibuf->name, value_str, value_str_len + 1);
+ return 0;
+}
+
+PyDoc_STRVAR(py_imbuf_planes_doc, "Number of bits associated with this image.\n\n:type: int");
+static PyObject *py_imbuf_planes_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *imbuf = self->ibuf;
+ return PyLong_FromLong(imbuf->planes);
+}
+
+PyDoc_STRVAR(py_imbuf_channels_doc, "Number of bit-planes.\n\n:type: int");
+static PyObject *py_imbuf_channels_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *imbuf = self->ibuf;
+ return PyLong_FromLong(imbuf->channels);
+}
+
static PyGetSetDef Py_ImBuf_getseters[] = {
{(char *)"size", (getter)py_imbuf_size_get, (setter)NULL, (char *)py_imbuf_size_doc, NULL},
{(char *)"ppm",
@@ -234,6 +295,13 @@ static PyGetSetDef Py_ImBuf_getseters[] = {
(setter)py_imbuf_ppm_set,
(char *)py_imbuf_ppm_doc,
NULL},
+ {(char *)"filepath",
+ (getter)py_imbuf_filepath_get,
+ (setter)py_imbuf_filepath_set,
+ (char *)py_imbuf_filepath_doc,
+ NULL},
+ {(char *)"planes", (getter)py_imbuf_planes_get, NULL, (char *)py_imbuf_planes_doc, NULL},
+ {(char *)"channels", (getter)py_imbuf_channels_get, NULL, (char *)py_imbuf_channels_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -258,7 +326,7 @@ static PyObject *py_imbuf_repr(Py_ImBuf *self)
const ImBuf *ibuf = self->ibuf;
if (ibuf != NULL) {
return PyUnicode_FromFormat(
- "<imbuf: address=%p, filename='%s', size=(%d, %d)>", ibuf, ibuf->name, ibuf->x, ibuf->y);
+ "<imbuf: address=%p, filepath='%s', size=(%d, %d)>", ibuf, ibuf->name, ibuf->x, ibuf->y);
}
else {
return PyUnicode_FromString("<imbuf: address=0x0>");
@@ -280,7 +348,7 @@ PyTypeObject Py_ImBuf_Type = {
/* Methods to implement standard operations */
(destructor)py_imbuf_dealloc, /* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* cmpfunc tp_compare; */
@@ -375,73 +443,73 @@ static PyObject *M_imbuf_new(PyObject *UNUSED(self), PyObject *args, PyObject *k
}
PyDoc_STRVAR(M_imbuf_load_doc,
- ".. function:: load(filename)\n"
+ ".. function:: load(filepath)\n"
"\n"
" Load an image from a file.\n"
"\n"
- " :arg filename: the filename of the image.\n"
- " :type filename: string\n"
+ " :arg filepath: the filepath of the image.\n"
+ " :type filepath: string\n"
" :return: the newly loaded image.\n"
" :rtype: :class:`ImBuf`\n");
static PyObject *M_imbuf_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *filename;
+ const char *filepath;
- static const char *_keywords[] = {"filename", NULL};
+ static const char *_keywords[] = {"filepath", NULL};
static _PyArg_Parser _parser = {"s:load", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filename)) {
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filepath)) {
return NULL;
}
- const int file = BLI_open(filename, O_BINARY | O_RDONLY, 0);
+ const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
if (file == -1) {
- PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno));
+ PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno), filepath);
return NULL;
}
- ImBuf *ibuf = IMB_loadifffile(file, filename, IB_rect, NULL, filename);
+ ImBuf *ibuf = IMB_loadifffile(file, filepath, IB_rect, NULL, filepath);
close(file);
if (ibuf == NULL) {
PyErr_Format(
- PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filename);
+ PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filepath);
return NULL;
}
- BLI_strncpy(ibuf->name, filename, sizeof(ibuf->name));
+ BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
return Py_ImBuf_CreatePyObject(ibuf);
}
PyDoc_STRVAR(M_imbuf_write_doc,
- ".. function:: write(image, filename)\n"
+ ".. function:: write(image, filepath)\n"
"\n"
" Write an image.\n"
"\n"
" :arg image: the image to write.\n"
" :type image: :class:`ImBuf`\n"
- " :arg filename: the filename of the image.\n"
- " :type filename: string\n");
+ " :arg filepath: the filepath of the image.\n"
+ " :type filepath: string\n");
static PyObject *M_imbuf_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
Py_ImBuf *py_imb;
- const char *filename = NULL;
+ const char *filepath = NULL;
- static const char *_keywords[] = {"image", "filename", NULL};
+ static const char *_keywords[] = {"image", "filepath", NULL};
static _PyArg_Parser _parser = {"O!|s:write", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &Py_ImBuf_Type, &py_imb, &filename)) {
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &Py_ImBuf_Type, &py_imb, &filepath)) {
return NULL;
}
- if (filename == NULL) {
- filename = py_imb->ibuf->name;
+ if (filepath == NULL) {
+ filepath = py_imb->ibuf->name;
}
- bool ok = IMB_saveiff(py_imb->ibuf, filename, IB_rect);
+ bool ok = IMB_saveiff(py_imb->ibuf, filepath, IB_rect);
if (ok == false) {
PyErr_Format(
- PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filename);
+ PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filepath);
return NULL;
}
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index ca9f15ed01a..c4a363e25e5 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -25,6 +25,9 @@
* BLI_string_utf8() for unicode conversion.
*/
+/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
+#define PY_SSIZE_T_CLEAN
+
#include <Python.h>
#include <frameobject.h>
@@ -231,6 +234,37 @@ int PyC_ParseBool(PyObject *o, void *p)
return 1;
}
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ */
+int PyC_ParseStringEnum(PyObject *o, void *p)
+{
+ struct PyC_StringEnum *e = p;
+ const char *value = _PyUnicode_AsString(o);
+ if (value == NULL) {
+ PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name);
+ return 0;
+ }
+ int i;
+ for (i = 0; e->items[i].id; i++) {
+ if (STREQ(e->items[i].id, value)) {
+ e->value_found = e->items[i].value;
+ return 1;
+ }
+ }
+
+ /* Set as a precaution. */
+ e->value_found = -1;
+
+ PyObject *enum_items = PyTuple_New(i);
+ for (i = 0; e->items[i].id; i++) {
+ PyTuple_SET_ITEM(enum_items, i, PyUnicode_FromString(e->items[i].id));
+ }
+ PyErr_Format(PyExc_ValueError, "expected a string in %S, got '%s'", enum_items, value);
+ Py_DECREF(enum_items);
+ return 0;
+}
+
/* silly function, we dont use arg. just check its compatible with __deepcopy__ */
int PyC_CheckArgs_DeepCopy(PyObject *args)
{
@@ -717,9 +751,10 @@ PyObject *PyC_UnicodeFromByte(const char *str)
****************************************************************************/
PyObject *PyC_DefaultNameSpace(const char *filename)
{
- PyInterpreterState *interp = PyThreadState_GET()->interp;
+ PyObject *modules = PyImport_GetModuleDict();
+ PyObject *builtins = PyEval_GetBuiltins();
PyObject *mod_main = PyModule_New("__main__");
- PyDict_SetItemString(interp->modules, "__main__", mod_main);
+ PyDict_SetItemString(modules, "__main__", mod_main);
Py_DECREF(mod_main); /* sys.modules owns now */
PyModule_AddStringConstant(mod_main, "__name__", "__main__");
if (filename) {
@@ -727,8 +762,8 @@ PyObject *PyC_DefaultNameSpace(const char *filename)
* note: this wont map to a real file when executing text-blocks and buttons. */
PyModule_AddObject(mod_main, "__file__", PyC_UnicodeFromByte(filename));
}
- PyModule_AddObject(mod_main, "__builtins__", interp->builtins);
- Py_INCREF(interp->builtins); /* AddObject steals a reference */
+ PyModule_AddObject(mod_main, "__builtins__", builtins);
+ Py_INCREF(builtins); /* AddObject steals a reference */
return PyModule_GetDict(mod_main);
}
@@ -755,15 +790,15 @@ bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[])
/* restore MUST be called after this */
void PyC_MainModule_Backup(PyObject **main_mod)
{
- PyInterpreterState *interp = PyThreadState_GET()->interp;
- *main_mod = PyDict_GetItemString(interp->modules, "__main__");
+ PyObject *modules = PyImport_GetModuleDict();
+ *main_mod = PyDict_GetItemString(modules, "__main__");
Py_XINCREF(*main_mod); /* don't free */
}
void PyC_MainModule_Restore(PyObject *main_mod)
{
- PyInterpreterState *interp = PyThreadState_GET()->interp;
- PyDict_SetItemString(interp->modules, "__main__", main_mod);
+ PyObject *modules = PyImport_GetModuleDict();
+ PyDict_SetItemString(modules, "__main__", main_mod);
Py_XDECREF(main_mod);
}
@@ -836,7 +871,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...)
va_list vargs;
- int *sizes = PyMem_MALLOC(sizeof(int) * (n / 2));
+ Py_ssize_t *sizes = PyMem_MALLOC(sizeof(*sizes) * (n / 2));
int i;
PyObject *py_dict = PyC_DefaultNameSpace(filepath);
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 4454aa11d77..1f552c3d78d 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -126,6 +126,17 @@ bool PyC_RunString_AsString(const char **imports,
int PyC_ParseBool(PyObject *o, void *p);
+struct PyC_StringEnumItems {
+ int value;
+ const char *id;
+};
+struct PyC_StringEnum {
+ const struct PyC_StringEnumItems *items;
+ int value_found;
+};
+
+int PyC_ParseStringEnum(PyObject *o, void *p);
+
int PyC_CheckArgs_DeepCopy(PyObject *args);
/* Integer parsing (with overflow checks), -1 on error. */
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 70f76896898..6505e59624b 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -183,7 +183,7 @@ static PyObject *bpygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args,
PyDoc_STRVAR(
bpygpu_offscreen_draw_view3d_doc,
- ".. method:: draw_view3d(scene, view3d, region, view_matrix, projection_matrix)\n"
+ ".. method:: draw_view3d(scene, view_layer, view3d, region, view_matrix, projection_matrix)\n"
"\n"
" Draw the 3d viewport in the offscreen object.\n"
"\n"
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 8c34699b598..52b35478dd0 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -147,39 +147,28 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
// PyDoc_STRVAR(bpy_user_resource_doc[] = // now in bpy/utils.py
static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *type;
+ const struct PyC_StringEnumItems type_items[] = {
+ {BLENDER_USER_DATAFILES, "DATAFILES"},
+ {BLENDER_USER_CONFIG, "CONFIG"},
+ {BLENDER_USER_SCRIPTS, "SCRIPTS"},
+ {BLENDER_USER_AUTOSAVE, "AUTOSAVE"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum type = {type_items};
+
const char *subdir = NULL;
- int folder_id;
const char *path;
static const char *_keywords[] = {"type", "subdir", NULL};
- static _PyArg_Parser _parser = {"s|s:user_resource", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &subdir)) {
- return NULL;
- }
-
- /* stupid string compare */
- if (STREQ(type, "DATAFILES")) {
- folder_id = BLENDER_USER_DATAFILES;
- }
- else if (STREQ(type, "CONFIG")) {
- folder_id = BLENDER_USER_CONFIG;
- }
- else if (STREQ(type, "SCRIPTS")) {
- folder_id = BLENDER_USER_SCRIPTS;
- }
- else if (STREQ(type, "AUTOSAVE")) {
- folder_id = BLENDER_USER_AUTOSAVE;
- }
- else {
- PyErr_SetString(PyExc_ValueError, "invalid resource argument");
+ static _PyArg_Parser _parser = {"O&|s:user_resource", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, PyC_ParseStringEnum, &type, &subdir)) {
return NULL;
}
/* same logic as BKE_appdir_folder_id_create(),
* but best leave it up to the script author to create */
- path = BKE_appdir_folder_id_user_notest(folder_id, subdir);
+ path = BKE_appdir_folder_id_user_notest(type.value_found, subdir);
return PyC_UnicodeFromByte(path ? path : "");
}
@@ -195,34 +184,25 @@ PyDoc_STRVAR(bpy_system_resource_doc,
" :type path: string\n");
static PyObject *bpy_system_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *type;
+ const struct PyC_StringEnumItems type_items[] = {
+ {BLENDER_SYSTEM_DATAFILES, "DATAFILES"},
+ {BLENDER_SYSTEM_SCRIPTS, "SCRIPTS"},
+ {BLENDER_SYSTEM_PYTHON, "PYTHON"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum type = {type_items};
+
const char *subdir = NULL;
- int folder_id;
const char *path;
static const char *_keywords[] = {"type", "path", NULL};
- static _PyArg_Parser _parser = {"s|s:system_resource", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &subdir)) {
+ static _PyArg_Parser _parser = {"O&|s:system_resource", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, PyC_ParseStringEnum, &type, &subdir)) {
return NULL;
}
- /* stupid string compare */
- if (STREQ(type, "DATAFILES")) {
- folder_id = BLENDER_SYSTEM_DATAFILES;
- }
- else if (STREQ(type, "SCRIPTS")) {
- folder_id = BLENDER_SYSTEM_SCRIPTS;
- }
- else if (STREQ(type, "PYTHON")) {
- folder_id = BLENDER_SYSTEM_PYTHON;
- }
- else {
- PyErr_SetString(PyExc_ValueError, "invalid resource argument");
- return NULL;
- }
-
- path = BKE_appdir_folder_id(folder_id, subdir);
+ path = BKE_appdir_folder_id(type.value_found, subdir);
return PyC_UnicodeFromByte(path ? path : "");
}
@@ -243,33 +223,25 @@ PyDoc_STRVAR(
" :rtype: string\n");
static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- const char *type;
+ const struct PyC_StringEnumItems type_items[] = {
+ {BLENDER_RESOURCE_PATH_USER, "USER"},
+ {BLENDER_RESOURCE_PATH_LOCAL, "LOCAL"},
+ {BLENDER_RESOURCE_PATH_SYSTEM, "SYSTEM"},
+ {0, NULL},
+ };
+ struct PyC_StringEnum type = {type_items};
+
int major = BLENDER_VERSION / 100, minor = BLENDER_VERSION % 100;
- int folder_id;
const char *path;
static const char *_keywords[] = {"type", "major", "minor", NULL};
- static _PyArg_Parser _parser = {"s|ii:resource_path", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &major, &minor)) {
- return NULL;
- }
-
- /* stupid string compare */
- if (STREQ(type, "USER")) {
- folder_id = BLENDER_RESOURCE_PATH_USER;
- }
- else if (STREQ(type, "LOCAL")) {
- folder_id = BLENDER_RESOURCE_PATH_LOCAL;
- }
- else if (STREQ(type, "SYSTEM")) {
- folder_id = BLENDER_RESOURCE_PATH_SYSTEM;
- }
- else {
- PyErr_SetString(PyExc_ValueError, "invalid resource argument");
+ static _PyArg_Parser _parser = {"O&|ii:resource_path", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser, PyC_ParseStringEnum, &type, &major, &minor)) {
return NULL;
}
- path = BKE_appdir_folder_id_version(folder_id, (major * 100) + minor, false);
+ path = BKE_appdir_folder_id_version(type.value_found, (major * 100) + minor, false);
return PyC_UnicodeFromByte(path ? path : "");
}
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index 3c1dbfba72e..fffa43c1dcd 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -780,10 +780,10 @@ static PyTypeObject BlenderAppTranslationsType = {
0, /* tp_itemsize */
/* methods */
/* No destructor, this is a singleton! */
- NULL, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_dealloc */
+ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in python 3.0! */
NULL, /* tp_repr */
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 5ea16c8c197..b797624f23c 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -92,7 +92,7 @@ static PyTypeObject bpy_lib_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)bpy_lib_dealloc, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL,
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 6b63d1ef2c3..4fd81a707fb 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -22,6 +22,9 @@
* existing blender types.
*/
+/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
+#define PY_SSIZE_T_CLEAN
+
#include <Python.h>
#include "RNA_types.h"
@@ -2101,7 +2104,7 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
if (srna) {
const char *id = NULL, *name = NULL, *description = "";
- int id_len;
+ Py_ssize_t id_len;
bool def = false;
PropertyRNA *prop;
PyObject *pyopts = NULL;
@@ -2204,7 +2207,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
if (srna) {
const char *id = NULL, *name = NULL, *description = "";
- int id_len;
+ Py_ssize_t id_len;
bool def[PYRNA_STACK_ARRAY] = {0};
int size = 3;
PropertyRNA *prop;
@@ -2336,7 +2339,7 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
if (srna) {
const char *id = NULL, *name = NULL, *description = "";
- int id_len;
+ Py_ssize_t id_len;
int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1, def = 0;
PropertyRNA *prop;
PyObject *pyopts = NULL;
@@ -2456,7 +2459,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
if (srna) {
const char *id = NULL, *name = NULL, *description = "";
- int id_len;
+ Py_ssize_t id_len;
int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1;
int def[PYRNA_STACK_ARRAY] = {0};
int size = 3;
@@ -2599,7 +2602,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
if (srna) {
const char *id = NULL, *name = NULL, *description = "";
- int id_len;
+ Py_ssize_t id_len;
float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3,
def = 0.0f;
int precision = 2;
@@ -2735,7 +2738,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
if (srna) {
const char *id = NULL, *name = NULL, *description = "";
- int id_len;
+ Py_ssize_t id_len;
float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3;
float def[PYRNA_STACK_ARRAY] = {0.0f};
int precision = 2, size = 3;
@@ -2869,7 +2872,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
if (srna) {
const char *id = NULL, *name = NULL, *description = "", *def = "";
- int id_len;
+ Py_ssize_t id_len;
int maxlen = 0;
PropertyRNA *prop;
PyObject *pyopts = NULL;
@@ -3015,7 +3018,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
if (srna) {
const char *id = NULL, *name = NULL, *description = "";
PyObject *def = NULL;
- int id_len;
+ Py_ssize_t id_len;
int defvalue = 0;
PyObject *items, *items_fast;
const EnumPropertyItem *eitems;
@@ -3191,7 +3194,7 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
if (srna) {
const char *id = NULL, *name = NULL, *description = "";
- int id_len;
+ Py_ssize_t id_len;
PropertyRNA *prop;
StructRNA *ptype;
PyObject *type = Py_None;
@@ -3286,7 +3289,7 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_HEAD(CollectionProperty);
if (srna) {
- int id_len;
+ Py_ssize_t id_len;
const char *id = NULL, *name = NULL, *description = "";
PropertyRNA *prop;
StructRNA *ptype;
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index c5424ca6ffb..570c5012ed8 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -70,6 +70,8 @@
/* Only for types. */
#include "BKE_node.h"
+#include "DEG_depsgraph_query.h"
+
#include "../generic/idprop_py_api.h" /* For IDprop lookups. */
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
@@ -918,7 +920,10 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self)
tmp_str = PyUnicode_FromString(id->name + 2);
- if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) {
+ if (DEG_get_original_id(id) != id) {
+ ret = PyUnicode_FromFormat("Evaluated %s %R", BKE_idcode_to_name(GS(id->name)), tmp_str);
+ }
+ else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) {
ret = PyUnicode_FromFormat(
"bpy.data.%s[%R]", BKE_idcode_to_name_plural(GS(id->name)), tmp_str);
}
@@ -926,14 +931,25 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self)
const char *path;
ID *real_id = NULL;
path = RNA_path_from_real_ID_to_struct(G_MAIN, &self->ptr, &real_id);
- if (path) {
- if (real_id != id) {
+ if (path != NULL) {
+ /* 'real_id' may be NULL in some cases, although the only valid one is evaluated data,
+ * which should have already been caught above.
+ * So assert, but handle it without crashing for release builds. */
+ BLI_assert(real_id != NULL);
+
+ if (real_id != NULL) {
Py_DECREF(tmp_str);
tmp_str = PyUnicode_FromString(real_id->name + 2);
+ ret = PyUnicode_FromFormat(
+ "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(real_id->name)), tmp_str, path);
+ }
+ else {
+ /* Can't find the path, print something useful as a fallback. */
+ ret = PyUnicode_FromFormat("bpy.data.%s[%R]...%s",
+ BKE_idcode_to_name_plural(GS(id->name)),
+ tmp_str,
+ RNA_struct_identifier(self->ptr.type));
}
- ret = PyUnicode_FromFormat(
- "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(real_id->name)), tmp_str, path);
-
MEM_freeN((void *)path);
}
else {
@@ -1928,7 +1944,7 @@ static int pyrna_py_to_prop(
* layout.prop(self.properties, "filepath")
*
* we need to do this trick.
- * if the prop is not an operator type and the pyobject is an operator,
+ * if the prop is not an operator type and the PyObject is an operator,
* use its properties in place of itself.
*
* This is so bad that it is almost a good reason to do away with fake
@@ -3710,9 +3726,9 @@ static PyObject *pyrna_struct_is_property_readonly(BPy_StructRNA *self, PyObject
PyDoc_STRVAR(pyrna_struct_is_property_overridable_library_doc,
".. method:: is_property_overridable_library(property)\n"
"\n"
- " Check if a property is statically overridable.\n"
+ " Check if a property is overridable.\n"
"\n"
- " :return: True when the property is statically overridable.\n"
+ " :return: True when the property is overridable.\n"
" :rtype: boolean\n");
static PyObject *pyrna_struct_is_property_overridable_library(BPy_StructRNA *self, PyObject *args)
{
@@ -3736,14 +3752,13 @@ static PyObject *pyrna_struct_is_property_overridable_library(BPy_StructRNA *sel
return PyBool_FromLong((long)RNA_property_overridable_get(&self->ptr, prop));
}
-PyDoc_STRVAR(
- pyrna_struct_property_overridable_library_set_doc,
- ".. method:: property_overridable_library_set(property)\n"
- "\n"
- " Define a property as statically overridable or not (only for custom properties!).\n"
- "\n"
- " :return: True when the overridable status of the property was successfully set.\n"
- " :rtype: boolean\n");
+PyDoc_STRVAR(pyrna_struct_property_overridable_library_set_doc,
+ ".. method:: property_overridable_library_set(property, overridable)\n"
+ "\n"
+ " Define a property as overridable or not (only for custom properties!).\n"
+ "\n"
+ " :return: True when the overridable status of the property was successfully set.\n"
+ " :rtype: boolean\n");
static PyObject *pyrna_struct_property_overridable_library_set(BPy_StructRNA *self, PyObject *args)
{
PropertyRNA *prop;
@@ -3986,7 +4001,7 @@ static PyObject *pyrna_struct_type_recast(BPy_StructRNA *self)
}
/**
- * \note Return value is borrowed, caller must incref.
+ * \note Return value is borrowed, caller must #Py_INCREF.
*/
static PyObject *pyrna_struct_bl_rna_find_subclass_recursive(PyObject *cls, const char *id)
{
@@ -6222,10 +6237,10 @@ PyTypeObject pyrna_struct_meta_idprop_Type = {
0, /* tp_itemsize */
/* methods */
- NULL, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_dealloc */
+ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* deprecated in Python 3.0! */
NULL, /* tp_repr */
@@ -6304,7 +6319,7 @@ PyTypeObject pyrna_struct_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_struct_dealloc, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL,
@@ -6393,7 +6408,7 @@ PyTypeObject pyrna_prop_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_dealloc, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL,
@@ -6477,7 +6492,7 @@ PyTypeObject pyrna_prop_array_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_array_dealloc, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL,
@@ -6560,7 +6575,7 @@ PyTypeObject pyrna_prop_collection_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_dealloc, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL,
@@ -6646,7 +6661,7 @@ static PyTypeObject pyrna_prop_collection_idprop_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_dealloc, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL,
@@ -6731,10 +6746,10 @@ PyTypeObject pyrna_func_Type = {
sizeof(BPy_FunctionRNA), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- NULL, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_dealloc */
+ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in Python 3.0! */
(reprfunc)pyrna_func_repr, /* tp_repr */
@@ -6828,7 +6843,7 @@ static PyTypeObject pyrna_prop_collection_iter_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_collection_iter_dealloc, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL,
@@ -7193,7 +7208,7 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna)
#endif
/* Newclass will now have 2 ref's, ???,
- * probably 1 is internal since decrefing here segfaults. */
+ * probably 1 is internal since #Py_DECREF here segfaults. */
/* PyC_ObSpit("new class ref", newclass); */
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 5e535d0e3ce..8aa6aa91fcf 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -277,7 +277,7 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr,
char pyrna_struct_keyframe_insert_doc[] =
".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, "
- "group=\"\")\n"
+ "group=\"\", options=set())\n"
"\n"
" Insert a keyframe on the property given, adding fcurves and animation data when "
"necessary.\n"
@@ -294,7 +294,7 @@ char pyrna_struct_keyframe_insert_doc[] =
" :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
"yet.\n"
" :type group: str\n"
- " :arg options: Optional flags:\n"
+ " :arg options: Optional set of flags:\n"
"\n"
" - ``INSERTKEY_NEEDED`` Only insert keyframes where they're needed in the relevant "
"F-Curves.\n"
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index 4e21a8e0389..b587738c8d7 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -921,7 +921,7 @@ PyTypeObject color_Type = {
sizeof(ColorObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)BaseMathObject_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
+ (printfunc)NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 56662465b52..3fd9bf666e2 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -750,7 +750,7 @@ PyTypeObject euler_Type = {
sizeof(EulerObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)BaseMathObject_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
+ (printfunc)NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 6fd0fab2cdd..c6e6d395b6b 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -3141,7 +3141,7 @@ PyTypeObject matrix_Type = {
sizeof(MatrixObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)BaseMathObject_dealloc, /*tp_dealloc*/
- NULL, /*tp_print*/
+ (printfunc)NULL, /*tp_print*/
NULL, /*tp_getattr*/
NULL, /*tp_setattr*/
NULL, /*tp_compare*/
@@ -3532,7 +3532,7 @@ PyTypeObject matrix_access_Type = {
sizeof(MatrixAccessObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)MatrixAccess_dealloc, /*tp_dealloc*/
- NULL, /*tp_print*/
+ (printfunc)NULL, /*tp_print*/
NULL, /*tp_getattr*/
NULL, /*tp_setattr*/
NULL, /*tp_compare*/
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 267971408bf..0de1ffb9879 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -176,6 +176,50 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self)
return ret;
}
+PyDoc_STRVAR(Quaternion_to_swing_twist_doc,
+ ".. method:: to_swing_twist(axis)\n"
+ "\n"
+ " Split the rotation into a swing quaternion with the specified\n"
+ "axis fixed at zero, and the remaining twist rotation angle.\n"
+ "\n"
+ " :arg axis: twist axis as a string in ['X', 'Y', 'Z']\n"
+ " :return: swing, twist angle.\n"
+ " :rtype: (:class:`Quaternion`, float) pair\n");
+static PyObject *Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axis_arg)
+{
+ PyObject *ret;
+
+ const char *axis_str = NULL;
+ float swing[4], twist;
+ int axis;
+
+ if (axis_arg && PyUnicode_Check(axis_arg)) {
+ axis_str = _PyUnicode_AsString(axis_arg);
+ }
+
+ if (axis_str && axis_str[0] >= 'X' && axis_str[0] <= 'Z' && axis_str[1] == 0) {
+ axis = axis_str[0] - 'X';
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "Quaternion.to_swing_twist(): "
+ "the axis agrument must be "
+ "a string in 'X', 'Y', 'Z'");
+ return NULL;
+ }
+
+ if (BaseMath_ReadCallback(self) == -1) {
+ return NULL;
+ }
+
+ twist = quat_split_swing_and_twist(self->quat, axis, swing, NULL);
+
+ ret = PyTuple_New(2);
+ PyTuple_SET_ITEMS(
+ ret, Quaternion_CreatePyObject(swing, Py_TYPE(self)), PyFloat_FromDouble(twist));
+ return ret;
+}
+
PyDoc_STRVAR(
Quaternion_to_exponential_map_doc,
".. method:: to_exponential_map()\n"
@@ -1368,6 +1412,10 @@ static struct PyMethodDef Quaternion_methods[] = {
(PyCFunction)Quaternion_to_axis_angle,
METH_NOARGS,
Quaternion_to_axis_angle_doc},
+ {"to_swing_twist",
+ (PyCFunction)Quaternion_to_swing_twist,
+ METH_O,
+ Quaternion_to_swing_twist_doc},
{"to_exponential_map",
(PyCFunction)Quaternion_to_exponential_map,
METH_NOARGS,
@@ -1479,7 +1527,7 @@ PyTypeObject quaternion_Type = {
sizeof(QuaternionObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)BaseMathObject_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
+ (printfunc)NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index aa7cbadde14..387e560d946 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -691,7 +691,8 @@ PyDoc_STRVAR(Vector_to_track_quat_doc,
static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args)
{
float vec[3], quat[4];
- const char *strack, *sup;
+ const char *strack = NULL;
+ const char *sup = NULL;
short track = 2, up = 1;
if (!PyArg_ParseTuple(args, "|ss:to_track_quat", &strack, &sup)) {
@@ -2350,26 +2351,26 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos
*
* axis_dict = {}
* axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3}
- * axises = 'xyzw'
- * while len(axises) >= 2:
- * for axis_0 in axises:
+ * axis_chars = 'xyzw'
+ * while len(axis_chars) >= 2:
+ * for axis_0 in axis_chars:
* axis_0_pos = axis_pos[axis_0]
- * for axis_1 in axises:
+ * for axis_1 in axis_chars:
* axis_1_pos = axis_pos[axis_1]
* axis_dict[axis_0 + axis_1] = (
* '((%s | SWIZZLE_VALID_AXIS) | '
* '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' %
* (axis_0_pos, axis_1_pos))
- * if len(axises) > 2:
- * for axis_2 in axises:
+ * if len(axis_chars) > 2:
+ * for axis_2 in axis_chars:
* axis_2_pos = axis_pos[axis_2]
* axis_dict[axis_0 + axis_1 + axis_2] = (
* '((%s | SWIZZLE_VALID_AXIS) | '
* '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | '
* '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' %
* (axis_0_pos, axis_1_pos, axis_2_pos))
- * if len(axises) > 3:
- * for axis_3 in axises:
+ * if len(axis_chars) > 3:
+ * for axis_3 in axis_chars:
* axis_3_pos = axis_pos[axis_3]
* axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = (
* '((%s | SWIZZLE_VALID_AXIS) | '
@@ -2379,7 +2380,7 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos
* %
* (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos))
*
- * axises = axises[:-1]
+ * axis_chars = axis_chars[:-1]
* items = list(axis_dict.items())
* items.sort(
* key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')
@@ -3054,7 +3055,7 @@ PyTypeObject vector_Type = {
/* Methods to implement standard operations */
(destructor)BaseMathObject_dealloc, /* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
+ (printfunc)NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* cmpfunc tp_compare; */
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c
index 254177b14fe..d28b9a0de8f 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -1267,7 +1267,7 @@ PyTypeObject PyBVHTree_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)py_bvhtree__tp_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
+ (printfunc)NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 13d36e5af91..9a519abd49f 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -1201,8 +1201,8 @@ static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject
PyDoc_STRVAR(M_Geometry_tessellate_polygon_doc,
".. function:: tessellate_polygon(veclist_list)\n"
"\n"
- " Takes a list of polylines (each point a vector) and returns the point indices "
- "for a polyline filled with triangles.\n"
+ " Takes a list of polylines (each point a pair or triplet of numbers) and returns "
+ "the point indices for a polyline filled with triangles.\n"
"\n"
" :arg veclist_list: list of polylines\n"
" :rtype: list\n");
@@ -1211,13 +1211,15 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
{
PyObject *tri_list; /*return this list of tri's */
PyObject *polyLine, *polyVec;
- int i, len_polylines, len_polypoints, ls_error = 0;
+ int i, len_polylines, len_polypoints;
+ bool list_parse_error = false;
+ bool is_2d = true;
/* Display #ListBase. */
ListBase dispbase = {NULL, NULL};
DispList *dl;
float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */
- int index, *dl_face, totpoints = 0;
+ int totpoints = 0;
if (!PySequence_Check(polyLineSeq)) {
PyErr_SetString(PyExc_TypeError, "expected a sequence of poly lines");
@@ -1238,15 +1240,6 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
len_polypoints = PySequence_Size(polyLine);
if (len_polypoints > 0) { /* don't bother adding edges as polylines */
-# if 0
- if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) {
- freedisplist(&dispbase);
- Py_DECREF(polyLine);
- PyErr_SetString(PyExc_TypeError,
- "A point in one of the polylines is not a mathutils.Vector type");
- return NULL;
- }
-# endif
dl = MEM_callocN(sizeof(DispList), "poly disp");
BLI_addtail(&dispbase, dl);
dl->type = DL_INDEX3;
@@ -1254,49 +1247,38 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
dl->type = DL_POLY;
dl->parts = 1; /* no faces, 1 edge loop */
dl->col = 0; /* no material */
- dl->verts = fp = MEM_callocN(sizeof(float) * 3 * len_polypoints, "dl verts");
- dl->index = MEM_callocN(sizeof(int) * 3 * len_polypoints, "dl index");
+ dl->verts = fp = MEM_mallocN(sizeof(float[3]) * len_polypoints, "dl verts");
+ dl->index = MEM_callocN(sizeof(int[3]) * len_polypoints, "dl index");
- for (index = 0; index < len_polypoints; index++, fp += 3) {
+ for (int index = 0; index < len_polypoints; index++, fp += 3) {
polyVec = PySequence_GetItem(polyLine, index);
- if (VectorObject_Check(polyVec)) {
-
- if (BaseMath_ReadCallback((VectorObject *)polyVec) == -1) {
- ls_error = 1;
- }
+ const int polyVec_len = mathutils_array_parse(
+ fp, 2, 3 | MU_ARRAY_SPILL, polyVec, "tessellate_polygon: parse coord");
+ Py_DECREF(polyVec);
- fp[0] = ((VectorObject *)polyVec)->vec[0];
- fp[1] = ((VectorObject *)polyVec)->vec[1];
- if (((VectorObject *)polyVec)->size > 2) {
- fp[2] = ((VectorObject *)polyVec)->vec[2];
- }
- else {
- /* if its a 2d vector then set the z to be zero */
- fp[2] = 0.0f;
- }
+ if (UNLIKELY(polyVec_len == -1)) {
+ list_parse_error = true;
}
- else {
- ls_error = 1;
+ else if (polyVec_len == 2) {
+ fp[2] = 0.0f;
+ }
+ else if (polyVec_len == 3) {
+ is_2d = false;
}
totpoints++;
- Py_DECREF(polyVec);
}
}
Py_DECREF(polyLine);
}
- if (ls_error) {
+ if (list_parse_error) {
BKE_displist_free(&dispbase); /* possible some dl was allocated */
- PyErr_SetString(PyExc_TypeError,
- "A point in one of the polylines "
- "is not a mathutils.Vector type");
return NULL;
}
else if (totpoints) {
/* now make the list to return */
- /* TODO, add normal arg */
- BKE_displist_fill(&dispbase, &dispbase, NULL, false);
+ BKE_displist_fill(&dispbase, &dispbase, is_2d ? ((const float[3]){0, 0, -1}) : NULL, false);
/* The faces are stored in a new DisplayList
* that's added to the head of the #ListBase. */
@@ -1309,12 +1291,10 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
return NULL;
}
- index = 0;
- dl_face = dl->index;
- while (index < dl->parts) {
+ int *dl_face = dl->index;
+ for (int index = 0; index < dl->parts; index++) {
PyList_SET_ITEM(tri_list, index, PyC_Tuple_Pack_I32(dl_face[0], dl_face[1], dl_face[2]));
dl_face += 3;
- index++;
}
BKE_displist_free(&dispbase);
}
diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c
index b8a7f4d8708..e3f2cd9bd14 100644
--- a/source/blender/python/mathutils/mathutils_kdtree.c
+++ b/source/blender/python/mathutils/mathutils_kdtree.c
@@ -393,7 +393,7 @@ PyTypeObject PyKDTree_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)PyKDTree__tp_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
+ (printfunc)NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
@@ -436,7 +436,7 @@ PyTypeObject PyKDTree_Type = {
(destructor)NULL, /* tp_del */
};
-PyDoc_STRVAR(py_kdtree_doc, "Generic 3-dimentional kd-tree to perform spatial searches.");
+PyDoc_STRVAR(py_kdtree_doc, "Generic 3-dimensional kd-tree to perform spatial searches.");
static struct PyModuleDef kdtree_moduledef = {
PyModuleDef_HEAD_INIT,
"mathutils.kdtree", /* m_name */
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index fdb90a6e91e..c3125cb72a1 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -2506,6 +2506,10 @@ void RE_RenderAnim(Render *re,
int efra,
int tfra)
{
+ /* Call hooks before taking a copy of scene->r, so user can alter the render settings prior to
+ * copying (e.g. alter the output path). */
+ render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
+
const RenderData rd = scene->r;
bMovieHandle *mh = NULL;
const int cfrao = rd.cfra;
@@ -2515,8 +2519,6 @@ void RE_RenderAnim(Render *re,
const bool is_multiview_name = ((rd.scemode & R_MULTIVIEW) != 0 &&
(rd.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL));
- render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
-
/* do not fully call for each frame, it initializes & pops output window */
if (!render_initialize_from_main(re, &rd, bmain, scene, single_layer, camera_override, 0, 1)) {
return;
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index cb33492763a..c99f5d4075f 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -832,7 +832,7 @@ void RE_point_density_cache(struct Depsgraph *depsgraph, PointDensity *pd)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
- /* Same matricies/resolution as dupli_render_particle_set(). */
+ /* Same matrices/resolution as dupli_render_particle_set(). */
BLI_mutex_lock(&sample_mutex);
cache_pointdensity(depsgraph, scene, pd);
BLI_mutex_unlock(&sample_mutex);
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index ddd0ddb46da..59f99a9ff88 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -68,6 +68,7 @@ set(SRC
intern/wm_operator_type.c
intern/wm_operators.c
intern/wm_panel_type.c
+ intern/wm_platform_support.c
intern/wm_playanim.c
intern/wm_splash_screen.c
intern/wm_stereo.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 455a30b6ff5..f8b6b5171da 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -102,6 +102,8 @@ void WM_init_opengl(struct Main *bmain);
void WM_check(struct bContext *C);
void WM_reinit_gizmomap_all(struct Main *bmain);
+void WM_script_tag_reload(void);
+
uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]);
int WM_window_pixels_x(const struct wmWindow *win);
@@ -153,18 +155,15 @@ void WM_opengl_context_dispose(void *context);
void WM_opengl_context_activate(void *context);
void WM_opengl_context_release(void *context);
-/* defines for 'type' WM_window_open_temp */
-enum {
- WM_WINDOW_RENDER = 1,
- WM_WINDOW_USERPREFS,
- WM_WINDOW_DRIVERS,
- WM_WINDOW_INFO,
- WM_WINDOW_FILESEL,
-};
-
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
-struct wmWindow *WM_window_open_temp(
- struct bContext *C, int x, int y, int sizex, int sizey, int type);
+struct wmWindow *WM_window_open_temp(struct bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ int space_type,
+ bool dialog);
void WM_window_set_dpi(wmWindow *win);
bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test);
@@ -336,6 +335,12 @@ void WM_event_timer_sleep(struct wmWindowManager *wm,
/* operator api, default callbacks */
/* invoke callback, uses enum property named "type" */
+int WM_generic_select_modal(struct bContext *C,
+ struct wmOperator *op,
+ const struct wmEvent *event);
+int WM_generic_select_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const struct wmEvent *event);
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op);
int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext);
@@ -475,6 +480,7 @@ void WM_operator_properties_select_random(struct wmOperatorType *ot);
int WM_operator_properties_select_random_seed_increment_get(wmOperator *op);
void WM_operator_properties_select_operation(struct wmOperatorType *ot);
void WM_operator_properties_select_operation_simple(struct wmOperatorType *ot);
+void WM_operator_properties_generic_select(struct wmOperatorType *ot);
struct CheckerIntervalParams {
int nth; /* bypass when set to zero */
int skip;
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 5ecd3191bfb..15ad8cbedc4 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -776,7 +776,7 @@ typedef struct wmOperatorType {
} wmOperatorType;
/**
- * Wrapper to reference a wmOperatorType together with some set properties and othere relevant
+ * Wrapper to reference a #wmOperatorType together with some set properties and other relevant
* information to invoke the operator in a customizable way.
*/
typedef struct wmOperatorCallParams {
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 2313383fe6e..8e796a7981a 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -45,35 +45,90 @@
#include "wm_cursors.h"
#include "wm_window.h"
-/* XXX this still is mess from old code */
+/* Blender custom cursor. */
+typedef struct BCursor {
+ char *small_bm;
+ char *small_mask;
-/* Some simple ghost <-> blender conversions */
-static GHOST_TStandardCursor convert_cursor(int curs)
+ char small_sizex;
+ char small_sizey;
+ char small_hotx;
+ char small_hoty;
+
+ char *big_bm;
+ char *big_mask;
+
+ char big_sizex;
+ char big_sizey;
+ char big_hotx;
+ char big_hoty;
+
+ bool can_invert_color;
+} BCursor;
+
+static BCursor *BlenderCursor[WM_CURSOR_NUM] = {0};
+
+/* Blender cursor to GHOST standard cursor conversion. */
+static GHOST_TStandardCursor convert_to_ghost_standard_cursor(WMCursorType curs)
{
switch (curs) {
- default:
- case CURSOR_STD:
+ case WM_CURSOR_DEFAULT:
return GHOST_kStandardCursorDefault;
- case CURSOR_FACESEL:
- return GHOST_kStandardCursorRightArrow;
- case CURSOR_WAIT:
+ case WM_CURSOR_WAIT:
return GHOST_kStandardCursorWait;
- case CURSOR_EDIT:
+ case WM_CURSOR_EDIT:
+ case WM_CURSOR_CROSS:
return GHOST_kStandardCursorCrosshair;
- case CURSOR_HELP:
-#ifdef __APPLE__
- return GHOST_kStandardCursorLeftRight;
-#else
- return GHOST_kStandardCursorHelp;
-#endif
- case CURSOR_X_MOVE:
+ case WM_CURSOR_X_MOVE:
return GHOST_kStandardCursorLeftRight;
- case CURSOR_Y_MOVE:
+ case WM_CURSOR_Y_MOVE:
return GHOST_kStandardCursorUpDown;
- case CURSOR_PENCIL:
- return GHOST_kStandardCursorPencil;
- case CURSOR_COPY:
+ case WM_CURSOR_COPY:
return GHOST_kStandardCursorCopy;
+ case WM_CURSOR_HAND:
+ return GHOST_kStandardCursorMove;
+ case WM_CURSOR_H_SPLIT:
+ return GHOST_kStandardCursorHorizontalSplit;
+ case WM_CURSOR_V_SPLIT:
+ return GHOST_kStandardCursorVerticalSplit;
+ case WM_CURSOR_STOP:
+ return GHOST_kStandardCursorStop;
+ case WM_CURSOR_KNIFE:
+ return GHOST_kStandardCursorKnife;
+ case WM_CURSOR_NSEW_SCROLL:
+ return GHOST_kStandardCursorNSEWScroll;
+ case WM_CURSOR_NS_SCROLL:
+ return GHOST_kStandardCursorNSScroll;
+ case WM_CURSOR_EW_SCROLL:
+ return GHOST_kStandardCursorEWScroll;
+ case WM_CURSOR_EYEDROPPER:
+ return GHOST_kStandardCursorEyedropper;
+ case WM_CURSOR_N_ARROW:
+ return GHOST_kStandardCursorUpArrow;
+ case WM_CURSOR_S_ARROW:
+ return GHOST_kStandardCursorDownArrow;
+ case WM_CURSOR_PAINT:
+ return GHOST_kStandardCursorCrosshairA;
+ case WM_CURSOR_DOT:
+ return GHOST_kStandardCursorCrosshairB;
+ case WM_CURSOR_CROSSC:
+ return GHOST_kStandardCursorCrosshairC;
+ case WM_CURSOR_ERASER:
+ return GHOST_kStandardCursorEraser;
+ case WM_CURSOR_ZOOM_IN:
+ return GHOST_kStandardCursorZoomIn;
+ case WM_CURSOR_ZOOM_OUT:
+ return GHOST_kStandardCursorZoomOut;
+ case WM_CURSOR_TEXT_EDIT:
+ return GHOST_kStandardCursorText;
+ case WM_CURSOR_PAINT_BRUSH:
+ return GHOST_kStandardCursorPencil;
+ case WM_CURSOR_E_ARROW:
+ return GHOST_kStandardCursorRightArrow;
+ case WM_CURSOR_W_ARROW:
+ return GHOST_kStandardCursorLeftArrow;
+ default:
+ return GHOST_kStandardCursorCustom;
}
}
@@ -87,9 +142,9 @@ static void window_set_custom_cursor(wmWindow *win,
win->ghostwin, (GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask, 16, 16, hotx, hoty, true);
}
-static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useBig)
+static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor)
{
- if (useBig) {
+ if (U.curssize && cursor->big_bm) {
GHOST_SetCustomCursorShape(win->ghostwin,
(GHOST_TUns8 *)cursor->big_bm,
(GHOST_TUns8 *)cursor->big_mask,
@@ -111,60 +166,55 @@ static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useB
}
}
-/* Cursor Globals */
-static BCursor *BlenderCursor[BC_NUMCURSORS]; /*Points to static BCursor Structs */
-
void WM_cursor_set(wmWindow *win, int curs)
{
-
if (win == NULL || G.background) {
return; /* Can't set custom cursor before Window init */
}
- if (curs == CURSOR_NONE) {
+ if (curs == WM_CURSOR_NONE) {
GHOST_SetCursorVisibility(win->ghostwin, 0);
return;
}
-#ifdef _WIN32
- /* the default win32 cross cursor is barely visible,
- * only 1 pixel thick, use another one instead */
- if (curs == CURSOR_EDIT) {
- curs = BC_CROSSCURSOR;
- }
-#else
- /* in case of large cursor, also use custom cursor because
- * large cursors don't work for system cursors */
- if (U.curssize && curs == CURSOR_EDIT) {
- curs = BC_CROSSCURSOR;
- }
-#endif
-
GHOST_SetCursorVisibility(win->ghostwin, 1);
- if (curs == CURSOR_STD && win->modalcursor) {
+ if (curs == WM_CURSOR_DEFAULT && win->modalcursor) {
curs = win->modalcursor;
}
win->cursor = curs;
- /* detect if we use system cursor or Blender cursor */
- if (curs >= BC_GHOST_CURSORS) {
- GHOST_SetCursorShape(win->ghostwin, convert_cursor(curs));
+ if (curs < 0 || curs >= WM_CURSOR_NUM) {
+ BLI_assert(!"Invalid cursor number");
+ return;
}
- else {
- if ((curs < SYSCURSOR) || (curs >= BC_NUMCURSORS)) {
- return;
- }
- if (curs == SYSCURSOR) { /* System default Cursor */
- GHOST_SetCursorShape(win->ghostwin, convert_cursor(CURSOR_STD));
- }
- else if ((U.curssize == 0) || (BlenderCursor[curs]->big_bm == NULL)) {
- window_set_custom_cursor_ex(win, BlenderCursor[curs], 0);
+ GHOST_TStandardCursor ghost_cursor = convert_to_ghost_standard_cursor(curs);
+
+#if !defined(_WIN32) && !defined(__APPLE__)
+ /* Workaround crosshair cursors with bad visibility in some cursor themes.
+ * Better solution would be to always use custom cursors and support DPI
+ * properly so that the cursors look as good as the native ones. */
+ if (U.curssize && ghost_cursor == GHOST_kStandardCursorCrosshair) {
+ ghost_cursor = GHOST_kStandardCursorCustom;
+ }
+#endif
+
+ if (ghost_cursor != GHOST_kStandardCursorCustom &&
+ GHOST_HasCursorShape(win->ghostwin, ghost_cursor)) {
+ /* Use native GHOST cursor when available. */
+ GHOST_SetCursorShape(win->ghostwin, ghost_cursor);
+ }
+ else {
+ BCursor *bcursor = BlenderCursor[curs];
+ if (bcursor) {
+ /* Use custom bitmap cursor. */
+ window_set_custom_cursor_ex(win, bcursor);
}
else {
- window_set_custom_cursor_ex(win, BlenderCursor[curs], 1);
+ /* Fallback to default cursor if no bitmap found. */
+ GHOST_SetCursorShape(win->ghostwin, GHOST_kStandardCursorDefault);
}
}
}
@@ -176,7 +226,7 @@ bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const AReg
}
bToolRef_Runtime *tref_rt = (sa && sa->runtime.tool) ? sa->runtime.tool->runtime : NULL;
- if (tref_rt && tref_rt->cursor != CURSOR_STD) {
+ if (tref_rt && tref_rt->cursor != WM_CURSOR_DEFAULT) {
if (win->modalcursor == 0) {
WM_cursor_set(win, tref_rt->cursor);
win->cursor = tref_rt->cursor;
@@ -213,7 +263,7 @@ void WM_cursor_wait(bool val)
for (; win; win = win->next) {
if (val) {
- WM_cursor_modal_set(win, BC_WAITCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_WAIT);
}
else {
WM_cursor_modal_restore(win);
@@ -410,15 +460,39 @@ void wm_init_cursor_data(void)
/********************** NW_ARROW Cursor **************************/
BEGIN_CURSOR_BLOCK;
static char nw_sbm[] = {
- 0x03, 0x00, 0x05, 0x00, 0x09, 0x00, 0x11, 0x00, 0x21, 0x00, 0x41,
- 0x00, 0x81, 0x00, 0x01, 0x01, 0x01, 0x02, 0xc1, 0x03, 0x49, 0x00,
- 0x8d, 0x00, 0x8b, 0x00, 0x10, 0x01, 0x90, 0x01, 0x60, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x3e,
+ 0x00, 0x7e, 0x00, 0xfe, 0x00, 0xfe, 0x01, 0xfe, 0x03, 0xfe, 0x07,
+ 0x7e, 0x00, 0x6e, 0x00, 0xc6, 0x00, 0xc2, 0x00, 0x00, 0x00,
};
static char nw_smsk[] = {
0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x3f, 0x00, 0x7f,
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x03, 0xff, 0x03, 0x7f, 0x00,
- 0xff, 0x00, 0xfb, 0x00, 0xf0, 0x01, 0xf0, 0x01, 0x60, 0x00,
+ 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x03, 0xff, 0x07, 0xff, 0x0f,
+ 0xff, 0x0f, 0xff, 0x00, 0xef, 0x01, 0xe7, 0x01, 0xc3, 0x00,
+ };
+
+ static char nw_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00,
+ 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe,
+ 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x07,
+ 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xfe, 0x3f,
+ 0x00, 0x00, 0xfe, 0x3e, 0x00, 0x00, 0x7e, 0x7c, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x1e,
+ 0xf8, 0x00, 0x00, 0x0e, 0xf8, 0x00, 0x00, 0x06, 0xf0, 0x01, 0x00, 0x02, 0xf0, 0x01, 0x00,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char nw_lmsk[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01,
+ 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff,
+ 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x0f,
+ 0x00, 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x7f,
+ 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f,
+ 0xfc, 0x01, 0x00, 0x1f, 0xfc, 0x01, 0x00, 0x0f, 0xf8, 0x03, 0x00, 0x07, 0xf8, 0x03, 0x00,
+ 0x03, 0xf0, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00,
};
static BCursor NWArrowCursor = {
@@ -427,34 +501,60 @@ void wm_init_cursor_data(void)
nw_smsk,
16,
16,
- 6,
- 7,
+ 0,
+ 0,
/* big */
- NULL,
- NULL,
+ nw_lbm,
+ nw_lmsk,
32,
32,
- 15,
- 15,
+ 0,
+ 0,
/* can invert color */
true,
};
- BlenderCursor[BC_NW_ARROWCURSOR] = &NWArrowCursor;
+ BlenderCursor[WM_CURSOR_DEFAULT] = &NWArrowCursor;
+ BlenderCursor[WM_CURSOR_COPY] = &NWArrowCursor;
+ BlenderCursor[WM_CURSOR_NW_ARROW] = &NWArrowCursor;
END_CURSOR_BLOCK;
///********************** NS_ARROW Cursor *************************/
BEGIN_CURSOR_BLOCK;
static char ns_sbm[] = {
- 0x40, 0x01, 0x20, 0x02, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x3c,
- 0x1e, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x3c, 0x1e,
- 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0x80,
+ 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char ns_smsk[] = {
- 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1f, 0xfc,
- 0x1f, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xfc, 0x1f,
- 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc,
+ 0x1f, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xfc, 0x1f,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00,
+ };
+
+ static char ns_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03,
+ 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff,
+ 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
+ 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+ 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ns_lmsk[] = {
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07,
+ 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01,
+ 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0xe0, 0xff,
+ 0xff, 0x01, 0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00,
};
static BCursor NSArrowCursor = {
@@ -463,11 +563,11 @@ void wm_init_cursor_data(void)
ns_smsk,
16,
16,
- 6,
+ 7,
7,
/* big */
- NULL,
- NULL,
+ ns_lbm,
+ ns_lmsk,
32,
32,
15,
@@ -476,21 +576,46 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_NS_ARROWCURSOR] = &NSArrowCursor;
+ BlenderCursor[WM_CURSOR_Y_MOVE] = &NSArrowCursor;
+ BlenderCursor[WM_CURSOR_NS_ARROW] = &NSArrowCursor;
END_CURSOR_BLOCK;
/********************** EW_ARROW Cursor *************************/
BEGIN_CURSOR_BLOCK;
static char ew_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x2c, 0x34, 0xe6,
- 0x67, 0x03, 0xc0, 0x01, 0x80, 0x03, 0xc0, 0xe6, 0x67, 0x2c, 0x34,
- 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x18,
+ 0x18, 0x1c, 0x38, 0xfe, 0x7f, 0x1c, 0x38, 0x18, 0x18, 0x10, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char ew_smsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x3c, 0x3c, 0xfe,
- 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x3c, 0x3c,
- 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x30, 0x0c, 0x38, 0x1c, 0x3c,
+ 0x3c, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0x3c, 0x3c, 0x38, 0x1c,
+ 0x30, 0x0c, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ew_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x80, 0x00, 0x80, 0x01, 0x80, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x01, 0x80, 0x07, 0xf0,
+ 0x01, 0x80, 0x0f, 0xf8, 0x01, 0x80, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0xff, 0xff, 0x7f,
+ 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0x01, 0x80, 0x3f, 0xf8, 0x01, 0x80, 0x1f, 0xf0, 0x01, 0x80,
+ 0x0f, 0xe0, 0x01, 0x80, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x01, 0x80, 0x01, 0x00, 0x01,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ew_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x80, 0x03,
+ 0xc0, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x03, 0xc0, 0x0f, 0xf8,
+ 0x03, 0xc0, 0x1f, 0xfc, 0x03, 0xc0, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0x03, 0xc0, 0x3f, 0xf8, 0x03, 0xc0,
+ 0x1f, 0xf0, 0x03, 0xc0, 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x03,
+ 0xc0, 0x01, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static BCursor EWArrowCursor = {
@@ -500,10 +625,10 @@ void wm_init_cursor_data(void)
16,
16,
7,
- 6,
+ 7,
/* big */
- NULL,
- NULL,
+ ew_lbm,
+ ew_lmsk,
32,
32,
15,
@@ -512,45 +637,46 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_EW_ARROWCURSOR] = &EWArrowCursor;
+ BlenderCursor[WM_CURSOR_X_MOVE] = &EWArrowCursor;
+ BlenderCursor[WM_CURSOR_EW_ARROW] = &EWArrowCursor;
END_CURSOR_BLOCK;
/********************** Wait Cursor *****************************/
BEGIN_CURSOR_BLOCK;
static char wait_sbm[] = {
- 0xfe, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x84, 0x21, 0xc8, 0x13, 0xd0,
- 0x0b, 0xa0, 0x04, 0x20, 0x05, 0xa0, 0x04, 0x10, 0x09, 0x88, 0x11,
- 0xc4, 0x23, 0xe2, 0x47, 0xfa, 0x5f, 0x02, 0x40, 0xfe, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xf0, 0x07, 0xb0, 0x06, 0x60,
+ 0x03, 0xc0, 0x01, 0x80, 0x00, 0x80, 0x00, 0xc0, 0x01, 0x60, 0x03,
+ 0x30, 0x06, 0x10, 0x04, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00,
};
static char wait_smsk[] = {
- 0xfe, 0x7f, 0xfe, 0x7f, 0x06, 0x60, 0x8c, 0x31, 0xd8, 0x1b, 0xf0,
- 0x0f, 0xe0, 0x06, 0x60, 0x07, 0xe0, 0x06, 0x30, 0x0d, 0x98, 0x19,
- 0xcc, 0x33, 0xe6, 0x67, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
+ 0xfc, 0x1f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf0,
+ 0x07, 0xe0, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07,
+ 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xfc, 0x1f, 0xfc, 0x1f,
};
static char wait_lbm[] = {
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00,
- 0x30, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x18, 0x18, 0xc0, 0x03, 0x0c, 0x30, 0x20,
- 0x07, 0x06, 0x60, 0xf0, 0x0f, 0x03, 0xc0, 0xd0, 0x8d, 0x01, 0x80, 0x79, 0xcf, 0x00, 0x00,
- 0xf3, 0x67, 0x00, 0x00, 0x66, 0x37, 0x00, 0x00, 0x8c, 0x33, 0x00, 0x00, 0x0c, 0x32, 0x00,
- 0x00, 0xcc, 0x33, 0x00, 0x00, 0x8c, 0x30, 0x00, 0x00, 0x46, 0x61, 0x00, 0x00, 0x03, 0xc3,
- 0x00, 0x80, 0x01, 0x83, 0x01, 0xc0, 0xc0, 0x03, 0x03, 0x60, 0xa0, 0x05, 0x06, 0x30, 0xf0,
- 0x0f, 0x0c, 0x18, 0xf8, 0x1d, 0x18, 0x0c, 0x5c, 0x3f, 0x30, 0x0c, 0xff, 0x5f, 0x30, 0x0c,
- 0xf7, 0xfe, 0x31, 0xcc, 0xfb, 0x9f, 0x33, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x30,
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f,
+ 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0x80, 0x07, 0x78, 0x00, 0x00, 0x0f, 0x3c, 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00,
+ 0x3c, 0x0f, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x30, 0x03,
+ 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1f,
+ 0x3e, 0x00, 0x80, 0x0f, 0x7c, 0x00, 0x80, 0x07, 0x78, 0x00, 0x80, 0x03, 0x70, 0x00, 0x80,
+ 0x01, 0x60, 0x00, 0x80, 0x01, 0x60, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char wait_lmsk[] = {
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff,
- 0x3f, 0x3c, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x00, 0x1e, 0x78, 0xc0, 0x03, 0x0f, 0xf0, 0xa0,
- 0x87, 0x07, 0xe0, 0xf1, 0xcf, 0x03, 0xc0, 0xf3, 0xef, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00,
- 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x3c, 0x3f, 0x00,
- 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xbc, 0x3c, 0x00, 0x00, 0xde, 0x79, 0x00, 0x00, 0x0f, 0xf3,
- 0x00, 0x80, 0x07, 0xe3, 0x01, 0xc0, 0xc3, 0xc3, 0x03, 0xe0, 0xe1, 0x87, 0x07, 0xf0, 0xf0,
- 0x0f, 0x0f, 0x78, 0xf8, 0x1f, 0x1e, 0x3c, 0x7c, 0x3f, 0x3c, 0x3c, 0xff, 0x7f, 0x3c, 0xbc,
- 0xff, 0xff, 0x3d, 0xfc, 0xfb, 0xbf, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
- 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff,
+ 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff,
+ 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07,
+ 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0,
+ 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xff, 0x03,
+ 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03,
};
static BCursor WaitCursor = {
@@ -568,48 +694,50 @@ void wm_init_cursor_data(void)
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_WAITCURSOR] = &WaitCursor;
+ BlenderCursor[WM_CURSOR_WAIT] = &WaitCursor;
END_CURSOR_BLOCK;
- /********************** Cross Cursor ***************************/
+ /****************** Normal Cross Cursor ************************/
BEGIN_CURSOR_BLOCK;
static char cross_sbm[] = {
0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
- 0x01, 0x80, 0x01, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x01, 0x80, 0x01,
+ 0x01, 0x00, 0x00, 0x3e, 0x7c, 0x3e, 0x7c, 0x00, 0x00, 0x80, 0x01,
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00,
+
};
static char cross_smsk[] = {
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
- 0x01, 0xc0, 0x03, 0x7f, 0xfe, 0x7f, 0xfe, 0xc0, 0x03, 0x80, 0x01,
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0,
+ 0x03, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0xff, 0xff, 0xc0, 0x03,
+ 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03,
};
static char cross_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
- 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x78, 0x1e, 0x00,
- 0xfc, 0x1f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf8, 0x3f, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x40, 0x02,
- 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0x3f, 0xfc, 0x7f, 0xfe, 0x3f, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+
};
static char cross_lmsk[] = {
- 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
- 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
- 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
- 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x78, 0x1e, 0x00,
- 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x70, 0x0e,
- 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
- 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
- 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
- 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03,
+ 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0,
+ 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xc0, 0x03,
+ 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0,
+ 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
};
static BCursor CrossCursor = {
@@ -627,121 +755,227 @@ void wm_init_cursor_data(void)
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_CROSSCURSOR] = &CrossCursor;
+ BlenderCursor[WM_CURSOR_EDIT] = &CrossCursor;
+ BlenderCursor[WM_CURSOR_CROSS] = &CrossCursor;
END_CURSOR_BLOCK;
- /********************** EditCross Cursor ***********************/
+ /****************** Painting Cursor ************************/
BEGIN_CURSOR_BLOCK;
- static char editcross_sbm[] = {
- 0x0e, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x19, 0x03, 0x1d, 0x03, 0x11,
- 0x03, 0x0e, 0x03, 0x00, 0x03, 0xf8, 0x7c, 0xf8, 0x7c, 0x00, 0x03,
- 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00,
+ static char paint_sbm[] = {
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
+ };
+
+ static char paint_smsk[] = {
+ 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x8f, 0x78, 0xcf, 0x79, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00,
+ };
+ static char paint_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0x80, 0x01, 0x7f, 0xfe, 0x80, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
};
- static char editcross_smsk[] = {
- 0x0e, 0x00, 0x1f, 0x00, 0x1f, 0x03, 0x1f, 0x03, 0x1f, 0x03, 0x1f,
- 0x03, 0x0e, 0x03, 0x80, 0x07, 0xfc, 0xfc, 0xfc, 0xfc, 0x80, 0x07,
- 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
+ static char paint_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03,
+ 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0,
+ 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x01, 0x7f,
+ 0xff, 0xc1, 0x83, 0xff, 0xff, 0xc1, 0x83, 0xff, 0xfe, 0x80, 0x01, 0x7f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
};
- static BCursor EditCrossCursor = {
+ static BCursor PaintCursor = {
/* small */
- editcross_sbm,
- editcross_smsk,
+ paint_sbm,
+ paint_smsk,
16,
16,
- 9,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ paint_lbm,
+ paint_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_EDITCROSSCURSOR] = &EditCrossCursor;
+ BlenderCursor[WM_CURSOR_PAINT] = &PaintCursor;
END_CURSOR_BLOCK;
- /********************** Box Select *************************/
+ /********************** Dot Cursor ***********************/
BEGIN_CURSOR_BLOCK;
- static char box_sbm[32] = {
- 0x7f, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x06, 0x41, 0x06, 0x41,
- 0x06, 0x7f, 0x06, 0x00, 0x06, 0xe0, 0x79, 0xe0, 0x79, 0x00, 0x06,
- 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
+ static char dot_sbm[] = {
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
};
- static char box_smsk[32] = {
- 0x7f, 0x00, 0x7f, 0x00, 0x63, 0x06, 0x63, 0x06, 0x63, 0x06, 0x7f,
- 0x06, 0x7f, 0x06, 0x00, 0x0f, 0xf0, 0xf9, 0xf0, 0xf9, 0x00, 0x0f,
- 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06,
+ static char dot_smsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ static char dot_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
- static BCursor BoxSelCursor = {
+ static char dot_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static BCursor DotCursor = {
/* small */
- box_sbm,
- box_smsk,
+ dot_sbm,
+ dot_smsk,
16,
16,
- 9,
- 8,
+ 7,
+ 7,
+ /* big */
+ dot_lbm,
+ dot_lmsk,
+ 32,
+ 32,
+ 14,
+ 14,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_DOT] = &DotCursor;
+ END_CURSOR_BLOCK;
+
+ /************* Minimal Crosshair Cursor ***************/
+ BEGIN_CURSOR_BLOCK;
+ static char crossc_sbm[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x55, 0x55, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ };
+
+ static char crossc_smsk[] = {
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x00, 0x80, 0x00, 0x7f, 0x7f, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
+ };
+ static char crossc_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char crossc_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x78, 0x1e, 0x00,
+ 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x70, 0x0e,
+ 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ };
+
+ static BCursor CrossCursorC = {
+ /* small */
+ crossc_sbm,
+ crossc_smsk,
+ 16,
+ 16,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ crossc_lbm,
+ crossc_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_BOXSELCURSOR] = &BoxSelCursor;
-
+ BlenderCursor[WM_CURSOR_CROSSC] = &CrossCursorC;
END_CURSOR_BLOCK;
+
/********************** Knife Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char knife_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x2c, 0x00, 0x5a, 0x00,
- 0x34, 0x00, 0x2a, 0x00, 0x17, 0x80, 0x06, 0x40, 0x03, 0xa0, 0x03,
- 0xd0, 0x01, 0x68, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00,
+ 0x0c, 0x00, 0x06, 0x00, 0x0f, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01,
+ 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00, 0x0e, 0x00, 0x00, 0x00,
};
static char knife_smsk[] = {
- 0x00, 0x60, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0xfe, 0x00,
- 0x7e, 0x00, 0x7f, 0x80, 0x3f, 0xc0, 0x0e, 0x60, 0x07, 0xb0, 0x07,
- 0xd8, 0x03, 0xec, 0x01, 0x7e, 0x00, 0x1f, 0x00, 0x07, 0x00,
+ 0x00, 0x40, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00,
+ 0x1e, 0x00, 0x0f, 0x80, 0x1f, 0xc0, 0x0f, 0xe0, 0x07, 0xf0, 0x03,
+ 0xf8, 0x01, 0xfc, 0x00, 0x7e, 0x00, 0x3f, 0x00, 0x0f, 0x00,
};
static char knife_lbm[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00,
- 0x00, 0x7f, 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0xc0, 0x5f, 0x00, 0x00, 0xc0, 0x6f, 0x00,
- 0x00, 0xc0, 0x37, 0x00, 0x00, 0xa8, 0x1b, 0x00, 0x00, 0x54, 0x0d, 0x00, 0x00, 0xa8, 0x00,
- 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc0, 0x07,
- 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xd0, 0x0f, 0x00, 0x00, 0xe8, 0x07, 0x00, 0x00, 0xf4,
- 0x07, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0xc0,
- 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xe0, 0x1f,
+ 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe,
+ 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xe0,
+ 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char knife_lmsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
- 0x80, 0xff, 0x00, 0x00, 0xc0, 0xbf, 0x00, 0x00, 0xe0, 0xdf, 0x00, 0x00, 0xe0, 0xef, 0x00,
- 0x00, 0xf8, 0x77, 0x00, 0x00, 0xfc, 0x3b, 0x00, 0x00, 0xfe, 0x1d, 0x00, 0x00, 0xfe, 0x0f,
- 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xe0, 0x7f,
- 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xd8, 0x1f, 0x00, 0x00, 0xec, 0x0f, 0x00, 0x00, 0xf6,
- 0x0f, 0x00, 0x00, 0xfb, 0x06, 0x00, 0x80, 0xbd, 0x01, 0x00, 0xc0, 0x6e, 0x00, 0x00, 0xe0,
- 0x1b, 0x00, 0x00, 0xf0, 0x06, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
- 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+ 0xc0, 0x1f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf8, 0x03, 0x00,
+ 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0xff, 0x01,
+ 0x00, 0xc0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, 0x7f,
+ 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x80, 0xff,
+ 0x07, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8,
+ 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x03, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
};
static BCursor KnifeCursor = {
@@ -759,11 +993,11 @@ void wm_init_cursor_data(void)
32,
0,
31,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_KNIFECURSOR] = &KnifeCursor;
+ BlenderCursor[WM_CURSOR_KNIFE] = &KnifeCursor;
END_CURSOR_BLOCK;
@@ -771,9 +1005,9 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char vloop_sbm[] = {
- 0x00, 0x00, 0x7e, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x66,
- 0x60, 0x62, 0x6f, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x00, 0x00, 0x60, 0x60, 0x60, 0x6f, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0xfe, 0xf0, 0x96,
+ 0x9f, 0x92, 0x90, 0xf0, 0xf0, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40,
+ 0x20, 0x40, 0xf0, 0xf0, 0x90, 0x90, 0x90, 0x9f, 0xf0, 0xf0,
};
static char vloop_smsk[] = {
@@ -783,27 +1017,27 @@ void wm_init_cursor_data(void)
};
static char vloop_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00,
- 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03,
- 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x3c, 0x3c,
- 0x3c, 0x00, 0x3c, 0x0c, 0x3c, 0xff, 0x3c, 0x0c, 0x3c, 0xff, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00,
- 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c,
- 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xff, 0x3c, 0x00, 0x3c, 0xff, 0x3c,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00,
+ 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x01,
+ 0x00, 0x00, 0xfe, 0x7e, 0x00, 0x7e, 0x7e, 0xff, 0x00, 0xff, 0x3e, 0xc3, 0x00, 0xc3, 0x1e,
+ 0xc3, 0xff, 0xc3, 0x0e, 0xc3, 0xff, 0xc3, 0x06, 0xc3, 0x00, 0xc3, 0x02, 0xff, 0x00, 0xff,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00,
+ 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18,
+ 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xc3, 0x00, 0xc3, 0x00, 0xc3, 0xff, 0xc3, 0x00, 0xc3, 0xff, 0xc3, 0x00, 0xc3, 0x00, 0xc3,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x7e,
};
static char vloop_lmsk[] = {
- 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
- 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f,
- 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x00, 0xff,
- 0x0f, 0xff, 0x00, 0xff, 0x03, 0x3c, 0x00, 0x3c, 0x03, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00,
- 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c,
- 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
- 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
- 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x07,
+ 0x00, 0x00, 0xff, 0x7f, 0x00, 0x7e, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x7f,
+ 0xe7, 0xff, 0xe7, 0x3f, 0xe7, 0xff, 0xe7, 0x1f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x00, 0xff,
+ 0x07, 0x7e, 0x00, 0x7e, 0x03, 0x38, 0x00, 0x38, 0x01, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00,
+ 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
+ 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0xe7, 0xff, 0xe7, 0x00, 0xe7, 0xff, 0xe7, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x7e,
};
static BCursor VLoopCursor = {
@@ -821,26 +1055,50 @@ void wm_init_cursor_data(void)
32,
0,
0,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_VLOOPCURSOR] = &VLoopCursor;
+ BlenderCursor[WM_CURSOR_VERTEX_LOOP] = &VLoopCursor;
END_CURSOR_BLOCK;
/********************** TextEdit Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char textedit_sbm[] = {
- 0xe0, 0x03, 0x10, 0x04, 0x60, 0x03, 0x40, 0x01, 0x40, 0x01, 0x40,
- 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01,
- 0x40, 0x01, 0x40, 0x01, 0x60, 0x03, 0x10, 0x04, 0xe0, 0x03,
+ 0x00, 0x00, 0x70, 0x07, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x70, 0x07, 0x00, 0x00,
};
static char textedit_smsk[] = {
- 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
+ 0x70, 0x07, 0xf8, 0x0f, 0xf0, 0x07, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
- 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03,
+ 0xc0, 0x01, 0xc0, 0x01, 0xf0, 0x07, 0xf8, 0x0f, 0x70, 0x07,
+ };
+
+ static char textedit_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xe0, 0x01,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
+ 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
+ 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xff, 0x3f, 0x00,
+ 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char textedit_lmsk[] = {
+ 0x00, 0x3f, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f,
+ 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0,
+ 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01,
+ 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0,
+ 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+ 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00,
+ 0x80, 0xff, 0x7f, 0x00, 0x00, 0x3f, 0x3f, 0x00,
};
static BCursor TextEditCursor = {
@@ -849,35 +1107,58 @@ void wm_init_cursor_data(void)
textedit_smsk,
16,
16,
- 9,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ textedit_lbm,
+ textedit_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_TEXTEDITCURSOR] = &TextEditCursor;
+ BlenderCursor[WM_CURSOR_TEXT_EDIT] = &TextEditCursor;
END_CURSOR_BLOCK;
/********************** Paintbrush Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char paintbrush_sbm[] = {
-
- 0x00, 0xe0, 0x00, 0x98, 0x00, 0x44, 0x00, 0x42, 0x00, 0x21, 0x80,
- 0x20, 0x40, 0x13, 0x40, 0x17, 0xa0, 0x0b, 0x98, 0x05, 0x04, 0x02,
- 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x81, 0x00, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0x74, 0x00, 0x2e, 0x00,
+ 0x1f, 0x80, 0x0f, 0xc0, 0x07, 0xe0, 0x03, 0xf0, 0x01, 0xf8, 0x00,
+ 0x7c, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x00, 0x00,
};
static char paintbrush_smsk[] = {
- 0x00, 0xe0, 0x00, 0xf8, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x3f, 0x80,
- 0x3f, 0xc0, 0x1f, 0xc0, 0x1f, 0xe0, 0x0f, 0xf8, 0x07, 0xfc, 0x03,
- 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xff, 0x00, 0x7f, 0x00,
+ 0x00, 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0x7f, 0x80,
+ 0x3f, 0xc0, 0x1f, 0xe0, 0x0f, 0xf0, 0x07, 0xf8, 0x03, 0xfc, 0x01,
+ 0xfe, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x1f, 0x00, 0x0f, 0x00,
+ };
+
+ static char paintbrush_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+ 0x10, 0x1f, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x7c, 0x04, 0x00, 0x00, 0xfe, 0x00, 0x00,
+ 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03,
+ 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe,
+ 0x03, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char paintbrush_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xc0,
+ 0x3f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00,
+ 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00,
+ 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00,
+ 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f,
+ 0x00, 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff,
+ 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff,
+ 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
};
static BCursor PaintBrushCursor = {
@@ -889,32 +1170,116 @@ void wm_init_cursor_data(void)
0,
15,
/* big */
- NULL,
- NULL,
+ paintbrush_lbm,
+ paintbrush_lmsk,
32,
32,
- 15,
- 15,
- /* can invert color */
- true,
+ 0,
+ 31,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_PAINTBRUSHCURSOR] = &PaintBrushCursor;
+ BlenderCursor[WM_CURSOR_PAINT_BRUSH] = &PaintBrushCursor;
+ END_CURSOR_BLOCK;
+
+ /********************** Eraser Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+ static char eraser_sbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x07,
+ 0xfe, 0x03, 0xfe, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char eraser_smsk[] = {
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x1f, 0x80, 0x3f, 0xc0,
+ 0x7f, 0xe0, 0xff, 0xf0, 0x7f, 0xf8, 0x3f, 0xfc, 0x1f, 0xfe, 0x0f,
+ 0xff, 0x07, 0xff, 0x03, 0xff, 0x01, 0xff, 0x00, 0x00, 0x00,
+ };
+
+ static char eraser_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80,
+ 0x01, 0x06, 0x00, 0xc0, 0x00, 0x0c, 0x00, 0x60, 0x00, 0x18, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x18, 0x00, 0x60, 0x00, 0x4c, 0x00, 0xc0, 0x00, 0xe6, 0x00, 0xc0, 0x00, 0xf3, 0x01, 0x60,
+ 0x80, 0xf9, 0x03, 0x30, 0xc0, 0xfc, 0x07, 0x18, 0x60, 0xfe, 0x0f, 0x0c, 0x30, 0xff, 0x1f,
+ 0x06, 0x98, 0xff, 0x3f, 0x03, 0xcc, 0xff, 0x9f, 0x01, 0xe6, 0xff, 0xcf, 0x00, 0xf3, 0xff,
+ 0x67, 0x00, 0xf9, 0xff, 0x33, 0x00, 0xfd, 0xff, 0x19, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd,
+ 0x7f, 0x06, 0x00, 0xfd, 0x3f, 0x03, 0x00, 0x01, 0x80, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char eraser_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x80,
+ 0xff, 0x07, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0x3f, 0x00,
+ 0xf8, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0x00, 0xff, 0xff, 0x7f,
+ 0x80, 0xff, 0xff, 0x3f, 0xc0, 0xff, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff,
+ 0x07, 0xf8, 0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0x7f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xff,
+ 0xff, 0x07, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static BCursor EraserCursor = {
+ /* small */
+ eraser_sbm,
+ eraser_smsk,
+ 16,
+ 16,
+ 0,
+ 14,
+ /* big */
+ eraser_lbm,
+ eraser_lmsk,
+ 32,
+ 32,
+ 0,
+ 28,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_ERASER] = &EraserCursor;
END_CURSOR_BLOCK;
/********************** Hand Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char hand_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x0d, 0x98, 0x6d, 0x98,
- 0x6d, 0xb0, 0x6d, 0xb0, 0x6d, 0xe0, 0x6f, 0xe6, 0x7f, 0xee, 0x7f,
- 0xfc, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xc0, 0x1f, 0xc0, 0x1f,
+ 0x00, 0x00, 0x80, 0x01, 0x80, 0x0d, 0x98, 0x6d, 0xb8, 0x6d, 0xb0,
+ 0x6d, 0xb0, 0x6d, 0xe0, 0x6f, 0xe6, 0x7f, 0xee, 0x7f, 0x7c, 0x35,
+ 0x78, 0x35, 0x70, 0x15, 0x60, 0x15, 0xc0, 0x1f, 0xc0, 0x1f,
};
static char hand_smsk[] = {
- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x0f, 0xd8, 0x7f, 0xfc, 0xff, 0xfc,
- 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x3f,
+ 0x80, 0x01, 0xc0, 0x0f, 0xd8, 0x7f, 0xfc, 0xff, 0xfc, 0xff, 0xf8,
+ 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f,
+ 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x3f, 0xe0, 0x3f,
+ };
+
+ static char hand_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x30, 0x0f,
+ 0x00, 0x00, 0x78, 0xcf, 0x00, 0x00, 0x78, 0xef, 0x01, 0x00, 0x78, 0xef, 0x01, 0x00, 0x78,
+ 0xef, 0x01, 0x00, 0x78, 0xef, 0x1d, 0x00, 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x00,
+ 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x70, 0x78, 0xef, 0x3d,
+ 0xf0, 0x78, 0xef, 0x3d, 0xf0, 0xf8, 0xff, 0x3d, 0xf0, 0xf8, 0xff, 0x3d, 0xf0, 0xf8, 0xff,
+ 0x3f, 0xf0, 0xb9, 0xf7, 0x3f, 0xe0, 0xbb, 0xf7, 0x3f, 0xe0, 0xbf, 0xf7, 0x3e, 0xe0, 0xbf,
+ 0xf7, 0x3e, 0xc0, 0xbf, 0xf7, 0x3e, 0x80, 0xbf, 0xf7, 0x3e, 0x80, 0xbf, 0xf7, 0x3e, 0x00,
+ 0xbf, 0xf7, 0x1e, 0x00, 0xbe, 0xf7, 0x1e, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f,
+ 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x07,
+ };
+
+ static char hand_lmsk[] = {
+ 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0xff,
+ 0x01, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc,
+ 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00,
+ 0xfc, 0xff, 0x7f, 0x60, 0xfc, 0xff, 0x7f, 0xf8, 0xfc, 0xff, 0x7f, 0xf8, 0xfd, 0xff, 0x7f,
+ 0xfc, 0xfd, 0xff, 0x7f, 0xfc, 0xfd, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff,
+ 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf0, 0xff,
+ 0xff, 0x7f, 0xe0, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0x7f, 0x80,
+ 0xff, 0xff, 0x7f, 0x80, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x1f,
+ 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x1f,
};
static BCursor HandCursor = {
@@ -926,17 +1291,17 @@ void wm_init_cursor_data(void)
8,
8,
/* big */
- NULL,
- NULL,
+ hand_lbm,
+ hand_lmsk,
32,
32,
- 15,
- 15,
- /* can invert color */
- true,
+ 17,
+ 17,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_HANDCURSOR] = &HandCursor;
+ BlenderCursor[WM_CURSOR_HAND] = &HandCursor;
END_CURSOR_BLOCK;
@@ -944,15 +1309,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char nsewscroll_sbm[] = {
- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x0c, 0x30, 0x0e, 0x70, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x40, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x30, 0x06, 0x60, 0x06, 0x60, 0x0c, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x02, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
};
static char nsewscroll_smsk[] = {
- 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x0c,
- 0x30, 0x1e, 0x78, 0x1f, 0xf8, 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30,
- 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+ 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0x40, 0x02, 0x0c,
+ 0x30, 0x1e, 0x78, 0x0f, 0xf0, 0x0f, 0xf8, 0x1e, 0x78, 0x0c, 0x30,
+ 0x40, 0x02, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+ };
+
+ static char nsewscroll_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07,
+ 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x38,
+ 0x1c, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x02, 0xe0,
+ 0x00, 0x00, 0x07, 0xf0, 0x01, 0x80, 0x0f, 0xf8, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x3e,
+ 0x3e, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x00,
+ 0x1f, 0xf0, 0x01, 0x80, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00,
+ 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char nsewscroll_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x0f,
+ 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x7c,
+ 0x3e, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x40, 0x10, 0x08, 0x02, 0xe0, 0x00, 0x00, 0x07, 0xf0,
+ 0x01, 0x80, 0x0f, 0xf8, 0x03, 0xc0, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0x00, 0x00, 0x7f,
+ 0x7f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x01, 0x80,
+ 0x3f, 0xf8, 0x03, 0xc0, 0x1f, 0xf0, 0x01, 0x80, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0x40, 0x10,
+ 0x08, 0x02, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
};
static BCursor NSEWScrollCursor = {
@@ -961,11 +1350,11 @@ void wm_init_cursor_data(void)
nsewscroll_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ nsewscroll_lbm,
+ nsewscroll_lmsk,
32,
32,
15,
@@ -974,7 +1363,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_NSEW_SCROLLCURSOR] = &NSEWScrollCursor;
+ BlenderCursor[WM_CURSOR_NSEW_SCROLL] = &NSEWScrollCursor;
END_CURSOR_BLOCK;
@@ -982,15 +1371,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char nsscroll_sbm[] = {
- 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0x70, 0x07, 0x20,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02,
+ 0x70, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char nsscroll_smsk[] = {
- 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0x70,
+ 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x70, 0x07,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00,
+ };
+
+ static char nsscroll_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03,
+ 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff,
+ 0x3f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1c,
+ 0x0e, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+ 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char nsscroll_lmsk[] = {
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07,
+ 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff,
+ 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00,
+ 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00, 0x3e,
+ 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00,
};
static BCursor NSScrollCursor = {
@@ -999,11 +1412,11 @@ void wm_init_cursor_data(void)
nsscroll_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ nsscroll_lbm,
+ nsscroll_lmsk,
32,
32,
15,
@@ -1012,7 +1425,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_NS_SCROLLCURSOR] = &NSScrollCursor;
+ BlenderCursor[WM_CURSOR_NS_SCROLL] = &NSScrollCursor;
END_CURSOR_BLOCK;
@@ -1020,15 +1433,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char ewscroll_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0c, 0x30, 0x0e, 0x70, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38,
+ 0x1c, 0x1c, 0x38, 0x0e, 0x70, 0x1c, 0x38, 0x38, 0x1c, 0x10, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char ewscroll_smsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
- 0x30, 0x1e, 0x78, 0x1f, 0xf8, 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x7c,
+ 0x3e, 0x3e, 0x7c, 0x1f, 0xf8, 0x3e, 0x7c, 0x7c, 0x3e, 0x38, 0x1c,
+ 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ewscroll_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0,
+ 0x07, 0xe0, 0x0f, 0xf8, 0x03, 0xc0, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0x00, 0x00, 0x7f,
+ 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x01, 0x80, 0x3f, 0xf8, 0x03, 0xc0, 0x1f, 0xf0, 0x07, 0xe0,
+ 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ewscroll_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x07, 0xe0, 0x0f, 0xf8,
+ 0x0f, 0xf0, 0x1f, 0xfc, 0x07, 0xe0, 0x3f, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0x01, 0x80, 0xff,
+ 0xff, 0x01, 0x80, 0xff, 0xfe, 0x03, 0xc0, 0x7f, 0xfc, 0x07, 0xe0, 0x3f, 0xf8, 0x0f, 0xf0,
+ 0x1f, 0xf0, 0x07, 0xe0, 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static BCursor EWScrollCursor = {
@@ -1037,11 +1474,11 @@ void wm_init_cursor_data(void)
ewscroll_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ ewscroll_lbm,
+ ewscroll_lmsk,
32,
32,
15,
@@ -1050,7 +1487,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_EW_SCROLLCURSOR] = &EWScrollCursor;
+ BlenderCursor[WM_CURSOR_EW_SCROLL] = &EWScrollCursor;
END_CURSOR_BLOCK;
@@ -1058,15 +1495,39 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char eyedropper_sbm[] = {
- 0x00, 0x30, 0x00, 0x48, 0x00, 0x85, 0x80, 0x82, 0x40, 0x40, 0x80,
- 0x20, 0x40, 0x11, 0xa0, 0x23, 0xd0, 0x15, 0xe8, 0x0a, 0x74, 0x01,
- 0xb4, 0x00, 0x4a, 0x00, 0x35, 0x00, 0x08, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x17, 0x00,
+ 0x0e, 0x00, 0x1d, 0x80, 0x0b, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00,
+ 0x38, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00,
};
static char eyedropper_smsk[] = {
- 0x00, 0x30, 0x00, 0x78, 0x00, 0xfd, 0x80, 0xff, 0xc0, 0x7f, 0x80,
- 0x3f, 0xc0, 0x1f, 0xe0, 0x3f, 0xf0, 0x1f, 0xf8, 0x0b, 0xfc, 0x01,
- 0xfc, 0x00, 0x7e, 0x00, 0x3f, 0x00, 0x0c, 0x00, 0x04, 0x00,
+ 0x00, 0x60, 0x00, 0xf0, 0x00, 0xfa, 0x00, 0x7f, 0x80, 0x3f, 0x00,
+ 0x1f, 0x80, 0x3f, 0xc0, 0x1f, 0xe0, 0x0b, 0xf0, 0x01, 0xf8, 0x00,
+ 0x7c, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x03, 0x00,
+ };
+
+ static char eyedropper_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe4, 0x3f, 0x00, 0x00,
+ 0xee, 0x1f, 0x00, 0x00, 0xdf, 0x0f, 0x00, 0x00, 0xbf, 0x07, 0x00, 0x00, 0x7e, 0x03, 0x00,
+ 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfb, 0x01, 0x00, 0x80, 0xf7, 0x03, 0x00, 0xc0, 0xef, 0x01,
+ 0x00, 0xe0, 0xcf, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xb8, 0x03, 0x00, 0x00, 0xdc, 0x01,
+ 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x80, 0x3b, 0x00, 0x00, 0xc0, 0x1d,
+ 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xf8,
+ 0x01, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char eyedropper_lmsk[] = {
+ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x80,
+ 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xe4, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xff, 0x3f, 0x00, 0x80, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03,
+ 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xcf, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03,
+ 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfc,
+ 0x03, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
};
static BCursor EyedropperCursor = {
@@ -1075,108 +1536,134 @@ void wm_init_cursor_data(void)
eyedropper_smsk,
16,
16,
- 1,
+ 0,
15,
/* big */
- NULL,
- NULL,
+ eyedropper_lbm,
+ eyedropper_lmsk,
32,
32,
- 15,
- 15,
- /* can invert color */
- true,
+ 1,
+ 30,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_EYEDROPPER_CURSOR] = &EyedropperCursor;
+ BlenderCursor[WM_CURSOR_EYEDROPPER] = &EyedropperCursor;
END_CURSOR_BLOCK;
/********************** Swap Area Cursor ***********************/
BEGIN_CURSOR_BLOCK;
static char swap_sbm[] = {
- 0xc0, 0xff, 0x40, 0x80, 0x40, 0x80, 0x40, 0x9c, 0x40, 0x98, 0x40,
- 0x94, 0x00, 0x82, 0xfe, 0x80, 0x7e, 0xfd, 0xbe, 0x01, 0xda, 0x01,
+ 0xc0, 0xff, 0x40, 0x80, 0x40, 0xbc, 0x40, 0xb8, 0x40, 0xb8, 0x40,
+ 0xa4, 0x00, 0x82, 0xfe, 0x81, 0x7e, 0x81, 0xbe, 0xfd, 0xda, 0x01,
0xe2, 0x01, 0xe2, 0x01, 0xc2, 0x01, 0xfe, 0x01, 0x00, 0x00,
};
static char swap_smsk[] = {
0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0x03,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03,
};
+ static char swap_lbm[] = {
+ 0x00, 0xe0, 0xff, 0xff, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0xf8,
+ 0x9f, 0x00, 0x20, 0xf0, 0x9f, 0x00, 0x20, 0xe0, 0x9f, 0x00, 0x20, 0xc0, 0x9f, 0x00, 0x20,
+ 0x80, 0x9f, 0x00, 0x20, 0xc0, 0x9f, 0x00, 0x20, 0xe0, 0x9e, 0x00, 0x20, 0x70, 0x9c, 0x00,
+ 0x20, 0x38, 0x98, 0x00, 0x20, 0x1c, 0x90, 0x00, 0x00, 0x0e, 0x80, 0xfe, 0xff, 0x07, 0x80,
+ 0xfe, 0x7f, 0x03, 0x80, 0xfe, 0x3f, 0x02, 0x80, 0xfe, 0x1f, 0x03, 0x80, 0xfe, 0x8f, 0xfb,
+ 0xff, 0xf6, 0xc7, 0x03, 0x00, 0xe6, 0xe3, 0x03, 0x00, 0xc6, 0xf1, 0x03, 0x00, 0x86, 0xf8,
+ 0x03, 0x00, 0x06, 0xfc, 0x03, 0x00, 0x06, 0xfe, 0x03, 0x00, 0x06, 0xfc, 0x03, 0x00, 0x06,
+ 0xf8, 0x03, 0x00, 0x06, 0xf0, 0x03, 0x00, 0x06, 0xe0, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00,
+ 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char swap_lmsk[] = {
+ 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff,
+ 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0,
+ 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00,
+ 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff,
+ 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff,
+ 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ };
+
static BCursor SwapCursor = {
/* small */
swap_sbm,
swap_smsk,
16,
16,
- 8,
- 8,
+ 7,
+ 7,
/* big */
- NULL,
- NULL,
+ swap_lbm,
+ swap_lmsk,
32,
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_SWAPAREA_CURSOR] = &SwapCursor;
+ BlenderCursor[WM_CURSOR_SWAP_AREA] = &SwapCursor;
END_CURSOR_BLOCK;
- /********************** Horizontal Split Cursor ***********************/
+ /********************** Vertical Split Cursor ***********************/
BEGIN_CURSOR_BLOCK;
- static char hsplit_sbm[] = {
- 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x88,
- 0x08, 0x8C, 0x18, 0x8E, 0x38, 0x8C, 0x18, 0x88, 0x08, 0x80, 0x00,
- 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ static char vsplit_sbm[] = {
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x88,
+ 0x11, 0x8c, 0x31, 0x86, 0x61, 0x86, 0x61, 0x8c, 0x31, 0x88, 0x11,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
};
- static char hsplit_smsk[] = {
- 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xD0, 0x05, 0xD8, 0x0D, 0xDC,
- 0x1D, 0xDE, 0x3D, 0xDF, 0x7D, 0xDE, 0x3D, 0xDC, 0x1D, 0xD8, 0x0D,
- 0xD0, 0x05, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00,
+ static char vsplit_smsk[] = {
+ 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc8, 0x13, 0xdc,
+ 0x3b, 0xde, 0x7b, 0xcf, 0xf3, 0xcf, 0xf3, 0xde, 0x7b, 0xdc, 0x3b,
+ 0xc8, 0x13, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07,
};
- static char hsplit_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01,
- 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
- 0x01, 0x00, 0x00, 0x84, 0x21, 0x00, 0x00, 0x86, 0x61, 0x00, 0x00, 0x87, 0xE1, 0x00, 0x80,
- 0x87, 0xE1, 0x01, 0xC0, 0x87, 0xE1, 0x03, 0xE0, 0x87, 0xE1, 0x07, 0xF0, 0x87, 0xE1, 0x0F,
- 0xF8, 0x87, 0xE1, 0x1F, 0xF0, 0x87, 0xE1, 0x0F, 0xE0, 0x87, 0xE1, 0x07, 0xC0, 0x87, 0xE1,
- 0x03, 0x80, 0x87, 0xE1, 0x01, 0x00, 0x87, 0xE1, 0x00, 0x00, 0x86, 0x61, 0x00, 0x00, 0x84,
- 0x21, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
- 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char vsplit_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c,
+ 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38,
+ 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x80, 0x38, 0x1c, 0x01, 0xc0, 0x39, 0x9c, 0x03, 0xe0,
+ 0x3b, 0xdc, 0x07, 0xf0, 0x39, 0x9c, 0x0f, 0xf8, 0x38, 0x1c, 0x1f, 0x7c, 0x38, 0x1c, 0x3e,
+ 0x3e, 0x38, 0x1c, 0x7c, 0x3e, 0x38, 0x1c, 0x7c, 0x7c, 0x38, 0x1c, 0x3e, 0xf8, 0x38, 0x1c,
+ 0x1f, 0xf0, 0x39, 0x9c, 0x0f, 0xe0, 0x3b, 0xdc, 0x07, 0xc0, 0x39, 0x9c, 0x03, 0x80, 0x38,
+ 0x1c, 0x01, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00,
+ 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00,
+ 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
- static char hsplit_lmsk[] = {
- 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03,
- 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC8, 0x13, 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00, 0xCE,
- 0x73, 0x00, 0x00, 0xCF, 0xF3, 0x00, 0x80, 0xCF, 0xF3, 0x01, 0xC0, 0xCF, 0xF3, 0x03, 0xE0,
- 0xCF, 0xF3, 0x07, 0xF0, 0xCF, 0xF3, 0x0F, 0xF8, 0xCF, 0xF3, 0x1F, 0xFC, 0xCF, 0xF3, 0x3F,
- 0xFE, 0xCF, 0xF3, 0x7F, 0xFC, 0xCF, 0xF3, 0x3F, 0xF8, 0xCF, 0xF3, 0x1F, 0xF0, 0xCF, 0xF3,
- 0x0F, 0xE0, 0xCF, 0xF3, 0x07, 0xC0, 0xCF, 0xF3, 0x03, 0x80, 0xCF, 0xF3, 0x01, 0x00, 0xCF,
- 0xF3, 0x00, 0x00, 0xCE, 0x73, 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00, 0xC8, 0x13, 0x00, 0x00,
- 0xC8, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00,
- 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char vsplit_lmsk[] = {
+ 0x00, 0x18, 0x18, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e,
+ 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78,
+ 0x1e, 0x00, 0x80, 0x78, 0x1e, 0x01, 0xc0, 0x79, 0x9e, 0x03, 0xe0, 0x7b, 0xde, 0x07, 0xf0,
+ 0x7f, 0xfe, 0x0f, 0xf8, 0x7b, 0xde, 0x1f, 0xfc, 0x79, 0x9e, 0x3f, 0xfe, 0x78, 0x1e, 0x7f,
+ 0x7f, 0x78, 0x1e, 0xfe, 0x7f, 0x78, 0x1e, 0xfe, 0xfe, 0x78, 0x1e, 0x7f, 0xfc, 0x79, 0x9e,
+ 0x3f, 0xf8, 0x7b, 0xde, 0x1f, 0xf0, 0x7f, 0xfe, 0x0f, 0xe0, 0x7b, 0xde, 0x07, 0xc0, 0x79,
+ 0x9e, 0x03, 0x80, 0x78, 0x1e, 0x01, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00,
+ 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00,
+ 0x00, 0x38, 0x1c, 0x00, 0x00, 0x18, 0x18, 0x00,
+ };
- static BCursor HSplitCursor = {
+ static BCursor VSplitCursor = {
/* small */
- hsplit_sbm,
- hsplit_smsk,
+ vsplit_sbm,
+ vsplit_smsk,
16,
16,
7,
7,
/* big */
- hsplit_lbm,
- hsplit_lmsk,
+ vsplit_lbm,
+ vsplit_lmsk,
32,
32,
15,
@@ -1185,58 +1672,60 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_H_SPLITCURSOR] = &HSplitCursor;
+ BlenderCursor[WM_CURSOR_V_SPLIT] = &VSplitCursor;
END_CURSOR_BLOCK;
- /********************** Vertical Split Cursor ***********************/
+ /********************** Horizontal Split Cursor ***********************/
BEGIN_CURSOR_BLOCK;
- static char vsplit_sbm[] = {
- 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ static char hsplit_sbm[] = {
+ 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x60, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x06, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
};
- static char vsplit_smsk[] = {
- 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8, 0x0F, 0x00,
- 0x00, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x00, 0x00, 0xF8, 0x0F,
- 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00,
+ static char hsplit_smsk[] = {
+ 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0x60, 0x06, 0x01,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80,
+ 0x60, 0x06, 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
};
- static char vsplit_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
- 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8,
- 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xFE, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00,
- 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char hsplit_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07,
+ 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x3e,
+ 0x7c, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
+ 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x10, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00,
+ 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
- static char vsplit_lmsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03,
- 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0,
- 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F,
- 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF,
- 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00,
- 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static char hsplit_lmsk[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x0f,
+ 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x7f,
+ 0xfe, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x08, 0x10, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff,
+ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x10, 0x00, 0x00, 0x1c,
+ 0x38, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00,
+ 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
+ };
- static BCursor VSplitCursor = {
+ static BCursor HSplitCursor = {
/* small */
- vsplit_sbm,
- vsplit_smsk,
+ hsplit_sbm,
+ hsplit_smsk,
16,
16,
7,
7,
/* big */
- vsplit_lbm,
- vsplit_lmsk,
+ hsplit_lbm,
+ hsplit_lmsk,
32,
32,
15,
@@ -1245,7 +1734,7 @@ void wm_init_cursor_data(void)
true,
};
- BlenderCursor[BC_V_SPLITCURSOR] = &VSplitCursor;
+ BlenderCursor[WM_CURSOR_H_SPLIT] = &HSplitCursor;
END_CURSOR_BLOCK;
@@ -1253,38 +1742,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char narrow_sbm[] = {
- 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8,
- 0x0F, 0xFC, 0x1F, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8,
+ 0x0f, 0x7c, 0x1f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char narrow_smsk[] = {
- 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8, 0x0F, 0xFC,
- 0x1F, 0xFE, 0x3F, 0xFF, 0x7F, 0xF0, 0x07, 0xF0, 0x07, 0xF0, 0x07,
- 0xF0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc,
+ 0x1f, 0xfe, 0x3f, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char narrow_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01,
- 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC,
- 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0,
- 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x0F,
- 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F,
- 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC,
- 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07,
+ 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc,
+ 0x7f, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x80, 0xff, 0xfe, 0x03, 0xc0,
+ 0x7f, 0xfc, 0x07, 0xe0, 0x3f, 0xf8, 0x0f, 0xf0, 0x1f, 0xf0, 0x1f, 0xf8, 0x0f, 0xe0, 0x3f,
+ 0xfc, 0x07, 0xc0, 0x7f, 0xf8, 0x03, 0x80, 0x3f, 0xf0, 0x01, 0x00, 0x1f, 0xe0, 0x00, 0x00,
+ 0x0e, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char narrow_lmsk[] = {
- 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07,
- 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF,
- 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x03, 0xF0,
- 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0x3F,
- 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F,
- 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe,
+ 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0x07, 0xe0,
+ 0xff, 0xfe, 0x0f, 0xf0, 0x7f, 0xfc, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf0, 0x7f,
+ 0xfe, 0x0f, 0xe0, 0xff, 0xfc, 0x07, 0xc0, 0x7f, 0xf8, 0x03, 0x80, 0x3f, 0xf0, 0x01, 0x00,
+ 0x1f, 0xe0, 0x00, 0x00, 0x0e, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static BCursor NArrowCursor = {
/* small */
@@ -1293,19 +1784,19 @@ void wm_init_cursor_data(void)
16,
16,
7,
- 4,
+ 5,
/* big */
narrow_lbm,
narrow_lmsk,
32,
32,
- 15,
- 10,
+ 16,
+ 12,
/* can invert color */
true,
};
- BlenderCursor[BC_N_ARROWCURSOR] = &NArrowCursor;
+ BlenderCursor[WM_CURSOR_N_ARROW] = &NArrowCursor;
END_CURSOR_BLOCK;
@@ -1313,38 +1804,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char sarrow_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0,
- 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xFC, 0x1F, 0xF8, 0x0F,
- 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7c, 0x1f, 0xf8, 0x0f,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char sarrow_smsk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0xF0,
- 0x07, 0xF0, 0x07, 0xF0, 0x07, 0xFF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F,
- 0xF8, 0x0F, 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00,
};
static char sarrow_lbm[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00,
- 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00,
- 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF,
- 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
- 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00,
- 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x80, 0x0f,
+ 0xfc, 0x01, 0xc0, 0x1f, 0xfe, 0x03, 0xe0, 0x3f, 0xfc, 0x07, 0xf0, 0x1f, 0xf8, 0x0f, 0xf8,
+ 0x0f, 0xf0, 0x1f, 0xfc, 0x07, 0xe0, 0x3f, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0x01, 0x80, 0xff,
+ 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00,
+ 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char sarrow_lmsk[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE,
- 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00,
- 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00,
- 0x00, 0xFE, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF,
- 0x1F, 0xF8, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF,
- 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00,
- 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00,
- 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x80, 0x0f, 0xfc, 0x01, 0xc0, 0x1f,
+ 0xfe, 0x03, 0xe0, 0x3f, 0xff, 0x07, 0xf0, 0x7f, 0xfe, 0x0f, 0xf8, 0x3f, 0xfc, 0x1f, 0xfc,
+ 0x1f, 0xf8, 0x3f, 0xfe, 0x0f, 0xf0, 0x7f, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x03, 0xc0, 0xff,
+ 0xff, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00,
+ 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ };
static BCursor SArrowCursor = {
/* small */
@@ -1353,19 +1846,19 @@ void wm_init_cursor_data(void)
16,
16,
7,
- 11,
+ 10,
/* big */
sarrow_lbm,
sarrow_lmsk,
32,
32,
15,
- 21,
+ 18,
/* can invert color */
true,
};
- BlenderCursor[BC_S_ARROWCURSOR] = &SArrowCursor;
+ BlenderCursor[WM_CURSOR_S_ARROW] = &SArrowCursor;
END_CURSOR_BLOCK;
@@ -1373,38 +1866,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char earrow_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0E, 0xE0,
- 0x1F, 0xE0, 0x3F, 0xE0, 0x7F, 0xE0, 0x3F, 0xE0, 0x1F, 0x00, 0x0E,
- 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00,
+ 0x1f, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x1f, 0x80, 0x0f,
+ 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
};
static char earrow_smsk[] = {
- 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0F, 0xF0, 0x1F, 0xF0,
- 0x3F, 0xF0, 0x7F, 0xF0, 0xFF, 0xF0, 0x7F, 0xF0, 0x3F, 0xF0, 0x1F,
- 0x00, 0x0F, 0x00, 0x07, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x1f, 0x80,
+ 0x3f, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0x7f, 0x80, 0x3f, 0xc0, 0x1f,
+ 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00,
};
static char earrow_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
- 0x3E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00,
- 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x1F,
- 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF,
- 0x07, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00,
- 0x7E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00,
- 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07,
+ 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xc0,
+ 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00,
+ 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8,
+ 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x80,
+ 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00,
+ 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char earrow_lmsk[] = {
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0F,
- 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00,
- 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x07, 0x80,
- 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF, 0x7F,
- 0x80, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0x7F, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF,
- 0x1F, 0x80, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x07, 0x80, 0xFF, 0xFF, 0x03, 0x00, 0x00,
- 0xFF, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00,
- 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0f,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xe0,
+ 0xff, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf0, 0x7f,
+ 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc,
+ 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0,
+ 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00,
+ 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static BCursor EArrowCursor = {
/* small */
@@ -1412,20 +1907,20 @@ void wm_init_cursor_data(void)
earrow_smsk,
16,
16,
- 11,
+ 10,
7,
/* big */
earrow_lbm,
earrow_lmsk,
32,
32,
+ 18,
15,
- 22,
/* can invert color */
true,
};
- BlenderCursor[BC_E_ARROWCURSOR] = &EArrowCursor;
+ BlenderCursor[WM_CURSOR_E_ARROW] = &EArrowCursor;
END_CURSOR_BLOCK;
@@ -1433,38 +1928,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char warrow_sbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0xF8,
- 0x07, 0xFC, 0x07, 0xFE, 0x07, 0xFC, 0x07, 0xF8, 0x07, 0x70, 0x00,
- 0x60, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x01, 0xf8,
+ 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x01,
+ 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char warrow_smsk[] = {
- 0x80, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0xF0, 0x00, 0xF8, 0x0F, 0xFC,
- 0x0F, 0xFE, 0x0F, 0xFF, 0x0F, 0xFE, 0x0F, 0xFC, 0x0F, 0xF8, 0x0F,
- 0xF0, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x03, 0xfc,
+ 0x01, 0xfe, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0xfc, 0x01, 0xf8, 0x03,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00,
};
static char warrow_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
- 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7C,
- 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0,
- 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0xFF, 0x00,
- 0xFC, 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF,
- 0x00, 0xC0, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7E,
- 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
- 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03,
+ 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe,
+ 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0,
+ 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00,
+ 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char warrow_lmsk[] = {
- 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x00,
- 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x01, 0xF0,
- 0xFF, 0xFF, 0x01, 0xF8, 0xFF, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0x01,
- 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0x01, 0xF8, 0xFF, 0xFF,
- 0x01, 0xF0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF,
- 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00,
- 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07,
+ 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xff,
+ 0x07, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0,
+ 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x80, 0xff,
+ 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00,
+ 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static BCursor WArrowCursor = {
/* small */
@@ -1472,20 +1969,20 @@ void wm_init_cursor_data(void)
warrow_smsk,
16,
16,
- 4,
+ 5,
7,
/* big */
warrow_lbm,
warrow_lmsk,
32,
32,
- 15,
+ 18,
15,
/* can invert color */
true,
};
- BlenderCursor[BC_W_ARROWCURSOR] = &WArrowCursor;
+ BlenderCursor[WM_CURSOR_W_ARROW] = &WArrowCursor;
END_CURSOR_BLOCK;
@@ -1493,38 +1990,40 @@ void wm_init_cursor_data(void)
BEGIN_CURSOR_BLOCK;
static char stop_sbm[] = {
- 0x00, 0x00, 0xE0, 0x07, 0x38, 0x1C, 0x1C, 0x30, 0x3C, 0x20, 0x76,
- 0x60, 0xE2, 0x40, 0xC2, 0x41, 0x82, 0x43, 0x02, 0x47, 0x06, 0x6E,
- 0x04, 0x3C, 0x0C, 0x38, 0x38, 0x1C, 0xE0, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x07, 0xf8, 0x1f, 0x1c, 0x3c, 0x3c, 0x30, 0x76,
+ 0x70, 0xe6, 0x60, 0xc6, 0x61, 0x86, 0x63, 0x06, 0x67, 0x0e, 0x6e,
+ 0x0c, 0x3c, 0x3c, 0x38, 0xf8, 0x1f, 0xe0, 0x07, 0x00, 0x00,
};
static char stop_smsk[] = {
- 0xE0, 0x07, 0xF8, 0x1F, 0xFC, 0x3F, 0x3E, 0x7C, 0x7E, 0x70, 0xFF,
- 0xF0, 0xF7, 0xE1, 0xE7, 0xE3, 0xC7, 0xE7, 0x87, 0xEF, 0x0F, 0xFF,
- 0x0E, 0x7E, 0x3E, 0x7C, 0xFC, 0x3F, 0xF8, 0x1F, 0xE0, 0x07,
+ 0xe0, 0x07, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0x7e, 0x7c, 0xff,
+ 0xf8, 0xff, 0xf1, 0xef, 0xf3, 0xcf, 0xf7, 0x8f, 0xff, 0x1f, 0xff,
+ 0x3e, 0x7e, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xe0, 0x07,
};
static char stop_lbm[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x0F, 0xF0,
- 0x00, 0xC0, 0x03, 0xC0, 0x03, 0xE0, 0x01, 0x00, 0x07, 0xF0, 0x01, 0x00, 0x0E, 0xF0, 0x01,
- 0x00, 0x0C, 0xF8, 0x03, 0x00, 0x18, 0x1C, 0x07, 0x00, 0x38, 0x0C, 0x0E, 0x00, 0x30, 0x0C,
- 0x1C, 0x00, 0x30, 0x06, 0x38, 0x00, 0x60, 0x06, 0x70, 0x00, 0x60, 0x06, 0xE0, 0x00, 0x60,
- 0x06, 0xC0, 0x01, 0x60, 0x06, 0x80, 0x03, 0x60, 0x06, 0x00, 0x07, 0x60, 0x06, 0x00, 0x0E,
- 0x60, 0x06, 0x00, 0x1C, 0x60, 0x0C, 0x00, 0x38, 0x30, 0x0C, 0x00, 0x70, 0x30, 0x1C, 0x00,
- 0xE0, 0x38, 0x18, 0x00, 0xC0, 0x1F, 0x30, 0x00, 0x80, 0x0F, 0x70, 0x00, 0x80, 0x0F, 0xE0,
- 0x00, 0x80, 0x07, 0xC0, 0x03, 0xC0, 0x03, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFE, 0x7F, 0x00,
- 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xc0, 0x1f, 0xf8, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x01, 0x80, 0x0f, 0xf0, 0x03,
+ 0x00, 0x0f, 0xf8, 0x07, 0x00, 0x1e, 0xbc, 0x0f, 0x00, 0x3c, 0x1c, 0x1f, 0x00, 0x38, 0x1c,
+ 0x3e, 0x00, 0x38, 0x1e, 0x7c, 0x00, 0x78, 0x0e, 0xf8, 0x00, 0x70, 0x0e, 0xf0, 0x01, 0x70,
+ 0x0e, 0xe0, 0x03, 0x70, 0x0e, 0xc0, 0x07, 0x70, 0x0e, 0x80, 0x0f, 0x70, 0x0e, 0x00, 0x1f,
+ 0x70, 0x1e, 0x00, 0x3e, 0x78, 0x1c, 0x00, 0x7c, 0x38, 0x1c, 0x00, 0xf8, 0x38, 0x3c, 0x00,
+ 0xf0, 0x3d, 0x78, 0x00, 0xe0, 0x1f, 0xf0, 0x00, 0xc0, 0x0f, 0xf0, 0x01, 0x80, 0x0f, 0xe0,
+ 0x03, 0xc0, 0x07, 0xc0, 0x1f, 0xf8, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00,
+ 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
static char stop_lmsk[] = {
- 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF,
- 0x03, 0xE0, 0x1F, 0xF8, 0x07, 0xF0, 0x03, 0xC0, 0x0F, 0xF8, 0x03, 0x80, 0x1F, 0xFC, 0x07,
- 0x00, 0x3F, 0xFC, 0x0F, 0x00, 0x3E, 0xFE, 0x1F, 0x00, 0x7C, 0x9E, 0x3F, 0x00, 0x78, 0x1E,
- 0x7F, 0x00, 0x78, 0x1F, 0xFE, 0x00, 0xF8, 0x0F, 0xFC, 0x01, 0xF0, 0x0F, 0xF8, 0x03, 0xF0,
- 0x0F, 0xF0, 0x07, 0xF0, 0x0F, 0xE0, 0x0F, 0xF0, 0x0F, 0xC0, 0x1F, 0xF0, 0x0F, 0x80, 0x3F,
- 0xF0, 0x1F, 0x00, 0x7F, 0xF8, 0x1E, 0x00, 0xFE, 0x78, 0x1E, 0x00, 0xFC, 0x79, 0x3E, 0x00,
- 0xF8, 0x7F, 0x7C, 0x00, 0xF0, 0x3F, 0xFC, 0x00, 0xE0, 0x3F, 0xF8, 0x01, 0xC0, 0x1F, 0xF0,
- 0x03, 0xC0, 0x0F, 0xE0, 0x1F, 0xF8, 0x07, 0xC0, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x01,
- 0x00, 0xFE, 0x7F, 0x00, 0x00, 0xF0, 0x0F, 0x00};
+ 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff,
+ 0x07, 0xf0, 0xff, 0xff, 0x0f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf8, 0x07, 0xe0, 0x1f, 0xfc, 0x0f,
+ 0xc0, 0x3f, 0xfe, 0x1f, 0x80, 0x7f, 0xfe, 0x3f, 0x00, 0x7f, 0xfe, 0x7f, 0x00, 0x7e, 0xbf,
+ 0xff, 0x00, 0xfc, 0x3f, 0xff, 0x01, 0xfc, 0x3f, 0xfe, 0x03, 0xfc, 0x1f, 0xfc, 0x07, 0xf8,
+ 0x1f, 0xf8, 0x0f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf8, 0x1f, 0xe0, 0x3f, 0xf8, 0x3f, 0xc0, 0x7f,
+ 0xfc, 0x3f, 0x80, 0xff, 0xfc, 0x3f, 0x00, 0xff, 0xfd, 0x7e, 0x00, 0xfe, 0x7f, 0xfe, 0x00,
+ 0xfc, 0x7f, 0xfe, 0x01, 0xf8, 0x7f, 0xfc, 0x03, 0xf0, 0x3f, 0xf8, 0x07, 0xe0, 0x1f, 0xf8,
+ 0x3f, 0xfc, 0x1f, 0xf0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0x01,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x1f, 0x00,
+ };
static BCursor StopCursor = {
/* small */
@@ -1541,11 +2040,135 @@ void wm_init_cursor_data(void)
32,
15,
15,
- /* can invert color */
- true,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_STOP] = &StopCursor;
+
+ END_CURSOR_BLOCK;
+
+ /********************** Zoom In Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+
+ static char zoomin_sbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xb8, 0x03, 0xbc,
+ 0x07, 0x0c, 0x06, 0xbc, 0x07, 0xb8, 0x03, 0xf8, 0x0b, 0xe0, 0x14,
+ 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, 0x90, 0x00, 0x60,
+ };
+
+ static char zoomin_smsk[] = {
+ 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07, 0xfe,
+ 0x0f, 0xfe, 0x0f, 0xfe, 0x0f, 0xfc, 0x07, 0xfc, 0x0f, 0xf8, 0x1f,
+ 0xe0, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0x60,
+ };
+
+ static char zoomin_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f,
+ 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xe7,
+ 0x3f, 0x00, 0xfc, 0xe7, 0x3f, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0xfe, 0xe7, 0x7f, 0x00,
+ 0xfc, 0xe7, 0x3f, 0x00, 0xfc, 0xe7, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x5f,
+ 0x00, 0xf8, 0xff, 0x9f, 0x00, 0xf0, 0xff, 0x0f, 0x01, 0xc0, 0xff, 0x03, 0x02, 0x00, 0x7e,
+ 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00,
+ 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82,
+ 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static char zoomin_lmsk[] = {
+ 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x1f,
+ 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff,
+ 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f,
+ 0x00, 0xfc, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff,
+ 0xff, 0x07, 0x00, 0x7e, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe,
+ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static BCursor ZoomInCursor = {
+ /* small */
+ zoomin_sbm,
+ zoomin_smsk,
+ 16,
+ 16,
+ 6,
+ 6,
+ /* big */
+ zoomin_lbm,
+ zoomin_lmsk,
+ 32,
+ 32,
+ 11,
+ 11,
+ /* don't invert color */
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_ZOOM_IN] = &ZoomInCursor;
+
+ END_CURSOR_BLOCK;
+
+ /********************** Zoom Out Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+
+ static char zoomout_sbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xf8, 0x03, 0xfc,
+ 0x07, 0x0c, 0x06, 0xfc, 0x07, 0xf8, 0x03, 0xf8, 0x0b, 0xe0, 0x14,
+ 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, 0x90, 0x00, 0x60,
+ };
+
+ static char zoomout_smsk[] = {
+ 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07, 0xfe,
+ 0x0f, 0xfe, 0x0f, 0xfe, 0x0f, 0xfc, 0x07, 0xfc, 0x0f, 0xf8, 0x1f,
+ 0xe0, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0x60,
+ };
+
+ static char zoomout_lbm[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f,
+ 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff,
+ 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x7e,
+ 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x5f,
+ 0x00, 0xf8, 0xff, 0x9f, 0x00, 0xf0, 0xff, 0x0f, 0x01, 0xc0, 0xff, 0x03, 0x02, 0x00, 0x7e,
+ 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00,
+ 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82,
+ 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static char zoomout_lmsk[] = {
+ 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x1f,
+ 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff,
+ 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f,
+ 0x00, 0xfc, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff,
+ 0xff, 0x07, 0x00, 0x7e, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe,
+ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x38,
+ };
+
+ static BCursor ZoomOutCursor = {
+ /* small */
+ zoomout_sbm,
+ zoomout_smsk,
+ 16,
+ 16,
+ 6,
+ 6,
+ /* big */
+ zoomout_lbm,
+ zoomout_lmsk,
+ 32,
+ 32,
+ 11,
+ 11,
+ /* don't invert color */
+ false,
};
- BlenderCursor[BC_STOPCURSOR] = &StopCursor;
+ BlenderCursor[WM_CURSOR_ZOOM_OUT] = &ZoomOutCursor;
END_CURSOR_BLOCK;
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index ba6a0c4ebe1..901594850dd 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -265,7 +265,7 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *e
if (opname) {
BLI_strncpy(drag->opname, opname, sizeof(drag->opname));
- // WM_cursor_modal_set(win, CURSOR_COPY);
+ // WM_cursor_modal_set(win, WM_CURSOR_COPY);
}
// else
// WM_cursor_modal_restore(win);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 77672e04030..a744cfb8c28 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -58,6 +58,8 @@
#include "BKE_sound.h"
+#include "BLT_translation.h"
+
#include "ED_fileselect.h"
#include "ED_info.h"
#include "ED_screen.h"
@@ -2336,22 +2338,22 @@ static int wm_handler_fileselect_do(bContext *C,
int val)
{
wmWindowManager *wm = CTX_wm_manager(C);
- SpaceFile *sfile;
int action = WM_HANDLER_CONTINUE;
switch (val) {
case EVT_FILESELECT_FULL_OPEN: {
wmWindow *win = CTX_wm_window(C);
- const int sizex = 1020 * UI_DPI_FAC;
- const int sizey = 600 * UI_DPI_FAC;
-
- if (WM_window_open_temp(C,
- WM_window_pixels_x(win) / 2,
- WM_window_pixels_y(win) / 2,
- sizex,
- sizey,
- WM_WINDOW_FILESEL) != NULL) {
- ScrArea *area = CTX_wm_area(C);
+ ScrArea *area;
+
+ if ((area = ED_screen_temp_space_open(C,
+ IFACE_("Blender File View"),
+ WM_window_pixels_x(win) / 2,
+ WM_window_pixels_y(win) / 2,
+ U.file_space_data.temp_win_sizex * UI_DPI_FAC,
+ U.file_space_data.temp_win_sizey * UI_DPI_FAC,
+ SPACE_FILE,
+ U.filebrowser_display_type,
+ true))) {
ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
BLI_assert(area->spacetype == SPACE_FILE);
@@ -2361,10 +2363,10 @@ static int wm_handler_fileselect_do(bContext *C,
region_header->alignment = RGN_ALIGN_BOTTOM;
/* settings for filebrowser, sfile is not operator owner but sends events */
- sfile = (SpaceFile *)area->spacedata.first;
+ SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
sfile->op = handler->op;
- ED_fileselect_set_params(sfile);
+ ED_fileselect_set_params_from_userdef(sfile);
}
else {
BKE_report(&wm->reports, RPT_ERROR, "Failed to open window!");
@@ -2390,17 +2392,27 @@ static int wm_handler_fileselect_do(bContext *C,
}
}
else {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- if (WM_window_is_temp_screen(win)) {
- bScreen *screen = WM_window_get_active_screen(win);
- ScrArea *file_sa = screen->areabase.first;
+ wmWindow *temp_win;
+ ScrArea *ctx_sa = CTX_wm_area(C);
+
+ for (temp_win = wm->windows.first; temp_win; temp_win = temp_win->next) {
+ bScreen *screen = WM_window_get_active_screen(temp_win);
+ ScrArea *file_sa = screen->areabase.first;
+
+ if (screen->temp && (file_sa->spacetype == SPACE_FILE)) {
+ int win_size[2];
- BLI_assert(file_sa->spacetype == SPACE_FILE);
+ /* Get DPI/pixelsize independent size to be stored in preferences. */
+ WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */
+ win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC;
+ win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC;
+
+ ED_fileselect_params_to_userdef(file_sa->spacedata.first, win_size);
if (BLI_listbase_is_single(&file_sa->spacedata)) {
- BLI_assert(ctx_win != win);
+ BLI_assert(ctx_win != temp_win);
- wm_window_close(C, wm, win);
+ wm_window_close(C, wm, temp_win);
CTX_wm_window_set(C, ctx_win); // wm_window_close() NULLs.
/* Some operators expect a drawable context (for EVT_FILESELECT_EXEC) */
@@ -2409,7 +2421,7 @@ static int wm_handler_fileselect_do(bContext *C,
* opening (UI_BLOCK_MOVEMOUSE_QUIT) */
wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
wm->winactive = ctx_win; /* Reports use this... */
- if (handler->context.win == win) {
+ if (handler->context.win == temp_win) {
handler->context.win = NULL;
}
}
@@ -2423,6 +2435,11 @@ static int wm_handler_fileselect_do(bContext *C,
break;
}
}
+
+ if (!temp_win && ctx_sa->full) {
+ ED_fileselect_params_to_userdef(ctx_sa->spacedata.first, NULL);
+ ED_screen_full_prevspace(C, ctx_sa);
+ }
}
wm_handler_op_context(C, handler, ctx_win->eventstate);
@@ -2721,7 +2738,10 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
/* Clear the tool-tip whenever a key binding is handled, without this tool-tips
* are kept when a modal operators starts (annoying but otherwise harmless). */
if (action & WM_HANDLER_BREAK) {
- WM_tooltip_clear(C, CTX_wm_window(C));
+ /* Window may be gone after file read. */
+ if (CTX_wm_window(C) != NULL) {
+ WM_tooltip_clear(C, CTX_wm_window(C));
+ }
}
}
else if (handler_base->type == WM_HANDLER_TYPE_UI) {
@@ -3536,15 +3556,52 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- /* Don't add the file handler to the temporary window, or else it owns the handlers for itself,
- * causing dangling pointers once it's destructed through a handler. It has a parent which should
- * hold the handlers itself. */
- ListBase *modalhandlers = WM_window_is_temp_screen(win) ? &win->parent->modalhandlers :
- &win->modalhandlers;
+ const bool is_temp_screen = WM_window_is_temp_screen(win);
+ const bool opens_window = (U.filebrowser_display_type == USER_TEMP_SPACE_DISPLAY_WINDOW);
+ /* Don't add the file handler to the temporary window if one is opened, or else it owns the
+ * handlers for itself, causing dangling pointers once it's destructed through a handler. It has
+ * a parent which should hold the handlers itself. */
+ ListBase *modalhandlers = (is_temp_screen && opens_window) ? &win->parent->modalhandlers :
+ &win->modalhandlers;
/* Close any popups, like when opening a file browser from the splash. */
UI_popup_handlers_remove_all(C, modalhandlers);
+ if (!is_temp_screen) {
+ /* only allow 1 file selector open per window */
+ LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, modalhandlers) {
+ if (handler_base->type == WM_HANDLER_TYPE_OP) {
+ wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
+ if (handler->is_fileselect == false) {
+ continue;
+ }
+ bScreen *screen = CTX_wm_screen(C);
+ bool cancel_handler = true;
+
+ /* find the area with the file selector for this handler */
+ ED_screen_areas_iter(win, screen, sa)
+ {
+ if (sa->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = sa->spacedata.first;
+
+ if (sfile->op == handler->op) {
+ CTX_wm_area_set(C, sa);
+ wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
+ cancel_handler = false;
+ break;
+ }
+ }
+ }
+
+ /* if not found we stop the handler without changing the screen */
+ if (cancel_handler) {
+ wm_handler_fileselect_do(
+ C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
+ }
+ }
+ }
+ }
+
wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
handler->head.type = WM_HANDLER_TYPE_OP;
@@ -4157,19 +4214,31 @@ static void wm_eventemulation(wmEvent *event, bool test_only)
if (U.flag & USER_TWOBUTTONMOUSE) {
if (event->type == LEFTMOUSE) {
- if (event->val == KM_PRESS && event->alt) {
- event->type = MIDDLEMOUSE;
- event->alt = 0;
+ short *mod = (
+#if !defined(WIN32)
+ (U.mouse_emulate_3_button_modifier == USER_EMU_MMB_MOD_OSKEY) ? &event->oskey :
+ &event->alt
+#else
+ /* Disable for WIN32 for now because it accesses the start menu. */
+ &event->alt
+#endif
+ );
- if (!test_only) {
- emulating_event = MIDDLEMOUSE;
+ if (event->val == KM_PRESS) {
+ if (*mod) {
+ *mod = 0;
+ event->type = MIDDLEMOUSE;
+
+ if (!test_only) {
+ emulating_event = MIDDLEMOUSE;
+ }
}
}
else if (event->val == KM_RELEASE) {
/* only send middle-mouse release if emulated */
if (emulating_event == MIDDLEMOUSE) {
event->type = MIDDLEMOUSE;
- event->alt = 0;
+ *mod = 0;
}
if (!test_only) {
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 561300ab7b9..f96a8c3d7fd 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -2515,7 +2515,7 @@ void WM_OT_recover_auto_save(wmOperatorType *ot)
FILE_BLENDER,
FILE_OPENFILE,
WM_FILESEL_FILEPATH,
- FILE_HORIZONTALDISPLAY,
+ FILE_VERTICALDISPLAY,
FILE_SORT_TIME);
}
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index ce2319e0394..3374d17cbfd 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -575,7 +575,7 @@ void WM_OT_link(wmOperatorType *ot)
FILE_LOADLIB,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
- WM_FILESEL_RELPATH | WM_FILESEL_FILES,
+ WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
@@ -599,7 +599,7 @@ void WM_OT_append(wmOperatorType *ot)
FILE_LOADLIB,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME |
- WM_FILESEL_FILES,
+ WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 6a6861ae697..c8c35ba1bfc 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -99,6 +99,7 @@
#include "wm.h"
#include "wm_files.h"
#include "wm_window.h"
+#include "wm_platform_support.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
@@ -314,6 +315,10 @@ void WM_init(bContext *C, int argc, const char **argv)
#endif
WM_init_opengl(G_MAIN);
+ if (!WM_platform_support_perform_checks()) {
+ exit(-1);
+ }
+
UI_init();
}
@@ -681,3 +686,12 @@ void WM_exit(bContext *C)
exit(G.is_break == true);
}
+
+/**
+ * Needed for cases when operators are re-registered
+ * (when operator type pointers are stored).
+ */
+void WM_script_tag_reload(void)
+{
+ UI_interface_tag_script_reload();
+}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 04775a7a880..21636153904 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -78,15 +78,6 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
{FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
{0, NULL, 0, NULL, NULL},
};
- static const EnumPropertyItem file_action_types[] = {
- {FILE_OPENFILE,
- "OPENFILE",
- 0,
- "Open",
- "Use the file browser for opening files or a directory"},
- {FILE_SAVE, "SAVE", 0, "Save", "Use the file browser for saving a file"},
- {0, NULL, 0, NULL, NULL},
- };
if (flag & WM_FILESEL_FILEPATH) {
RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to file");
@@ -207,9 +198,6 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
prop = RNA_def_enum(
ot->srna, "sort_method", rna_enum_file_sort_items, sort, "File sorting mode", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- prop = RNA_def_enum(ot->srna, "action_type", file_action_types, action, "Action Type", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
static void wm_operator_properties_select_action_ex(wmOperatorType *ot,
@@ -408,6 +396,16 @@ void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+void WM_operator_properties_generic_select(wmOperatorType *ot)
+{
+ PropertyRNA *prop = RNA_def_boolean(
+ ot->srna, "wait_to_deselect_others", false, "Wait to Deselect Others", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX);
+}
+
void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
{
WM_operator_properties_border(ot);
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 9657347a1c4..6bafbed9804 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -41,6 +41,7 @@
#include "CLG_log.h"
#include "DNA_ID.h"
+#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
@@ -58,6 +59,7 @@
#include "BLI_utildefines.h"
#include "BKE_brush.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -140,13 +142,13 @@ void WM_operator_bl_idname(char *to, const char *from)
if (from) {
const char *sep = strchr(from, '.');
- if (sep) {
- int ofs = (sep - from);
-
+ int from_len;
+ if (sep && (from_len = strlen(from)) < OP_MAX_TYPENAME - 3) {
+ const int ofs = (sep - from);
memcpy(to, from, sizeof(char) * ofs);
BLI_str_toupper_ascii(to, ofs);
- strcpy(to + ofs, "_OT_");
- strcpy(to + (ofs + 4), sep + 1);
+ memcpy(to + ofs, "_OT_", 4);
+ memcpy(to + (ofs + 4), sep + 1, (from_len - ofs));
}
else {
/* should not happen but support just in case */
@@ -427,26 +429,16 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr
} \
(void)0
-# define CTX_TEST_PTR_DATA_TYPE(C, member, rna_type, rna_ptr, dataptr_cmp) \
+# define TEST_PTR_DATA_TYPE(member, rna_type, rna_ptr, dataptr_cmp) \
{ \
const char *ctx_member = member; \
- if (RNA_struct_is_a((ptr)->type, &(rna_type)) && (ptr)->data == (dataptr_cmp)) { \
+ if (RNA_struct_is_a((rna_ptr)->type, &(rna_type)) && (rna_ptr)->data == (dataptr_cmp)) { \
member_id = ctx_member; \
break; \
} \
} \
(void)0
-# define CTX_TEST_SPACE_TYPE(space_data_type, member_full, dataptr_cmp) \
- { \
- const char *ctx_member_full = member_full; \
- if (space_data->spacetype == space_data_type && ptr->data == dataptr_cmp) { \
- member_id = ctx_member_full; \
- break; \
- } \
- } \
- (void)0
-
switch (GS(ptr->owner_id->name)) {
case ID_SCE: {
CTX_TEST_PTR_ID(C, "scene", ptr->owner_id);
@@ -482,19 +474,50 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr
SpaceLink *space_data = CTX_wm_space_data(C);
- CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, space_data);
- CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_View3DOverlay, ptr, space_data);
- CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_View3DShading, ptr, space_data);
- CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C));
- CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C));
-
- CTX_TEST_SPACE_TYPE(SPACE_IMAGE, "space_data.uv_editor", space_data);
- CTX_TEST_SPACE_TYPE(
- SPACE_VIEW3D, "space_data.fx_settings", &(CTX_wm_view3d(C)->fx_settings));
- CTX_TEST_SPACE_TYPE(SPACE_NLA, "space_data.dopesheet", CTX_wm_space_nla(C)->ads);
- CTX_TEST_SPACE_TYPE(SPACE_GRAPH, "space_data.dopesheet", CTX_wm_space_graph(C)->ads);
- CTX_TEST_SPACE_TYPE(SPACE_ACTION, "space_data.dopesheet", &(CTX_wm_space_action(C)->ads));
- CTX_TEST_SPACE_TYPE(SPACE_FILE, "space_data.params", CTX_wm_space_file(C)->params);
+ TEST_PTR_DATA_TYPE("space_data", RNA_Space, ptr, space_data);
+ TEST_PTR_DATA_TYPE("area", RNA_Area, ptr, CTX_wm_area(C));
+ TEST_PTR_DATA_TYPE("region", RNA_Region, ptr, CTX_wm_region(C));
+
+ switch (space_data->spacetype) {
+ case SPACE_VIEW3D: {
+ const View3D *v3d = (View3D *)space_data;
+ const View3DShading *shading = &v3d->shading;
+
+ TEST_PTR_DATA_TYPE("space_data", RNA_View3DOverlay, ptr, v3d);
+ TEST_PTR_DATA_TYPE("space_data", RNA_View3DShading, ptr, shading);
+ break;
+ }
+ case SPACE_GRAPH: {
+ const SpaceGraph *sipo = (SpaceGraph *)space_data;
+ const bDopeSheet *ads = sipo->ads;
+ TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads);
+ break;
+ }
+ case SPACE_FILE: {
+ const SpaceFile *sfile = (SpaceFile *)space_data;
+ const FileSelectParams *params = sfile->params;
+ TEST_PTR_DATA_TYPE("space_data", RNA_FileSelectParams, ptr, params);
+ break;
+ }
+ case SPACE_IMAGE: {
+ const SpaceImage *sima = (SpaceImage *)space_data;
+ TEST_PTR_DATA_TYPE("space_data", RNA_SpaceUVEditor, ptr, sima);
+ break;
+ }
+ case SPACE_NLA: {
+ const SpaceNla *snla = (SpaceNla *)space_data;
+ const bDopeSheet *ads = snla->ads;
+ TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads);
+ break;
+ }
+ case SPACE_ACTION: {
+ const SpaceAction *sact = (SpaceAction *)space_data;
+ const bDopeSheet *ads = &sact->ads;
+ TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads);
+ break;
+ }
+ }
+
break;
}
default:
@@ -502,7 +525,7 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr
}
# undef CTX_TEST_PTR_ID
# undef CTX_TEST_PTR_ID_CAST
-# undef CTX_TEST_SPACE_TYPE
+# undef TEST_PTR_DATA_TYPE
}
return member_id;
@@ -698,6 +721,82 @@ void WM_operator_properties_free(PointerRNA *ptr)
/** \name Default Operator Callbacks
* \{ */
+int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ PropertyRNA *wait_to_deselect_prop = RNA_struct_find_property(op->ptr,
+ "wait_to_deselect_others");
+ const short init_event_type = (short)POINTER_AS_INT(op->customdata);
+ int ret_value = 0;
+
+ /* get settings from RNA properties for operator */
+ int mval[2];
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
+
+ if (init_event_type == 0) {
+ if (event->val == KM_PRESS) {
+ RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, true);
+
+ ret_value = op->type->exec(C, op);
+ OPERATOR_RETVAL_CHECK(ret_value);
+
+ op->customdata = POINTER_FROM_INT((int)event->type);
+ if (ret_value & OPERATOR_RUNNING_MODAL) {
+ WM_event_add_modal_handler(C, op);
+ }
+ return ret_value | OPERATOR_PASS_THROUGH;
+ }
+ else {
+ /* If we are in init phase, and cannot validate init of modal operations,
+ * just fall back to basic exec.
+ */
+ RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false);
+
+ ret_value = op->type->exec(C, op);
+ OPERATOR_RETVAL_CHECK(ret_value);
+
+ return ret_value | OPERATOR_PASS_THROUGH;
+ }
+ }
+ else if (event->type == init_event_type && event->val == KM_RELEASE) {
+ RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false);
+
+ ret_value = op->type->exec(C, op);
+ OPERATOR_RETVAL_CHECK(ret_value);
+
+ return ret_value | OPERATOR_PASS_THROUGH;
+ }
+ else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ const int drag_delta[2] = {
+ mval[0] - event->mval[0],
+ mval[1] - event->mval[1],
+ };
+ /* If user moves mouse more than defined threshold, we consider select operator as
+ * finished. Otherwise, it is still running until we get an 'release' event. In any
+ * case, we pass through event, but select op is not finished yet. */
+ if (WM_event_drag_test_with_delta(event, drag_delta)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+ else {
+ /* Important not to return anything other than PASS_THROUGH here,
+ * otherwise it prevents underlying tweak detection code to work properly. */
+ return OPERATOR_PASS_THROUGH;
+ }
+ }
+
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+}
+
+int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
+ RNA_int_set(op->ptr, "mouse_y", event->mval[1]);
+
+ op->customdata = POINTER_FROM_INT(0);
+
+ return op->type->modal(C, op, event);
+}
+
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op)
{
if (op->flag & OP_IS_INVOKE) {
@@ -1862,6 +1961,7 @@ typedef struct {
StructRNA *image_id_srna;
float initial_value, current_value, min_value, max_value;
int initial_mouse[2];
+ int initial_co[2];
int slow_mouse[2];
bool slow_mode;
Dial *dial;
@@ -1924,6 +2024,9 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
rc->initial_mouse[0] = event->x;
rc->initial_mouse[1] = event->y;
+ rc->initial_co[0] = event->x;
+ rc->initial_co[1] = event->y;
+
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
@@ -1935,7 +2038,7 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
break;
case PROP_FACTOR:
- d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
+ d[0] = rc->initial_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
break;
case PROP_ANGLE:
@@ -1962,8 +2065,10 @@ static void radial_control_set_tex(RadialControl *rc)
switch (RNA_type_to_ID_code(rc->image_id_ptr.type)) {
case ID_BR:
- if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data,
- rc->use_secondary_tex))) {
+ if ((ibuf = BKE_brush_gen_radial_control_imbuf(
+ rc->image_id_ptr.data,
+ rc->use_secondary_tex,
+ !ELEM(rc->subtype, PROP_NONE, PROP_PIXEL, PROP_DISTANCE)))) {
glGenTextures(1, &rc->gltex);
glBindTexture(GL_TEXTURE_2D, rc->gltex);
glTexImage2D(
@@ -2061,6 +2166,22 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
immUnbindProgram();
}
+static void radial_control_paint_curve(uint pos, Brush *br, float radius, int line_segments)
+{
+ GPU_line_width(2.0f);
+ immUniformColor4f(0.8f, 0.8f, 0.8f, 0.85f);
+ float step = (radius * 2.0f) / (float)line_segments;
+ BKE_curvemapping_initialize(br->curve);
+ immBegin(GPU_PRIM_LINES, line_segments * 2);
+ for (int i = 0; i < line_segments; i++) {
+ float h1 = BKE_brush_curve_strength_clamped(br, fabsf((i * step) - radius), radius);
+ immVertex2f(pos, -radius + (i * step), h1 * radius);
+ float h2 = BKE_brush_curve_strength_clamped(br, fabsf(((i + 1) * step) - radius), radius);
+ immVertex2f(pos, -radius + ((i + 1) * step), h2 * radius);
+ }
+ immEnd();
+}
+
static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void *customdata)
{
RadialControl *rc = customdata;
@@ -2094,7 +2215,7 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
alpha = 0.75;
break;
case PROP_FACTOR:
- r1 = (1 - rc->current_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
+ r1 = rc->current_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH +
WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
@@ -2115,9 +2236,17 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
break;
}
- /* Keep cursor in the original place */
- x = rc->initial_mouse[0];
- y = rc->initial_mouse[1];
+ if (rc->subtype == PROP_ANGLE) {
+ /* Use the initial mouse position to draw the rotation preview. This avoids starting the
+ * rotation in a random direction */
+ x = rc->initial_mouse[0];
+ y = rc->initial_mouse[1];
+ }
+ else {
+ /* Keep cursor in the original place */
+ x = rc->initial_co[0];
+ y = rc->initial_co[1];
+ }
GPU_matrix_translate_2f((float)x, (float)y);
GPU_blend(true);
@@ -2141,7 +2270,6 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor3fvAlpha(col, 0.5f);
if (rc->subtype == PROP_ANGLE) {
GPU_matrix_push();
@@ -2164,25 +2292,40 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
}
/* draw circles on top */
- imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 40);
- imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 40);
+ GPU_line_width(2.0f);
+ immUniformColor3fvAlpha(col, 0.8f);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 80);
+
+ GPU_line_width(1.0f);
+ immUniformColor3fvAlpha(col, 0.5f);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 80);
if (rmin > 0.0f) {
- imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 40);
+ /* Inner fill circle to increase the contrast of the value */
+ float black[3] = {0.0f};
+ immUniformColor3fvAlpha(black, 0.2f);
+ imm_draw_circle_fill_2d(pos, 0.0, 0.0f, rmin, 80);
+
+ immUniformColor3fvAlpha(col, 0.5f);
+ imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 80);
}
+
+ /* draw curve falloff preview */
+ if (RNA_type_to_ID_code(rc->image_id_ptr.type) == ID_BR && rc->subtype == PROP_FACTOR) {
+ Brush *br = rc->image_id_ptr.data;
+ if (br) {
+ radial_control_paint_curve(pos, br, r2, 120);
+ }
+ }
+
immUnbindProgram();
- BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi);
- BLF_enable(fontid, BLF_SHADOW);
- BLF_shadow(fontid, 3, (const float[4]){0.0f, 0.0f, 0.0f, 0.5f});
- BLF_shadow_offset(fontid, 1, -1);
+ BLF_size(fontid, 1.75f * fstyle_points * U.pixelsize, U.dpi);
/* draw value */
BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
BLF_draw(fontid, str, strdrawlen);
- BLF_disable(fontid, BLF_SHADOW);
-
GPU_blend(false);
GPU_line_smooth(false);
}
@@ -2575,38 +2718,38 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
}
else {
delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0];
- delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1];
+ delta[1] = 0.0f;
if (rc->zoom_prop) {
RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
delta[0] /= zoom[0];
- delta[1] /= zoom[1];
}
dist = len_v2(delta);
delta[0] = event->x - rc->slow_mouse[0];
- delta[1] = event->y - rc->slow_mouse[1];
if (rc->zoom_prop) {
delta[0] /= zoom[0];
- delta[1] /= zoom[1];
}
- dist = dist + 0.1f * (delta[0] + delta[1]);
+ dist = dist + 0.1f * (delta[0]);
}
}
else {
delta[0] = rc->initial_mouse[0] - event->x;
delta[1] = rc->initial_mouse[1] - event->y;
-
if (rc->zoom_prop) {
RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
delta[0] /= zoom[0];
delta[1] /= zoom[1];
}
-
- dist = len_v2(delta);
+ if (rc->subtype == PROP_ANGLE) {
+ dist = len_v2(delta);
+ }
+ else {
+ dist = clamp_f(-delta[0], 0.0f, FLT_MAX);
+ }
}
/* calculate new value and apply snapping */
@@ -2633,6 +2776,8 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
if (snap) {
new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f;
}
+ /* Invert new value to increase the factor moving the mouse to the right */
+ new_value = 1 - new_value;
break;
case PROP_ANGLE:
new_value = atan2f(delta[1], delta[0]) + (float)M_PI + angle_precision;
diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c
new file mode 100644
index 00000000000..94eceafc59b
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_platform_support.c
@@ -0,0 +1,219 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup wm
+ */
+#include "wm_platform_support.h"
+#include "wm_window_private.h"
+
+#include <string.h>
+
+#include "BLI_sys_types.h"
+#include "BLI_dynstr.h"
+#include "BLI_path_util.h"
+#include "BLI_fileops.h"
+#include "BLI_string.h"
+#include "BLI_linklist.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_appdir.h"
+#include "BKE_global.h"
+
+#include "GPU_platform.h"
+
+#include "GHOST_C-api.h"
+
+#define WM_PLATFORM_SUPPORT_TEXT_SIZE 1024
+
+/* Check if user has already approved the given platform_support_key. */
+static bool wm_platform_support_check_approval(const char *platform_support_key, bool update)
+{
+ const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
+ bool result = false;
+
+ if (G.factory_startup) {
+ return result;
+ }
+
+ if (cfgdir) {
+ char filepath[FILE_MAX];
+ BLI_make_file_string("/", filepath, cfgdir, BLENDER_PLATFORM_SUPPORT_FILE);
+ LinkNode *lines = BLI_file_read_as_lines(filepath);
+ for (LinkNode *line_node = lines; line_node; line_node = line_node->next) {
+ char *line = line_node->link;
+ if (STREQ(line, platform_support_key)) {
+ result = true;
+ break;
+ }
+ }
+
+ if (!result && update) {
+ FILE *fp = BLI_fopen(filepath, "a");
+ if (fp) {
+ fprintf(fp, "%s\n", platform_support_key);
+ fclose(fp);
+ }
+ }
+
+ BLI_file_free_lines(lines);
+ }
+ return result;
+}
+
+static void wm_platform_support_create_link(char *link)
+{
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, "https://docs.blender.org/manual/en/dev/troubleshooting/gpu/");
+#if defined(_WIN32)
+ BLI_dynstr_append(ds, "windows/");
+#elif defined(__APPLE__)
+ BLI_dynstr_append(ds, "apple/");
+#else /* UNIX */
+ BLI_dynstr_append(ds, "linux/");
+#endif
+
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ BLI_dynstr_append(ds, "intel.html");
+ }
+ else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ BLI_dynstr_append(ds, "nvidia.html");
+ }
+ else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ BLI_dynstr_append(ds, "amd.html");
+ }
+ else {
+ BLI_dynstr_append(ds, "unknown.html");
+ }
+
+ BLI_assert(BLI_dynstr_get_len(ds) < WM_PLATFORM_SUPPORT_TEXT_SIZE);
+ BLI_dynstr_get_cstring_ex(ds, link);
+ BLI_dynstr_free(ds);
+}
+
+bool WM_platform_support_perform_checks()
+{
+ char title[WM_PLATFORM_SUPPORT_TEXT_SIZE];
+ char message[WM_PLATFORM_SUPPORT_TEXT_SIZE];
+ char link[WM_PLATFORM_SUPPORT_TEXT_SIZE];
+
+ bool result = true;
+
+ eGPUSupportLevel support_level = GPU_platform_support_level();
+ const char *platform_key = GPU_platform_support_level_key();
+
+ /* check if previous check matches the current check. Don't update the approval when running in
+ * `background`. this could have been triggered by installing addons via installers. */
+ if (support_level != GPU_SUPPORT_LEVEL_UNSUPPORTED && !G.factory_startup &&
+ wm_platform_support_check_approval(platform_key, !G.background)) {
+ /* if it matches the user has confirmed and whishes to use it */
+ return result;
+ }
+
+ /* update the message and link based on the found support level */
+ GHOST_DialogOptions dialog_options = 0;
+
+ switch (support_level) {
+ default:
+ case GPU_SUPPORT_LEVEL_SUPPORTED:
+ break;
+
+ case GPU_SUPPORT_LEVEL_LIMITED: {
+ size_t slen = 0;
+ STR_CONCAT(title, slen, "Blender - ");
+ STR_CONCAT(
+ title, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Limited Platform Support"));
+ slen = 0;
+ STR_CONCAT(
+ message,
+ slen,
+ CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER,
+ "Your graphics card or driver has limited support. It may work, but with "
+ "issues."));
+
+ /* TODO: Extra space is needed for the split function in GHOST_SystemX11. We should change
+ * the behavior in GHOST_SystemX11. */
+ STR_CONCAT(message, slen, "\n \n");
+ STR_CONCAT(
+ message,
+ slen,
+ CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER,
+ "Newer graphics drivers may be available to improve Blender support."));
+ STR_CONCAT(message, slen, "\n \n");
+ STR_CONCAT(message, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Graphics card:\n"));
+ STR_CONCAT(message, slen, GPU_platform_gpu_name());
+
+ dialog_options = GHOST_DialogWarning;
+ break;
+ }
+
+ case GPU_SUPPORT_LEVEL_UNSUPPORTED: {
+ size_t slen = 0;
+ STR_CONCAT(title, slen, "Blender - ");
+ STR_CONCAT(
+ title, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Platform Unsupported"));
+ slen = 0;
+ STR_CONCAT(message,
+ slen,
+ CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER,
+ "Your graphics card or driver is not supported."));
+
+ STR_CONCAT(message, slen, "\n \n");
+ STR_CONCAT(
+ message,
+ slen,
+ CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER,
+ "Newer graphics drivers may be available to improve Blender support."));
+
+ STR_CONCAT(message, slen, "\n \n");
+ STR_CONCAT(message, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Graphics card:\n"));
+ STR_CONCAT(message, slen, GPU_platform_gpu_name());
+ STR_CONCAT(message, slen, "\n \n");
+
+ STR_CONCAT(message,
+ slen,
+ CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "The program will now close."));
+ dialog_options = GHOST_DialogError;
+ result = false;
+ break;
+ }
+ }
+ wm_platform_support_create_link(link);
+
+ bool show_message = ELEM(
+ support_level, GPU_SUPPORT_LEVEL_LIMITED, GPU_SUPPORT_LEVEL_UNSUPPORTED);
+
+ /* We are running in the background print the message in the console. */
+ if ((G.background || G.debug & G_DEBUG) && show_message) {
+ printf("%s\n\n%s\n%s\n", title, message, link);
+ }
+ if (G.background) {
+ /* Don't show the message-box when running in background mode.
+ * Printing to console is enough. */
+ result = true;
+ }
+ else if (show_message) {
+ WM_ghost_show_message_box(
+ title, message, "Find Latest Drivers", "Continue Anyway", link, dialog_options);
+ }
+
+ return result;
+}
diff --git a/source/blender/windowmanager/intern/wm_platform_support.h b/source/blender/windowmanager/intern/wm_platform_support.h
new file mode 100644
index 00000000000..a8e20f6bcdf
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_platform_support.h
@@ -0,0 +1,30 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup wm
+ */
+#ifndef __WM_PLATFORM_SUPPORT_H__
+#define __WM_PLATFORM_SUPPORT_H__
+
+#include "BLI_sys_types.h"
+
+bool WM_platform_support_perform_checks(void);
+
+#endif
diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c
index d3f7661a008..3603ce81654 100644
--- a/source/blender/windowmanager/intern/wm_splash_screen.c
+++ b/source/blender/windowmanager/intern/wm_splash_screen.c
@@ -178,68 +178,79 @@ static void wm_block_splash_add_labels(uiBlock *block, int x, int y)
#endif /* WITH_BUILDINFO */
}
-static ImBuf *wm_block_splash_image(void)
+static ImBuf *wm_block_splash_image(int r_unit_size[2])
{
#ifndef WITH_HEADLESS
extern char datatoc_splash_png[];
extern int datatoc_splash_png_size;
extern char datatoc_splash_2x_png[];
extern int datatoc_splash_2x_png_size;
+ const bool is_2x = U.dpi_fac > 1.0;
+ const int imb_scale = is_2x ? 2 : 1;
- ImBuf *ibuf = NULL;
+ /* We could allow this to be variable,
+ * for now don't since allowing it might create layout issues.
+ *
+ * Only check width because splashes sometimes change height
+ * and we don't want to break app-templates. */
+ const int x_expect = 501 * imb_scale;
- if (U.dpi_fac > 1.0) {
- ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_2x_png,
- datatoc_splash_2x_png_size,
- IB_rect,
- NULL,
- "<splash screen>");
- }
- else {
- ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_png,
- datatoc_splash_png_size,
- IB_rect,
- NULL,
- "<splash screen>");
- }
+ ImBuf *ibuf = NULL;
- /* overwrite splash with template image */
if (U.app_template[0] != '\0') {
- ImBuf *ibuf_template = NULL;
char splash_filepath[FILE_MAX];
char template_directory[FILE_MAX];
-
if (BKE_appdir_app_template_id_search(
U.app_template, template_directory, sizeof(template_directory))) {
BLI_join_dirfile(splash_filepath,
sizeof(splash_filepath),
template_directory,
- (U.dpi_fac > 1.0) ? "splash_2x.png" : "splash.png");
- ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL);
- if (ibuf_template) {
- const int x_expect = ibuf->x;
- const int y_expect = 250 * (int)U.dpi_fac;
- /* don't cover the header text */
- if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) {
- memcpy(ibuf->rect,
- ibuf_template->rect,
- ibuf_template->x * ibuf_template->y * sizeof(char[4]));
- }
- else {
- CLOG_ERROR(WM_LOG_OPERATORS,
- "Splash expected %dx%d found %dx%d, ignoring: %s\n",
- x_expect,
- y_expect,
- ibuf_template->x,
- ibuf_template->y,
- splash_filepath);
- }
- IMB_freeImBuf(ibuf_template);
+ is_2x ? "splash_2x.png" : "splash.png");
+ ibuf = IMB_loadiffname(splash_filepath, IB_rect, NULL);
+
+ /* We could skip this check, see comment about 'x_expect' above. */
+ if (ibuf && ibuf->x != x_expect) {
+ CLOG_ERROR(WM_LOG_OPERATORS,
+ "Splash expected %d width found %d, ignoring: %s\n",
+ x_expect,
+ ibuf->x,
+ splash_filepath);
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
}
}
}
+
+ if (ibuf == NULL) {
+ const uchar *splash_data;
+ size_t splash_data_size;
+
+ if (is_2x) {
+ splash_data = (const uchar *)datatoc_splash_2x_png;
+ splash_data_size = datatoc_splash_2x_png_size;
+ }
+ else {
+ splash_data = (const uchar *)datatoc_splash_png;
+ splash_data_size = datatoc_splash_png_size;
+ }
+
+ ibuf = IMB_ibImageFromMemory(splash_data, splash_data_size, IB_rect, NULL, "<splash screen>");
+
+ BLI_assert(ibuf->x == x_expect);
+ }
+
+ if (is_2x) {
+ r_unit_size[0] = ibuf->x / 2;
+ r_unit_size[1] = ibuf->y / 2;
+ }
+ else {
+ r_unit_size[0] = ibuf->x;
+ r_unit_size[1] = ibuf->y;
+ }
+
return ibuf;
#else
+ UNUSED_VARS(r_unit_size);
return NULL;
#endif
}
@@ -258,15 +269,17 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
- ImBuf *ibuf = wm_block_splash_image();
+ /* Size before dpi scaling (halved for hi-dpi image). */
+ int ibuf_unit_size[2];
+ ImBuf *ibuf = wm_block_splash_image(ibuf_unit_size);
but = uiDefBut(block,
UI_BTYPE_IMAGE,
0,
"",
0,
0.5f * U.widget_unit,
- U.dpi_fac * 501,
- U.dpi_fac * 250,
+ U.dpi_fac * ibuf_unit_size[0],
+ U.dpi_fac * ibuf_unit_size[1],
/* Button owns the imbuf now. */
ibuf,
0.0,
@@ -277,17 +290,18 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
UI_but_func_set(but, wm_block_splash_close, block, NULL);
UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL);
- int x = U.dpi_fac * 502;
- int y = U.dpi_fac * 237;
+ int x = U.dpi_fac * (ibuf_unit_size[0] + 1);
+ int y = U.dpi_fac * (ibuf_unit_size[1] - 13);
wm_block_splash_add_labels(block, x, y);
+ const int layout_margin_x = U.dpi_fac * 26;
uiLayout *layout = UI_block_layout(block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- U.dpi_fac * 26,
+ layout_margin_x,
0,
- U.dpi_fac * 450,
+ (U.dpi_fac * ibuf_unit_size[0]) - (layout_margin_x * 2),
U.dpi_fac * 110,
0,
style);
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 7437001cdfc..fa2320585d7 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -61,7 +61,9 @@
#include "wm.h"
#include "wm_draw.h"
#include "wm_files.h"
+#include "wm_platform_support.h"
#include "wm_window.h"
+#include "wm_window_private.h"
#include "wm_event_system.h"
#include "ED_anim_api.h"
@@ -78,7 +80,7 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
#include "GPU_draw.h"
-#include "GPU_extensions.h"
+#include "GPU_platform.h"
#include "GPU_framebuffer.h"
#include "GPU_init_exit.h"
#include "GPU_immediate.h"
@@ -409,8 +411,10 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
/* this is event from ghost, or exit-blender op */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
- /* First check if there is another main window remaining. */
wmWindow *win_other;
+ const bool is_dialog = GHOST_IsDialogWindow(win->ghostwin);
+
+ /* First check if there is another main window remaining. */
for (win_other = wm->windows.first; win_other; win_other = win_other->next) {
if (win_other != win && win_other->parent == NULL && !WM_window_is_temp_screen(win_other)) {
break;
@@ -422,10 +426,15 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
return;
}
- /* close child windows */
- for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
- if (win_child->parent == win) {
- wm_window_close(C, wm, win_child);
+ /* Close child windows and bring windows back to front that dialogs have pushed behind the main
+ * window. */
+ for (wmWindow *iter_win = wm->windows.first; iter_win; iter_win = iter_win->next) {
+ if (iter_win->parent == win) {
+ wm_window_close(C, wm, iter_win);
+ }
+ else if (is_dialog && iter_win != win && iter_win->parent &&
+ (GHOST_GetWindowState(iter_win->ghostwin) != GHOST_kWindowStateMinimized)) {
+ wm_window_raise(iter_win);
}
}
@@ -547,7 +556,10 @@ static void wm_window_ensure_eventstate(wmWindow *win)
}
/* belongs to below */
-static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win)
+static void wm_window_ghostwindow_add(wmWindowManager *wm,
+ const char *title,
+ wmWindow *win,
+ bool is_dialog)
{
GHOST_WindowHandle ghostwin;
GHOST_GLSettings glSettings = {0};
@@ -569,15 +581,29 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
wmWindow *prev_windrawable = wm->windrawable;
wm_window_clear_drawable(wm);
- ghostwin = GHOST_CreateWindow(g_system,
- title,
- win->posx,
- posy,
- win->sizex,
- win->sizey,
- (GHOST_TWindowState)win->windowstate,
- GHOST_kDrawingContextTypeOpenGL,
- glSettings);
+ if (is_dialog && win->parent) {
+ ghostwin = GHOST_CreateDialogWindow(g_system,
+ win->parent->ghostwin,
+ title,
+ win->posx,
+ posy,
+ win->sizex,
+ win->sizey,
+ (GHOST_TWindowState)win->windowstate,
+ GHOST_kDrawingContextTypeOpenGL,
+ glSettings);
+ }
+ else {
+ ghostwin = GHOST_CreateWindow(g_system,
+ title,
+ win->posx,
+ posy,
+ win->sizex,
+ win->sizey,
+ (GHOST_TWindowState)win->windowstate,
+ GHOST_kDrawingContextTypeOpenGL,
+ glSettings);
+ }
if (ghostwin) {
GHOST_RectangleHandle bounds;
@@ -635,6 +661,68 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
}
}
+static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, bool is_dialog)
+{
+ wmKeyMap *keymap;
+
+ if (win->ghostwin == NULL) {
+ if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) {
+ win->posx = wm_init_state.start_x;
+ win->posy = wm_init_state.start_y;
+ win->sizex = wm_init_state.size_x;
+ win->sizey = wm_init_state.size_y;
+
+ if (wm_init_state.override_flag & WIN_OVERRIDE_GEOM) {
+ win->windowstate = GHOST_kWindowStateNormal;
+ wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM;
+ }
+ else {
+ win->windowstate = GHOST_WINDOW_STATE_DEFAULT;
+ }
+ }
+
+ if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) {
+ win->windowstate = wm_init_state.windowstate;
+ wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE;
+ }
+
+ /* without this, cursor restore may fail, T45456 */
+ if (win->cursor == 0) {
+ win->cursor = WM_CURSOR_DEFAULT;
+ }
+
+ wm_window_ghostwindow_add(wm, "Blender", win, is_dialog);
+ }
+
+ if (win->ghostwin != NULL) {
+ /* If we have no ghostwin this is a buggy window that should be removed.
+ * However we still need to initialize it correctly so the screen doesn't hang. */
+
+ /* happens after fileread */
+ wm_window_ensure_eventstate(win);
+ }
+
+ /* add keymap handlers (1 handler for all keys in map!) */
+ keymap = WM_keymap_ensure(wm->defaultconf, "Window", 0, 0);
+ WM_event_add_keymap_handler(&win->handlers, keymap);
+
+ keymap = WM_keymap_ensure(wm->defaultconf, "Screen", 0, 0);
+ WM_event_add_keymap_handler(&win->handlers, keymap);
+
+ keymap = WM_keymap_ensure(wm->defaultconf, "Screen Editing", 0, 0);
+ WM_event_add_keymap_handler(&win->modalhandlers, keymap);
+
+ /* add drop boxes */
+ {
+ ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
+ WM_event_add_dropbox_handler(&win->handlers, lb);
+ }
+ wm_window_title(wm, win);
+
+ /* add topbar */
+ ED_screen_global_areas_refresh(win);
+}
+
/**
* Initialize #wmWindow without ghostwin, open these and clear.
*
@@ -650,9 +738,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
*/
void wm_window_ghostwindows_ensure(wmWindowManager *wm)
{
- wmKeyMap *keymap;
- wmWindow *win;
-
BLI_assert(G.background == false);
/* No command-line prefsize? then we set this.
@@ -682,63 +767,8 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
#endif
}
- for (win = wm->windows.first; win; win = win->next) {
- if (win->ghostwin == NULL) {
- if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) {
- win->posx = wm_init_state.start_x;
- win->posy = wm_init_state.start_y;
- win->sizex = wm_init_state.size_x;
- win->sizey = wm_init_state.size_y;
-
- if (wm_init_state.override_flag & WIN_OVERRIDE_GEOM) {
- win->windowstate = GHOST_kWindowStateNormal;
- wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM;
- }
- else {
- win->windowstate = GHOST_WINDOW_STATE_DEFAULT;
- }
- }
-
- if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) {
- win->windowstate = wm_init_state.windowstate;
- wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE;
- }
-
- /* without this, cursor restore may fail, T45456 */
- if (win->cursor == 0) {
- win->cursor = CURSOR_STD;
- }
-
- wm_window_ghostwindow_add(wm, "Blender", win);
- }
-
- if (win->ghostwin != NULL) {
- /* If we have no ghostwin this is a buggy window that should be removed.
- * However we still need to initialize it correctly so the screen doesn't hang. */
-
- /* happens after fileread */
- wm_window_ensure_eventstate(win);
- }
-
- /* add keymap handlers (1 handler for all keys in map!) */
- keymap = WM_keymap_ensure(wm->defaultconf, "Window", 0, 0);
- WM_event_add_keymap_handler(&win->handlers, keymap);
-
- keymap = WM_keymap_ensure(wm->defaultconf, "Screen", 0, 0);
- WM_event_add_keymap_handler(&win->handlers, keymap);
-
- keymap = WM_keymap_ensure(wm->defaultconf, "Screen Editing", 0, 0);
- WM_event_add_keymap_handler(&win->modalhandlers, keymap);
-
- /* add drop boxes */
- {
- ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
- WM_event_add_dropbox_handler(&win->handlers, lb);
- }
- wm_window_title(wm, win);
-
- /* add topbar */
- ED_screen_global_areas_refresh(win);
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ wm_window_ghostwindow_ensure(wm, win, false);
}
}
@@ -792,20 +822,26 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
* Uses `screen->temp` tag to define what to do, currently it limits
* to only one "temp" window for render out, preferences, filewindow, etc...
*
- * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
- * \return the window or NULL.
+ * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
+ * \return the window or NULL in case of failure.
*/
-wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
+wmWindow *WM_window_open_temp(bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ int space_type,
+ bool dialog)
{
Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
bScreen *screen;
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- eSpace_Type space_type = SPACE_EMPTY;
- const char *title;
/* convert to native OS window coordinates */
const float native_pixel_size = GHOST_GetNativePixelSize(win_prev->ghostwin);
@@ -824,9 +860,10 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
/* changes rect to fit within desktop */
wm_window_check_position(&rect);
- /* test if we have a temp screen already */
- for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
- if (WM_window_is_temp_screen(win)) {
+ /* Reuse temporary or dialog window if one is open (but don't use a dialog for a regular
+ * temporary window, or vice versa). */
+ for (win = wm->windows.first; win; win = win->next) {
+ if (WM_window_is_temp_screen(win) && (dialog == GHOST_IsDialogWindow(win->ghostwin))) {
break;
}
}
@@ -844,11 +881,6 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
win->sizex = BLI_rcti_size_x(&rect);
win->sizey = BLI_rcti_size_y(&rect);
- if (win->ghostwin) {
- wm_window_set_size(win, win->sizex, win->sizey);
- wm_window_raise(win);
- }
-
if (WM_window_get_active_workspace(win) == NULL) {
WorkSpace *workspace = WM_window_get_active_workspace(win_prev);
BKE_workspace_active_set(win->workspace_hook, workspace);
@@ -873,6 +905,9 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
/* make window active, and validate/resize */
CTX_wm_window_set(C, win);
+ if (!win->ghostwin) {
+ wm_window_ghostwindow_ensure(wm, win, dialog);
+ }
WM_check(C);
/* It's possible `win->ghostwin == NULL`.
@@ -885,60 +920,21 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
sa = screen->areabase.first;
CTX_wm_area_set(C, sa);
- if (type == WM_WINDOW_RENDER) {
- space_type = SPACE_IMAGE;
- }
- else if (type == WM_WINDOW_DRIVERS) {
- space_type = SPACE_GRAPH;
- }
- else if (type == WM_WINDOW_USERPREFS) {
- space_type = SPACE_USERPREF;
- }
- else if (type == WM_WINDOW_FILESEL) {
- space_type = SPACE_FILE;
- }
- else if (type == WM_WINDOW_INFO) {
- space_type = SPACE_INFO;
- }
- else {
- BLI_assert(false);
- }
ED_area_newspace(C, sa, space_type, false);
ED_screen_change(C, screen);
- ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
-
- /* do additional setup for specific editor type */
- if (type == WM_WINDOW_DRIVERS) {
- ED_drivers_editor_init(C, sa);
- }
-
- if (sa->spacetype == SPACE_IMAGE) {
- title = IFACE_("Blender Render");
- }
- else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF)) {
- title = IFACE_("Blender Preferences");
- }
- else if (sa->spacetype == SPACE_FILE) {
- title = IFACE_("Blender File View");
- }
- else if (sa->spacetype == SPACE_GRAPH) {
- title = IFACE_("Blender Drivers Editor");
- }
- else if (sa->spacetype == SPACE_INFO) {
- title = IFACE_("Blender Info Log");
- }
- else {
- title = "Blender";
- }
+ ED_screen_refresh(wm, win); /* test scale */
if (win->ghostwin) {
+ wm_window_set_size(win, win->sizex, win->sizey);
+ wm_window_raise(win);
+
GHOST_SetTitle(win->ghostwin, title);
return win;
}
else {
/* very unlikely! but opening a new window can fail */
- wm_window_close(C, CTX_wm_manager(C), win);
+ wm_window_close(C, wm, win);
CTX_wm_window_set(C, win_prev);
return NULL;
@@ -2437,4 +2433,14 @@ void WM_opengl_context_release(void *context)
GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context);
}
+void WM_ghost_show_message_box(const char *title,
+ const char *message,
+ const char *help_label,
+ const char *continue_label,
+ const char *link,
+ GHOST_DialogOptions dialog_options)
+{
+ BLI_assert(g_system);
+ GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options);
+}
/** \} */
diff --git a/source/blender/windowmanager/intern/wm_window_private.h b/source/blender/windowmanager/intern/wm_window_private.h
new file mode 100644
index 00000000000..115539861d7
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_window_private.h
@@ -0,0 +1,42 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup wm
+ */
+#ifndef __WM_WINDOW_PRIVATE_H__
+#define __WM_WINDOW_PRIVATE_H__
+
+#include "BLI_sys_types.h"
+#include "GHOST_Types.h"
+
+/* *************** Message box *************** */
+/* `WM_ghost_show_message_box` is implemented in `wm_windows.c` it is
+ * defined here as it was implemented to be used for showing
+ * a message to the user when the platform is not (fully) supported.
+ *
+ * In all other cases this message box should not be used. */
+void WM_ghost_show_message_box(const char *title,
+ const char *message,
+ const char *help_label,
+ const char *continue_label,
+ const char *link,
+ GHOST_DialogOptions dialog_options);
+
+#endif
diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h
index 6793937c413..7a28aeb3c70 100644
--- a/source/blender/windowmanager/wm_cursors.h
+++ b/source/blender/windowmanager/wm_cursors.h
@@ -24,80 +24,57 @@
#ifndef __WM_CURSORS_H__
#define __WM_CURSORS_H__
-void wm_init_cursor_data(void);
-
-#define BC_GHOST_CURSORS 1000
-
-/* old cursors */
-enum {
- CURSOR_FACESEL = BC_GHOST_CURSORS,
- CURSOR_WAIT,
- CURSOR_EDIT,
- CURSOR_X_MOVE,
- CURSOR_Y_MOVE,
- CURSOR_HELP,
- CURSOR_STD,
- CURSOR_NONE,
- CURSOR_PENCIL,
- CURSOR_COPY,
-};
-
-// typedef struct BCursor_s BCursor;
-typedef struct BCursor {
-
- char *small_bm;
- char *small_mask;
-
- char small_sizex;
- char small_sizey;
- char small_hotx;
- char small_hoty;
-
- char *big_bm;
- char *big_mask;
-
- char big_sizex;
- char big_sizey;
- char big_hotx;
- char big_hoty;
-
- bool can_invert_color;
+struct wmEvent;
+struct wmWindow;
-} BCursor;
+typedef enum WMCursorType {
+ WM_CURSOR_DEFAULT = 1,
+ WM_CURSOR_TEXT_EDIT,
+ WM_CURSOR_WAIT,
+ WM_CURSOR_STOP,
+ WM_CURSOR_EDIT,
+ WM_CURSOR_COPY,
+ WM_CURSOR_HAND,
+
+ WM_CURSOR_CROSS,
+ WM_CURSOR_PAINT,
+ WM_CURSOR_DOT,
+ WM_CURSOR_CROSSC,
+
+ WM_CURSOR_KNIFE,
+ WM_CURSOR_VERTEX_LOOP,
+ WM_CURSOR_PAINT_BRUSH,
+ WM_CURSOR_ERASER,
+ WM_CURSOR_EYEDROPPER,
+
+ WM_CURSOR_SWAP_AREA,
+ WM_CURSOR_X_MOVE,
+ WM_CURSOR_Y_MOVE,
+ WM_CURSOR_H_SPLIT,
+ WM_CURSOR_V_SPLIT,
+
+ WM_CURSOR_NW_ARROW,
+ WM_CURSOR_NS_ARROW,
+ WM_CURSOR_EW_ARROW,
+ WM_CURSOR_N_ARROW,
+ WM_CURSOR_S_ARROW,
+ WM_CURSOR_E_ARROW,
+ WM_CURSOR_W_ARROW,
+
+ WM_CURSOR_NSEW_SCROLL,
+ WM_CURSOR_NS_SCROLL,
+ WM_CURSOR_EW_SCROLL,
+
+ WM_CURSOR_ZOOM_IN,
+ WM_CURSOR_ZOOM_OUT,
+
+ WM_CURSOR_NONE,
-#define SYSCURSOR 1
-enum {
- BC_NW_ARROWCURSOR = 2,
- BC_NS_ARROWCURSOR,
- BC_EW_ARROWCURSOR,
- BC_WAITCURSOR,
- BC_CROSSCURSOR,
- BC_EDITCROSSCURSOR,
- BC_BOXSELCURSOR,
- BC_KNIFECURSOR,
- BC_VLOOPCURSOR,
- BC_TEXTEDITCURSOR,
- BC_PAINTBRUSHCURSOR,
- BC_HANDCURSOR,
- BC_NSEW_SCROLLCURSOR,
- BC_NS_SCROLLCURSOR,
- BC_EW_SCROLLCURSOR,
- BC_EYEDROPPER_CURSOR,
- BC_SWAPAREA_CURSOR,
- BC_H_SPLITCURSOR,
- BC_V_SPLITCURSOR,
- BC_N_ARROWCURSOR,
- BC_S_ARROWCURSOR,
- BC_E_ARROWCURSOR,
- BC_W_ARROWCURSOR,
- BC_STOPCURSOR,
/* --- ALWAYS LAST ----- */
- BC_NUMCURSORS,
-};
-
-struct wmEvent;
-struct wmWindow;
+ WM_CURSOR_NUM,
+} WMCursorType;
+void wm_init_cursor_data(void);
bool wm_cursor_arrow_move(struct wmWindow *win, const struct wmEvent *event);
#endif /* __WM_CURSORS_H__ */
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index e1326d62ae0..50b4f3edfa9 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -133,7 +133,7 @@ if(WIN32 AND NOT UNIX)
string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2)
string(SUBSTRING ${BLENDER_VERSION} 3 1 bver3)
add_definitions(
- -DBLEN_VER_RC_STR=${BLENDER_VERSION}
+ -DBLEN_VER_RC_STR="${BLENDER_VERSION}"
-DBLEN_VER_RC_1=${bver1}
-DBLEN_VER_RC_2=${bver2}
-DBLEN_VER_RC_3=${bver3}
@@ -513,6 +513,16 @@ if(UNIX AND NOT APPLE)
DESTINATION "."
)
+ if(EXISTS ${LIBDIR}/mesa)
+ install(DIRECTORY ${LIBDIR}/mesa/lib DESTINATION ".")
+
+ install(
+ PROGRAMS
+ ${CMAKE_SOURCE_DIR}/release/bin/blender-softwaregl
+ DESTINATION "."
+ )
+ endif()
+
set(BLENDER_TEXT_FILES_DESTINATION ".")
else()
# main blender binary
@@ -674,6 +684,13 @@ elseif(WIN32)
set(BLENDER_TEXT_FILES_DESTINATION ".")
+ if(WITH_OPENMP AND MSVC_CLANG)
+ install(
+ FILES ${CLANG_OPENMP_DLL}
+ DESTINATION "."
+ )
+ endif()
+
if(WITH_PYTHON)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
@@ -748,13 +765,13 @@ elseif(WIN32)
if(WINDOWS_PYTHON_DEBUG)
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.pdb
+ FILES ${LIBDIR}/python/37/libs/python${_PYTHON_VERSION_NO_DOTS}.pdb
DESTINATION "."
CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
)
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.pdb
+ FILES ${LIBDIR}/python/37/libs/python${_PYTHON_VERSION_NO_DOTS}_d.pdb
DESTINATION "."
CONFIGURATIONS Debug
)
@@ -837,8 +854,10 @@ elseif(WIN32)
)
endif()
elseif(APPLE)
- # Uppercase name for app bundle
- set_target_properties(blender PROPERTIES OUTPUT_NAME Blender)
+ if(NOT WITH_PYTHON_MODULE)
+ # Uppercase name for app bundle
+ set_target_properties(blender PROPERTIES OUTPUT_NAME Blender)
+ endif()
# handy install macro to exclude files, we use \$ escape for the "to"
# argument when calling so ${BUILD_TYPE} does not get expanded
@@ -1023,7 +1042,7 @@ setup_liblinks(blender)
# vcpkg substitutes our libs with theirs, which will cause issues when you
# you run these builds on other systems due to missing dlls. So we opt out
# the use of vcpkg
-if (WIN32)
+if(WIN32)
set_target_properties(blender PROPERTIES VS_GLOBAL_VcpkgEnabled "false")
endif()
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 850608bf83c..936bdf52c91 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -874,7 +874,7 @@ static int arg_handle_log_set(int argc, const char **argv, void *UNUSED(data))
}
if (str_step_end) {
- /* typically only be one, but don't fail on multiple.*/
+ /* Typically only be one, but don't fail on multiple. */
while (*str_step_end == ',') {
str_step_end++;
}
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index 5a5bc74d2d3..e8c6e9251bc 100644
--- a/source/creator/creator_signals.c
+++ b/source/creator/creator_signals.c
@@ -301,6 +301,12 @@ void main_signal_setup(void)
# endif
}
+# ifdef WIN32
+ /* Prevent any error mode dialogs from hanging the application. */
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX);
+# endif
+
if (app_state.signal.use_abort_handler) {
signal(SIGABRT, sig_handle_abort);
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 7d8a1390628..94b6e49181c 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -4,6 +4,7 @@
#
# Getting the install path of the executable is somewhat involved, as there are
# no direct CMake generator expressions to get the install paths of executables.
+get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(GENERATOR_IS_MULTI_CONFIG)
string(REPLACE "\${BUILD_TYPE}" "$<CONFIG>" TEST_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
else()
diff --git a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
index 315e5804784..8b29128eb0d 100644
--- a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
+++ b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
@@ -667,6 +667,32 @@ TEST(delaunay, TriCutoff)
BLI_delaunay_2d_cdt_free(out);
}
+TEST(delaunay, TriInTri)
+{
+ CDT_input in;
+ CDT_result *out;
+ float p[][2] = {
+ {-5.65685f, 0.0f},
+ {1.41421f, -5.83095f},
+ {0.0f, 0.0f},
+ {-2.47487f, -1.45774f},
+ {-0.707107f, -2.91548f},
+ {-1.06066f, -1.45774f},
+ };
+ int f[] = {0, 1, 2, 3, 4, 5};
+ int fstart[] = {0, 3};
+ int flen[] = {3, 3};
+
+ fill_input_verts(&in, p, 6);
+ add_input_faces(&in, f, fstart, flen, 2);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
+ EXPECT_EQ(out->verts_len, 6);
+ EXPECT_EQ(out->edges_len, 8);
+ EXPECT_EQ(out->faces_len, 3);
+ BLI_delaunay_2d_cdt_free(out);
+}
+
+#if 0
enum {
RANDOM_PTS,
RANDOM_SEGS,
@@ -739,12 +765,12 @@ static void rand_delaunay_test(int test_kind,
times[lg_size] += PIL_check_seconds_timer() - tstart;
}
}
-#ifdef DO_TIMING
+# ifdef DO_TIMING
fprintf(stderr, "size,time\n");
for (lg_size = 0; lg_size <= max_lg_size; lg_size++) {
fprintf(stderr, "%d,%f\n", 1 << lg_size, times[lg_size] / reps_per_size);
}
-#endif
+# endif
MEM_freeN(p);
if (e)
MEM_freeN(e);
@@ -781,6 +807,7 @@ TEST(delaunay, randompoly_validbmesh)
{
rand_delaunay_test(RANDOM_POLY, 7, 1, CDT_CONSTRAINTS_VALID_BMESH);
}
+#endif
#if 0
/* For debugging or timing large examples.
diff --git a/tests/gtests/blenlib/BLI_kdopbvh_test.cc b/tests/gtests/blenlib/BLI_kdopbvh_test.cc
index bd35a491550..ac0d477ee14 100644
--- a/tests/gtests/blenlib/BLI_kdopbvh_test.cc
+++ b/tests/gtests/blenlib/BLI_kdopbvh_test.cc
@@ -50,7 +50,7 @@ TEST(kdopbvh, Single)
BLI_bvhtree_free(tree);
}
-void optimal_check_callback(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void optimal_check_callback(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
{
float(*points)[3] = (float(*)[3])userdata;
diff --git a/tests/gtests/blenlib/BLI_map_test.cc b/tests/gtests/blenlib/BLI_map_test.cc
index 8d5b178aea6..e91f809abba 100644
--- a/tests/gtests/blenlib/BLI_map_test.cc
+++ b/tests/gtests/blenlib/BLI_map_test.cc
@@ -2,7 +2,8 @@
#include "BLI_map.h"
#include "BLI_set.h"
-using IntFloatMap = BLI::Map<int, float>;
+using BLI::Map;
+using IntFloatMap = Map<int, float>;
TEST(map, DefaultConstructor)
{
@@ -155,7 +156,7 @@ TEST(map, ItemIterator)
EXPECT_TRUE(values.contains(0.0f));
}
-float return_42()
+static float return_42()
{
return 42.0f;
}
@@ -179,11 +180,17 @@ TEST(map, LookupOrAdd_Lambdas)
EXPECT_EQ(map.lookup_or_add(1, lambda1), 20.0f);
}
-TEST(map, InsertOrModify)
+TEST(map, AddOrModify)
{
IntFloatMap map;
- auto create_func = []() { return 10.0f; };
- auto modify_func = [](float &value) { value += 5; };
+ auto create_func = [](float *value) {
+ *value = 10.0f;
+ return true;
+ };
+ auto modify_func = [](float *value) {
+ *value += 5;
+ return false;
+ };
EXPECT_TRUE(map.add_or_modify(1, create_func, modify_func));
EXPECT_EQ(map.lookup(1), 10.0f);
EXPECT_FALSE(map.add_or_modify(1, create_func, modify_func));
@@ -258,3 +265,24 @@ TEST(map, Clear)
EXPECT_FALSE(map.contains(1));
EXPECT_FALSE(map.contains(2));
}
+
+TEST(map, UniquePtrValue)
+{
+ auto value1 = std::unique_ptr<int>(new int());
+ auto value2 = std::unique_ptr<int>(new int());
+ auto value3 = std::unique_ptr<int>(new int());
+
+ int *value1_ptr = value1.get();
+
+ Map<int, std::unique_ptr<int>> map;
+ map.add_new(1, std::move(value1));
+ map.add(2, std::move(value2));
+ map.add_override(3, std::move(value3));
+ map.lookup_or_add(4, []() { return std::unique_ptr<int>(new int()); });
+ map.add_new(5, std::unique_ptr<int>(new int()));
+ map.add(6, std::unique_ptr<int>(new int()));
+ map.add_override(7, std::unique_ptr<int>(new int()));
+
+ EXPECT_EQ(map.lookup(1).get(), value1_ptr);
+ EXPECT_EQ(map.lookup_ptr(100), nullptr);
+}
diff --git a/tests/gtests/blenlib/BLI_memiter_test.cc b/tests/gtests/blenlib/BLI_memiter_test.cc
index c1c07dc7540..d92daefff3b 100644
--- a/tests/gtests/blenlib/BLI_memiter_test.cc
+++ b/tests/gtests/blenlib/BLI_memiter_test.cc
@@ -17,7 +17,7 @@ TEST(memiter, Nop)
BLI_memiter_destroy(mi);
}
-void memiter_empty_test(int num_elems, const int chunk_size)
+static void memiter_empty_test(int num_elems, const int chunk_size)
{
BLI_memiter *mi = BLI_memiter_create(chunk_size);
void *data;
@@ -39,7 +39,7 @@ void memiter_empty_test(int num_elems, const int chunk_size)
}
#define MEMITER_NUMBER_TEST_FN(fn, number_type) \
- void fn(int num_elems, const int chunk_size) \
+ static void fn(int num_elems, const int chunk_size) \
{ \
BLI_memiter *mi = BLI_memiter_create(chunk_size); \
number_type *data; \
@@ -65,7 +65,7 @@ MEMITER_NUMBER_TEST_FN(memiter_short_test, short)
MEMITER_NUMBER_TEST_FN(memiter_int_test, int)
MEMITER_NUMBER_TEST_FN(memiter_long_test, int64_t)
-void memiter_string_test(const char *strings[], const int chunk_size)
+static void memiter_string_test(const char *strings[], const int chunk_size)
{
BLI_memiter *mi = BLI_memiter_create(chunk_size);
char *data;
@@ -95,7 +95,7 @@ void memiter_string_test(const char *strings[], const int chunk_size)
BLI_memiter_destroy(mi);
}
-void memiter_words10k_test(const char split_char, const int chunk_size)
+static void memiter_words10k_test(const char split_char, const int chunk_size)
{
const int words_len = sizeof(words10k) - 1;
char *words = BLI_strdupn(words10k, words_len);
diff --git a/tests/gtests/blenlib/BLI_set_test.cc b/tests/gtests/blenlib/BLI_set_test.cc
index f331639b345..5baf069557e 100644
--- a/tests/gtests/blenlib/BLI_set_test.cc
+++ b/tests/gtests/blenlib/BLI_set_test.cc
@@ -1,7 +1,10 @@
#include "testing/testing.h"
#include "BLI_set.h"
+#include "BLI_vector.h"
-using IntSet = BLI::Set<int>;
+using BLI::Set;
+using BLI::Vector;
+using IntSet = Set<int>;
TEST(set, Defaultconstructor)
{
@@ -187,3 +190,14 @@ TEST(set, OftenAddRemove)
EXPECT_EQ(set.size(), 0);
}
}
+
+TEST(set, UniquePtrValues)
+{
+ Set<std::unique_ptr<int>> set;
+ set.add_new(std::unique_ptr<int>(new int()));
+ auto value1 = std::unique_ptr<int>(new int());
+ set.add_new(std::move(value1));
+ set.add(std::unique_ptr<int>(new int()));
+
+ EXPECT_EQ(set.size(), 3);
+}
diff --git a/tests/gtests/blenlib/BLI_stack_cxx_test.cc b/tests/gtests/blenlib/BLI_stack_cxx_test.cc
index 02c5407fda3..436f1f307b9 100644
--- a/tests/gtests/blenlib/BLI_stack_cxx_test.cc
+++ b/tests/gtests/blenlib/BLI_stack_cxx_test.cc
@@ -1,7 +1,8 @@
#include "testing/testing.h"
#include "BLI_stack_cxx.h"
-using IntStack = BLI::Stack<int>;
+using BLI::Stack;
+using IntStack = Stack<int>;
TEST(stack, DefaultConstructor)
{
@@ -50,3 +51,13 @@ TEST(stack, Peek)
stack.pop();
EXPECT_EQ(stack.peek(), 3);
}
+
+TEST(stack, UniquePtrValues)
+{
+ Stack<std::unique_ptr<int>> stack;
+ stack.push(std::unique_ptr<int>(new int()));
+ stack.push(std::unique_ptr<int>(new int()));
+ std::unique_ptr<int> a = stack.pop();
+ std::unique_ptr<int> &b = stack.peek();
+ UNUSED_VARS(a, b);
+}
diff --git a/tests/gtests/blenlib/BLI_string_map_test.cc b/tests/gtests/blenlib/BLI_string_map_test.cc
index e5e32352161..cc02a54e0c8 100644
--- a/tests/gtests/blenlib/BLI_string_map_test.cc
+++ b/tests/gtests/blenlib/BLI_string_map_test.cc
@@ -199,3 +199,12 @@ TEST(string_map, WithVectors)
EXPECT_EQ(map.lookup("A").size(), 3);
EXPECT_EQ(map.lookup("B").size(), 7);
}
+
+TEST(string_map, UniquePtrValues)
+{
+ StringMap<std::unique_ptr<int>> map;
+ map.add_new("A", std::unique_ptr<int>(new int()));
+ std::unique_ptr<int> &a = map.lookup("A");
+ std::unique_ptr<int> *b = map.lookup_ptr("A");
+ EXPECT_EQ(a.get(), b->get());
+}
diff --git a/tests/gtests/blenlib/BLI_string_test.cc b/tests/gtests/blenlib/BLI_string_test.cc
index d69cb519494..257f478622f 100644
--- a/tests/gtests/blenlib/BLI_string_test.cc
+++ b/tests/gtests/blenlib/BLI_string_test.cc
@@ -453,7 +453,7 @@ struct WordInfo {
}
int start, end;
};
-std::ostream &operator<<(std::ostream &os, const WordInfo &word_info)
+static std::ostream &operator<<(std::ostream &os, const WordInfo &word_info)
{
os << "start: " << word_info.start << ", end: " << word_info.end;
return os;
diff --git a/tests/gtests/blenlib/BLI_set_vector_test.cc b/tests/gtests/blenlib/BLI_vector_set_test.cc
index be6f9a80d7c..675e5a154d5 100644
--- a/tests/gtests/blenlib/BLI_set_vector_test.cc
+++ b/tests/gtests/blenlib/BLI_vector_set_test.cc
@@ -1,26 +1,27 @@
#include "testing/testing.h"
-#include "BLI_set_vector.h"
+#include "BLI_vector_set.h"
-using IntSetVector = BLI::SetVector<int>;
+using BLI::VectorSet;
+using IntVectorSet = VectorSet<int>;
-TEST(set_vector, DefaultConstructor)
+TEST(vector_set, DefaultConstructor)
{
- IntSetVector set;
+ IntVectorSet set;
EXPECT_EQ(set.size(), 0);
}
-TEST(set_vector, InitializerListConstructor_WithoutDuplicates)
+TEST(vector_set, InitializerListConstructor_WithoutDuplicates)
{
- IntSetVector set = {1, 4, 5};
+ IntVectorSet set = {1, 4, 5};
EXPECT_EQ(set.size(), 3);
EXPECT_EQ(set[0], 1);
EXPECT_EQ(set[1], 4);
EXPECT_EQ(set[2], 5);
}
-TEST(set_vector, InitializerListConstructor_WithDuplicates)
+TEST(vector_set, InitializerListConstructor_WithDuplicates)
{
- IntSetVector set = {1, 3, 3, 2, 1, 5};
+ IntVectorSet set = {1, 3, 3, 2, 1, 5};
EXPECT_EQ(set.size(), 4);
EXPECT_EQ(set[0], 1);
EXPECT_EQ(set[1], 3);
@@ -28,35 +29,35 @@ TEST(set_vector, InitializerListConstructor_WithDuplicates)
EXPECT_EQ(set[3], 5);
}
-TEST(set_vector, Copy)
+TEST(vector_set, Copy)
{
- IntSetVector set1 = {1, 2, 3};
- IntSetVector set2 = set1;
+ IntVectorSet set1 = {1, 2, 3};
+ IntVectorSet set2 = set1;
EXPECT_EQ(set1.size(), 3);
EXPECT_EQ(set2.size(), 3);
EXPECT_EQ(set1.index(2), 1);
EXPECT_EQ(set2.index(2), 1);
}
-TEST(set_vector, Move)
+TEST(vector_set, Move)
{
- IntSetVector set1 = {1, 2, 3};
- IntSetVector set2 = std::move(set1);
+ IntVectorSet set1 = {1, 2, 3};
+ IntVectorSet set2 = std::move(set1);
EXPECT_EQ(set1.size(), 0);
EXPECT_EQ(set2.size(), 3);
}
-TEST(set_vector, AddNewIncreasesSize)
+TEST(vector_set, AddNewIncreasesSize)
{
- IntSetVector set;
+ IntVectorSet set;
EXPECT_EQ(set.size(), 0);
set.add(5);
EXPECT_EQ(set.size(), 1);
}
-TEST(set_vector, AddExistingDoesNotIncreaseSize)
+TEST(vector_set, AddExistingDoesNotIncreaseSize)
{
- IntSetVector set;
+ IntVectorSet set;
EXPECT_EQ(set.size(), 0);
set.add(5);
EXPECT_EQ(set.size(), 1);
@@ -64,26 +65,26 @@ TEST(set_vector, AddExistingDoesNotIncreaseSize)
EXPECT_EQ(set.size(), 1);
}
-TEST(set_vector, Index)
+TEST(vector_set, Index)
{
- IntSetVector set = {3, 6, 4};
+ IntVectorSet set = {3, 6, 4};
EXPECT_EQ(set.index(6), 1);
EXPECT_EQ(set.index(3), 0);
EXPECT_EQ(set.index(4), 2);
}
-TEST(set_vector, IndexTry)
+TEST(vector_set, IndexTry)
{
- IntSetVector set = {3, 6, 4};
+ IntVectorSet set = {3, 6, 4};
EXPECT_EQ(set.index_try(5), -1);
EXPECT_EQ(set.index_try(3), 0);
EXPECT_EQ(set.index_try(6), 1);
EXPECT_EQ(set.index_try(2), -1);
}
-TEST(set_vector, Remove)
+TEST(vector_set, Remove)
{
- IntSetVector set = {4, 5, 6, 7};
+ IntVectorSet set = {4, 5, 6, 7};
EXPECT_EQ(set.size(), 4);
set.remove(5);
EXPECT_EQ(set.size(), 3);
@@ -100,3 +101,13 @@ TEST(set_vector, Remove)
set.remove(7);
EXPECT_EQ(set.size(), 0);
}
+
+TEST(vector_set, UniquePtrValue)
+{
+ VectorSet<std::unique_ptr<int>> set;
+ set.add_new(std::unique_ptr<int>(new int()));
+ set.add(std::unique_ptr<int>(new int()));
+ set.index_try(std::unique_ptr<int>(new int()));
+ std::unique_ptr<int> value = set.pop();
+ UNUSED_VARS(value);
+}
diff --git a/tests/gtests/blenlib/BLI_vector_test.cc b/tests/gtests/blenlib/BLI_vector_test.cc
index 60f78025269..f258e50a60c 100644
--- a/tests/gtests/blenlib/BLI_vector_test.cc
+++ b/tests/gtests/blenlib/BLI_vector_test.cc
@@ -261,7 +261,7 @@ TEST(vector, BecomeLarge)
}
}
-IntVector return_by_value_helper()
+static IntVector return_by_value_helper()
{
return IntVector({3, 5, 1});
}
@@ -398,3 +398,17 @@ TEST(vector, AppendNTimes)
EXPECT_EQ(a[3], 2);
EXPECT_EQ(a[4], 2);
}
+
+TEST(vector, UniquePtrValue)
+{
+ Vector<std::unique_ptr<int>> vec;
+ vec.append(std::unique_ptr<int>(new int()));
+ vec.append(std::unique_ptr<int>(new int()));
+ vec.append(std::unique_ptr<int>(new int()));
+
+ std::unique_ptr<int> &a = vec.last();
+ std::unique_ptr<int> b = vec.pop_last();
+ vec.remove_and_reorder(0);
+
+ UNUSED_VARS(a, b);
+}
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index 1d4b0b18973..1f52886132f 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -61,7 +61,6 @@ BLENDER_TEST(BLI_memiter "bf_blenlib")
BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}")
BLENDER_TEST(BLI_polyfill_2d "bf_blenlib")
BLENDER_TEST(BLI_set "bf_blenlib")
-BLENDER_TEST(BLI_set_vector "bf_blenlib")
BLENDER_TEST(BLI_stack "bf_blenlib")
BLENDER_TEST(BLI_stack_cxx "bf_blenlib")
BLENDER_TEST(BLI_string "bf_blenlib")
@@ -70,6 +69,7 @@ BLENDER_TEST(BLI_string_ref "bf_blenlib")
BLENDER_TEST(BLI_string_utf8 "bf_blenlib")
BLENDER_TEST(BLI_task "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_vector "bf_blenlib")
+BLENDER_TEST(BLI_vector_set "bf_blenlib")
BLENDER_TEST_PERFORMANCE(BLI_ghash_performance "bf_blenlib")
BLENDER_TEST_PERFORMANCE(BLI_task_performance "bf_blenlib")
diff --git a/tests/gtests/blenlib/stubs/bf_intern_eigen_stubs.h b/tests/gtests/blenlib/stubs/bf_intern_eigen_stubs.h
index 97c0916dd9b..dec2631fc63 100644
--- a/tests/gtests/blenlib/stubs/bf_intern_eigen_stubs.h
+++ b/tests/gtests/blenlib/stubs/bf_intern_eigen_stubs.h
@@ -2,6 +2,13 @@
extern "C" {
+void EIG_svd_square_matrix(
+ const int size, const float *matrix, float *r_U, float *r_S, float *r_V);
+bool EIG_self_adjoint_eigen_solve(const int size,
+ const float *matrix,
+ float *r_eigen_values,
+ float *r_eigen_vectors);
+
bool EIG_self_adjoint_eigen_solve(const int size,
const float *matrix,
float *r_eigen_values,
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
index d6e7127c35a..92734b5bc7d 100755
--- a/tests/python/ffmpeg_tests.py
+++ b/tests/python/ffmpeg_tests.py
@@ -86,6 +86,15 @@ class FPSDetectionTest(AbstractFFmpegSequencerTest):
1.0,
places=2)
+ def test_T68091(self):
+ self.assertAlmostEqual(
+ self.get_movie_file_fps('T68091-invalid-nb_frames-at-10fps.mp4'),
+ 10.0,
+ places=2)
+ self.assertEqual(
+ self.get_movie_file_duration('T68091-invalid-nb_frames-at-10fps.mp4'),
+ 10)
+
def test_T54834(self):
self.assertEqual(
self.get_movie_file_duration('T54834.ogg'),