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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build_files/build_environment/cmake/harvest.cmake6
-rwxr-xr-xbuild_files/build_environment/install_deps.sh175
-rw-r--r--doc/doxygen/Doxyfile2
-rw-r--r--intern/cycles/device/device_optix.cpp4
-rw-r--r--intern/cycles/kernel/shaders/node_ies_light.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_mapping.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_voronoi_texture.osl2
-rw-r--r--intern/cycles/render/shader.cpp3
-rw-r--r--intern/ghost/GHOST_IWindow.h6
-rw-r--r--intern/ghost/GHOST_Types.h10
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp2
-rw-r--r--intern/ghost/intern/GHOST_EventButton.h1
-rw-r--r--intern/ghost/intern/GHOST_EventCursor.h1
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm27
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp22
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm2
-rw-r--r--intern/ghost/intern/GHOST_WindowNULL.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp10
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h9
-rw-r--r--intern/guardedalloc/intern/mallocn.c3
-rw-r--r--intern/guardedalloc/intern/mallocn_intern.h2
-rw-r--r--intern/guardedalloc/intern/mallocn_lockfree_impl.c23
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c11
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py7
-rw-r--r--release/scripts/modules/rna_prop_ui.py5
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py56
-rw-r--r--release/scripts/startup/bl_operators/vertexpaint_dirt.py14
-rw-r--r--release/scripts/startup/bl_ui/properties_data_light.py9
-rw-r--r--release/scripts/startup/bl_ui/space_info.py2
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py45
-rw-r--r--release/scripts/startup/bl_ui/space_text.py33
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py10
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py104
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py23
-rw-r--r--source/blender/blenfont/intern/blf.c5
-rw-r--r--source/blender/blenkernel/BKE_animsys.h4
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_cloth.h20
-rw-r--r--source/blender/blenkernel/BKE_lightprobe.h1
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h1
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c22
-rw-r--r--source/blender/blenkernel/intern/cloth.c118
-rw-r--r--source/blender/blenkernel/intern/collision.c673
-rw-r--r--source/blender/blenkernel/intern/curve.c137
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c24
-rw-r--r--source/blender/blenkernel/intern/object.c2
-rw-r--r--source/blender/blenkernel/intern/workspace.c8
-rw-r--r--source/blender/blenlib/BLI_rect.h4
-rw-r--r--source/blender/blenlib/intern/rct.c80
-rw-r--r--source/blender/blenloader/intern/readfile.c7
-rw-r--r--source/blender/blenloader/intern/versioning_280.c57
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c11
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c4
-rw-r--r--source/blender/collada/EffectExporter.cpp4
-rw-r--r--source/blender/collada/Materials.cpp1
-rw-r--r--source/blender/collada/collada_utils.cpp15
-rw-r--r--source/blender/collada/collada_utils.h5
-rw-r--r--source/blender/depsgraph/CMakeLists.txt2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc20
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc7
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc144
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h65
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c32
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c52
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl21
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c3
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c2
-rw-r--r--source/blender/draw/intern/draw_cache.c39
-rw-r--r--source/blender/draw/intern/draw_cache.h10
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h6
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c18
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h5
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c82
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c2
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c6
-rw-r--r--source/blender/editors/curve/editcurve_paint.c10
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c41
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c41
-rw-r--r--source/blender/editors/include/ED_screen.h2
-rw-r--r--source/blender/editors/include/UI_interface.h7
-rw-r--r--source/blender/editors/include/UI_resources.h1
-rw-r--r--source/blender/editors/interface/interface_align.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c6
-rw-r--r--source/blender/editors/interface/interface_layout.c28
-rw-r--r--source/blender/editors/interface/interface_panel.c35
-rw-r--r--source/blender/editors/interface/interface_region_hud.c2
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c4
-rw-r--r--source/blender/editors/interface/interface_region_popover.c4
-rw-r--r--source/blender/editors/interface/interface_region_popup.c2
-rw-r--r--source/blender/editors/interface/interface_region_search.c2
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c2
-rw-r--r--source/blender/editors/interface/interface_templates.c3
-rw-r--r--source/blender/editors/interface/interface_widgets.c10
-rw-r--r--source/blender/editors/interface/resources.c3
-rw-r--r--source/blender/editors/interface/view2d.c5
-rw-r--r--source/blender/editors/io/io_alembic.c4
-rw-r--r--source/blender/editors/io/io_collada.c4
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin.c2
-rw-r--r--source/blender/editors/object/object_add.c21
-rw-r--r--source/blender/editors/object/object_edit.c2
-rw-r--r--source/blender/editors/object/object_vgroup.c2
-rw-r--r--source/blender/editors/screen/area.c51
-rw-r--r--source/blender/editors/screen/area_query.c12
-rw-r--r--source/blender/editors/screen/screen_ops.c18
-rw-r--r--source/blender/editors/space_action/action_data.c26
-rw-r--r--source/blender/editors/space_action/action_edit.c4
-rw-r--r--source/blender/editors/space_clip/space_clip.c6
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c76
-rw-r--r--source/blender/editors/space_graph/graph_edit.c15
-rw-r--r--source/blender/editors/space_graph/space_graph.c6
-rw-r--r--source/blender/editors/space_nla/nla_edit.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c58
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c137
-rw-r--r--source/blender/editors/space_sequencer/sequencer_modifier.c13
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c8
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c57
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c2
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/transform.c2
-rw-r--r--source/blender/editors/transform/transform_ops.c2
-rw-r--r--source/blender/freestyle/intern/application/AppConfig.cpp4
-rw-r--r--source/blender/freestyle/intern/application/AppConfig.h5
-rw-r--r--source/blender/gpu/GPU_texture.h1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c26
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c40
-rw-r--r--source/blender/gpu/intern/gpu_texture.c50
-rw-r--r--source/blender/makesdna/DNA_armature_types.h3
-rw-r--r--source/blender/makesdna/DNA_screen_types.h12
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesrna/RNA_define.h10
-rw-r--r--source/blender/makesrna/RNA_enum_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_define.c30
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c11
-rw-r--r--source/blender/makesrna/intern/rna_object.c8
-rw-r--r--source/blender/makesrna/intern/rna_particle.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c24
-rw-r--r--source/blender/makesrna/intern/rna_space.c27
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c8
-rw-r--r--source/blender/makesrna/intern/rna_wm.c2
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c24
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp156
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h62
-rw-r--r--source/blender/windowmanager/WM_toolsystem.h4
-rw-r--r--source/blender/windowmanager/WM_types.h33
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c2
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c3
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c13
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c427
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c770
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c105
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c18
-rw-r--r--source/blender/windowmanager/intern/wm_window.c54
-rw-r--r--source/blender/windowmanager/wm_event_system.h3
-rw-r--r--source/creator/creator_signals.c11
-rw-r--r--tests/gtests/CMakeLists.txt3
-rw-r--r--tests/gtests/ffmpeg/CMakeLists.txt44
-rw-r--r--tests/gtests/ffmpeg/ffmpeg_codecs.cc147
-rw-r--r--tests/gtests/guardedalloc/guardedalloc_alignment_test.cc76
-rw-r--r--tests/python/CMakeLists.txt27
-rw-r--r--tests/python/bevel_operator.py184
-rw-r--r--tests/python/boolean_operator.py68
-rw-r--r--tests/python/modifiers.py156
-rw-r--r--tests/python/modules/mesh_test.py495
-rw-r--r--tests/python/operators.py172
179 files changed, 4319 insertions, 2196 deletions
diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake
index 5b5c254b150..5fb62e330af 100644
--- a/build_files/build_environment/cmake/harvest.cmake
+++ b/build_files/build_environment/cmake/harvest.cmake
@@ -62,14 +62,8 @@ if(BUILD_MODE STREQUAL Debug)
# OpenImageIO
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimageio/lib/OpenImageIO.lib ${HARVEST_TARGET}/openimageio/lib/OpenImageIO_d.lib &&
${CMAKE_COMMAND} -E copy ${LIBDIR}/openimageio/lib/OpenImageIO_Util.lib ${HARVEST_TARGET}/openimageio/lib/OpenImageIO_Util_d.lib &&
- # python
- ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/python/ ${HARVEST_TARGET}/python/ &&
# hdf5
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/hdf5/lib ${HARVEST_TARGET}/hdf5/lib &&
- # numpy
- ${CMAKE_COMMAND} -E copy ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}_numpy_${NUMPY_SHORT_VERSION}d.tar.gz ${HARVEST_TARGET}/Release/python${PYTHON_SHORT_VERSION_NO_DOTS}_numpy_${NUMPY_SHORT_VERSION}d.tar.gz &&
- # python
- ${CMAKE_COMMAND} -E copy ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}_d.tar.gz ${HARVEST_TARGET}/Release/python${PYTHON_SHORT_VERSION_NO_DOTS}_d.tar.gz
DEPENDS Package_Python
)
endif()
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index dd15fb0d2ed..bc9ee802810 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -19,7 +19,32 @@
# A shell script installing/building all needed dependencies to build Blender, for some Linux distributions.
-##### Args and Help Handling #####
+# ----------------------------------------------------------------------------
+# Debugging Helpers
+#
+# Use for developing this script (keep first).
+
+# Useful for debugging this script:
+USE_DEBUG_TRAP=${USE_DEBUG_TRAP:-0}
+USE_DEBUG_LOG=${USE_DEBUG_LOG:-0}
+
+# Print the line that exits.
+if [ $USE_DEBUG_TRAP -ne 0 ]; then
+ err_report() {
+ echo "Error on line $1"
+ exit 1
+ }
+ trap 'err_report $LINENO' ERR
+fi
+
+# Noisy, show every line that runs with it's line number.
+if [ $USE_DEBUG_LOG -ne 0 ]; then
+ PS4='\e[0;33m$(printf %4d ${LINENO}):\e\033[0m '
+ set -x
+fi
+
+# ----------------------------------------------------------------------------
+# Args and Help Handling
# Parse command line!
ARGS=$( \
@@ -305,7 +330,8 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--skip-ffmpeg
Unconditionally skip FFMpeg installation/building.\""
-##### Main Vars #####
+# ----------------------------------------------------------------------------
+# Main Vars
DO_SHOW_DEPS=false
@@ -447,7 +473,8 @@ LANG_BACK=$LANG
LANG=""
export LANG
-##### Generic Helpers #####
+# ----------------------------------------------------------------------------
+# Generic Helpers
BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
@@ -489,7 +516,8 @@ PRINT() {
_echo "$@"
}
-##### Args Handling #####
+# ----------------------------------------------------------------------------
+# Args Handling
# Finish parsing the commandline args.
eval set -- "$ARGS"
@@ -892,7 +920,8 @@ CXXFLAGS_BACK=$CXXFLAGS
CXXFLAGS="$CXXFLAGS -std=c++11"
export CXXFLAGS
-#### Show Dependencies ####
+# ----------------------------------------------------------------------------
+# Show Dependencies
# Need those to be after we defined versions...
DEPS_COMMON_INFO="\"COMMON DEPENDENCIES:
@@ -940,9 +969,8 @@ if [ "$DO_SHOW_DEPS" = true ]; then
exit 0
fi
-
-
-##### Generic Helpers #####
+# ----------------------------------------------------------------------------
+# Generic Helpers
# Check return code of wget for success...
download() {
@@ -965,15 +993,25 @@ download() {
fi
}
+version_sanitize() {
+ # Remove suffix such as '1.3_RC2', keeping only '1.3'.
+ # Needed for numeric comparisons.
+ local val=$(sed -r 's/^([^_]+).*/\1/' <<< "$1")
+ # Remove trailing punctuation such as '1.0.', keeping only '1.0'.
+ val=$(sed -r 's/[[:punct:]]*$//g' <<< "$val")
+ echo $val
+}
+
# Return 0 if $1 = $2 (i.e. 1.01.0 = 1.1, but 1.1.1 != 1.1), else 1.
# $1 and $2 should be version numbers made of numbers only.
version_eq() {
- backIFS=$IFS
- IFS='.'
+ local VER_1=$(version_sanitize "$1")
+ local VER_2=$(version_sanitize "$2")
+ local IFS='.'
# Split both version numbers into their numeric elements.
- arr1=( $1 )
- arr2=( $2 )
+ arr1=( $VER_1 )
+ arr2=( $VER_2 )
ret=1
@@ -983,8 +1021,8 @@ version_eq() {
_t=$count1
count1=$count2
count2=$_t
- arr1=( $2 )
- arr2=( $1 )
+ arr1=( $VER_2 )
+ arr2=( $VER_1 )
fi
ret=0
@@ -1004,7 +1042,6 @@ version_eq() {
fi
done
- IFS=$backIFS
return $ret
}
@@ -1035,12 +1072,13 @@ version_ge_lt() {
# $1 and $2 should be version numbers made of numbers only.
# $1 should be at least as long as $2!
version_match() {
- backIFS=$IFS
- IFS='.'
+ local VER_1=$(version_sanitize "$1")
+ local VER_2=$(version_sanitize "$2")
+ local IFS='.'
# Split both version numbers into their numeric elements.
- arr1=( $1 )
- arr2=( $2 )
+ arr1=( $VER_1 )
+ arr2=( $VER_2 )
ret=1
@@ -1057,11 +1095,12 @@ version_match() {
done
fi
- IFS=$backIFS
return $ret
}
-##### Generic compile helpers #####
+# ----------------------------------------------------------------------------
+# Generic compile helpers
+
prepare_opt() {
INFO "Ensuring $INST exists and is writable by us"
if [ ! $SUDO ]; then
@@ -1123,7 +1162,9 @@ run_ldconfig() {
PRINT ""
}
-#### Build Python ####
+# ----------------------------------------------------------------------------
+# Build Python
+
_init_python() {
_src=$SRC/Python-$PYTHON_VERSION
_git=false
@@ -1192,7 +1233,9 @@ compile_Python() {
fi
}
-##### Build Numpy #####
+# ----------------------------------------------------------------------------
+# Build Numpy
+
_init_numpy() {
_src=$SRC/numpy-$NUMPY_VERSION
_git=false
@@ -1259,7 +1302,9 @@ compile_Numpy() {
fi
}
-#### Build Boost ####
+# ----------------------------------------------------------------------------
+# Build Boost
+
_init_boost() {
_src=$SRC/boost-$BOOST_VERSION
_git=false
@@ -1337,7 +1382,9 @@ compile_Boost() {
run_ldconfig "boost"
}
-#### Build OCIO ####
+# ----------------------------------------------------------------------------
+# Build OCIO
+
_init_ocio() {
_src=$SRC/OpenColorIO-$OCIO_VERSION
if [ "$OCIO_USE_REPO" = true ]; then
@@ -1452,7 +1499,9 @@ compile_OCIO() {
run_ldconfig "ocio"
}
-#### Build ILMBase ####
+# ----------------------------------------------------------------------------
+# Build ILMBase
+
_init_ilmbase() {
_src=$SRC/ILMBase-$ILMBASE_VERSION
_git=false
@@ -1543,7 +1592,9 @@ compile_ILMBASE() {
magic_compile_set ilmbase-$ILMBASE_VERSION $ilmbase_magic
}
-#### Build OpenEXR ####
+# ----------------------------------------------------------------------------
+# Build OpenEXR
+
_init_openexr() {
_src=$SRC/OpenEXR-$OPENEXR_VERSION
_git=true
@@ -1663,7 +1714,9 @@ compile_OPENEXR() {
run_ldconfig "openexr"
}
-#### Build OIIO ####
+# ----------------------------------------------------------------------------
+# Build OIIO
+
_init_oiio() {
_src=$SRC/OpenImageIO-$OIIO_VERSION
_git=true
@@ -1804,7 +1857,9 @@ compile_OIIO() {
run_ldconfig "oiio"
}
-#### Build LLVM ####
+# ----------------------------------------------------------------------------
+# Build LLVM
+
_init_llvm() {
_src=$SRC/LLVM-$LLVM_VERSION
_src_clang=$SRC/CLANG-$LLVM_VERSION
@@ -1904,7 +1959,9 @@ compile_LLVM() {
fi
}
-#### Build OSL ####
+# ----------------------------------------------------------------------------
+# Build OSL
+
_init_osl() {
_src=$SRC/OpenShadingLanguage-$OSL_VERSION
_git=true
@@ -2034,7 +2091,9 @@ compile_OSL() {
run_ldconfig "osl"
}
-#### Build OSD ####
+# ----------------------------------------------------------------------------
+# Build OSD
+
_init_osd() {
_src=$SRC/OpenSubdiv-$OSD_VERSION
_git=true
@@ -2131,7 +2190,9 @@ compile_OSD() {
run_ldconfig "osd"
}
-#### Build Blosc ####
+# ----------------------------------------------------------------------------
+# Build Blosc
+
_init_blosc() {
_src=$SRC/c-blosc-$OPENVDB_BLOSC_VERSION
_git=false
@@ -2218,7 +2279,9 @@ compile_BLOSC() {
run_ldconfig "blosc"
}
-#### Build OpenVDB ####
+# ----------------------------------------------------------------------------
+# Build OpenVDB
+
_init_openvdb() {
_src=$SRC/openvdb-$OPENVDB_VERSION
_git=false
@@ -2319,7 +2382,9 @@ compile_OPENVDB() {
run_ldconfig "openvdb"
}
-#### Build Alembic ####
+# ----------------------------------------------------------------------------
+# Build Alembic
+
_init_alembic() {
_src=$SRC/alembic-$ALEMBIC_VERSION
_git=false
@@ -2412,7 +2477,9 @@ compile_ALEMBIC() {
run_ldconfig "alembic"
}
-#### Build OpenCOLLADA ####
+# ----------------------------------------------------------------------------
+# Build OpenCOLLADA
+
_init_opencollada() {
_src=$SRC/OpenCOLLADA-$OPENCOLLADA_VERSION
_git=true
@@ -2504,7 +2571,9 @@ compile_OpenCOLLADA() {
fi
}
-#### Build Embree ####
+# ----------------------------------------------------------------------------
+# Build Embree
+
_init_embree() {
_src=$SRC/embree-$EMBREE_VERSION
_git=true
@@ -2599,7 +2668,9 @@ compile_Embree() {
fi
}
-#### Build OpenImageDenoise ####
+# ----------------------------------------------------------------------------
+# Build OpenImageDenoise
+
_init_oidn() {
_src=$SRC/oidn-$OIDN_VERSION
_git=true
@@ -2691,7 +2762,9 @@ compile_OIDN() {
run_ldconfig "oidn"
}
-#### Build FFMPEG ####
+# ----------------------------------------------------------------------------
+# Build FFMPEG
+
_init_ffmpeg() {
_src=$SRC/ffmpeg-$FFMPEG_VERSION
_inst=$INST/ffmpeg-$FFMPEG_VERSION
@@ -2806,7 +2879,9 @@ compile_FFmpeg() {
}
-#### Install on DEB-like ####
+# ----------------------------------------------------------------------------
+# Install on DEB-like
+
get_package_version_DEB() {
dpkg-query -W -f '${Version}' $1 | sed -r 's/([0-9]+:)?(([0-9]+\.?)+([0-9]+)).*/\2/'
}
@@ -3341,7 +3416,9 @@ install_DEB() {
}
-#### Install on RPM-like ####
+# ----------------------------------------------------------------------------
+# Install on RPM-like
+
rpm_flavour() {
if [ -f /etc/redhat-release ]; then
if [ "`grep '[6-7]\.' /etc/redhat-release`" ]; then
@@ -3936,7 +4013,9 @@ install_RPM() {
}
-#### Install on ARCH-like ####
+# ----------------------------------------------------------------------------
+# Install on ARCH-like
+
get_package_version_ARCH() {
pacman -Si $1 | grep Version | tail -n 1 | sed -r 's/.*:\s+?(([0-9]+\.?)+).*/\1/'
}
@@ -4056,7 +4135,7 @@ install_ARCH() {
fi
if [ "$WITH_JACK" = true ]; then
- _packages="$_packages jack"
+ _packages="$_packages jack2"
fi
PRINT ""
@@ -4426,7 +4505,8 @@ install_ARCH() {
}
-#### Install on other distro (very limited!) ####
+# ----------------------------------------------------------------------------
+# Install on other distro (very limited!)
install_OTHER() {
PRINT ""
@@ -4621,7 +4701,8 @@ install_OTHER() {
fi
}
-#### Printing User Info ####
+# ----------------------------------------------------------------------------
+# Printing User Info
print_info_ffmpeglink_DEB() {
dpkg -L $_packages | grep -e ".*\/lib[^\/]\+\.so" | gawk '{ printf(nlines ? "'"$_ffmpeg_list_sep"'%s" : "%s", gensub(/.*lib([^\/]+)\.so/, "\\1", "g", $0)); nlines++ }'
@@ -4713,7 +4794,7 @@ print_info() {
_1="-D PYTHON_VERSION=$PYTHON_VERSION_MIN"
PRINT " $_1"
_buildargs="$_buildargs $_1"
- if [ -d $INST/python-$PYTHON_VERSION_MIN ]; then
+ if [ -d "$INST/python-$PYTHON_VERSION_MIN" ]; then
_1="-D PYTHON_ROOT_DIR=$INST/python-$PYTHON_VERSION_MIN"
PRINT " $_1"
_buildargs="$_buildargs $_1"
@@ -4889,7 +4970,9 @@ print_info() {
PRINT " cmake $_buildargs ."
}
-#### "Main" ####
+# ----------------------------------------------------------------------------
+# "Main"
+
# Detect distribution type used on this machine
if [ -f /etc/debian_version ]; then
DISTRO="DEB"
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index c07a80bf0d5..ecd60957f2b 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.82"
+PROJECT_NUMBER = "V2.83"
# 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/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index 8a8eef0e059..c1106b367ca 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -1188,8 +1188,8 @@ class OptiXDevice : public Device {
out_data,
sizes.outputSizeInBytes,
&out_handle,
- &compacted_size_prop,
- 1));
+ background ? &compacted_size_prop : NULL,
+ background ? 1 : 0));
// Wait for all operations to finish
check_result_cuda_ret(cuStreamSynchronize(NULL));
diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/shaders/node_ies_light.osl
index 6e9181cde40..4d881eb3b65 100644
--- a/intern/cycles/kernel/shaders/node_ies_light.osl
+++ b/intern/cycles/kernel/shaders/node_ies_light.osl
@@ -31,7 +31,7 @@ shader node_ies_light(int use_mapping = 0,
p = transform(mapping, p);
}
- p = normalize(p);
+ p = normalize((vector)p);
float v_angle = acos(-p[2]);
float h_angle = atan2(p[0], p[1]) + M_PI;
diff --git a/intern/cycles/kernel/shaders/node_mapping.osl b/intern/cycles/kernel/shaders/node_mapping.osl
index 8eed0ae9c48..e8a9d940eda 100644
--- a/intern/cycles/kernel/shaders/node_mapping.osl
+++ b/intern/cycles/kernel/shaders/node_mapping.osl
@@ -65,7 +65,7 @@ shader node_mapping(string type = "point",
VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale));
}
else if (type == "normal") {
- VectorOut = normalize(transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale)));
+ VectorOut = normalize((vector)transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale)));
}
else {
warning("%s", "Unknown Mapping vector type!");
diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
index 5de4aeef943..10a9f7a6329 100644
--- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl
+++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
@@ -603,7 +603,7 @@ void voronoi_distance_to_edge_3d(vector3 coord, float randomness, output float o
vector3 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
- normalize(perpendicularToEdge));
+ normalize((vector)perpendicularToEdge));
minDistance = min(minDistance, distanceToEdge);
}
}
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index da04ef63295..661208c6463 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -317,7 +317,8 @@ void Shader::tag_update(Scene *scene)
* has use_mis set to false. We are quite close to release now, so
* better to be safe.
*/
- if (this == scene->background->get_shader(scene) && scene->light_manager->has_background_light(scene)) {
+ if (this == scene->background->get_shader(scene) &&
+ scene->light_manager->has_background_light(scene)) {
scene->light_manager->need_update = true;
}
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index c19d4bdf6bd..07133d86ce4 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -247,7 +247,11 @@ class GHOST_IWindow {
* Returns the tablet data (pressure etc).
* \return The tablet data (pressure etc).
*/
- virtual const GHOST_TabletData *GetTabletData() = 0;
+ virtual const GHOST_TabletData &GetTabletData()
+ {
+ /* Default state when no tablet is used, for systems without tablet support. */
+ return GHOST_TABLET_DATA_DEFAULT;
+ }
/***************************************************************************************
* Progress bar functionality
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index fab315e5f13..c7c9f91a361 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -101,6 +101,12 @@ typedef struct GHOST_TabletData {
float Ytilt; /* as above */
} GHOST_TabletData;
+static const GHOST_TabletData GHOST_TABLET_DATA_DEFAULT = {
+ GHOST_kTabletModeNone, /* No tablet connected. */
+ 1.0f, /* Pressure */
+ 0.0f, /* Xtilt */
+ 0.0f}; /* Ytilt */
+
typedef enum {
GHOST_kNotVisible = 0,
GHOST_kPartiallyVisible,
@@ -409,11 +415,15 @@ typedef struct {
GHOST_TInt32 x;
/** The y-coordinate of the cursor position. */
GHOST_TInt32 y;
+ /** Associated tablet data. */
+ GHOST_TabletData tablet;
} GHOST_TEventCursorData;
typedef struct {
/** The mask of the mouse button. */
GHOST_TButtonMask button;
+ /** Associated tablet data. */
+ GHOST_TabletData tablet;
} GHOST_TEventButtonData;
typedef struct {
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 1bed7afdfc4..3c3860bd2c0 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -708,7 +708,7 @@ void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api)
const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle)
{
- return ((GHOST_IWindow *)windowhandle)->GetTabletData();
+ return &((GHOST_IWindow *)windowhandle)->GetTabletData();
}
GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle)
diff --git a/intern/ghost/intern/GHOST_EventButton.h b/intern/ghost/intern/GHOST_EventButton.h
index da1dc929f4f..0f9d3b7e6bc 100644
--- a/intern/ghost/intern/GHOST_EventButton.h
+++ b/intern/ghost/intern/GHOST_EventButton.h
@@ -46,6 +46,7 @@ class GHOST_EventButton : public GHOST_Event {
: GHOST_Event(time, type, window)
{
m_buttonEventData.button = button;
+ m_buttonEventData.tablet = window->GetTabletData();
m_data = &m_buttonEventData;
}
diff --git a/intern/ghost/intern/GHOST_EventCursor.h b/intern/ghost/intern/GHOST_EventCursor.h
index ac40f78569d..41597db216a 100644
--- a/intern/ghost/intern/GHOST_EventCursor.h
+++ b/intern/ghost/intern/GHOST_EventCursor.h
@@ -48,6 +48,7 @@ class GHOST_EventCursor : public GHOST_Event {
{
m_cursorEventData.x = x;
m_cursorEventData.y = y;
+ m_cursorEventData.tablet = window->GetTabletData();
m_data = &m_cursorEventData;
}
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 2f597aee476..e50e478b9fc 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -1451,11 +1451,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
break;
case NSEventTypeTabletProximity:
- ct.Pressure = 0;
- ct.Xtilt = 0;
- ct.Ytilt = 0;
+ /* Reset tablet data when device enters proximity or leaves. */
+ ct = GHOST_TABLET_DATA_DEFAULT;
if ([event isEnteringProximity]) {
- // pointer is entering tablet area proximity
+ /* Pointer is entering tablet area proximity. */
switch ([event pointingDeviceType]) {
case NSPointingDeviceTypePen:
ct.Active = GHOST_kTabletModeStylus;
@@ -1466,14 +1465,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
case NSPointingDeviceTypeCursor:
case NSPointingDeviceTypeUnknown:
default:
- ct.Active = GHOST_kTabletModeNone;
break;
}
}
- else {
- // pointer is leaving - return to mouse
- ct.Active = GHOST_kTabletModeNone;
- }
break;
default:
@@ -1524,46 +1518,45 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
switch ([event type]) {
case NSEventTypeLeftMouseDown:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeRightMouseDown:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeOtherMouseDown:
+ handleTabletEvent(event); // Handle tablet events combined with mouse events
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonDown,
window,
convertButton([event buttonNumber])));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeLeftMouseUp:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeRightMouseUp:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeOtherMouseUp:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonUp,
window,
convertButton([event buttonNumber])));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeLeftMouseDragged:
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged:
- // Handle tablet events combined with mouse events
- handleTabletEvent(event);
+ handleTabletEvent(event); // Update window tablet state to be included in event.
case NSEventTypeMouseMoved: {
GHOST_TGrabCursorMode grab_mode = window->getCursorGrabMode();
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index fa2fc9fff37..31a6ea96bc3 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -894,6 +894,7 @@ GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type,
switch (type) {
case GHOST_kEventButtonDown:
+ /* Update window tablet data to be included in event. */
window->setTabletData(&pointerInfo.tabletData);
eventHandled = true;
return new GHOST_EventButton(
@@ -903,6 +904,7 @@ GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type,
return new GHOST_EventButton(
system->getMilliSeconds(), GHOST_kEventButtonUp, window, pointerInfo.buttonMask);
case GHOST_kEventCursorMove:
+ /* Update window tablet data to be included in event. */
window->setTabletData(&pointerInfo.tabletData);
eventHandled = true;
return new GHOST_EventCursor(system->getMilliSeconds(),
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index c50ff8e7426..f15641352e0 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -823,7 +823,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
* in the future we could have a ghost call window->CheckTabletProximity()
* but for now enough parts of the code are checking 'Active'
* - campbell */
- if (window->GetTabletData()->Active != GHOST_kTabletModeNone) {
+ if (window->GetTabletData().Active != GHOST_kTabletModeNone) {
bool any_proximity = false;
for (GHOST_TabletX11 &xtablet : m_xtablets) {
@@ -834,7 +834,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
if (!any_proximity) {
// printf("proximity disable\n");
- window->GetTabletData()->Active = GHOST_kTabletModeNone;
+ window->GetTabletData().Active = GHOST_kTabletModeNone;
}
}
#endif /* WITH_X11_XINPUT */
@@ -855,7 +855,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
XMotionEvent &xme = xe->xmotion;
#ifdef WITH_X11_XINPUT
- bool is_tablet = window->GetTabletData()->Active != GHOST_kTabletModeNone;
+ bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
#else
bool is_tablet = false;
#endif
@@ -1395,7 +1395,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* stroke might begin without leading ProxyIn event,
* this happens when window is opened when stylus is already hovering
* around tablet surface */
- window->GetTabletData()->Active = xtablet.mode;
+ window->GetTabletData().Active = xtablet.mode;
/* Note: This event might be generated with incomplete dataset
* (don't exactly know why, looks like in some cases, if the value does not change,
@@ -1408,7 +1408,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
((void)(val = data->axis_data[axis - axis_first]), true))
if (AXIS_VALUE_GET(2, axis_value)) {
- window->GetTabletData()->Pressure = axis_value / ((float)xtablet.PressureLevels);
+ window->GetTabletData().Pressure = axis_value / ((float)xtablet.PressureLevels);
}
/* the (short) cast and the & 0xffff is bizarre and unexplained anywhere,
@@ -1420,12 +1420,12 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
* check this. --mont29
*/
if (AXIS_VALUE_GET(3, axis_value)) {
- window->GetTabletData()->Xtilt = (short)(axis_value & 0xffff) /
- ((float)xtablet.XtiltLevels);
+ window->GetTabletData().Xtilt = (short)(axis_value & 0xffff) /
+ ((float)xtablet.XtiltLevels);
}
if (AXIS_VALUE_GET(4, axis_value)) {
- window->GetTabletData()->Ytilt = (short)(axis_value & 0xffff) /
- ((float)xtablet.YtiltLevels);
+ window->GetTabletData().Ytilt = (short)(axis_value & 0xffff) /
+ ((float)xtablet.YtiltLevels);
}
# undef AXIS_VALUE_GET
@@ -1436,10 +1436,10 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
continue;
}
- window->GetTabletData()->Active = xtablet.mode;
+ window->GetTabletData().Active = xtablet.mode;
}
else if (xe->type == xtablet.ProxOutEvent) {
- window->GetTabletData()->Active = GHOST_kTabletModeNone;
+ window->GetTabletData().Active = GHOST_kTabletModeNone;
}
}
#endif // WITH_X11_XINPUT
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index d260d0eacbc..a49949c2c8d 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -222,9 +222,9 @@ class GHOST_WindowCocoa : public GHOST_Window {
bool isDialog() const;
- const GHOST_TabletData *GetTabletData()
+ const GHOST_TabletData &GetTabletData()
{
- return &m_tablet;
+ return m_tablet;
}
GHOST_TabletData &GetCocoaTabletData()
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 1d89da90a32..340beef9609 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -387,7 +387,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
setTitle(title);
- m_tablet.Active = GHOST_kTabletModeNone;
+ m_tablet = GHOST_TABLET_DATA_DEFAULT;
CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
[windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h
index 29f3eee7cce..db40075e6ca 100644
--- a/intern/ghost/intern/GHOST_WindowNULL.h
+++ b/intern/ghost/intern/GHOST_WindowNULL.h
@@ -31,11 +31,6 @@ class GHOST_SystemNULL;
class GHOST_WindowNULL : public GHOST_Window {
public:
- const GHOST_TabletData *GetTabletData()
- {
- return NULL;
- }
-
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor)
{
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h
index d9342de4d69..6332ce584d2 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.h
+++ b/intern/ghost/intern/GHOST_WindowSDL.h
@@ -48,11 +48,6 @@ class GHOST_WindowSDL : public GHOST_Window {
SDL_Cursor *m_sdl_custom_cursor;
public:
- const GHOST_TabletData *GetTabletData()
- {
- return NULL;
- }
-
GHOST_WindowSDL(GHOST_SystemSDL *system,
const STR_String &title,
GHOST_TInt32 left,
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index fd9e0240b1b..e91dba5cef8 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -89,8 +89,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
{
// Initialize tablet variables
memset(&m_wintab, 0, sizeof(m_wintab));
- memset(&m_tabletData, 0, sizeof(m_tabletData));
- m_tabletData.Active = GHOST_kTabletModeNone;
+ m_tabletData = GHOST_TABLET_DATA_DEFAULT;
// Create window
if (state != GHOST_kWindowStateFullScreen) {
@@ -1085,10 +1084,7 @@ void GHOST_WindowWin32::setTabletData(GHOST_TabletData *pTabletData)
m_tabletData = *pTabletData;
}
else {
- m_tabletData.Active = GHOST_kTabletModeNone;
- m_tabletData.Pressure = 1.0f;
- m_tabletData.Xtilt = 0.0f;
- m_tabletData.Ytilt = 0.0f;
+ m_tabletData = GHOST_TABLET_DATA_DEFAULT;
}
}
@@ -1150,8 +1146,6 @@ void GHOST_WindowWin32::processWin32TabletInitEvent()
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
}
}
-
- m_tabletData.Active = GHOST_kTabletModeNone;
}
m_tabletData.Active = GHOST_kTabletModeNone;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index f72f03855fd..4795539e0f9 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -392,9 +392,9 @@ class GHOST_WindowWin32 : public GHOST_Window {
HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const;
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
- const GHOST_TabletData *GetTabletData()
+ const GHOST_TabletData &GetTabletData()
{
- return &m_tabletData;
+ return m_tabletData;
}
void setTabletData(GHOST_TabletData *tabletData);
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index ae8d705fe4a..6fbdacf98d6 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -478,7 +478,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
#ifdef WITH_X11_XINPUT
refreshXInputDevices();
- m_tabletData.Active = GHOST_kTabletModeNone;
+ m_tabletData = GHOST_TABLET_DATA_DEFAULT;
#endif
/* now set up the rendering context. */
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index faf3acba234..a9914d88340 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -145,14 +145,9 @@ class GHOST_WindowX11 : public GHOST_Window {
*/
Window getXWindow();
#ifdef WITH_X11_XINPUT
- GHOST_TabletData *GetTabletData()
+ GHOST_TabletData &GetTabletData()
{
- return &m_tabletData;
- }
-#else // WITH_X11_XINPUT
- const GHOST_TabletData *GetTabletData()
- {
- return NULL;
+ return m_tabletData;
}
#endif // WITH_X11_XINPUT
diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c
index fa2d0d1e334..d24437c85f2 100644
--- a/intern/guardedalloc/intern/mallocn.c
+++ b/intern/guardedalloc/intern/mallocn.c
@@ -70,6 +70,9 @@ const char *(*MEM_name_ptr)(void *vmemh) = MEM_lockfree_name_ptr;
void *aligned_malloc(size_t size, size_t alignment)
{
+ /* posix_memalign requires alignment to be a multiple of sizeof(void *). */
+ assert(alignment >= ALIGNED_MALLOC_MINIMUM_ALIGNMENT);
+
#ifdef _WIN32
return _aligned_malloc(size, alignment);
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
diff --git a/intern/guardedalloc/intern/mallocn_intern.h b/intern/guardedalloc/intern/mallocn_intern.h
index e6e090703d4..876607fdb77 100644
--- a/intern/guardedalloc/intern/mallocn_intern.h
+++ b/intern/guardedalloc/intern/mallocn_intern.h
@@ -107,6 +107,8 @@ size_t malloc_usable_size(void *ptr);
#include "mallocn_inline.h"
+#define ALIGNED_MALLOC_MINIMUM_ALIGNMENT sizeof(void *)
+
void *aligned_malloc(size_t size, size_t alignment);
void aligned_free(void *ptr);
diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
index e8fd8de738b..87091bb9862 100644
--- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c
+++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
@@ -346,7 +346,17 @@ void *MEM_lockfree_malloc_arrayN(size_t len, size_t size, const char *str)
void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str)
{
- MemHeadAligned *memh;
+ /* Huge alignment values doesn't make sense and they wouldn't fit into 'short' used in the
+ * MemHead. */
+ assert(alignment < 1024);
+
+ /* We only support alignments that are a power of two. */
+ assert(IS_POW2(alignment));
+
+ /* Some OS specific aligned allocators require a certain minimal alignment. */
+ if (alignment < ALIGNED_MALLOC_MINIMUM_ALIGNMENT) {
+ alignment = ALIGNED_MALLOC_MINIMUM_ALIGNMENT;
+ }
/* It's possible that MemHead's size is not properly aligned,
* do extra padding to deal with this.
@@ -356,17 +366,10 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str
*/
size_t extra_padding = MEMHEAD_ALIGN_PADDING(alignment);
- /* Huge alignment values doesn't make sense and they
- * wouldn't fit into 'short' used in the MemHead.
- */
- assert(alignment < 1024);
-
- /* We only support alignment to a power of two. */
- assert(IS_POW2(alignment));
-
len = SIZET_ALIGN_4(len);
- memh = (MemHeadAligned *)aligned_malloc(len + extra_padding + sizeof(MemHeadAligned), alignment);
+ MemHeadAligned *memh = (MemHeadAligned *)aligned_malloc(
+ len + extra_padding + sizeof(MemHeadAligned), alignment);
if (LIKELY(memh)) {
/* We keep padding in the beginning of MemHead,
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 8a05b618f031582c006c6f62b9e60619ab3eef8
+Subproject 19f3349d204303ae90e31939d5bf3f0c4fe9df4
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index 147b55f60ef..03df24d2057 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -339,6 +339,7 @@ const bTheme U_theme_default = {
.bone_solid = RGBA(0xb2b2b2ff),
.bone_pose = RGBA(0x50c8ff50),
.bone_pose_active = RGBA(0x8cffff50),
+ .bone_locked_weight = RGBA(0xff000080),
.cframe = RGBA(0x60c040ff),
.time_keyframe = RGBA(0xddd700ff),
.time_gp_keyframe = RGBA(0xb5e61dff),
@@ -453,11 +454,11 @@ const bTheme U_theme_default = {
.anim_preview_range = RGBA(0xa14d0066),
},
.space_info = {
- .back = RGBA(0x42424200),
- .title = RGBA(0xeeeeeeff),
- .text = RGBA(0xe6e6e6ff),
+ .back = RGBA(0x28282800),
+ .title = RGBA(0xffffffff),
+ .text = RGBA(0xc3c3c3ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x454545ff),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
.tab_active = RGBA(0x4b4b4bff),
@@ -476,7 +477,7 @@ const bTheme U_theme_default = {
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
- .info_selected = RGBA(0x6080ffff),
+ .info_selected = RGBA(0x3b5689ff),
.info_selected_text = RGBA(0xffffffff),
.info_error = RGBA(0x990000ff),
.info_error_text = RGBA(0xffffffff),
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 1470f353c65034db91131d21ab9c782d029a2ee
+Subproject 1e165b809b66fbf19778dbb6f1a3f4e64efef03
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject ffbaca558a27bab4716bcd51ca7ea1df8e4f4b1
+Subproject 70b649775eeeebedb02c1c7b7aa996a7f629417
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 19697b25f70..9e8febb47cd 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -116,6 +116,13 @@ class ImportHelper:
subtype='FILE_PATH',
)
+ # Hide opertator properties, rest of this is managed in C. See WM_operator_properties_filesel().
+ hide_props_region: BoolProperty(
+ name="Hide Operator Properties",
+ description="Collapse the region displaying the operator settings",
+ default=True,
+ )
+
def invoke(self, context, _event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 202fd865723..8dda8c90f85 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -277,14 +277,15 @@ def draw(layout, context, context_member, property_type, use_edit=True):
else:
val_draw = val
- row = flow.row(align=True)
+ row = layout.row(align=True)
box = row.box()
if use_edit:
split = box.split(factor=0.75)
row = split.row(align=True)
else:
- row = box.row(align=True)
+ split = box.split(factor=1.00)
+ row = split.row(align=True)
row.alignment = 'RIGHT'
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 8f8b1cc39d9..81d59f9f751 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -290,12 +290,14 @@ def _template_items_proportional_editing(*, connected=False):
# Tool System Templates
-def _template_items_tool_select(params, operator, cursor_operator):
+def _template_items_tool_select(params, operator, cursor_operator, *, extend):
if params.select_mouse == 'LEFTMOUSE':
# Immediate select without quick delay.
return [
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("deselect_all", True)]}),
+ (operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+ {"properties": [(extend, True)]}),
]
else:
# For right mouse, set the cursor.
@@ -2333,6 +2335,7 @@ def km_sequencercommon(_params):
items.extend([
*_template_space_region_type_toggle(
+ toolbar_key={"type": 'T', "value": 'PRESS'},
sidebar_key={"type": 'N', "value": 'PRESS'},
),
("wm.context_toggle", {"type": 'O', "value": 'PRESS', "shift": True},
@@ -2340,6 +2343,13 @@ def km_sequencercommon(_params):
("sequencer.view_toggle", {"type": 'TAB', "value": 'PRESS', "ctrl": True}, None),
])
+ if _params.select_mouse == 'LEFTMOUSE' and not _params.legacy:
+ # Quick switch to select tool, since left select can't easily
+ # select with any tool active.
+ items.extend([
+ op_tool_cycle("builtin.select_box", {"type": 'W', "value": 'PRESS'}),
+ ])
+
return keymap
@@ -5055,7 +5065,7 @@ def km_image_editor_tool_uv_select(params):
return (
"Image Editor Tool: Uv, Tweak",
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
- {"items": _template_items_tool_select(params, "uv.select", "uv.cursor_set")},
+ {"items": _template_items_tool_select(params, "uv.select", "uv.cursor_set", extend="extend")},
)
@@ -5206,7 +5216,7 @@ def km_3d_view_tool_select(params):
return (
"3D View Tool: Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": _template_items_tool_select(params, "view3d.select", "view3d.cursor3d")},
+ {"items": _template_items_tool_select(params, "view3d.select", "view3d.cursor3d", extend="toggle")},
)
@@ -5913,7 +5923,7 @@ def km_3d_view_tool_edit_gpencil_select(params):
return (
"3D View Tool: Edit Gpencil, Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d")},
+ {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d", extend="toggle")},
)
@@ -6018,7 +6028,7 @@ def km_3d_view_tool_sculpt_gpencil_select(params):
return (
"3D View Tool: Sculpt Gpencil, Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d")},
+ {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d", extend="toggle")},
)
@@ -6049,6 +6059,39 @@ def km_3d_view_tool_sculpt_gpencil_select_lasso(params):
)
+def km_sequencer_editor_tool_select(params):
+ return (
+ "Sequencer Tool: Select",
+ {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
+ {"items": [
+ ("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'},
+ {"properties": [("extend", False), ("deselect_all", not params.legacy)]}),
+ ]},
+ )
+
+
+def km_sequencer_editor_tool_select_box(params):
+ return (
+ "Sequencer Tool: Select Box",
+ {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
+ {"items": _template_items_tool_select_actions_simple(
+ "sequencer.select_box", type=params.tool_tweak, value='ANY',
+ properties=[("tweak", True)],
+ )},
+ )
+
+
+def km_sequencer_editor_tool_cut(params):
+ return (
+ "Sequencer Tool: Cut",
+ {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
+ {"items":[
+ ("sequencer.cut", {"type": 'LEFTMOUSE', "value": 'PRESS'},
+ {"properties": [("type", 'SOFT'), ("side", 'NO_CHANGE'), ("use_cursor_position", True), ("ignore_selection", True)]}),
+ ]},
+ )
+
+
# ------------------------------------------------------------------------------
# Full Configuration
@@ -6262,6 +6305,9 @@ def generate_keymaps(params=None):
km_3d_view_tool_sculpt_gpencil_select_box(params),
km_3d_view_tool_sculpt_gpencil_select_circle(params),
km_3d_view_tool_sculpt_gpencil_select_lasso(params),
+ km_sequencer_editor_tool_select(params),
+ km_sequencer_editor_tool_select_box(params),
+ km_sequencer_editor_tool_cut(params),
]
# ------------------------------------------------------------------------------
diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
index 39d792bd557..a249599b5d7 100644
--- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py
+++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
@@ -37,6 +37,20 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
from math import acos
import array
+ # We simulate the accumulation of dirt in the creases of geometric surfaces
+ # by comparing the vertex normal to the average direction of all vertices
+ # connected to that vertex. We can also simulate surfaces being buffed or
+ # worn by testing protruding surfaces.
+ #
+ # So if the angle between the normal and geometric direction is:
+ # < 90 - dirt has accumulated in the crease
+ # > 90 - surface has been worn or buffed
+ # ~ 90 - surface is flat and is generally unworn and clean
+ #
+ # This method is limited by the complexity or lack there of in the geometry.
+ #
+ # Original code and method by Keith "Wahooney" Boshoff.
+
vert_tone = array.array("f", [0.0]) * len(me.vertices)
# create lookup table for each vertex's connected vertices (via edges)
diff --git a/release/scripts/startup/bl_ui/properties_data_light.py b/release/scripts/startup/bl_ui/properties_data_light.py
index 6f730cf3307..cf894b48e1e 100644
--- a/release/scripts/startup/bl_ui/properties_data_light.py
+++ b/release/scripts/startup/bl_ui/properties_data_light.py
@@ -134,17 +134,15 @@ class DATA_PT_EEVEE_light_distance(DataButtonsPanel, Panel):
light = context.light
layout = self.layout
- layout.active = light.use_shadow
layout.prop(light, "use_custom_distance", text="")
def draw(self, context):
layout = self.layout
light = context.light
+ layout.active = light.use_custom_distance
layout.use_property_split = True
- col = layout.column()
-
- col.prop(light, "cutoff_distance", text="Distance")
+ layout.prop(light, "cutoff_distance", text="Distance")
class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel):
@@ -311,7 +309,8 @@ class DATA_PT_falloff_curve(DataButtonsPanel, Panel):
def draw(self, context):
light = context.light
- self.layout.template_curve_mapping(light, "falloff_curve", use_negative_slope=True)
+ self.layout.template_curve_mapping(
+ light, "falloff_curve", use_negative_slope=True)
class DATA_PT_custom_props_light(DataButtonsPanel, PropertyPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index 82ed701aa4c..cd65980fc0d 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -92,7 +92,7 @@ class INFO_MT_area(Menu):
layout.separator()
- layout.operator("screen.area_dupli", icon='DUPLICATE')
+ layout.operator("screen.area_dupli", icon='WINDOW')
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 097564444d0..af0c23e7892 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -30,6 +30,9 @@ from bpy.app.translations import (
from bl_ui.properties_grease_pencil_common import (
AnnotationDataPanel,
)
+from bl_ui.space_toolsystem_common import (
+ ToolActivePanelHelper,
+)
from rna_prop_ui import PropertyPanel
@@ -89,6 +92,35 @@ def draw_color_balance(layout, color_balance):
split.template_color_picker(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True)
+class SEQUENCER_PT_active_tool(ToolActivePanelHelper, Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "Tool"
+
+
+class SEQUENCER_HT_tool_header(Header):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'TOOL_HEADER'
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.template_header()
+
+ self.draw_tool_settings(context)
+
+ # TODO: options popover.
+
+ def draw_tool_settings(self, context):
+ layout = self.layout
+
+ # Active Tool
+ # -----------
+ from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
+ tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout)
+ tool_mode = context.mode if tool is None else tool.mode
+
+
class SEQUENCER_HT_header(Header):
bl_space_type = 'SEQUENCE_EDITOR'
@@ -97,7 +129,10 @@ class SEQUENCER_HT_header(Header):
st = context.space_data
- layout.template_header()
+ show_region_tool_header = st.show_region_tool_header
+
+ if not show_region_tool_header:
+ layout.template_header()
layout.prop(st, "view_type", text="")
@@ -226,8 +261,12 @@ class SEQUENCER_MT_view(Menu):
# wm_keymap_item_find_props() (see #32595).
layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.prop(st, "show_region_ui")
+ layout.prop(st, "show_region_toolbar")
layout.operator_context = 'INVOKE_DEFAULT'
+ if is_sequencer_view:
+ layout.prop(st, "show_region_hud")
+
if st.view_type == 'SEQUENCER':
layout.prop(st, "show_backdrop", text="Preview as Backdrop")
@@ -268,6 +307,7 @@ class SEQUENCER_MT_view(Menu):
layout.operator_context = 'INVOKE_DEFAULT'
layout.prop(st, "show_seconds")
+ layout.prop(st, "show_locked_time")
layout.prop(st, "show_strip_offset")
layout.separator()
layout.prop(st, "show_markers")
@@ -2128,6 +2168,7 @@ class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
classes = (
SEQUENCER_MT_change,
+ SEQUENCER_HT_tool_header,
SEQUENCER_HT_header,
SEQUENCER_MT_editor_menus,
SEQUENCER_MT_range,
@@ -2153,7 +2194,7 @@ classes = (
SEQUENCER_MT_strip_input,
SEQUENCER_MT_strip_lock_mute,
SEQUENCER_MT_context_menu,
-
+ SEQUENCER_PT_active_tool,
SEQUENCER_PT_strip,
SEQUENCER_PT_effect,
diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py
index 81ccc9216a1..b7c5dcd5437 100644
--- a/release/scripts/startup/bl_ui/space_text.py
+++ b/release/scripts/startup/bl_ui/space_text.py
@@ -30,7 +30,7 @@ class TEXT_HT_header(Header):
st = context.space_data
text = st.text
-
+ is_syntax_highlight_supported = st.is_syntax_highlight_supported()
layout.template_header()
TEXT_MT_editor_menus.draw_collapsible(context, layout)
@@ -43,7 +43,18 @@ class TEXT_HT_header(Header):
layout.separator_spacer()
row = layout.row(align=True)
- row.template_ID(st, "text", new="text.new", unlink="text.unlink", open="text.open")
+ row.template_ID(st, "text", new="text.new",
+ unlink="text.unlink", open="text.open")
+
+ if text:
+ is_osl = text.name.endswith((".osl", ".osl"))
+ if is_osl:
+ row.operator("node.shader_script_update",
+ text="", icon='FILE_REFRESH')
+ else:
+ row = layout.row()
+ row.active = is_syntax_highlight_supported
+ row.operator("text.run_script", text="", icon='PLAY')
layout.separator_spacer()
@@ -51,28 +62,10 @@ class TEXT_HT_header(Header):
row.prop(st, "show_line_numbers", text="")
row.prop(st, "show_word_wrap", text="")
- is_syntax_highlight_supported = st.is_syntax_highlight_supported()
syntax = row.row(align=True)
syntax.active = is_syntax_highlight_supported
syntax.prop(st, "show_syntax_highlight", text="")
- if text:
- text_name = text.name
- is_osl = text_name.endswith((".osl", ".oso"))
-
- row = layout.row()
- if is_osl:
- row = layout.row()
- row.operator("node.shader_script_update")
- else:
- row = layout.row()
- row.active = text_name.endswith(".py")
- row.prop(text, "use_module")
-
- row = layout.row()
- row.active = is_syntax_highlight_supported
- row.operator("text.run_script")
-
class TEXT_HT_footer(Header):
bl_space_type = 'TEXT_EDITOR'
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
index 05785b85dfc..4dc724299f0 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_common.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -390,6 +390,14 @@ class ToolSelectPanelHelper:
if tool is not None:
tool.refresh_from_context()
return tool
+ elif space_type == 'SEQUENCE_EDITOR':
+ space_data = context.space_data
+ if mode is None:
+ mode = space_data.view_type
+ tool = context.workspace.tools.from_space_sequencer(mode, create=create)
+ if tool is not None:
+ tool.refresh_from_context()
+ return tool
return None
@staticmethod
@@ -656,6 +664,8 @@ class ToolSelectPanelHelper:
return space_type, space_data.mode
elif space_type == 'NODE_EDITOR':
return space_type, None
+ elif space_type == 'SEQUENCE_EDITOR':
+ return space_type, context.space_data.view_type
else:
return None, None
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 170b635f7e1..c03d681f2b2 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1707,6 +1707,51 @@ class _defs_node_edit:
keymap="Node Tool: Links Cut",
)
+class _defs_sequencer_generic:
+
+ @ToolDef.from_fn
+ def cut():
+ def draw_settings(_context, layout, tool):
+ props = tool.operator_properties("sequencer.cut")
+ row = layout.row()
+ row.use_property_split = False
+ row.prop(props, "type", expand=True)
+ return dict(
+ idname="builtin.cut",
+ label="Cut",
+ icon="ops.mesh.knife_tool",
+ widget=None,
+ keymap="Sequencer Tool: Cut",
+ draw_settings=draw_settings,
+ )
+
+class _defs_sequencer_select:
+ @ToolDef.from_fn
+ def select():
+ return dict(
+ idname="builtin.select",
+ label="Select",
+ icon="ops.generic.select",
+ widget=None,
+ keymap="Sequencer Tool: Select",
+ )
+ @ToolDef.from_fn
+ def box():
+ def draw_settings(_context, layout, tool):
+ props = tool.operator_properties("sequencer.select_box")
+ row = layout.row()
+ row.use_property_split = False
+ row.prop(props, "mode", text="", expand=True, icon_only=True)
+ pass
+ return dict(
+ idname="builtin.select_box",
+ label="Select Box",
+ icon="ops.generic.select_box",
+ widget=None,
+ keymap="Sequencer Tool: Select Box",
+ draw_settings=draw_settings,
+ )
+
class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
bl_space_type = 'IMAGE_EDITOR'
@@ -2150,12 +2195,71 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
*_tools_annotate,
],
}
+class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'TOOLS'
+ bl_label = "Tools" # not visible
+ bl_options = {'HIDE_HEADER'}
+
+ # Satisfy the 'ToolSelectPanelHelper' API.
+ keymap_prefix = "Sequence Editor Tool:"
+
+ # Default group to use as a fallback.
+ tool_fallback_id = "builtin.select"
+
+ @classmethod
+ def tools_from_context(cls, context, mode=None):
+ if mode is None:
+ if context.space_data:
+ mode = context.space_data.view_type
+ for tools in (cls._tools[None], cls._tools.get(mode, ())):
+ for item in tools:
+ if not (type(item) is ToolDef) and callable(item):
+ yield from item(context)
+ else:
+ yield item
+
+ @classmethod
+ def tools_all(cls):
+ yield from cls._tools.items()
+ _tools_select = (
+ (
+ _defs_sequencer_select.select,
+ _defs_sequencer_select.box,
+ ),
+ )
+ _tools_annotate = (
+ (
+ _defs_annotate.scribble,
+ _defs_annotate.line,
+ _defs_annotate.poly,
+ _defs_annotate.eraser,
+ ),
+ )
+
+ _tools = {
+ None: [
+ ],
+ 'PREVIEW': [
+ *_tools_annotate,
+ ],
+ 'SEQUENCER': [
+ *_tools_select,
+ _defs_sequencer_generic.cut,
+ ],
+ 'SEQUENCER_PREVIEW': [
+ *_tools_select,
+ *_tools_annotate,
+ _defs_sequencer_generic.cut,
+ ],
+ }
classes = (
IMAGE_PT_tools_active,
NODE_PT_tools_active,
VIEW3D_PT_tools_active,
+ SEQUENCER_PT_tools_active,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 4f35bcc29df..ad5e7b5442c 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -997,6 +997,7 @@ class PreferenceThemeSpacePanel:
"freestyle_face_mark",
"split_normal",
"bone_solid",
+ "bone_locked_weight",
"paint_curve_pivot",
},
'GRAPH_EDITOR': {
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 011c2a8b39a..19d5e3da309 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -560,12 +560,23 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
layout.operator("image.save_all_modified", text="Save All Images", icon='FILE_TICK')
+class VIEW3D_PT_mask(View3DPanel, Panel):
+ bl_category = "Tool"
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_label = "Masking"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ pass
+
+
# TODO, move to space_view3d.py
class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".imagepaint" # dot on purpose (access from topbar)
- bl_label = "Mask"
+ bl_label = "Stencil Mask"
bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = "VIEW3D_PT_mask"
bl_ui_units_x = 14
@classmethod
@@ -1192,6 +1203,7 @@ class VIEW3D_PT_tools_imagepaint_options_cavity(View3DPaintPanel, Panel):
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Cavity Mask"
bl_parent_id = "VIEW3D_PT_tools_imagepaint_options"
+ bl_parent_id = "VIEW3D_PT_mask"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
@@ -1876,7 +1888,7 @@ classes = (
VIEW3D_PT_tools_curveedit_options_stroke,
VIEW3D_PT_tools_armatureedit_options,
VIEW3D_PT_tools_posemode_options,
-
+
VIEW3D_PT_slots_projectpaint,
VIEW3D_PT_tools_brush_select,
VIEW3D_PT_tools_brush_settings,
@@ -1886,7 +1898,6 @@ classes = (
VIEW3D_PT_tools_brush_clone,
TEXTURE_UL_texpaintslots,
VIEW3D_MT_tools_projectpaint_uvlayer,
- VIEW3D_PT_stencil_projectpaint,
VIEW3D_PT_tools_brush_texture,
VIEW3D_PT_tools_mask_texture,
VIEW3D_PT_tools_brush_stroke,
@@ -1912,9 +1923,13 @@ classes = (
VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar,
VIEW3D_PT_tools_vertexpaint_options,
+ VIEW3D_PT_mask,
+ VIEW3D_PT_stencil_projectpaint,
+ VIEW3D_PT_tools_imagepaint_options_cavity,
+
VIEW3D_PT_tools_imagepaint_symmetry,
VIEW3D_PT_tools_imagepaint_options,
- VIEW3D_PT_tools_imagepaint_options_cavity,
+
VIEW3D_PT_tools_imagepaint_options_external,
VIEW3D_MT_tools_projectpaint_stencil,
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 10bb1bd3c9c..2b592c9e550 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -935,10 +935,7 @@ void blf_draw_buffer__start(FontBLF *font)
{
FontBufInfoBLF *buf_info = &font->buf_info;
- buf_info->col_char[0] = buf_info->col_init[0] * 255;
- buf_info->col_char[1] = buf_info->col_init[1] * 255;
- buf_info->col_char[2] = buf_info->col_init[2] * 255;
- buf_info->col_char[3] = buf_info->col_init[3] * 255;
+ rgba_float_to_uchar(buf_info->col_char, buf_info->col_init);
if (buf_info->display) {
copy_v4_v4(buf_info->col_float, buf_info->col_init);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 963e3158d46..9da17d777cd 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -249,6 +249,10 @@ typedef enum eAnimData_Recalc {
ADT_RECALC_ALL = (ADT_RECALC_DRIVERS | ADT_RECALC_ANIM),
} eAnimData_Recalc;
+bool BKE_animsys_store_rna_setting(struct PointerRNA *ptr,
+ const char *rna_path,
+ const int array_index,
+ struct PathResolvedRNA *r_result);
bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_value);
bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 75e14b7efca..4fcb10b29f3 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 282
-#define BLENDER_SUBVERSION 6
+#define BLENDER_VERSION 283
+#define BLENDER_SUBVERSION 1
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
@@ -36,7 +36,7 @@
/** Can be left blank, otherwise a,b,c... etc with no quotes. */
#define BLENDER_VERSION_CHAR
/** alpha/beta/rc/release, docs use this. */
-#define BLENDER_VERSION_CYCLE beta
+#define BLENDER_VERSION_CYCLE alpha
/** Optionally set to 1,2,... for example to get alpha1 or rc2. */
#define BLENDER_VERSION_CYCLE_NUMBER
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 17de53be42a..2862dda8ead 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -74,11 +74,11 @@ typedef struct ClothSolverResult {
* own connectivity of the mesh based on the actual edges in the mesh.
*/
typedef struct Cloth {
- struct ClothVertex *verts; /* The vertices that represent this cloth. */
- struct LinkNode *springs; /* The springs connecting the mesh. */
- unsigned int numsprings; /* The count of springs. */
- unsigned int mvert_num; /* The number of verts == m * n. */
- unsigned int tri_num;
+ struct ClothVertex *verts; /* The vertices that represent this cloth. */
+ struct LinkNode *springs; /* The springs connecting the mesh. */
+ unsigned int numsprings; /* The count of springs. */
+ unsigned int mvert_num; /* The number of verts == m * n. */
+ unsigned int primitive_num; /* Number of triangles for cloth and edges for hair. */
unsigned char old_solver_type; /* unused, only 1 solver here */
unsigned char pad2;
short pad3;
@@ -89,6 +89,7 @@ typedef struct Cloth {
struct EdgeSet *edgeset; /* used for selfcollisions */
int last_frame;
float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */
+ struct MEdge *edges; /* Used for hair collisions. */
} Cloth;
/**
@@ -265,15 +266,6 @@ int cloth_bvh_collision(struct Depsgraph *depsgraph,
float step,
float dt);
-void cloth_find_point_contacts(struct Depsgraph *depsgraph,
- struct Object *ob,
- struct ClothModifierData *clmd,
- float step,
- float dt,
- ColliderContacts **r_collider_contacts,
- int *r_totcolliders);
-void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders);
-
////////////////////////////////////////////////
/////////////////////////////////////////////////
diff --git a/source/blender/blenkernel/BKE_lightprobe.h b/source/blender/blenkernel/BKE_lightprobe.h
index bd442c97000..153ad9bb915 100644
--- a/source/blender/blenkernel/BKE_lightprobe.h
+++ b/source/blender/blenkernel/BKE_lightprobe.h
@@ -29,6 +29,7 @@ struct LightProbe;
struct Main;
void BKE_lightprobe_init(struct LightProbe *probe);
+void BKE_lightprobe_type_set(struct LightProbe *probe, const short lightprobe_type);
void *BKE_lightprobe_add(struct Main *bmain, const char *name);
void BKE_lightprobe_copy_data(struct Main *bmain,
struct LightProbe *probe_dst,
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 33bcd3bc91d..aba3a5d5b8d 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -504,6 +504,7 @@ enum {
SEQ_SIDE_LEFT,
SEQ_SIDE_RIGHT,
SEQ_SIDE_BOTH,
+ SEQ_SIDE_NO_CHANGE,
};
int BKE_sequencer_find_next_prev_edit(struct Scene *scene,
int cfra,
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 32420e2e894..be6622e5d42 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1665,11 +1665,11 @@ void BKE_keyingsets_free(ListBase *list)
/* ***************************************** */
/* Evaluation Data-Setting Backend */
-static bool animsys_store_rna_setting(PointerRNA *ptr,
- /* typically 'fcu->rna_path', 'fcu->array_index' */
- const char *rna_path,
- const int array_index,
- PathResolvedRNA *r_result)
+bool BKE_animsys_store_rna_setting(PointerRNA *ptr,
+ /* typically 'fcu->rna_path', 'fcu->array_index' */
+ const char *rna_path,
+ const int array_index,
+ PathResolvedRNA *r_result)
{
bool success = false;
const char *path = rna_path;
@@ -1880,7 +1880,7 @@ static void animsys_write_orig_anim_rna(PointerRNA *ptr,
}
PathResolvedRNA orig_anim_rna;
/* TODO(sergey): Should be possible to cache resolved path in dependency graph somehow. */
- if (animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) {
+ if (BKE_animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) {
BKE_animsys_write_rna_setting(&orig_anim_rna, value);
}
}
@@ -1910,7 +1910,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr,
continue;
}
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
BKE_animsys_write_rna_setting(&anim_rna, curval);
if (flush_to_original) {
@@ -1944,7 +1944,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
* NOTE: for 'layering' option later on, we should check if we should remove old value
* before adding new to only be done when drivers only changed. */
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
ok = BKE_animsys_write_rna_setting(&anim_rna, curval);
}
@@ -2023,7 +2023,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0 && !BKE_fcurve_is_empty(fcu)) {
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
BKE_animsys_write_rna_setting(&anim_rna, curval);
}
@@ -3803,7 +3803,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
/* for each override, simply execute... */
for (aor = adt->overrides.first; aor; aor = aor->next) {
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) {
+ if (BKE_animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) {
BKE_animsys_write_rna_setting(&anim_rna, aor->value);
}
}
@@ -4125,7 +4125,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCu
// printf("\told val = %f\n", fcu->curval);
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (BKE_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 = calculate_fcurve(&anim_rna, fcu, ctime);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index c26800aefba..7332c3e0d43 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -190,22 +190,36 @@ static BVHTree *bvhtree_build_from_cloth(ClothModifierData *clmd, float epsilon)
vt = cloth->tri;
/* in the moment, return zero if no faces there */
- if (!cloth->tri_num) {
+ if (!cloth->primitive_num) {
return NULL;
}
/* create quadtree with k=26 */
- bvhtree = BLI_bvhtree_new(cloth->tri_num, epsilon, 4, 26);
+ bvhtree = BLI_bvhtree_new(cloth->primitive_num, epsilon, 4, 26);
/* fill tree */
- for (i = 0; i < cloth->tri_num; i++, vt++) {
- float co[3][3];
+ if (clmd->hairdata == NULL) {
+ for (i = 0; i < cloth->primitive_num; i++, vt++) {
+ float co[3][3];
- copy_v3_v3(co[0], verts[vt->tri[0]].xold);
- copy_v3_v3(co[1], verts[vt->tri[1]].xold);
- copy_v3_v3(co[2], verts[vt->tri[2]].xold);
+ copy_v3_v3(co[0], verts[vt->tri[0]].xold);
+ copy_v3_v3(co[1], verts[vt->tri[1]].xold);
+ copy_v3_v3(co[2], verts[vt->tri[2]].xold);
- BLI_bvhtree_insert(bvhtree, i, co[0], 3);
+ BLI_bvhtree_insert(bvhtree, i, co[0], 3);
+ }
+ }
+ else {
+ MEdge *edges = cloth->edges;
+
+ for (i = 0; i < cloth->primitive_num; i++) {
+ float co[2][3];
+
+ copy_v3_v3(co[0], verts[edges[i].v1].xold);
+ copy_v3_v3(co[1], verts[edges[i].v2].xold);
+
+ BLI_bvhtree_insert(bvhtree, i, co[0], 2);
+ }
}
/* balance tree */
@@ -222,6 +236,8 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self)
ClothVertex *verts = cloth->verts;
const MVertTri *vt;
+ BLI_assert(!(clmd->hairdata != NULL && self));
+
if (self) {
bvhtree = cloth->bvhselftree;
}
@@ -236,39 +252,59 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self)
vt = cloth->tri;
/* update vertex position in bvh tree */
- if (verts && vt) {
- for (i = 0; i < cloth->tri_num; i++, vt++) {
- float co[3][3], co_moving[3][3];
- bool ret;
-
- /* copy new locations into array */
- if (moving) {
- copy_v3_v3(co[0], verts[vt->tri[0]].txold);
- copy_v3_v3(co[1], verts[vt->tri[1]].txold);
- copy_v3_v3(co[2], verts[vt->tri[2]].txold);
-
- /* update moving positions */
- copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
- copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
- copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx);
-
- ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
- }
- else {
- copy_v3_v3(co[0], verts[vt->tri[0]].tx);
- copy_v3_v3(co[1], verts[vt->tri[1]].tx);
- copy_v3_v3(co[2], verts[vt->tri[2]].tx);
+ if (clmd->hairdata == NULL) {
+ if (verts && vt) {
+ for (i = 0; i < cloth->primitive_num; i++, vt++) {
+ float co[3][3], co_moving[3][3];
+ bool ret;
+
+ /* copy new locations into array */
+ if (moving) {
+ copy_v3_v3(co[0], verts[vt->tri[0]].txold);
+ copy_v3_v3(co[1], verts[vt->tri[1]].txold);
+ copy_v3_v3(co[2], verts[vt->tri[2]].txold);
+
+ /* update moving positions */
+ copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
+ copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
+ copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx);
+
+ ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
+ }
+ else {
+ copy_v3_v3(co[0], verts[vt->tri[0]].tx);
+ copy_v3_v3(co[1], verts[vt->tri[1]].tx);
+ copy_v3_v3(co[2], verts[vt->tri[2]].tx);
- ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
- }
+ ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
+ }
- /* check if tree is already full */
- if (ret == false) {
- break;
+ /* check if tree is already full */
+ if (ret == false) {
+ break;
+ }
}
+
+ BLI_bvhtree_update_tree(bvhtree);
}
+ }
+ else {
+ if (verts) {
+ MEdge *edges = cloth->edges;
+
+ for (i = 0; i < cloth->primitive_num; i++) {
+ float co[2][3];
- BLI_bvhtree_update_tree(bvhtree);
+ copy_v3_v3(co[0], verts[edges[i].v1].tx);
+ copy_v3_v3(co[1], verts[edges[i].v2].tx);
+
+ if (!BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 2)) {
+ break;
+ }
+ }
+
+ BLI_bvhtree_update_tree(bvhtree);
+ }
}
}
@@ -900,7 +936,13 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
}
/* save face information */
- clmd->clothObject->tri_num = looptri_num;
+ if (clmd->hairdata == NULL) {
+ clmd->clothObject->primitive_num = looptri_num;
+ }
+ else {
+ clmd->clothObject->primitive_num = mesh->totedge;
+ }
+
clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris");
if (clmd->clothObject->tri == NULL) {
cloth_free_modifier(clmd);
@@ -910,6 +952,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
}
BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
+ clmd->clothObject->edges = mesh->medge;
+
/* Free the springs since they can't be correct if the vertices
* changed.
*/
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 220b9417a6c..5db42618a9e 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -33,6 +33,7 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_task.h"
#include "BLI_threads.h"
@@ -193,17 +194,17 @@ BLI_INLINE int next_ind(int i)
return (++i < 3) ? i : 0;
}
-static float compute_collision_point(float a1[3],
- const float a2[3],
- const float a3[3],
- const float b1[3],
- const float b2[3],
- const float b3[3],
- bool culling,
- bool use_normal,
- float r_a[3],
- float r_b[3],
- float r_vec[3])
+static float compute_collision_point_tri_tri(const float a1[3],
+ const float a2[3],
+ const float a3[3],
+ const float b1[3],
+ const float b2[3],
+ const float b3[3],
+ bool culling,
+ bool use_normal,
+ float r_a[3],
+ float r_b[3],
+ float r_vec[3])
{
float a[3][3];
float b[3][3];
@@ -423,6 +424,179 @@ static float compute_collision_point(float a1[3],
return dist;
}
+static float compute_collision_point_edge_tri(const float a1[3],
+ const float a2[3],
+ const float b1[3],
+ const float b2[3],
+ const float b3[3],
+ bool culling,
+ bool use_normal,
+ float r_a[3],
+ float r_b[3],
+ float r_vec[3])
+{
+ float a[2][3];
+ float b[3][3];
+ float dist = FLT_MAX;
+ float tmp_co1[3], tmp_co2[3];
+ float isect_a[3];
+ bool isect = false;
+ float tmp, tmp_vec[3];
+ float normal[3], cent[3];
+ bool backside = false;
+
+ copy_v3_v3(a[0], a1);
+ copy_v3_v3(a[1], a2);
+
+ copy_v3_v3(b[0], b1);
+ copy_v3_v3(b[1], b2);
+ copy_v3_v3(b[2], b3);
+
+ normal_tri_v3(normal, b[0], b[1], b[2]);
+
+ /* Find intersection. */
+ if (isect_line_segment_tri_v3(a[0], a[1], b[0], b[1], b[2], &tmp, NULL)) {
+ interp_v3_v3v3(isect_a, a[0], a[1], tmp);
+ isect = true;
+ }
+
+ /* Determine collision side. */
+ if (culling) {
+ if (isect) {
+ backside = true;
+ }
+ else {
+ mid_v3_v3v3v3(cent, b[0], b[1], b[2]);
+
+ for (int i = 0; i < 2; i++) {
+ sub_v3_v3v3(tmp_vec, a[i], cent);
+ if (dot_v3v3(tmp_vec, normal) < 0.0f) {
+ backside = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (isect) {
+ /* Edge intersection. */
+ copy_v3_v3(r_a, isect_a);
+ copy_v3_v3(r_b, isect_a);
+
+ copy_v3_v3(r_vec, normal);
+
+ return 0.0f;
+ }
+
+ if (backside) {
+ float maxdist = 0.0f;
+ bool found = false;
+
+ /* Point projections. */
+ for (int i = 0; i < 2; i++) {
+ if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) {
+ if (tmp > maxdist) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ madd_v3_v3v3fl(r_b, a[i], normal, tmp);
+ found = true;
+ }
+ }
+ }
+
+ /* Edge projections. */
+ for (int i = 0; i < 3; i++) {
+ float dir[3];
+
+ sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]);
+ cross_v3_v3v3(dir, tmp_vec, normal);
+
+ if (isect_line_plane_v3(tmp_co1, a[0], a[1], b[i], dir) &&
+ point_in_slice_seg(tmp_co1, a[0], a[1]) &&
+ point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)])) {
+ closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]);
+ sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2);
+ tmp = len_v3(tmp_vec);
+
+ if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ found = true;
+ }
+ }
+ }
+
+ /* If no point is found, will fallback onto regular proximity test below. */
+ if (found) {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+
+ if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+
+ return 0.0f;
+ }
+ }
+
+ /* Closest point. */
+ for (int i = 0; i < 2; i++) {
+ closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]);
+ tmp = len_squared_v3v3(tmp_co1, a[i]);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ copy_v3_v3(r_b, tmp_co1);
+ }
+ }
+
+ /* Closest edge. */
+ if (!isect) {
+ for (int j = 0; j < 3; j++) {
+ isect_seg_seg_v3(a[0], a[1], b[j], b[next_ind(j)], tmp_co1, tmp_co2);
+ tmp = len_squared_v3v3(tmp_co1, tmp_co2);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ }
+ }
+ }
+
+ if (isect) {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+ dist = 0.0f;
+ }
+ else {
+ sub_v3_v3v3(r_vec, r_a, r_b);
+ dist = sqrtf(dist);
+ }
+
+ if (culling && use_normal) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+ else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) {
+ return FLT_MAX;
+ }
+
+ return dist;
+}
+
// w3 is not perfect
static void collision_compute_barycentric(
const float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3)
@@ -494,6 +668,7 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
float v1[3], v2[3], relativeVelocity[3];
float magrelVel;
float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
+ const bool is_hair = (clmd->hairdata != NULL);
cloth1 = clmd->clothObject;
@@ -509,14 +684,32 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
continue;
}
- /* Compute barycentric coordinates for both collision points. */
- collision_compute_barycentric(collpair->pa,
- cloth1->verts[collpair->ap1].tx,
- cloth1->verts[collpair->ap2].tx,
- cloth1->verts[collpair->ap3].tx,
- &w1,
- &w2,
- &w3);
+ /* Compute barycentric coordinates and relative "velocity" for both collision points. */
+ if (is_hair) {
+ w2 = line_point_factor_v3(
+ collpair->pa, cloth1->verts[collpair->ap1].tx, cloth1->verts[collpair->ap2].tx);
+
+ w1 = 1.0f - w2;
+
+ interp_v3_v3v3(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, w2);
+ }
+ else {
+ collision_compute_barycentric(collpair->pa,
+ cloth1->verts[collpair->ap1].tx,
+ cloth1->verts[collpair->ap2].tx,
+ cloth1->verts[collpair->ap3].tx,
+ &w1,
+ &w2,
+ &w3);
+
+ collision_interpolateOnTriangle(v1,
+ cloth1->verts[collpair->ap1].tv,
+ cloth1->verts[collpair->ap2].tv,
+ cloth1->verts[collpair->ap3].tv,
+ w1,
+ w2,
+ w3);
+ }
collision_compute_barycentric(collpair->pb,
collmd->current_xnew[collpair->bp1].co,
@@ -526,15 +719,6 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
&u2,
&u3);
- /* Calculate relative "velocity". */
- collision_interpolateOnTriangle(v1,
- cloth1->verts[collpair->ap1].tv,
- cloth1->verts[collpair->ap2].tv,
- cloth1->verts[collpair->ap3].tv,
- w1,
- w2,
- w3);
-
collision_interpolateOnTriangle(v2,
collmd->current_v[collpair->bp1].co,
collmd->current_v[collpair->bp2].co,
@@ -576,7 +760,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
VECADDMUL(i1, vrel_t_pre, w1 * impulse);
VECADDMUL(i2, vrel_t_pre, w2 * impulse);
- VECADDMUL(i3, vrel_t_pre, w3 * impulse);
+
+ if (!is_hair) {
+ VECADDMUL(i3, vrel_t_pre, w3 * impulse);
+ }
}
/* Apply velocity stopping impulse. */
@@ -588,8 +775,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
VECADDMUL(i2, collpair->normal, w2 * impulse);
cloth1->verts[collpair->ap2].impulse_count++;
- VECADDMUL(i3, collpair->normal, w3 * impulse);
- cloth1->verts[collpair->ap3].impulse_count++;
+ if (!is_hair) {
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ cloth1->verts[collpair->ap3].impulse_count++;
+ }
time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
@@ -609,7 +798,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
VECADDMUL(i1, collpair->normal, impulse);
VECADDMUL(i2, collpair->normal, impulse);
- VECADDMUL(i3, collpair->normal, impulse);
+
+ if (!is_hair) {
+ VECADDMUL(i3, collpair->normal, impulse);
+ }
}
result = 1;
@@ -627,11 +819,17 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
VECADDMUL(i1, collpair->normal, w1 * impulse);
VECADDMUL(i2, collpair->normal, w2 * impulse);
- VECADDMUL(i3, collpair->normal, w3 * impulse);
+
+ if (!is_hair) {
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ }
cloth1->verts[collpair->ap1].impulse_count++;
cloth1->verts[collpair->ap2].impulse_count++;
- cloth1->verts[collpair->ap3].impulse_count++;
+
+ if (!is_hair) {
+ cloth1->verts[collpair->ap3].impulse_count++;
+ }
result = 1;
}
@@ -656,9 +854,11 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
cloth1->verts[collpair->ap2].impulse[j] = i2[j];
}
- if (cloth1->verts[collpair->ap3].impulse_count > 0 &&
- ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) {
- cloth1->verts[collpair->ap3].impulse[j] = i3[j];
+ if (!is_hair) {
+ if (cloth1->verts[collpair->ap3].impulse_count > 0 &&
+ ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) {
+ cloth1->verts[collpair->ap3].impulse[j] = i3[j];
+ }
}
}
}
@@ -875,17 +1075,17 @@ static void cloth_collision(void *__restrict userdata,
tri_b = &collmd->tri[data->overlap[index].indexB];
/* Compute distance and normal. */
- distance = compute_collision_point(verts1[tri_a->tri[0]].tx,
- verts1[tri_a->tri[1]].tx,
- verts1[tri_a->tri[2]].tx,
- collmd->current_xnew[tri_b->tri[0]].co,
- collmd->current_xnew[tri_b->tri[1]].co,
- collmd->current_xnew[tri_b->tri[2]].co,
- data->culling,
- data->use_normal,
- pa,
- pb,
- vect);
+ distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx,
+ verts1[tri_a->tri[1]].tx,
+ verts1[tri_a->tri[2]].tx,
+ collmd->current_xnew[tri_b->tri[0]].co,
+ collmd->current_xnew[tri_b->tri[1]].co,
+ collmd->current_xnew[tri_b->tri[2]].co,
+ data->culling,
+ data->use_normal,
+ pa,
+ pb,
+ vect);
if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
collpair[index].ap1 = tri_a->tri[0];
@@ -946,17 +1146,17 @@ static void cloth_selfcollision(void *__restrict userdata,
}
/* Compute distance and normal. */
- distance = compute_collision_point(verts1[tri_a->tri[0]].tx,
- verts1[tri_a->tri[1]].tx,
- verts1[tri_a->tri[2]].tx,
- verts1[tri_b->tri[0]].tx,
- verts1[tri_b->tri[1]].tx,
- verts1[tri_b->tri[2]].tx,
- false,
- false,
- pa,
- pb,
- vect);
+ distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx,
+ verts1[tri_a->tri[1]].tx,
+ verts1[tri_a->tri[2]].tx,
+ verts1[tri_b->tri[0]].tx,
+ verts1[tri_b->tri[1]].tx,
+ verts1[tri_b->tri[2]].tx,
+ false,
+ false,
+ pa,
+ pb,
+ vect);
if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
collpair[index].ap1 = tri_a->tri[0];
@@ -983,6 +1183,64 @@ static void cloth_selfcollision(void *__restrict userdata,
}
}
+static void hair_collision(void *__restrict userdata,
+ const int index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ ColDetectData *data = (ColDetectData *)userdata;
+
+ ClothModifierData *clmd = data->clmd;
+ CollisionModifierData *collmd = data->collmd;
+ CollPair *collpair = data->collisions;
+ const MVertTri *tri_coll;
+ const MEdge *edge_coll;
+ ClothVertex *verts1 = clmd->clothObject->verts;
+ float distance = 0.0f;
+ float epsilon1 = clmd->coll_parms->epsilon;
+ float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
+ float pa[3], pb[3], vect[3];
+
+ /* TODO: This is not efficient. Might be wise to instead build an array before iterating, to
+ * avoid walking the list every time. */
+ edge_coll = &clmd->clothObject->edges[data->overlap[index].indexA];
+ tri_coll = &collmd->tri[data->overlap[index].indexB];
+
+ /* Compute distance and normal. */
+ distance = compute_collision_point_edge_tri(verts1[edge_coll->v1].tx,
+ verts1[edge_coll->v2].tx,
+ collmd->current_x[tri_coll->tri[0]].co,
+ collmd->current_x[tri_coll->tri[1]].co,
+ collmd->current_x[tri_coll->tri[2]].co,
+ data->culling,
+ data->use_normal,
+ pa,
+ pb,
+ vect);
+
+ if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
+ collpair[index].ap1 = edge_coll->v1;
+ collpair[index].ap2 = edge_coll->v2;
+
+ collpair[index].bp1 = tri_coll->tri[0];
+ collpair[index].bp2 = tri_coll->tri[1];
+ collpair[index].bp3 = tri_coll->tri[2];
+
+ copy_v3_v3(collpair[index].pa, pa);
+ copy_v3_v3(collpair[index].pb, pb);
+ copy_v3_v3(collpair[index].vector, vect);
+
+ normalize_v3_v3(collpair[index].normal, collpair[index].vector);
+
+ collpair[index].distance = distance;
+ collpair[index].flag = 0;
+
+ data->collided = true;
+ }
+ else {
+ collpair[index].flag = COLLISION_INACTIVE;
+ }
+}
+
static void add_collision_object(ListBase *relations,
Object *ob,
int level,
@@ -1148,6 +1406,7 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd,
bool culling,
bool use_normal)
{
+ const bool is_hair = (clmd->hairdata != NULL);
*collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array");
ColDetectData data = {
@@ -1163,7 +1422,8 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd,
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = true;
- BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings);
+ BLI_task_parallel_range(
+ 0, numresult, &data, is_hair ? hair_collision : cloth_collision, &settings);
return data.collided;
}
@@ -1308,8 +1568,14 @@ int cloth_bvh_collision(
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
bvhtree_update_from_cloth(clmd, false, false);
- collobjs = BKE_collision_objects_create(
- depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ /* Enable self collision if this is a hair sim */
+ const bool is_hair = (clmd->hairdata != NULL);
+
+ collobjs = BKE_collision_objects_create(depsgraph,
+ is_hair ? NULL : ob,
+ clmd->coll_parms->group,
+ &numcollobj,
+ eModifierType_Collision);
if (collobjs) {
coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts");
@@ -1474,286 +1740,3 @@ void collision_get_collider_velocity(float vel_old[3],
/* XXX assume constant velocity of the collider for now */
copy_v3_v3(vel_old, vel_new);
}
-
-BLI_INLINE bool cloth_point_face_collision_params(const float p1[3],
- const float p2[3],
- const float v0[3],
- const float v1[3],
- const float v2[3],
- float r_nor[3],
- float *r_lambda,
- float r_w[3])
-{
- float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3];
- float nor_v0p2, nor_p1p2;
-
- sub_v3_v3v3(edge1, v1, v0);
- sub_v3_v3v3(edge2, v2, v0);
- cross_v3_v3v3(r_nor, edge1, edge2);
- normalize_v3(r_nor);
-
- sub_v3_v3v3(v0p2, p2, v0);
- nor_v0p2 = dot_v3v3(v0p2, r_nor);
- madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
- interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
-
- sub_v3_v3v3(p1p2, p2, p1);
- nor_p1p2 = dot_v3v3(p1p2, r_nor);
- *r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f);
-
- return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f;
-}
-
-static CollPair *cloth_point_collpair(float p1[3],
- const float p2[3],
- const MVert *mverts,
- int bp1,
- int bp2,
- int bp3,
- int index_cloth,
- int index_coll,
- float epsilon,
- CollPair *collpair)
-{
- const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
- float lambda /*, distance1 */, distance2;
- float facenor[3], v1p1[3], v1p2[3];
- float w[3];
-
- if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w)) {
- return collpair;
- }
-
- sub_v3_v3v3(v1p1, p1, co1);
- // distance1 = dot_v3v3(v1p1, facenor);
- sub_v3_v3v3(v1p2, p2, co1);
- distance2 = dot_v3v3(v1p2, facenor);
- // if (distance2 > epsilon || (distance1 < 0.0f && distance2 < 0.0f))
- if (distance2 > epsilon) {
- return collpair;
- }
-
- collpair->face1 = index_cloth; /* XXX actually not a face, but equivalent index for point */
- collpair->face2 = index_coll;
- collpair->ap1 = index_cloth;
- collpair->ap2 = collpair->ap3 = -1; /* unused */
- collpair->bp1 = bp1;
- collpair->bp2 = bp2;
- collpair->bp3 = bp3;
-
- /* note: using the second point here, which is
- * the current updated position that needs to be corrected
- */
- copy_v3_v3(collpair->pa, p2);
- collpair->distance = distance2;
- mul_v3_v3fl(collpair->vector, facenor, -distance2);
-
- interp_v3_v3v3v3(collpair->pb, co1, co2, co3, w);
-
- copy_v3_v3(collpair->normal, facenor);
- collpair->time = lambda;
- collpair->flag = 0;
-
- collpair++;
- return collpair;
-}
-
-/* Determines collisions on overlap,
- * collisions are written to collpair[i] and collision+number_collision_found is returned. */
-static CollPair *cloth_point_collision(ModifierData *md1,
- ModifierData *md2,
- BVHTreeOverlap *overlap,
- float epsilon,
- CollPair *collpair,
- float UNUSED(dt))
-{
- ClothModifierData *clmd = (ClothModifierData *)md1;
- CollisionModifierData *collmd = (CollisionModifierData *)md2;
- /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
- ClothVertex *vert = NULL;
- const MVertTri *vt;
- const MVert *mverts = collmd->current_x;
-
- vert = &clmd->clothObject->verts[overlap->indexA];
- vt = &collmd->tri[overlap->indexB];
-
- collpair = cloth_point_collpair(vert->tx,
- vert->x,
- mverts,
- vt->tri[0],
- vt->tri[1],
- vt->tri[2],
- overlap->indexA,
- overlap->indexB,
- epsilon,
- collpair);
-
- return collpair;
-}
-
-static void cloth_points_objcollisions_nearcheck(ClothModifierData *clmd,
- CollisionModifierData *collmd,
- CollPair **collisions,
- CollPair **collisions_index,
- int numresult,
- BVHTreeOverlap *overlap,
- float epsilon,
- double dt)
-{
- int i;
-
- /* can return 2 collisions in total */
- *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult * 2, "collision array");
- *collisions_index = *collisions;
-
- for (i = 0; i < numresult; i++) {
- *collisions_index = cloth_point_collision(
- (ModifierData *)clmd, (ModifierData *)collmd, overlap + i, epsilon, *collisions_index, dt);
- }
-}
-
-void cloth_find_point_contacts(Depsgraph *depsgraph,
- Object *ob,
- ClothModifierData *clmd,
- float step,
- float dt,
- ColliderContacts **r_collider_contacts,
- int *r_totcolliders)
-{
- Cloth *cloth = clmd->clothObject;
- BVHTree *cloth_bvh;
- unsigned int i = 0, mvert_num = 0;
- ClothVertex *verts = NULL;
-
- ColliderContacts *collider_contacts;
-
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
-
- verts = cloth->verts;
- mvert_num = cloth->mvert_num;
-
- ////////////////////////////////////////////////////////////
- // static collisions
- ////////////////////////////////////////////////////////////
-
- /* Check we do have collision objects to test against, before doing anything else. */
- collobjs = BKE_collision_objects_create(
- depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
- if (!collobjs) {
- *r_collider_contacts = NULL;
- *r_totcolliders = 0;
- return;
- }
-
- // create temporary cloth points bvh
- cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6);
- /* fill tree */
- for (i = 0; i < mvert_num; i++) {
- float co[6];
-
- copy_v3_v3(&co[0 * 3], verts[i].x);
- copy_v3_v3(&co[1 * 3], verts[i].tx);
-
- BLI_bvhtree_insert(cloth_bvh, i, co, 2);
- }
- /* balance tree */
- BLI_bvhtree_balance(cloth_bvh);
-
- /* move object to position (step) in time */
- for (i = 0; i < numcollobj; i++) {
- Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
- collob, eModifierType_Collision);
- if (!collmd->bvhtree) {
- continue;
- }
-
- /* move object to position (step) in time */
- collision_move_object(collmd, step + dt, step, true);
- }
-
- collider_contacts = MEM_callocN(sizeof(ColliderContacts) * numcollobj, "CollPair");
-
- // check all collision objects
- for (i = 0; i < numcollobj; i++) {
- ColliderContacts *ct = collider_contacts + i;
- Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
- collob, eModifierType_Collision);
- BVHTreeOverlap *overlap;
- unsigned int result = 0;
- float epsilon;
-
- ct->ob = collob;
- ct->collmd = collmd;
- ct->collisions = NULL;
- ct->totcollisions = 0;
-
- if (!collmd->bvhtree) {
- continue;
- }
-
- /* search for overlapping collision pairs */
- overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
- epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
-
- // go to next object if no overlap is there
- if (result && overlap) {
- CollPair *collisions_index;
-
- /* check if collisions really happen (costly near check) */
- cloth_points_objcollisions_nearcheck(
- clmd, collmd, &ct->collisions, &collisions_index, result, overlap, epsilon, dt);
- ct->totcollisions = (int)(collisions_index - ct->collisions);
-
- /* Resolve nearby collisions. */
-#if 0
- ret += cloth_points_objcollisions_resolve(
- clmd, collmd, collob->pd, collisions[i], collisions_index[i], dt);
-#endif
- }
-
- if (overlap) {
- MEM_freeN(overlap);
- }
- }
-
- BKE_collision_objects_free(collobjs);
-
- BLI_bvhtree_free(cloth_bvh);
-
- ////////////////////////////////////////////////////////////
- // update positions
- // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
- ////////////////////////////////////////////////////////////
-
- // verts come from clmd
- for (i = 0; i < mvert_num; i++) {
- if (clmd->sim_parms->vgroup_mass > 0) {
- if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
- continue;
- }
- }
-
- add_v3_v3v3(verts[i].tx, verts[i].txold, verts[i].tv);
- }
- ////////////////////////////////////////////////////////////
-
- *r_collider_contacts = collider_contacts;
- *r_totcolliders = numcollobj;
-}
-
-void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders)
-{
- if (collider_contacts) {
- int i;
- for (i = 0; i < totcolliders; i++) {
- ColliderContacts *ct = collider_contacts + i;
- if (ct->collisions) {
- MEM_freeN(ct->collisions);
- }
- }
- MEM_freeN(collider_contacts);
- }
-}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 12bb7b573bd..4f0ff8bdcd3 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -1805,91 +1805,88 @@ void BKE_curve_bevel_make(Object *ob, ListBase *disp)
}
}
else {
- short dnr;
-
- /* bevel now in three parts, for proper vertex normals */
- /* part 1, back */
-
- if ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT)) {
- dnr = nr = 2 + cu->bevresol;
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- nr = 3 + 2 * cu->bevresol;
- }
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->parts = 1;
- dl->flag = DL_BACK_CURVE;
- dl->nr = nr;
-
- /* half a circle */
- fp = dl->verts;
- dangle = ((float)M_PI_2 / (dnr - 1));
- angle = -(nr - 1) * dangle;
-
- for (a = 0; a < nr; a++) {
+ /* The general case for nonzero extrusion or an incomplete loop. */
+ dl = MEM_callocN(sizeof(DispList), "makebevelcurve");
+ if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
+ /* The full loop. */
+ nr = 4 * cu->bevresol + 6;
+ dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
+ }
+ else if ((cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) {
+ /* Half the loop. */
+ nr = 2 * (cu->bevresol + 1) + ((cu->ext1 == 0.0f) ? 1 : 2);
+ dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
+ }
+ else {
+ /* One quarter of the loop (just front or back). */
+ nr = (cu->ext1 == 0.0f) ? cu->bevresol + 2 : cu->bevresol + 3;
+ dl->flag = (cu->flag & CU_FRONT) ? DL_FRONT_CURVE : DL_BACK_CURVE;
+ }
+
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve");
+ BLI_addtail(disp, dl);
+ /* Use a different type depending on whether the loop is complete or not. */
+ dl->type = ((cu->flag & (CU_FRONT | CU_BACK)) == 0) ? DL_POLY : DL_SEGM;
+ dl->parts = 1;
+ dl->nr = nr;
+
+ fp = dl->verts;
+ dangle = (float)M_PI_2 / (cu->bevresol + 1);
+ angle = 0.0;
+
+ /* Build the back section. */
+ if (cu->flag & CU_BACK || !(cu->flag & CU_FRONT)) {
+ angle = (float)M_PI_2 * 3.0f;
+ for (a = 0; a < cu->bevresol + 2; a++) {
fp[0] = 0.0;
fp[1] = (float)(cosf(angle) * (cu->ext2));
fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
angle += dangle;
fp += 3;
}
+ if ((cu->ext1 != 0.0f) && !(cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) {
+ /* Add the extrusion if we're only building the back. */
+ fp[0] = 0.0;
+ fp[1] = cu->ext2;
+ fp[2] = cu->ext1;
+ }
}
- /* part 2, sidefaces */
- if (cu->ext1 != 0.0f) {
- nr = 2;
-
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->parts = 1;
- dl->nr = nr;
-
- fp = dl->verts;
- fp[1] = cu->ext2;
- fp[2] = -cu->ext1;
- fp[4] = cu->ext2;
- fp[5] = cu->ext1;
-
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- dl = MEM_dupallocN(dl);
- dl->verts = MEM_dupallocN(dl->verts);
- BLI_addtail(disp, dl);
-
- fp = dl->verts;
- fp[1] = -fp[1];
- fp[2] = -fp[2];
- fp[4] = -fp[4];
- fp[5] = -fp[5];
+ /* Build the front section. */
+ if (cu->flag & CU_FRONT || !(cu->flag & CU_BACK)) {
+ if ((cu->ext1 != 0.0f) && !(cu->flag & CU_BACK) && (cu->flag & CU_FRONT)) {
+ /* Add the extrusion if we're only building the back. */
+ fp[0] = 0.0;
+ fp[1] = cu->ext2;
+ fp[2] = -cu->ext1;
+ fp += 3;
+ }
+ /* Don't duplicate the last back vertex. */
+ angle = (cu->ext1 == 0.0f && (cu->flag & CU_BACK)) ? dangle : 0;
+ for (a = 0; a < cu->bevresol + 2; a++) {
+ fp[0] = 0.0;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
+ angle += dangle;
+ fp += 3;
}
}
- /* part 3, front */
- if ((cu->flag & CU_FRONT) || !(cu->flag & CU_BACK)) {
- dnr = nr = 2 + cu->bevresol;
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- nr = 3 + 2 * cu->bevresol;
+ /* Build the other half only if we're building the full loop. */
+ if (!(cu->flag & (CU_FRONT | CU_BACK))) {
+ for (a = 0; a < cu->bevresol + 1; a++) {
+ fp[0] = 0.0;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
+ angle += dangle;
+ fp += 3;
}
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->flag = DL_FRONT_CURVE;
- dl->parts = 1;
- dl->nr = nr;
-
- /* half a circle */
- fp = dl->verts;
- angle = 0.0;
- dangle = ((float)M_PI_2 / (dnr - 1));
- for (a = 0; a < nr; a++) {
+ angle = (float)M_PI;
+ for (a = 0; a < cu->bevresol + 1; a++) {
fp[0] = 0.0;
fp[1] = (float)(cosf(angle) * (cu->ext2));
- fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
angle += dangle;
fp += 3;
}
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 06f1ee5050b..3cba3aa9611 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -41,6 +41,30 @@ void BKE_lightprobe_init(LightProbe *probe)
MEMCPY_STRUCT_AFTER(probe, DNA_struct_default_get(LightProbe), id);
}
+void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type)
+{
+ probe->type = lightprobe_type;
+
+ switch (probe->type) {
+ case LIGHTPROBE_TYPE_GRID:
+ probe->distinf = 0.3f;
+ probe->falloff = 1.0f;
+ probe->clipsta = 0.01f;
+ break;
+ case LIGHTPROBE_TYPE_PLANAR:
+ probe->distinf = 0.1f;
+ probe->falloff = 0.5f;
+ probe->clipsta = 0.001f;
+ break;
+ case LIGHTPROBE_TYPE_CUBE:
+ probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID;
+ break;
+ default:
+ BLI_assert(!"LightProbe type not configured.");
+ break;
+ }
+}
+
void *BKE_lightprobe_add(Main *bmain, const char *name)
{
LightProbe *probe;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index da3986d33df..d0bbbe997cb 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -804,6 +804,8 @@ static const char *get_obdata_defname(int type)
return DATA_("Empty");
case OB_GPENCIL:
return DATA_("GPencil");
+ case OB_LIGHTPROBE:
+ return DATA_("LightProbe");
default:
CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
return DATA_("Empty");
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 3e449fa6b25..f58c20a7d72 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -247,8 +247,12 @@ WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain,
void BKE_workspace_layout_remove(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout)
{
- id_us_min(&layout->screen->id);
- BKE_id_free(bmain, layout->screen);
+ /* Screen should usually be set, but we call this from file reading to get rid of invalid
+ * layouts. */
+ if (layout->screen) {
+ id_us_min(&layout->screen->id);
+ BKE_id_free(bmain, layout->screen);
+ }
BLI_freelinkN(&workspace->layouts, layout);
}
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index e3cd70f7413..fdb4fe30f1c 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -39,6 +39,10 @@ bool BLI_rcti_is_empty(const struct rcti *rect);
bool BLI_rctf_is_empty(const struct rctf *rect);
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax);
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax);
+bool BLI_rctf_is_valid(const struct rctf *rect);
+bool BLI_rcti_is_valid(const struct rcti *rect);
+void BLI_rctf_sanitize(struct rctf *rect);
+void BLI_rcti_sanitize(struct rcti *rect);
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size);
void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size);
void BLI_rcti_init_minmax(struct rcti *rect);
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index ecff2ebffef..8fab4ed8e6a 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -439,42 +439,66 @@ void BLI_rcti_union(rcti *rct1, const rcti *rct2)
void BLI_rctf_init(rctf *rect, float xmin, float xmax, float ymin, float ymax)
{
- if (xmin <= xmax) {
- rect->xmin = xmin;
- rect->xmax = xmax;
- }
- else {
- rect->xmax = xmin;
- rect->xmin = xmax;
- }
- if (ymin <= ymax) {
- rect->ymin = ymin;
- rect->ymax = ymax;
- }
- else {
- rect->ymax = ymin;
- rect->ymin = ymax;
- }
+ rect->xmin = xmin;
+ rect->xmax = xmax;
+ rect->ymin = ymin;
+ rect->ymax = ymax;
+
+ BLI_rctf_sanitize(rect);
}
void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax)
{
- if (xmin <= xmax) {
- rect->xmin = xmin;
- rect->xmax = xmax;
+ rect->xmin = xmin;
+ rect->xmax = xmax;
+ rect->ymin = ymin;
+ rect->ymax = ymax;
+
+ BLI_rcti_sanitize(rect);
+}
+
+/**
+ * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ * If this returns false, #BLI_rctf_sanitize() can be called to address this.
+ *
+ * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
+ * have max < min. Usually this is what you'd want though.
+ */
+bool BLI_rctf_is_valid(const rctf *rect)
+{
+ return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
+}
+
+bool BLI_rcti_is_valid(const rcti *rect)
+{
+ return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
+}
+
+/**
+ * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ */
+void BLI_rctf_sanitize(rctf *rect)
+{
+ if (rect->xmin > rect->xmax) {
+ SWAP(float, rect->xmin, rect->xmax);
}
- else {
- rect->xmax = xmin;
- rect->xmin = xmax;
+ if (rect->ymin > rect->ymax) {
+ SWAP(float, rect->ymin, rect->ymax);
}
- if (ymin <= ymax) {
- rect->ymin = ymin;
- rect->ymax = ymax;
+
+ BLI_assert(BLI_rctf_is_valid(rect));
+}
+
+void BLI_rcti_sanitize(rcti *rect)
+{
+ if (rect->xmin > rect->xmax) {
+ SWAP(int, rect->xmin, rect->xmax);
}
- else {
- rect->ymax = ymin;
- rect->ymin = ymax;
+ if (rect->ymin > rect->ymax) {
+ SWAP(int, rect->ymin, rect->ymax);
}
+
+ BLI_assert(BLI_rcti_is_valid(rect));
}
void BLI_rctf_init_pt_radius(rctf *rect, const float xy[2], float size)
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 0ebff916cf9..e1424da2207 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3371,6 +3371,11 @@ static void lib_link_workspaces(FileData *fd, Main *bmain)
}
}
}
+ else {
+ /* If we're reading a layout without screen stored, it's useless and we shouldn't keep it
+ * around. */
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
}
id->tag &= ~LIB_TAG_NEED_LINK;
@@ -3869,7 +3874,7 @@ static void direct_link_bones(FileData *fd, Bone *bone)
bone->bbone_next = newdataadr(fd, bone->bbone_next);
bone->bbone_prev = newdataadr(fd, bone->bbone_prev);
- bone->flag &= ~BONE_DRAW_ACTIVE;
+ bone->flag &= ~(BONE_DRAW_ACTIVE | BONE_DRAW_LOCKED_WEIGHT);
link_list(fd, &bone->childbase);
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 6d4dd98729a..7377f6a62a1 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -636,6 +636,29 @@ static ARegion *do_versions_add_region(int regiontype, const char *name)
return ar;
}
+static void do_versions_area_ensure_tool_region(Main *bmain,
+ const short space_type,
+ const short region_flag)
+{
+ 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_type) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS);
+ if (!ar) {
+ ARegion *header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ ar = do_versions_add_region(RGN_TYPE_TOOLS, "tools region");
+ BLI_insertlinkafter(regionbase, header, ar);
+ ar->alignment = RGN_ALIGN_LEFT;
+ ar->flag = region_flag;
+ }
+ }
+ }
+ }
+ }
+}
+
static void do_version_bones_split_bbone_scale(ListBase *lb)
{
for (Bone *bone = lb->first; bone; bone = bone->next) {
@@ -2828,6 +2851,35 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ /* Files stored pre 2.5 (possibly re-saved with newer versions) may have non-visible
+ * spaces without a header (visible/active ones are properly versioned).
+ * Multiple version patches below assume there's always a header though. So inserting this
+ * patch in-between older ones to add a header when needed.
+ *
+ * From here on it should be fine to assume there always is a header.
+ */
+ if (!MAIN_VERSION_ATLEAST(bmain, 283, 1)) {
+ 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) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar_header = do_versions_find_region_or_null(regionbase, RGN_TYPE_HEADER);
+
+ if (!ar_header) {
+ /* Headers should always be first in the region list, except if there's also a
+ * tool-header. These were only introduced in later versions though, so should be
+ * fine to always insert headers first. */
+ BLI_assert(!do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER));
+
+ ARegion *ar = do_versions_add_region(RGN_TYPE_HEADER, "header 2.83.1 versioning");
+ ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+ BLI_addhead(regionbase, ar);
+ }
+ }
+ }
+ }
+ }
+
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) {
@@ -3709,7 +3761,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
/* All spaces that use tools must be eventually added. */
ARegion *ar = NULL;
- if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE) &&
+ if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ) &&
((ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER)) == NULL)) {
/* Add tool header. */
ar = do_versions_add_region(RGN_TYPE_TOOL_HEADER, "tool header");
@@ -4309,6 +4361,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
/* Keep this block, even when empty. */
+ /* Sequencer Tool region */
+ do_versions_area_ensure_tool_region(bmain, SPACE_SEQ, RGN_FLAG_HIDDEN);
+
/* Cloth internal springs */
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index bc43d9605e2..8c7a0c4f7b2 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -207,13 +207,20 @@ static void blo_update_defaults_screen(bScreen *screen,
}
}
- /* Show top-bar by default. */
+ /* Show tool-header by default (for most cases at least, hide for others). */
+ const bool hide_image_tool_header = STREQ(workspace_name, "Rendering");
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+
for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_TOOL_HEADER) {
- ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER);
+ if ((sl->spacetype == SPACE_IMAGE) && hide_image_tool_header) {
+ ar->flag |= RGN_FLAG_HIDDEN;
+ }
+ else {
+ ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER);
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index b1f70848bdc..e1ea4e3bb24 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -164,6 +164,10 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_view3d.face_front);
}
+ if (!USER_VERSION_ATLEAST(283, 1)) {
+ FROM_DEFAULT_V4_UCHAR(space_view3d.bone_locked_weight);
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 80f84738f6e..2d69fae035f 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -112,26 +112,22 @@ void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *m
void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma)
{
- // get diffuse color
COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
ep.setDiffuse(cot, false, "diffuse");
}
void EffectsExporter::set_ambient(COLLADASW::EffectProfile &ep, Material *ma)
{
- // get diffuse color
COLLADASW::ColorOrTexture cot = bc_get_ambient(ma);
ep.setAmbient(cot, false, "ambient");
}
void EffectsExporter::set_specular(COLLADASW::EffectProfile &ep, Material *ma)
{
- // get diffuse color
COLLADASW::ColorOrTexture cot = bc_get_specular(ma);
ep.setSpecular(cot, false, "specular");
}
void EffectsExporter::set_reflective(COLLADASW::EffectProfile &ep, Material *ma)
{
- // get diffuse color
COLLADASW::ColorOrTexture cot = bc_get_reflective(ma);
ep.setReflective(cot, false, "reflective");
}
diff --git a/source/blender/collada/Materials.cpp b/source/blender/collada/Materials.cpp
index 3b2c68ef95e..06f54884668 100644
--- a/source/blender/collada/Materials.cpp
+++ b/source/blender/collada/Materials.cpp
@@ -202,6 +202,7 @@ void MaterialNode::set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode,
bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Alpha");
((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
+ material->a = alpha;
}
else if (cot.isTexture()) {
int locy = -300 * (node_map.size() - 2);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index b688840cb09..d5011581204 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -1321,10 +1321,10 @@ void bc_add_default_shader(bContext *C, Material *ma)
COLLADASW::ColorOrTexture bc_get_base_color(Material *ma)
{
- Color default_color = {0.8, 0.8, 0.8, 1.0};
+ Color default_color = {ma->r, ma->g, ma->b, 1.0}; // for alpha see bc_get_alpha()
bNode *shader = bc_get_master_shader(ma);
if (ma->use_nodes && shader) {
- return bc_get_cot_from_shader(shader, "Base Color", default_color);
+ return bc_get_cot_from_shader(shader, "Base Color", default_color, false);
}
else {
return bc_get_cot(default_color);
@@ -1414,16 +1414,17 @@ double bc_get_float_from_shader(bNode *shader, double &val, std::string nodeid)
COLLADASW::ColorOrTexture bc_get_cot_from_shader(bNode *shader,
std::string nodeid,
- Color &default_color)
+ Color &default_color,
+ bool with_alpha)
{
bNodeSocket *socket = nodeFindSocket(shader, SOCK_IN, nodeid.c_str());
if (socket) {
bNodeSocketValueRGBA *dcol = (bNodeSocketValueRGBA *)socket->default_value;
float *col = dcol->value;
- return bc_get_cot(col);
+ return bc_get_cot(col, with_alpha);
}
else {
- return bc_get_cot(default_color); /* default black */
+ return bc_get_cot(default_color, with_alpha);
}
}
@@ -1447,9 +1448,9 @@ COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a)
return cot;
}
-COLLADASW::ColorOrTexture bc_get_cot(Color col)
+COLLADASW::ColorOrTexture bc_get_cot(Color col, bool with_alpha)
{
- COLLADASW::Color color(col[0], col[1], col[2], col[3]);
+ COLLADASW::Color color(col[0], col[1], col[2], (with_alpha) ? col[3] : 1.0);
COLLADASW::ColorOrTexture cot(color);
return cot;
}
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index c0425e59d1a..b313fcd6e66 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -397,9 +397,10 @@ double bc_get_shininess(Material *ma);
double bc_get_float_from_shader(bNode *shader, double &ior, std::string nodeid);
COLLADASW::ColorOrTexture bc_get_cot_from_shader(bNode *shader,
std::string nodeid,
- Color &default_color);
+ Color &default_color,
+ bool with_alpha = true);
COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a);
-COLLADASW::ColorOrTexture bc_get_cot(Color col);
+COLLADASW::ColorOrTexture bc_get_cot(Color col, bool with_alpha = true);
#endif
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 4abeec19645..7f3c7d5043f 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -59,6 +59,7 @@ set(SRC
intern/eval/deg_eval_copy_on_write.cc
intern/eval/deg_eval_flush.cc
intern/eval/deg_eval_runtime_backup.cc
+ intern/eval/deg_eval_runtime_backup_animation.cc
intern/eval/deg_eval_runtime_backup_modifier.cc
intern/eval/deg_eval_runtime_backup_movieclip.cc
intern/eval/deg_eval_runtime_backup_object.cc
@@ -108,6 +109,7 @@ set(SRC
intern/eval/deg_eval_copy_on_write.h
intern/eval/deg_eval_flush.h
intern/eval/deg_eval_runtime_backup.h
+ intern/eval/deg_eval_runtime_backup_animation.h
intern/eval/deg_eval_runtime_backup_modifier.h
intern/eval/deg_eval_runtime_backup_movieclip.h
intern/eval/deg_eval_runtime_backup_object.h
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 7d7a183ee75..bc428dd755f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -2690,6 +2690,26 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
BLI_assert(object->type == OB_EMPTY);
}
}
+
+#if 0
+ /* NOTE: Relation is disabled since AnimationBackup() is disabled.
+ * See comment in AnimationBackup:init_from_id(). */
+
+ /* Copy-on-write of write will iterate over f-curves to store current values corresponding
+ * to their RNA path. This means that action must be copied prior to the ID's copy-on-write,
+ * otherwise depsgraph might try to access freed data. */
+ AnimData *animation_data = BKE_animdata_from_id(id_orig);
+ if (animation_data != NULL) {
+ if (animation_data->action != NULL) {
+ OperationKey action_copy_on_write_key(
+ &animation_data->action->id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
+ add_relation(action_copy_on_write_key,
+ copy_on_write_key,
+ "Eval Order",
+ RELATION_FLAG_GODMODE | RELATION_FLAG_NO_FLUSH);
+ }
+ }
+#endif
}
/* **** ID traversal callbacks functions **** */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
index 88390ab412f..4da5ca77fb8 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
@@ -32,7 +32,8 @@
namespace DEG {
RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph)
- : scene_backup(depsgraph),
+ : animation_backup(depsgraph),
+ scene_backup(depsgraph),
sound_backup(depsgraph),
object_backup(depsgraph),
drawdata_ptr(NULL),
@@ -47,6 +48,8 @@ void RuntimeBackup::init_from_id(ID *id)
return;
}
+ animation_backup.init_from_id(id);
+
const ID_Type id_type = GS(id->name);
switch (id_type) {
case ID_OB:
@@ -76,6 +79,8 @@ void RuntimeBackup::init_from_id(ID *id)
void RuntimeBackup::restore_to_id(ID *id)
{
+ animation_backup.restore_to_id(id);
+
const ID_Type id_type = GS(id->name);
switch (id_type) {
case ID_OB:
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
index 31ae3164e37..892cc88002f 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
@@ -25,6 +25,7 @@
#include "DNA_ID.h"
+#include "intern/eval/deg_eval_runtime_backup_animation.h"
#include "intern/eval/deg_eval_runtime_backup_movieclip.h"
#include "intern/eval/deg_eval_runtime_backup_object.h"
#include "intern/eval/deg_eval_runtime_backup_scene.h"
@@ -44,6 +45,7 @@ class RuntimeBackup {
/* Restore fields to the given ID. */
void restore_to_id(ID *id);
+ AnimationBackup animation_backup;
SceneBackup scene_backup;
SoundBackup sound_backup;
ObjectRuntimeBackup object_backup;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc
new file mode 100644
index 00000000000..cc4935431d1
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc
@@ -0,0 +1,144 @@
+/*
+ * 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 depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_animation.h"
+
+#include "DNA_anim_types.h"
+
+#include "BKE_animsys.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "intern/depsgraph.h"
+
+namespace DEG {
+
+namespace {
+
+struct AnimatedPropertyStoreCalbackData {
+ AnimationBackup *backup;
+
+ /* ID which needs to be stored.
+ * Is used to check possibly nested IDs which f-curves are pointing to. */
+ ID *id;
+
+ PointerRNA id_pointer_rna;
+};
+
+void animated_property_store_cb(ID *id, FCurve *fcurve, void *data_v)
+{
+ AnimatedPropertyStoreCalbackData *data = reinterpret_cast<AnimatedPropertyStoreCalbackData *>(
+ data_v);
+ if (fcurve->rna_path == NULL || fcurve->rna_path[0] == '\0') {
+ return;
+ }
+ if (id != data->id) {
+ return;
+ }
+
+ /* Resolve path to the property. */
+ PathResolvedRNA resolved_rna;
+ if (!BKE_animsys_store_rna_setting(
+ &data->id_pointer_rna, fcurve->rna_path, fcurve->array_index, &resolved_rna)) {
+ return;
+ }
+
+ /* Read property value. */
+ float value;
+ if (!BKE_animsys_read_rna_setting(&resolved_rna, &value)) {
+ return;
+ }
+
+ data->backup->values_backup.emplace_back(fcurve->rna_path, fcurve->array_index, value);
+}
+
+} // namespace
+
+AnimationValueBackup::AnimationValueBackup()
+{
+}
+
+AnimationValueBackup::AnimationValueBackup(const string &rna_path, int array_index, float value)
+ : rna_path(rna_path), array_index(array_index), value(value)
+{
+}
+
+AnimationValueBackup::~AnimationValueBackup()
+{
+}
+
+AnimationBackup::AnimationBackup(const Depsgraph *depsgraph)
+{
+ meed_value_backup = !depsgraph->is_active;
+ reset();
+}
+
+void AnimationBackup::reset()
+{
+}
+
+void AnimationBackup::init_from_id(ID *id)
+{
+ /* NOTE: This animation backup nicely preserves values which are animated and
+ * are not touched by frame/depsgraph post_update handler.
+ *
+ * But it makes it impossible to have user edits to animated properties: for
+ * example, translation of object with animated location will not work with
+ * the current version of backup. */
+ return;
+
+ AnimatedPropertyStoreCalbackData data;
+ data.backup = this;
+ data.id = id;
+ RNA_id_pointer_create(id, &data.id_pointer_rna);
+ BKE_fcurves_id_cb(id, animated_property_store_cb, &data);
+}
+
+void AnimationBackup::restore_to_id(ID *id)
+{
+ return;
+
+ PointerRNA id_pointer_rna;
+ RNA_id_pointer_create(id, &id_pointer_rna);
+ for (const AnimationValueBackup &value_backup : values_backup) {
+ /* Resolve path to the property.
+ *
+ * NOTE: Do it again (after storing), since the sub-data pointers might be
+ * changed after copy-on-write. */
+ PathResolvedRNA resolved_rna;
+ if (!BKE_animsys_store_rna_setting(&id_pointer_rna,
+ value_backup.rna_path.c_str(),
+ value_backup.array_index,
+ &resolved_rna)) {
+ return;
+ }
+
+ /* Write property value. */
+ if (!BKE_animsys_write_rna_setting(&resolved_rna, value_backup.value)) {
+ return;
+ }
+ }
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h
new file mode 100644
index 00000000000..d97ee2b0556
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h
@@ -0,0 +1,65 @@
+/*
+ * 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 depsgraph
+ */
+
+#pragma once
+
+#include "BKE_modifier.h"
+
+#include "intern/depsgraph_type.h"
+
+namespace DEG {
+
+struct Depsgraph;
+
+class AnimationValueBackup {
+ public:
+ AnimationValueBackup();
+ AnimationValueBackup(const string &rna_path, int array_index, float value);
+ ~AnimationValueBackup();
+
+ AnimationValueBackup(const AnimationValueBackup &other) = default;
+ AnimationValueBackup(AnimationValueBackup &&other) noexcept = default;
+
+ AnimationValueBackup &operator=(const AnimationValueBackup &other) = default;
+ AnimationValueBackup &operator=(AnimationValueBackup &&other) = default;
+
+ string rna_path;
+ int array_index;
+ float value;
+};
+
+/* Backup of animated properties values. */
+class AnimationBackup {
+ public:
+ AnimationBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_id(ID *id);
+ void restore_to_id(ID *id);
+
+ bool meed_value_backup;
+ vector<AnimationValueBackup> values_backup;
+};
+
+} // namespace DEG
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index d0fe7c6637e..97d492d5dd5 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -1529,18 +1529,10 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) {
/* Get per-material split surface */
- char *auto_layer_names;
- int *auto_layer_is_srgb;
- int auto_layer_count;
struct GPUBatch **mat_geom = NULL;
if (!use_sculpt_pbvh) {
- mat_geom = DRW_cache_object_surface_material_get(ob,
- gpumat_array,
- materials_len,
- &auto_layer_names,
- &auto_layer_is_srgb,
- &auto_layer_count);
+ mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
}
if (use_sculpt_pbvh) {
@@ -1577,28 +1569,6 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, mat_geom[i], oedata);
ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i], oedata);
- char *name = auto_layer_names;
- for (int j = 0; j < auto_layer_count; j++) {
- /* TODO don't add these uniform when not needed (default pass shaders). */
- /* FIXME: This is broken, as it overrides any autolayers srgb bool of the previous mesh
- * that shares the same material. */
- if (shgrp_array[i]) {
- DRW_shgroup_uniform_bool_copy(shgrp_array[i], name, auto_layer_is_srgb[j]);
- }
- if (shgrp_depth_array[i]) {
- DRW_shgroup_uniform_bool_copy(shgrp_depth_array[i], name, auto_layer_is_srgb[j]);
- }
- if (shgrp_depth_clip_array[i]) {
- DRW_shgroup_uniform_bool_copy(
- shgrp_depth_clip_array[i], name, auto_layer_is_srgb[j]);
- }
- /* Go to next layer name. */
- while (*name != '\0') {
- name++;
- }
- name += 1;
- }
-
/* Shadow Pass */
struct GPUMaterial *gpumat;
const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree);
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 0b77fcad265..416283e321b 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -35,6 +35,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_modifier.h"
@@ -974,6 +975,15 @@ static bool set_pchan_color(const ArmatureDrawContext *ctx,
/** \name Drawing Color Helpers
* \{ */
+static void bone_locked_color_shade(float color[4])
+{
+ float locked_color[4];
+
+ UI_GetThemeColor4fv(TH_BONE_LOCKED_WEIGHT, locked_color);
+
+ interp_v3_v3v3(color, color, locked_color, locked_color[3]);
+}
+
static const float *get_bone_solid_color(const ArmatureDrawContext *ctx,
const EditBone *UNUSED(eBone),
const bPoseChannel *pchan,
@@ -989,6 +999,11 @@ static const float *get_bone_solid_color(const ArmatureDrawContext *ctx,
static float disp_color[4];
copy_v4_v4(disp_color, pchan->draw_data->solid_color);
set_pchan_color(ctx, PCHAN_COLOR_SOLID, boneflag, constflag, disp_color);
+
+ if (boneflag & BONE_DRAW_LOCKED_WEIGHT) {
+ bone_locked_color_shade(disp_color);
+ }
+
return disp_color;
}
@@ -1009,7 +1024,7 @@ static const float *get_bone_solid_with_consts_color(const ArmatureDrawContext *
const float *col = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
static float consts_color[4];
- if ((arm->flag & ARM_POSEMODE) &&
+ if ((arm->flag & ARM_POSEMODE) && !(boneflag & BONE_DRAW_LOCKED_WEIGHT) &&
set_pchan_color(ctx, PCHAN_COLOR_CONSTS, boneflag, constflag, consts_color)) {
interp_v3_v3v3(consts_color, col, consts_color, 0.5f);
}
@@ -1065,6 +1080,10 @@ static const float *get_bone_wire_color(const ArmatureDrawContext *ctx,
else if (arm->flag & ARM_POSEMODE) {
copy_v4_v4(disp_color, pchan->draw_data->wire_color);
set_pchan_color(ctx, PCHAN_COLOR_NORMAL, boneflag, constflag, disp_color);
+
+ if (boneflag & BONE_DRAW_LOCKED_WEIGHT) {
+ bone_locked_color_shade(disp_color);
+ }
}
else {
copy_v3_v3(disp_color, ctx->color.vertex);
@@ -1518,7 +1537,7 @@ static void draw_bone_custom_shape(ArmatureDrawContext *ctx,
drw_shgroup_bone_custom_empty(ctx, disp_mat, col_wire, pchan->custom);
}
}
- if ((boneflag & BONE_DRAWWIRE) == 0) {
+ if ((boneflag & BONE_DRAWWIRE) == 0 && (boneflag & BONE_DRAW_LOCKED_WEIGHT) == 0) {
drw_shgroup_bone_custom_solid(ctx, disp_mat, col_solid, col_hint, col_wire, pchan->custom);
}
else {
@@ -2010,6 +2029,8 @@ static void draw_armature_edit(ArmatureDrawContext *ctx)
boneflag |= BONE_DRAW_ACTIVE;
}
+ boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
+
draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag);
if (arm->drawtype == ARM_ENVELOPE) {
@@ -2054,6 +2075,7 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
bPoseChannel *pchan;
int index = -1;
const bool show_text = DRW_state_show_text();
+ bool draw_locked_weights = false;
/* We can't safely draw non-updated pose, might contain NULL bone pointers... */
if (ob->pose->flag & POSE_RECALC) {
@@ -2089,6 +2111,28 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
}
}
+ /* In weight paint mode retrieve the vertex group lock status. */
+ if ((draw_ctx->object_mode == OB_MODE_WEIGHT_PAINT) && (draw_ctx->object_pose == ob) &&
+ (draw_ctx->obact != NULL)) {
+ draw_locked_weights = true;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone->flag &= ~BONE_DRAW_LOCKED_WEIGHT;
+ }
+
+ const Object *obact_orig = DEG_get_original_object(draw_ctx->obact);
+
+ LISTBASE_FOREACH (bDeformGroup *, dg, &obact_orig->defbase) {
+ if (dg->flag & DG_LOCK_WEIGHT) {
+ pchan = BKE_pose_channel_find_name(ob->pose, dg->name);
+
+ if (pchan) {
+ pchan->bone->flag |= BONE_DRAW_LOCKED_WEIGHT;
+ }
+ }
+ }
+ }
+
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, index += 0x10000) {
Bone *bone = pchan->bone;
const bool bone_visible = (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0;
@@ -2120,6 +2164,10 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
boneflag |= BONE_DRAW_ACTIVE;
}
+ if (!draw_locked_weights) {
+ boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
+ }
+
draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag);
if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) {
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 04dd9ab85bb..0a3252f0b9b 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -4,13 +4,18 @@ in vec3 pos;
in vec3 nor;
in vec2 au; /* active texture layer */
# ifdef V3D_SHADING_VERTEX_COLOR
-in vec3 ac; /* active color */
+in vec4 ac; /* active color */
# endif
# define uv au
#else /* HAIR_SHADER */
+
# ifdef V3D_SHADING_TEXTURE_COLOR
uniform samplerBuffer au; /* active texture layer */
# endif
+# ifdef V3D_SHADING_VERTEX_COLOR
+uniform samplerBuffer ac; /* active color layer */
+# endif
+
flat out float hair_rand;
#endif /* HAIR_SHADER */
@@ -37,16 +42,6 @@ float integer_noise(int n)
return (float(nn) / 1073741824.0);
}
-#ifdef V3D_SHADING_VERTEX_COLOR
-vec3 srgb_to_linear_attr(vec3 c)
-{
- c = max(c, vec3(0.0));
- vec3 c1 = c * (1.0 / 12.92);
- vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
- return mix(c1, c2, step(vec3(0.04045), c));
-}
-#endif
-
vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand)
{
/* To "simulate" anisotropic shading, randomize hair normal per strand. */
@@ -90,7 +85,9 @@ void main()
#ifdef V3D_SHADING_VERTEX_COLOR
# ifndef HAIR_SHADER
- vertexColor = srgb_to_linear_attr(ac);
+ vertexColor = ac.rgb;
+# else
+ vertexColor = hair_get_customdata_vec4(ac).rgb;
# endif
#endif
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index 1af9357e015..86ed1f0b4c3 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -1138,8 +1138,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
- geoms = DRW_cache_object_surface_material_get(
- ob, gpumat_array, materials_len, NULL, NULL, NULL);
+ geoms = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
for (int i = 0; i < materials_len; i++) {
if (geoms != NULL && geoms[i] != NULL) {
Material *mat = give_current_material(ob, i + 1);
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index ae001f8d10c..3b588868a94 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -756,7 +756,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
- ob, gpumat_array, materials_len, NULL, NULL, NULL);
+ ob, gpumat_array, materials_len);
if (mat_geom) {
for (int i = 0; i < materials_len; i++) {
if (mat_geom[i] == NULL) {
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index f2e43e032a9..bfb74a9576f 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -826,25 +826,11 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob)
GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count)
+ uint gpumat_array_len)
{
- if (auto_layer_names != NULL) {
- *auto_layer_names = NULL;
- *auto_layer_is_srgb = NULL;
- *auto_layer_count = 0;
- }
-
switch (ob->type) {
case OB_MESH:
- return DRW_cache_mesh_surface_shaded_get(ob,
- gpumat_array,
- gpumat_array_len,
- auto_layer_names,
- auto_layer_is_srgb,
- auto_layer_count);
+ return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
case OB_CURVE:
return DRW_cache_curve_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
case OB_SURF:
@@ -2737,18 +2723,10 @@ GPUBatch *DRW_cache_mesh_surface_edges_get(Object *ob)
/* Return list of batches with length equal to max(1, totcol). */
GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count)
+ uint gpumat_array_len)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_shaded(ob->data,
- gpumat_array,
- gpumat_array_len,
- auto_layer_names,
- auto_layer_is_srgb,
- auto_layer_count);
+ return DRW_mesh_batch_cache_get_surface_shaded(ob->data, gpumat_array, gpumat_array_len);
}
/* Return list of batches with length equal to max(1, totcol). */
@@ -2899,8 +2877,7 @@ GPUBatch **DRW_cache_curve_surface_shaded_get(Object *ob,
struct Curve *cu = ob->data;
struct Mesh *mesh_eval = ob->runtime.mesh_eval;
if (mesh_eval != NULL) {
- return DRW_mesh_batch_cache_get_surface_shaded(
- mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL);
+ return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len);
}
else {
return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
@@ -3040,8 +3017,7 @@ GPUBatch **DRW_cache_text_surface_shaded_get(Object *ob,
return NULL;
}
if (mesh_eval != NULL) {
- return DRW_mesh_batch_cache_get_surface_shaded(
- mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL);
+ return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len);
}
else {
return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
@@ -3135,8 +3111,7 @@ GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob,
struct Curve *cu = ob->data;
struct Mesh *mesh_eval = ob->runtime.mesh_eval;
if (mesh_eval != NULL) {
- return DRW_mesh_batch_cache_get_surface_shaded(
- mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL);
+ return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len);
}
else {
return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 11564464546..3759654931a 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -54,10 +54,7 @@ struct GPUBatch *DRW_cache_object_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob);
struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count);
+ uint gpumat_array_len);
struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob);
/* Empties */
@@ -127,10 +124,7 @@ struct GPUBatch *DRW_cache_mesh_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_edges_get(struct Object *ob);
struct GPUBatch **DRW_cache_mesh_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count);
+ uint gpumat_array_len);
struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_vertpaint_get(struct Object *ob);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 2d10199782b..9228147af44 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -213,12 +213,6 @@ typedef struct MeshBatchCache {
GPUBatch **surface_per_mat;
- /* arrays of bool uniform names (and value) that will be use to
- * set srgb conversion for auto attributes.*/
- char *auto_layer_names;
- int *auto_layer_is_srgb;
- int auto_layer_len;
-
DRWBatchFlag batch_requested;
DRWBatchFlag batch_ready;
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index c98494ebdd9..ee0597c6b21 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -1928,7 +1928,7 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
GPU_vertformat_alias_add(&format, "c");
@@ -1948,12 +1948,20 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- MLoopCol *vcol_data = (MLoopCol *)vbo->data;
+ typedef struct gpuMeshVcol {
+ ushort r, g, b, a;
+ } gpuMeshVcol;
+
+ gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data;
for (int i = 0; i < 8; i++) {
if (vcol_layers & (1 << i)) {
- void *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
- memcpy(vcol_data, layer_data, sizeof(*vcol_data) * mr->loop_len);
- vcol_data += mr->loop_len;
+ MLoopCol *mcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
+ for (int l = 0; l < mr->loop_len; l++, mcol++, vcol_data++) {
+ vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
+ vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
+ vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
+ vcol_data->a = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
+ }
}
}
return NULL;
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 8cb318bd0bb..bf056d7444d 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -127,10 +127,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_edges(struct Mesh *me);
struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Mesh *me,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count);
+ uint gpumat_array_len);
struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(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 aadcc2a939a..458029c2580 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -230,68 +230,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
return cd_used;
}
-static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me,
- DRW_MeshCDMask cd_used,
- char **r_auto_layers_names,
- int **r_auto_layers_srgb,
- int *r_auto_layers_len)
-{
- 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);
- int uv_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPUV);
- int vcol_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPCOL);
-
- uint auto_names_len = 32 * (uv_len_used + vcol_len_used);
- uint auto_ofs = 0;
- /* Allocate max, resize later. */
- char *auto_names = MEM_callocN(sizeof(char) * auto_names_len, __func__);
- int *auto_is_srgb = MEM_callocN(sizeof(int) * (uv_len_used + vcol_len_used), __func__);
-
- for (int i = 0; i < uv_len; i++) {
- if ((cd_used.uv & (1 << i)) != 0) {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
- char safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
- GPU_vertformat_safe_attrib_name(name, safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
- auto_ofs += BLI_snprintf_rlen(
- auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%s", safe_name);
- /* +1 to include '\0' terminator. */
- auto_ofs += 1;
- }
- }
-
- uint auto_is_srgb_ofs = uv_len_used;
- for (int i = 0; i < vcol_len; i++) {
- if ((cd_used.vcol & (1 << i)) != 0) {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
- /* We only do vcols that are not overridden by a uv layer with same name. */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) {
- char safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
- GPU_vertformat_safe_attrib_name(name, safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
- auto_ofs += BLI_snprintf_rlen(
- auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%s", safe_name);
- /* +1 to include '\0' terminator. */
- auto_ofs += 1;
- auto_is_srgb[auto_is_srgb_ofs] = true;
- auto_is_srgb_ofs++;
- }
- }
- }
-
- auto_names = MEM_reallocN(auto_names, sizeof(char) * auto_ofs);
- auto_is_srgb = MEM_reallocN(auto_is_srgb, sizeof(int) * auto_is_srgb_ofs);
-
- /* WATCH: May have been referenced somewhere before freeing. */
- MEM_SAFE_FREE(*r_auto_layers_names);
- MEM_SAFE_FREE(*r_auto_layers_srgb);
-
- *r_auto_layers_names = auto_names;
- *r_auto_layers_srgb = auto_is_srgb;
- *r_auto_layers_len = auto_is_srgb_ofs;
-}
-
/** \} */
/* ---------------------------------------------------------------------- */
@@ -492,8 +430,6 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
mesh_cd_layers_type_clear(&cache->cd_used);
MEM_SAFE_FREE(cache->surface_per_mat);
- MEM_SAFE_FREE(cache->auto_layer_names);
- MEM_SAFE_FREE(cache->auto_layer_is_srgb);
cache->mat_len = 0;
}
@@ -771,10 +707,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh *me)
GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count)
+ uint gpumat_array_len)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(me, gpumat_array, gpumat_array_len);
@@ -783,21 +716,8 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
- if (!mesh_cd_layers_type_overlap(cache->cd_used, cd_needed)) {
- mesh_cd_extract_auto_layers_names_and_srgb(me,
- cache->cd_needed,
- &cache->auto_layer_names,
- &cache->auto_layer_is_srgb,
- &cache->auto_layer_len);
- }
-
mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT);
- if (auto_layer_names) {
- *auto_layer_names = cache->auto_layer_names;
- *auto_layer_is_srgb = cache->auto_layer_is_srgb;
- *auto_layer_count = cache->auto_layer_len;
- }
for (int i = 0; i < cache->mat_len; i++) {
DRW_batch_request(&cache->surface_per_mat[i]);
}
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 7de6ee2b3b1..f4057927d55 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -1199,7 +1199,7 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
BLI_snprintf(uuid, sizeof(uuid), "c%s", attr_safe_name);
- col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_U16, 4, GPU_FETCH_FLOAT);
if (i == active_col) {
GPU_vertformat_alias_add(&format, "c");
diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c
index 70a9b7ba1fa..ae489fb5233 100644
--- a/source/blender/editors/animation/time_scrub_ui.c
+++ b/source/blender/editors/animation/time_scrub_ui.c
@@ -179,9 +179,9 @@ void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *ar, bDopeShee
rcti rect;
rect.xmin = 0;
- rect.xmax = ceilf(ar->sizex * UI_DPI_FAC);
- rect.ymin = ar->sizey * UI_DPI_FAC - UI_TIME_SCRUB_MARGIN_Y;
- rect.ymax = ceilf(ar->sizey * UI_DPI_FAC);
+ rect.xmax = ar->winx;
+ rect.ymin = ar->winy - UI_TIME_SCRUB_MARGIN_Y;
+ rect.ymax = ar->winy;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 4c4bac6a249..5486d60d5d7 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -460,14 +460,8 @@ static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
ARRAY_SET_ITEMS(selem->mval, event->mval[0], event->mval[1]);
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- selem->pressure = wmtab->Pressure;
- }
- else {
- selem->pressure = 1.0f;
- }
+ /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
+ selem->pressure = event->tablet.pressure;
bool is_depth_found = stroke_elem_project_fallback_elem(
cdd, cdd->prev.location_world_valid, selem);
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 04b5d8f6d40..5eaf14e361b 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1461,12 +1461,7 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en
/* Check if tablet eraser is being used (when processing events) */
static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
{
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- return (wmtab->Active == EVT_TABLET_ERASER);
- }
-
- return false;
+ return (event->tablet.active == EVT_TABLET_ERASER);
}
/* ------------------------------- */
@@ -1686,7 +1681,6 @@ static void annotation_draw_apply_event(
tGPsdata *p = op->customdata;
PointerRNA itemptr;
float mousef[2];
- int tablet = 0;
/* convert from window-space to area-space mouse coordinates
* add any x,y override position for fake events
@@ -1720,29 +1714,20 @@ static void annotation_draw_apply_event(
p->curtime = PIL_check_seconds_timer();
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
+ /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
+ p->pressure = event->tablet.pressure;
- tablet = (wmtab->Active != EVT_TABLET_NONE);
- p->pressure = wmtab->Pressure;
-
- /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
- * The pen has to float over the tablet surface, resulting in
- * zero pressure (T47101). Ignore pressure values if floating
- * (i.e. "effectively zero" pressure), and only when the "active"
- * end is the stylus (i.e. the default when not eraser)
- */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
- p->pressure = 1.0f;
- }
+ /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
+ * The pen has to float over the tablet surface, resulting in
+ * zero pressure (T47101). Ignore pressure values if floating
+ * (i.e. "effectively zero" pressure), and only when the "active"
+ * end is the stylus (i.e. the default when not eraser)
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if ((event->tablet.active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
+ p->pressure = 1.0f;
}
}
- else {
- /* No tablet data -> No pressure info is available */
- p->pressure = 1.0f;
- }
/* special exception for start of strokes (i.e. maybe for just a dot) */
if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
@@ -1758,7 +1743,7 @@ static void annotation_draw_apply_event(
/* special exception here for too high pressure values on first touch in
* windows for some tablets, then we just skip first touch...
*/
- if (tablet && (p->pressure >= 0.99f)) {
+ if ((event->tablet.active != EVT_TABLET_NONE) && (p->pressure >= 0.99f)) {
return;
}
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 91e70e0e089..c2f1e9f091a 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -1977,7 +1977,6 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
PointerRNA itemptr;
float mouse[2];
- int tablet = 0;
mouse[0] = event->mval[0] + 1;
mouse[1] = event->mval[1] + 1;
@@ -1989,24 +1988,14 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven
RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
RNA_boolean_set(&itemptr, "is_start", gso->first);
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- float pressure = wmtab->Pressure;
-
- tablet = (wmtab->Active != EVT_TABLET_NONE);
-
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets: clamp the values to be sane
- */
- if (tablet && (pressure >= 0.99f)) {
- pressure = 1.0f;
- }
- RNA_float_set(&itemptr, "pressure", pressure);
- }
- else {
- RNA_float_set(&itemptr, "pressure", 1.0f);
+ /* handle pressure sensitivity (which is supplied by tablets and otherwise 1.0) */
+ float pressure = event->tablet.pressure;
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets: clamp the values to be sane */
+ if (pressure >= 0.99f) {
+ pressure = 1.0f;
}
+ RNA_float_set(&itemptr, "pressure", pressure);
if (!gso->is_weight_mode) {
if (event->shift) {
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 6a91417e7f3..09ff24f05fc 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -2553,12 +2553,7 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en
/* Check if tablet eraser is being used (when processing events) */
static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
{
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- return (wmtab->Active == EVT_TABLET_ERASER);
- }
-
- return false;
+ return (event->tablet.active == EVT_TABLET_ERASER);
}
/* ------------------------------- */
@@ -3020,7 +3015,6 @@ static void gpencil_draw_apply_event(bContext *C,
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
PointerRNA itemptr;
float mousef[2];
- int tablet = 0;
bool is_speed_guide = ((guide->use_guide) &&
(p->brush && (p->brush->gpencil_tool == GPAINT_TOOL_DRAW)));
@@ -3055,29 +3049,20 @@ static void gpencil_draw_apply_event(bContext *C,
p->curtime = PIL_check_seconds_timer();
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
+ /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
+ p->pressure = event->tablet.pressure;
- tablet = (wmtab->Active != EVT_TABLET_NONE);
- p->pressure = wmtab->Pressure;
-
- /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
- * The pen has to float over the tablet surface, resulting in
- * zero pressure (T47101). Ignore pressure values if floating
- * (i.e. "effectively zero" pressure), and only when the "active"
- * end is the stylus (i.e. the default when not eraser)
- */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
- p->pressure = 1.0f;
- }
+ /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
+ * The pen has to float over the tablet surface, resulting in
+ * zero pressure (T47101). Ignore pressure values if floating
+ * (i.e. "effectively zero" pressure), and only when the "active"
+ * end is the stylus (i.e. the default when not eraser)
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if ((event->tablet.active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
+ p->pressure = 1.0f;
}
}
- else {
- /* No tablet data -> No pressure info is available */
- p->pressure = 1.0f;
- }
/* special eraser modes */
if (p->paintmode == GP_PAINTMODE_ERASER) {
@@ -3101,7 +3086,7 @@ static void gpencil_draw_apply_event(bContext *C,
/* special exception here for too high pressure values on first touch in
* windows for some tablets, then we just skip first touch...
*/
- if (tablet && (p->pressure >= 0.99f)) {
+ if ((event->tablet.active != EVT_TABLET_NONE) && (p->pressure >= 0.99f)) {
return;
}
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 6a801fc9928..9e0272d1402 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -69,7 +69,7 @@ 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);
+void ED_region_floating_initialize(struct ARegion *ar);
void ED_region_tag_redraw(struct ARegion *ar);
void ED_region_tag_redraw_partial(struct ARegion *ar, const struct rcti *rct, bool rebuild);
void ED_region_tag_redraw_overlay(struct ARegion *ar);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index b81fa4ae483..3089d980f06 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1640,7 +1640,12 @@ struct Panel *UI_panel_begin(struct ScrArea *sa,
struct PanelType *pt,
struct Panel *pa,
bool *r_open);
-void UI_panel_end(uiBlock *block, int width, int height, bool open);
+void UI_panel_end(const struct ScrArea *sa,
+ const struct ARegion *ar,
+ uiBlock *block,
+ int width,
+ int height,
+ bool open);
void UI_panels_scale(struct ARegion *ar, float new_width);
void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y);
int UI_panel_size_y(const struct Panel *pa);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index bd8eed4e4aa..66662c8c27d 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -143,6 +143,7 @@ typedef enum ThemeColorID {
TH_BONE_SOLID,
TH_BONE_POSE,
TH_BONE_POSE_ACTIVE,
+ TH_BONE_LOCKED_WEIGHT,
TH_STRIP,
TH_STRIP_SELECT,
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index cc68e303e4a..c058fefb4fa 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -124,7 +124,7 @@ bool ui_but_can_align(const uiBut *but)
int ui_but_align_opposite_to_area_align_get(const ARegion *ar)
{
- switch (ar->alignment) {
+ switch (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment)) {
case RGN_ALIGN_TOP:
return UI_BUT_ALIGN_DOWN;
case RGN_ALIGN_BOTTOM:
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 05d5f03a363..16996681695 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1886,11 +1886,13 @@ static bool ui_but_drag_init(bContext *C,
RGN_TYPE_HEADER,
RGN_TYPE_TOOL_HEADER,
RGN_TYPE_FOOTER)) {
+ const int ar_alignment = RGN_ALIGN_ENUM_FROM_MASK(data->region->alignment);
int lock_axis = -1;
- if (ELEM(data->region->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+
+ if (ELEM(ar_alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
lock_axis = 0;
}
- else if (ELEM(data->region->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ else if (ELEM(ar_alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
lock_axis = 1;
}
if (lock_axis != -1) {
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 52696475c20..179fe84264f 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1241,17 +1241,19 @@ static void ui_item_menu_hold(struct bContext *C, ARegion *butregion, uiBut *but
char direction = UI_DIR_DOWN;
if (!but->drawstr[0]) {
- if (butregion->alignment == RGN_ALIGN_LEFT) {
- direction = UI_DIR_RIGHT;
- }
- else if (butregion->alignment == RGN_ALIGN_RIGHT) {
- direction = UI_DIR_LEFT;
- }
- else if (butregion->alignment == RGN_ALIGN_BOTTOM) {
- direction = UI_DIR_UP;
- }
- else {
- direction = UI_DIR_DOWN;
+ switch (RGN_ALIGN_ENUM_FROM_MASK(butregion->alignment)) {
+ case RGN_ALIGN_LEFT:
+ direction = UI_DIR_RIGHT;
+ break;
+ case RGN_ALIGN_RIGHT:
+ direction = UI_DIR_LEFT;
+ break;
+ case RGN_ALIGN_BOTTOM:
+ direction = UI_DIR_UP;
+ break;
+ default:
+ direction = UI_DIR_DOWN;
+ break;
}
}
UI_block_direction_set(block, direction);
@@ -2436,6 +2438,10 @@ void uiItemEnumR_string_prop(uiLayout *layout,
}
for (a = 0; item[a].identifier; a++) {
+ if (item[a].identifier[0] == '\0') {
+ /* Skip enum item separators. */
+ continue;
+ }
if (item[a].value == ivalue) {
const char *item_name = name ?
name :
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 8adb82a22c8..cc1b7187e45 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -131,7 +131,7 @@ typedef enum eSpaceButtons_Align {
BUT_AUTO = 2,
} eSpaceButtons_Align;
-static int panel_aligned(ScrArea *sa, ARegion *ar)
+static int panel_aligned(const ScrArea *sa, const ARegion *ar)
{
if (sa->spacetype == SPACE_PROPERTIES && ar->regiontype == RGN_TYPE_WINDOW) {
return BUT_VERTICAL;
@@ -367,7 +367,19 @@ Panel *UI_panel_begin(
return pa;
}
-void UI_panel_end(uiBlock *block, int width, int height, bool open)
+static float panel_region_offset_x_get(const ARegion *ar, int align)
+{
+ if (UI_panel_category_is_visible(ar)) {
+ if (align == BUT_VERTICAL && (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) != RGN_ALIGN_RIGHT)) {
+ return UI_PANEL_CATEGORY_MARGIN_WIDTH;
+ }
+ }
+
+ return 0;
+}
+
+void UI_panel_end(
+ const ScrArea *sa, const ARegion *ar, uiBlock *block, int width, int height, bool open)
{
Panel *pa = block->panel;
@@ -391,6 +403,7 @@ void UI_panel_end(uiBlock *block, int width, int height, bool open)
}
else {
int old_sizex = pa->sizex, old_sizey = pa->sizey;
+ int old_region_ofsx = pa->runtime.region_ofsx;
/* update width/height if non-zero */
if (width != 0) {
@@ -405,6 +418,11 @@ void UI_panel_end(uiBlock *block, int width, int height, bool open)
pa->runtime_flag |= PNL_ANIM_ALIGN;
pa->ofsy += old_sizey - pa->sizey;
}
+
+ int align = panel_aligned(sa, ar);
+ if (old_region_ofsx != panel_region_offset_x_get(ar, align)) {
+ pa->runtime_flag |= PNL_ANIM_ALIGN;
+ }
}
}
@@ -1004,7 +1022,6 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo
int a, tot = 0;
bool done;
int align = panel_aligned(sa, ar);
- bool has_category_tabs = UI_panel_category_is_visible(ar);
/* count active, not tabbed panels */
for (pa = ar->panels.first; pa; pa = pa->next) {
@@ -1061,14 +1078,10 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo
/* no smart other default start loc! this keeps switching f5/f6/etc compatible */
ps = panelsort;
+ ps->pa->runtime.region_ofsx = panel_region_offset_x_get(ar, align);
ps->pa->ofsx = 0;
ps->pa->ofsy = -get_panel_size_y(ps->pa);
-
- if (has_category_tabs) {
- if (align == BUT_VERTICAL && (ar->alignment != RGN_ALIGN_RIGHT)) {
- ps->pa->ofsx += UI_PANEL_CATEGORY_MARGIN_WIDTH;
- }
- }
+ ps->pa->ofsx += ps->pa->runtime.region_ofsx;
for (a = 0; a < tot - 1; a++, ps++) {
psnext = ps + 1;
@@ -1913,7 +1926,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
{
/* no tab outlines for */
// #define USE_FLAT_INACTIVE
- const bool is_left = (ar->alignment != RGN_ALIGN_RIGHT);
+ const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment != RGN_ALIGN_RIGHT);
View2D *v2d = &ar->v2d;
uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
@@ -2201,7 +2214,7 @@ static int ui_handle_panel_category_cycling(const wmEvent *event,
{
const bool is_mousewheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE);
const bool inside_tabregion =
- ((ar->alignment != RGN_ALIGN_RIGHT) ?
+ ((RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) != RGN_ALIGN_RIGHT) ?
(event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax) :
(event->mval[0] > ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmin));
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
index fa471441cc9..d32cd5c17e2 100644
--- a/source/blender/editors/interface/interface_region_hud.c
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -364,7 +364,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
ED_area_update_region_sizes(wm, win, sa);
}
- ED_region_init(ar);
+ ED_region_floating_initialize(ar);
ED_region_tag_redraw(ar);
/* Reset zoom level (not well supported). */
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index fed3c0b3d11..560c6146afe 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -280,13 +280,13 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
ARegion *ar = CTX_wm_region(C);
if (sa && ar) {
if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP);
UI_block_order_flip(block);
}
}
if (ar->regiontype == RGN_TYPE_FOOTER) {
- if (ED_area_footer_alignment(sa) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP);
UI_block_order_flip(block);
}
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index cd0421dde09..2042c15ed96 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -189,12 +189,12 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
/* Prefer popover from header to be positioned into the editor. */
else if (sa && ar) {
if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
}
}
if (ar->regiontype == RGN_TYPE_FOOTER) {
- if (ED_area_footer_alignment(sa) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
}
}
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 63dee77e90e..59d955e0278 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -728,7 +728,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
ui_popup_block_scrolltest(block);
/* adds subwindow */
- ED_region_init(ar);
+ ED_region_floating_initialize(ar);
/* get winmat now that we actually have the subwindow */
wmGetProjectionMatrix(block->winmat, &ar->winrct);
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c
index 251bc86a3f5..94bcd6ab37d 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.c
@@ -639,7 +639,7 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but
}
/* adds subwindow */
- ED_region_init(ar);
+ ED_region_floating_initialize(ar);
/* notify change and redraw */
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 38c17f3c395..7a0c04be356 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -1391,7 +1391,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
}
/* adds subwindow */
- ED_region_init(ar);
+ ED_region_floating_initialize(ar);
/* notify change and redraw */
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 280ce4c0efa..c43b7385a36 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -6865,7 +6865,6 @@ static char *progress_tooltip_func(bContext *UNUSED(C), void *argN, const char *
void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
{
- bScreen *screen = CTX_wm_screen(C);
wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *sa = CTX_wm_area(C);
uiBlock *block;
@@ -7047,7 +7046,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
}
}
- if (screen->animtimer) {
+ if (ED_screen_animation_no_scrub(wm)) {
uiDefIconTextBut(block,
UI_BTYPE_BUT,
B_STOPANIM,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index d313310bfa1..fd2f652d40e 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -2662,10 +2662,14 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
if (color_blend != NULL) {
color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
}
- }
- if (state & UI_ACTIVE) {
- widget_active_color(&wt->wcol);
+ /* Add "hover" highlight. Ideally this could apply in all cases,
+ * even if UI_SELECT. But currently this causes some flickering
+ * as buttons can be created and updated without respect to mouse
+ * position and so can draw without UI_ACTIVE set. See D6503. */
+ if (state & UI_ACTIVE) {
+ widget_active_color(&wt->wcol);
+ }
}
if (state & UI_BUT_REDALERT) {
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index f8b4d85a212..37921b48401 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -443,6 +443,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_BONE_POSE_ACTIVE:
cp = ts->bone_pose_active;
break;
+ case TH_BONE_LOCKED_WEIGHT:
+ cp = ts->bone_locked_weight;
+ break;
case TH_STRIP:
cp = ts->strip;
break;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index a3f84e7bdd0..a23bd7dad35 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -354,11 +354,6 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
/* note, scroll is being flipped in ED_region_panels() drawing */
v2d->scroll |= (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_VERTICAL_HIDE);
- /* initialize without scroll bars (interferes with zoom level see: T47047) */
- if (do_init) {
- v2d->scroll |= (V2D_SCROLL_VERTICAL_FULLR | V2D_SCROLL_HORIZONTAL_FULLR);
- }
-
if (do_init) {
float panelzoom = (style) ? style->panelzoom : 1.0f;
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 7582ef3f41d..9f9e523b57b 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -316,7 +316,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
FILE_BLENDER,
FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
@@ -694,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_RELPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index dad84c87fd7..3f51504d6ac 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -541,7 +541,7 @@ void WM_OT_collada_export(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_COLLADA,
FILE_BLENDER,
FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
@@ -870,7 +870,7 @@ void WM_OT_collada_import(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_COLLADA,
FILE_BLENDER,
FILE_OPENFILE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c
index f19a988809a..69274f77049 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin.c
@@ -199,7 +199,7 @@ void MESH_OT_spin(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000);
+ RNA_def_int(ot->srna, "steps", 12, 0, 1000000, "Steps", "Steps", 0, 1000);
prop = RNA_def_boolean(ot->srna, "dupli", 0, "Use Duplicates", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 452b349cfbf..5c1c6d27ec6 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -603,27 +603,8 @@ static int lightprobe_add_exec(bContext *C, wmOperator *op)
copy_v3_fl(ob->scale, radius);
probe = (LightProbe *)ob->data;
- probe->type = type;
- switch (type) {
- case LIGHTPROBE_TYPE_GRID:
- probe->distinf = 0.3f;
- probe->falloff = 1.0f;
- probe->clipsta = 0.01f;
- break;
- case LIGHTPROBE_TYPE_PLANAR:
- probe->distinf = 0.1f;
- probe->falloff = 0.5f;
- probe->clipsta = 0.001f;
- ob->empty_drawsize = 0.5f;
- break;
- case LIGHTPROBE_TYPE_CUBE:
- probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID;
- break;
- default:
- BLI_assert(!"LightProbe type not configured.");
- break;
- }
+ BKE_lightprobe_type_set(probe, type);
DEG_relations_tag_update(CTX_data_main(C));
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 8012565ba2e..34e1b3b2b4b 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_DEPSGRAPH)) {
+ if (!(base->flag & BASE_VISIBLE_VIEWLAYER)) {
continue;
}
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index e8e0569f15e..05fa78aab1c 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -3179,6 +3179,8 @@ static int vertex_group_lock_exec(bContext *C, wmOperator *op)
vgroup_lock_all(ob, action);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 29626fb6a8f..cb0be6f56ac 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1141,6 +1141,9 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar)
}
}
+ /* Guard against flags slipping through that would have to be masked out in usages below. */
+ BLI_assert(align1 == RGN_ALIGN_ENUM_FROM_MASK(align1));
+
/* translate or close */
if (ar1) {
if (align1 == RGN_ALIGN_LEFT) {
@@ -1244,6 +1247,20 @@ static void region_rect_recursive(
alignment = RGN_ALIGN_NONE;
}
+ /* If both the ARegion.sizex/y and the prefsize are 0, the region is tagged as too small, even
+ * before the layout for dynamic regions is created. #wm_draw_window_offscreen() allows the
+ * layout to be created despite the RGN_FLAG_TOO_SMALL flag being set. But there may still be
+ * regions that don't have a separate ARegionType.layout callback. For those, set a default
+ * prefsize so they can become visible. */
+ if ((ar->flag & RGN_FLAG_DYNAMIC_SIZE) && !(ar->type->layout)) {
+ if ((ar->sizex == 0) && (ar->type->prefsizex == 0)) {
+ ar->type->prefsizex = AREAMINX;
+ }
+ if ((ar->sizey == 0) && (ar->type->prefsizey == 0)) {
+ ar->type->prefsizey = HEADERY;
+ }
+ }
+
/* prefsize, taking into account DPI */
int prefsizex = UI_DPI_FAC * ((ar->sizex > 1) ? ar->sizex + 0.5f : ar->type->prefsizex);
int prefsizey;
@@ -1323,7 +1340,7 @@ static void region_rect_recursive(
else if (alignment == RGN_ALIGN_TOP || alignment == RGN_ALIGN_BOTTOM) {
rcti *winrct = (ar->overlap) ? overlap_remainder : remainder;
- if (rct_fits(winrct, 'v', prefsizey) < 0) {
+ if ((prefsizey == 0) || (rct_fits(winrct, 'v', prefsizey) < 0)) {
ar->flag |= RGN_FLAG_TOO_SMALL;
}
else {
@@ -1348,7 +1365,7 @@ static void region_rect_recursive(
else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
rcti *winrct = (ar->overlap) ? overlap_remainder : remainder;
- if (rct_fits(winrct, 'h', prefsizex) < 0) {
+ if ((prefsizex == 0) || (rct_fits(winrct, 'h', prefsizex) < 0)) {
ar->flag |= RGN_FLAG_TOO_SMALL;
}
else {
@@ -1438,9 +1455,8 @@ static void region_rect_recursive(
}
/* Fix any negative dimensions. This can happen when a quad split 3d view gets to small. (see
- * T72200). BLI_rcti_init() sanitizes, making sure min values are <= max values. */
- BLI_rcti_init(
- &ar->winrct, ar->winrct.xmin, ar->winrct.xmax, ar->winrct.ymin, ar->winrct.ymax);
+ * T72200). */
+ BLI_rcti_sanitize(&ar->winrct);
quad++;
}
@@ -1479,11 +1495,16 @@ static void region_rect_recursive(
ar->winrct.xmin = ar->winrct.xmax;
break;
case RGN_ALIGN_LEFT:
+ ar->winrct.xmax = ar->winrct.xmin;
+ break;
default:
/* prevent winrct to be valid */
ar->winrct.xmax = ar->winrct.xmin;
break;
}
+
+ /* Size on one axis is now 0, the other axis may still be invalid (negative) though. */
+ BLI_rcti_sanitize(&ar->winrct);
}
/* restore prev-split exception */
@@ -1501,6 +1522,8 @@ static void region_rect_recursive(
*overlap_remainder = *remainder;
}
+ BLI_assert(BLI_rcti_is_valid(&ar->winrct));
+
region_rect_recursive(sa, ar->next, remainder, overlap_remainder, quad);
/* Tag for redraw if size changes. */
@@ -1818,8 +1841,10 @@ void ED_region_update_rect(ARegion *ar)
}
/* externally called for floating regions like menus */
-void ED_region_init(ARegion *ar)
+void ED_region_floating_initialize(ARegion *ar)
{
+ BLI_assert(ar->alignment == RGN_ALIGN_FLOAT);
+
/* refresh can be called before window opened */
region_subwindow(ar);
@@ -2321,7 +2346,7 @@ static void ed_panel_draw(const bContext *C,
}
}
- UI_panel_end(block, w, h, open);
+ UI_panel_end(sa, ar, block, w, h, open);
}
/**
@@ -2565,7 +2590,7 @@ void ED_region_panels_draw(const bContext *C, ARegion *ar)
/* scrollers */
const rcti *mask = NULL;
rcti mask_buf;
- if (ar->runtime.category && (ar->alignment == RGN_ALIGN_RIGHT)) {
+ if (ar->runtime.category && (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_RIGHT)) {
UI_view2d_mask_from_win(v2d, &mask_buf);
mask_buf.xmax -= UI_PANEL_CATEGORY_MARGIN_WIDTH;
mask = &mask_buf;
@@ -2902,7 +2927,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
@@ -3327,7 +3352,9 @@ static void region_visible_rect_calc(ARegion *ar, rcti *rect)
for (; arn; arn = arn->next) {
if (ar != arn && arn->overlap) {
if (BLI_rcti_isect(rect, &arn->winrct, NULL)) {
- if (ELEM(arn->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ int alignment = RGN_ALIGN_ENUM_FROM_MASK(arn->alignment);
+
+ if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
/* Overlap left, also check 1 pixel offset (2 regions on one side). */
if (ABS(rect->xmin - arn->winrct.xmin) < 2) {
rect->xmin = arn->winrct.xmax;
@@ -3338,7 +3365,7 @@ static void region_visible_rect_calc(ARegion *ar, rcti *rect)
rect->xmax = arn->winrct.xmin;
}
}
- else if (ELEM(arn->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ else if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
/* Same logic as above for vertical regions. */
if (ABS(rect->ymin - arn->winrct.ymin) < 2) {
rect->ymin = arn->winrct.ymax;
@@ -3347,7 +3374,7 @@ static void region_visible_rect_calc(ARegion *ar, rcti *rect)
rect->ymax = arn->winrct.ymin;
}
}
- else if (arn->alignment == RGN_ALIGN_FLOAT) {
+ else if (alignment == RGN_ALIGN_FLOAT) {
/* Skip floating. */
}
else {
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 46559efc614..942050aaffd 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -67,10 +67,12 @@ bool ED_region_panel_category_gutter_calc_rect(const ARegion *ar, rcti *r_ar_gut
if (UI_panel_category_is_visible(ar)) {
const int category_tabs_width = round_fl_to_int(UI_view2d_scale_get_x(&ar->v2d) *
UI_PANEL_CATEGORY_MARGIN_WIDTH);
- if (ar->alignment == RGN_ALIGN_LEFT) {
+ const int alignment = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment);
+
+ if (alignment == RGN_ALIGN_LEFT) {
r_ar_gutter->xmax = r_ar_gutter->xmin + category_tabs_width;
}
- else if (ar->alignment == RGN_ALIGN_RIGHT) {
+ else if (alignment == RGN_ALIGN_RIGHT) {
r_ar_gutter->xmin = r_ar_gutter->xmax - category_tabs_width;
}
else {
@@ -141,14 +143,16 @@ bool ED_region_contains_xy(const ARegion *ar, const int event_xy[2])
else {
/* Side-bar & any other kind of overlapping region. */
+ const int alignment = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment);
+
/* Check alignment to avoid region tabs being clipped out
* by only clipping a single axis for aligned regions. */
- if (ELEM(ar->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
if (!ED_region_overlap_isect_x_with_margin(ar, event_xy[0], overlap_margin)) {
return false;
}
}
- else if (ELEM(ar->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
if (ED_region_panel_category_gutter_isect_xy(ar, event_xy)) {
/* pass */
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index dd09def2df6..0e1ae03fd20 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -4114,8 +4114,9 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
- const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") :
- IFACE_("Flip to Top");
+ const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_TOP) ?
+ IFACE_("Flip to Bottom") :
+ IFACE_("Flip to Top");
{
PointerRNA ptr;
RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr);
@@ -4160,8 +4161,9 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
- const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") :
- IFACE_("Flip to Top");
+ const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_TOP) ?
+ IFACE_("Flip to Bottom") :
+ IFACE_("Flip to Top");
{
PointerRNA ptr;
RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr);
@@ -4186,8 +4188,9 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN
void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
const ARegion *ar = CTX_wm_region(C);
- const char *but_flip_str = (ar->alignment == RGN_ALIGN_LEFT) ? IFACE_("Flip to Right") :
- IFACE_("Flip to Left");
+ const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_LEFT) ?
+ IFACE_("Flip to Right") :
+ IFACE_("Flip to Left");
/* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
@@ -4840,7 +4843,10 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
* So hiding in the temp window makes sense. */
ScrArea *area = CTX_wm_area(C);
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
+
region->flag |= RGN_FLAG_HIDDEN;
+ ED_region_visibility_change_update(C, area, region);
+
return OPERATOR_FINISHED;
}
else {
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 5ceaefd6309..5fdabea62c1 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -211,12 +211,13 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
PointerRNA ptr, idptr;
PropertyRNA *prop;
+ bAction *oldact = NULL;
+ AnimData *adt = NULL;
/* hook into UI */
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
- bAction *action = NULL, *oldact = NULL;
- AnimData *adt = NULL;
+ /* The operator was called from a button. */
PointerRNA oldptr;
oldptr = RNA_property_pointer_get(&ptr, prop);
@@ -229,6 +230,13 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
adt = ED_actedit_animdata_from_context(C);
}
+ }
+ else {
+ adt = ED_actedit_animdata_from_context(C);
+ oldact = adt->action;
+ }
+ {
+ bAction *action = NULL;
/* Perform stashing operation - But only if there is an action */
if (adt && oldact) {
@@ -257,12 +265,14 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
/* create action */
action = action_create_new(C, oldact);
- /* set this new action
- * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
- */
- RNA_id_pointer_create(&action->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
- RNA_property_update(C, &ptr, prop);
+ if (prop) {
+ /* set this new action
+ * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
+ */
+ RNA_id_pointer_create(&action->id, &idptr);
+ RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_update(C, &ptr, prop);
+ }
}
/* set notifier that keyframes have changed */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 5eac041b217..6e44992ea6e 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -488,9 +488,9 @@ static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
void ACTION_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Frame";
+ ot->name = "Go to Current Frame";
ot->idname = "ACTION_OT_view_frame";
- ot->description = "Reset viewable area to show range around current frame";
+ ot->description = "Move the view to the playhead";
/* api callbacks */
ot->exec = actkeys_view_frame_exec;
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 16305a9b17b..04c939ec41b 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -1083,11 +1083,7 @@ static void graph_region_draw(const bContext *C, ARegion *ar)
/* scale indicators */
{
rcti rect;
- BLI_rcti_init(&rect,
- 0,
- 15 * UI_DPI_FAC,
- 15 * UI_DPI_FAC,
- UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y);
+ BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y);
UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_TEXT);
}
}
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 6c95e74e834..0a3663372be 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -156,7 +156,7 @@ static void graph_panel_properties(const bContext *C, Panel *pa)
FCurve *fcu;
PointerRNA fcu_ptr;
uiLayout *layout = pa->layout;
- uiLayout *col, *row, *sub;
+ uiLayout *col;
char name[256];
int icon = 0;
@@ -193,27 +193,26 @@ static void graph_panel_properties(const bContext *C, Panel *pa)
}
uiItemL(col, name, icon);
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
/* RNA-Path Editing - only really should be enabled when things aren't working */
- col = uiLayoutColumn(layout, true);
+ col = uiLayoutColumn(layout, false);
uiLayoutSetEnabled(col, (fcu->flag & FCURVE_DISABLED) != 0);
uiItemR(col, &fcu_ptr, "data_path", 0, "", ICON_RNA);
uiItemR(col, &fcu_ptr, "array_index", 0, NULL, ICON_NONE);
/* color settings */
col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Display Color:"), ICON_NONE);
+ uiItemR(col, &fcu_ptr, "color_mode", 0, "Display Color", ICON_NONE);
- row = uiLayoutRow(col, true);
- uiItemR(row, &fcu_ptr, "color_mode", 0, "", ICON_NONE);
-
- sub = uiLayoutRow(row, true);
- uiLayoutSetEnabled(sub, (fcu->color_mode == FCURVE_COLOR_CUSTOM));
- uiItemR(sub, &fcu_ptr, "color", 0, "", ICON_NONE);
+ if (fcu->color_mode == FCURVE_COLOR_CUSTOM) {
+ uiItemR(col, &fcu_ptr, "color", 0, "Color", ICON_NONE);
+ }
/* smoothing setting */
col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Auto Handle Smoothing:"), ICON_NONE);
- uiItemR(col, &fcu_ptr, "auto_smoothing", 0, "", ICON_NONE);
+ uiItemR(col, &fcu_ptr, "auto_smoothing", 0, "Handle Smoothing", ICON_NONE);
MEM_freeN(ale);
}
@@ -339,6 +338,9 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
BezTriple *bezt, *prevbezt;
uiLayout *layout = pa->layout;
+ const ARegion *ar = CTX_wm_region(C);
+ /* Just a width big enough so buttons use entire layout width (will be clamped by it then). */
+ const int but_max_width = ar->winx;
uiLayout *col;
uiBlock *block;
@@ -348,6 +350,8 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
block = uiLayoutGetBlock(layout);
/* UI_block_func_handle_set(block, do_graph_region_buttons, NULL); */
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* only show this info if there are keyframes to edit */
if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) {
@@ -404,57 +408,60 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
col = uiLayoutColumn(layout, true);
/* keyframe itself */
{
- uiItemL(col, IFACE_("Key:"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Key Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- IFACE_("Frame:"),
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"co",
- 0,
+ 1,
0,
0,
-1,
-1,
NULL);
UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
+ UI_but_unit_type_set(but, unit);
+ uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- IFACE_("Value:"),
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"co",
- 1,
+ 0,
0,
0,
-1,
-1,
NULL);
UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
- UI_but_unit_type_set(but, unit);
}
/* previous handle - only if previous was Bezier interpolation */
if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
- uiItemL(col, IFACE_("Left Handle:"), ICON_NONE);
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL_respect_property_split(col, IFACE_("Left Handle X"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- "X:",
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_left",
@@ -466,13 +473,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
+ uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- "Y:",
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_left",
@@ -485,14 +493,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
- /* XXX: with label? */
+ uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_MENU,
B_REDR,
NULL,
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_left_type",
@@ -508,15 +516,16 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
/* next handle - only if current is Bezier interpolation */
if (bezt->ipo == BEZT_IPO_BEZ) {
/* NOTE: special update callbacks are needed on the coords here due to T39911 */
- uiItemL(col, IFACE_("Right Handle:"), ICON_NONE);
+ col = uiLayoutColumn(layout, true);
+ uiItemL_respect_property_split(col, IFACE_("Right Handle X"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- "X:",
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_right",
@@ -528,13 +537,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
+ uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- "Y:",
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_right",
@@ -547,14 +557,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
- /* XXX: with label? */
+ uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_MENU,
B_REDR,
NULL,
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_right_type",
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 03df93e4c8a..59a1102f7d6 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -292,13 +292,12 @@ static int graphkeys_viewall(bContext *C,
/* Give some more space at the borders. */
BLI_rctf_scale(&cur_new, 1.1f);
- /* Take regions into account, that could block the view. */
+ /* Take regions into account, that could block the view. Marker region is supposed to be larger
+ * than the scrollbar, so priorize it.*/
float pad_top = UI_TIME_SCRUB_MARGIN_Y;
- float pad_bottom = 0;
- if (!BLI_listbase_is_empty(ED_context_get_markers(C))) {
- pad_bottom = UI_MARKER_MARGIN_Y;
- }
- BLI_rctf_pad_y(&cur_new, ac.ar->sizey * UI_DPI_FAC, pad_bottom, pad_top);
+ float pad_bottom = BLI_listbase_is_empty(ED_context_get_markers(C)) ? V2D_SCROLL_HANDLE_HEIGHT :
+ UI_MARKER_MARGIN_Y;
+ BLI_rctf_pad_y(&cur_new, ac.ar->winy, pad_bottom, pad_top);
UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx);
return OPERATOR_FINISHED;
@@ -384,9 +383,9 @@ static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
void GRAPH_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Frame";
+ ot->name = "Go to Current Frame";
ot->idname = "GRAPH_OT_view_frame";
- ot->description = "Reset viewable area to show range around current frame";
+ ot->description = "Move the view to the playhead";
/* api callbacks */
ot->exec = graphkeys_view_frame_exec;
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 7bc907bb3db..d01e4112fd0 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -326,11 +326,7 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
/* scale numbers */
{
rcti rect;
- BLI_rcti_init(&rect,
- 0,
- 15 * UI_DPI_FAC,
- 15 * UI_DPI_FAC,
- UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y);
+ BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y);
UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_SCROLL_TEXT);
}
}
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 04a20efe887..0f170b1f530 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -565,9 +565,9 @@ static int nlaedit_viewframe_exec(bContext *C, wmOperator *op)
void NLA_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Frame";
+ ot->name = "Go to Current Frame";
ot->idname = "NLA_OT_view_frame";
- ot->description = "Reset viewable area to show range around current frame";
+ ot->description = "Move the view to the playhead";
/* api callbacks */
ot->exec = nlaedit_viewframe_exec;
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 589375530f5..9e8fa6475a0 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -96,8 +96,8 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
INT_MAX,
"Start Frame",
"Start frame of the sequence strip",
- INT_MIN,
- INT_MAX);
+ -MAXFRAME,
+ MAXFRAME);
}
if (flag & SEQPROP_ENDFRAME) {
@@ -109,8 +109,8 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
INT_MAX,
"End Frame",
"End frame for the color strip",
- INT_MIN,
- INT_MAX);
+ -MAXFRAME,
+ MAXFRAME);
}
RNA_def_int(
@@ -312,6 +312,26 @@ static void sequencer_add_apply_replace_sel(bContext *C, wmOperator *op, Sequenc
}
}
+static bool seq_effect_add_properties_poll(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ /* Hide start/end frames for effect strips that are locked to their parents' location. */
+ if (BKE_sequence_effect_get_num_inputs(type) != 0) {
+ if ((STREQ(prop_id, "frame_start")) || (STREQ(prop_id, "frame_end"))) {
+ return false;
+ }
+ }
+ if ((type != SEQ_TYPE_COLOR) && (STREQ(prop_id, "color"))) {
+ return false;
+ }
+
+ return true;
+}
+
/* add scene operator */
static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
{
@@ -1066,8 +1086,8 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
/* If seq1 is NULL and no error was raised it means the seq is standalone
* (like color strips) and we need to check its start and end frames are valid */
if (seq1 == NULL && end_frame <= start_frame) {
- BKE_report(op->reports, RPT_ERROR, "Start and end frame are not set");
- return OPERATOR_CANCELLED;
+ end_frame = start_frame + 1;
+ RNA_int_set(op->ptr, "frame_end", end_frame);
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, type);
@@ -1161,6 +1181,8 @@ static int sequencer_add_effect_strip_invoke(bContext *C,
void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Effect Strip";
ot->idname = "SEQUENCER_OT_effect_strip_add";
@@ -1171,25 +1193,27 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
ot->exec = sequencer_add_effect_strip_exec;
ot->poll = ED_operator_sequencer_active_editable;
+ ot->poll_property = seq_effect_add_properties_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
- RNA_def_float_vector(ot->srna,
- "color",
- 3,
- NULL,
- 0.0f,
- 1.0f,
- "Color",
- "Initialize the strip with this color (only used when type='COLOR')",
- 0.0f,
- 1.0f);
+ sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
+ prop = RNA_def_float_color(ot->srna,
+ "color",
+ 3,
+ NULL,
+ 0.0f,
+ 1.0f,
+ "Color",
+ "Initialize the strip with this color (only used when type='COLOR')",
+ 0.0f,
+ 1.0f);
+ RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 20fba7aa919..bef4a7cdd22 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2113,11 +2113,7 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
/* channel numbers */
{
rcti rect;
- BLI_rcti_init(&rect,
- 0,
- 15 * UI_DPI_FAC,
- 15 * UI_DPI_FAC,
- UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y);
+ BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y);
UI_view2d_draw_scale_y__block(ar, v2d, &rect, TH_SCROLL_TEXT);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 57a0d63c35e..a1177454acd 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -103,6 +103,7 @@ EnumPropertyItem prop_side_types[] = {
{SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
{SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
{SEQ_SIDE_BOTH, "BOTH", 0, "Both", ""},
+ {SEQ_SIDE_NO_CHANGE, "NO_CHANGE", 0, "No change", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -958,6 +959,8 @@ static bool cut_seq_list(Main *bmain,
Scene *scene,
ListBase *slist,
int cutframe,
+ int channel,
+ bool use_cursor_position,
Sequence *(*cut_seq)(Main *bmain, Scene *, Sequence *, ListBase *, int))
{
Sequence *seq, *seq_next_iter;
@@ -968,8 +971,8 @@ static bool cut_seq_list(Main *bmain,
while (seq && seq != seq_first_new) {
seq_next_iter = seq->next; /* we need this because we may remove seq */
seq->tmp = NULL;
- if (seq->flag & SELECT) {
- if (cutframe > seq->startdisp && cutframe < seq->enddisp) {
+ if (use_cursor_position) {
+ if (seq->machine == channel && seq->startdisp < cutframe && seq->enddisp > cutframe) {
Sequence *seqn = cut_seq(bmain, scene, seq, slist, cutframe);
if (seqn) {
if (seq_first_new == NULL) {
@@ -977,16 +980,28 @@ static bool cut_seq_list(Main *bmain,
}
}
}
- else if (seq->enddisp <= cutframe) {
- /* do nothing */
- }
- else if (seq->startdisp >= cutframe) {
- /* move to tail */
- BLI_remlink(slist, seq);
- BLI_addtail(slist, seq);
+ }
+ else {
+ if (seq->flag & SELECT) {
+ if (cutframe > seq->startdisp && cutframe < seq->enddisp) {
+ Sequence *seqn = cut_seq(bmain, scene, seq, slist, cutframe);
+ if (seqn) {
+ if (seq_first_new == NULL) {
+ seq_first_new = seqn;
+ }
+ }
+ }
+ else if (seq->enddisp <= cutframe) {
+ /* do nothing */
+ }
+ else if (seq->startdisp >= cutframe) {
+ /* move to tail */
+ BLI_remlink(slist, seq);
+ BLI_addtail(slist, seq);
- if (seq_first_new == NULL) {
- seq_first_new = seq;
+ if (seq_first_new == NULL) {
+ seq_first_new = seq;
+ }
}
}
}
@@ -2154,40 +2169,64 @@ static int sequencer_cut_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- int cut_side, cut_hard, cut_frame;
-
- bool changed;
+ int cut_side, cut_hard, cut_frame, cut_channel;
+ bool changed, use_cursor_position, ignore_selection;
+ bool seq_selected = false;
cut_frame = RNA_int_get(op->ptr, "frame");
+ cut_channel = RNA_int_get(op->ptr, "channel");
+ use_cursor_position = RNA_boolean_get(op->ptr, "use_cursor_position");
cut_hard = RNA_enum_get(op->ptr, "type");
cut_side = RNA_enum_get(op->ptr, "side");
+ ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection");
if (cut_hard == SEQ_CUT_HARD) {
- changed = cut_seq_list(bmain, scene, ed->seqbasep, cut_frame, cut_seq_hard);
+ changed = cut_seq_list(
+ bmain, scene, ed->seqbasep, cut_frame, cut_channel, use_cursor_position, cut_seq_hard);
}
else {
- changed = cut_seq_list(bmain, scene, ed->seqbasep, cut_frame, cut_seq_soft);
+ changed = cut_seq_list(
+ bmain, scene, ed->seqbasep, cut_frame, cut_channel, use_cursor_position, cut_seq_soft);
}
if (changed) { /* got new strips ? */
Sequence *seq;
- if (cut_side != SEQ_SIDE_BOTH) {
- SEQP_BEGIN (ed, seq) {
- if (cut_side == SEQ_SIDE_LEFT) {
- if (seq->startdisp >= cut_frame) {
- seq->flag &= ~SEQ_ALLSEL;
+ if (ignore_selection) {
+ if (use_cursor_position) {
+ SEQP_BEGIN (ed, seq) {
+ if (seq->enddisp == cut_frame && seq->machine == cut_channel) {
+ seq_selected = seq->flag & SEQ_ALLSEL;
}
}
- else {
- if (seq->enddisp <= cut_frame) {
- seq->flag &= ~SEQ_ALLSEL;
+ SEQ_END;
+ if (!seq_selected) {
+ SEQP_BEGIN (ed, seq) {
+ if (seq->startdisp == cut_frame && seq->machine == cut_channel) {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
}
+ SEQ_END;
}
}
- SEQ_END;
}
-
+ else {
+ if (cut_side != SEQ_SIDE_BOTH) {
+ SEQP_BEGIN (ed, seq) {
+ if (cut_side == SEQ_SIDE_LEFT) {
+ if (seq->startdisp >= cut_frame) {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
+ }
+ else {
+ if (seq->enddisp <= cut_frame) {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
+ }
+ }
+ SEQ_END;
+ }
+ }
SEQP_BEGIN (ed, seq) {
if (seq->seq1 || seq->seq2 || seq->seq3) {
BKE_sequence_calc(scene, seq);
@@ -2204,7 +2243,8 @@ static int sequencer_cut_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
else {
- return OPERATOR_CANCELLED;
+ /* Passthrough to selection if used as tool. */
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
}
@@ -2224,7 +2264,17 @@ static int sequencer_cut_invoke(bContext *C, wmOperator *op, const wmEvent *even
cut_side = SEQ_SIDE_BOTH;
}
}
- RNA_int_set(op->ptr, "frame", cut_frame);
+
+ float mouseloc[2];
+ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
+
+ if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
+ RNA_int_set(op->ptr, "frame", mouseloc[0]);
+ }
+ else {
+ RNA_int_set(op->ptr, "frame", cut_frame);
+ }
+ RNA_int_set(op->ptr, "channel", mouseloc[1]);
RNA_enum_set(op->ptr, "side", cut_side);
/*RNA_enum_set(op->ptr, "type", cut_hard); */ /*This type is set from the key shortcut */
return sequencer_cut_exec(C, op);
@@ -2255,19 +2305,43 @@ void SEQUENCER_OT_cut(struct wmOperatorType *ot)
"Frame where selected strips will be cut",
INT_MIN,
INT_MAX);
+ RNA_def_int(ot->srna,
+ "channel",
+ 0,
+ INT_MIN,
+ INT_MAX,
+ "Channel",
+ "Channel in which strip will be cut",
+ INT_MIN,
+ INT_MAX);
RNA_def_enum(ot->srna,
"type",
prop_cut_types,
SEQ_CUT_SOFT,
"Type",
"The type of cut operation to perform on strips");
+ RNA_def_boolean(ot->srna,
+ "use_cursor_position",
+ 0,
+ "Use Cursor Position",
+ "Cut at position of the cursor instead of playhead");
prop = RNA_def_enum(ot->srna,
"side",
prop_side_types,
SEQ_SIDE_MOUSE,
"Side",
"The side that remains selected after cutting");
+
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(
+ ot->srna,
+ "ignore_selection",
+ false,
+ "Ignore Selection",
+ "Make cut event if strip is not selected preserving selection state after cut");
+
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
#undef SEQ_SIDE_MOUSE
@@ -2326,9 +2400,6 @@ void SEQUENCER_OT_duplicate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* to give to transform */
- RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
/* delete operator */
@@ -3153,7 +3224,7 @@ void SEQUENCER_OT_strip_jump(wmOperatorType *ot)
ot->poll = sequencer_strip_jump_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "next", true, "Next Strip", "");
@@ -4246,5 +4317,5 @@ void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_boolean(ot->srna, "preview", false, "Preview", "Set the preview range instead");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c
index f262c6518aa..b90dc5e10ff 100644
--- a/source/blender/editors/space_sequencer/sequencer_modifier.c
+++ b/source/blender/editors/space_sequencer/sequencer_modifier.c
@@ -123,6 +123,8 @@ static int strip_modifier_remove_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_strip_modifier_remove(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Remove Strip Modifier";
ot->idname = "SEQUENCER_OT_strip_modifier_remove";
@@ -136,7 +138,8 @@ void SEQUENCER_OT_strip_modifier_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
+ prop = RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/*********************** Move operator *************************/
@@ -183,6 +186,8 @@ static int strip_modifier_move_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
static const EnumPropertyItem direction_items[] = {
{SEQ_MODIFIER_MOVE_UP, "UP", 0, "Up", "Move modifier up in the stack"},
{SEQ_MODIFIER_MOVE_DOWN, "DOWN", 0, "Down", "Move modifier down in the stack"},
@@ -202,8 +207,10 @@ void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
- RNA_def_enum(ot->srna, "direction", direction_items, SEQ_MODIFIER_MOVE_UP, "Type", "");
+ prop = RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_enum(ot->srna, "direction", direction_items, SEQ_MODIFIER_MOVE_UP, "Type", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/*********************** Copy to selected operator *************************/
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index ea93ef2e040..a5bb66ca65f 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -312,7 +312,7 @@ void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
ot->poll = sequencer_edit_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
WM_operator_properties_select_all(ot);
}
@@ -353,7 +353,7 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
ot->poll = sequencer_edit_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
}
static int sequencer_select_exec(bContext *C, wmOperator *op)
@@ -647,7 +647,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
ot->poll = ED_operator_sequencer_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
WM_operator_properties_generic_select(ot);
@@ -1086,7 +1086,7 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot)
ot->poll = ED_operator_sequencer_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
WM_operator_properties_gesture_box(ot);
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 6e1b9d62f0e..81783f9105c 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -110,6 +110,14 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
ar->alignment = RGN_ALIGN_RIGHT;
ar->flag = RGN_FLAG_HIDDEN;
+ /* toolbar */
+ ar = MEM_callocN(sizeof(ARegion), "tools for sequencer");
+
+ BLI_addtail(&sseq->regionbase, ar);
+ ar->regiontype = RGN_TYPE_TOOLS;
+ ar->alignment = RGN_ALIGN_LEFT;
+ ar->flag = RGN_FLAG_HIDDEN;
+
/* preview region */
/* NOTE: if you change values here, also change them in sequencer_init_preview_region */
ar = MEM_callocN(sizeof(ARegion), "preview region for sequencer");
@@ -618,6 +626,23 @@ static void sequencer_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
+/* *********************** toolbar region ************************ */
+/* add handlers, stuff you only do once or on area/region changes */
+static void sequencer_tools_region_init(wmWindowManager *wm, ARegion *ar)
+{
+ wmKeyMap *keymap;
+
+ ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
+ ED_region_panels_init(wm, ar);
+
+ keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
+ WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
+}
+
+static void sequencer_tools_region_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_panels(C, ar);
+}
/* *********************** preview region ************************ */
static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *ar)
{
@@ -832,7 +857,7 @@ void ED_spacetype_sequencer(void)
art->draw = sequencer_main_region_draw;
art->listener = sequencer_main_region_listener;
art->message_subscribe = sequencer_main_region_message_subscribe;
- art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
+ art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
BLI_addhead(&st->regiontypes, art);
@@ -842,7 +867,8 @@ void ED_spacetype_sequencer(void)
art->init = sequencer_preview_region_init;
art->draw = sequencer_preview_region_draw;
art->listener = sequencer_preview_region_listener;
- art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
+ art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES |
+ ED_KEYMAP_GPENCIL;
BLI_addhead(&st->regiontypes, art);
/* regions: listview/buttons */
@@ -850,12 +876,35 @@ void ED_spacetype_sequencer(void)
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH * 1.3f;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
+ art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_ui;
art->listener = sequencer_buttons_region_listener;
art->init = sequencer_buttons_region_init;
art->draw = sequencer_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
sequencer_buttons_register(art);
+ /* regions: tool(bar) */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tools region");
+ art->regionid = RGN_TYPE_TOOLS;
+ art->prefsizex = 58; /* XXX */
+ art->prefsizey = 50; /* XXX */
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
+ art->message_subscribe = ED_region_generic_tools_region_message_subscribe;
+ art->snap_size = ED_region_generic_tools_region_snap_size;
+ art->init = sequencer_tools_region_init;
+ art->draw = sequencer_tools_region_draw;
+ BLI_addhead(&st->regiontypes, art);
+
+ /* regions: tool header */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tool header region");
+ art->regionid = RGN_TYPE_TOOL_HEADER;
+ art->prefsizey = HEADERY;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
+ art->listener = sequencer_main_region_listener;
+ art->init = sequencer_header_region_init;
+ art->draw = sequencer_header_region_draw;
+ art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header;
+ BLI_addhead(&st->regiontypes, art);
/* regions: header */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
@@ -869,6 +918,10 @@ void ED_spacetype_sequencer(void)
BLI_addhead(&st->regiontypes, art);
+ /* regions: hud */
+ art = ED_area_type_hud(st->spaceid);
+ BLI_addhead(&st->regiontypes, art);
+
BKE_spacetype_register(st);
/* set the sequencer callback when not in background mode */
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
index 63f27b4d74a..69060daa171 100644
--- a/source/blender/editors/space_statusbar/space_statusbar.c
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -81,7 +81,7 @@ static SpaceLink *statusbar_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
static void statusbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
{
- if (ELEM(region->alignment, RGN_ALIGN_RIGHT)) {
+ if (ELEM(RGN_ALIGN_ENUM_FROM_MASK(region->alignment), RGN_ALIGN_RIGHT)) {
region->flag |= RGN_FLAG_DYNAMIC_SIZE;
}
ED_region_header_init(region);
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index 725a49e417e..d62fcf45d68 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -103,7 +103,7 @@ static void topbar_main_region_init(wmWindowManager *wm, ARegion *region)
wmKeyMap *keymap;
/* force delayed UI_view2d_region_reinit call */
- if (ELEM(region->alignment, RGN_ALIGN_RIGHT)) {
+ if (ELEM(RGN_ALIGN_ENUM_FROM_MASK(region->alignment), RGN_ALIGN_RIGHT)) {
region->flag |= RGN_FLAG_DYNAMIC_SIZE;
}
UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_HEADER, region->winx, region->winy);
@@ -123,7 +123,7 @@ static void topbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
/* add handlers, stuff you only do once or on area/region changes */
static void topbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
- if ((ar->alignment & ~RGN_SPLIT_PREV) == RGN_ALIGN_RIGHT) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_RIGHT) {
ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
}
ED_region_header_init(ar);
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index a4714249da2..83fb87264e3 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -158,6 +158,12 @@ typedef struct ViewOpsData {
float trackvec[3];
/** Dolly only. */
float mousevec[3];
+
+ /**
+ * #RegionView3D.persp set after auto-perspective is applied.
+ * If we want the value before running the operator, add a separate member.
+ */
+ char persp;
} init;
/** Previous state (previous modal event handled). */
@@ -413,6 +419,7 @@ static void viewops_data_create(bContext *C,
* we may want to make this optional but for now its needed always */
ED_view3d_camera_lock_init(depsgraph, vod->v3d, vod->rv3d);
+ vod->init.persp = rv3d->persp;
vod->init.dist = rv3d->dist;
vod->init.camzoom = rv3d->camzoom;
copy_qt_qt(vod->init.quat, rv3d->viewquat);
@@ -613,6 +620,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
float zaxis_best[3];
int x, y, z;
bool found = false;
+ bool is_axis_aligned = false;
invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat);
@@ -630,6 +638,10 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
if (angle_normalized_v3v3(zaxis_test, zaxis) < axis_limit) {
copy_v3_v3(zaxis_best, zaxis_test);
found = true;
+
+ if (abs(x) + abs(y) + abs(z) == 1) {
+ is_axis_aligned = true;
+ }
}
}
}
@@ -700,6 +712,17 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
copy_qt_qt(rv3d->viewquat, quat_best);
viewrotate_apply_dyn_ofs(vod, rv3d->viewquat);
+
+ if (U.uiflag & USER_AUTOPERSP) {
+ if (is_axis_aligned) {
+ if (rv3d->persp == RV3D_PERSP) {
+ rv3d->persp = RV3D_ORTHO;
+ }
+ }
+ }
+ }
+ else if (U.uiflag & USER_AUTOPERSP) {
+ rv3d->persp = vod->init.persp;
}
}
@@ -859,6 +882,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
event_code = VIEW_APPLY;
break;
case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
+ vod->rv3d->persp = vod->init.persp;
vod->axis_snap = false;
event_code = VIEW_APPLY;
break;
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 494e7529975..34470896fb9 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -676,7 +676,7 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
return;
}
- if ((walk->is_cursor_absolute == false) && event->is_motion_absolute) {
+ if ((walk->is_cursor_absolute == false) && event->tablet.is_motion_absolute) {
walk->is_cursor_absolute = true;
copy_v2_v2_int(walk->prev_mval, event->mval);
copy_v2_v2_int(walk->center_mval, event->mval);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 9a98a2b8a00..62a61a3a05a 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -856,7 +856,7 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
if (t->spacetype != SPACE_VIEW3D) {
return false;
}
- else if (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) {
+ else if ((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) == 0) {
return false;
}
else if (!validSnap(t)) {
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index b2d8671fbce..09992e8be0e 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -720,7 +720,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
ot->poll = ED_operator_screenactive;
ot->poll_property = transform_poll_property;
- RNA_def_float_vector_xyz(
+ RNA_def_float_translation(
ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Move", "", -FLT_MAX, FLT_MAX);
WM_operatortype_props_advanced_begin(ot);
diff --git a/source/blender/freestyle/intern/application/AppConfig.cpp b/source/blender/freestyle/intern/application/AppConfig.cpp
index 3e3a939a8fe..a2f0a3395af 100644
--- a/source/blender/freestyle/intern/application/AppConfig.cpp
+++ b/source/blender/freestyle/intern/application/AppConfig.cpp
@@ -53,10 +53,6 @@ void Path::setRootDir(const string &iRootDir)
string(DIR_SEP.c_str());
_BrushesPath = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) +
"textures" + string(DIR_SEP.c_str()) + "brushes" + string(DIR_SEP.c_str());
- _PythonPath = _ProjectDir + string(DIR_SEP.c_str()) + "modules" + string(DIR_SEP.c_str());
- if (getenv("PYTHONPATH")) {
- _PythonPath += string(PATH_SEP.c_str()) + string(getenv("PYTHONPATH"));
- }
_EnvMapDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) +
"env_map" + string(DIR_SEP.c_str());
_MapsDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "maps" +
diff --git a/source/blender/freestyle/intern/application/AppConfig.h b/source/blender/freestyle/intern/application/AppConfig.h
index cc2a3962ecd..9369ed81d50 100644
--- a/source/blender/freestyle/intern/application/AppConfig.h
+++ b/source/blender/freestyle/intern/application/AppConfig.h
@@ -43,7 +43,6 @@ class Path {
string _ModelsPath;
string _PatternsPath;
string _BrushesPath;
- string _PythonPath;
string _EnvMapDir;
string _MapsDir;
string _HomeDir;
@@ -72,10 +71,6 @@ class Path {
{
return _BrushesPath;
}
- const string &getPythonPath() const
- {
- return _PythonPath;
- }
const string &getEnvMapDir() const
{
return _EnvMapDir;
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index a8e8ca72023..19c7386ad6d 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -188,7 +188,6 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint bu
GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode);
GPUTexture *GPU_texture_from_blender(struct Image *ima, struct ImageUser *iuser, int textarget);
-GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
/* movie clip drawing */
GPUTexture *GPU_texture_from_movieclip(struct MovieClip *clip,
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 2c74afd2d8e..bf7b1908321 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -116,7 +116,7 @@ void gpu_pbvh_init()
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);
+ &g_vbo_id.format, "ac", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
}
@@ -240,8 +240,13 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
for (int j = 0; j < 3; j++) {
const int loop_index = lt->tri[j];
const int vidx = face_vert_indices[i][j];
- const uchar *elem = &vcol[loop_index].r;
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, elem);
+ const MLoopCol *mcol = &vcol[loop_index];
+ ushort scol[4];
+ scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
+ scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
+ scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
+ scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, scol);
}
}
}
@@ -289,8 +294,13 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
if (show_vcol) {
const uint loop_index = lt->tri[j];
- const uchar *elem = &vcol[loop_index].r;
- memcpy(GPU_vertbuf_raw_step(&col_step), elem, sizeof(uchar) * 4);
+ const MLoopCol *mcol = &vcol[loop_index];
+ ushort scol[4];
+ scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
+ scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
+ scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
+ scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
+ memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
}
}
}
@@ -654,7 +664,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
}
if (show_vcol) {
- char vcol[4] = {255, 255, 255, 255};
+ ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol);
}
@@ -705,7 +715,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
empty_mask = empty_mask && (fmask == 0.0f);
}
- char vcol[4] = {255, 255, 255, 255};
+ ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 0, &vcol);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 1, &vcol);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol);
@@ -781,7 +791,7 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
}
if (show_vcol) {
- static char vcol[4] = {255, 255, 255, 255};
+ ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol);
}
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 5a5c3ace552..a7dd34a5f96 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -1042,12 +1042,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
input->attr_id,
attr_prefix_get(input->attr_type),
attr_safe_name);
- /* Auto attribute can be vertex color byte buffer.
- * We need to know and convert them to linear space in VS. */
- if (input->attr_type == CD_AUTO_FROM_NAME) {
- BLI_dynstr_appendf(ds, "uniform bool ba%s;\n", attr_safe_name);
- BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%s\n", input->attr_id, attr_safe_name);
- }
}
BLI_dynstr_appendf(ds,
"out %s var%d%s;\n",
@@ -1101,24 +1095,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
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"
- "\tc = max(c, vec3(0.0));\n"
- "\tvec3 c1 = c * (1.0 / 12.92);\n"
- "\tvec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));\n"
- "\treturn mix(c1, c2, step(vec3(0.04045), c));\n"
- "}\n\n");
-
- BLI_dynstr_append(ds,
- "vec4 srgba_to_linear_attr(vec4 c) {\n"
- "\tc = max(c, vec4(0.0));\n"
- "\tvec4 c1 = c * (1.0 / 12.92);\n"
- "\tvec4 c2 = pow((c + 0.055) * (1.0 / 1.055), vec4(2.4));\n"
- "\tvec4 final = mix(c1, c2, step(vec4(0.04045), c));"
- "\treturn vec4(final.xyz, c.a);\n"
- "}\n\n");
-
/* Prototype because defined later. */
BLI_dynstr_append(ds,
"vec2 hair_get_customdata_vec2(const samplerBuffer);\n"
@@ -1224,22 +1200,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
input->attr_id,
use_geom ? "g" : "");
}
- else if (input->attr_type == CD_MCOL) {
- BLI_dynstr_appendf(ds,
- "\tvar%d%s = srgba_to_linear_attr(att%d);\n",
- input->attr_id,
- use_geom ? "g" : "",
- input->attr_id);
- }
- else if (input->attr_type == CD_AUTO_FROM_NAME) {
- BLI_dynstr_appendf(ds,
- "\tvar%d%s = (att%d_is_srgb) ? srgb_to_linear_attr(att%d) : att%d;\n",
- input->attr_id,
- use_geom ? "g" : "",
- input->attr_id,
- input->attr_id,
- input->attr_id);
- }
else {
BLI_dynstr_appendf(
ds, "\tvar%d%s = att%d;\n", input->attr_id, use_geom ? "g" : "", input->attr_id);
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 201194232db..84328b8dfd4 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -1064,56 +1064,6 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode)
return tex;
}
-GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
-{
- GPUTexture *tex = prv->gputexture[0];
- GLuint bindcode = 0;
-
- if (tex) {
- bindcode = tex->bindcode;
- }
-
- /* this binds a texture, so that's why we restore it to 0 */
- if (bindcode == 0) {
- GPU_create_gl_tex(
- &bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, false, NULL);
- }
- if (tex) {
- tex->bindcode = bindcode;
- glBindTexture(GL_TEXTURE_2D, 0);
- return tex;
- }
-
- tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->bindcode = bindcode;
- tex->number = -1;
- tex->refcount = 1;
- tex->target = GL_TEXTURE_2D;
- tex->target_base = GL_TEXTURE_2D;
- tex->format = -1;
- tex->components = -1;
-
- prv->gputexture[0] = tex;
-
- if (!glIsTexture(tex->bindcode)) {
- GPU_print_error_debug("Blender Texture Not Loaded");
- }
- else {
- GLint w, h;
-
- glBindTexture(GL_TEXTURE_2D, tex->bindcode);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
-
- tex->w = w;
- tex->h = h;
- }
-
- glBindTexture(GL_TEXTURE_2D, 0);
-
- return tex;
-}
-
GPUTexture *GPU_texture_create_1d(int w,
eGPUTextureFormat tex_format,
const float *pixels,
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 354344328d3..7192b1295aa 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -252,7 +252,8 @@ typedef enum eBone_Flag {
BONE_ADD_PARENT_END_ROLL = (1 << 24),
/** this bone was transformed by the mirror function */
BONE_TRANSFORM_MIRROR = (1 << 25),
-
+ /** this bone is associated with a locked vertex group, ONLY USE FOR DRAWING */
+ BONE_DRAW_LOCKED_WEIGHT = (1 << 26),
} eBone_Flag;
/* bone->inherit_scale_mode */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index d3c5a707b44..a52767834a4 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -129,6 +129,12 @@ typedef struct ScrAreaMap {
ListBase areabase;
} ScrAreaMap;
+typedef struct Panel_Runtime {
+ /* Applied to Panel.ofsx, but saved separately so we can track changes between redraws. */
+ int region_ofsx;
+ char _pad[4];
+} Panel_Runtime;
+
/** The part from uiBlock that needs saved in file. */
typedef struct Panel {
struct Panel *next, *prev;
@@ -159,6 +165,8 @@ typedef struct Panel {
void *activedata;
/** Sub panels. */
ListBase children;
+
+ Panel_Runtime runtime;
} Panel;
/**
@@ -409,7 +417,9 @@ typedef struct ARegion {
short flag;
/** Current split size in unscaled pixels (if zero it uses regiontype).
- * To convert to pixels use: `UI_DPI_FAC * ar->sizex + 0.5f`. */
+ * To convert to pixels use: `UI_DPI_FAC * ar->sizex + 0.5f`.
+ * However to get the current region size, you should usually use winx/winy from above, not this!
+ */
short sizex, sizey;
/** Private, cached notifier events. */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index f0a852a7a1a..d81d8db3bd3 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -283,13 +283,12 @@ typedef struct ThemeSpace {
unsigned char normal[4];
unsigned char vertex_normal[4];
unsigned char loop_normal[4];
- unsigned char bone_solid[4], bone_pose[4], bone_pose_active[4];
+ unsigned char bone_solid[4], bone_pose[4], bone_pose_active[4], bone_locked_weight[4];
unsigned char strip[4], strip_select[4];
unsigned char cframe[4];
unsigned char time_keyframe[4], time_gp_keyframe[4];
unsigned char freestyle_edge_mark[4], freestyle_face_mark[4];
unsigned char time_scrub_background[4];
- char _pad5[4];
unsigned char nurb_uline[4], nurb_vline[4];
unsigned char act_spline[4], nurb_sel_uline[4], nurb_sel_vline[4], lastsel_point[4];
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 0beb14614ec..349b30fa64e 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -233,6 +233,16 @@ PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont,
const char *ui_description,
float softmin,
float softmax);
+PropertyRNA *RNA_def_float_translation(StructOrFunctionRNA *cont,
+ const char *identifier,
+ int len,
+ const float *default_value,
+ float hardmin,
+ float hardmax,
+ const char *ui_name,
+ const char *ui_description,
+ float softmin,
+ float softmax);
PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont,
const char *identifier,
int len,
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index d7f6ec1fb5a..c10436ae08e 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -52,6 +52,7 @@ extern const EnumPropertyItem rna_enum_mesh_select_mode_items[];
extern const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[];
extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[];
extern const EnumPropertyItem rna_enum_space_graph_mode_items[];
+extern const EnumPropertyItem rna_enum_space_sequencer_view_type_items[];
extern const EnumPropertyItem rna_enum_space_type_items[];
extern const EnumPropertyItem rna_enum_space_image_mode_items[];
extern const EnumPropertyItem rna_enum_space_image_mode_all_items[];
@@ -141,6 +142,8 @@ extern const EnumPropertyItem rna_enum_texture_type_items[];
extern const EnumPropertyItem rna_enum_light_type_items[];
+extern const EnumPropertyItem rna_enum_lightprobes_type_items[];
+
extern const EnumPropertyItem rna_enum_unpack_method_items[];
extern const EnumPropertyItem rna_enum_object_type_items[];
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 55aa529a30e..73a59cbba11 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -3888,6 +3888,36 @@ PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont_,
return prop;
}
+PropertyRNA *RNA_def_float_translation(StructOrFunctionRNA *cont_,
+ const char *identifier,
+ int len,
+ const float *default_value,
+ float hardmin,
+ float hardmax,
+ const char *ui_name,
+ const char *ui_description,
+ float softmin,
+ float softmax)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_float_vector(cont_,
+ identifier,
+ len,
+ default_value,
+ hardmin,
+ hardmax,
+ ui_name,
+ ui_description,
+ softmin,
+ softmax);
+ prop->subtype = PROP_TRANSLATION;
+
+ RNA_def_property_ui_range(prop, softmin, softmax, 1, RNA_TRANSLATION_PREC_DEFAULT);
+
+ return prop;
+}
+
PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index d85c5c5f249..9df21a16e90 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -250,6 +250,9 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
case ID_AR:
type = OB_ARMATURE;
break;
+ case ID_LP:
+ type = OB_LIGHTPROBE;
+ break;
default: {
const char *idname;
if (RNA_enum_id_from_value(rna_enum_id_type_items, GS(data->name), &idname) == 0) {
@@ -665,12 +668,15 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name
return linestyle;
}
-static LightProbe *rna_Main_lightprobe_new(Main *bmain, const char *name)
+static LightProbe *rna_Main_lightprobe_new(Main *bmain, const char *name, int type)
{
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
LightProbe *probe = BKE_lightprobe_add(bmain, safe_name);
+
+ BKE_lightprobe_type_set(probe, type);
+
id_us_min(&probe->id);
return probe;
}
@@ -2079,6 +2085,9 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a new probe to the main database");
parm = RNA_def_string(func, "name", "Probe", 0, "", "New name for the data-block");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(
+ func, "type", rna_enum_lightprobes_type_items, 0, "Type", "The type of lightprobe to add");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "lightprobe", "LightProbe", "", "New light probe data-block");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 40622894145..182e80900bd 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -25,6 +25,7 @@
#include "DNA_brush_types.h"
#include "DNA_collection_types.h"
#include "DNA_customdata_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_force_types.h"
@@ -196,6 +197,13 @@ const EnumPropertyItem rna_enum_metaelem_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_lightprobes_type_items[] = {
+ {LIGHTPROBE_TYPE_CUBE, "CUBE", ICON_LIGHTPROBE_CUBEMAP, "Cube", ""},
+ {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_LIGHTPROBE_PLANAR, "Planar", ""},
+ {LIGHTPROBE_TYPE_GRID, "GRID", ICON_LIGHTPROBE_GRID, "Grid", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
/* used for 2 enums */
#define OBTYPE_CU_CURVE \
{ \
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 536691b074d..d914dc3b8dd 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -867,7 +867,7 @@ static void rna_PartSettings_start_set(struct PointerRNA *ptr, float value)
/* check for clipping */
if (value > settings->end) {
- value = settings->end;
+ settings->end = value;
}
/*if (settings->type==PART_REACTOR && value < 1.0) */
@@ -886,7 +886,7 @@ static void rna_PartSettings_end_set(struct PointerRNA *ptr, float value)
/* check for clipping */
if (value < settings->sta) {
- value = settings->sta;
+ settings->sta = value;
}
settings->end = value;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index ea1fb1eb489..7d35a1c5e2a 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -941,8 +941,8 @@ static void rna_Scene_start_frame_set(PointerRNA *ptr, int value)
CLAMP(value, MINFRAME, MAXFRAME);
data->r.sfra = value;
- if (data->r.sfra >= data->r.efra) {
- data->r.efra = MIN2(data->r.sfra, MAXFRAME);
+ if (value > data->r.efra) {
+ data->r.efra = MIN2(value, MAXFRAME);
}
}
@@ -952,8 +952,8 @@ static void rna_Scene_end_frame_set(PointerRNA *ptr, int value)
CLAMP(value, MINFRAME, MAXFRAME);
data->r.efra = value;
- if (data->r.sfra >= data->r.efra) {
- data->r.sfra = MAX2(data->r.efra, MINFRAME);
+ if (data->r.sfra > value) {
+ data->r.sfra = MAX2(value, MINFRAME);
}
}
@@ -985,10 +985,12 @@ static void rna_Scene_preview_range_start_frame_set(PointerRNA *ptr, int value)
/* TODO: or just refuse to set instead? */
data->r.pefra = data->r.efra;
}
-
- /* now set normally */
- CLAMP(value, MINAFRAME, data->r.pefra);
+ CLAMP(value, MINAFRAME, MAXFRAME);
data->r.psfra = value;
+
+ if (value > data->r.pefra) {
+ data->r.pefra = MIN2(value, MAXFRAME);
+ }
}
static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value)
@@ -1001,10 +1003,12 @@ static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value)
/* TODO: or just refuse to set instead? */
data->r.psfra = data->r.sfra;
}
-
- /* now set normally */
- CLAMP(value, data->r.psfra, MAXFRAME);
+ CLAMP(value, MINAFRAME, MAXFRAME);
data->r.pefra = value;
+
+ if (data->r.psfra > value) {
+ data->r.psfra = MAX2(value, MINAFRAME);
+ }
}
static void rna_Scene_show_subframe_update(Main *UNUSED(bmain),
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 67b43cb13df..5a671ab146c 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -161,6 +161,13 @@ const EnumPropertyItem rna_enum_space_graph_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_space_sequencer_view_type_items[] = {
+ {SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
+ {SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Preview", ""},
+ {SEQ_VIEW_SEQUENCE_PREVIEW, "SEQUENCER_PREVIEW", ICON_SEQ_SPLITVIEW, "Sequencer/Preview", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#define SACT_ITEM_DOPESHEET \
{ \
SACTCONT_DOPESHEET, "DOPESHEET", ICON_ACTION, "Dope Sheet", "Edit all keyframes in scene" \
@@ -2640,7 +2647,9 @@ static void rna_def_space(BlenderRNA *brna)
/* access to V2D_VIEWSYNC_SCREEN_TIME */
prop = RNA_def_property(srna, "show_locked_time", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Space_view2d_sync_get", "rna_Space_view2d_sync_set");
- RNA_def_property_ui_text(prop, "Lock Time to Other Windows", "");
+ RNA_def_property_ui_text(prop,
+ "Sync Visible Range",
+ "Syncronize the visible timeline range with other time-based editors");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, "rna_Space_view2d_sync_update");
rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_HEADER));
@@ -4458,17 +4467,6 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem view_type_items[] = {
- {SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
- {SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Preview", ""},
- {SEQ_VIEW_SEQUENCE_PREVIEW,
- "SEQUENCER_PREVIEW",
- ICON_SEQ_SPLITVIEW,
- "Sequencer/Preview",
- ""},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem display_mode_items[] = {
{SEQ_DRAW_IMG_IMBUF, "IMAGE", ICON_SEQ_PREVIEW, "Image Preview", ""},
{SEQ_DRAW_IMG_WAVEFORM, "WAVEFORM", ICON_SEQ_LUMA_WAVEFORM, "Luma Waveform", ""},
@@ -4528,12 +4526,13 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SpaceSeq");
RNA_def_struct_ui_text(srna, "Space Sequence Editor", "Sequence editor space data");
- rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_UI));
+ rna_def_space_generic_show_region_toggles(
+ srna, (1 << RGN_TYPE_TOOL_HEADER) | (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_TOOLS));
/* view type, fairly important */
prop = RNA_def_property(srna, "view_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "view");
- RNA_def_property_enum_items(prop, view_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_sequencer_view_type_items);
RNA_def_property_ui_text(
prop, "View Type", "Type of the Sequencer view (sequencer, preview or both)");
RNA_def_property_update(prop, 0, "rna_Sequencer_view_type_update");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 56f19d313fd..fc2b074d6d1 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2231,6 +2231,14 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Bone Solid", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "bone_locked_weight", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(
+ prop,
+ "Bone Locked Weight",
+ "Shade for bones corresponding to a locked weight group during painting");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
/* misc */
prop = RNA_def_property(srna, "bundle_solid", PROP_FLOAT, PROP_COLOR_GAMMA);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 249581d22bf..532992baa5c 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -2185,7 +2185,7 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Is Tablet", "The event has tablet data");
prop = RNA_def_property(srna, "is_mouse_absolute", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "is_motion_absolute", 1);
+ RNA_def_property_boolean_sdna(prop, NULL, "tablet.is_motion_absolute", 1);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Absolute Motion", "The last motion event was an absolute input");
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
index 4d4ab64abb9..32e348ea72f 100644
--- a/source/blender/makesrna/intern/rna_workspace.c
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -152,7 +152,17 @@ static bToolRef *rna_WorkSpace_tools_from_space_node(WorkSpace *workspace, bool
},
create);
}
-
+static bToolRef *rna_WorkSpace_tools_from_space_sequencer(WorkSpace *workspace,
+ int mode,
+ bool create)
+{
+ return rna_WorkSpace_tools_from_tkey(workspace,
+ &(bToolKey){
+ .space_type = SPACE_SEQ,
+ .mode = mode,
+ },
+ create);
+}
const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf(bContext *UNUSED(C),
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
@@ -164,6 +174,8 @@ const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf(bContext *UNUSED(C),
return rna_enum_context_mode_items;
case SPACE_IMAGE:
return rna_enum_space_image_mode_all_items;
+ case SPACE_SEQ:
+ return rna_enum_space_sequencer_view_type_items;
}
return DummyRNA_DEFAULT_items;
}
@@ -335,6 +347,16 @@ static void rna_def_workspace_tools(BlenderRNA *brna, PropertyRNA *cprop)
/* return type */
parm = RNA_def_pointer(func, "result", "WorkSpaceTool", "", "");
RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(
+ srna, "from_space_sequencer", "rna_WorkSpace_tools_from_space_sequencer");
+ RNA_def_function_ui_description(func, "");
+ parm = RNA_def_enum(func, "mode", rna_enum_space_sequencer_view_type_items, 0, "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "create", false, "Create", "");
+ /* return type */
+ parm = RNA_def_pointer(func, "result", "WorkSpaceTool", "", "");
+ RNA_def_function_return(func, parm);
}
static void rna_def_workspace(BlenderRNA *brna)
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 999cefde104..94eaffd1f91 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -83,7 +83,7 @@ static float cloth_calc_volume(ClothModifierData *clmd)
float vol = 0;
if (clmd->sim_parms->vgroup_pressure > 0) {
- for (unsigned int i = 0; i < cloth->tri_num; i++) {
+ for (unsigned int i = 0; i < cloth->primitive_num; i++) {
bool skip_face = false;
/* We have custom vertex weights for pressure. */
const MVertTri *vt = &tri[i];
@@ -103,7 +103,7 @@ static float cloth_calc_volume(ClothModifierData *clmd)
}
}
else {
- for (unsigned int i = 0; i < cloth->tri_num; i++) {
+ for (unsigned int i = 0; i < cloth->primitive_num; i++) {
const MVertTri *vt = &tri[i];
vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]);
}
@@ -174,96 +174,17 @@ void BKE_cloth_solver_set_volume(ClothModifierData *clmd)
cloth->initial_mesh_volume = cloth_calc_volume(clmd);
}
-static bool collision_response(ClothModifierData *clmd,
- CollisionModifierData *collmd,
- CollPair *collpair,
- float dt,
- float restitution,
- float r_impulse[3])
-{
- Cloth *cloth = clmd->clothObject;
- int index = collpair->ap1;
- bool result = false;
-
- float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
- float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
-
- float margin_distance = (float)collpair->distance - epsilon2;
- float mag_v_rel;
-
- zero_v3(r_impulse);
-
- if (margin_distance > 0.0f) {
- return false; /* XXX tested before already? */
- }
-
- /* only handle static collisions here */
- if (collpair->flag & COLLISION_IN_FUTURE) {
- return false;
- }
-
- /* velocity */
- copy_v3_v3(v1, cloth->verts[index].v);
- collision_get_collider_velocity(v2_old, v2_new, collmd, collpair);
- /* relative velocity = velocity of the cloth point relative to the collider */
- sub_v3_v3v3(v_rel_old, v1, v2_old);
- sub_v3_v3v3(v_rel_new, v1, v2_new);
- /* normal component of the relative velocity */
- mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
-
- /* only valid when moving toward the collider */
- if (mag_v_rel < -ALMOST_ZERO) {
- float v_nor_old, v_nor_new;
- float v_tan_old[3], v_tan_new[3];
- float bounce, repulse;
-
- /* Collision response based on
- * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
- * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
- */
-
- v_nor_old = mag_v_rel;
- v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
-
- madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
- madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
-
- bounce = -v_nor_old * restitution;
-
- repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */
- /* XXX this clamping factor is quite arbitrary ...
- * not sure if there is a more scientific approach, but seems to give good results
- */
- CLAMP(repulse, 0.0f, 4.0f * bounce);
-
- if (margin_distance < -epsilon2) {
- mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new);
- }
- else {
- bounce = 0.0f;
- mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new);
- }
-
- result = true;
- }
-
- return result;
-}
-
/* Init constraint matrix
* This is part of the modified CG method suggested by Baraff/Witkin in
* "Large Steps in Cloth Simulation" (Siggraph 1998)
*/
-static void cloth_setup_constraints(ClothModifierData *clmd,
- ColliderContacts *contacts,
- int totcolliders,
- float dt)
+static void cloth_setup_constraints(ClothModifierData *clmd)
{
Cloth *cloth = clmd->clothObject;
Implicit_Data *data = cloth->implicit;
ClothVertex *verts = cloth->verts;
int mvert_num = cloth->mvert_num;
- int i, j, v;
+ int v;
const float ZERO[3] = {0.0f, 0.0f, 0.0f};
@@ -277,37 +198,6 @@ static void cloth_setup_constraints(ClothModifierData *clmd,
verts[v].impulse_count = 0;
}
-
- for (i = 0; i < totcolliders; i++) {
- ColliderContacts *ct = &contacts[i];
- for (j = 0; j < ct->totcollisions; j++) {
- CollPair *collpair = &ct->collisions[j];
- // float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
- float restitution = 0.0f;
- int v = collpair->face1;
- float impulse[3];
-
- /* pinned verts handled separately */
- if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) {
- continue;
- }
-
- /* XXX cheap way of avoiding instability from multiple collisions in the same step
- * this should eventually be supported ...
- */
- if (verts[v].impulse_count > 0) {
- continue;
- }
-
- /* calculate collision response */
- if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse)) {
- continue;
- }
-
- BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse);
- ++verts[v].impulse_count;
- }
- }
}
/* computes where the cloth would be if it were subject to perfectly stiff edges
@@ -691,7 +581,7 @@ static void cloth_calc_force(
pressure_difference *= clmd->sim_parms->pressure_factor;
- for (i = 0; i < cloth->tri_num; i++) {
+ for (i = 0; i < cloth->primitive_num; i++) {
const MVertTri *vt = &tri[i];
if (fabs(pressure_difference) > 1E-6f) {
if (clmd->sim_parms->vgroup_pressure > 0) {
@@ -744,13 +634,13 @@ static void cloth_calc_force(
effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
}
- for (i = 0; i < cloth->tri_num; i++) {
+ for (i = 0; i < cloth->primitive_num; i++) {
const MVertTri *vt = &tri[i];
BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec);
}
/* Hair has only edges */
- if (cloth->tri_num == 0) {
+ if (cloth->primitive_num == 0) {
#if 0
ClothHairData *hairdata = clmd->hairdata;
ClothHairData *hair_ij, *hair_kl;
@@ -1241,8 +1131,6 @@ int BPH_cloth_solve(
unsigned int mvert_num = cloth->mvert_num;
float dt = clmd->sim_parms->dt * clmd->sim_parms->timescale;
Implicit_Data *id = cloth->implicit;
- ColliderContacts *contacts = NULL;
- int totcolliders = 0;
BKE_sim_debug_data_clear_category("collision");
@@ -1269,25 +1157,8 @@ int BPH_cloth_solve(
while (step < tf) {
ImplicitSolverResult result;
- if (is_hair) {
- /* copy velocities for collision */
- for (i = 0; i < mvert_num; i++) {
- BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
- copy_v3_v3(verts[i].v, verts[i].tv);
- }
-
- /* determine contact points */
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
- cloth_find_point_contacts(depsgraph, ob, clmd, 0.0f, tf, &contacts, &totcolliders);
- }
-
- /* setup vertex constraints for pinned vertices and contacts */
- cloth_setup_constraints(clmd, contacts, totcolliders, dt);
- }
- else {
- /* setup vertex constraints for pinned vertices */
- cloth_setup_constraints(clmd, NULL, 0, dt);
- }
+ /* setup vertex constraints for pinned vertices */
+ cloth_setup_constraints(clmd);
/* initialize forces to zero */
BPH_mass_spring_clear_forces(id);
@@ -1300,9 +1171,7 @@ int BPH_cloth_solve(
cloth_record_result(clmd, &result, dt);
/* Calculate collision impulses. */
- if (!is_hair) {
- cloth_solve_collisions(depsgraph, ob, clmd, step, dt);
- }
+ cloth_solve_collisions(depsgraph, ob, clmd, step, dt);
if (is_hair) {
cloth_continuum_step(clmd, dt);
@@ -1327,11 +1196,6 @@ int BPH_cloth_solve(
BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL);
}
- /* free contact points */
- if (contacts) {
- cloth_free_contacts(contacts, totcolliders);
- }
-
step += dt;
}
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 73fbde4148e..e7a4ca9a005 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SRC
intern/wm_cursors.c
intern/wm_dragdrop.c
intern/wm_draw.c
+ intern/wm_event_query.c
intern/wm_event_system.c
intern/wm_files.c
intern/wm_files_link.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index d24157a22a6..cfdb15026fd 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -205,11 +205,6 @@ void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *ar);
void WM_cursor_warp(struct wmWindow *win, int x, int y);
void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y);
-float WM_cursor_pressure(const struct wmWindow *win);
-
-/* event map */
-int WM_userdef_event_map(int kmitype);
-int WM_userdef_event_type_from_keymap_type(int kmitype);
/* handlers */
@@ -250,6 +245,11 @@ wmKeyMapItem *WM_event_match_keymap_item(struct bContext *C,
wmKeyMap *keymap,
const struct wmEvent *event);
+wmKeyMapItem *WM_event_match_keymap_item_from_handlers(struct bContext *C,
+ struct wmWindowManager *wm,
+ struct ListBase *handlers,
+ const struct wmEvent *event);
+
typedef int (*wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata);
typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata);
@@ -294,8 +294,6 @@ struct wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers,
/* mouse */
void WM_event_add_mousemove(const struct bContext *C);
-bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
-bool WM_event_is_last_mousemove(const struct wmEvent *event);
#ifdef WITH_INPUT_NDOF
/* 3D mouse */
@@ -631,15 +629,9 @@ bool WM_gesture_is_modal_first(const struct wmGesture *gesture);
/* fileselecting support */
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval);
-int WM_event_modifier_flag(const struct wmEvent *event);
-void WM_event_print(const struct wmEvent *event);
void WM_operator_region_active_win_set(struct bContext *C);
-int WM_event_drag_threshold(const struct wmEvent *event);
-bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]);
-bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]);
-
/* drag and drop */
struct wmDrag *WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags);
@@ -783,6 +775,36 @@ bool write_crash_blend(void);
/* Lock the interface for any communication */
void WM_set_locked_interface(struct wmWindowManager *wm, bool lock);
+/* For testing only 'G_FLAG_EVENT_SIMULATE' */
+struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add);
+
+const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
+ int button_index,
+ int type_index);
+void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win);
+
+void WM_window_status_area_tag_redraw(struct wmWindow *win);
+struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *sc);
+bool WM_window_modal_keymap_status_draw(struct bContext *C,
+ struct wmWindow *win,
+ struct uiLayout *layout);
+
+/* wm_event_query.c */
+void WM_event_print(const struct wmEvent *event);
+
+int WM_event_modifier_flag(const struct wmEvent *event);
+
+bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
+bool WM_event_is_last_mousemove(const struct wmEvent *event);
+
+int WM_event_drag_threshold(const struct wmEvent *event);
+bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]);
+bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]);
+
+/* event map */
+int WM_userdef_event_map(int kmitype);
+int WM_userdef_event_type_from_keymap_type(int kmitype);
+
#ifdef WITH_INPUT_NDOF
void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof,
float r_pan[3],
@@ -800,20 +822,6 @@ bool WM_event_is_tablet(const struct wmEvent *event);
bool WM_event_is_ime_switch(const struct wmEvent *event);
#endif
-/* For testing only 'G_FLAG_EVENT_SIMULATE' */
-struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add);
-
-const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
- int button_index,
- int type_index);
-void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win);
-
-void WM_window_status_area_tag_redraw(struct wmWindow *win);
-struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *sc);
-bool WM_window_modal_keymap_status_draw(struct bContext *C,
- struct wmWindow *win,
- struct uiLayout *layout);
-
/* wm_tooltip.c */
typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C,
struct ARegion *ar,
diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h
index 620150ba14f..36cb5be7547 100644
--- a/source/blender/windowmanager/WM_toolsystem.h
+++ b/source/blender/windowmanager/WM_toolsystem.h
@@ -41,8 +41,8 @@ struct wmOperatorType;
/* wm_toolsystem.c */
-#define WM_TOOLSYSTEM_SPACE_MASK ((1 << SPACE_IMAGE) | (1 << SPACE_NODE) | (1 << SPACE_VIEW3D))
-
+#define WM_TOOLSYSTEM_SPACE_MASK \
+ ((1 << SPACE_IMAGE) | (1 << SPACE_NODE) | (1 << SPACE_VIEW3D) | (1 << SPACE_SEQ))
/* Values that define a categoey of active tool. */
typedef struct bToolKey {
int space_type;
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 0c3a5f92113..5870802d02b 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -505,6 +505,19 @@ typedef struct wmGesture {
/* ************** wmEvent ************************ */
+typedef struct wmTabletData {
+ /** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */
+ int active;
+ /** range 0.0 (not touching) to 1.0 (full pressure). */
+ float pressure;
+ /** range 0.0 (upright) to 1.0 (tilted fully against the tablet surface). */
+ float x_tilt;
+ /** as above. */
+ float y_tilt;
+ /** Interpret mouse motion as absolute as typical for tablets. */
+ char is_motion_absolute;
+} wmTabletData;
+
/**
* Each event should have full modifier state.
* event comes from event manager and from keymap.
@@ -546,13 +559,9 @@ typedef struct wmEvent {
/** Set in case a #KM_PRESS went by unhandled. */
char check_click;
char check_drag;
- char is_motion_absolute;
- /** Keymap item, set by handler (weak?). */
- const char *keymap_idname;
-
- /** Tablet info, only use when the tablet is active. */
- const struct wmTabletData *tablet_data;
+ /** Tablet info, available for mouse move and button events. */
+ wmTabletData tablet;
/* custom data */
/** Custom data type, stylus, 6dof, see wm_event_types.h */
@@ -580,18 +589,6 @@ bool WM_event_cursor_click_drag_threshold_met(const wmEvent *event);
*/
#define WM_EVENT_CURSOR_MOTION_THRESHOLD ((float)U.move_threshold * U.dpi_fac)
-/* ************** custom wmEvent data ************** */
-typedef struct wmTabletData {
- /** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */
- int Active;
- /** range 0.0 (not touching) to 1.0 (full pressure). */
- float Pressure;
- /** range 0.0 (upright) to 1.0 (tilted fully against the tablet surface). */
- float Xtilt;
- /** as above. */
- float Ytilt;
-} wmTabletData;
-
/** Motion progress, for modal handlers. */
typedef enum {
P_NOT_STARTED,
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 59975080f49..383ca806d35 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -1088,7 +1088,7 @@ void wm_gizmomap_modal_set(
gz->state |= WM_GIZMO_STATE_MODAL;
gzmap->gzmap_context.modal = gz;
- if ((gz->flag & WM_GIZMO_MOVE_CURSOR) && (event->is_motion_absolute == false)) {
+ if ((gz->flag & WM_GIZMO_MOVE_CURSOR) && (event->tablet.is_motion_absolute == false)) {
WM_cursor_grab_enable(win, WM_CURSOR_WRAP_XY, true, NULL);
copy_v2_v2_int(gzmap->gzmap_context.event_xy, &event->x);
gzmap->gzmap_context.event_grabcursor = win->grabcursor;
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 8e796a7981a..b82865a727d 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -304,8 +304,7 @@ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
if ((G.debug & G_DEBUG) == 0) {
if (win->ghostwin) {
- /* Note: There is no tabletdata on Windows if no tablet device is connected. */
- if (win->eventstate->is_motion_absolute == false) {
+ if (win->eventstate->tablet.is_motion_absolute == false) {
GHOST_SetCursorGrab(win->ghostwin, mode, mode_axis, bounds, NULL);
}
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 09b7d89fc2b..a26a728461d 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -514,12 +514,12 @@ void wm_draw_region_blend(ARegion *ar, int view, bool blend)
/* Slide vertical panels */
float ofs_x = BLI_rcti_size_x(&ar->winrct) * (1.0f - alpha_easing);
- if (ar->alignment == RGN_ALIGN_RIGHT) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_RIGHT) {
rect_geo.xmin += ofs_x;
rect_tex.xmax *= alpha_easing;
alpha = 1.0f;
}
- else if (ar->alignment == RGN_ALIGN_LEFT) {
+ else if (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_LEFT) {
rect_geo.xmax -= ofs_x;
rect_tex.xmin += 1.0f - alpha_easing;
alpha = 1.0f;
@@ -581,7 +581,14 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
/* Compute UI layouts for dynamically size regions. */
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->visible && ar->do_draw && ar->type && ar->type->layout) {
+ /* Dynamic region may have been flagged as too small because their size on init is 0.
+ * ARegion.visible is false then, as expected. The layout should still be created then, so
+ * the region size can be updated (it may turn out to be not too small then). */
+ const bool ignore_visibility = (ar->flag & RGN_FLAG_DYNAMIC_SIZE) &&
+ (ar->flag & RGN_FLAG_TOO_SMALL) &&
+ !(ar->flag & RGN_FLAG_HIDDEN);
+
+ if ((ar->visible || ignore_visibility) && ar->do_draw && ar->type && ar->type->layout) {
CTX_wm_region_set(C, ar);
ED_region_do_layout(C, ar);
CTX_wm_region_set(C, NULL);
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
new file mode 100644
index 00000000000..3cec185fd36
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -0,0 +1,427 @@
+/*
+ * 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) 2007 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup wm
+ *
+ * Read-only queries utility functions for the event system.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "DNA_listBase.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_event_system.h"
+#include "wm_event_types.h"
+
+#include "RNA_enum_types.h"
+
+#include "DEG_depsgraph.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Event Printing
+ * \{ */
+
+/* for debugging only, getting inspecting events manually is tedious */
+void WM_event_print(const wmEvent *event)
+{
+ if (event) {
+ const char *unknown = "UNKNOWN";
+ const char *type_id = unknown;
+ const char *val_id = unknown;
+
+ RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id);
+ RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id);
+
+ printf(
+ "wmEvent type:%d / %s, val:%d / %s,\n"
+ " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n"
+ " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n",
+ event->type,
+ type_id,
+ event->val,
+ val_id,
+ event->shift,
+ event->ctrl,
+ event->alt,
+ event->oskey,
+ event->keymodifier,
+ event->x,
+ event->y,
+ event->ascii,
+ BLI_str_utf8_size(event->utf8_buf),
+ event->utf8_buf,
+ (const void *)event);
+
+#ifdef WITH_INPUT_NDOF
+ if (ISNDOF(event->type)) {
+ const wmNDOFMotionData *ndof = event->customdata;
+ if (event->type == NDOF_MOTION) {
+ printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n",
+ UNPACK3(ndof->rvec),
+ UNPACK3(ndof->tvec),
+ ndof->dt,
+ ndof->progress);
+ }
+ else {
+ /* ndof buttons printed already */
+ }
+ }
+#endif /* WITH_INPUT_NDOF */
+
+ if (event->tablet.active != EVT_TABLET_NONE) {
+ const wmTabletData *wmtab = &event->tablet;
+ printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n",
+ wmtab->active,
+ wmtab->pressure,
+ wmtab->x_tilt,
+ wmtab->y_tilt);
+ }
+ }
+ else {
+ printf("wmEvent - NULL\n");
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Modifier/Type Queries
+ * \{ */
+
+int WM_event_modifier_flag(const wmEvent *event)
+{
+ int flag = 0;
+ if (event->ctrl) {
+ flag |= KM_CTRL;
+ }
+ if (event->alt) {
+ flag |= KM_ALT;
+ }
+ if (event->shift) {
+ flag |= KM_SHIFT;
+ }
+ if (event->oskey) {
+ flag |= KM_OSKEY;
+ }
+ return flag;
+}
+
+bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask)
+{
+ /* Keyboard. */
+ if (mask & EVT_TYPE_MASK_KEYBOARD) {
+ if (ISKEYBOARD(event_type)) {
+ return true;
+ }
+ }
+ else if (mask & EVT_TYPE_MASK_KEYBOARD_MODIFIER) {
+ if (ISKEYMODIFIER(event_type)) {
+ return true;
+ }
+ }
+
+ /* Mouse. */
+ if (mask & EVT_TYPE_MASK_MOUSE) {
+ if (ISMOUSE(event_type)) {
+ return true;
+ }
+ }
+ else if (mask & EVT_TYPE_MASK_MOUSE_WHEEL) {
+ if (ISMOUSE_WHEEL(event_type)) {
+ return true;
+ }
+ }
+ else if (mask & EVT_TYPE_MASK_MOUSE_GESTURE) {
+ if (ISMOUSE_GESTURE(event_type)) {
+ return true;
+ }
+ }
+
+ /* Tweak. */
+ if (mask & EVT_TYPE_MASK_TWEAK) {
+ if (ISTWEAK(event_type)) {
+ return true;
+ }
+ }
+
+ /* Action Zone. */
+ if (mask & EVT_TYPE_MASK_ACTIONZONE) {
+ if (IS_EVENT_ACTIONZONE(event_type)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Motion Queries
+ * \{ */
+
+/* for modal callbacks, check configuration for how to interpret exit with tweaks */
+bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
+{
+ /* if the release-confirm userpref setting is enabled,
+ * tweak events can be canceled when mouse is released
+ */
+ if (U.flag & USER_RELEASECONFIRM) {
+ /* option on, so can exit with km-release */
+ if (event->val == KM_RELEASE) {
+ switch (tweak_event) {
+ case EVT_TWEAK_L:
+ case EVT_TWEAK_M:
+ case EVT_TWEAK_R:
+ return 1;
+ }
+ }
+ else {
+ /* if the initial event wasn't a tweak event then
+ * ignore USER_RELEASECONFIRM setting: see [#26756] */
+ if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
+ return 1;
+ }
+ }
+ }
+ else {
+ /* this is fine as long as not doing km-release, otherwise
+ * some items (i.e. markers) being tweaked may end up getting
+ * dropped all over
+ */
+ if (event->val != KM_RELEASE) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+bool WM_event_is_last_mousemove(const wmEvent *event)
+{
+ while ((event = event->next)) {
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Click/Drag Checks
+ *
+ * Values under this limit are detected as clicks.
+ *
+ * \{ */
+
+int WM_event_drag_threshold(const struct wmEvent *event)
+{
+ int drag_threshold;
+ if (WM_event_is_tablet(event)) {
+ drag_threshold = U.drag_threshold_tablet;
+ }
+ else if (ISMOUSE(event->prevtype)) {
+ drag_threshold = U.drag_threshold_mouse;
+ }
+ else {
+ /* Typically keyboard, could be NDOF button or other less common types. */
+ drag_threshold = U.drag_threshold;
+ }
+ return drag_threshold * U.dpi_fac;
+}
+
+bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2])
+{
+ const int drag_threshold = WM_event_drag_threshold(event);
+ return abs(drag_delta[0]) > drag_threshold || abs(drag_delta[1]) > drag_threshold;
+}
+
+bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2])
+{
+ const int drag_delta[2] = {
+ prev_xy[0] - event->x,
+ prev_xy[1] - event->y,
+ };
+ return WM_event_drag_test_with_delta(event, drag_delta);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Preference Mapping
+ * \{ */
+
+int WM_userdef_event_map(int kmitype)
+{
+ switch (kmitype) {
+ case WHEELOUTMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
+ case WHEELINMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
+ }
+
+ return kmitype;
+}
+
+/**
+ * Use so we can check if 'wmEvent.type' is released in modal operators.
+ *
+ * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
+ */
+int WM_userdef_event_type_from_keymap_type(int kmitype)
+{
+ switch (kmitype) {
+ case EVT_TWEAK_L:
+ return LEFTMOUSE;
+ case EVT_TWEAK_M:
+ return MIDDLEMOUSE;
+ case EVT_TWEAK_R:
+ return RIGHTMOUSE;
+ case WHEELOUTMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
+ case WHEELINMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
+ }
+
+ return kmitype;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event NDOF Input Access
+ * \{ */
+
+#ifdef WITH_INPUT_NDOF
+
+void WM_event_ndof_pan_get(const wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom)
+{
+ int z_flag = use_zoom ? NDOF_ZOOM_INVERT : NDOF_PANZ_INVERT_AXIS;
+ r_pan[0] = ndof->tvec[0] * ((U.ndof_flag & NDOF_PANX_INVERT_AXIS) ? -1.0f : 1.0f);
+ r_pan[1] = ndof->tvec[1] * ((U.ndof_flag & NDOF_PANY_INVERT_AXIS) ? -1.0f : 1.0f);
+ r_pan[2] = ndof->tvec[2] * ((U.ndof_flag & z_flag) ? -1.0f : 1.0f);
+}
+
+void WM_event_ndof_rotate_get(const wmNDOFMotionData *ndof, float r_rot[3])
+{
+ r_rot[0] = ndof->rvec[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
+ r_rot[1] = ndof->rvec[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
+ r_rot[2] = ndof->rvec[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
+}
+
+float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3])
+{
+ float angle;
+ angle = normalize_v3_v3(axis, ndof->rvec);
+
+ axis[0] = axis[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
+ axis[1] = axis[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
+ axis[2] = axis[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
+
+ return ndof->dt * angle;
+}
+
+void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
+{
+ float axis[3];
+ float angle;
+
+ angle = WM_event_ndof_to_axis_angle(ndof, axis);
+ axis_angle_to_quat(q, axis, angle);
+}
+#endif /* WITH_INPUT_NDOF */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Tablet Input Access
+ * \{ */
+
+/* applies the global tablet pressure correction curve */
+float wm_pressure_curve(float pressure)
+{
+ if (U.pressure_threshold_max != 0.0f) {
+ pressure /= U.pressure_threshold_max;
+ }
+
+ CLAMP(pressure, 0.0f, 1.0f);
+
+ if (U.pressure_softness != 0.0f) {
+ pressure = powf(pressure, powf(4.0f, -U.pressure_softness));
+ }
+
+ return pressure;
+}
+
+/* if this is a tablet event, return tablet pressure and set *pen_flip
+ * to 1 if the eraser tool is being used, 0 otherwise */
+float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
+{
+ if (tilt) {
+ tilt[0] = event->tablet.x_tilt;
+ tilt[1] = event->tablet.y_tilt;
+ }
+
+ if (pen_flip) {
+ (*pen_flip) = (event->tablet.active == EVT_TABLET_ERASER);
+ }
+
+ return event->tablet.pressure;
+}
+
+bool WM_event_is_tablet(const struct wmEvent *event)
+{
+ return (event->tablet.active != EVT_TABLET_NONE);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event IME Input Access
+ * \{ */
+
+#ifdef WITH_INPUT_IME
+/* most os using ctrl/oskey + space to switch ime, avoid added space */
+bool WM_event_is_ime_switch(const struct wmEvent *event)
+{
+ return event->val == KM_PRESS && event->type == SPACEKEY &&
+ (event->ctrl || event->oskey || event->shift || event->alt);
+}
+#endif
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index f5970e8fb61..ba1f34478ed 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -70,7 +70,6 @@
#include "RNA_access.h"
#include "UI_interface.h"
-#include "UI_view2d.h"
#include "PIL_time.h"
@@ -84,8 +83,6 @@
#include "wm_event_system.h"
#include "wm_event_types.h"
-#include "RNA_enum_types.h"
-
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -104,7 +101,6 @@
#define USE_GIZMO_MOUSE_PRIORITY_HACK
static void wm_notifier_clear(wmNotifier *note);
-static void update_tablet_data(wmWindow *win, wmEvent *event);
static int wm_operator_call_internal(bContext *C,
wmOperatorType *ot,
@@ -114,6 +110,8 @@ static int wm_operator_call_internal(bContext *C,
const bool poll_only,
wmEvent *event);
+static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot);
+
/* -------------------------------------------------------------------- */
/** \name Event Management
* \{ */
@@ -126,14 +124,6 @@ wmEvent *wm_event_add_ex(wmWindow *win,
*event = *event_to_add;
- update_tablet_data(win, event);
-
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- /* We could have a preference to support relative tablet motion (we can't detect that). */
- event->is_motion_absolute = ((event->tablet_data != NULL) &&
- (event->tablet_data->Active != GHOST_kTabletModeNone));
- }
-
if (event_to_add_after == NULL) {
BLI_addtail(&win->queue, event);
}
@@ -177,10 +167,6 @@ void wm_event_free(wmEvent *event)
}
}
- if (event->tablet_data) {
- MEM_freeN((void *)event->tablet_data);
- }
-
MEM_freeN(event);
}
@@ -195,9 +181,6 @@ void wm_event_free_all(wmWindow *win)
void wm_event_init_from_window(wmWindow *win, wmEvent *event)
{
- /* make sure we don't copy any owned pointers */
- BLI_assert(win->eventstate->tablet_data == NULL);
-
*event = *(win->eventstate);
}
@@ -682,6 +665,82 @@ static void wm_handler_ui_cancel(bContext *C)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name WM Reports
+ *
+ * Access to #wmWindowManager.reports
+ * \{ */
+
+/**
+ * Show the report in the info header.
+ */
+void WM_report_banner_show(void)
+{
+ wmWindowManager *wm = G_MAIN->wm.first;
+ ReportList *wm_reports = &wm->reports;
+ ReportTimerInfo *rti;
+
+ /* After adding reports to the global list, reset the report timer. */
+ WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
+
+ /* Records time since last report was added */
+ wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
+
+ rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
+ wm_reports->reporttimer->customdata = rti;
+}
+
+#ifdef WITH_INPUT_NDOF
+void WM_ndof_deadzone_set(float deadzone)
+{
+ GHOST_setNDOFDeadZone(deadzone);
+}
+#endif
+
+static void wm_add_reports(ReportList *reports)
+{
+ /* if the caller owns them, handle this */
+ if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
+ wmWindowManager *wm = G_MAIN->wm.first;
+
+ /* add reports to the global list, otherwise they are not seen */
+ BLI_movelisttolist(&wm->reports.list, &reports->list);
+
+ WM_report_banner_show();
+ }
+}
+
+void WM_report(ReportType type, const char *message)
+{
+ ReportList reports;
+
+ BKE_reports_init(&reports, RPT_STORE);
+ BKE_report(&reports, type, message);
+
+ wm_add_reports(&reports);
+
+ BKE_reports_clear(&reports);
+}
+
+void WM_reportf(ReportType type, const char *format, ...)
+{
+ DynStr *ds;
+ va_list args;
+
+ ds = BLI_dynstr_new();
+ va_start(args, format);
+ BLI_dynstr_vappendf(ds, format, args);
+ va_end(args);
+
+ char *str = BLI_dynstr_get_cstring(ds);
+ WM_report(type, str);
+ MEM_freeN(str);
+
+ BLI_dynstr_free(ds);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Operator Logic
* \{ */
@@ -762,164 +821,6 @@ void WM_operator_region_active_win_set(bContext *C)
}
}
-int WM_event_modifier_flag(const wmEvent *event)
-{
- int flag = 0;
- if (event->ctrl) {
- flag |= KM_CTRL;
- }
- if (event->alt) {
- flag |= KM_ALT;
- }
- if (event->shift) {
- flag |= KM_SHIFT;
- }
- if (event->oskey) {
- flag |= KM_OSKEY;
- }
- return flag;
-}
-
-/* for debugging only, getting inspecting events manually is tedious */
-void WM_event_print(const wmEvent *event)
-{
- if (event) {
- const char *unknown = "UNKNOWN";
- const char *type_id = unknown;
- const char *val_id = unknown;
-
- RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id);
- RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id);
-
- printf(
- "wmEvent type:%d / %s, val:%d / %s,\n"
- " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n"
- " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', keymap_idname:%s, pointer:%p\n",
- event->type,
- type_id,
- event->val,
- val_id,
- event->shift,
- event->ctrl,
- event->alt,
- event->oskey,
- event->keymodifier,
- event->x,
- event->y,
- event->ascii,
- BLI_str_utf8_size(event->utf8_buf),
- event->utf8_buf,
- event->keymap_idname,
- (const void *)event);
-
-#ifdef WITH_INPUT_NDOF
- if (ISNDOF(event->type)) {
- const wmNDOFMotionData *ndof = event->customdata;
- if (event->type == NDOF_MOTION) {
- printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n",
- UNPACK3(ndof->rvec),
- UNPACK3(ndof->tvec),
- ndof->dt,
- ndof->progress);
- }
- else {
- /* ndof buttons printed already */
- }
- }
-#endif /* WITH_INPUT_NDOF */
-
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n",
- wmtab->Active,
- wmtab->Pressure,
- wmtab->Xtilt,
- wmtab->Ytilt);
- }
- }
- else {
- printf("wmEvent - NULL\n");
- }
-}
-
-/**
- * Show the report in the info header.
- */
-void WM_report_banner_show(void)
-{
- wmWindowManager *wm = G_MAIN->wm.first;
- ReportList *wm_reports = &wm->reports;
- ReportTimerInfo *rti;
-
- /* After adding reports to the global list, reset the report timer. */
- WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
-
- /* Records time since last report was added */
- wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
-
- rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
- wm_reports->reporttimer->customdata = rti;
-}
-
-bool WM_event_is_last_mousemove(const wmEvent *event)
-{
- while ((event = event->next)) {
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- return false;
- }
- }
- return true;
-}
-
-#ifdef WITH_INPUT_NDOF
-void WM_ndof_deadzone_set(float deadzone)
-{
- GHOST_setNDOFDeadZone(deadzone);
-}
-#endif
-
-static void wm_add_reports(ReportList *reports)
-{
- /* if the caller owns them, handle this */
- if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
- wmWindowManager *wm = G_MAIN->wm.first;
-
- /* add reports to the global list, otherwise they are not seen */
- BLI_movelisttolist(&wm->reports.list, &reports->list);
-
- WM_report_banner_show();
- }
-}
-
-void WM_report(ReportType type, const char *message)
-{
- ReportList reports;
-
- BKE_reports_init(&reports, RPT_STORE);
- BKE_report(&reports, type, message);
-
- wm_add_reports(&reports);
-
- BKE_reports_clear(&reports);
-}
-
-void WM_reportf(ReportType type, const char *format, ...)
-{
- DynStr *ds;
- va_list args;
-
- ds = BLI_dynstr_new();
- va_start(args, format);
- BLI_dynstr_vappendf(ds, format, args);
- va_end(args);
-
- char *str = BLI_dynstr_get_cstring(ds);
- WM_report(type, str);
- MEM_freeN(str);
-
- BLI_dynstr_free(ds);
-}
-
/* (caller_owns_reports == true) when called from python */
static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports)
{
@@ -1301,105 +1202,6 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
}
}
-#if 1 /* may want to disable operator remembering previous state for testing */
-
-static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_properties)
-{
- bool changed = false;
- IDPropertyTemplate val = {0};
- IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
- PropertyRNA *iterprop;
-
- CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname);
-
- iterprop = RNA_struct_iterator_property(op->type->srna);
-
- RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) {
- PropertyRNA *prop = itemptr.data;
- if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
- if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */
- const char *identifier = RNA_property_identifier(prop);
- IDProperty *idp_src = IDP_GetPropertyFromGroup(last_properties, identifier);
- if (idp_src) {
- IDProperty *idp_dst = IDP_CopyProperty(idp_src);
-
- /* note - in the future this may need to be done recursively,
- * but for now RNA doesn't access nested operators */
- idp_dst->flag |= IDP_FLAG_GHOST;
-
- /* add to temporary group instead of immediate replace,
- * because we are iterating over this group */
- IDP_AddToGroup(replaceprops, idp_dst);
- changed = true;
- }
- }
- }
- }
- RNA_PROP_END;
-
- IDP_MergeGroup(op->properties, replaceprops, true);
- IDP_FreeProperty(replaceprops);
- return changed;
-}
-
-bool WM_operator_last_properties_init(wmOperator *op)
-{
- bool changed = false;
- if (op->type->last_properties) {
- changed |= operator_last_properties_init_impl(op, op->type->last_properties);
- for (wmOperator *opm = op->macro.first; opm; opm = opm->next) {
- IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname);
- if (idp_src) {
- changed |= operator_last_properties_init_impl(opm, idp_src);
- }
- }
- }
- return changed;
-}
-
-bool WM_operator_last_properties_store(wmOperator *op)
-{
- if (op->type->last_properties) {
- IDP_FreeProperty(op->type->last_properties);
- op->type->last_properties = NULL;
- }
-
- if (op->properties) {
- CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname);
- op->type->last_properties = IDP_CopyProperty(op->properties);
- }
-
- if (op->macro.first != NULL) {
- for (wmOperator *opm = op->macro.first; opm; opm = opm->next) {
- if (opm->properties) {
- if (op->type->last_properties == NULL) {
- op->type->last_properties = IDP_New(
- IDP_GROUP, &(IDPropertyTemplate){0}, "wmOperatorProperties");
- }
- IDProperty *idp_macro = IDP_CopyProperty(opm->properties);
- STRNCPY(idp_macro->name, opm->type->idname);
- IDP_ReplaceInGroup(op->type->last_properties, idp_macro);
- }
- }
- }
-
- return (op->type->last_properties != NULL);
-}
-
-#else
-
-bool WM_operator_last_properties_init(wmOperator *UNUSED(op))
-{
- return false;
-}
-
-bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
-{
- return false;
-}
-
-#endif
-
/**
* Also used for exec when 'event' is NULL.
*/
@@ -1954,42 +1756,6 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
}
}
-/* do userdef mappings */
-int WM_userdef_event_map(int kmitype)
-{
- switch (kmitype) {
- case WHEELOUTMOUSE:
- return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
- case WHEELINMOUSE:
- return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
- }
-
- return kmitype;
-}
-
-/**
- * Use so we can check if 'wmEvent.type' is released in modal operators.
- *
- * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
- */
-int WM_userdef_event_type_from_keymap_type(int kmitype)
-{
- switch (kmitype) {
- case EVT_TWEAK_L:
- return LEFTMOUSE;
- case EVT_TWEAK_M:
- return MIDDLEMOUSE;
- case EVT_TWEAK_R:
- return RIGHTMOUSE;
- case WHEELOUTMOUSE:
- return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
- case WHEELINMOUSE:
- return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
- }
-
- return kmitype;
-}
-
static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
{
if (kmi->flag & KMI_INACTIVE) {
@@ -2011,19 +1777,16 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
if (kmitype != KM_ANY) {
if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) {
- const wmTabletData *wmtab = winevent->tablet_data;
+ const wmTabletData *wmtab = &winevent->tablet;
- if (wmtab == NULL) {
- return false;
- }
- else if (winevent->type != LEFTMOUSE) {
+ if (winevent->type != LEFTMOUSE) {
/* tablet events can occur on hover + keypress */
return false;
}
- else if ((kmitype == TABLET_STYLUS) && (wmtab->Active != EVT_TABLET_STYLUS)) {
+ else if ((kmitype == TABLET_STYLUS) && (wmtab->active != EVT_TABLET_STYLUS)) {
return false;
}
- else if ((kmitype == TABLET_ERASER) && (wmtab->Active != EVT_TABLET_ERASER)) {
+ else if ((kmitype == TABLET_ERASER) && (wmtab->active != EVT_TABLET_ERASER)) {
return false;
}
}
@@ -2103,10 +1866,10 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap,
* This is done since we only want to use double click events to match key-map items,
* allowing modal functions to check for press/release events without having to interpret them.
*/
-static void wm_event_modalkeymap(const bContext *C,
- wmOperator *op,
- wmEvent *event,
- bool *dbl_click_disabled)
+static void wm_event_modalkeymap_begin(const bContext *C,
+ wmOperator *op,
+ wmEvent *event,
+ bool *dbl_click_disabled)
{
BLI_assert(event->type != EVT_MODAL_MAP);
@@ -2159,25 +1922,13 @@ static void wm_event_modalkeymap(const bContext *C,
}
/**
- * Check whether operator is allowed to run in case interface is locked,
- * If interface is unlocked, will always return truth.
+ * Restore changes from #wm_event_modalkeymap_begin
+ *
+ * \warning bad hacking event system...
+ * better restore event type for checking of #KM_CLICK for example.
+ * Modal maps could use different method (ton).
*/
-static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
-
- if (wm->is_interface_locked) {
- if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) {
- return false;
- }
- }
-
- return true;
-}
-
-/* bad hacking event system... better restore event type for checking of KM_CLICK for example */
-/* XXX modal maps could use different method (ton) */
-static void wm_event_modalmap_end(wmEvent *event, bool dbl_click_disabled)
+static void wm_event_modalkeymap_end(wmEvent *event, bool dbl_click_disabled)
{
if (event->type == EVT_MODAL_MAP) {
event->type = event->prevtype;
@@ -2196,7 +1947,8 @@ static int wm_handler_operator_call(bContext *C,
ListBase *handlers,
wmEventHandler *handler_base,
wmEvent *event,
- PointerRNA *properties)
+ PointerRNA *properties,
+ const char *kmi_idname)
{
int retval = OPERATOR_PASS_THROUGH;
@@ -2221,7 +1973,7 @@ static int wm_handler_operator_call(bContext *C,
wm_handler_op_context(C, handler, event);
wm_region_mouse_co(C, event);
- wm_event_modalkeymap(C, op, event, &dbl_click_disabled);
+ wm_event_modalkeymap_begin(C, op, event, &dbl_click_disabled);
if (ot->flag & OPTYPE_UNDO) {
wm->op_undo_depth++;
@@ -2236,7 +1988,7 @@ static int wm_handler_operator_call(bContext *C,
* the event, operator etc have all been freed. - campbell */
if (CTX_wm_manager(C) == wm) {
- wm_event_modalmap_end(event, dbl_click_disabled);
+ wm_event_modalkeymap_end(event, dbl_click_disabled);
if (ot->flag & OPTYPE_UNDO) {
wm->op_undo_depth--;
@@ -2298,7 +2050,7 @@ static int wm_handler_operator_call(bContext *C,
}
}
else {
- wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0);
if (ot && wm_operator_check_locked_interface(C, ot)) {
bool use_last_properties = true;
@@ -2636,10 +2388,8 @@ static int wm_handlers_do_keymap_with_keymap_handler(
PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
- /* weak, but allows interactive callback to not use rawkey */
- event->keymap_idname = kmi->idname;
-
- action |= wm_handler_operator_call(C, handlers, &handler->head, event, kmi->ptr);
+ action |= wm_handler_operator_call(
+ C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
if (action & WM_HANDLER_BREAK) {
/* not always_pass here, it denotes removed handler_base */
@@ -2693,13 +2443,11 @@ static int wm_handlers_do_keymap_with_gizmo_handler(
if (wm_eventmatch(event, kmi)) {
PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
- /* weak, but allows interactive callback to not use rawkey */
- event->keymap_idname = kmi->idname;
-
CTX_wm_gizmo_group_set(C, gzgroup);
/* handler->op is called later, we want keymap op to be triggered here */
- action |= wm_handler_operator_call(C, handlers, &handler->head, event, kmi->ptr);
+ action |= wm_handler_operator_call(
+ C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
CTX_wm_gizmo_group_set(C, NULL);
@@ -2990,7 +2738,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
}
}
else {
- action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL);
+ action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL);
}
}
else {
@@ -4099,91 +3847,6 @@ void WM_event_add_mousemove(const bContext *C)
window->addmousemove = 1;
}
-/* for modal callbacks, check configuration for how to interpret exit with tweaks */
-bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
-{
- /* if the release-confirm userpref setting is enabled,
- * tweak events can be canceled when mouse is released
- */
- if (U.flag & USER_RELEASECONFIRM) {
- /* option on, so can exit with km-release */
- if (event->val == KM_RELEASE) {
- switch (tweak_event) {
- case EVT_TWEAK_L:
- case EVT_TWEAK_M:
- case EVT_TWEAK_R:
- return 1;
- }
- }
- else {
- /* if the initial event wasn't a tweak event then
- * ignore USER_RELEASECONFIRM setting: see [#26756] */
- if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
- return 1;
- }
- }
- }
- else {
- /* this is fine as long as not doing km-release, otherwise
- * some items (i.e. markers) being tweaked may end up getting
- * dropped all over
- */
- if (event->val != KM_RELEASE) {
- return 1;
- }
- }
-
- return 0;
-}
-
-bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask)
-{
- /* Keyboard. */
- if (mask & EVT_TYPE_MASK_KEYBOARD) {
- if (ISKEYBOARD(event_type)) {
- return true;
- }
- }
- else if (mask & EVT_TYPE_MASK_KEYBOARD_MODIFIER) {
- if (ISKEYMODIFIER(event_type)) {
- return true;
- }
- }
-
- /* Mouse. */
- if (mask & EVT_TYPE_MASK_MOUSE) {
- if (ISMOUSE(event_type)) {
- return true;
- }
- }
- else if (mask & EVT_TYPE_MASK_MOUSE_WHEEL) {
- if (ISMOUSE_WHEEL(event_type)) {
- return true;
- }
- }
- else if (mask & EVT_TYPE_MASK_MOUSE_GESTURE) {
- if (ISMOUSE_GESTURE(event_type)) {
- return true;
- }
- }
-
- /* Tweak. */
- if (mask & EVT_TYPE_MASK_TWEAK) {
- if (ISTWEAK(event_type)) {
- return true;
- }
- }
-
- /* Action Zone. */
- if (mask & EVT_TYPE_MASK_ACTIONZONE) {
- if (IS_EVENT_ACTIONZONE(event_type)) {
- return true;
- }
- }
-
- return false;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -4421,41 +4084,23 @@ static void wm_eventemulation(wmEvent *event, bool test_only)
}
}
-/* applies the global tablet pressure correction curve */
-float wm_pressure_curve(float pressure)
+void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
{
- if (U.pressure_threshold_max != 0.0f) {
- pressure /= U.pressure_threshold_max;
- }
-
- CLAMP(pressure, 0.0f, 1.0f);
-
- if (U.pressure_softness != 0.0f) {
- pressure = powf(pressure, powf(4.0f, -U.pressure_softness));
- }
-
- return pressure;
-}
-
-/* adds customdata to event */
-static void update_tablet_data(wmWindow *win, wmEvent *event)
-{
- const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin);
-
- /* if there's tablet data from an active tablet device then add it */
- if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
- struct wmTabletData *wmtab = MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
-
- wmtab->Active = (int)td->Active;
- wmtab->Pressure = wm_pressure_curve(td->Pressure);
- wmtab->Xtilt = td->Xtilt;
- wmtab->Ytilt = td->Ytilt;
-
- event->tablet_data = wmtab;
- // printf("%s: using tablet %.5f\n", __func__, wmtab->Pressure);
+ if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) {
+ wmtab->active = (int)tablet_data->Active;
+ wmtab->pressure = wm_pressure_curve(tablet_data->Pressure);
+ wmtab->x_tilt = tablet_data->Xtilt;
+ wmtab->y_tilt = tablet_data->Ytilt;
+ /* We could have a preference to support relative tablet motion (we can't detect that). */
+ wmtab->is_motion_absolute = true;
+ // printf("%s: using tablet %.5f\n", __func__, wmtab->pressure);
}
else {
- event->tablet_data = NULL;
+ wmtab->active = EVT_TABLET_NONE;
+ wmtab->pressure = 1.0f;
+ wmtab->x_tilt = 0.0f;
+ wmtab->y_tilt = 0.0f;
+ wmtab->is_motion_absolute = false;
// printf("%s: not using tablet\n", __func__);
}
}
@@ -4607,6 +4252,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
copy_v2_v2_int(&event.x, &cd->x);
wm_stereo3d_mouse_offset_apply(win, &event.x);
+ wm_tablet_data_from_ghost(&cd->tablet, &event.tablet);
event.prevtype = event.type;
event.prevval = event.val;
@@ -4614,7 +4260,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
{
wmEvent *event_new = wm_event_add_mousemove(win, &event);
copy_v2_v2_int(&evt->x, &event_new->x);
- evt->is_motion_absolute = event_new->is_motion_absolute;
+ evt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
}
/* also add to other window if event is there, this makes overdraws disappear nicely */
@@ -4632,7 +4278,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
{
wmEvent *event_new = wm_event_add_mousemove(owin, &oevent);
copy_v2_v2_int(&oevt->x, &event_new->x);
- oevt->is_motion_absolute = event_new->is_motion_absolute;
+ oevt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
}
}
@@ -4696,6 +4342,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
event.type = MIDDLEMOUSE;
}
+ /* Get tablet data. */
+ wm_tablet_data_from_ghost(&bd->tablet, &event.tablet);
+
wm_eventemulation(&event, false);
/* copy previous state to prev event state (two old!) */
@@ -4706,17 +4355,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
evt->val = event.val;
evt->type = event.type;
- if (win->active == 0) {
- int cx, cy;
-
- /* Entering window, update mouse pos.
- * (ghost sends win-activate *after* the mouseclick in window!) */
- wm_get_cursor_position(win, &cx, &cy);
-
- event.x = evt->x = cx;
- event.y = evt->y = cy;
- }
-
/* double click test */
if (wm_event_is_double_click(&event, evt)) {
CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
@@ -4737,6 +4375,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
oevent.y = event.y;
oevent.type = event.type;
oevent.val = event.val;
+ oevent.tablet = event.tablet;
wm_event_add(owin, &oevent);
}
@@ -5003,6 +4642,29 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
#endif
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name WM Interface Locking
+ * \{ */
+
+/**
+ * Check whether operator is allowed to run in case interface is locked,
+ * If interface is unlocked, will always return truth.
+ */
+static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ if (wm->is_interface_locked) {
+ if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
{
/* This will prevent events from being handled while interface is locked
@@ -5024,96 +4686,12 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock)
BKE_spacedata_draw_locks(lock);
}
-#ifdef WITH_INPUT_NDOF
+/** \} */
/* -------------------------------------------------------------------- */
-/** \name NDOF Utility Functions
+/** \name Event / Keymap Matching API
* \{ */
-void WM_event_ndof_pan_get(const wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom)
-{
- int z_flag = use_zoom ? NDOF_ZOOM_INVERT : NDOF_PANZ_INVERT_AXIS;
- r_pan[0] = ndof->tvec[0] * ((U.ndof_flag & NDOF_PANX_INVERT_AXIS) ? -1.0f : 1.0f);
- r_pan[1] = ndof->tvec[1] * ((U.ndof_flag & NDOF_PANY_INVERT_AXIS) ? -1.0f : 1.0f);
- r_pan[2] = ndof->tvec[2] * ((U.ndof_flag & z_flag) ? -1.0f : 1.0f);
-}
-
-void WM_event_ndof_rotate_get(const wmNDOFMotionData *ndof, float r_rot[3])
-{
- r_rot[0] = ndof->rvec[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
- r_rot[1] = ndof->rvec[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
- r_rot[2] = ndof->rvec[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
-}
-
-float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3])
-{
- float angle;
- angle = normalize_v3_v3(axis, ndof->rvec);
-
- axis[0] = axis[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
- axis[1] = axis[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
- axis[2] = axis[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
-
- return ndof->dt * angle;
-}
-
-void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
-{
- float axis[3];
- float angle;
-
- angle = WM_event_ndof_to_axis_angle(ndof, axis);
- axis_angle_to_quat(q, axis, angle);
-}
-#endif /* WITH_INPUT_NDOF */
-
-/* if this is a tablet event, return tablet pressure and set *pen_flip
- * to 1 if the eraser tool is being used, 0 otherwise */
-float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
-{
- int erasor = 0;
- float pressure = 1;
-
- if (tilt) {
- zero_v2(tilt);
- }
-
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
-
- erasor = (wmtab->Active == EVT_TABLET_ERASER);
- if (wmtab->Active != EVT_TABLET_NONE) {
- pressure = wmtab->Pressure;
- if (tilt) {
- tilt[0] = wmtab->Xtilt;
- tilt[1] = wmtab->Ytilt;
- }
- }
- }
-
- if (pen_flip) {
- (*pen_flip) = erasor;
- }
-
- return pressure;
-}
-
-bool WM_event_is_tablet(const struct wmEvent *event)
-{
- return (event->tablet_data) ? true : false;
-}
-
-#ifdef WITH_INPUT_IME
-/* most os using ctrl/oskey + space to switch ime, avoid added space */
-bool WM_event_is_ime_switch(const struct wmEvent *event)
-{
- return event->val == KM_PRESS && event->type == SPACEKEY &&
- (event->ctrl || event->oskey || event->shift || event->alt);
-}
-#endif
-
-/** \} */
-
wmKeyMap *WM_event_get_keymap_from_handler(wmWindowManager *wm, wmEventHandler_Keymap *handler)
{
wmKeyMap *keymap;
@@ -5141,10 +4719,10 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm
return NULL;
}
-static wmKeyMapItem *wm_kmi_from_event(bContext *C,
- wmWindowManager *wm,
- ListBase *handlers,
- const wmEvent *event)
+wmKeyMapItem *WM_event_match_keymap_item_from_handlers(bContext *C,
+ wmWindowManager *wm,
+ ListBase *handlers,
+ const wmEvent *event)
{
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
/* during this loop, ui handlers for nested menus can tag multiple handlers free */
@@ -5167,6 +4745,8 @@ static wmKeyMapItem *wm_kmi_from_event(bContext *C,
return NULL;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Cursor Keymap Status
*
@@ -5379,7 +4959,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
wm_eventemulation(&test_event, true);
wmKeyMapItem *kmi = NULL;
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
- kmi = wm_kmi_from_event(C, wm, handlers[handler_index], &test_event);
+ kmi = WM_event_match_keymap_item_from_handlers(C, wm, handlers[handler_index], &test_event);
if (kmi) {
break;
}
@@ -5475,43 +5055,3 @@ bool WM_window_modal_keymap_status_draw(bContext *UNUSED(C), wmWindow *win, uiLa
}
/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Event Click/Drag Checks
- *
- * Values under this limit are detected as clicks.
- *
- * \{ */
-
-int WM_event_drag_threshold(const struct wmEvent *event)
-{
- int drag_threshold;
- if (WM_event_is_tablet(event)) {
- drag_threshold = U.drag_threshold_tablet;
- }
- else if (ISMOUSE(event->prevtype)) {
- drag_threshold = U.drag_threshold_mouse;
- }
- else {
- /* Typically keyboard, could be NDOF button or other less common types. */
- drag_threshold = U.drag_threshold;
- }
- return drag_threshold * U.dpi_fac;
-}
-
-bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2])
-{
- const int drag_threshold = WM_event_drag_threshold(event);
- return abs(drag_delta[0]) > drag_threshold || abs(drag_delta[1]) > drag_threshold;
-}
-
-bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2])
-{
- const int drag_delta[2] = {
- prev_xy[0] - event->x,
- prev_xy[1] - event->y,
- };
- return WM_event_drag_test_with_delta(event, drag_delta);
-}
-
-/** \} */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 678b7d9dcee..5837e8e952c 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -720,6 +720,111 @@ void WM_operator_properties_free(PointerRNA *ptr)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Operator Last Properties API
+ * \{ */
+
+#if 1 /* may want to disable operator remembering previous state for testing */
+
+static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_properties)
+{
+ bool changed = false;
+ IDPropertyTemplate val = {0};
+ IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ PropertyRNA *iterprop;
+
+ CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname);
+
+ iterprop = RNA_struct_iterator_property(op->type->srna);
+
+ RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) {
+ PropertyRNA *prop = itemptr.data;
+ if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
+ if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */
+ const char *identifier = RNA_property_identifier(prop);
+ IDProperty *idp_src = IDP_GetPropertyFromGroup(last_properties, identifier);
+ if (idp_src) {
+ IDProperty *idp_dst = IDP_CopyProperty(idp_src);
+
+ /* note - in the future this may need to be done recursively,
+ * but for now RNA doesn't access nested operators */
+ idp_dst->flag |= IDP_FLAG_GHOST;
+
+ /* add to temporary group instead of immediate replace,
+ * because we are iterating over this group */
+ IDP_AddToGroup(replaceprops, idp_dst);
+ changed = true;
+ }
+ }
+ }
+ }
+ RNA_PROP_END;
+
+ IDP_MergeGroup(op->properties, replaceprops, true);
+ IDP_FreeProperty(replaceprops);
+ return changed;
+}
+
+bool WM_operator_last_properties_init(wmOperator *op)
+{
+ bool changed = false;
+ if (op->type->last_properties) {
+ changed |= operator_last_properties_init_impl(op, op->type->last_properties);
+ for (wmOperator *opm = op->macro.first; opm; opm = opm->next) {
+ IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname);
+ if (idp_src) {
+ changed |= operator_last_properties_init_impl(opm, idp_src);
+ }
+ }
+ }
+ return changed;
+}
+
+bool WM_operator_last_properties_store(wmOperator *op)
+{
+ if (op->type->last_properties) {
+ IDP_FreeProperty(op->type->last_properties);
+ op->type->last_properties = NULL;
+ }
+
+ if (op->properties) {
+ CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname);
+ op->type->last_properties = IDP_CopyProperty(op->properties);
+ }
+
+ if (op->macro.first != NULL) {
+ for (wmOperator *opm = op->macro.first; opm; opm = opm->next) {
+ if (opm->properties) {
+ if (op->type->last_properties == NULL) {
+ op->type->last_properties = IDP_New(
+ IDP_GROUP, &(IDPropertyTemplate){0}, "wmOperatorProperties");
+ }
+ IDProperty *idp_macro = IDP_CopyProperty(opm->properties);
+ STRNCPY(idp_macro->name, opm->type->idname);
+ IDP_ReplaceInGroup(op->type->last_properties, idp_macro);
+ }
+ }
+ }
+
+ return (op->type->last_properties != NULL);
+}
+
+#else
+
+bool WM_operator_last_properties_init(wmOperator *UNUSED(op))
+{
+ return false;
+}
+
+bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
+{
+ return false;
+}
+
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Default Operator Callbacks
* \{ */
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index 3218f8c45e4..8e49e47c492 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -487,6 +487,8 @@ static bool toolsystem_key_ensure_check(const bToolKey *tkey)
break;
case SPACE_NODE:
return true;
+ case SPACE_SEQ:
+ return true;
}
return false;
}
@@ -516,6 +518,11 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int sp
mode = 0;
break;
}
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = sa->spacedata.first;
+ mode = sseq->view;
+ break;
+ }
}
return mode;
}
@@ -736,6 +743,17 @@ static const char *toolsystem_default_tool(const bToolKey *tkey)
case SPACE_NODE: {
return "builtin.select_box";
}
+ case SPACE_SEQ: {
+ switch (tkey->mode) {
+ case SEQ_VIEW_SEQUENCE:
+ return "builtin.select";
+ case SEQ_VIEW_PREVIEW:
+ return "builtin.annotate";
+ case SEQ_VIEW_SEQUENCE_PREVIEW:
+ return "builtin.select";
+ }
+ return "builtin.select_box";
+ }
}
return "builtin.select_box";
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index e68d4902c66..850eb12b12a 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -547,6 +547,12 @@ void WM_window_set_dpi(const wmWindow *win)
BLF_default_dpi(U.pixelsize * U.dpi);
}
+static void wm_window_update_eventstate(wmWindow *win)
+{
+ /* Update mouse position when a window is activated. */
+ wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y);
+}
+
static void wm_window_ensure_eventstate(wmWindow *win)
{
if (win->eventstate) {
@@ -554,7 +560,7 @@ static void wm_window_ensure_eventstate(wmWindow *win)
}
win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
- wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y);
+ wm_window_update_eventstate(win);
}
/* belongs to below */
@@ -702,6 +708,8 @@ static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, boo
/* happens after fileread */
wm_window_ensure_eventstate(win);
+
+ WM_window_set_dpi(win);
}
/* add keymap handlers (1 handler for all keys in map!) */
@@ -1206,7 +1214,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
case GHOST_kEventWindowActivate: {
GHOST_TEventKeyData kdata;
wmEvent event;
- int wx, wy;
const int keymodifier = ((query_qual(SHIFT) ? KM_SHIFT : 0) |
(query_qual(CONTROL) ? KM_CTRL : 0) |
(query_qual(ALT) ? KM_ALT : 0) | (query_qual(OS) ? KM_OSKEY : 0));
@@ -1291,10 +1298,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
win->eventstate->keymodifier = 0;
/* entering window, update mouse pos. but no event */
- wm_get_cursor_position(win, &wx, &wy);
-
- win->eventstate->x = wx;
- win->eventstate->y = wy;
+ wm_window_update_eventstate(win);
win->addmousemove = 1; /* enables highlighted buttons */
@@ -1455,12 +1459,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
case GHOST_kEventDraggingDropDone: {
wmEvent event;
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
- int wx, wy;
/* entering window, update mouse pos */
- wm_get_cursor_position(win, &wx, &wy);
- win->eventstate->x = wx;
- win->eventstate->y = wy;
+ wm_window_update_eventstate(win);
wm_event_init_from_window(win, &event); /* copy last state, like mouse coords */
@@ -1542,9 +1543,21 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
wm_event_add_ghostevent(wm, win, type, data);
break;
}
- default:
+ case GHOST_kEventButtonDown:
+ case GHOST_kEventButtonUp: {
+ if (win->active == 0) {
+ /* Entering window, update cursor and tablet state.
+ * (ghost sends win-activate *after* the mouseclick in window!) */
+ wm_window_update_eventstate(win);
+ }
+
+ wm_event_add_ghostevent(wm, win, type, data);
+ break;
+ }
+ default: {
wm_event_add_ghostevent(wm, win, type, data);
break;
+ }
}
}
return 1;
@@ -2098,21 +2111,6 @@ void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
}
}
-/**
- * Get the cursor pressure, in most cases you'll want to use wmTabletData from the event
- */
-float WM_cursor_pressure(const struct wmWindow *win)
-{
- const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin);
- /* if there's tablet data from an active tablet device then add it */
- if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
- return wm_pressure_curve(td->Pressure);
- }
- else {
- return -1.0f;
- }
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -2189,8 +2187,8 @@ void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
}
}
- BLI_assert(screen_rect.xmin < screen_rect.xmax);
- BLI_assert(screen_rect.ymin < screen_rect.ymax);
+ BLI_assert(BLI_rcti_is_valid(&screen_rect));
+
*r_rect = screen_rect;
}
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index c53ccda170a..97c5980e3e7 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -31,6 +31,7 @@
#define WM_HANDLER_MODAL 4 /* MODAL|BREAK means unhandled */
struct ARegion;
+struct GHOST_TabletData;
struct ScrArea;
/* wmKeyMap is in DNA_windowmanager.h, it's saveable */
@@ -148,7 +149,9 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file);
void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
void wm_event_do_notifiers(bContext *C);
+/* wm_event_query.c */
float wm_pressure_curve(float raw_pressure);
+void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab);
/* wm_keymap.c */
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index e8c6e9251bc..446f8f51875 100644
--- a/source/creator/creator_signals.c
+++ b/source/creator/creator_signals.c
@@ -102,15 +102,18 @@ static void sig_handle_crash_backtrace(FILE *fp)
static void sig_handle_crash(int signum)
{
- wmWindowManager *wm = G_MAIN->wm.first;
+ /* Might be called after WM/Main exit, so needs to be careful about NULL-checking before
+ * dereferencing. */
+
+ wmWindowManager *wm = G_MAIN ? G_MAIN->wm.first : NULL;
# ifdef USE_WRITE_CRASH_BLEND
- if (wm->undo_stack) {
+ if (wm && wm->undo_stack) {
struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack);
if (memfile) {
char fname[FILE_MAX];
- if (!G_MAIN->name[0]) {
+ if (!(G_MAIN && G_MAIN->name[0])) {
BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
}
else {
@@ -131,7 +134,7 @@ static void sig_handle_crash(int signum)
char fname[FILE_MAX];
- if (!G_MAIN->name[0]) {
+ if (!(G_MAIN && G_MAIN->name[0])) {
BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
}
else {
diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt
index 7da65bcc8b9..bcf77fb6de7 100644
--- a/tests/gtests/CMakeLists.txt
+++ b/tests/gtests/CMakeLists.txt
@@ -16,6 +16,9 @@ if(WITH_GTESTS)
add_subdirectory(blenloader)
add_subdirectory(guardedalloc)
add_subdirectory(bmesh)
+ if(WITH_CODEC_FFMPEG)
+ add_subdirectory(ffmpeg)
+ endif()
if(WITH_ALEMBIC)
add_subdirectory(alembic)
endif()
diff --git a/tests/gtests/ffmpeg/CMakeLists.txt b/tests/gtests/ffmpeg/CMakeLists.txt
new file mode 100644
index 00000000000..dbd4f9f1fed
--- /dev/null
+++ b/tests/gtests/ffmpeg/CMakeLists.txt
@@ -0,0 +1,44 @@
+# ***** 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.
+#
+# The Original Code is Copyright (C) 2014, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ..
+
+ ${FFMPEG_INCLUDE_DIRS}
+ ${PNG_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(LIB
+ ${PNG_LIBRARIES}
+ ${FFMPEG_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+)
+
+if(WITH_IMAGE_OPENJPEG)
+ set(LIB ${LIB} ${OPENJPEG_LIBRARIES})
+endif()
+
+setup_platform_linker_flags()
+link_directories(${FFMPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH})
+include_directories(${INC})
+
+BLENDER_SRC_GTEST(ffmpeg "ffmpeg_codecs.cc" "${LIB}")
diff --git a/tests/gtests/ffmpeg/ffmpeg_codecs.cc b/tests/gtests/ffmpeg/ffmpeg_codecs.cc
new file mode 100644
index 00000000000..bbf2b3a4111
--- /dev/null
+++ b/tests/gtests/ffmpeg/ffmpeg_codecs.cc
@@ -0,0 +1,147 @@
+#include "testing/testing.h"
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavutil/log.h>
+}
+
+bool test_vcodec(AVCodec *codec, AVPixelFormat pixelformat)
+{
+ av_log_set_level(AV_LOG_QUIET);
+ bool result = false;
+ if (codec) {
+ AVCodecContext *ctx = avcodec_alloc_context3(codec);
+ if (ctx) {
+ ctx->time_base.num = 1;
+ ctx->time_base.den = 25;
+ ctx->pix_fmt = pixelformat;
+ ctx->width = 720;
+ ctx->height = 576;
+ int open = avcodec_open2(ctx, codec, NULL);
+ if (open >= 0) {
+ avcodec_free_context(&ctx);
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+bool test_acodec(AVCodec *codec, AVSampleFormat fmt)
+{
+ av_log_set_level(AV_LOG_QUIET);
+ bool result = false;
+ if (codec) {
+ AVCodecContext *ctx = avcodec_alloc_context3(codec);
+ if (ctx) {
+ ctx->sample_fmt = fmt;
+ ctx->sample_rate = 48000;
+ ctx->channel_layout = AV_CH_LAYOUT_MONO;
+ ctx->bit_rate = 128000;
+ int open = avcodec_open2(ctx, codec, NULL);
+ if (open >= 0) {
+ avcodec_free_context(&ctx);
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+
+bool test_codec_video_by_codecid(AVCodecID codec_id, AVPixelFormat pixelformat)
+{
+ bool result = false;
+ AVCodec *codec = avcodec_find_encoder(codec_id);
+ if (codec)
+ result = test_vcodec(codec, pixelformat);
+ return result;
+}
+
+bool test_codec_video_by_name(const char *codecname, AVPixelFormat pixelformat)
+{
+ bool result = false;
+ AVCodec *codec = avcodec_find_encoder_by_name(codecname);
+ if (codec)
+ result = test_vcodec(codec, pixelformat);
+ return result;
+}
+
+bool test_codec_audio_by_codecid(AVCodecID codec_id, AVSampleFormat fmt)
+{
+ bool result = false;
+ AVCodec *codec = avcodec_find_encoder(codec_id);
+ if (codec)
+ result = test_acodec(codec, fmt);
+ return result;
+}
+
+bool test_codec_audio_by_name(const char *codecname, AVSampleFormat fmt)
+{
+ bool result = false;
+ AVCodec *codec = avcodec_find_encoder_by_name(codecname);
+ if (codec)
+ result = test_acodec(codec, fmt);
+ return result;
+}
+
+#define str(s) #s
+#define FFMPEG_TEST_VCODEC_ID(codec, fmt) \
+ TEST(CheckCodec, codec##_##fmt) \
+ { \
+ EXPECT_TRUE(test_codec_video_by_codecid(codec, fmt)); \
+ }
+
+#define FFMPEG_TEST_VCODEC_NAME(codec, fmt) \
+ TEST(CheckCodec, codec##_##fmt) \
+ { \
+ EXPECT_TRUE(test_codec_video_by_name(str(codec), fmt)); \
+ }
+
+#define FFMPEG_TEST_ACODEC_ID(codec, fmt) \
+ TEST(CheckCodec, codec##_##fmt) \
+ { \
+ EXPECT_TRUE(test_codec_audio_by_codecid(codec, fmt)); \
+ }
+
+#define FFMPEG_TEST_ACODEC_NAME(codec, fmt) \
+ TEST(CheckCodec, codec) \
+ { \
+ EXPECT_TRUE(test_codec_audio_by_name(str(codec), fmt)); \
+ }
+
+/* generic codec ID's used in blender */
+
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_HUFFYUV, AV_PIX_FMT_BGRA)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_HUFFYUV, AV_PIX_FMT_RGB32)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_FFV1, AV_PIX_FMT_RGB32)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_QTRLE, AV_PIX_FMT_ARGB)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_VP9, AV_PIX_FMT_YUVA420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_PNG, AV_PIX_FMT_RGBA)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_H264, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG4, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_THEORA, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_DVVIDEO, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG1VIDEO, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG2VIDEO, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_FLV1, AV_PIX_FMT_YUV420P)
+
+/* Audio codecs */
+
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_AAC, AV_SAMPLE_FMT_FLTP)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_AC3, AV_SAMPLE_FMT_FLTP)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_FLAC, AV_SAMPLE_FMT_S16)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_MP2, AV_SAMPLE_FMT_S16)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_MP3, AV_SAMPLE_FMT_FLTP)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_OPUS, AV_SAMPLE_FMT_FLT)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_PCM_S16LE, AV_SAMPLE_FMT_S16)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_VORBIS, AV_SAMPLE_FMT_FLTP)
+
+/* Libraries we count on ffmpeg being linked against */
+
+FFMPEG_TEST_VCODEC_NAME(libtheora, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_NAME(libx264, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_NAME(libvpx, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_NAME(libopenjpeg, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_NAME(libxvid, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_ACODEC_NAME(libvorbis, AV_SAMPLE_FMT_FLTP)
+FFMPEG_TEST_ACODEC_NAME(libopus, AV_SAMPLE_FMT_FLT)
+FFMPEG_TEST_ACODEC_NAME(libmp3lame, AV_SAMPLE_FMT_FLTP)
diff --git a/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc b/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc
index efb29a6088d..4866ac44e3c 100644
--- a/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc
+++ b/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc
@@ -34,6 +34,50 @@ void DoBasicAlignmentChecks(const int alignment)
} // namespace
+TEST(guardedalloc, LockfreeAlignedAlloc1)
+{
+ DoBasicAlignmentChecks(1);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc1)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(1);
+}
+
+TEST(guardedalloc, LockfreeAlignedAlloc2)
+{
+ DoBasicAlignmentChecks(2);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc2)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(2);
+}
+
+TEST(guardedalloc, LockfreeAlignedAlloc4)
+{
+ DoBasicAlignmentChecks(4);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc4)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(4);
+}
+
+TEST(guardedalloc, LockfreeAlignedAlloc8)
+{
+ DoBasicAlignmentChecks(8);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc8)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(8);
+}
+
TEST(guardedalloc, LockfreeAlignedAlloc16)
{
DoBasicAlignmentChecks(16);
@@ -45,13 +89,35 @@ TEST(guardedalloc, GuardedAlignedAlloc16)
DoBasicAlignmentChecks(16);
}
-// On Apple we currently support 16 bit alignment only.
-// Harmless for Blender, but would be nice to support
-// eventually.
-#ifndef __APPLE__
+TEST(guardedalloc, LockfreeAlignedAlloc32)
+{
+ DoBasicAlignmentChecks(32);
+}
+
TEST(guardedalloc, GuardedAlignedAlloc32)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(32);
}
-#endif
+
+TEST(guardedalloc, LockfreeAlignedAlloc256)
+{
+ DoBasicAlignmentChecks(256);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc256)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(256);
+}
+
+TEST(guardedalloc, LockfreeAlignedAlloc512)
+{
+ DoBasicAlignmentChecks(512);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc512)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(512);
+}
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 7241c26dfec..b5af3e14237 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -22,6 +22,7 @@
set(USE_EXPERIMENTAL_TESTS FALSE)
set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
+set(TEST_PYTHON_DIR ${CMAKE_SOURCE_DIR}/tests/python)
set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
# ugh, any better way to do this on testing only?
@@ -126,13 +127,17 @@ add_blender_test(
add_blender_test(
bmesh_bevel
${TEST_SRC_DIR}/modeling/bevel_regression.blend
- --python-text run_tests
+ --python ${TEST_PYTHON_DIR}/bevel_operator.py
+ --
+ --run-all-tests
)
add_blender_test(
bmesh_boolean
${TEST_SRC_DIR}/modeling/bool_regression.blend
- --python-text run_tests
+ --python ${TEST_PYTHON_DIR}/boolean_operator.py
+ --
+ --run-all-tests
)
add_blender_test(
@@ -149,6 +154,24 @@ add_blender_test(
--python-text run_tests.py
)
+add_blender_test(
+ modifiers
+ ${TEST_SRC_DIR}/modeling/modifiers.blend
+ --python ${TEST_PYTHON_DIR}/modifiers.py
+ --
+ --run-all-tests
+)
+
+# ------------------------------------------------------------------------------
+# OPERATORS TESTS
+add_blender_test(
+ operators
+ ${TEST_SRC_DIR}/modeling/operators.blend
+ --python ${TEST_PYTHON_DIR}/operators.py
+ --
+ --run-all-tests
+)
+
# ------------------------------------------------------------------------------
# IO TESTS
diff --git a/tests/python/bevel_operator.py b/tests/python/bevel_operator.py
new file mode 100644
index 00000000000..3cdbeb9300b
--- /dev/null
+++ b/tests/python/bevel_operator.py
@@ -0,0 +1,184 @@
+# ##### 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 #####
+
+# To run all tests, use
+# BLENDER_VERBOSE=1 blender path/to/bevel_regression.blend --python path/to/bevel_operator.py -- --run-all-tests
+# To run one test, use
+# BLENDER_VERBOSE=1 blender path/to/bevel_regression.blend --python path/to/bevel_operator.py -- --run-test <index>
+# where <index> is the index of the test specified in the list tests.
+
+import bpy
+import os
+import sys
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import OperatorTest
+
+
+def main():
+ tests = [
+ # 0
+ ['EDGE', {10}, 'Cube_test', 'Cube_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {10, 7}, 'Cube_test', 'Cube_result_2', 'bevel', {'offset': 0.2, 'offset_type': 'WIDTH'}],
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_3', 'bevel', {'offset': 0.2, 'offset_type': 'DEPTH'}],
+ ['EDGE', {10}, 'Cube_test', 'Cube_result_4', 'bevel', {'offset': 0.4, 'segments': 2}],
+ ['EDGE', {10, 7}, 'Cube_test', 'Cube_result_5', 'bevel', {'offset': 0.4, 'segments': 3}],
+ # 5
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_6', 'bevel', {'offset': 0.4, 'segments': 4}],
+ ['EDGE', {0, 10, 4, 7}, 'Cube_test', 'Cube_result_7', 'bevel', {'offset': 0.4, 'segments': 5, 'profile': 0.2}],
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_8', 'bevel', {'offset': 0.4, 'segments': 5, 'profile': 0.25}],
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_9', 'bevel', {'offset': 0.4, 'segments': 6, 'profile': 0.9}],
+ ['EDGE', {10, 7}, 'Cube_test', 'Cube_result_10', 'bevel', {'offset': 0.4, 'segments': 4, 'profile': 1.0}],
+ # 10
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_11', 'bevel', {'offset': 0.4, 'segments': 5, 'profile': 1.0}],
+ ['EDGE', {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 'Cube_test', 'Cube_result_12', 'bevel',
+ {'offset': 0.4, 'segments': 8}],
+ ['EDGE', {5}, 'Pyr4_test', 'Pyr4_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {2, 5}, 'Pyr4_test', 'Pyr4_result_2', 'bevel', {'offset': 0.2}],
+ ['EDGE', {2, 3, 5}, 'Pyr4_test', 'Pyr4_result_3', 'bevel', {'offset': 0.2}],
+ # 15
+ ['EDGE', {1, 2, 3, 5}, 'Pyr4_test', 'Pyr4_result_4', 'bevel', {'offset': 0.2}],
+ ['EDGE', {1, 2, 3, 5}, 'Pyr4_test', 'Pyr4_result_5', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {2, 3}, 'Pyr4_test', 'Pyr4_result_6', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {1, 2, 3, 5}, 'Pyr4_test', 'Pyr4_result_7', 'bevel', {'offset': 0.2, 'segments': 4, 'profile': 0.15}],
+ ['VERT', {1}, 'Pyr4_test', 'Pyr4_result_8', 'bevel', {'offset': 0.75, 'segments': 4, 'vertex_only': True}],
+ # 20
+ ['VERT', {1}, 'Pyr4_test', 'Pyr4_result_9', 'bevel',
+ {'offset': 0.75, 'segments': 3, 'vertex_only': True, 'profile': 0.25}],
+ ['EDGE', {2, 3}, 'Pyr6_test', 'Pyr6_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {8, 2, 3}, 'Pyr6_test', 'Pyr6_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {0, 2, 3, 4, 6, 7, 9, 10, 11}, 'Pyr6_test', 'Pyr6_result_3', 'bevel',
+ {'offset': 0.2, 'segments': 4, 'profile': 0.8}],
+ ['EDGE', {8, 9, 3, 11}, 'Sept_test', 'Sept_result_1', 'bevel', {'offset': 0.1}],
+ # 25
+ ['EDGE', {8, 9, 11}, 'Sept_test', 'Sept_result_2', 'bevel', {'offset': 0.1, 'offset_type': 'WIDTH'}],
+ ['EDGE', {2, 8, 9, 12, 13, 14}, 'Saddle_test', 'Saddle_result_1', 'bevel', {'offset': 0.3, 'segments': 5}],
+ ['VERT', {4}, 'Saddle_test', 'Saddle_result_2', 'bevel', {'offset': 0.6, 'segments': 6, 'vertex_only': True}],
+ ['EDGE', {2, 5, 8, 11, 14, 18, 21, 24, 27, 30, 34, 37, 40, 43, 46, 50, 53, 56, 59, 62, 112, 113, 114, 115},
+ 'Bent_test', 'Bent_result_1', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {1, 8, 9, 10, 11}, 'Bentlines_test', 'Bentlines_result_1', 'bevel', {'offset': 0.2, 'segments': 3}],
+ # 30
+ ['EDGE', {26, 12, 20}, 'Flaretop_test', 'Flaretop_result_1', 'bevel', {'offset': 0.4, 'segments': 2}],
+ ['EDGE', {26, 12, 20}, 'Flaretop_test', 'Flaretop_result_2', 'bevel',
+ {'offset': 0.4, 'segments': 2, 'profile': 1.0}],
+ ['FACE', {1, 6, 7, 8, 9, 10, 11, 12}, 'Flaretop_test', 'Flaretop_result_3', 'bevel',
+ {'offset': 0.4, 'segments': 4}],
+ ['EDGE', {4, 8, 10, 18, 24}, 'BentL_test', 'BentL_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {0, 1, 2, 10}, 'Wires_test', 'Wires_test_result_1', 'bevel', {'offset': 0.3}],
+ # 35
+ ['VERT', {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 'Wires_test', 'Wires_test_result_2', 'bevel',
+ {'offset': 0.3, 'vertex_only': True}],
+ ['EDGE', {3, 4, 5}, 'tri', 'tri_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4, 5}, 'tri', 'tri_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 4, 5}, 'tri', 'tri_result_3', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 4}, 'tri', 'tri_result_4', 'bevel', {'offset': 0.2}],
+ # 40
+ ['EDGE', {3, 4}, 'tri', 'tri_result_5', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['VERT', {3}, 'tri', 'tri_result_6', 'bevel', {'offset': 0.2, 'vertex_only': True}],
+ ['VERT', {3}, 'tri', 'tri_result_7', 'bevel', {'offset': 0.2, 'segments': 2, 'vertex_only': True}],
+ ['VERT', {3}, 'tri', 'tri_result_8', 'bevel', {'offset': 0.2, 'segments': 3, 'vertex_only': True}],
+ ['VERT', {1}, 'tri', 'tri_result_9', 'bevel', {'offset': 0.2, 'vertex_only': True}],
+ # 45
+ ['EDGE', {3, 4, 5}, 'tri1gap', 'tri1gap_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4, 5}, 'tri1gap', 'tri1gap_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 4, 5}, 'tri1gap', 'tri1gap_result_3', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 4}, 'tri1gap', 'tri1gap_result_4', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4}, 'tri1gap', 'tri1gap_result_5', 'bevel', {'offset': 0.2, 'segments': 2}],
+ # 50
+ ['EDGE', {3, 4}, 'tri1gap', 'tri1gap_result_6', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 5}, 'tri1gap', 'tri1gap_result_7', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 5}, 'tri1gap', 'tri1gap_result_8', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 5}, 'tri1gap', 'tri1gap_result_9', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['VERT', {3}, 'tri1gap', 'tri1gap_result_10', 'bevel', {'offset': 0.2, 'vertex_only': True}],
+ # 55
+ ['EDGE', {3, 4, 5}, 'tri2gaps', 'tri2gaps_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4, 5}, 'tri2gaps', 'tri2gaps_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 4, 5}, 'tri2gaps', 'tri2gaps_result_3', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 4}, 'tri2gaps', 'tri2gaps_result_4', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4}, 'tri2gaps', 'tri2gaps_result_5', 'bevel', {'offset': 0.2, 'segments': 2}],
+ # 60
+ ['EDGE', {3, 4}, 'tri2gaps', 'tri2gaps_result_6', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 4, 5}, 'tri3gaps', 'tri3gaps_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4, 5}, 'tri3gaps', 'tri3gaps_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 4, 5}, 'tri3gaps', 'tri3gaps_result_3', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {32, 33, 34, 35, 24, 25, 26, 27, 28, 29, 30, 31}, 'cube3', 'cube3_result_1', 'bevel', {'offset': 0.2}],
+ # 65
+ ['EDGE', {32, 33, 34, 35, 24, 25, 26, 27, 28, 29, 30, 31}, 'cube3', 'cube3_result_2', 'bevel',
+ {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {32, 35}, 'cube3', 'cube3_result_3', 'bevel', {'offset': 0.2}],
+ ['EDGE', {24, 35}, 'cube3', 'cube3_result_4', 'bevel', {'offset': 0.2}],
+ ['EDGE', {24, 32, 35}, 'cube3', 'cube3_result_5', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {24, 32, 35}, 'cube3', 'cube3_result_6', 'bevel', {'offset': 0.2, 'segments': 3}],
+ # 70
+ ['EDGE', {0, 1, 6, 7, 12, 14, 16, 17}, 'Tray', 'Tray_result_1', 'bevel', {'offset': 0.01, 'segments': 2}],
+ ['EDGE', {33, 4, 38, 8, 41, 10, 42, 12, 14, 17, 24, 31}, 'Bumptop', 'Bumptop_result_1', 'bevel',
+ {'offset': 0.1, 'segments': 4}],
+ ['EDGE', {16, 14, 15}, 'Multisegment_test', 'Multisegment_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {16, 14, 15}, 'Multisegment_test', 'Multisegment_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {19, 20, 23, 15}, 'Window_test', 'Window_result_1', 'bevel', {'offset': 0.05, 'segments': 2}],
+ # 75
+ ['EDGE', {8}, 'Cube_hn_test', 'Cube_hn_result_1', 'bevel', {'offset': 0.2, 'harden_normals': True}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_1', 'bevel',
+ {'offset': 0.2, 'miter_outer': 'PATCH'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_2', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'PATCH'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_3', 'bevel',
+ {'offset': 0.2, 'segments': 3, 'miter_outer': 'PATCH'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_4', 'bevel',
+ {'offset': 0.2, 'miter_outer': 'ARC'}],
+ # 80
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_5', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_6', 'bevel',
+ {'offset': 0.2, 'segments': 3, 'miter_outer': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_7', 'bevel',
+ {'offset': 0.2, 'miter_outer': 'PATCH', 'miter_inner': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_8', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'PATCH', 'miter_inner': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps2_test', 'Blocksteps2_result_9', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}],
+ # 85
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps3_test', 'Blocksteps3_result_10', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps4_test', 'Blocksteps4_result_11', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps4_test', 'Blocksteps4_result_12', 'bevel',
+ {'offset': 0.2, 'segments': 3, 'miter_outer': 'ARC'}],
+ ['EDGE', {1, 7}, 'Spike_test', 'Spike_result_1', 'bevel', {'offset': 0.2, 'segments': 3}]
+ ]
+
+ operator_test = OperatorTest(tests)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ operator_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ index = int(command[i + 1])
+ operator_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except:
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
diff --git a/tests/python/boolean_operator.py b/tests/python/boolean_operator.py
new file mode 100644
index 00000000000..b05e60eea6c
--- /dev/null
+++ b/tests/python/boolean_operator.py
@@ -0,0 +1,68 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+# To run all tests, use
+# BLENDER_VERBOSE=1 blender path/to/bool_regression.blend --python path/to/boolean_operator.py -- --run-all-tests
+# To run one test, use
+# BLENDER_VERBOSE=1 blender path/to/bool_regression.blend --python path/to/boolean_operator.py -- --run-test <index>
+# where <index> is the index of the test specified in the list tests.
+
+import bpy
+import os
+import sys
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import OperatorTest
+
+
+def main():
+ tests = [
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_1', 'intersect_boolean', {'operation': 'UNION'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_2', 'intersect_boolean', {'operation': 'INTERSECT'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_3', 'intersect_boolean', {'operation': 'DIFFERENCE'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_4', 'intersect', {'separate_mode': 'CUT'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_5', 'intersect', {'separate_mode': 'ALL'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_6', 'intersect', {'separate_mode': 'NONE'}],
+ ['FACE', {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 'Cubecube', 'Cubecube_result_7', 'intersect',
+ {'mode': 'SELECT', 'separate_mode': 'NONE'}],
+ ['FACE', {6, 7, 8, 9, 10}, 'Cubecone', 'Cubecone_result_1', 'intersect_boolean', {'operation': 'UNION'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecones', 'Cubecones_result_1', 'intersect_boolean', {'operation': 'UNION'}],
+ ]
+
+ operator_test = OperatorTest(tests)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ operator_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ index = int(command[i + 1])
+ operator_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except:
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
diff --git a/tests/python/modifiers.py b/tests/python/modifiers.py
new file mode 100644
index 00000000000..22ddfd163b1
--- /dev/null
+++ b/tests/python/modifiers.py
@@ -0,0 +1,156 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+import bpy
+import os
+import sys
+from random import shuffle, seed
+seed(0)
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import ModifierTest, ModifierSpec
+
+
+def get_generate_modifiers_list(test_object_name, randomize=False):
+ """
+ Construct a list of 'Generate' modifiers with default parameters.
+ :param test_object_name: str - name of test object. Some modifiers like boolean need an extra parameter beside
+ the default one. E.g. boolean needs object, mask needs vertex group etc...
+ The extra parameter name will be <test_object_name>_<modifier_type>
+ :param randomize: bool - if True shuffle the list of modifiers.
+ :return: list of 'Generate' modifiers with default parameters.
+ """
+
+ boolean_test_object = bpy.data.objects[test_object_name + "_boolean"]
+
+ generate_modifiers = [
+ ModifierSpec('array', 'ARRAY', {}),
+ ModifierSpec('bevel', 'BEVEL', {'width': 0.1}),
+ ModifierSpec('boolean', 'BOOLEAN', {'object': boolean_test_object}),
+ ModifierSpec('build', 'BUILD', {'frame_start': 0, 'frame_duration': 1}),
+ ModifierSpec('decimate', 'DECIMATE', {}),
+ ModifierSpec('edge split', 'EDGE_SPLIT', {}),
+
+ # mask can effectively delete the mesh since the vertex group need to be updated after each
+ # applied modifier. Needs to be tested separately.
+ # ModifierSpec('mask', 'MASK', {'vertex_group': mask_vertex_group}, False),
+
+ ModifierSpec('mirror', 'MIRROR', {}),
+ ModifierSpec('multires', 'MULTIRES', {}),
+
+ # remesh can also generate an empty mesh. Skip.
+ # ModifierSpec('remesh', 'REMESH', {}),
+
+ # ModifierSpec('screw', 'SCREW', {}), # screw can make the test very slow. Skipping for now.
+ # ModifierSpec('skin', 'SKIN', {}), # skin is not reproducible .
+
+ ModifierSpec('solidify', 'SOLIDIFY', {}),
+ ModifierSpec('subsurf', 'SUBSURF', {}),
+ ModifierSpec('triangulate', 'TRIANGULATE', {}),
+ ModifierSpec('wireframe', 'WIREFRAME', {})
+
+ ]
+
+ if randomize:
+ shuffle(generate_modifiers)
+
+ return generate_modifiers
+
+
+def main():
+
+ mask_first_list = get_generate_modifiers_list("testCubeMaskFirst", randomize=True)
+ mask_vertex_group = "testCubeMaskFirst" + "_mask"
+ mask_first_list.insert(0, ModifierSpec('mask', 'MASK', {'vertex_group': mask_vertex_group}))
+
+ tests = [
+ ###############################
+ # List of 'Generate' modifiers on a cube
+ ###############################
+ # 0
+ # ["testCube", "expectedCube", get_generate_modifiers_list("testCube")],
+ ["testCubeRandom", "expectedCubeRandom", get_generate_modifiers_list("testCubeRandom", randomize=True)],
+ ["testCubeMaskFirst", "expectedCubeMaskFirst", mask_first_list],
+
+ ############################################
+ # One 'Generate' modifier on primitive meshes
+ #############################################
+ # 4
+ ["testCubeArray", "expectedCubeArray", [ModifierSpec('array', 'ARRAY', {})]],
+ ["testCylinderBuild", "expectedCylinderBuild", [ModifierSpec('build', 'BUILD', {'frame_start': 0, 'frame_duration': 1})]],
+
+ # 6
+ ["testConeDecimate", "expectedConeDecimate", [ModifierSpec('decimate', 'DECIMATE', {'ratio': 0.5})]],
+ ["testCubeEdgeSplit", "expectedCubeEdgeSplit", [ModifierSpec('edge split', 'EDGE_SPLIT', {})]],
+ ["testSphereMirror", "expectedSphereMirror", [ModifierSpec('mirror', 'MIRROR', {})]],
+ ["testCylinderMask", "expectedCylinderMask", [ModifierSpec('mask', 'MASK', {'vertex_group': "mask_vertex_group"})]],
+ ["testConeMultiRes", "expectedConeMultiRes", [ModifierSpec('multires', 'MULTIRES', {})]],
+
+ # 11
+ ["testCubeScrew", "expectedCubeScrew", [ModifierSpec('screw', 'SCREW', {})]],
+ ["testCubeSolidify", "expectedCubeSolidify", [ModifierSpec('solidify', 'SOLIDIFY', {})]],
+ ["testMonkeySubsurf", "expectedMonkeySubsurf", [ModifierSpec('subsurf', 'SUBSURF', {})]],
+ ["testSphereTriangulate", "expectedSphereTriangulate", [ModifierSpec('triangulate', 'TRIANGULATE', {})]],
+ ["testMonkeyWireframe", "expectedMonkeyWireframe", [ModifierSpec('wireframe', 'WIREFRAME', {})]],
+ #ModifierSpec('skin', 'SKIN', {}), # skin is not reproducible .
+
+ #############################################
+ # One 'Deform' modifier on primitive meshes
+ #############################################
+ # 16
+ ["testMonkeyArmature", "expectedMonkeyArmature",
+ [ModifierSpec('armature', 'ARMATURE', {'object': bpy.data.objects['testArmature'], 'use_vertex_groups': True})]],
+ ["testTorusCast", "expectedTorusCast", [ModifierSpec('cast', 'CAST', {'factor': 2.64})]],
+ ["testCubeCurve", "expectedCubeCurve",
+ [ModifierSpec('curve', 'CURVE', {'object': bpy.data.objects['testBezierCurve']})]],
+ ["testMonkeyDisplace", "expectedMonkeyDisplace", [ModifierSpec('displace', "DISPLACE", {})]],
+
+ # Hook modifier requires moving the hook object to get a mesh change, so can't test it with the current framework
+ # ["testMonkeyHook", "expectedMonkeyHook",
+ # [ModifierSpec('hook', 'HOOK', {'object': bpy.data.objects["EmptyHook"], 'vertex_group': "HookVertexGroup"})]],
+
+ # 20
+ #ModifierSpec('laplacian_deform', 'LAPLACIANDEFORM', {}) Laplacian requires a more complex mesh
+ ["testCubeLattice", "expectedCubeLattice",
+ [ModifierSpec('lattice', 'LATTICE', {'object': bpy.data.objects["testLattice"]})]],
+ ]
+
+ modifiers_test = ModifierTest(tests)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ modifiers_test.apply_modifiers = True
+ modifiers_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ modifiers_test.apply_modifiers = False
+ index = int(command[i + 1])
+ modifiers_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except:
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py
new file mode 100644
index 00000000000..9fb487bcef9
--- /dev/null
+++ b/tests/python/modules/mesh_test.py
@@ -0,0 +1,495 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+# A framework to run regression tests on mesh modifiers and operators based on howardt's mesh_ops_test.py
+#
+# General idea:
+# A test is:
+# Object mode
+# Select <test_object>
+# Duplicate the object
+# Select the object
+# Apply operation for each operation in <operations_stack> with given parameters
+# (an operation is either a modifier or an operator)
+# test_mesh = <test_object>.data
+# run test_mesh.unit_test_compare(<expected object>.data)
+# delete the duplicate object
+#
+# The words in angle brackets are parameters of the test, and are specified in
+# the main class MeshTest.
+#
+# If the environment variable BLENDER_TEST_UPDATE is set to 1, the <expected_object>
+# is updated with the new test result.
+# Tests are verbose when the environment variable BLENDER_VERBOSE is set.
+
+
+import bpy
+import os
+import inspect
+
+
+class ModifierSpec:
+ """
+ Holds one modifier and its parameters.
+ """
+
+ def __init__(self, modifier_name: str, modifier_type: str, modifier_parameters: dict):
+ """
+ Constructs a modifier spec.
+ :param modifier_name: str - name of object modifier, e.g. "myFirstSubsurfModif"
+ :param modifier_type: str - type of object modifier, e.g. "SUBSURF"
+ :param modifier_parameters: dict - {name : val} dictionary giving modifier parameters, e.g. {"quality" : 4}
+ """
+ self.modifier_name = modifier_name
+ self.modifier_type = modifier_type
+ self.modifier_parameters = modifier_parameters
+
+ def __str__(self):
+ return "Modifier: " + self.modifier_name + " of type " + self.modifier_type + \
+ " with parameters: " + str(self.modifier_parameters)
+
+
+class OperatorSpec:
+ """
+ Holds one operator and its parameters.
+ """
+
+ def __init__(self, operator_name: str, operator_parameters: dict, select_mode: str, selection: set):
+ """
+ Constructs an operatorSpec. Raises ValueError if selec_mode is invalid.
+ :param operator_name: str - name of mesh operator from bpy.ops.mesh, e.g. "bevel" or "fill"
+ :param operator_parameters: dict - {name : val} dictionary containing operator parameters.
+ :param select_mode: str - mesh selection mode, must be either 'VERT', 'EDGE' or 'FACE'
+ :param selection: set - set of vertices/edges/faces indices to select, e.g. [0, 9, 10].
+ """
+ self.operator_name = operator_name
+ self.operator_parameters = operator_parameters
+ if select_mode not in ['VERT', 'EDGE', 'FACE']:
+ raise ValueError("select_mode must be either {}, {} or {}".format('VERT', 'EDGE', 'FACE'))
+ self.select_mode = select_mode
+ self.selection = selection
+
+ def __str__(self):
+ return "Operator: " + self.operator_name + " with parameters: " + str(self.operator_parameters) + \
+ " in selection mode: " + self.select_mode + ", selecting " + str(self.selection)
+
+
+class MeshTest:
+ """
+ A mesh testing class targeted at testing modifiers and operators on a single object.
+ It holds a stack of mesh operations, i.e. modifiers or operators. The test is executed using
+ the public method run_test().
+ """
+
+ def __init__(self, test_object_name: str, expected_object_name: str, operations_stack=None, apply_modifiers=False):
+ """
+ Constructs a MeshTest object. Raises a KeyError if objects with names expected_object_name
+ or test_object_name don't exist.
+ :param test_object: str - Name of object of mesh type to run the operations on.
+ :param expected_object: str - Name of object of mesh type that has the expected
+ geometry after running the operations.
+ :param operations_stack: list - stack holding operations to perform on the test_object.
+ :param apply_modifier: bool - True if we want to apply the modifiers right after adding them to the object.
+ This affects operations of type ModifierSpec only.
+ """
+ if operations_stack is None:
+ operations_stack = []
+ for operation in operations_stack:
+ if not (isinstance(operation, ModifierSpec) or isinstance(operation, OperatorSpec)):
+ raise ValueError("Expected operation of type {} or {}. Got {}".
+ format(type(ModifierSpec), type(OperatorSpec),
+ type(operation)))
+ self.operations_stack = operations_stack
+ self.apply_modifier = apply_modifiers
+
+ self.verbose = os.environ.get("BLENDER_VERBOSE") is not None
+ self.update = os.getenv('BLENDER_TEST_UPDATE') is not None
+
+ # Initialize test objects.
+ objects = bpy.data.objects
+ self.test_object = objects[test_object_name]
+ self.expected_object = objects[expected_object_name]
+ if self.verbose:
+ print("Found test object {}".format(test_object_name))
+ print("Found test object {}".format(expected_object_name))
+
+ # Private flag to indicate whether the blend file was updated after the test.
+ self._test_updated = False
+
+ def set_test_object(self, test_object_name):
+ """
+ Set test object for the test. Raises a KeyError if object with given name does not exist.
+ :param test_object_name: name of test object to run operations on.
+ """
+ objects = bpy.data.objects
+ self.test_object = objects[test_object_name]
+
+ def set_expected_object(self, expected_object_name):
+ """
+ Set expected object for the test. Raises a KeyError if object with given name does not exist
+ :param expected_object_name: Name of expected object.
+ """
+ objects = bpy.data.objects
+ self.expected_object = objects[expected_object_name]
+
+ def add_modifier(self, modifier_spec: ModifierSpec):
+ """
+ Add a modifier to the operations stack.
+ :param modifier_spec: modifier to add to the operations stack
+ """
+ self.operations_stack.append(modifier_spec)
+ if self.verbose:
+ print("Added modififier {}".format(modifier_spec))
+
+ def add_operator(self, operator_spec: OperatorSpec):
+ """
+ Adds an operator to the operations stack.
+ :param operator_spec: OperatorSpec - operator to add to the operations stack.
+ """
+ self.operations_stack.append(operator_spec)
+
+ def _on_failed_test(self, compare, evaluated_test_object):
+ if self.update:
+ if self.verbose:
+ print("Test failed expectantly. Updating expected mesh...")
+
+ # Replace expected object with object we ran operations on, i.e. evaluated_test_object.
+ evaluated_test_object.location = self.expected_object.location
+ expected_object_name = self.expected_object.name
+
+ bpy.data.objects.remove(self.expected_object, do_unlink=True)
+ evaluated_test_object.name = expected_object_name
+
+ # Save file
+ blend_file = bpy.data.filepath
+ bpy.ops.wm.save_as_mainfile(filepath=blend_file)
+
+ self._test_updated = True
+
+ # Set new expected object.
+ self.expected_object = evaluated_test_object
+ return True
+
+ else:
+ blender_file = bpy.data.filepath
+ print("Test failed with error: {}. Resulting object mesh '{}' did not match expected object '{}' "
+ "from file blender file {}".
+ format(compare, evaluated_test_object.name, self.expected_object.name, blender_file))
+
+ return False
+
+ def is_test_updated(self):
+ """
+ Check whether running the test with BLENDER_TEST_UPDATE actually modified the .blend test file.
+ :return: Bool - True if blend file has been updated. False otherwise.
+ """
+ return self._test_updated
+
+ def _apply_modifier(self, test_object, modifier_spec: ModifierSpec):
+ """
+ Add modifier to object and apply (if modifier_spec.apply_modifier is True)
+ :param test_object: bpy.types.Object - Blender object to apply modifier on.
+ :param modifier_spec: ModifierSpec - ModifierSpec object with parameters
+ """
+ modifier = test_object.modifiers.new(modifier_spec.modifier_name,
+ modifier_spec.modifier_type)
+ if self.verbose:
+ print("Created modifier '{}' of type '{}'.".
+ format(modifier_spec.modifier_name, modifier_spec.modifier_type))
+
+ for param_name in modifier_spec.modifier_parameters:
+ try:
+ setattr(modifier, param_name, modifier_spec.modifier_parameters[param_name])
+ if self.verbose:
+ print("\t set parameter '{}' with value '{}'".
+ format(param_name, modifier_spec.modifier_parameters[param_name]))
+ except AttributeError:
+ # Clean up first
+ bpy.ops.object.delete()
+ raise AttributeError("Modifier '{}' has no parameter named '{}'".
+ format(modifier_spec.modifier_type, param_name))
+
+ if self.apply_modifier:
+ bpy.ops.object.modifier_apply(modifier=modifier_spec.modifier_name)
+
+ def _apply_operator(self, test_object, operator: OperatorSpec):
+ """
+ Apply operator on test object.
+ :param test_object: bpy.types.Object - Blender object to apply operator on.
+ :param operator: OperatorSpec - OperatorSpec object with parameters.
+ """
+ mesh = test_object.data
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_all(action='DESELECT')
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Do selection.
+ bpy.context.tool_settings.mesh_select_mode = (operator.select_mode == 'VERT',
+ operator.select_mode == 'EDGE',
+ operator.select_mode == 'FACE')
+ for index in operator.selection:
+ if operator.select_mode == 'VERT':
+ mesh.vertices[index].select = True
+ elif operator.select_mode == 'EDGE':
+ mesh.edges[index].select = True
+ elif operator.select_mode == 'FACE':
+ mesh.polygons[index].select = True
+ else:
+ raise ValueError("Invalid selection mode")
+
+ # Apply operator in edit mode.
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_mode(type=operator.select_mode)
+ mesh_operator = getattr(bpy.ops.mesh, operator.operator_name)
+ if not mesh_operator:
+ raise AttributeError("No mesh operator {}".format(operator.operator_name))
+ retval = mesh_operator(**operator.operator_parameters)
+ if retval != {'FINISHED'}:
+ raise RuntimeError("Unexpected operator return value: {}".format(retval))
+ if self.verbose:
+ print("Applied operator {}".format(operator))
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ def run_test(self):
+ """
+ Apply operations in self.operations_stack on self.test_object and compare the
+ resulting mesh with self.expected_object.data
+ :return: bool - True if the test passed, False otherwise.
+ """
+ self._test_updated = False
+ bpy.context.view_layer.objects.active = self.test_object
+
+ # Duplicate test object.
+ bpy.ops.object.mode_set(mode="OBJECT")
+ bpy.ops.object.select_all(action="DESELECT")
+ bpy.context.view_layer.objects.active = self.test_object
+
+ self.test_object.select_set(True)
+ bpy.ops.object.duplicate()
+ evaluated_test_object = bpy.context.active_object
+ evaluated_test_object.name = "evaluated_object"
+ if self.verbose:
+ print(evaluated_test_object.name, "is set to active")
+
+ # Add modifiers and operators.
+ for operation in self.operations_stack:
+ if isinstance(operation, ModifierSpec):
+ self._apply_modifier(evaluated_test_object, operation)
+
+ elif isinstance(operation, OperatorSpec):
+ self._apply_operator(evaluated_test_object, operation)
+ else:
+ raise ValueError("Expected operation of type {} or {}. Got {}".
+ format(type(ModifierSpec), type(OperatorSpec),
+ type(operation)))
+
+ # Compare resulting mesh with expected one.
+ if self.verbose:
+ print("Comparing expected mesh with resulting mesh...")
+ evaluated_test_mesh = evaluated_test_object.data
+ expected_mesh = self.expected_object.data
+ compare = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh)
+ success = (compare == 'Same')
+
+ if success:
+ if self.verbose:
+ print("Success!")
+
+ # Clean up.
+ if self.verbose:
+ print("Cleaning up...")
+ # Delete evaluated_test_object.
+ bpy.ops.object.delete()
+ return True
+
+ else:
+ return self._on_failed_test(compare, evaluated_test_object)
+
+
+class OperatorTest:
+ """
+ Helper class that stores and executes operator tests.
+
+ Example usage:
+
+ >>> tests = [
+ >>> ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_1', 'intersect_boolean', {'operation': 'UNION'}],
+ >>> ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_2', 'intersect_boolean', {'operation': 'INTERSECT'}],
+ >>> ]
+ >>> operator_test = OperatorTest(tests)
+ >>> operator_test.run_all_tests()
+ """
+
+ def __init__(self, operator_tests):
+ """
+ Constructs an operator test.
+ :param operator_tests: list - list of operator test cases. Each element in the list must contain the following
+ in the correct order:
+ 1) select_mode: str - mesh selection mode, must be either 'VERT', 'EDGE' or 'FACE'
+ 2) selection: set - set of vertices/edges/faces indices to select, e.g. [0, 9, 10].
+ 3) test_object_name: bpy.Types.Object - test object
+ 4) expected_object_name: bpy.Types.Object - expected object
+ 5) operator_name: str - name of mesh operator from bpy.ops.mesh, e.g. "bevel" or "fill"
+ 6) operator_parameters: dict - {name : val} dictionary containing operator parameters.
+ """
+ self.operator_tests = operator_tests
+ self.verbose = os.environ.get("BLENDER_VERBOSE") is not None
+ self._failed_tests_list = []
+
+ def run_test(self, index: int):
+ """
+ Run a single test from operator_tests list
+ :param index: int - index of test
+ :return: bool - True if test is successful. False otherwise.
+ """
+ case = self.operator_tests[index]
+ if len(case) != 6:
+ raise ValueError("Expected exactly 6 parameters for each test case, got {}".format(len(case)))
+ select_mode = case[0]
+ selection = case[1]
+ test_object_name = case[2]
+ expected_object_name = case[3]
+ operator_name = case[4]
+ operator_parameters = case[5]
+
+ operator_spec = OperatorSpec(operator_name, operator_parameters, select_mode, selection)
+
+ test = MeshTest(test_object_name, expected_object_name)
+ test.add_operator(operator_spec)
+
+ success = test.run_test()
+ if test.is_test_updated():
+ # Run the test again if the blend file has been updated.
+ success = test.run_test()
+ return success
+
+ def run_all_tests(self):
+ for index, _ in enumerate(self.operator_tests):
+ if self.verbose:
+ print()
+ print("Running test {}...".format(index))
+ success = self.run_test(index)
+
+ if not success:
+ self._failed_tests_list.append(index)
+
+ if len(self._failed_tests_list) != 0:
+ print("Following tests failed: {}".format(self._failed_tests_list))
+
+ blender_path = bpy.app.binary_path
+ blend_path = bpy.data.filepath
+ frame = inspect.stack()[1]
+ module = inspect.getmodule(frame[0])
+ python_path = module.__file__
+
+ print("Run following command to open Blender and run the failing test:")
+ print("{} {} --python {} -- {} {}"
+ .format(blender_path, blend_path, python_path, "--run-test", "<test_index>"))
+
+ raise Exception("Tests {} failed".format(self._failed_tests_list))
+
+
+class ModifierTest:
+ """
+ Helper class that stores and executes modifier tests.
+
+ Example usage:
+
+ >>> modifier_list = [
+ >>> ModifierSpec("firstSUBSURF", "SUBSURF", {"quality": 5}),
+ >>> ModifierSpec("firstSOLIDIFY", "SOLIDIFY", {"thickness_clamp": 0.9, "thickness": 1})
+ >>> ]
+ >>> tests = [
+ >>> ["testCube", "expectedCube", modifier_list],
+ >>> ["testCube_2", "expectedCube_2", modifier_list]
+ >>> ]
+ >>> modifiers_test = ModifierTest(tests)
+ >>> modifiers_test.run_all_tests()
+ """
+
+ def __init__(self, modifier_tests: list, apply_modifiers=False):
+ """
+ Construct a modifier test.
+ :param modifier_tests: list - list of modifier test cases. Each element in the list must contain the following
+ in the correct order:
+ 1) test_object_name: bpy.Types.Object - test object
+ 2) expected_object_name: bpy.Types.Object - expected object
+ 3) modifiers: list - list of mesh_test.ModifierSpec objects.
+ """
+ self.modifier_tests = modifier_tests
+ self.apply_modifiers = apply_modifiers
+ self.verbose = os.environ.get("BLENDER_VERBOSE") is not None
+ self._failed_tests_list = []
+
+ def run_test(self, index: int):
+ """
+ Run a single test from self.modifier_tests list
+ :param index: int - index of test
+ :return: bool - True if test passed, False otherwise.
+ """
+ case = self.modifier_tests[index]
+ if len(case) != 3:
+ raise ValueError("Expected exactly 3 parameters for each test case, got {}".format(len(case)))
+ test_object_name = case[0]
+ expected_object_name = case[1]
+ spec_list = case[2]
+
+ test = MeshTest(test_object_name, expected_object_name)
+ if self.apply_modifiers:
+ test.apply_modifier = True
+
+ for modifier_spec in spec_list:
+ test.add_modifier(modifier_spec)
+
+ success = test.run_test()
+ if test.is_test_updated():
+ # Run the test again if the blend file has been updated.
+ success = test.run_test()
+
+ return success
+
+ def run_all_tests(self):
+ """
+ Run all tests in self.modifiers_tests list. Raises an exception if one the tests fails.
+ """
+ for index, _ in enumerate(self.modifier_tests):
+ if self.verbose:
+ print()
+ print("Running test {}...\n".format(index))
+ success = self.run_test(index)
+
+ if not success:
+ self._failed_tests_list.append(index)
+
+ if len(self._failed_tests_list) != 0:
+ print("Following tests failed: {}".format(self._failed_tests_list))
+
+ blender_path = bpy.app.binary_path
+ blend_path = bpy.data.filepath
+ frame = inspect.stack()[1]
+ module = inspect.getmodule(frame[0])
+ python_path = module.__file__
+
+ print("Run following command to open Blender and run the failing test:")
+ print("{} {} --python {} -- {} {}"
+ .format(blender_path, blend_path, python_path, "--run-test", "<test_index>"))
+
+ raise Exception("Tests {} failed".format(self._failed_tests_list))
diff --git a/tests/python/operators.py b/tests/python/operators.py
new file mode 100644
index 00000000000..c5b3ac745c6
--- /dev/null
+++ b/tests/python/operators.py
@@ -0,0 +1,172 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+import bpy
+import os
+import sys
+from random import shuffle, seed
+
+seed(0)
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import OperatorTest, OperatorSpec
+
+# Central vertical loop of Suzanne
+MONKEY_LOOP_VERT = {68, 69, 71, 73, 74, 75, 76, 77, 90, 129, 136, 175, 188, 189, 198, 207,
+ 216, 223, 230, 301, 302, 303, 304, 305, 306, 307, 308}
+MONKEY_LOOP_EDGE = {131, 278, 299, 305, 307, 334, 337, 359, 384, 396, 399, 412, 415, 560,
+ 567, 572, 577, 615, 622, 627, 632, 643, 648, 655, 660, 707}
+
+
+def main():
+ tests = [
+ #### 0
+ # bisect
+ ['FACE', {0, 1, 2, 3, 4, 5}, "testCubeBisect", "expectedCubeBisect", "bisect",
+ {"plane_co": (0, 0, 0), "plane_no": (0, 1, 1), "clear_inner": True, "use_fill": True}],
+
+ # blend from shape
+ ['FACE', {0, 1, 2, 3, 4, 5}, "testCubeBlendFromShape", "expectedCubeBlendFromShape", "blend_from_shape",
+ {"shape": "Key 1"}],
+
+ # bridge edge loops
+ ["FACE", {0, 1}, "testCubeBrigeEdgeLoop", "expectedCubeBridgeEdgeLoop", "bridge_edge_loops", {}],
+
+ # decimate
+ ["FACE", {i for i in range(500)}, "testMonkeyDecimate", "expectedMonkeyDecimate", "decimate", {"ratio": 0.1}],
+
+ ### 4
+ # delete
+ ["VERT", {3}, "testCubeDeleteVertices", "expectedCubeDeleteVertices", "delete", {}],
+ ["FACE", {0}, "testCubeDeleteFaces", "expectedCubeDeleteFaces", "delete", {}],
+ ["EDGE", {0, 1, 2, 3}, "testCubeDeleteEdges", "expectedCubeDeleteEdges", "delete", {}],
+
+ # delete edge loop
+ ["VERT", MONKEY_LOOP_VERT, "testMokneyDeleteEdgeLoopVertices", "expectedMonkeyDeleteEdgeLoopVertices",
+ "delete_edgeloop", {}],
+ ["EDGE", MONKEY_LOOP_EDGE, "testMokneyDeleteEdgeLoopEdges", "expectedMonkeyDeleteEdgeLoopEdges",
+ "delete_edgeloop", {}],
+
+ ### 9
+ # delete loose
+ ["VERT", {i for i in range(12)}, "testCubeDeleteLooseVertices", "expectedCubeDeleteLooseVertices",
+ "delete_loose", {"use_verts": True, "use_edges": False, "use_faces": False}],
+ ["EDGE", {i for i in range(14)}, "testCubeDeleteLooseEdges", "expectedCubeDeleteLooseEdges",
+ "delete_loose", {"use_verts": False, "use_edges": True, "use_faces": False}],
+ ["FACE", {i for i in range(7)}, "testCubeDeleteLooseFaces", "expectedCubeDeleteLooseFaces",
+ "delete_loose", {"use_verts": False, "use_edges": False, "use_faces": True}],
+
+ # dissolve degenerate
+ ["VERT", {i for i in range(8)}, "testCubeDissolveDegenerate", "expectedCubeDissolveDegenerate",
+ "dissolve_degenerate", {}],
+
+ ### 13
+ # dissolve edges
+ ["EDGE", {0, 5, 6, 9}, "testCylinderDissolveEdges", "expectedCylinderDissolveEdges",
+ "dissolve_edges", {}],
+
+ # dissolve faces
+ ["VERT", {5, 34, 47, 49, 83, 91, 95}, "testCubeDissolveFaces", "expectedCubeDissolveFaces", "dissolve_faces",
+ {}],
+
+ ### 15
+ # dissolve verts
+ ["VERT", {16, 20, 22, 23, 25}, "testCubeDissolveVerts", "expectedCubeDissolveVerts", "dissolve_verts", {}],
+
+ # duplicate
+ ["VERT", {i for i in range(33)} - {23}, "testConeDuplicateVertices", "expectedConeDuplicateVertices",
+ "duplicate", {}],
+ ["VERT", {23}, "testConeDuplicateOneVertex", "expectedConeDuplicateOneVertex", "duplicate", {}],
+ ["FACE", {6, 9}, "testConeDuplicateFaces", "expectedConeDuplicateFaces", "duplicate", {}],
+ ["EDGE", {i for i in range(64)}, "testConeDuplicateEdges", "expectedConeDuplicateEdges", "duplicate", {}],
+
+ ### 20
+ # edge collapse
+ ["EDGE", {1, 9, 4}, "testCylinderEdgeCollapse", "expectedCylinderEdgeCollapse", "edge_collapse", {}],
+
+ # edge face add
+ ["VERT", {1, 3, 4, 5, 7}, "testCubeEdgeFaceAddFace", "expectedCubeEdgeFaceAddFace", "edge_face_add", {}],
+ ["VERT", {4, 5}, "testCubeEdgeFaceAddEdge", "expectedCubeEdgeFaceAddEdge", "edge_face_add", {}],
+
+ # edge rotate
+ ["EDGE", {1}, "testCubeEdgeRotate", "expectedCubeEdgeRotate", "edge_rotate", {}],
+
+ # edge split
+ ["EDGE", {2, 5, 8, 11, 14, 17, 20, 23}, "testCubeEdgeSplit", "expectedCubeEdgeSplit", "edge_split", {}],
+
+ ### 25
+ # face make planar
+ ["FACE", {i for i in range(500)}, "testMonkeyFaceMakePlanar", "expectedMonkeyFaceMakePlanar",
+ "face_make_planar", {}],
+
+ # face split by edges
+ ["VERT", {i for i in range(6)}, "testPlaneFaceSplitByEdges", "expectedPlaneFaceSplitByEdges",
+ "face_split_by_edges", {}],
+
+ # fill
+ ["EDGE", {20, 21, 22, 23, 24, 45, 46, 47, 48, 49}, "testIcosphereFill", "expectedIcosphereFill",
+ "fill", {}],
+ ["EDGE", {20, 21, 22, 23, 24, 45, 46, 47, 48, 49}, "testIcosphereFillUseBeautyFalse",
+ "expectedIcosphereFillUseBeautyFalse", "fill", {"use_beauty": False}],
+
+ # fill grid
+ ["EDGE", {1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 15}, "testPlaneFillGrid", "expectedPlaneFillGrid",
+ "fill_grid", {}],
+ ["EDGE", {1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 15}, "testPlaneFillGridSimpleBlending",
+ "expectedPlaneFillGridSimpleBlending", "fill_grid", {"use_interp_simple": True}],
+
+ ### 31
+ # fill holes
+ ["VERT", {i for i in range(481)}, "testSphereFillHoles", "expectedSphereFillHoles", "fill_holes", {"sides": 9}],
+
+ # inset faces
+ ["VERT", {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95}, "testCubeInset",
+ "expectedCubeInset", "inset", {"thickness": 0.2}],
+ ["VERT", {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95},
+ "testCubeInsetEvenOffsetFalse", "expectedCubeInsetEvenOffsetFalse",
+ "inset", {"thickness": 0.2, "use_even_offset": False}],
+ ["VERT", {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95}, "testCubeInsetDepth",
+ "expectedCubeInsetDepth", "inset", {"thickness": 0.2, "depth": 0.2}],
+ ["FACE", {35, 36, 37, 45, 46, 47, 55, 56, 57}, "testGridInsetRelativeOffset", "expectedGridInsetRelativeOffset",
+ "inset", {"thickness": 0.4, "use_relative_offset": True}],
+ ]
+
+ operators_test = OperatorTest(tests)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ operators_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ operators_test.apply_modifiers = False
+ index = int(command[i + 1])
+ operators_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except:
+ import traceback
+
+ traceback.print_exc()
+ sys.exit(1)