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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYimingWu <xp8110@outlook.com>2019-11-02 08:53:39 +0300
committerYimingWu <xp8110@outlook.com>2019-11-02 08:53:39 +0300
commitc30aaff302e0d64ca11939a18d00460c3e656293 (patch)
tree4d638ef7d6de3dfb90b0086d658c079a9e851ca9
parentb475daeb04098ecdad22ec91cae9d5fefdffca38 (diff)
parent9da7a0f8bf1403b96452d58f232f47adbbe0876b (diff)
Merge remote-tracking branch 'origin/master' into temp-npr-gpencil-modifiers
-rw-r--r--GNUmakefile6
-rwxr-xr-xbuild_files/utils/make_source_archive.sh (renamed from build_files/utils/build_tgz.sh)17
-rw-r--r--build_files/windows/check_libraries.cmd4
-rwxr-xr-xdoc/manpage/blender.1.py2
-rw-r--r--doc/python_api/examples/bpy.app.timers.1.py2
-rw-r--r--doc/python_api/examples/bpy.app.timers.2.py2
-rw-r--r--doc/python_api/examples/bpy.app.timers.3.py2
-rw-r--r--doc/python_api/examples/bpy.app.timers.4.py2
-rw-r--r--doc/python_api/examples/bpy.types.Depsgraph.6.py2
-rw-r--r--doc/python_api/examples/bpy.types.RenderEngine.py16
-rw-r--r--intern/cycles/blender/addon/properties.py4
-rw-r--r--intern/cycles/blender/addon/ui.py2
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerWin32.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsWin32.cpp17
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_TaskbarWin32.h4
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator.cc13
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc287
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator_internal.h13
-rw-r--r--intern/opensubdiv/opensubdiv_capi_type.h7
-rw-r--r--intern/opensubdiv/opensubdiv_evaluator_capi.h14
-rw-r--r--release/datafiles/icons/ops.gpencil.primitive_polyline.datbin0 -> 674 bytes
-rw-r--r--release/datafiles/icons/ops.paint.eyedropper_add.datbin0 -> 962 bytes
-rw-r--r--release/scripts/modules/bpy/utils/__init__.py35
-rw-r--r--release/scripts/startup/bl_operators/add_mesh_torus.py3
-rw-r--r--release/scripts/startup/bl_operators/presets.py6
-rw-r--r--release/scripts/startup/bl_operators/sequencer.py10
-rw-r--r--release/scripts/startup/bl_operators/userpref.py4
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_follow_active.py5
-rw-r--r--release/scripts/startup/bl_operators/wm.py83
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py12
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py2
-rw-r--r--release/scripts/startup/bl_ui/space_image.py8
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py6
-rw-r--r--release/scripts/startup/bl_ui/space_text.py5
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py13
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py12
-rw-r--r--source/blender/blenkernel/intern/brush.c1
-rw-r--r--source/blender/blenlib/BLI_task.h40
-rw-r--r--source/blender/blenlib/intern/task.c362
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc83
-rw-r--r--source/blender/draw/modes/object_mode.c45
-rw-r--r--source/blender/draw/modes/sculpt_mode.c2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h2
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin.c5
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c5
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c2
-rw-r--r--source/blender/editors/render/render_view.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c7
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_image/image_undo.c20
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c77
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h30
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c133
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c17
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c43
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c86
-rw-r--r--source/blender/editors/transform/transform_snap.c4
-rw-r--r--source/blender/editors/transform/transform_snap_object.c186
-rw-r--r--source/blender/makesdna/DNA_brush_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_brush_types.h10
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_brush.c5
-rw-r--r--source/blender/makesrna/intern/rna_scene.c5
-rw-r--r--tests/gtests/blenlib/BLI_task_performance_test.cc32
-rw-r--r--tests/gtests/blenlib/BLI_task_test.cc10
77 files changed, 1318 insertions, 557 deletions
diff --git a/GNUmakefile b/GNUmakefile
index e52fd38a7e3..2c7856db7b4 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -118,7 +118,7 @@ Utilities
Example
make icons_geom BLENDER_BIN=/path/to/blender
- * tgz:
+ * source_archive:
Create a compressed archive of the source code.
* update:
@@ -525,8 +525,8 @@ check_descriptions: .FORCE
# Utilities
#
-tgz: .FORCE
- ./build_files/utils/build_tgz.sh
+source_archive: .FORCE
+ ./build_files/utils/make_source_archive.sh
INKSCAPE_BIN?="inkscape"
icons: .FORCE
diff --git a/build_files/utils/build_tgz.sh b/build_files/utils/make_source_archive.sh
index 63c3264b18e..cafd1c31486 100755
--- a/build_files/utils/build_tgz.sh
+++ b/build_files/utils/make_source_archive.sh
@@ -20,7 +20,7 @@ else
fi
MANIFEST="blender-$VERSION-manifest.txt"
-TARBALL="blender-$VERSION.tar.gz"
+TARBALL="blender-$VERSION.tar.xz"
cd "$blender_srcdir"
@@ -51,19 +51,26 @@ echo "OK"
# Create the tarball
+#
+# Without owner/group args, extracting the files as root will
+# use ownership from the tar archive.
cd "$blender_srcdir"
echo -n "Creating archive: \"$BASE_DIR/$TARBALL\" ..."
-tar --transform "s,^,blender-$VERSION/,g" \
- --use-compress-program="gzip --best" \
+tar \
+ --transform "s,^,blender-$VERSION/,g" \
+ --use-compress-program="xz -9" \
--create \
--file="$BASE_DIR/$TARBALL" \
- --files-from="$BASE_DIR/$MANIFEST"
+ --files-from="$BASE_DIR/$MANIFEST" \
+ --owner=0 \
+ --group=0
+
echo "OK"
# Create checksum file
cd "$BASE_DIR"
-echo -n "Creating checksum: \"$BASE_DIR/$TARBALL.md5sum\" ..."
+echo -n "Creating checksum: \"$BASE_DIR/$TARBALL.md5sum\" ..."
md5sum "$TARBALL" > "$TARBALL.md5sum"
echo "OK"
diff --git a/build_files/windows/check_libraries.cmd b/build_files/windows/check_libraries.cmd
index b838c7d7d19..24b30c6a9b0 100644
--- a/build_files/windows/check_libraries.cmd
+++ b/build_files/windows/check_libraries.cmd
@@ -10,7 +10,6 @@ if NOT "%verbose%" == "" (
)
if NOT EXIST %BUILD_VS_LIBDIR% (
rem libs not found, but svn is on the system
- echo
if not "%SVN%"=="" (
echo.
echo The required external libraries in %BUILD_VS_LIBDIR% are missing
@@ -55,5 +54,8 @@ if NOT EXIST %BUILD_VS_LIBDIR% (
echo Error: Required libraries not found at "%BUILD_VS_LIBDIR%"
echo This is needed for building, aborting!
echo.
+ if "%SVN%"=="" (
+ echo This is most likely caused by svn.exe not being available.
+ )
exit /b 1
) \ No newline at end of file
diff --git a/doc/manpage/blender.1.py b/doc/manpage/blender.1.py
index fc2200ab859..da83abe8442 100755
--- a/doc/manpage/blender.1.py
+++ b/doc/manpage/blender.1.py
@@ -62,7 +62,7 @@ if blender_date is None:
# Happens when built without WITH_BUILD_INFO e.g.
date_string = time.strftime("%B %d, %Y", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
else:
- blender_date = blender_date.strip().partition(" ")[2] # remove 'date:' prefix
+ blender_date = blender_date.strip().partition(" ")[2] # remove 'date:' prefix
date_string = time.strftime("%B %d, %Y", time.strptime(blender_date, "%Y-%m-%d"))
outfile = open(outfilename, "w")
diff --git a/doc/python_api/examples/bpy.app.timers.1.py b/doc/python_api/examples/bpy.app.timers.1.py
index bae3b94b24a..a8ce7fde552 100644
--- a/doc/python_api/examples/bpy.app.timers.1.py
+++ b/doc/python_api/examples/bpy.app.timers.1.py
@@ -4,7 +4,9 @@ Run a Function in x Seconds
"""
import bpy
+
def in_5_seconds():
print("Hello World")
+
bpy.app.timers.register(in_5_seconds, first_interval=5)
diff --git a/doc/python_api/examples/bpy.app.timers.2.py b/doc/python_api/examples/bpy.app.timers.2.py
index c663959c209..e17d43cccd8 100644
--- a/doc/python_api/examples/bpy.app.timers.2.py
+++ b/doc/python_api/examples/bpy.app.timers.2.py
@@ -4,8 +4,10 @@ Run a Function every x Seconds
"""
import bpy
+
def every_2_seconds():
print("Hello World")
return 2.0
+
bpy.app.timers.register(every_2_seconds)
diff --git a/doc/python_api/examples/bpy.app.timers.3.py b/doc/python_api/examples/bpy.app.timers.3.py
index 79daf6a7740..a738f9ca01c 100644
--- a/doc/python_api/examples/bpy.app.timers.3.py
+++ b/doc/python_api/examples/bpy.app.timers.3.py
@@ -6,6 +6,7 @@ import bpy
counter = 0
+
def run_10_times():
global counter
counter += 1
@@ -14,4 +15,5 @@ def run_10_times():
return None
return 0.1
+
bpy.app.timers.register(run_10_times)
diff --git a/doc/python_api/examples/bpy.app.timers.4.py b/doc/python_api/examples/bpy.app.timers.4.py
index 6cdee564bb5..c14bc15166c 100644
--- a/doc/python_api/examples/bpy.app.timers.4.py
+++ b/doc/python_api/examples/bpy.app.timers.4.py
@@ -5,8 +5,10 @@ Assign parameters to functions
import bpy
import functools
+
def print_message(message):
print("Message:", message)
+
bpy.app.timers.register(functools.partial(print_message, "Hello"), first_interval=2.0)
bpy.app.timers.register(functools.partial(print_message, "World"), first_interval=3.0)
diff --git a/doc/python_api/examples/bpy.types.Depsgraph.6.py b/doc/python_api/examples/bpy.types.Depsgraph.6.py
index 56e028e8813..1f809356b13 100644
--- a/doc/python_api/examples/bpy.types.Depsgraph.6.py
+++ b/doc/python_api/examples/bpy.types.Depsgraph.6.py
@@ -29,7 +29,7 @@ class OBJECT_OT_simple_exporter(bpy.types.Operator):
# Happens for non-geometry objects.
continue
print(f"Exporting mesh with {len(mesh.vertices)} vertices "
- f"at {object_instance.matrix_world}")
+ f"at {object_instance.matrix_world}")
object_instace.to_mesh_clear()
return {'FINISHED'}
diff --git a/doc/python_api/examples/bpy.types.RenderEngine.py b/doc/python_api/examples/bpy.types.RenderEngine.py
index 86ab4b3097d..45910194244 100644
--- a/doc/python_api/examples/bpy.types.RenderEngine.py
+++ b/doc/python_api/examples/bpy.types.RenderEngine.py
@@ -101,7 +101,7 @@ class CustomRenderEngine(bpy.types.RenderEngine):
# Bind shader that converts from scene linear to display space,
bgl.glEnable(bgl.GL_BLEND)
- bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ONE_MINUS_SRC_ALPHA);
+ bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ONE_MINUS_SRC_ALPHA)
self.bind_display_space_shader(scene)
if not self.draw_data or self.draw_data.dimensions != dimensions:
@@ -135,18 +135,18 @@ class CustomDrawData:
# Bind shader that converts from scene linear to display space,
# use the scene's color management settings.
shader_program = bgl.Buffer(bgl.GL_INT, 1)
- bgl.glGetIntegerv(bgl.GL_CURRENT_PROGRAM, shader_program);
+ bgl.glGetIntegerv(bgl.GL_CURRENT_PROGRAM, shader_program)
# Generate vertex array
self.vertex_array = bgl.Buffer(bgl.GL_INT, 1)
bgl.glGenVertexArrays(1, self.vertex_array)
bgl.glBindVertexArray(self.vertex_array[0])
- texturecoord_location = bgl.glGetAttribLocation(shader_program[0], "texCoord");
- position_location = bgl.glGetAttribLocation(shader_program[0], "pos");
+ texturecoord_location = bgl.glGetAttribLocation(shader_program[0], "texCoord")
+ position_location = bgl.glGetAttribLocation(shader_program[0], "pos")
- bgl.glEnableVertexAttribArray(texturecoord_location);
- bgl.glEnableVertexAttribArray(position_location);
+ bgl.glEnableVertexAttribArray(texturecoord_location)
+ bgl.glEnableVertexAttribArray(position_location)
# Generate geometry buffers for drawing textured quad
position = [0.0, 0.0, width, 0.0, width, height, 0.0, height]
@@ -178,7 +178,7 @@ class CustomDrawData:
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.texture[0])
bgl.glBindVertexArray(self.vertex_array[0])
- bgl.glDrawArrays(bgl.GL_TRIANGLE_FAN, 0, 4);
+ bgl.glDrawArrays(bgl.GL_TRIANGLE_FAN, 0, 4)
bgl.glBindVertexArray(0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, 0)
@@ -201,6 +201,7 @@ def get_panels():
return panels
+
def register():
# Register the RenderEngine
bpy.utils.register_class(CustomRenderEngine)
@@ -208,6 +209,7 @@ def register():
for panel in get_panels():
panel.COMPAT_ENGINES.add('CUSTOM')
+
def unregister():
bpy.utils.unregister_class(CustomRenderEngine)
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 840ab557132..26e1a6a223a 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -1467,9 +1467,11 @@ class CyclesPreferences(bpy.types.AddonPreferences):
devices.extend(cpu_devices)
return devices
- # For backwards compatibility, only has CUDA and OpenCL.
+ # For backwards compatibility, only returns CUDA and OpenCL but still
+ # refreshes all devices.
def get_devices(self, compute_device_type=''):
cuda_devices = self.get_devices_for_type('CUDA')
+ self.get_devices_for_type('OPTIX')
opencl_devices = self.get_devices_for_type('OPENCL')
return cuda_devices, opencl_devices
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index b2624b2aa81..4ff154d4bcd 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -2166,7 +2166,7 @@ def draw_pause(self, context):
if view.shading.type == 'RENDERED':
cscene = scene.cycles
- layout.prop(cscene, "preview_pause", icon='PAUSE', text="")
+ layout.prop(cscene, "preview_pause", icon='PLAY' if cscene.preview_pause else 'PAUSE', text="")
def get_panels():
diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
index 3b28f055191..aabaffc7732 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
@@ -24,8 +24,6 @@
#include "GHOST_DisplayManagerWin32.h"
#include "GHOST_Debug.h"
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x501 // require Windows XP or newer
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
index bdc403b947e..63a6b7224b5 100644
--- a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
@@ -39,15 +39,16 @@ GHOST_SystemPathsWin32::~GHOST_SystemPathsWin32()
const GHOST_TUns8 *GHOST_SystemPathsWin32::getSystemDir(int, const char *versionstr) const
{
- static char knownpath[MAX_PATH * 3 + 128] = {
- 0}; /* 1 utf-16 might translante into 3 utf-8. 2 utf-16 translates into 4 utf-8*/
- wchar_t knownpath_16[MAX_PATH];
+ /* 1 utf-16 might translante into 3 utf-8. 2 utf-16 translates into 4 utf-8*/
+ static char knownpath[MAX_PATH * 3 + 128] = {0};
+ PWSTR knownpath_16 = NULL;
- HRESULT hResult = SHGetFolderPathW(
- NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath_16);
+ HRESULT hResult = SHGetKnownFolderPath(
+ FOLDERID_ProgramData, KF_FLAG_DEFAULT, NULL, &knownpath_16);
if (hResult == S_OK) {
conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3);
+ CoTaskMemFree(knownpath_16);
strcat(knownpath, "\\Blender Foundation\\Blender\\");
strcat(knownpath, versionstr);
return (GHOST_TUns8 *)knownpath;
@@ -59,12 +60,14 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getSystemDir(int, const char *version
const GHOST_TUns8 *GHOST_SystemPathsWin32::getUserDir(int, const char *versionstr) const
{
static char knownpath[MAX_PATH * 3 + 128] = {0};
- wchar_t knownpath_16[MAX_PATH];
+ PWSTR knownpath_16 = NULL;
- HRESULT hResult = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath_16);
+ HRESULT hResult = SHGetKnownFolderPath(
+ FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &knownpath_16);
if (hResult == S_OK) {
conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3);
+ CoTaskMemFree(knownpath_16);
strcat(knownpath, "\\Blender Foundation\\Blender\\");
strcat(knownpath, versionstr);
return (GHOST_TUns8 *)knownpath;
diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.h b/intern/ghost/intern/GHOST_SystemPathsWin32.h
index 49d241df633..f1924ea51bc 100644
--- a/intern/ghost/intern/GHOST_SystemPathsWin32.h
+++ b/intern/ghost/intern/GHOST_SystemPathsWin32.h
@@ -28,8 +28,6 @@
# error WIN32 only!
#endif // WIN32
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x501 // require Windows XP or newer
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
diff --git a/intern/ghost/intern/GHOST_TaskbarWin32.h b/intern/ghost/intern/GHOST_TaskbarWin32.h
index b1b81337494..abf1172cea8 100644
--- a/intern/ghost/intern/GHOST_TaskbarWin32.h
+++ b/intern/ghost/intern/GHOST_TaskbarWin32.h
@@ -24,10 +24,6 @@
# error WIN32 only!
#endif // WIN32
-/* require Windows XP or newer */
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x501
-
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlobj.h>
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator.cc b/intern/opensubdiv/internal/opensubdiv_evaluator.cc
index 2500691885c..4f5a1db82ca 100644
--- a/intern/opensubdiv/internal/opensubdiv_evaluator.cc
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator.cc
@@ -102,6 +102,17 @@ void evaluateLimit(OpenSubdiv_Evaluator *evaluator,
evaluator->internal->eval_output->evaluateLimit(ptex_face_index, face_u, face_v, P, dPdu, dPdv);
}
+void evaluatePatchesLimit(OpenSubdiv_Evaluator *evaluator,
+ const OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv)
+{
+ evaluator->internal->eval_output->evaluatePatchesLimit(
+ patch_coords, num_patch_coords, P, dPdu, dPdv);
+}
+
void evaluateVarying(OpenSubdiv_Evaluator *evaluator,
const int ptex_face_index,
float face_u,
@@ -137,6 +148,8 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
evaluator->evaluateLimit = evaluateLimit;
evaluator->evaluateVarying = evaluateVarying;
evaluator->evaluateFaceVarying = evaluateFaceVarying;
+
+ evaluator->evaluatePatchesLimit = evaluatePatchesLimit;
}
} // namespace
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
index fa45c0119ec..c5dd4509976 100644
--- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
@@ -54,109 +54,133 @@ using OpenSubdiv::Osd::CpuPatchTable;
using OpenSubdiv::Osd::CpuVertexBuffer;
using OpenSubdiv::Osd::PatchCoord;
-// TODO(sergey): Remove after official requirement bump for OSD version.
-#if OPENSUBDIV_VERSION_NUMBER >= 30200
-# define OPENSUBDIV_HAS_FVAR_EVALUATION
-#else
-# undef OPENSUBDIV_HAS_FVAR_EVALUATION
-#endif
-
namespace opensubdiv_capi {
namespace {
-// Helper class to wrap numerous of patch coordinates into a buffer.
-// Used to pass coordinates to the CPU evaluator. Other evaluators are not
-// supported.
-class PatchCoordBuffer : public vector<PatchCoord> {
+// Array implementation which stores small data on stack (or, rather, in the class itself).
+template<typename T, int kNumMaxElementsOnStack> class StackOrHeapArray {
public:
- static PatchCoordBuffer *Create(int size)
+ StackOrHeapArray()
+ : num_elements_(0), heap_elements_(NULL), num_heap_elements_(0), effective_elements_(NULL)
{
- PatchCoordBuffer *buffer = new PatchCoordBuffer();
- buffer->resize(size);
- return buffer;
}
- PatchCoord *BindCpuBuffer()
+ explicit StackOrHeapArray(int size) : StackOrHeapArray()
{
- return reinterpret_cast<PatchCoord *>(&(*this)[0]);
+ resize(size);
}
- int GetNumVertices()
+ ~StackOrHeapArray()
{
- return size();
+ delete[] heap_elements_;
}
- void UpdateData(const PatchCoord *patch_coords, int num_patch_coords)
+ int size() const
{
- memcpy(&(*this)[0],
- reinterpret_cast<const void *>(patch_coords),
- sizeof(PatchCoord) * num_patch_coords);
- }
-};
+ return num_elements_;
+ };
-// Helper class to wrap single of patch coord into a buffer. Used to pass
-// coordinates to the CPU evaluator. Other evaluators are not supported.
-class SinglePatchCoordBuffer {
- public:
- static SinglePatchCoordBuffer *Create()
+ T *data()
{
- return new SinglePatchCoordBuffer();
+ return effective_elements_;
}
- SinglePatchCoordBuffer()
+ void resize(int num_elements)
{
+ const int old_num_elements = num_elements_;
+ num_elements_ = num_elements;
+ // Early output if allcoation size did not change, or allocation size is smaller.
+ // We never re-allocate, sacrificing some memory over performance.
+ if (old_num_elements >= num_elements) {
+ return;
+ }
+ // Simple case: no previously allocated buffer, can simply do one allocation.
+ if (effective_elements_ == NULL) {
+ effective_elements_ = allocate(num_elements);
+ return;
+ }
+ // Make new allocation, and copy elements if needed.
+ T *old_buffer = effective_elements_;
+ effective_elements_ = allocate(num_elements);
+ if (old_buffer != effective_elements_) {
+ memcpy(effective_elements_, old_buffer, sizeof(T) * min(old_num_elements, num_elements));
+ }
+ if (old_buffer != stack_elements_) {
+ delete[] old_buffer;
+ }
}
- explicit SinglePatchCoordBuffer(const PatchCoord &patch_coord) : patch_coord_(patch_coord)
+ protected:
+ T *allocate(int num_elements)
{
+ if (num_elements < kNumMaxElementsOnStack) {
+ return stack_elements_;
+ }
+ heap_elements_ = new T[num_elements];
+ return heap_elements_;
}
- PatchCoord *BindCpuBuffer()
- {
- return &patch_coord_;
- }
+ // Number of elements in the buffer.
+ int num_elements_;
- int GetNumVertices()
+ // Elements which are allocated on a stack (or, rather, in the same allocation as the buffer
+ // itself).
+ // Is used as long as buffer is smaller than kNumMaxElementsOnStack.
+ T stack_elements_[kNumMaxElementsOnStack];
+
+ // Heap storage for buffer larger than kNumMaxElementsOnStack.
+ T *heap_elements_;
+ int num_heap_elements_;
+
+ // Depending on the current buffer size points to rither stack_elements_ or heap_elements_.
+ T *effective_elements_;
+};
+
+// 32 is a number of inner vertices along the patch size at subdivision level 6.
+typedef StackOrHeapArray<PatchCoord, 32 * 32> StackOrHeapPatchCoordArray;
+
+// Buffer which implements API required by OpenSubdiv and uses an existing memory as an underlying
+// storage.
+template<typename T> class RawDataWrapperBuffer {
+ public:
+ RawDataWrapperBuffer(T *data) : data_(data)
{
- return 1;
}
- void UpdateData(const PatchCoord &patch_coord)
+ T *BindCpuBuffer()
{
- patch_coord_ = patch_coord;
+ return data_;
}
+ // TODO(sergey): Support UpdateData().
+
protected:
- PatchCoord patch_coord_;
+ T *data_;
};
-// Helper class which is aimed to be used in cases when buffer is small enough
-// and better to be allocated in stack rather than in heap.
-//
-// TODO(sergey): Check if bare arrays could be used by CPU evaluator.
-template<int element_size, int num_vertices> class StackAllocatedBuffer {
+template<typename T> class RawDataWrapperVertexBuffer : public RawDataWrapperBuffer<T> {
public:
- static PatchCoordBuffer *Create(int /*size*/)
+ RawDataWrapperVertexBuffer(T *data, int num_vertices)
+ : RawDataWrapperBuffer<T>(data), num_vertices_(num_vertices)
{
- // TODO(sergey): Validate that requested size is smaller than static
- // stack memory size.
- return new StackAllocatedBuffer<element_size, num_vertices>();
- }
-
- float *BindCpuBuffer()
- {
- return &data_[0];
}
int GetNumVertices()
{
- return num_vertices;
+ return num_vertices_;
}
- // TODO(sergey): Support UpdateData().
protected:
- float data_[element_size * num_vertices];
+ int num_vertices_;
+};
+
+class ConstPatchCoordWrapperBuffer : public RawDataWrapperVertexBuffer<const PatchCoord> {
+ public:
+ ConstPatchCoordWrapperBuffer(const PatchCoord *data, int num_vertices)
+ : RawDataWrapperVertexBuffer(data, num_vertices)
+ {
+ }
};
template<typename EVAL_VERTEX_BUFFER,
@@ -217,11 +241,12 @@ class FaceVaryingVolatileEval {
device_context_);
}
- void evalPatch(const PatchCoord &patch_coord, float face_varying[2])
+ // NOTE: face_varying must point to a memory of at least float[2]*num_patch_coords.
+ void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *face_varying)
{
- StackAllocatedBuffer<2, 1> face_varying_data;
+ RawDataWrapperBuffer<float> face_varying_data(face_varying);
BufferDescriptor face_varying_desc(0, 2, 2);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
evaluator_cache_, src_face_varying_desc_, face_varying_desc, device_context_);
EVALUATOR::EvalPatchesFaceVarying(src_face_varying_data_,
@@ -234,8 +259,6 @@ class FaceVaryingVolatileEval {
face_varying_channel_,
eval_instance,
device_context_);
- const float *refined_face_varying = face_varying_data.BindCpuBuffer();
- memcpy(face_varying, refined_face_varying, sizeof(float) * 2);
}
protected:
@@ -297,7 +320,6 @@ class VolatileEvalOutput {
src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
patch_table_ = PATCH_TABLE::Create(patch_table, device_context_);
- patch_coords_ = NULL;
vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils,
device_context_);
varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils,
@@ -398,74 +420,66 @@ class VolatileEvalOutput {
}
}
- void evalPatchCoord(const PatchCoord &patch_coord, float P[3])
+ // NOTE: P must point to a memory of at least float[3]*num_patch_coords.
+ void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *P)
{
- StackAllocatedBuffer<6, 1> vertex_data;
- // TODO(sergey): Varying data is interleaved in vertex array, so need to
- // adjust stride if there is a varying data.
- // BufferDescriptor vertex_desc(0, 3, 6);
- BufferDescriptor vertex_desc(0, 3, 3);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ RawDataWrapperBuffer<float> P_data(P);
+ // TODO(sergey): Support interleaved vertex-varying data.
+ BufferDescriptor P_desc(0, 3, 3);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_desc_, vertex_desc, device_context_);
+ evaluator_cache_, src_desc_, P_desc, device_context_);
EVALUATOR::EvalPatches(src_data_,
src_desc_,
- &vertex_data,
- vertex_desc,
+ &P_data,
+ P_desc,
patch_coord_buffer.GetNumVertices(),
&patch_coord_buffer,
patch_table_,
eval_instance,
device_context_);
- const float *refined_vertices = vertex_data.BindCpuBuffer();
- memcpy(P, refined_vertices, sizeof(float) * 3);
}
- void evalPatchesWithDerivatives(const PatchCoord &patch_coord,
- float P[3],
- float dPdu[3],
- float dPdv[3])
+ // NOTE: P, dPdu, dPdv must point to a memory of at least float[3]*num_patch_coords.
+ void evalPatchesWithDerivatives(const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv)
{
- StackAllocatedBuffer<6, 1> vertex_data, derivatives;
- // TODO(sergey): Varying data is interleaved in vertex array, so need to
- // adjust stride if there is a varying data.
- // BufferDescriptor vertex_desc(0, 3, 6);
- BufferDescriptor vertex_desc(0, 3, 3);
- BufferDescriptor du_desc(0, 3, 6), dv_desc(3, 3, 6);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ assert(dPdu);
+ assert(dPdv);
+ RawDataWrapperBuffer<float> P_data(P);
+ RawDataWrapperBuffer<float> dPdu_data(dPdu), dPdv_data(dPdv);
+ // TODO(sergey): Support interleaved vertex-varying data.
+ BufferDescriptor P_desc(0, 3, 3);
+ BufferDescriptor dpDu_desc(0, 3, 3), pPdv_desc(0, 3, 3);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_desc_, vertex_desc, du_desc, dv_desc, device_context_);
+ evaluator_cache_, src_desc_, P_desc, dpDu_desc, pPdv_desc, device_context_);
EVALUATOR::EvalPatches(src_data_,
src_desc_,
- &vertex_data,
- vertex_desc,
- &derivatives,
- du_desc,
- &derivatives,
- dv_desc,
+ &P_data,
+ P_desc,
+ &dPdu_data,
+ dpDu_desc,
+ &dPdv_data,
+ pPdv_desc,
patch_coord_buffer.GetNumVertices(),
&patch_coord_buffer,
patch_table_,
eval_instance,
device_context_);
- const float *refined_vertices = vertex_data.BindCpuBuffer();
- memcpy(P, refined_vertices, sizeof(float) * 3);
- if (dPdu != NULL || dPdv != NULL) {
- const float *refined_derivatives = derivatives.BindCpuBuffer();
- if (dPdu != NULL) {
- memcpy(dPdu, refined_derivatives, sizeof(float) * 3);
- }
- if (dPdv != NULL) {
- memcpy(dPdv, refined_derivatives + 3, sizeof(float) * 3);
- }
- }
}
- void evalPatchVarying(const PatchCoord &patch_coord, float varying[3])
+ // NOTE: varying must point to a memory of at least float[3]*num_patch_coords.
+ void evalPatchesVarying(const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float *varying)
{
- StackAllocatedBuffer<6, 1> varying_data;
+ RawDataWrapperBuffer<float> varying_data(varying);
BufferDescriptor varying_desc(3, 3, 6);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
evaluator_cache_, src_varying_desc_, varying_desc, device_context_);
EVALUATOR::EvalPatchesVarying(src_varying_data_,
@@ -477,23 +491,22 @@ class VolatileEvalOutput {
patch_table_,
eval_instance,
device_context_);
- const float *refined_varying = varying_data.BindCpuBuffer();
- memcpy(varying, refined_varying, sizeof(float) * 3);
}
- void evalPatchFaceVarying(const int face_varying_channel,
- const PatchCoord &patch_coord,
- float face_varying[2])
+ void evalPatchesFaceVarying(const int face_varying_channel,
+ const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float face_varying[2])
{
assert(face_varying_channel >= 0);
assert(face_varying_channel < face_varying_evaluators.size());
- face_varying_evaluators[face_varying_channel]->evalPatch(patch_coord, face_varying);
+ face_varying_evaluators[face_varying_channel]->evalPatches(
+ patch_coord, num_patch_coords, face_varying);
}
private:
SRC_VERTEX_BUFFER *src_data_;
SRC_VERTEX_BUFFER *src_varying_data_;
- PatchCoordBuffer *patch_coords_;
PATCH_TABLE *patch_table_;
BufferDescriptor src_desc_;
BufferDescriptor src_varying_desc_;
@@ -510,6 +523,19 @@ class VolatileEvalOutput {
DEVICE_CONTEXT *device_context_;
};
+void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ const OpenSubdiv::Far::PatchMap *patch_map,
+ StackOrHeapPatchCoordArray *array)
+{
+ array->resize(num_patch_coords);
+ for (int i = 0; i < num_patch_coords; ++i) {
+ const PatchTable::PatchHandle *handle = patch_map->FindPatch(
+ patch_coords[i].ptex_face, patch_coords[i].u, patch_coords[i].v);
+ (array->data())[i] = PatchCoord(*handle, patch_coords[i].u, patch_coords[i].v);
+ }
+}
+
} // namespace
// Note: Define as a class instead of typedcef to make it possible
@@ -653,10 +679,10 @@ void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index,
const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
PatchCoord patch_coord(*handle, face_u, face_v);
if (dPdu != NULL || dPdv != NULL) {
- implementation_->evalPatchesWithDerivatives(patch_coord, P, dPdu, dPdv);
+ implementation_->evalPatchesWithDerivatives(&patch_coord, 1, P, dPdu, dPdv);
}
else {
- implementation_->evalPatchCoord(patch_coord, P);
+ implementation_->evalPatches(&patch_coord, 1, P);
}
}
@@ -671,7 +697,7 @@ void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index,
assert(face_v <= 1.0f);
const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
PatchCoord patch_coord(*handle, face_u, face_v);
- implementation_->evalPatchVarying(patch_coord, varying);
+ implementation_->evalPatchesVarying(&patch_coord, 1, varying);
}
void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
@@ -686,7 +712,24 @@ void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
assert(face_v <= 1.0f);
const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
PatchCoord patch_coord(*handle, face_u, face_v);
- implementation_->evalPatchFaceVarying(face_varying_channel, patch_coord, face_varying);
+ implementation_->evalPatchesFaceVarying(face_varying_channel, &patch_coord, 1, face_varying);
+}
+
+void CpuEvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv)
+{
+ StackOrHeapPatchCoordArray patch_coords_array;
+ convertPatchCoordsToArray(patch_coords, num_patch_coords, patch_map_, &patch_coords_array);
+ if (dPdu != NULL || dPdv != NULL) {
+ implementation_->evalPatchesWithDerivatives(
+ patch_coords_array.data(), num_patch_coords, P, dPdu, dPdv);
+ }
+ else {
+ implementation_->evalPatches(patch_coords_array.data(), num_patch_coords, P);
+ }
}
} // namespace opensubdiv_capi
@@ -757,7 +800,6 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal(
}
// Face warying stencil.
vector<const StencilTable *> all_face_varying_stencils;
-#ifdef OPENSUBDIV_HAS_FVAR_EVALUATION
all_face_varying_stencils.reserve(num_face_varying_channels);
for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
++face_varying_channel) {
@@ -769,7 +811,6 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal(
all_face_varying_stencils.push_back(
StencilTableFactory::Create(*refiner, face_varying_stencil_options));
}
-#endif
// Generate bi-cubic patch table for the limit surface.
// TODO(sergey): Ideally we would want to expose end-cap settings via
// C-API to make it more generic. Currently it matches old Blender's
@@ -800,7 +841,6 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal(
varying_stencils = table;
}
}
-#ifdef OPENSUBDIV_HAS_FVAR_EVALUATION
for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
++face_varying_channel) {
const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTableFaceVarying(
@@ -813,7 +853,6 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal(
all_face_varying_stencils[face_varying_channel] = table;
}
}
-#endif
// Create OpenSubdiv's CPU side evaluator.
// TODO(sergey): Make it possible to use different evaluators.
opensubdiv_capi::CpuEvalOutput *eval_output = new opensubdiv_capi::CpuEvalOutput(
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h
index 7c963227d17..392633944c6 100644
--- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h
@@ -26,6 +26,7 @@
#include <opensubdiv/far/patchMap.h>
#include <opensubdiv/far/patchTable.h>
+struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
namespace opensubdiv_capi {
@@ -114,6 +115,18 @@ class CpuEvalOutputAPI {
float face_v,
float face_varying[2]);
+ // Batched evaluation of multiple input coordinates.
+
+ // Evaluate given ptex face at given bilinear coordinate.
+ // If derivatives are NULL, they will not be evaluated.
+ //
+ // NOTE: Output arrays must point to a memory of size float[3]*num_patch_coords.
+ void evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv);
+
protected:
CpuEvalOutput *implementation_;
OpenSubdiv::Far::PatchMap *patch_map_;
diff --git a/intern/opensubdiv/opensubdiv_capi_type.h b/intern/opensubdiv/opensubdiv_capi_type.h
index 35eeb71dede..e759c5f43b0 100644
--- a/intern/opensubdiv/opensubdiv_capi_type.h
+++ b/intern/opensubdiv/opensubdiv_capi_type.h
@@ -58,6 +58,13 @@ typedef enum OpenSubdiv_FVarLinearInterpolation {
OSD_FVAR_LINEAR_INTERPOLATION_ALL,
} OpenSubdiv_FVarLinearInterpolation;
+typedef struct OpenSubdiv_PatchCoord {
+ int ptex_face;
+
+ // Parametric location on patch.
+ float u, v;
+} OpenSubdiv_PatchCoord;
+
#ifdef __cplusplus
}
#endif
diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h
index ceb0c58feba..1572d01b851 100644
--- a/intern/opensubdiv/opensubdiv_evaluator_capi.h
+++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h
@@ -24,6 +24,7 @@ extern "C" {
#endif
struct OpenSubdiv_EvaluatorInternal;
+struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
typedef struct OpenSubdiv_Evaluator {
@@ -108,6 +109,19 @@ typedef struct OpenSubdiv_Evaluator {
float face_v,
float face_varying[2]);
+ // Batched evaluation of multiple input coordinates.
+
+ // Evaluate limit surface.
+ // If derivatives are NULL, they will not be evaluated.
+ //
+ // NOTE: Output arrays must point to a memory of size float[3]*num_patch_coords.
+ void (*evaluatePatchesLimit)(struct OpenSubdiv_Evaluator *evaluator,
+ const struct OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv);
+
// Internal storage for the use in this module only.
//
// This is where actual OpenSubdiv's evaluator is living.
diff --git a/release/datafiles/icons/ops.gpencil.primitive_polyline.dat b/release/datafiles/icons/ops.gpencil.primitive_polyline.dat
new file mode 100644
index 00000000000..35a869661b2
--- /dev/null
+++ b/release/datafiles/icons/ops.gpencil.primitive_polyline.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.paint.eyedropper_add.dat b/release/datafiles/icons/ops.paint.eyedropper_add.dat
new file mode 100644
index 00000000000..135cbbb4a9d
--- /dev/null
+++ b/release/datafiles/icons/ops.paint.eyedropper_add.dat
Binary files differ
diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py
index 04aaa7bd69d..abe33b0e8ea 100644
--- a/release/scripts/modules/bpy/utils/__init__.py
+++ b/release/scripts/modules/bpy/utils/__init__.py
@@ -457,6 +457,41 @@ def preset_paths(subdir):
return dirs
+def is_path_builtin(path):
+ """
+ Returns True if the path is one of the built-in paths used by Blender.
+
+ :arg path: Path you want to check if it is in the built-in settings directory
+ :type path: str
+ :rtype: bool
+ """
+ # Note that this function is is not optimized for speed,
+ # it's intended to be used to check if it's OK to remove presets.
+ #
+ # If this is used in a draw-loop for example, we could cache some of the values.
+ user_path = resource_path('USER')
+
+ for res in ('SYSTEM', 'LOCAL'):
+ parent_path = resource_path(res)
+ if not parent_path or parent_path == user_path:
+ # Make sure that the current path is not empty string and that it is
+ # not the same as the user config path. IE "~/.config/blender" on Linux
+ # This can happen on portable installs.
+ continue
+
+ try:
+ if _os.path.samefile(
+ _os.path.commonpath([parent_path]),
+ _os.path.commonpath([parent_path, path])
+ ):
+ return True
+ except FileNotFoundError:
+ #The path we tried to look up doesn't exist
+ pass
+
+ return False
+
+
def smpte_from_seconds(time, fps=None, fps_base=None):
"""
Returns an SMPTE formatted string from the *time*:
diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py
index 0f95371d4c5..3ce06647cdc 100644
--- a/release/scripts/startup/bl_operators/add_mesh_torus.py
+++ b/release/scripts/startup/bl_operators/add_mesh_torus.py
@@ -22,6 +22,7 @@ from bpy.types import Operator
from bpy.props import (
BoolProperty,
+ EnumProperty,
FloatProperty,
IntProperty,
)
@@ -147,7 +148,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
min=3, max=256,
default=12,
)
- mode: bpy.props.EnumProperty(
+ mode: EnumProperty(
name="Torus Dimensions",
items=(
('MAJOR_MINOR', "Major/Minor",
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 661a7bd4aea..deb33f77050 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -84,6 +84,7 @@ class AddPresetBase:
def execute(self, context):
import os
+ from bpy.utils import is_path_builtin
if hasattr(self, "pre_cb"):
self.pre_cb(context)
@@ -190,6 +191,11 @@ class AddPresetBase:
if not filepath:
return {'CANCELLED'}
+ # Do not remove bundled presets
+ if is_path_builtin(filepath):
+ self.report({'WARNING'}, "You can't remove the default presets")
+ return {'CANCELLED'}
+
try:
if hasattr(self, "remove"):
self.remove(context, filepath)
diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py
index ab87dc47075..9a0028d1f14 100644
--- a/release/scripts/startup/bl_operators/sequencer.py
+++ b/release/scripts/startup/bl_operators/sequencer.py
@@ -21,7 +21,11 @@
import bpy
from bpy.types import Operator
-from bpy.props import IntProperty
+from bpy.props import (
+ EnumProperty,
+ FloatProperty,
+ IntProperty,
+)
class SequencerCrossfadeSounds(Operator):
@@ -170,12 +174,12 @@ class SequencerFadesAdd(Operator):
bl_label = "Add Fades"
bl_options = {'REGISTER', 'UNDO'}
- duration_seconds: bpy.props.FloatProperty(
+ duration_seconds: FloatProperty(
name="Fade Duration",
description="Duration of the fade in seconds",
default=1.0,
min=0.01)
- type: bpy.props.EnumProperty(
+ type: EnumProperty(
items=(
('IN_OUT', 'Fade In And Out', 'Fade selected strips in and out'),
('IN', 'Fade In', 'Fade in selected strips'),
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index 0cd90610cdc..4c5c269955a 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -1032,7 +1032,7 @@ class PREFERENCES_OT_studiolight_uninstall(Operator):
"""Delete Studio Light"""
bl_idname = "preferences.studiolight_uninstall"
bl_label = "Uninstall Studio Light"
- index: bpy.props.IntProperty()
+ index: IntProperty()
def execute(self, context):
import os
@@ -1055,7 +1055,7 @@ class PREFERENCES_OT_studiolight_copy_settings(Operator):
"""Copy Studio Light settings to the Studio light editor"""
bl_idname = "preferences.studiolight_copy_settings"
bl_label = "Copy Studio Light settings"
- index: bpy.props.IntProperty()
+ index: IntProperty()
def execute(self, context):
prefs = context.preferences
diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
index 7b25491764b..83d451fbc89 100644
--- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py
+++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
@@ -24,6 +24,9 @@
import bpy
from bpy.types import Operator
+from bpy.props import (
+ EnumProperty,
+)
STATUS_OK = (1 << 0)
STATUS_ERR_ACTIVE_FACE = (1 << 1)
@@ -253,7 +256,7 @@ class FollowActiveQuads(Operator):
bl_label = "Follow Active Quads"
bl_options = {'REGISTER', 'UNDO'}
- mode: bpy.props.EnumProperty(
+ mode: EnumProperty(
name="Edge Length Mode",
description="Method to space UV edge loops",
items=(
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 037303a08e1..bdac6332bd8 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1781,6 +1781,44 @@ class WM_OT_toolbar_prompt(Operator):
bl_idname = "wm.toolbar_prompt"
bl_label = "Toolbar Prompt"
+ @staticmethod
+ def _status_items_generate(cls, keymap, context):
+ from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
+
+ # The keymap doesn't have the same order the tools are declared in,
+ # while we could support this, it's simpler to apply order here.
+ tool_map_id_to_order = {}
+ # Map the
+ tool_map_id_to_label = {}
+ for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context)):
+ if item is not None:
+ tool_map_id_to_label[item.idname] = item.label
+ tool_map_id_to_order[item.idname] = len(tool_map_id_to_order)
+
+ status_items = []
+
+ for item in keymap.keymap_items:
+ name = item.name
+ key_str = item.to_string()
+ # These are duplicated from regular numbers.
+ if key_str.startswith("Numpad "):
+ continue
+ properties = item.properties
+ idname = item.idname
+ if idname == "wm.tool_set_by_id":
+ tool_idname = properties["name"]
+ name = tool_map_id_to_label[tool_idname]
+ name = name.replace("Annotate ", "")
+ else:
+ continue
+
+ status_items.append((tool_idname, name, item))
+
+ status_items.sort(
+ key=lambda a: tool_map_id_to_order[a[0]]
+ )
+ return status_items
+
def modal(self, context, event):
event_type = event.type
event_value = event.value
@@ -1805,14 +1843,18 @@ class WM_OT_toolbar_prompt(Operator):
return {'RUNNING_MODAL'}
def invoke(self, context, event):
- space_type = context.space_data.type
+ space_data = context.space_data
+ if space_data is None:
+ return {'CANCELLED'}
+
+ space_type = space_data.type
cls, keymap = WM_OT_toolbar.keymap_from_toolbar(
context,
space_type,
use_fallback_keys=False,
use_reset=False,
)
- if keymap is None:
+ if (keymap is None) or (not keymap.keymap_items):
return {'CANCELLED'}
self._init_event_type = event.type
@@ -1823,18 +1865,9 @@ class WM_OT_toolbar_prompt(Operator):
del init_event_type_as_text[0]
init_event_type_as_text = " ".join(init_event_type_as_text)
+ status_items = self._status_items_generate(cls, keymap, context)
+
def status_text_fn(self, context):
- from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
-
- # The keymap doesn't have the same order the tools are declared in,
- # while we could support this, it's simpler to apply order here.
- tool_map_id_to_order = {}
- # Map the
- tool_map_id_to_label = {}
- for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context)):
- if item is not None:
- tool_map_id_to_label[item.idname] = item.label
- tool_map_id_to_order[item.idname] = len(tool_map_id_to_order)
layout = self.layout
if True:
@@ -1842,31 +1875,7 @@ class WM_OT_toolbar_prompt(Operator):
box.scale_x = 0.8
box.label(text=init_event_type_as_text)
- status_items = []
-
- for item in keymap.keymap_items:
- name = item.name
- key_str = item.to_string()
- # These are duplicated from regular numbers.
- if key_str.startswith("Numpad "):
- continue
- properties = item.properties
- idname = item.idname
- if idname == "wm.tool_set_by_id":
- tool_idname = properties["name"]
- name = tool_map_id_to_label[tool_idname]
- name = name.replace("Annotate ", "")
- else:
- continue
-
- status_items.append((tool_idname, name, item))
-
- status_items.sort(
- key=lambda a: tool_map_id_to_order[a[0]]
- )
-
flow = layout.grid_flow(columns=len(status_items), align=True, row_major=True)
-
for _, name, item in status_items:
row = flow.row(align=True)
row.template_event_from_keymap_item(item, text=name)
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index e545ee971d8..b6db3cf0b97 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -892,7 +892,7 @@ class GreasePencilMaterialsPanel:
if is_view3d and brush is not None:
gp_settings = brush.gpencil_settings
if gp_settings.use_material_pin is False:
- if ob.active_material_index > 0:
+ if ob.active_material_index >= 0:
ma = ob.material_slots[ob.active_material_index].material
else:
ma = gp_settings.material
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 636c7f42f65..98e812cf02d 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -108,7 +108,7 @@ class VIEW3D_MT_tools_projectpaint_clone(Menu):
props.value = i
-def brush_texpaint_common(panel, context, layout, brush, _settings, projpaint=False):
+def brush_texpaint_common(panel, context, layout, brush, _settings, *, projpaint=False):
col = layout.column()
if brush.image_tool == 'FILL' and not projpaint:
@@ -132,7 +132,7 @@ def brush_texpaint_common(panel, context, layout, brush, _settings, projpaint=Fa
brush_basic_texpaint_settings(col, context, brush)
-def brush_texpaint_common_clone(_panel, context, layout, _brush, settings, projpaint=False):
+def brush_texpaint_common_clone(_panel, context, layout, _brush, settings, *, projpaint=False):
ob = context.active_object
col = layout.column()
@@ -160,7 +160,7 @@ def brush_texpaint_common_clone(_panel, context, layout, _brush, settings, projp
col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False)
-def brush_texpaint_common_color(_panel, context, layout, brush, _settings, projpaint=False):
+def brush_texpaint_common_color(_panel, context, layout, brush, _settings, *, projpaint=False):
UnifiedPaintPanel.prop_unified_color_picker(layout, context, brush, "color", value_slider=True)
row = layout.row(align=True)
@@ -170,7 +170,7 @@ def brush_texpaint_common_color(_panel, context, layout, brush, _settings, projp
row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="", emboss=False)
-def brush_texpaint_common_gradient(_panel, context, layout, brush, _settings, projpaint=False):
+def brush_texpaint_common_gradient(_panel, context, layout, brush, _settings, *, projpaint=False):
layout.template_color_ramp(brush, "gradient", expand=True)
layout.use_property_split = True
@@ -186,7 +186,7 @@ def brush_texpaint_common_gradient(_panel, context, layout, brush, _settings, pr
col.prop(brush, "gradient_fill_mode")
-def brush_texpaint_common_options(_panel, _context, layout, brush, _settings, projpaint=False):
+def brush_texpaint_common_options(_panel, _context, layout, brush, _settings, *, projpaint=False):
capabilities = brush.image_paint_capabilities
col = layout.column()
@@ -199,6 +199,8 @@ def brush_texpaint_common_options(_panel, _context, layout, brush, _settings, pr
if projpaint:
col.prop(brush, "use_alpha")
+ else:
+ col.prop(brush, "use_paint_antialiasing")
# Used in both the View3D toolbar and texture properties
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 37271f2e242..958052c8f25 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -432,7 +432,7 @@ class FILEBROWSER_MT_view(Menu):
class FILEBROWSER_MT_select(Menu):
bl_label = "Select"
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("file.select_all", text="All").action = 'SELECT'
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index cf5283d65cb..8de12f759fc 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -1106,9 +1106,9 @@ class IMAGE_PT_paint_color(Panel, ImagePaintPanel):
layout.prop(brush, "color_type", expand=True)
if brush.color_type == 'COLOR':
- brush_texpaint_common_color(self, context, layout, brush, settings, True)
+ brush_texpaint_common_color(self, context, layout, brush, settings)
elif brush.color_type == 'GRADIENT':
- brush_texpaint_common_gradient(self, context, layout, brush, settings, True)
+ brush_texpaint_common_gradient(self, context, layout, brush, settings)
class IMAGE_PT_paint_swatches(Panel, ImagePaintPanel):
@@ -1160,7 +1160,7 @@ class IMAGE_PT_paint_clone(Panel, ImagePaintPanel):
layout.active = settings.use_clone_layer
- brush_texpaint_common_clone(self, context, layout, brush, settings, True)
+ brush_texpaint_common_clone(self, context, layout, brush, settings)
class IMAGE_PT_paint_options(Panel, ImagePaintPanel):
@@ -1186,7 +1186,7 @@ class IMAGE_PT_paint_options(Panel, ImagePaintPanel):
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
- brush_texpaint_common_options(self, context, layout, brush, settings, True)
+ brush_texpaint_common_options(self, context, layout, brush, settings)
class IMAGE_PT_tools_brush_display(BrushButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 5624236b6fc..e145b53cbd1 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -316,8 +316,10 @@ class SEQUENCER_MT_select_channel(Menu):
def draw(self, _context):
layout = self.layout
- layout.operator("sequencer.select_active_side", text="Left").side = 'LEFT'
- layout.operator("sequencer.select_active_side", text="Right").side = 'RIGHT'
+ layout.operator("sequencer.select_side", text="Left").side = 'LEFT'
+ layout.operator("sequencer.select_side", text="Right").side = 'RIGHT'
+ layout.separator()
+ layout.operator("sequencer.select_side", text="Both Sides").side = 'BOTH'
class SEQUENCER_MT_select_linked(Menu):
diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py
index 9e9ddcf3505..81ccc9216a1 100644
--- a/release/scripts/startup/bl_ui/space_text.py
+++ b/release/scripts/startup/bl_ui/space_text.py
@@ -57,7 +57,8 @@ class TEXT_HT_header(Header):
syntax.prop(st, "show_syntax_highlight", text="")
if text:
- is_osl = text.name.endswith((".osl", ".osl"))
+ text_name = text.name
+ is_osl = text_name.endswith((".osl", ".oso"))
row = layout.row()
if is_osl:
@@ -65,7 +66,7 @@ class TEXT_HT_header(Header):
row.operator("node.shader_script_update")
else:
row = layout.row()
- row.active = text.name.endswith(".py")
+ row.active = text_name.endswith(".py")
row.prop(text, "use_module")
row = layout.row()
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 00beb523d21..7d6ca5c9557 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1405,7 +1405,7 @@ class _defs_gpencil_paint:
return dict(
idname="builtin.eyedropper",
label="Eyedropper",
- icon="ops.paint.weight_sample",
+ icon="ops.paint.eyedropper_add",
cursor='EYEDROPPER',
widget=None,
keymap=(),
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index b22afe338ed..8ff0ba7bce4 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2522,11 +2522,18 @@ class VIEW3D_MT_object_parent(Menu):
def draw(self, _context):
layout = self.layout
+ operator_context_default = layout.operator_context
layout.operator_enum("object.parent_set", "type")
layout.separator()
+ layout.operator_context = 'EXEC_DEFAULT'
+ layout.operator("object.parent_no_inverse_set")
+ layout.operator_context = operator_context_default
+
+ layout.separator()
+
layout.operator_enum("object.parent_clear", "type")
@@ -4498,11 +4505,13 @@ class VIEW3D_MT_assign_material(Menu):
def draw(self, context):
layout = self.layout
ob = context.active_object
+ mat_active = ob.active_material
for slot in ob.material_slots:
mat = slot.material
if mat:
- layout.operator("gpencil.stroke_change_color", text=mat.name).material = mat.name
+ layout.operator("gpencil.stroke_change_color", text=mat.name,
+ icon='LAYER_ACTIVE' if mat == mat_active else 'BLANK1').material = mat.name
class VIEW3D_MT_gpencil_copy_layer(Menu):
@@ -6073,6 +6082,8 @@ class VIEW3D_PT_snapping(Panel):
row = col.row(align=True)
row.prop(tool_settings, "snap_target", expand=True)
+ col.prop(tool_settings, "use_snap_backface_culling")
+
if obj:
if object_mode == 'EDIT':
col.prop(tool_settings, "use_snap_self")
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index afaf06d2320..d99c7ae65b0 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -503,7 +503,7 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
# Texture Paint Mode #
elif context.image_paint_object and brush:
- brush_texpaint_common(self, context, layout, brush, settings, True)
+ brush_texpaint_common(self, context, layout, brush, settings, projpaint=True)
# Weight Paint Mode #
elif context.weight_paint_object and brush:
@@ -551,15 +551,15 @@ class VIEW3D_PT_tools_brush_color(Panel, View3DPaintPanel):
brush = settings.brush
if context.vertex_paint_object:
- brush_texpaint_common_color(self, context, layout, brush, settings, True)
+ brush_texpaint_common_color(self, context, layout, brush, settings, projpaint=True)
else:
layout.prop(brush, "color_type", expand=True)
if brush.color_type == 'COLOR':
- brush_texpaint_common_color(self, context, layout, brush, settings, True)
+ brush_texpaint_common_color(self, context, layout, brush, settings, projpaint=True)
elif brush.color_type == 'GRADIENT':
- brush_texpaint_common_gradient(self, context, layout, brush, settings, True)
+ brush_texpaint_common_gradient(self, context, layout, brush, settings, projpaint=True)
class VIEW3D_PT_tools_brush_swatches(Panel, View3DPaintPanel):
@@ -613,7 +613,7 @@ class VIEW3D_PT_tools_brush_clone(Panel, View3DPaintPanel):
layout.active = settings.use_clone_layer
- brush_texpaint_common_clone(self, context, layout, brush, settings, True)
+ brush_texpaint_common_clone(self, context, layout, brush, settings, projpaint=True)
class VIEW3D_PT_tools_brush_options(Panel, View3DPaintPanel):
@@ -635,7 +635,7 @@ class VIEW3D_PT_tools_brush_options(Panel, View3DPaintPanel):
col = layout.column()
if context.image_paint_object and brush:
- brush_texpaint_common_options(self, context, layout, brush, settings, True)
+ brush_texpaint_common_options(self, context, layout, brush, settings, projpaint=True)
elif context.sculpt_object and brush:
col.prop(brush, "use_automasking_topology")
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index fe740f4898e..73b7b1e2858 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -84,6 +84,7 @@ static void brush_defaults(Brush *brush)
FROM_DEFAULT(normal_weight);
FROM_DEFAULT(fill_threshold);
FROM_DEFAULT(flag);
+ FROM_DEFAULT(sampling_flag);
FROM_DEFAULT_PTR(rgb);
FROM_DEFAULT_PTR(secondary_rgb);
FROM_DEFAULT(spacing);
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 568d6c9a84a..7ef5e518cc8 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -198,11 +198,45 @@ void BLI_task_parallel_range(const int start,
TaskParallelRangeFunc func,
const TaskParallelSettings *settings);
-typedef void (*TaskParallelListbaseFunc)(void *userdata, struct Link *iter, int index);
+/* This data is shared between all tasks, its access needs thread lock or similar protection. */
+typedef struct TaskParallelIteratorStateShared {
+ /* Maximum amount of items to acquire at once. */
+ int chunk_size;
+ /* Next item to be acquired. */
+ void *next_item;
+ /* Index of the next item to be acquired. */
+ int next_index;
+ /* Indicates that end of iteration has been reached. */
+ bool is_finished;
+ /* Helper lock to protect access to this data in iterator getter callback,
+ * can be ignored (if the callback implements its own protection system, using atomics e.g.).
+ * Will be NULL when iterator is actually processed in a single thread. */
+ SpinLock *spin_lock;
+} TaskParallelIteratorStateShared;
+
+typedef void (*TaskParallelIteratorIterFunc)(void *__restrict userdata,
+ const TaskParallelTLS *__restrict tls,
+ void **r_next_item,
+ int *r_next_index,
+ bool *r_do_abort);
+
+typedef void (*TaskParallelIteratorFunc)(void *__restrict userdata,
+ void *item,
+ int index,
+ const TaskParallelTLS *__restrict tls);
+
+void BLI_task_parallel_iterator(void *userdata,
+ TaskParallelIteratorIterFunc iter_func,
+ void *init_item,
+ const int init_index,
+ const int tot_items,
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings);
+
void BLI_task_parallel_listbase(struct ListBase *listbase,
void *userdata,
- TaskParallelListbaseFunc func,
- const bool use_threading);
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings);
typedef struct MempoolIterData MempoolIterData;
typedef void (*TaskParallelMempoolFunc)(void *userdata, MempoolIterData *iter);
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 6cdaec97d9a..bb69dc6452f 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -149,7 +149,7 @@ typedef struct TaskThreadLocalStorage {
* without "interrupting" for task execution.
*
* We try to accumulate as much tasks as possible in a local queue without
- * any locks first, and then we push all of them into a schedulers queue
+ * any locks first, and then we push all of them into a scheduler's queue
* from within a single mutex lock.
*/
bool do_delayed_push;
@@ -1052,14 +1052,20 @@ typedef struct ParallelRangeState {
int chunk_size;
} ParallelRangeState;
-BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings *settings,
- const int num_tasks,
- ParallelRangeState *state)
+BLI_INLINE void task_parallel_calc_chunk_size(const TaskParallelSettings *settings,
+ const int tot_items,
+ int num_tasks,
+ int *r_chunk_size)
{
- const int tot_items = state->stop - state->start;
int chunk_size = 0;
- if (settings->min_iter_per_thread > 0) {
+ if (!settings->use_threading) {
+ /* Some users of this helper will still need a valid chunk size in case processing is not
+ * threaded. We can use a bigger one than in default threaded case then. */
+ chunk_size = 1024;
+ num_tasks = 1;
+ }
+ else if (settings->min_iter_per_thread > 0) {
/* Already set by user, no need to do anything here. */
chunk_size = settings->min_iter_per_thread;
}
@@ -1091,16 +1097,30 @@ BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings *
BLI_assert(chunk_size > 0);
- switch (settings->scheduling_mode) {
- case TASK_SCHEDULING_STATIC:
- state->chunk_size = max_ii(chunk_size, tot_items / (num_tasks));
- break;
- case TASK_SCHEDULING_DYNAMIC:
- state->chunk_size = chunk_size;
- break;
+ if (tot_items > 0) {
+ switch (settings->scheduling_mode) {
+ case TASK_SCHEDULING_STATIC:
+ *r_chunk_size = max_ii(chunk_size, tot_items / num_tasks);
+ break;
+ case TASK_SCHEDULING_DYNAMIC:
+ *r_chunk_size = chunk_size;
+ break;
+ }
+ }
+ else {
+ /* If total amount of items is unknown, we can only use dynamic scheduling. */
+ *r_chunk_size = chunk_size;
}
}
+BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings *settings,
+ const int num_tasks,
+ ParallelRangeState *state)
+{
+ task_parallel_calc_chunk_size(
+ settings, state->stop - state->start, num_tasks, &state->chunk_size);
+}
+
BLI_INLINE bool parallel_range_next_iter_get(ParallelRangeState *__restrict state,
int *__restrict iter,
int *__restrict count)
@@ -1256,77 +1276,239 @@ void BLI_task_parallel_range(const int start,
}
}
-#undef MALLOCA
-#undef MALLOCA_FREE
-
-typedef struct ParallelListbaseState {
+typedef struct TaskParallelIteratorState {
void *userdata;
- TaskParallelListbaseFunc func;
+ TaskParallelIteratorIterFunc iter_func;
+ TaskParallelIteratorFunc func;
+
+ /* *** Data used to 'acquire' chunks of items from the iterator. *** */
+ /* Common data also passed to the generator callback. */
+ TaskParallelIteratorStateShared iter_shared;
+ /* Total number of items. If unknown, set it to a negative number. */
+ int tot_items;
+} TaskParallelIteratorState;
+
+BLI_INLINE void task_parallel_iterator_calc_chunk_size(const TaskParallelSettings *settings,
+ const int num_tasks,
+ TaskParallelIteratorState *state)
+{
+ task_parallel_calc_chunk_size(
+ settings, state->tot_items, num_tasks, &state->iter_shared.chunk_size);
+}
- int chunk_size;
- int index;
- Link *link;
- SpinLock lock;
-} ParallelListState;
-
-BLI_INLINE Link *parallel_listbase_next_iter_get(ParallelListState *__restrict state,
- int *__restrict index,
- int *__restrict count)
+static void parallel_iterator_func_do(TaskParallelIteratorState *__restrict state,
+ void *userdata_chunk,
+ int threadid)
{
- int task_count = 0;
- BLI_spin_lock(&state->lock);
- Link *result = state->link;
- if (LIKELY(result != NULL)) {
- *index = state->index;
- while (state->link != NULL && task_count < state->chunk_size) {
- task_count++;
- state->link = state->link->next;
+ TaskParallelTLS tls = {
+ .thread_id = threadid,
+ .userdata_chunk = userdata_chunk,
+ };
+
+ void **current_chunk_items;
+ int *current_chunk_indices;
+ int current_chunk_size;
+
+ const size_t items_size = sizeof(*current_chunk_items) * (size_t)state->iter_shared.chunk_size;
+ const size_t indices_size = sizeof(*current_chunk_indices) *
+ (size_t)state->iter_shared.chunk_size;
+
+ current_chunk_items = MALLOCA(items_size);
+ current_chunk_indices = MALLOCA(indices_size);
+ current_chunk_size = 0;
+
+ for (bool do_abort = false; !do_abort;) {
+ if (state->iter_shared.spin_lock != NULL) {
+ BLI_spin_lock(state->iter_shared.spin_lock);
+ }
+
+ /* Get current status. */
+ int index = state->iter_shared.next_index;
+ void *item = state->iter_shared.next_item;
+ int i;
+
+ /* 'Acquire' a chunk of items from the iterator function. */
+ for (i = 0; i < state->iter_shared.chunk_size && !state->iter_shared.is_finished; i++) {
+ current_chunk_indices[i] = index;
+ current_chunk_items[i] = item;
+ state->iter_func(state->userdata, &tls, &item, &index, &state->iter_shared.is_finished);
+ }
+
+ /* Update current status. */
+ state->iter_shared.next_index = index;
+ state->iter_shared.next_item = item;
+ current_chunk_size = i;
+
+ do_abort = state->iter_shared.is_finished;
+
+ if (state->iter_shared.spin_lock != NULL) {
+ BLI_spin_unlock(state->iter_shared.spin_lock);
+ }
+
+ for (i = 0; i < current_chunk_size; ++i) {
+ state->func(state->userdata, current_chunk_items[i], current_chunk_indices[i], &tls);
}
- state->index += task_count;
}
- BLI_spin_unlock(&state->lock);
- *count = task_count;
- return result;
+
+ MALLOCA_FREE(current_chunk_items, items_size);
+ MALLOCA_FREE(current_chunk_indices, indices_size);
}
-static void parallel_listbase_func(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void parallel_iterator_func(TaskPool *__restrict pool, void *userdata_chunk, int threadid)
{
- ParallelListState *__restrict state = BLI_task_pool_userdata(pool);
- Link *link;
- int index, count;
+ TaskParallelIteratorState *__restrict state = BLI_task_pool_userdata(pool);
- while ((link = parallel_listbase_next_iter_get(state, &index, &count)) != NULL) {
- for (int i = 0; i < count; i++) {
- state->func(state->userdata, link, index + i);
- link = link->next;
+ parallel_iterator_func_do(state, userdata_chunk, threadid);
+}
+
+static void task_parallel_iterator_no_threads(const TaskParallelSettings *settings,
+ TaskParallelIteratorState *state)
+{
+ /* Prepare user's TLS data. */
+ void *userdata_chunk = settings->userdata_chunk;
+ const size_t userdata_chunk_size = settings->userdata_chunk_size;
+ void *userdata_chunk_local = NULL;
+ const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+ if (use_userdata_chunk) {
+ userdata_chunk_local = MALLOCA(userdata_chunk_size);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
+
+ /* Also marking it as non-threaded for the iterator callback. */
+ state->iter_shared.spin_lock = NULL;
+
+ parallel_iterator_func_do(state, userdata_chunk, 0);
+
+ if (use_userdata_chunk) {
+ if (settings->func_finalize != NULL) {
+ settings->func_finalize(state->userdata, userdata_chunk_local);
}
+ MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
}
}
-static void task_parallel_listbase_no_threads(struct ListBase *listbase,
- void *userdata,
- TaskParallelListbaseFunc func)
+static void task_parallel_iterator_do(const TaskParallelSettings *settings,
+ TaskParallelIteratorState *state)
{
- int i = 0;
- for (Link *link = listbase->first; link != NULL; link = link->next, i++) {
- func(userdata, link, i);
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ const int num_threads = BLI_task_scheduler_num_threads(task_scheduler);
+
+ task_parallel_iterator_calc_chunk_size(settings, num_threads, state);
+
+ if (!settings->use_threading) {
+ task_parallel_iterator_no_threads(settings, state);
+ return;
}
+
+ const int chunk_size = state->iter_shared.chunk_size;
+ const int tot_items = state->tot_items;
+ const size_t num_tasks = tot_items >= 0 ?
+ (size_t)min_ii(num_threads, state->tot_items / chunk_size) :
+ (size_t)num_threads;
+
+ BLI_assert(num_tasks > 0);
+ if (num_tasks == 1) {
+ task_parallel_iterator_no_threads(settings, state);
+ return;
+ }
+
+ SpinLock spin_lock;
+ BLI_spin_init(&spin_lock);
+ state->iter_shared.spin_lock = &spin_lock;
+
+ void *userdata_chunk = settings->userdata_chunk;
+ const size_t userdata_chunk_size = settings->userdata_chunk_size;
+ void *userdata_chunk_local = NULL;
+ void *userdata_chunk_array = NULL;
+ const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+
+ TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, state);
+
+ if (use_userdata_chunk) {
+ userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
+ }
+
+ for (size_t i = 0; i < num_tasks; i++) {
+ if (use_userdata_chunk) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
+ /* Use this pool's pre-allocated tasks. */
+ BLI_task_pool_push_from_thread(task_pool,
+ parallel_iterator_func,
+ userdata_chunk_local,
+ false,
+ TASK_PRIORITY_HIGH,
+ task_pool->thread_id);
+ }
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ if (use_userdata_chunk) {
+ if (settings->func_finalize != NULL) {
+ for (size_t i = 0; i < num_tasks; i++) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ settings->func_finalize(state->userdata, userdata_chunk_local);
+ }
+ }
+ MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
+ }
+
+ BLI_spin_end(&spin_lock);
+ state->iter_shared.spin_lock = NULL;
}
-/* NOTE: The idea here is to compensate for rather measurable threading
- * overhead caused by fetching tasks. With too many CPU threads we are starting
- * to spend too much time in those overheads. */
-BLI_INLINE int task_parallel_listbasecalc_chunk_size(const int num_threads)
+/**
+ * This function allows to parallelize for loops using a generic iterator.
+ *
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param iter_func: Callback function used to generate chunks of items.
+ * \param init_item: The initial item, if necessary (may be NULL if unused).
+ * \param init_index: The initial index.
+ * \param tot_items: The total amount of items to iterate over
+ * (if unkown, set it to a negative number).
+ * \param func: Callback function.
+ * \param settings: See public API doc of TaskParallelSettings for description of all settings.
+ *
+ * \note Static scheduling is only available when \a tot_items is >= 0.
+ */
+
+void BLI_task_parallel_iterator(void *userdata,
+ TaskParallelIteratorIterFunc iter_func,
+ void *init_item,
+ const int init_index,
+ const int tot_items,
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings)
{
- if (num_threads > 32) {
- return 128;
- }
- else if (num_threads > 16) {
- return 64;
+ TaskParallelIteratorState state = {0};
+
+ state.tot_items = tot_items;
+ state.iter_shared.next_index = init_index;
+ state.iter_shared.next_item = init_item;
+ state.iter_shared.is_finished = false;
+ state.userdata = userdata;
+ state.iter_func = iter_func;
+ state.func = func;
+
+ task_parallel_iterator_do(settings, &state);
+}
+
+static void task_parallel_listbase_get(void *__restrict UNUSED(userdata),
+ const TaskParallelTLS *__restrict UNUSED(tls),
+ void **r_next_item,
+ int *r_next_index,
+ bool *r_do_abort)
+{
+ /* Get current status. */
+ Link *link = *r_next_item;
+
+ if (link->next == NULL) {
+ *r_do_abort = true;
}
- return 32;
+ *r_next_item = link->next;
+ (*r_next_index)++;
}
/**
@@ -1335,58 +1517,36 @@ BLI_INLINE int task_parallel_listbasecalc_chunk_size(const int num_threads)
* \param listbase: The double linked list to loop over.
* \param userdata: Common userdata passed to all instances of \a func.
* \param func: Callback function.
- * \param use_threading: If \a true, actually split-execute loop in threads,
- * else just do a sequential forloop
- * (allows caller to use any kind of test to switch on parallelization or not).
+ * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
*
* \note There is no static scheduling here,
* since it would need another full loop over items to count them.
*/
-void BLI_task_parallel_listbase(struct ListBase *listbase,
+void BLI_task_parallel_listbase(ListBase *listbase,
void *userdata,
- TaskParallelListbaseFunc func,
- const bool use_threading)
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings)
{
if (BLI_listbase_is_empty(listbase)) {
return;
}
- if (!use_threading) {
- task_parallel_listbase_no_threads(listbase, userdata, func);
- return;
- }
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- const int num_threads = BLI_task_scheduler_num_threads(task_scheduler);
- /* TODO(sergey): Consider making chunk size configurable. */
- const int chunk_size = task_parallel_listbasecalc_chunk_size(num_threads);
- const int num_tasks = min_ii(num_threads, BLI_listbase_count(listbase) / chunk_size);
- if (num_tasks <= 1) {
- task_parallel_listbase_no_threads(listbase, userdata, func);
- return;
- }
- ParallelListState state;
- TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
+ TaskParallelIteratorState state = {0};
- state.index = 0;
- state.link = listbase->first;
+ state.tot_items = BLI_listbase_count(listbase);
+ state.iter_shared.next_index = 0;
+ state.iter_shared.next_item = listbase->first;
+ state.iter_shared.is_finished = false;
state.userdata = userdata;
+ state.iter_func = task_parallel_listbase_get;
state.func = func;
- state.chunk_size = chunk_size;
- BLI_spin_init(&state.lock);
- BLI_assert(num_tasks > 0);
- for (int i = 0; i < num_tasks; i++) {
- /* Use this pool's pre-allocated tasks. */
- BLI_task_pool_push_from_thread(
- task_pool, parallel_listbase_func, NULL, false, TASK_PRIORITY_HIGH, task_pool->thread_id);
- }
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- BLI_spin_end(&state.lock);
+ task_parallel_iterator_do(settings, &state);
}
+#undef MALLOCA
+#undef MALLOCA_FREE
+
typedef struct ParallelMempoolState {
void *userdata;
TaskParallelMempoolFunc func;
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index c9fb8b6990b..9fce89558b6 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -435,6 +435,9 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
* Note that sculpt is an exception,
* it's values are overwritten by #BKE_brush_sculpt_reset below. */
brush->alpha = 1.0;
+
+ /* Enable antialiasing by default */
+ brush->sampling_flag |= BRUSH_PAINT_ANTIALIASING;
}
{
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index f1e7278ffdb..f68b03034a9 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -120,31 +120,72 @@ namespace DEG {
/* ***************** */
/* Relations Builder */
+namespace {
+
/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive
- * time dependencies nor special exceptions in the depsgraph evaluation.
- */
-static bool python_driver_depends_on_time(ChannelDriver *driver)
+ * time dependencies nor special exceptions in the depsgraph evaluation. */
+
+bool python_driver_exression_depends_on_time(const char *expression)
{
- if (driver->expression[0] == '\0') {
+ if (expression[0] == '\0') {
/* Empty expression depends on nothing. */
return false;
}
- if (strchr(driver->expression, '(') != NULL) {
+ if (strchr(expression, '(') != NULL) {
/* Function calls are considered dependent on a time. */
return true;
}
- if (strstr(driver->expression, "frame") != NULL) {
+ if (strstr(expression, "frame") != NULL) {
/* Variable `frame` depends on time. */
- /* TODO(sergey): This is a bit weak, but not sure about better way of
- * handling this. */
+ /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */
+ return true;
+ }
+ /* Possible indirect time relation s should be handled via variable targets. */
+ return false;
+}
+
+bool driver_target_depends_on_time(const DriverTarget *target)
+{
+ if (target->idtype == ID_SCE && STREQ(target->rna_path, "frame_current")) {
return true;
}
- /* Possible indirect time relation s should be handled via variable
- * targets. */
return false;
}
-static bool particle_system_depends_on_time(ParticleSystem *psys)
+bool driver_variable_depends_on_time(const DriverVar *variable)
+{
+ for (int i = 0; i < variable->num_targets; ++i) {
+ if (driver_target_depends_on_time(&variable->targets[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool driver_variables_depends_on_time(const ListBase *variables)
+{
+ LISTBASE_FOREACH (const DriverVar *, variable, variables) {
+ if (driver_variable_depends_on_time(variable)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool driver_depends_on_time(ChannelDriver *driver)
+{
+ if (driver->type == DRIVER_TYPE_PYTHON) {
+ if (python_driver_exression_depends_on_time(driver->expression)) {
+ return true;
+ }
+ }
+ if (driver_variables_depends_on_time(&driver->variables)) {
+ return true;
+ }
+ return false;
+}
+
+bool particle_system_depends_on_time(ParticleSystem *psys)
{
ParticleSettings *part = psys->part;
/* Non-hair particles we always consider dependent on time. */
@@ -159,7 +200,7 @@ static bool particle_system_depends_on_time(ParticleSystem *psys)
return false;
}
-static bool object_particles_depends_on_time(Object *object)
+bool object_particles_depends_on_time(Object *object)
{
if (object->type != OB_MESH) {
return false;
@@ -172,7 +213,7 @@ static bool object_particles_depends_on_time(Object *object)
return false;
}
-static bool check_id_has_anim_component(ID *id)
+bool check_id_has_anim_component(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt == NULL) {
@@ -181,11 +222,11 @@ static bool check_id_has_anim_component(ID *id)
return (adt->action != NULL) || (!BLI_listbase_is_empty(&adt->nla_tracks));
}
-static OperationCode bone_target_opcode(ID *target,
- const char *subtarget,
- ID *id,
- const char *component_subdata,
- RootPChanMap *root_map)
+OperationCode bone_target_opcode(ID *target,
+ const char *subtarget,
+ ID *id,
+ const char *component_subdata,
+ RootPChanMap *root_map)
{
/* Same armature. */
if (target == id) {
@@ -200,11 +241,13 @@ static OperationCode bone_target_opcode(ID *target,
return OperationCode::BONE_DONE;
}
-static bool object_have_geometry_component(const Object *object)
+bool object_have_geometry_component(const Object *object)
{
return ELEM(object->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_MBALL, OB_LATTICE, OB_GPENCIL);
}
+} // namespace
+
/* **** General purpose functions **** */
DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain,
@@ -1380,7 +1423,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
/* It's quite tricky to detect if the driver actually depends on time or
* not, so for now we'll be quite conservative here about optimization and
* consider all python drivers to be depending on time. */
- if ((driver->type == DRIVER_TYPE_PYTHON) && python_driver_depends_on_time(driver)) {
+ if (driver_depends_on_time(driver)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, driver_key, "TimeSrc -> Driver");
}
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index 70bccb4849c..fe17019a5b5 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -1235,22 +1235,42 @@ static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
uv2img_space[1][1] = image_height;
const float fit_scale = image_aspect / camera_aspect;
- img2cam_space[0][0] = 1.0 / image_width;
- img2cam_space[1][1] = 1.0 / fit_scale / image_height;
+ if (camera_aspect < image_aspect) {
+ img2cam_space[0][0] = 1.0 / (1.0 / fit_scale) / image_width;
+ img2cam_space[1][1] = 1.0 / image_height;
+ }
+ else {
+ img2cam_space[0][0] = 1.0 / image_width;
+ img2cam_space[1][1] = 1.0 / fit_scale / image_height;
+ }
/* Update scaling based on image and camera framing */
float scale_x = bgpic->scale;
float scale_y = bgpic->scale;
+ float scale_x_offset = image_width;
+ float scale_y_offset = image_height;
+ if (image_aspect > 1.0f) {
+ scale_x_offset /= image_aspect;
+ if (camera_aspect > 1.0f) {
+ scale_x_offset *= min_ff(image_aspect, camera_aspect);
+ scale_y_offset *= min_ff(image_aspect, camera_aspect);
+ }
+ }
+ else {
+ scale_y_offset *= image_aspect;
+ if (camera_aspect < 1.0f) {
+ scale_x_offset /= max_ff(image_aspect, camera_aspect);
+ scale_y_offset /= max_ff(image_aspect, camera_aspect);
+ }
+ }
+
if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) {
- if (image_aspect > camera_aspect) {
- scale_x *= fit_scale;
- scale_y *= fit_scale;
- }
+ /* pass */
}
else {
- if (image_aspect > camera_aspect) {
+ if (camera_aspect < image_aspect) {
scale_x /= fit_scale;
scale_y /= fit_scale;
}
@@ -1262,7 +1282,12 @@ static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
}
else {
/* Stretch image to camera aspect */
- scale_y /= 1.0 / fit_scale;
+ if (camera_aspect < image_aspect) {
+ scale_x /= fit_scale;
+ }
+ else {
+ scale_y *= fit_scale;
+ }
}
// scale image to match the desired aspect ratio
@@ -1270,8 +1295,8 @@ static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
scale_m4[1][1] = scale_y;
/* Translate */
- translate_m4[3][0] = image_width * bgpic->offset[0] * 2.0f;
- translate_m4[3][1] = image_height * bgpic->offset[1] * 2.0f;
+ translate_m4[3][0] = bgpic->offset[0] * 2.0f * scale_x_offset;
+ translate_m4[3][1] = bgpic->offset[1] * 2.0f * scale_y_offset;
mul_m4_series(bg_data->transform_mat,
win_m4_translate,
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
index 9749619cffe..f32eb3b73ba 100644
--- a/source/blender/draw/modes/sculpt_mode.c
+++ b/source/blender/draw/modes/sculpt_mode.c
@@ -157,7 +157,7 @@ static void SCULPT_cache_populate(void *vedata, Object *ob)
if ((ob == draw_ctx->obact) &&
(BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) ||
- ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active)) {
+ !ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active)) {
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh && pbvh_has_mask(pbvh)) {
DRW_shgroup_call_sculpt(stl->g_data->mask_overlay_grp, ob, false, true, false);
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 1c7edb6c46a..680fe3a00e5 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -693,6 +693,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.gpencil.primitive_circle
ops.gpencil.primitive_curve
ops.gpencil.primitive_line
+ ops.gpencil.primitive_polyline
ops.gpencil.radius
ops.gpencil.sculpt_clone
ops.gpencil.sculpt_grab
@@ -728,6 +729,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.mesh.spin.duplicate
ops.mesh.vertices_smooth
ops.node.links_cut
+ ops.paint.eyedropper_add
ops.paint.vertex_color_fill
ops.paint.weight_fill
ops.paint.weight_gradient
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index c4f18c60f4d..3ab11f8f3f7 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1538,6 +1538,7 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
/* GPencil layer to use. */
ot->prop = RNA_def_int(ot->srna, "layer", 0, 0, INT_MAX, "Grease Pencil Layer", "", 0, INT_MAX);
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* ********************* Add Blank Frame *************************** */
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 40e0005b487..0e20abe4221 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -68,6 +68,8 @@ struct SnapObjectParams {
unsigned int use_object_edit_cage : 1;
/* snap to the closest element, use when using more than one snap type */
unsigned int use_occlusion_test : 1;
+ /* exclude back facing geometry from snapping */
+ unsigned int use_backface_culling : 1;
};
typedef struct SnapObjectContext SnapObjectContext;
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index d6a1d7f193c..c15f299bca8 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -857,7 +857,7 @@ DEF_ICON(SCRIPTPLUGINS)
DEF_ICON_BLANK(855)
DEF_ICON_BLANK(856)
DEF_ICON_BLANK(857)
-DEF_ICON(DISK)
+DEF_ICON(DISC)
DEF_ICON(DESKTOP)
DEF_ICON(EXTERNAL_DRIVE)
DEF_ICON(NETWORK_DRIVE)
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c
index bf4403e49ee..7cad7e1e062 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin.c
@@ -200,7 +200,10 @@ void MESH_OT_spin(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000);
- RNA_def_boolean(ot->srna, "dupli", 0, "Duplicate", "Make Duplicates");
+
+ prop = RNA_def_boolean(ot->srna, "dupli", 0, "Use Duplicates", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_float(ot->srna,
"angle",
DEG2RADF(90.0f),
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 8d98a3bf231..25d3118b3a9 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -30,6 +30,7 @@
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_paint.h"
@@ -179,7 +180,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- BKE_mesh_free(new_mesh);
+ BKE_id_free(bmain, new_mesh);
new_mesh = BKE_mesh_from_bmesh_nomain(bm,
(&(struct BMeshToMeshParams){
.calc_object_remap = false,
@@ -190,7 +191,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
MEM_freeN(em);
if (new_mesh->totvert == 0) {
- BKE_mesh_free(new_mesh);
+ BKE_id_free(bmain, new_mesh);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index 21c850160dd..a91f0f9274e 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -216,7 +216,7 @@ static int edbm_polybuild_delete_at_cursor_invoke(bContext *C,
}
if (ele_act->head.htype == BM_VERT) {
BMVert *v_act = (BMVert *)ele_act;
- if (BM_vert_is_edge_pair(v_act)) {
+ if (BM_vert_is_edge_pair(v_act) && !BM_vert_is_wire(v_act)) {
BM_edge_collapse(bm, v_act->e, v_act, true, true);
changed = true;
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index a54701f8725..8bc84388a1b 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -118,7 +118,7 @@ static ScrArea *find_area_image_empty(bContext *C)
for (sa = sc->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_IMAGE) {
sima = sa->spacedata.first;
- if (!sima->image) {
+ if ((sima->mode == SI_MODE_VIEW) && !sima->image) {
break;
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 9c95a3cee4d..a1e67e78a10 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -387,7 +387,12 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
m = mask;
int aa_samples = 1.0f / (radius * 0.20f);
- aa_samples = clamp_i(aa_samples, 3, 16);
+ if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) {
+ aa_samples = clamp_i(aa_samples, 3, 16);
+ }
+ else {
+ aa_samples = 1;
+ }
/* Temporal until we have the brush properties */
const float hardness = 1.0f;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 77c95c6acb3..ac7cf310099 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -2341,7 +2341,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, ss->cache->location);
+ paint_last_stroke_update(scene, ss->cache->true_location);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -3316,7 +3316,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, ss->cache->location);
+ paint_last_stroke_update(scene, ss->cache->true_location);
ED_region_tag_redraw(vc->ar);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 5d95cc80280..fc990c01bfb 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -77,6 +77,7 @@ static UndoSculpt *sculpt_undo_get_nodes(void);
static void update_cb(PBVHNode *node, void *rebuild)
{
BKE_pbvh_node_mark_update(node);
+ BKE_pbvh_node_mark_update_mask(node);
if (*((bool *)rebuild)) {
BKE_pbvh_node_mark_rebuild_draw(node);
}
@@ -497,7 +498,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
SculptSession *ss = ob->sculpt;
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
SculptUndoNode *unode;
- bool update = false, rebuild = false;
+ bool update = false, rebuild = false, update_mask = false;
bool need_mask = false;
for (unode = lb->first; unode; unode = unode->next) {
@@ -579,6 +580,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
case SCULPT_UNDO_MASK:
if (sculpt_undo_restore_mask(C, unode)) {
update = true;
+ update_mask = true;
}
break;
@@ -616,6 +618,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
};
BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw);
+ if (update_mask) {
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ }
if (BKE_sculpt_multires_active(scene, ob)) {
if (rebuild) {
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index e61375b2d4c..1ea7d81f9da 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -338,7 +338,7 @@ enum {
enum {
SPECIAL_IMG_DOCUMENT = 0,
- SPECIAL_IMG_DRIVE_DISK = 1,
+ SPECIAL_IMG_DRIVE_DISC = 1,
SPECIAL_IMG_FOLDER = 2,
SPECIAL_IMG_PARENT = 3,
SPECIAL_IMG_DRIVE_FIXED = 4,
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 577c4e24b11..b6b32293cee 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -115,7 +115,7 @@ typedef struct PaintTile {
ushort *mask;
bool valid;
bool use_float;
- int x, y;
+ int x_tile, y_tile;
} PaintTile;
static void ptile_free(PaintTile *ptile)
@@ -154,7 +154,7 @@ void *ED_image_paint_tile_find(ListBase *paint_tiles,
bool validate)
{
for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
- if (ptile->x == x_tile && ptile->y == y_tile) {
+ if (ptile->x_tile == x_tile && ptile->y_tile == y_tile) {
if (ptile->image == image && ptile->ibuf == ibuf) {
if (r_mask) {
/* allocate mask if requested. */
@@ -206,8 +206,8 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
ptile->image = image;
ptile->ibuf = ibuf;
- ptile->x = x_tile;
- ptile->y = y_tile;
+ ptile->x_tile = x_tile;
+ ptile->y_tile = y_tile;
/* add mask explicitly here */
if (r_mask) {
@@ -269,8 +269,14 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
}
- IMB_rectcpy(
- ibuf, tmpibuf, ptile->x, ptile->y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+ IMB_rectcpy(ibuf,
+ tmpibuf,
+ ptile->x_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ ptile->y_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ 0,
+ 0,
+ ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE);
if (has_float) {
SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
@@ -764,7 +770,7 @@ static bool image_undosys_step_encode(struct bContext *C,
utile->users = 1;
utile->rect.pt = ptile->rect.pt;
ptile->rect.pt = NULL;
- const uint tile_index = index_from_xy(ptile->x, ptile->y, ubuf_pre->tiles_dims);
+ const uint tile_index = index_from_xy(ptile->x_tile, ptile->y_tile, ubuf_pre->tiles_dims);
BLI_assert(ubuf_pre->tiles[tile_index] == NULL);
ubuf_pre->tiles[tile_index] = utile;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 3b86e04308e..d7a7d57b100 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -756,14 +756,15 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
}
case TSE_BONE: {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
bArmature *arm = (bArmature *)tselem->id;
Bone *bone = te->directdata;
char newname[sizeof(bone->name)];
/* always make current object active */
- tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true);
+ tree_element_active(C, &tvc, soops, te, OL_SETSEL_NORMAL, true);
/* restore bone name */
BLI_strncpy(newname, bone->name, sizeof(bone->name));
@@ -773,14 +774,15 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
break;
}
case TSE_POSE_CHANNEL: {
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
Object *ob = (Object *)tselem->id;
bPoseChannel *pchan = te->directdata;
char newname[sizeof(pchan->name)];
/* always make current pose-bone active */
- tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true);
+ tree_element_active(C, &tvc, soops, te, OL_SETSEL_NORMAL, true);
BLI_assert(ob->type == OB_ARMATURE);
@@ -2815,8 +2817,7 @@ typedef struct MergedIconRow {
static void outliner_draw_iconrow(bContext *C,
uiBlock *block,
const uiFontStyle *fstyle,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
ListBase *lb,
int level,
@@ -2827,7 +2828,6 @@ static void outliner_draw_iconrow(bContext *C,
MergedIconRow *merged)
{
eOLDrawState active = OL_DRAWSEL_NONE;
- const Object *obact = OBACT(view_layer);
for (TreeElement *te = lb->first; te; te = te->next) {
TreeStoreElem *tselem = TREESTORE(te);
@@ -2837,14 +2837,13 @@ static void outliner_draw_iconrow(bContext *C,
/* active blocks get white circle */
if (tselem->type == 0) {
if (te->idcode == ID_OB) {
- active = (OBACT(view_layer) == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL :
- OL_DRAWSEL_NONE;
+ active = (tvc->obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
}
- else if (is_object_data_in_editmode(tselem->id, obact)) {
+ else if (is_object_data_in_editmode(tselem->id, tvc->obact)) {
active = OL_DRAWSEL_ACTIVE;
}
else {
- active = tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false);
+ active = tree_element_active(C, tvc, soops, te, OL_SETSEL_NONE, false);
}
}
else if (tselem->type == TSE_GP_LAYER) {
@@ -2852,8 +2851,7 @@ static void outliner_draw_iconrow(bContext *C,
active = (gpl->flag & GP_LAYER_ACTIVE) ? OL_DRAWSEL_ACTIVE : OL_DRAWSEL_NONE;
}
else {
- active = tree_element_type_active(
- C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false);
+ active = tree_element_type_active(C, tvc, soops, te, tselem, OL_SETSEL_NONE, false);
}
if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) {
@@ -2874,8 +2872,7 @@ static void outliner_draw_iconrow(bContext *C,
outliner_draw_iconrow(C,
block,
fstyle,
- scene,
- view_layer,
+ tvc,
soops,
&te->subtree,
level + 1,
@@ -2933,8 +2930,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta
static void outliner_draw_tree_element(bContext *C,
uiBlock *block,
const uiFontStyle *fstyle,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
ARegion *ar,
SpaceOutliner *soops,
TreeElement *te,
@@ -2973,9 +2969,8 @@ static void outliner_draw_tree_element(bContext *C,
/* colors for active/selected data */
if (tselem->type == 0) {
- const Object *obact = OBACT(view_layer);
if (te->idcode == ID_SCE) {
- if (tselem->id == (ID *)scene) {
+ if (tselem->id == (ID *)tvc->scene) {
/* active scene */
icon_bgcolor[3] = 0.2f;
active = OL_DRAWSEL_ACTIVE;
@@ -2984,15 +2979,15 @@ static void outliner_draw_tree_element(bContext *C,
else if (te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
- BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_find(tvc->view_layer, ob);
const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
- if (ob == obact) {
+ if (ob == tvc->obact) {
active = OL_DRAWSEL_ACTIVE;
}
if (is_selected) {
- if (ob == obact) {
+ if (ob == tvc->obact) {
/* active selected object */
UI_GetThemeColor3ubv(TH_ACTIVE_OBJECT, text_color);
text_color[3] = 255;
@@ -3004,14 +2999,14 @@ static void outliner_draw_tree_element(bContext *C,
}
}
}
- else if (is_object_data_in_editmode(tselem->id, obact)) {
+ else if (is_object_data_in_editmode(tselem->id, tvc->obact)) {
/* objects being edited */
UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_bgcolor);
icon_border[3] = 0.3f;
active = OL_DRAWSEL_ACTIVE;
}
else {
- if (tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false)) {
+ if (tree_element_active(C, tvc, soops, te, OL_SETSEL_NONE, false)) {
/* active items like camera or material */
icon_bgcolor[3] = 0.2f;
active = OL_DRAWSEL_ACTIVE;
@@ -3026,8 +3021,7 @@ static void outliner_draw_tree_element(bContext *C,
}
}
else {
- active = tree_element_type_active(
- C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false);
+ active = tree_element_type_active(C, tvc, soops, te, tselem, OL_SETSEL_NONE, false);
/* active collection*/
icon_bgcolor[3] = 0.2f;
}
@@ -3036,7 +3030,7 @@ static void outliner_draw_tree_element(bContext *C,
if ((tselem->type == TSE_LAYER_COLLECTION) &&
(soops->show_restrict_flags & SO_RESTRICT_ENABLE)) {
tselem_draw_layer_collection_enable_icon(
- scene, block, xmax, (float)startx + offsx + UI_UNIT_X, (float)*starty, te, 0.8f);
+ tvc->scene, block, xmax, (float)startx + offsx + UI_UNIT_X, (float)*starty, te, 0.8f);
offsx += UI_UNIT_X;
}
@@ -3155,8 +3149,7 @@ static void outliner_draw_tree_element(bContext *C,
outliner_draw_iconrow(C,
block,
fstyle,
- scene,
- view_layer,
+ tvc,
soops,
&te->subtree,
0,
@@ -3186,8 +3179,7 @@ static void outliner_draw_tree_element(bContext *C,
outliner_draw_tree_element(C,
block,
fstyle,
- scene,
- view_layer,
+ tvc,
ar,
soops,
ten,
@@ -3486,8 +3478,7 @@ static void outliner_draw_highlights(ARegion *ar, SpaceOutliner *soops, int star
static void outliner_draw_tree(bContext *C,
uiBlock *block,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
ARegion *ar,
SpaceOutliner *soops,
const float restrict_column_width,
@@ -3533,8 +3524,7 @@ static void outliner_draw_tree(bContext *C,
outliner_draw_tree_element(C,
block,
fstyle,
- scene,
- view_layer,
+ tvc,
ar,
soops,
te,
@@ -3625,15 +3615,16 @@ static void outliner_update_viewable_area(ARegion *ar,
void draw_outliner(const bContext *C)
{
Main *mainvar = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
SpaceOutliner *soops = CTX_wm_space_outliner(C);
uiBlock *block;
TreeElement *te_edit = NULL;
- outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
+ outliner_build_tree(mainvar, tvc.scene, tvc.view_layer, soops, ar); // always
/* If global sync select is dirty, flag other outliners */
if (ED_outliner_select_sync_is_dirty(C)) {
@@ -3655,8 +3646,7 @@ void draw_outliner(const bContext *C)
const float restrict_column_width = outliner_restrict_columns_width(soops);
outliner_back(ar);
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
- outliner_draw_tree(
- (bContext *)C, block, scene, view_layer, ar, soops, restrict_column_width, &te_edit);
+ outliner_draw_tree((bContext *)C, block, &tvc, ar, soops, restrict_column_width, &te_edit);
/* Compute outliner dimensions after it has been drawn. */
int tree_width, tree_height;
@@ -3682,7 +3672,8 @@ void draw_outliner(const bContext *C)
/* draw restriction columns */
RestrictPropertiesActive props_active;
memset(&props_active, 1, sizeof(RestrictPropertiesActive));
- outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &soops->tree, props_active);
+ outliner_draw_restrictbuts(
+ block, tvc.scene, tvc.view_layer, ar, soops, &soops->tree, props_active);
}
UI_block_emboss_set(block, UI_EMBOSS);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index c55140db46f..34bbf3a2a30 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -1600,7 +1600,11 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *soops, List
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
- if (tselem->type == 0) {
+ if (ELEM(tselem->type,
+ 0,
+ TSE_SCENE_OBJECTS_BASE,
+ TSE_VIEW_COLLECTION_BASE,
+ TSE_LAYER_COLLECTION)) {
if (te->idcode == ID_SCE) {
if (tselem->id != (ID *)scene) {
tselem->flag |= TSE_CLOSED;
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 95e37dea249..23c883c0db3 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -200,6 +200,25 @@ typedef enum {
#define TSELEM_OPEN(telm, sv) \
((telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)))
+/**
+ * Container to avoid passing around these variables to many functions.
+ * Also so we can have one place to assing these variables.
+ */
+typedef struct TreeViewContext {
+ /* Scene level. */
+ struct Scene *scene;
+ struct ViewLayer *view_layer;
+
+ /* Object level. */
+ /** Avoid OBACT macro everywhere. */
+ Object *obact;
+ Object *ob_edit;
+ /**
+ * The pose object may not be the active object (when in weight paint mode).
+ * Checking this in draw loops isn't efficient, so set only once. */
+ Object *ob_pose;
+} TreeViewContext;
+
/* outliner_tree.c ----------------------------------------------- */
void outliner_free_tree(ListBase *tree);
@@ -237,16 +256,14 @@ int tree_element_id_type_to_index(TreeElement *te);
/* outliner_select.c -------------------------------------------- */
eOLDrawState tree_element_type_active(struct bContext *C,
- struct Scene *scene,
- struct ViewLayer *view_layer,
+ const TreeViewContext *tvc,
struct SpaceOutliner *soops,
TreeElement *te,
TreeStoreElem *tselem,
const eOLSetState set,
bool recursive);
eOLDrawState tree_element_active(struct bContext *C,
- struct Scene *scene,
- struct ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
TreeElement *te,
const eOLSetState set,
@@ -267,7 +284,8 @@ void outliner_object_mode_toggle(struct bContext *C,
void outliner_element_activate(struct SpaceOutliner *soops, struct TreeStoreElem *tselem);
-bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x);
+bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x);
+bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x);
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_cb)(struct bContext *C,
@@ -457,6 +475,8 @@ void OUTLINER_OT_unhide_all(struct wmOperatorType *ot);
/* outliner_utils.c ---------------------------------------------- */
+void outliner_viewcontext_init(const struct bContext *C, TreeViewContext *tvc);
+
TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
const ListBase *tree,
float view_co_y);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 19bbb115788..c96f2f9956f 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -595,6 +595,7 @@ static eOLDrawState tree_element_active_posegroup(bContext *C,
static eOLDrawState tree_element_active_posechannel(bContext *C,
Scene *UNUSED(scene),
ViewLayer *view_layer,
+ Object *ob_pose,
TreeElement *te,
TreeStoreElem *tselem,
const eOLSetState set,
@@ -651,7 +652,7 @@ static eOLDrawState tree_element_active_posechannel(bContext *C,
}
}
else {
- if (ob == OBACT(view_layer) && ob->pose) {
+ if (ob == ob_pose && ob->pose) {
if (pchan->bone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
}
@@ -1007,8 +1008,7 @@ static eOLDrawState tree_element_active_layer_collection(bContext *C,
/* generic call for ID data check or make/check active in UI */
eOLDrawState tree_element_active(bContext *C,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
TreeElement *te,
const eOLSetState set,
@@ -1020,17 +1020,18 @@ eOLDrawState tree_element_active(bContext *C,
* See #do_outliner_item_activate. */
case ID_OB:
if (handle_all_types) {
- return tree_element_set_active_object(C, scene, view_layer, soops, te, set, false);
+ return tree_element_set_active_object(
+ C, tvc->scene, tvc->view_layer, soops, te, set, false);
}
break;
case ID_MA:
- return tree_element_active_material(C, scene, view_layer, soops, te, set);
+ return tree_element_active_material(C, tvc->scene, tvc->view_layer, soops, te, set);
case ID_WO:
- return tree_element_active_world(C, scene, view_layer, soops, te, set);
+ return tree_element_active_world(C, tvc->scene, tvc->view_layer, soops, te, set);
case ID_TXT:
- return tree_element_active_text(C, scene, view_layer, soops, te, set);
+ return tree_element_active_text(C, tvc->scene, tvc->view_layer, soops, te, set);
case ID_CA:
- return tree_element_active_camera(C, scene, view_layer, soops, te, set);
+ return tree_element_active_camera(C, tvc->scene, tvc->view_layer, soops, te, set);
}
return OL_DRAWSEL_NONE;
}
@@ -1039,8 +1040,7 @@ eOLDrawState tree_element_active(bContext *C,
* Generic call for non-id data to make/check active in UI
*/
eOLDrawState tree_element_type_active(bContext *C,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
TreeElement *te,
TreeStoreElem *tselem,
@@ -1049,41 +1049,42 @@ eOLDrawState tree_element_type_active(bContext *C,
{
switch (tselem->type) {
case TSE_DEFGROUP:
- return tree_element_active_defgroup(C, view_layer, te, tselem, set);
+ return tree_element_active_defgroup(C, tvc->view_layer, te, tselem, set);
case TSE_BONE:
- return tree_element_active_bone(C, view_layer, te, tselem, set, recursive);
+ return tree_element_active_bone(C, tvc->view_layer, te, tselem, set, recursive);
case TSE_EBONE:
- return tree_element_active_ebone(C, view_layer, te, tselem, set, recursive);
+ return tree_element_active_ebone(C, tvc->view_layer, te, tselem, set, recursive);
case TSE_MODIFIER:
- return tree_element_active_modifier(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_modifier(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_LINKED_OB:
if (set != OL_SETSEL_NONE) {
- tree_element_set_active_object(C, scene, view_layer, soops, te, set, false);
+ tree_element_set_active_object(C, tvc->scene, tvc->view_layer, soops, te, set, false);
}
- else if (tselem->id == (ID *)OBACT(view_layer)) {
+ else if (tselem->id == (ID *)tvc->obact) {
return OL_DRAWSEL_NORMAL;
}
break;
case TSE_LINKED_PSYS:
- return tree_element_active_psys(C, scene, te, tselem, set);
+ return tree_element_active_psys(C, tvc->scene, te, tselem, set);
case TSE_POSE_BASE:
- return tree_element_active_pose(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_pose(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_POSE_CHANNEL:
- return tree_element_active_posechannel(C, scene, view_layer, te, tselem, set, recursive);
+ return tree_element_active_posechannel(
+ C, tvc->scene, tvc->view_layer, tvc->ob_pose, te, tselem, set, recursive);
case TSE_CONSTRAINT:
- return tree_element_active_constraint(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_constraint(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_R_LAYER:
- return active_viewlayer(C, scene, view_layer, te, set);
+ return active_viewlayer(C, tvc->scene, tvc->view_layer, te, set);
case TSE_POSEGRP:
- return tree_element_active_posegroup(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_posegroup(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_SEQUENCE:
- return tree_element_active_sequence(C, scene, te, tselem, set);
+ return tree_element_active_sequence(C, tvc->scene, te, tselem, set);
case TSE_SEQUENCE_DUP:
- return tree_element_active_sequence_dup(scene, te, tselem, set);
+ return tree_element_active_sequence_dup(tvc->scene, te, tselem, set);
case TSE_KEYMAP_ITEM:
- return tree_element_active_keymap_item(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_keymap_item(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_GP_LAYER:
- return tree_element_active_gplayer(C, scene, te, tselem, set);
+ return tree_element_active_gplayer(C, tvc->scene, te, tselem, set);
break;
case TSE_VIEW_COLLECTION_BASE:
return tree_element_active_master_collection(C, te, set);
@@ -1109,14 +1110,15 @@ void outliner_element_activate(SpaceOutliner *soops, TreeStoreElem *tselem)
* Needed to run from operators accessed from a menu.
*/
static void do_outliner_item_activate_tree_element(bContext *C,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
TreeElement *te,
TreeStoreElem *tselem,
const bool extend,
- const bool recursive)
+ const bool recursive,
+ const bool is_over_name_icons)
{
+ bool do_activate_data = soops->flag & SO_SYNC_SELECT || is_over_name_icons;
/* Always makes active object, except for some specific types. */
if (ELEM(tselem->type,
TSE_SEQUENCE,
@@ -1133,11 +1135,11 @@ static void do_outliner_item_activate_tree_element(bContext *C,
else if (tselem->type == TSE_POSE_BASE) {
/* Support pose mode toggle, keeping the active object as is. */
}
- else if (soops->flag & SO_SYNC_SELECT) {
+ else if (do_activate_data) {
/* Only activate when synced selection is enabled */
tree_element_set_active_object(C,
- scene,
- view_layer,
+ tvc->scene,
+ tvc->view_layer,
soops,
te,
(extend && tselem->type == 0) ? OL_SETSEL_EXTEND :
@@ -1149,9 +1151,11 @@ static void do_outliner_item_activate_tree_element(bContext *C,
outliner_element_activate(soops, tselem);
if (tselem->type == 0) { // the lib blocks
- /* editmode? */
- if (te->idcode == ID_SCE) {
- if (scene != (Scene *)tselem->id) {
+ if (do_activate_data == false) {
+ /* Only select in outliner. */
+ }
+ else if (te->idcode == ID_SCE) {
+ if (tvc->scene != (Scene *)tselem->id) {
WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id);
}
}
@@ -1161,7 +1165,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
if (extend) {
int sel = BA_SELECT;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
- Base *base = BKE_view_layer_base_find(view_layer, object);
+ Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
if (base && (base->flag & BASE_SELECTED)) {
sel = BA_DESELECT;
break;
@@ -1170,7 +1174,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
- Base *base = BKE_view_layer_base_find(view_layer, object);
+ Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
if (base) {
ED_object_base_select(base, sel);
}
@@ -1178,10 +1182,10 @@ static void do_outliner_item_activate_tree_element(bContext *C,
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
else {
- BKE_view_layer_base_deselect_all(view_layer);
+ BKE_view_layer_base_deselect_all(tvc->view_layer);
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
- Base *base = BKE_view_layer_base_find(view_layer, object);
+ Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
/* Object may not be in this scene */
if (base != NULL) {
if ((base->flag & BASE_SELECTED) == 0) {
@@ -1192,15 +1196,15 @@ static void do_outliner_item_activate_tree_element(bContext *C,
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ DEG_id_tag_update(&tvc->scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, tvc->scene);
}
else if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) {
Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
if ((ob != NULL) && (ob->data == tselem->id)) {
- Base *base = BKE_view_layer_base_find(view_layer, ob);
+ Base *base = BKE_view_layer_base_find(tvc->view_layer, ob);
if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
- do_outliner_activate_obdata(C, scene, view_layer, base, extend);
+ do_outliner_activate_obdata(C, tvc->scene, tvc->view_layer, base, extend);
}
}
}
@@ -1209,18 +1213,12 @@ static void do_outliner_item_activate_tree_element(bContext *C,
WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
}
else { // rest of types
- tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false);
+ tree_element_active(C, tvc, soops, te, OL_SETSEL_NORMAL, false);
}
}
- else if (soops->flag & SO_SYNC_SELECT) {
- tree_element_type_active(C,
- scene,
- view_layer,
- soops,
- te,
- tselem,
- extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
- recursive);
+ else if (do_activate_data) {
+ tree_element_type_active(
+ C, tvc, soops, te, tselem, extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, recursive);
}
}
@@ -1327,12 +1325,12 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops,
void outliner_item_do_activate_from_tree_element(
bContext *C, TreeElement *te, TreeStoreElem *tselem, bool extend, bool recursive)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
- do_outliner_item_activate_tree_element(
- C, scene, view_layer, soops, te, tselem, extend, recursive);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
+ do_outliner_item_activate_tree_element(C, &tvc, soops, te, tselem, extend, recursive, false);
}
/**
@@ -1347,7 +1345,6 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
const bool deselect_all)
{
ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te;
float view_mval[2];
@@ -1371,8 +1368,6 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
else {
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
/* The row may also contain children, if one is hovered we want this instead of current te */
bool merged_elements = false;
TreeElement *activate_te = outliner_find_item_at_x_in_row(
@@ -1390,9 +1385,14 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
do_outliner_range_select(C, soops, activate_te, extend);
}
else {
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
+ const bool is_over_name_icons = outliner_item_is_co_over_name_icons(activate_te,
+ view_mval[0]);
outliner_item_select(soops, activate_te, extend, extend);
do_outliner_item_activate_tree_element(
- C, scene, view_layer, soops, activate_te, activate_tselem, extend, false);
+ C, &tvc, soops, activate_te, activate_tselem, extend, false, is_over_name_icons);
}
changed = true;
@@ -1505,17 +1505,6 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* Find if x coordinate is over an icon or name */
-static bool outliner_item_is_co_over_name_icons(TreeElement *te, float view_co_x)
-{
- /* Special case: count area left of Scene Collection as empty space */
- bool outside_left = (TREESTORE(te)->type == TSE_VIEW_COLLECTION_BASE) ?
- (view_co_x > te->xs + UI_UNIT_X) :
- (view_co_x > te->xs);
-
- return outside_left && (view_co_x < te->xend);
-}
-
static int outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceOutliner *soops = CTX_wm_space_outliner(C);
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index 29c820bce92..745a527cc15 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_object.h"
#include "BKE_sequencer.h"
#include "DEG_depsgraph.h"
@@ -129,14 +130,14 @@ static void outliner_sync_select_from_outliner_set_types(bContext *C,
SpaceOutliner *soops,
SyncSelectTypes *sync_types)
{
- Object *obact = CTX_data_active_object(C);
- Object *obedit = CTX_data_edit_object(C);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
sync_types->object = !sequence_view;
- sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE);
- sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE);
+ sync_types->edit_bone = !sequence_view && (tvc.ob_edit && tvc.ob_edit->type == OB_ARMATURE);
+ sync_types->pose_bone = !sequence_view && (tvc.ob_pose && tvc.ob_pose->mode == OB_MODE_POSE);
sync_types->sequence = sequence_view;
}
@@ -149,16 +150,16 @@ static bool outliner_sync_select_to_outliner_set_types(const bContext *C,
SpaceOutliner *soops,
SyncSelectTypes *sync_types)
{
- Object *obact = CTX_data_active_object(C);
- Object *obedit = CTX_data_edit_object(C);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
sync_types->object = !sequence_view &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_OBJECT);
- sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE) &&
+ sync_types->edit_bone = !sequence_view && (tvc.ob_edit && tvc.ob_edit->type == OB_ARMATURE) &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE);
- sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE) &&
+ sync_types->pose_bone = !sequence_view && (tvc.ob_pose && tvc.ob_pose->mode == OB_MODE_POSE) &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE);
sync_types->sequence = sequence_view &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE);
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
index 5dfdf6f129b..c3984ab16fa 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -21,6 +21,8 @@
* \ingroup spoutliner
*/
+#include <string.h>
+
#include "BLI_utildefines.h"
#include "DNA_action_types.h"
@@ -30,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_outliner_treehash.h"
#include "BKE_layer.h"
+#include "BKE_object.h"
#include "ED_armature.h"
#include "ED_outliner.h"
@@ -39,6 +42,33 @@
#include "outliner_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Tree View Context
+ * \{ */
+
+void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
+{
+ memset(tvc, 0, sizeof(*tvc));
+
+ /* Scene level. */
+ tvc->scene = CTX_data_scene(C);
+ tvc->view_layer = CTX_data_view_layer(C);
+
+ /* Objects. */
+ tvc->obact = OBACT(tvc->view_layer);
+ if (tvc->obact != NULL) {
+ tvc->ob_edit = OBEDIT_FROM_OBACT(tvc->obact);
+
+ if ((tvc->obact->type == OB_ARMATURE) ||
+ /* This could be made into it's own function. */
+ ((tvc->obact->type == OB_MESH) && tvc->obact->mode & OB_MODE_WEIGHT_PAINT)) {
+ tvc->ob_pose = BKE_object_pose_armature_get(tvc->obact);
+ }
+ }
+}
+
+/** \} */
+
/**
* Try to find an item under y-coordinate \a view_co_y (view-space).
* \note Recursive
@@ -361,8 +391,19 @@ bool outliner_is_element_visible(const TreeElement *te)
return true;
}
+/* Find if x coordinate is over an icon or name */
+bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x)
+{
+ /* Special case: count area left of Scene Collection as empty space */
+ bool outside_left = (TREESTORE(te)->type == TSE_VIEW_COLLECTION_BASE) ?
+ (view_co_x > te->xs + UI_UNIT_X) :
+ (view_co_x > te->xs);
+
+ return outside_left && (view_co_x < te->xend);
+}
+
/* Find if x coordinate is over element disclosure toggle */
-bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
+bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x)
{
return (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 851d3b5f3aa..093d333c007 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -160,7 +160,7 @@ void SEQUENCER_OT_select_less(struct wmOperatorType *ot);
void SEQUENCER_OT_select_linked(struct wmOperatorType *ot);
void SEQUENCER_OT_select_linked_pick(struct wmOperatorType *ot);
void SEQUENCER_OT_select_handles(struct wmOperatorType *ot);
-void SEQUENCER_OT_select_active_side(struct wmOperatorType *ot);
+void SEQUENCER_OT_select_side(struct wmOperatorType *ot);
void SEQUENCER_OT_select_box(struct wmOperatorType *ot);
void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot);
void SEQUENCER_OT_select_grouped(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index b0bb775de83..e91d6cfa3e6 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -96,7 +96,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_select_linked_pick);
WM_operatortype_append(SEQUENCER_OT_select_linked);
WM_operatortype_append(SEQUENCER_OT_select_handles);
- WM_operatortype_append(SEQUENCER_OT_select_active_side);
+ WM_operatortype_append(SEQUENCER_OT_select_side);
WM_operatortype_append(SEQUENCER_OT_select_box);
WM_operatortype_append(SEQUENCER_OT_select_grouped);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 4c20fc1707a..a51b08f7525 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -27,6 +27,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_math.h"
#include "DNA_scene_types.h"
@@ -81,7 +82,7 @@ static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRIN
}
}
-/* used for mouse selection and for SEQUENCER_OT_select_active_side() */
+/* Used for mouse selection in SEQUENCER_OT_select. */
static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
{
Sequence *seq;
@@ -110,7 +111,43 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
}
}
-/* used for mouse selection and for SEQUENCER_OT_select_active_side() */
+/* Used for mouse selection in SEQUENCER_OT_select_side. */
+static void select_active_side_range(ListBase *seqbase,
+ const int sel_side,
+ const int frame_ranges[MAXSEQ],
+ const int frame_ignore)
+{
+ Sequence *seq;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if (seq->machine < MAXSEQ) {
+ const int frame = frame_ranges[seq->machine];
+ if (frame == frame_ignore) {
+ continue;
+ }
+ switch (sel_side) {
+ case SEQ_SIDE_LEFT:
+ if (frame > (seq->startdisp)) {
+ seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
+ }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if (frame < (seq->startdisp)) {
+ seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
+ }
+ break;
+ case SEQ_SIDE_BOTH:
+ seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
+ break;
+ }
+ }
+ }
+}
+
+/* used for mouse selection in SEQUENCER_OT_select */
static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
{
Sequence *seq;
@@ -913,20 +950,39 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot)
}
/* select side operator */
-static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
+static int sequencer_select_side_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq_act = BKE_sequencer_active_get(scene);
- if (ed == NULL || seq_act == NULL) {
- return OPERATOR_CANCELLED;
+ const int sel_side = RNA_enum_get(op->ptr, "side");
+ const int frame_init = sel_side == SEQ_SIDE_LEFT ? INT_MIN : INT_MAX;
+ int frame_ranges[MAXSEQ];
+ bool selected = false;
+
+ copy_vn_i(frame_ranges, ARRAY_SIZE(frame_ranges), frame_init);
+
+ for (Sequence *seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (UNLIKELY(seq->machine >= MAXSEQ)) {
+ continue;
+ }
+ int *frame_limit_p = &frame_ranges[seq->machine];
+ if (seq->flag & SELECT) {
+ selected = true;
+ if (sel_side == SEQ_SIDE_LEFT) {
+ *frame_limit_p = max_ii(*frame_limit_p, seq->startdisp);
+ }
+ else {
+ *frame_limit_p = min_ii(*frame_limit_p, seq->startdisp);
+ }
+ }
}
- seq_act->flag |= SELECT;
+ if (selected == false) {
+ return OPERATOR_CANCELLED;
+ }
- select_active_side(
- ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
+ select_active_side_range(ed->seqbasep, sel_side, frame_ranges, frame_init);
ED_outliner_select_sync_from_sequence_tag(C);
@@ -935,15 +991,15 @@ static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
+void SEQUENCER_OT_select_side(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Select Active Side";
- ot->idname = "SEQUENCER_OT_select_active_side";
- ot->description = "Select strips on the nominated side of the active strip";
+ ot->name = "Select Side";
+ ot->idname = "SEQUENCER_OT_select_side";
+ ot->description = "Select strips on the nominated side of the selected strips";
/* api callbacks */
- ot->exec = sequencer_select_active_side_exec;
+ ot->exec = sequencer_select_side_exec;
ot->poll = sequencer_edit_poll;
/* flags */
@@ -955,7 +1011,7 @@ void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
prop_side_types,
SEQ_SIDE_BOTH,
"Side",
- "The side of the handle that is selected");
+ "The side to which the selection is applied");
}
/* box_select operator */
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index a66e76abc58..15208c1a7d2 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -379,6 +379,8 @@ void applyProject(TransInfo *t)
.snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
.use_occlusion_test = false,
+ .use_backface_culling = (t->scene->toolsettings->snap_flag &
+ SCE_SNAP_BACKFACE_CULLING) != 0,
},
mval_fl,
NULL,
@@ -1364,6 +1366,8 @@ short snapObjectsTransform(
.snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
.use_occlusion_test = t->scene->toolsettings->snap_mode != SCE_SNAP_MODE_FACE,
+ .use_backface_culling = (t->scene->toolsettings->snap_flag &
+ SCE_SNAP_BACKFACE_CULLING) != 0,
},
mval,
t->tsnap.snapTarget,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index f35a2808f22..14e8b8f97e0 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -201,8 +201,12 @@ static SnapObjectData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext
return *sod_p;
}
-typedef void (*IterSnapObjsCallback)(
- SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data);
+typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
+ bool is_obedit,
+ bool use_backface_culling,
+ Object *ob,
+ float obmat[4][4],
+ void *data);
/**
* Walks through all objects in the scene to create the list of objects to snap.
@@ -219,6 +223,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
const View3D *v3d = sctx->v3d_data.v3d;
const eSnapSelect snap_select = params->snap_select;
const bool use_object_edit_cage = params->use_object_edit_cage;
+ const bool use_backface_culling = params->use_backface_culling;
Base *base_act = view_layer->basact;
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
@@ -250,12 +255,14 @@ static void iter_snap_objects(SnapObjectContext *sctx,
DupliObject *dupli_ob;
ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval);
for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- sob_callback(sctx, use_object_edit_cage, dupli_ob->ob, dupli_ob->mat, data);
+ sob_callback(
+ sctx, use_object_edit_cage, use_backface_culling, dupli_ob->ob, dupli_ob->mat, data);
}
free_object_duplilist(lb);
}
- sob_callback(sctx, use_object_edit_cage, obj_eval, obj_eval->obmat, data);
+ sob_callback(
+ sctx, use_object_edit_cage, use_backface_culling, obj_eval, obj_eval->obmat, data);
}
}
@@ -350,6 +357,70 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
}
}
+static bool raycast_tri_backface_culling_test(
+ const float dir[3], const float v0[3], const float v1[3], const float v2[3], float no[3])
+{
+ cross_tri_v3(no, v0, v1, v2);
+ return dot_v3v3(no, dir) < 0.0f;
+}
+
+/* Callback to raycast with backface culling (Mesh). */
+static void mesh_looptri_raycast_backface_culling_cb(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
+{
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MLoopTri *lt = &data->looptri[index];
+ const float *vtri_co[3] = {
+ vert[data->loop[lt->tri[0]].v].co,
+ vert[data->loop[lt->tri[1]].v].co,
+ vert[data->loop[lt->tri[2]].v].co,
+ };
+ float dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
+
+ if (dist >= 0 && dist < hit->dist) {
+ float no[3];
+ if (raycast_tri_backface_culling_test(ray->direction, UNPACK3(vtri_co), no)) {
+ hit->index = index;
+ hit->dist = dist;
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+ normalize_v3_v3(hit->no, no);
+ }
+ }
+}
+
+/* Callback to raycast with backface culling (EditMesh). */
+static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
+{
+ const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
+ BMEditMesh *em = data->em;
+ const BMLoop **ltri = (const BMLoop **)em->looptris[index];
+
+ const float *t0, *t1, *t2;
+ t0 = ltri[0]->v->co;
+ t1 = ltri[1]->v->co;
+ t2 = ltri[2]->v->co;
+
+ {
+ float dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
+
+ if (dist >= 0 && dist < hit->dist) {
+ float no[3];
+ if (raycast_tri_backface_culling_test(ray->direction, t0, t1, t2, no)) {
+ hit->index = index;
+ hit->dist = dist;
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+ normalize_v3_v3(hit->no, no);
+ }
+ }
+ }
+}
+
static bool raycastMesh(SnapObjectContext *sctx,
const float ray_start[3],
const float ray_dir[3],
@@ -358,6 +429,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
const float obmat[4][4],
const unsigned int ob_index,
bool use_hide,
+ bool use_backface_culling,
/* read/write args */
float *ray_depth,
/* return args */
@@ -494,7 +566,8 @@ static bool raycastMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- treedata->raycast_callback,
+ use_backface_culling ? mesh_looptri_raycast_backface_culling_cb :
+ treedata->raycast_callback,
treedata) != -1) {
hit.dist += len_diff;
hit.dist /= local_scale;
@@ -530,6 +603,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
BMEditMesh *em,
const float obmat[4][4],
const unsigned int ob_index,
+ bool use_backface_culling,
/* read/write args */
float *ray_depth,
/* return args */
@@ -670,7 +744,8 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- treedata->raycast_callback,
+ use_backface_culling ? editmesh_looptri_raycast_backface_culling_cb :
+ treedata->raycast_callback,
treedata) != -1) {
hit.dist += len_diff;
hit.dist /= local_scale;
@@ -715,6 +790,7 @@ static bool raycastObj(SnapObjectContext *sctx,
const unsigned int ob_index,
bool use_obedit,
bool use_occlusion_test,
+ bool use_backface_culling,
/* read/write args */
float *ray_depth,
/* return args */
@@ -753,6 +829,7 @@ static bool raycastObj(SnapObjectContext *sctx,
em,
obmat,
ob_index,
+ use_backface_culling,
ray_depth,
r_loc,
r_no,
@@ -773,6 +850,7 @@ static bool raycastObj(SnapObjectContext *sctx,
obmat,
ob_index,
use_hide,
+ use_backface_culling,
ray_depth,
r_loc,
r_no,
@@ -792,6 +870,7 @@ static bool raycastObj(SnapObjectContext *sctx,
obmat,
ob_index,
false,
+ use_backface_culling,
ray_depth,
r_loc,
r_no,
@@ -832,8 +911,12 @@ struct RaycastObjUserData {
bool ret;
};
-static void raycast_obj_cb(
- SnapObjectContext *sctx, bool use_obedit, Object *ob, float obmat[4][4], void *data)
+static void raycast_obj_cb(SnapObjectContext *sctx,
+ bool use_obedit,
+ bool use_backface_culling,
+ Object *ob,
+ float obmat[4][4],
+ void *data)
{
struct RaycastObjUserData *dt = data;
@@ -845,6 +928,7 @@ static void raycast_obj_cb(
dt->ob_index++,
use_obedit,
dt->use_occlusion_test,
+ use_backface_culling,
dt->ray_depth,
dt->r_loc,
dt->r_no,
@@ -1088,8 +1172,6 @@ typedef void (*Nearest2DGetTriEdgesCallback)(const int index, int e_index[3], vo
typedef void (*Nearest2DCopyVertNoCallback)(const int index, float r_no[3], void *data);
typedef struct Nearest2dUserData {
- bool is_persp;
-
void *userdata;
Nearest2DGetVertCoCallback get_vert_co;
Nearest2DGetEdgeVertsCallback get_edge_verts_index;
@@ -1097,6 +1179,8 @@ typedef struct Nearest2dUserData {
Nearest2DGetTriEdgesCallback get_tri_edges_index;
Nearest2DCopyVertNoCallback copy_vert_no;
+ bool is_persp;
+ bool use_backface_culling;
} Nearest2dUserData;
static void cb_snap_vert(void *userdata,
@@ -1181,6 +1265,20 @@ static void cb_snap_tri_edges(void *userdata,
{
struct Nearest2dUserData *data = userdata;
+ if (data->use_backface_culling) {
+ int vindex[3];
+ data->get_tri_verts_index(index, vindex, data->userdata);
+
+ const float *t0, *t1, *t2;
+ data->get_vert_co(vindex[0], &t0, data->userdata);
+ data->get_vert_co(vindex[1], &t1, data->userdata);
+ data->get_vert_co(vindex[2], &t2, data->userdata);
+ float dummy[3];
+ if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
+ return;
+ }
+ }
+
int eindex[3];
data->get_tri_edges_index(index, eindex, data->userdata);
for (int i = 3; i--;) {
@@ -1204,6 +1302,18 @@ static void cb_snap_tri_verts(void *userdata,
int vindex[3];
data->get_tri_verts_index(index, vindex, data->userdata);
+
+ if (data->use_backface_culling) {
+ const float *t0, *t1, *t2;
+ data->get_vert_co(vindex[0], &t0, data->userdata);
+ data->get_vert_co(vindex[1], &t1, data->userdata);
+ data->get_vert_co(vindex[2], &t2, data->userdata);
+ float dummy[3];
+ if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
+ return;
+ }
+ }
+
for (int i = 3; i--;) {
if (vindex[i] == nearest->index) {
continue;
@@ -1222,6 +1332,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
const float obmat[4][4],
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -1246,6 +1357,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
Nearest2dUserData nearest2d = {
.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
+ .use_backface_culling = use_backface_culling,
};
BVHTreeNearest nearest = {
@@ -1366,6 +1478,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
const float obmat[4][4],
float original_dist_px,
const float prev_co[3],
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -1392,6 +1505,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
Nearest2dUserData nearest2d;
{
nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ nearest2d.use_backface_culling = use_backface_culling;
if (sod->type == SNAP_MESH) {
nearest2d.userdata = &((SnapObjectData_Mesh *)sod)->treedata;
nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
@@ -1995,6 +2109,7 @@ static short snapMesh(SnapObjectContext *sctx,
Object *ob,
Mesh *me,
const float obmat[4][4],
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -2107,13 +2222,14 @@ static short snapMesh(SnapObjectContext *sctx,
}
Nearest2dUserData nearest2d = {
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
.userdata = treedata,
.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get,
.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get,
.get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get,
.get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get,
.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy,
+ .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
+ .use_backface_culling = use_backface_culling,
};
BVHTreeNearest nearest = {
@@ -2233,6 +2349,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
Object *ob,
BMEditMesh *em,
const float obmat[4][4],
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -2346,11 +2463,12 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
Nearest2dUserData nearest2d = {
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
.userdata = em,
.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get,
.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get,
.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy,
+ .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
+ .use_backface_culling = use_backface_culling,
};
BVHTreeNearest nearest = {
@@ -2436,6 +2554,7 @@ static short snapObject(SnapObjectContext *sctx,
Object *ob,
float obmat[4][4],
bool use_obedit,
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -2453,7 +2572,8 @@ static short snapObject(SnapObjectContext *sctx,
if (BKE_object_is_in_editmode(ob)) {
BMEditMesh *em = BKE_editmesh_from_object(ob);
if (use_obedit) {
- retval = snapEditMesh(sctx, snapdata, ob, em, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapEditMesh(
+ sctx, snapdata, ob, em, obmat, use_backface_culling, dist_px, r_loc, r_no, r_index);
break;
}
else if (em->mesh_eval_final) {
@@ -2465,7 +2585,8 @@ static short snapObject(SnapObjectContext *sctx,
return 0;
}
- retval = snapMesh(sctx, snapdata, ob, me, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapMesh(
+ sctx, snapdata, ob, me, obmat, use_backface_culling, dist_px, r_loc, r_no, r_index);
break;
}
case OB_ARMATURE:
@@ -2477,8 +2598,16 @@ static short snapObject(SnapObjectContext *sctx,
case OB_SURF:
case OB_FONT: {
if (ob->runtime.mesh_eval) {
- retval |= snapMesh(
- sctx, snapdata, ob, ob->runtime.mesh_eval, obmat, dist_px, r_loc, r_no, r_index);
+ retval |= snapMesh(sctx,
+ snapdata,
+ ob,
+ ob->runtime.mesh_eval,
+ obmat,
+ use_backface_culling,
+ dist_px,
+ r_loc,
+ r_no,
+ r_index);
}
break;
}
@@ -2519,8 +2648,12 @@ struct SnapObjUserData {
short ret;
};
-static void sanp_obj_cb(
- SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data)
+static void sanp_obj_cb(SnapObjectContext *sctx,
+ bool is_obedit,
+ bool use_backface_culling,
+ Object *ob,
+ float obmat[4][4],
+ void *data)
{
struct SnapObjUserData *dt = data;
@@ -2529,6 +2662,7 @@ static void sanp_obj_cb(
ob,
obmat,
is_obedit,
+ use_backface_culling,
/* read/write args */
dt->dist_px,
/* return args */
@@ -2881,7 +3015,8 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem_test = snap_mesh_polygon(sctx, &snapdata, ob, obmat, &dist_px_tmp, loc, no, &index);
+ elem_test = snap_mesh_polygon(
+ sctx, &snapdata, ob, obmat, params->use_backface_culling, &dist_px_tmp, loc, no, &index);
if (elem_test) {
elem = elem_test;
}
@@ -2904,8 +3039,17 @@ static short transform_snap_context_project_view3d_mixed_impl(
(snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR))) {
snapdata.snap_to_flag = snap_to_flag;
- elem = snap_mesh_edge_verts_mixed(
- sctx, &snapdata, ob, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index);
+ elem = snap_mesh_edge_verts_mixed(sctx,
+ &snapdata,
+ ob,
+ obmat,
+ *dist_px,
+ prev_co,
+ params->use_backface_culling,
+ &dist_px_tmp,
+ loc,
+ no,
+ &index);
}
if (elem & snap_to_flag) {
diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h
index 714c205cda2..b2d4124a348 100644
--- a/source/blender/makesdna/DNA_brush_defaults.h
+++ b/source/blender/makesdna/DNA_brush_defaults.h
@@ -34,6 +34,7 @@
{ \
.blend = 0, \
.flag = (BRUSH_ALPHA_PRESSURE | BRUSH_SPACE | BRUSH_SPACE_ATTEN), \
+ .sampling_flag = (BRUSH_PAINT_ANTIALIASING), \
\
.ob_mode = OB_MODE_ALL_PAINT, \
\
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index fc8763f1519..63fbf576bba 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -245,8 +245,9 @@ typedef struct Brush {
float weight;
/** Brush diameter. */
int size;
- /** General purpose flag. */
+ /** General purpose flags. */
int flag;
+ int sampling_flag;
/** Pressure influence for mask. */
int mask_pressure;
/** Jitter the position of the brush. */
@@ -283,7 +284,7 @@ typedef struct Brush {
/** Source for fill tool color gradient application. */
char gradient_fill_mode;
- char _pad;
+ char _pad[5];
/** Projection shape (sphere, circle). */
char falloff_shape;
float falloff_angle;
@@ -435,6 +436,11 @@ typedef enum eBrushFlags {
BRUSH_CURVE = (1u << 31),
} eBrushFlags;
+/* Brush.sampling_flag */
+typedef enum eBrushSamplingFlags {
+ BRUSH_PAINT_ANTIALIASING = (1 << 0),
+} eBrushSamplingFlags;
+
typedef enum {
BRUSH_MASK_PRESSURE_RAMP = (1 << 1),
BRUSH_MASK_PRESSURE_CUTOFF = (1 << 2),
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 3794508d5a2..2ca9e3b2ef7 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -2035,6 +2035,7 @@ enum {
#define SCE_SNAP_PROJECT (1 << 3)
#define SCE_SNAP_NO_SELF (1 << 4)
#define SCE_SNAP_ABS_GRID (1 << 5)
+#define SCE_SNAP_BACKFACE_CULLING (1 << 6)
/* ToolSettings.snap_target */
#define SCE_SNAP_TARGET_CLOSEST 0
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 99c1bdfdbee..a392e4c080f 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -2007,6 +2007,11 @@ static void rna_def_brush(BlenderRNA *brna)
"Apply the maximum grab strength to the active vertex instead of the cursor location");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_paint_antialiasing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sampling_flag", BRUSH_PAINT_ANTIALIASING);
+ RNA_def_property_ui_text(prop, "Antialasing", "Smooths the edges of the strokes");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ALPHA_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index f1e20b32ddc..b9bc7b2bbf5 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3035,6 +3035,11 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Project individual elements on the surface of other objects");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ prop = RNA_def_property(srna, "use_snap_backface_culling", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_BACKFACE_CULLING);
+ RNA_def_property_ui_text(prop, "Backface Culling", "Exclude back facing geometry from snapping");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
prop = RNA_def_property(srna, "use_snap_self", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "snap_flag", SCE_SNAP_NO_SELF);
RNA_def_property_ui_text(prop, "Project onto Self", "Snap onto itself (Edit Mode Only)");
diff --git a/tests/gtests/blenlib/BLI_task_performance_test.cc b/tests/gtests/blenlib/BLI_task_performance_test.cc
index ecc012aa47a..dc8981f8064 100644
--- a/tests/gtests/blenlib/BLI_task_performance_test.cc
+++ b/tests/gtests/blenlib/BLI_task_performance_test.cc
@@ -38,14 +38,22 @@ static uint gen_pseudo_random_number(uint num)
return ((num & 255) << 6) + 1;
}
-static void task_listbase_light_iter_func(void *UNUSED(userdata), Link *item, int index)
+static void task_listbase_light_iter_func(void *UNUSED(userdata),
+ void *item,
+ int index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+
{
LinkData *data = (LinkData *)item;
data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + index);
}
-static void task_listbase_light_membarrier_iter_func(void *userdata, Link *item, int index)
+static void task_listbase_light_membarrier_iter_func(void *userdata,
+ void *item,
+ int index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+
{
LinkData *data = (LinkData *)item;
int *count = (int *)userdata;
@@ -54,7 +62,11 @@ static void task_listbase_light_membarrier_iter_func(void *userdata, Link *item,
atomic_sub_and_fetch_uint32((uint32_t *)count, 1);
}
-static void task_listbase_heavy_iter_func(void *UNUSED(userdata), Link *item, int index)
+static void task_listbase_heavy_iter_func(void *UNUSED(userdata),
+ void *item,
+ int index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+
{
LinkData *data = (LinkData *)item;
@@ -66,7 +78,11 @@ static void task_listbase_heavy_iter_func(void *UNUSED(userdata), Link *item, in
}
}
-static void task_listbase_heavy_membarrier_iter_func(void *userdata, Link *item, int index)
+static void task_listbase_heavy_membarrier_iter_func(void *userdata,
+ void *item,
+ int index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+
{
LinkData *data = (LinkData *)item;
int *count = (int *)userdata;
@@ -84,14 +100,18 @@ static void task_listbase_test_do(ListBase *list,
const int num_items,
int *num_items_tmp,
const char *id,
- TaskParallelListbaseFunc func,
+ TaskParallelIteratorFunc func,
const bool use_threads,
const bool check_num_items_tmp)
{
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = use_threads;
+
double averaged_timing = 0.0;
for (int i = 0; i < NUM_RUN_AVERAGED; i++) {
const double init_time = PIL_check_seconds_timer();
- BLI_task_parallel_listbase(list, num_items_tmp, func, use_threads);
+ BLI_task_parallel_listbase(list, num_items_tmp, func, &settings);
averaged_timing += PIL_check_seconds_timer() - init_time;
/* Those checks should ensure us all items of the listbase were processed once, and only once -
diff --git a/tests/gtests/blenlib/BLI_task_test.cc b/tests/gtests/blenlib/BLI_task_test.cc
index 0c1868380da..62ae0baaec9 100644
--- a/tests/gtests/blenlib/BLI_task_test.cc
+++ b/tests/gtests/blenlib/BLI_task_test.cc
@@ -88,7 +88,10 @@ TEST(task, MempoolIter)
/* *** Parallel iterations over double-linked list items. *** */
-static void task_listbase_iter_func(void *userdata, Link *item, int index)
+static void task_listbase_iter_func(void *userdata,
+ void *item,
+ int index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
LinkData *data = (LinkData *)item;
int *count = (int *)userdata;
@@ -112,7 +115,10 @@ TEST(task, ListBaseIter)
num_items++;
}
- BLI_task_parallel_listbase(&list, &num_items, task_listbase_iter_func, true);
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+
+ BLI_task_parallel_listbase(&list, &num_items, task_listbase_iter_func, &settings);
/* Those checks should ensure us all items of the listbase were processed once, and only once -
* as expected. */