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:
-rwxr-xr-xbuild_files/build_environment/install_deps.sh3
-rw-r--r--build_files/buildbot/slave_compile.py6
-rwxr-xr-xdoc/python_api/sphinx_doc_update.py7
-rw-r--r--intern/atomic/atomic_ops.h24
-rw-r--r--intern/atomic/intern/atomic_ops_ext.h70
-rw-r--r--intern/atomic/intern/atomic_ops_msvc.h18
-rw-r--r--intern/atomic/intern/atomic_ops_unix.h36
-rw-r--r--intern/cycles/app/cycles_standalone.cpp2
-rw-r--r--intern/cycles/app/cycles_xml.cpp25
-rw-r--r--intern/cycles/blender/blender_sync.cpp9
-rw-r--r--intern/cycles/kernel/kernel_passes.h16
-rw-r--r--intern/cycles/kernel/kernel_path.h56
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h42
-rw-r--r--intern/cycles/render/image.cpp270
-rw-r--r--intern/cycles/render/image.h14
-rw-r--r--intern/cycles/render/light.cpp1
-rw-r--r--intern/cycles/util/util_atomic.h2
-rw-r--r--intern/cycles/util/util_path.cpp4
-rw-r--r--intern/cycles/util/util_stats.h4
-rw-r--r--intern/guardedalloc/intern/mallocn_guarded_impl.c12
-rw-r--r--intern/guardedalloc/intern/mallocn_lockfree_impl.c24
-rw-r--r--intern/iksolver/intern/IK_QSegment.h1
-rw-r--r--intern/iksolver/intern/IK_Solver.cpp1
-rw-r--r--release/scripts/startup/bl_operators/wm.py21
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py3
-rw-r--r--release/scripts/startup/bl_ui/space_image.py17
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py12
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py2
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_library.h2
-rw-r--r--source/blender/blenkernel/BKE_library_query.h3
-rw-r--r--source/blender/blenkernel/intern/action.c4
-rw-r--r--source/blender/blenkernel/intern/armature.c2
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c7
-rw-r--r--source/blender/blenkernel/intern/blendfile.c4
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c4
-rw-r--r--source/blender/blenkernel/intern/library.c156
-rw-r--r--source/blender/blenkernel/intern/library_query.c40
-rw-r--r--source/blender/blenkernel/intern/library_remap.c47
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c2
-rw-r--r--source/blender/blenkernel/intern/pbvh.c2
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c17
-rw-r--r--source/blender/blenlib/intern/task.c8
-rw-r--r--source/blender/blenloader/intern/versioning_270.c43
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c55
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c85
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c73
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c23
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h1
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c6
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c12
-rw-r--r--source/blender/bmesh/operators/bmo_fill_edgeloop.c2
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c3
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c10
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c2
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c2
-rw-r--r--source/blender/collada/MeshImporter.cpp15
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cpp2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h102
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc53
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc240
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc10
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc38
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc4
-rw-r--r--source/blender/draw/CMakeLists.txt62
-rw-r--r--source/blender/draw/DRW_defines.h25
-rw-r--r--source/blender/draw/DRW_engines.h0
-rw-r--r--source/blender/editors/animation/anim_ops.c4
-rw-r--r--source/blender/editors/armature/armature_edit.c1
-rw-r--r--source/blender/editors/armature/pose_edit.c2
-rw-r--r--source/blender/editors/armature/pose_slide.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c23
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_util.h2
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c9
-rw-r--r--source/blender/editors/interface/interface_icons.c233
-rw-r--r--source/blender/editors/interface/resources.c14
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c12
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c4
-rw-r--r--source/blender/editors/object/object_vgroup.c2
-rw-r--r--source/blender/editors/render/render_opengl.c35
-rw-r--r--source/blender/editors/screen/screen_ops.c23
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c9
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c2
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/transform/transform.c4
-rw-r--r--source/blender/editors/transform/transform_conversions.c4
-rw-r--r--source/blender/editors/util/undo.c23
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp11
-rw-r--r--source/blender/makesdna/DNA_scene_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c26
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c53
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c10
-rw-r--r--source/blender/makesrna/intern/rna_space.c2
-rw-r--r--source/blender/makesrna/intern/rna_wm.c46
-rw-r--r--source/blender/modifiers/intern/MOD_array.c8
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c5
-rw-r--r--source/blender/windowmanager/WM_types.h2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c12
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.cpp4
111 files changed, 1365 insertions, 1132 deletions
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index e1f5922272f..347a44d2900 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -1850,6 +1850,9 @@ compile_OSL() {
cmake_d="$cmake_d -D OSL_BUILD_PLUGINS=OFF"
cmake_d="$cmake_d -D OSL_BUILD_TESTS=OFF"
cmake_d="$cmake_d -D USE_SIMD=sse2"
+ if [ "$USE_CXX11" = true ]; then
+ cmake_d="$cmake_d -D OSL_BUILD_CPP11=1"
+ fi
#~ cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION"
diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py
index c2bfd882fde..76d538ad578 100644
--- a/build_files/buildbot/slave_compile.py
+++ b/build_files/buildbot/slave_compile.py
@@ -183,10 +183,8 @@ if 'cmake' in builder:
print('Condifuration FAILED!')
sys.exit(retcode)
- if 'win32' in builder:
- command = ['msbuild', 'INSTALL.vcxproj', '/Property:PlatformToolset=v120_xp', '/p:Configuration=Release']
- elif 'win64' in builder:
- command = ['msbuild', 'INSTALL.vcxproj', '/p:Configuration=Release']
+ if 'win32' in builder or 'win64' in builder:
+ command = ['cmake', '--build', '.', '--target', target_name, '--config', 'Release']
else:
command = target_chroot_prefix + ['make', '-s', '-j2', target_name]
diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py
index 5301f39b2e3..c7f0367a2a0 100755
--- a/doc/python_api/sphinx_doc_update.py
+++ b/doc/python_api/sphinx_doc_update.py
@@ -142,8 +142,11 @@ def main():
zip_name = "blender_python_reference_%s" % blenver_zip # We can't use 'release' postfix here...
zip_path = os.path.join(args.mirror_dir, zip_name)
with zipfile.ZipFile(zip_path, 'w') as zf:
- for de in os.scandir(api_dir):
- zf.write(de.path, arcname=os.path.join(zip_name, de.name))
+ for dirname, _, filenames in os.walk(api_dir):
+ for filename in filenames:
+ filepath = os.path.join(dirname, filename)
+ zip_filepath = os.path.join(zip_name, os.path.relpath(filepath, api_dir))
+ zf.write(filepath, arcname=zip_filepath)
os.rename(zip_path, os.path.join(api_dir, "%s.zip" % zip_name))
# VII) Create symlinks and html redirects.
diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h
index f78eab7951f..1107deddf94 100644
--- a/intern/atomic/atomic_ops.h
+++ b/intern/atomic/atomic_ops.h
@@ -77,13 +77,15 @@
/* Function prototypes. */
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
-ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x);
-ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x);
+ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x);
+ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x);
+ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x);
+ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new);
#endif
-ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x);
-ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x);
+ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x);
+ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new);
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x);
@@ -93,18 +95,22 @@ ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b);
ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b);
-ATOMIC_INLINE size_t atomic_add_z(size_t *p, size_t x);
-ATOMIC_INLINE size_t atomic_sub_z(size_t *p, size_t x);
+ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x);
+ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x);
+ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x);
+ATOMIC_INLINE size_t atomic_fetch_and_sub_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new);
-ATOMIC_INLINE unsigned atomic_add_u(unsigned *p, unsigned x);
-ATOMIC_INLINE unsigned atomic_sub_u(unsigned *p, unsigned x);
+ATOMIC_INLINE unsigned atomic_add_and_fetch_u(unsigned *p, unsigned x);
+ATOMIC_INLINE unsigned atomic_sub_and_fetch_u(unsigned *p, unsigned x);
+ATOMIC_INLINE unsigned atomic_fetch_and_add_u(unsigned *p, unsigned x);
+ATOMIC_INLINE unsigned atomic_fetch_and_sub_u(unsigned *p, unsigned x);
ATOMIC_INLINE unsigned atomic_cas_u(unsigned *v, unsigned old, unsigned _new);
/* WARNING! Float 'atomics' are really faked ones, those are actually closer to some kind of spinlock-sync'ed operation,
* which means they are only efficient if collisions are highly unlikely (i.e. if probability of two threads
* working on the same pointer at the same time is very low). */
-ATOMIC_INLINE float atomic_add_fl(float *p, const float x);
+ATOMIC_INLINE float atomic_add_and_fetch_fl(float *p, const float x);
/******************************************************************************/
/* Include system-dependent implementations. */
diff --git a/intern/atomic/intern/atomic_ops_ext.h b/intern/atomic/intern/atomic_ops_ext.h
index 4065299d2ea..8421aa72192 100644
--- a/intern/atomic/intern/atomic_ops_ext.h
+++ b/intern/atomic/intern/atomic_ops_ext.h
@@ -56,25 +56,47 @@
/******************************************************************************/
/* size_t operations. */
-ATOMIC_INLINE size_t atomic_add_z(size_t *p, size_t x)
+ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x)
{
assert(sizeof(size_t) == LG_SIZEOF_PTR);
#if (LG_SIZEOF_PTR == 8)
- return (size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)x);
+ return (size_t)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)x);
#elif (LG_SIZEOF_PTR == 4)
- return (size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)x);
+ return (size_t)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)x);
#endif
}
-ATOMIC_INLINE size_t atomic_sub_z(size_t *p, size_t x)
+ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x)
{
assert(sizeof(size_t) == LG_SIZEOF_PTR);
#if (LG_SIZEOF_PTR == 8)
- return (size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
+ return (size_t)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
#elif (LG_SIZEOF_PTR == 4)
- return (size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
+ return (size_t)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
+#endif
+}
+
+ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x)
+{
+ assert(sizeof(size_t) == LG_SIZEOF_PTR);
+
+#if (LG_SIZEOF_PTR == 8)
+ return (size_t)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)x);
+#elif (LG_SIZEOF_PTR == 4)
+ return (size_t)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)x);
+#endif
+}
+
+ATOMIC_INLINE size_t atomic_fetch_and_sub_z(size_t *p, size_t x)
+{
+ assert(sizeof(size_t) == LG_SIZEOF_PTR);
+
+#if (LG_SIZEOF_PTR == 8)
+ return (size_t)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
+#elif (LG_SIZEOF_PTR == 4)
+ return (size_t)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
#endif
}
@@ -91,25 +113,47 @@ ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new)
/******************************************************************************/
/* unsigned operations. */
-ATOMIC_INLINE unsigned atomic_add_u(unsigned *p, unsigned x)
+ATOMIC_INLINE unsigned atomic_add_and_fetch_u(unsigned *p, unsigned x)
+{
+ assert(sizeof(unsigned) == LG_SIZEOF_INT);
+
+#if (LG_SIZEOF_INT == 8)
+ return (unsigned)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)x);
+#elif (LG_SIZEOF_INT == 4)
+ return (unsigned)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)x);
+#endif
+}
+
+ATOMIC_INLINE unsigned atomic_sub_and_fetch_u(unsigned *p, unsigned x)
+{
+ assert(sizeof(unsigned) == LG_SIZEOF_INT);
+
+#if (LG_SIZEOF_INT == 8)
+ return (unsigned)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
+#elif (LG_SIZEOF_INT == 4)
+ return (unsigned)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
+#endif
+}
+
+ATOMIC_INLINE unsigned atomic_fetch_and_add_u(unsigned *p, unsigned x)
{
assert(sizeof(unsigned) == LG_SIZEOF_INT);
#if (LG_SIZEOF_INT == 8)
- return (unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)x);
+ return (unsigned)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)x);
#elif (LG_SIZEOF_INT == 4)
- return (unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)x);
+ return (unsigned)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)x);
#endif
}
-ATOMIC_INLINE unsigned atomic_sub_u(unsigned *p, unsigned x)
+ATOMIC_INLINE unsigned atomic_fetch_and_sub_u(unsigned *p, unsigned x)
{
assert(sizeof(unsigned) == LG_SIZEOF_INT);
#if (LG_SIZEOF_INT == 8)
- return (unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
+ return (unsigned)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x));
#elif (LG_SIZEOF_INT == 4)
- return (unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
+ return (unsigned)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x));
#endif
}
@@ -127,7 +171,7 @@ ATOMIC_INLINE unsigned atomic_cas_u(unsigned *v, unsigned old, unsigned _new)
/******************************************************************************/
/* float operations. */
-ATOMIC_INLINE float atomic_add_fl(float *p, const float x)
+ATOMIC_INLINE float atomic_add_and_fetch_fl(float *p, const float x)
{
assert(sizeof(float) == sizeof(uint32_t));
diff --git a/intern/atomic/intern/atomic_ops_msvc.h b/intern/atomic/intern/atomic_ops_msvc.h
index 3461719a4e7..034ac1e3e53 100644
--- a/intern/atomic/intern/atomic_ops_msvc.h
+++ b/intern/atomic/intern/atomic_ops_msvc.h
@@ -43,12 +43,12 @@
/******************************************************************************/
/* 64-bit operations. */
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
-ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x)
+ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x) + x;
}
-ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x)
+ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)) - x;
}
@@ -57,16 +57,26 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
{
return InterlockedCompareExchange64((int64_t *)v, _new, old);
}
+
+ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
+{
+ return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
+}
+
+ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
+{
+ return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x));
+}
#endif
/******************************************************************************/
/* 32-bit operations. */
-ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x)
+ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
{
return InterlockedExchangeAdd(p, x) + x;
}
-ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x)
+ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
{
return InterlockedExchangeAdd(p, -((int32_t)x)) - x;
}
diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h
index e63f09c76c5..0a3322ad2b1 100644
--- a/intern/atomic/intern/atomic_ops_unix.h
+++ b/intern/atomic/intern/atomic_ops_unix.h
@@ -58,22 +58,32 @@
/* 64-bit operations. */
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
# if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
-ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x)
+ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return __sync_add_and_fetch(p, x);
}
-ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x)
+ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return __sync_sub_and_fetch(p, x);
}
+ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
+{
+ return __sync_fetch_and_add(p, x);
+}
+
+ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
+{
+ return __sync_fetch_and_sub(p, x);
+}
+
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new)
{
return __sync_val_compare_and_swap(v, old, _new);
}
# elif (defined(__amd64__) || defined(__x86_64__))
-ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x)
+ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
{
asm volatile (
"lock; xaddq %0, %1;"
@@ -83,7 +93,7 @@ ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x)
return x;
}
-ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x)
+ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
{
x = (uint64_t)(-(int64_t)x);
asm volatile (
@@ -94,6 +104,16 @@ ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x)
return x;
}
+ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
+{
+ return atomic_fetch_and_add_uint64(p, x) + x;
+}
+
+ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x)
+{
+ return atomic_fetch_and_sub_uint64(p, x) - x;
+}
+
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new)
{
uint64_t ret;
@@ -112,12 +132,12 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
/******************************************************************************/
/* 32-bit operations. */
#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
-ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x)
+ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
{
return __sync_add_and_fetch(p, x);
}
-ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x)
+ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
{
return __sync_sub_and_fetch(p, x);
}
@@ -127,7 +147,7 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
return __sync_val_compare_and_swap(v, old, _new);
}
#elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
-ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x)
+ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
{
uint32_t ret = x;
asm volatile (
@@ -138,7 +158,7 @@ ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x)
return ret+x;
}
-ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x)
+ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
{
ret = (uint32_t)(-(int32_t)x);
asm volatile (
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index e8168bc15ff..b21e8630cdb 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -337,7 +337,7 @@ static void options_parse(int argc, const char **argv)
/* device names */
string device_names = "";
- string devicename = "cpu";
+ string devicename = "CPU";
bool list = false;
vector<DeviceType>& types = Device::available_types();
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 8a3eb98a5a0..29a68bf272e 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -210,17 +210,6 @@ static void xml_read_camera(XMLReadState& state, pugi::xml_node node)
/* Shader */
-static string xml_socket_name(const char *name)
-{
- string sname = name;
- size_t i;
-
- while((i = sname.find(" ")) != string::npos)
- sname.replace(i, 1, "");
-
- return sname;
-}
-
static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml_node graph_node)
{
xml_read_node(state, shader, graph_node);
@@ -255,7 +244,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
ShaderNode *fromnode = (ShaderNode*)graph_reader.node_map[from_node_name];
foreach(ShaderOutput *out, fromnode->outputs)
- if(string_iequals(xml_socket_name(out->name().c_str()), from_socket_name.c_str()))
+ if(string_iequals(out->socket_type.name.string(), from_socket_name.string()))
output = out;
if(!output)
@@ -268,7 +257,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
ShaderNode *tonode = (ShaderNode*)graph_reader.node_map[to_node_name];
foreach(ShaderInput *in, tonode->inputs)
- if(string_iequals(xml_socket_name(in->name().c_str()), to_socket_name.c_str()))
+ if(string_iequals(in->socket_type.name.string(), to_socket_name.string()))
input = in;
if(!input)
@@ -406,7 +395,7 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
int shader = 0;
bool smooth = state.smooth;
- /* read vertices and polygons, RIB style */
+ /* read vertices and polygons */
vector<float3> P;
vector<float> UV;
vector<int> verts, nverts;
@@ -532,8 +521,12 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
sdparams.objecttoworld = state.tfm;
}
- /* temporary for test compatibility */
- mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
+ /* we don't yet support arbitrary attributes, for now add vertex
+ * coordinates as generated coordinates if requested */
+ if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) {
+ Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
+ memcpy(attr->data_float3(), mesh->verts.data(), sizeof(float3)*mesh->verts.size());
+ }
}
/* Light */
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 62b9fa3c92b..49ddc8af9a8 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -249,9 +249,14 @@ void BlenderSync::sync_integrator()
integrator->seed = get_int(cscene, "seed");
if(get_boolean(cscene, "use_animated_seed")) {
integrator->seed = hash_int_2d(b_scene.frame_current(),
- get_int(cscene, "seed")) +
- hash_int_2d((int)(b_scene.frame_subframe() * (float)INT_MAX),
get_int(cscene, "seed"));
+ if(b_scene.frame_subframe() != 0.0f) {
+ /* TODO(sergey): Ideally should be some sort of hash_merge,
+ * but this is good enough for now.
+ */
+ integrator->seed += hash_int_2d((int)(b_scene.frame_subframe() * (float)INT_MAX),
+ get_int(cscene, "seed"));
+ }
}
integrator->sampling_pattern = (SamplingPattern)get_enum(
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index 20cf3fa931b..7aec47e4957 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -20,7 +20,7 @@ ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, int sam
{
ccl_global float *buf = buffer;
#if defined(__SPLIT_KERNEL__) && defined(__WORK_STEALING__)
- atomic_add_float(buf, value);
+ atomic_add_and_fetch_float(buf, value);
#else
*buf = (sample == 0)? value: *buf + value;
#endif // __SPLIT_KERNEL__ && __WORK_STEALING__
@@ -33,9 +33,9 @@ ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, int sa
ccl_global float *buf_y = buffer + 1;
ccl_global float *buf_z = buffer + 2;
- atomic_add_float(buf_x, value.x);
- atomic_add_float(buf_y, value.y);
- atomic_add_float(buf_z, value.z);
+ atomic_add_and_fetch_float(buf_x, value.x);
+ atomic_add_and_fetch_float(buf_y, value.y);
+ atomic_add_and_fetch_float(buf_z, value.z);
#else
ccl_global float3 *buf = (ccl_global float3*)buffer;
*buf = (sample == 0)? value: *buf + value;
@@ -50,10 +50,10 @@ ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, int sa
ccl_global float *buf_z = buffer + 2;
ccl_global float *buf_w = buffer + 3;
- atomic_add_float(buf_x, value.x);
- atomic_add_float(buf_y, value.y);
- atomic_add_float(buf_z, value.z);
- atomic_add_float(buf_w, value.w);
+ atomic_add_and_fetch_float(buf_x, value.x);
+ atomic_add_and_fetch_float(buf_y, value.y);
+ atomic_add_and_fetch_float(buf_z, value.z);
+ atomic_add_and_fetch_float(buf_w, value.w);
#else
ccl_global float4 *buf = (ccl_global float4*)buffer;
*buf = (sample == 0)? value: *buf + value;
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 4237fdb32ff..6d89a89ed5b 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -84,7 +84,7 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
light_ray.t = kernel_data.background.ao_distance;
#ifdef __OBJECT_MOTION__
light_ray.time = ccl_fetch(sd, time);
-#endif
+#endif /* __OBJECT_MOTION__ */
light_ray.dP = ccl_fetch(sd, dP);
light_ray.dD = differential3_zero();
@@ -138,7 +138,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
state->bounce);
}
}
-#endif
+#endif /* __LAMP_MIS__ */
#ifdef __VOLUME__
/* volume attenuation, emission, scatter */
@@ -239,7 +239,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
}
}
else
-# endif
+# endif /* __VOLUME_DECOUPLED__ */
{
/* integrate along volume segment with distance sampling */
VolumeIntegrateResult result = kernel_volume_integrate(
@@ -271,10 +271,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
break;
}
}
-# endif
+# endif /* __VOLUME_SCATTER__ */
}
}
-#endif
+#endif /* __VOLUME__ */
if(!hit) {
#ifdef __BACKGROUND__
@@ -284,7 +284,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
throughput,
L_background,
state->bounce);
-#endif
+#endif /* __BACKGROUND__ */
break;
}
@@ -298,7 +298,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
#ifdef __BRANCHED_PATH__
shader_merge_closures(sd);
-#endif
+#endif /* __BRANCHED_PATH__ */
/* blurring of bsdf after bounces, for rays that have a small likelihood
* of following this particular path (diffuse, rough glossy) */
@@ -321,7 +321,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
state->ray_pdf);
path_radiance_accum_emission(L, throughput, emission, state->bounce);
}
-#endif
+#endif /* __EMISSION__ */
/* path termination. this is a strange place to put the termination, it's
* mainly due to the mixed in MIS that we use. gives too many unneeded
@@ -348,7 +348,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) {
kernel_path_ao(kg, sd, emission_sd, L, state, rng, throughput, make_float3(0.0f, 0.0f, 0.0f));
}
-#endif
+#endif /* __AO__ */
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object, replacing
@@ -380,7 +380,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
false);
}
}
-#endif
+#endif /* __SUBSURFACE__ */
#if defined(__EMISSION__) && defined(__BRANCHED_PATH__)
if(kernel_data.integrator.use_direct_light) {
@@ -395,7 +395,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
L,
all);
}
-#endif
+#endif /* defined(__EMISSION__) && defined(__BRANCHED_PATH__) */
if(!kernel_path_surface_bounce(kg, rng, sd, &throughput, state, L, ray))
break;
@@ -449,7 +449,7 @@ bool kernel_path_subsurface_scatter(
ss_indirect->need_update_volume_stack =
kernel_data.integrator.use_volumes &&
ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
-# endif
+# endif /* __VOLUME__ */
/* compute lighting with the BSDF closure */
for(int hit = 0; hit < num_hits; hit++) {
@@ -492,7 +492,7 @@ bool kernel_path_subsurface_scatter(
{
# ifdef __LAMP_MIS__
hit_state->ray_t = 0.0f;
-# endif
+# endif /* __LAMP_MIS__ */
# ifdef __VOLUME__
if(ss_indirect->need_update_volume_stack) {
@@ -507,7 +507,7 @@ bool kernel_path_subsurface_scatter(
&volume_ray,
hit_state->volume_stack);
}
-# endif
+# endif /* __VOLUME__ */
path_radiance_reset_indirect(L);
ss_indirect->num_rays++;
}
@@ -593,14 +593,14 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#ifdef __KERNEL_DEBUG__
DebugData debug_data;
debug_data_init(&debug_data);
-#endif
+#endif /* __KERNEL_DEBUG__ */
#ifdef __SUBSURFACE__
SubsurfaceIndirectRays ss_indirect;
kernel_path_subsurface_init_indirect(&ss_indirect);
for(;;) {
-#endif
+#endif /* __SUBSURFACE__ */
/* path iteration */
for(;;) {
@@ -626,7 +626,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax);
#else
bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f);
-#endif
+#endif /* __HAIR__ */
#ifdef __KERNEL_DEBUG__
if(state.flag & PATH_RAY_CAMERA) {
@@ -634,7 +634,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
}
debug_data.num_ray_bounces++;
-#endif
+#endif /* __KERNEL_DEBUG__ */
#ifdef __LAMP_MIS__
if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
@@ -655,7 +655,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
if(indirect_lamp_emission(kg, &emission_sd, &state, &light_ray, &emission))
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
}
-#endif
+#endif /* __LAMP_MIS__ */
#ifdef __VOLUME__
/* volume attenuation, emission, scatter */
@@ -719,7 +719,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
}
}
else
-# endif
+# endif /* __VOLUME_DECOUPLED__ */
{
/* integrate along volume segment with distance sampling */
VolumeIntegrateResult result = kernel_volume_integrate(
@@ -736,10 +736,10 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
else
break;
}
-# endif
+# endif /* __VOLUME_SCATTER__ */
}
}
-#endif
+#endif /* __VOLUME__ */
if(!hit) {
/* eval background shader if nothing hit */
@@ -748,7 +748,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#ifdef __PASSES__
if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
-#endif
+#endif /* __PASSES__ */
break;
}
@@ -756,7 +756,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
/* sample background shader */
float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
-#endif
+#endif /* __BACKGROUND__ */
break;
}
@@ -784,7 +784,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
if(sd.flag & SD_HOLDOUT_MASK)
break;
}
-#endif
+#endif /* __HOLDOUT__ */
/* holdout mask objects do not write data passes */
kernel_write_data_passes(kg, buffer, &L, &sd, sample, &state, throughput);
@@ -807,7 +807,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf);
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
}
-#endif
+#endif /* __EMISSION__ */
/* path termination. this is a strange place to put the termination, it's
* mainly due to the mixed in MIS that we use. gives too many unneeded
@@ -830,7 +830,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
kernel_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput, shader_bsdf_alpha(kg, &sd));
}
-#endif
+#endif /* __AO__ */
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object, replacing
@@ -885,7 +885,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#ifdef __KERNEL_DEBUG__
kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample);
-#endif
+#endif /* __KERNEL_DEBUG__ */
return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent);
}
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index cdb07db587a..c84727ace99 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -51,7 +51,7 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg,
light_ray.t = kernel_data.background.ao_distance;
#ifdef __OBJECT_MOTION__
light_ray.time = ccl_fetch(sd, time);
-#endif
+#endif /* __OBJECT_MOTION__ */
light_ray.dP = ccl_fetch(sd, dP);
light_ray.dD = differential3_zero();
@@ -169,7 +169,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
Ray volume_ray = *ray;
bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
-#endif
+#endif /* __VOLUME__ */
/* compute lighting with the BSDF closure */
for(int hit = 0; hit < num_hits; hit++) {
@@ -200,7 +200,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
&volume_ray,
hit_state.volume_stack);
}
-#endif
+#endif /* __VOLUME__ */
#ifdef __EMISSION__
/* direct light */
@@ -217,7 +217,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
L,
all);
}
-#endif
+#endif /* __EMISSION__ */
/* indirect light */
kernel_branched_path_surface_indirect_light(
@@ -234,7 +234,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
}
}
}
-#endif
+#endif /* __SUBSURFACE__ */
ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, ccl_global float *buffer)
{
@@ -256,7 +256,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __KERNEL_DEBUG__
DebugData debug_data;
debug_data_init(&debug_data);
-#endif
+#endif /* __KERNEL_DEBUG__ */
/* Main Loop
* Here we only handle transparency intersections from the camera ray.
@@ -285,13 +285,13 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax);
#else
bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f);
-#endif
+#endif /* __HAIR__ */
#ifdef __KERNEL_DEBUG__
debug_data.num_bvh_traversal_steps += isect.num_traversal_steps;
debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
debug_data.num_ray_bounces++;
-#endif
+#endif /* __KERNEL_DEBUG__ */
#ifdef __VOLUME__
/* volume attenuation, emission, scatter */
@@ -432,14 +432,14 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
path_radiance_reset_indirect(&L);
}
}
-#endif
+#endif /* __VOLUME_SCATTER__ */
}
/* todo: avoid this calculation using decoupled ray marching */
kernel_volume_shadow(kg, &emission_sd, &state, &volume_ray, &throughput);
-#endif
+#endif /* __VOLUME_DECOUPLED__ */
}
-#endif
+#endif /* __VOLUME__ */
if(!hit) {
/* eval background shader if nothing hit */
@@ -448,7 +448,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __PASSES__
if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
-#endif
+#endif /* __PASSES__ */
break;
}
@@ -456,7 +456,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
/* sample background shader */
float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
-#endif
+#endif /* __BACKGROUND__ */
break;
}
@@ -484,7 +484,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
if(sd.flag & SD_HOLDOUT_MASK)
break;
}
-#endif
+#endif /* __HOLDOUT__ */
/* holdout mask objects do not write data passes */
kernel_write_data_passes(kg, buffer, &L, &sd, sample, &state, throughput);
@@ -495,7 +495,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf);
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
}
-#endif
+#endif /* __EMISSION__ */
/* transparency termination */
if(state.flag & PATH_RAY_TRANSPARENT) {
@@ -522,7 +522,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
kernel_branched_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput);
}
-#endif
+#endif /* __AO__ */
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object */
@@ -530,7 +530,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
kernel_branched_path_subsurface_scatter(kg, &sd, &indirect_sd, &emission_sd,
&L, &state, rng, &ray, throughput);
}
-#endif
+#endif /* __SUBSURFACE__ */
if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
PathState hit_state = state;
@@ -542,7 +542,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
kernel_branched_path_surface_connect_light(kg, rng,
&sd, &emission_sd, &hit_state, throughput, 1.0f, &L, all);
}
-#endif
+#endif /* __EMISSION__ */
/* indirect light */
kernel_branched_path_surface_indirect_light(kg, rng,
@@ -567,12 +567,12 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
ray.dP = sd.dP;
ray.dD.dx = -sd.dI.dx;
ray.dD.dy = -sd.dI.dy;
-#endif
+#endif /* __RAY_DIFFERENTIALS__ */
#ifdef __VOLUME__
/* enter/exit volume */
kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
-#endif
+#endif /* __VOLUME__ */
}
float3 L_sum = path_radiance_clamp_and_sum(kg, &L);
@@ -581,7 +581,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __KERNEL_DEBUG__
kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample);
-#endif
+#endif /* __KERNEL_DEBUG__ */
return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent);
}
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 073a0aa2ac9..7465fbd43a7 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -471,133 +471,43 @@ bool ImageManager::file_load_image_generic(Image *img, ImageInput **in, int &wid
return true;
}
-template<typename T>
-bool ImageManager::file_load_byte_image(Image *img, ImageDataType type, device_vector<T>& tex_img)
+template<TypeDesc::BASETYPE FileFormat,
+ typename StorageType,
+ typename DeviceType>
+bool ImageManager::file_load_image(Image *img,
+ ImageDataType type,
+ device_vector<DeviceType>& tex_img)
{
+ const StorageType alpha_one = (FileFormat == TypeDesc::UINT8)? 255 : 1;
ImageInput *in = NULL;
int width, height, depth, components;
-
- if(!file_load_image_generic(img, &in, width, height, depth, components))
- return false;
-
- /* read RGBA pixels */
- uchar *pixels = (uchar*)tex_img.resize(width, height, depth);
- if(pixels == NULL) {
+ if(!file_load_image_generic(img, &in, width, height, depth, components)) {
return false;
}
- bool cmyk = false;
-
- if(in) {
- if(depth <= 1) {
- int scanlinesize = width*components*sizeof(uchar);
-
- in->read_image(TypeDesc::UINT8,
- (uchar*)pixels + (((size_t)height)-1)*scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
- }
- else {
- in->read_image(TypeDesc::UINT8, (uchar*)pixels);
- }
-
- cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4;
-
- in->close();
- delete in;
- }
- else {
- builtin_image_pixels_cb(img->filename, img->builtin_data, pixels);
- }
-
- /* Check if we actually have a byte4 slot, in case components == 1, but device
- * doesn't support single channel textures. */
- if(type == IMAGE_DATA_TYPE_BYTE4) {
- size_t num_pixels = ((size_t)width) * height * depth;
- if(cmyk) {
- /* CMYK */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
- pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
- pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
- pixels[i*4+3] = 255;
- }
- }
- else if(components == 2) {
- /* grayscale + alpha */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = pixels[i*2+1];
- pixels[i*4+2] = pixels[i*2+0];
- pixels[i*4+1] = pixels[i*2+0];
- pixels[i*4+0] = pixels[i*2+0];
- }
- }
- else if(components == 3) {
- /* RGB */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
- pixels[i*4+2] = pixels[i*3+2];
- pixels[i*4+1] = pixels[i*3+1];
- pixels[i*4+0] = pixels[i*3+0];
- }
- }
- else if(components == 1) {
- /* grayscale */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
- pixels[i*4+2] = pixels[i];
- pixels[i*4+1] = pixels[i];
- pixels[i*4+0] = pixels[i];
- }
- }
-
- if(img->use_alpha == false) {
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
- }
- }
- }
-
- return true;
-}
-
-template<typename T>
-bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img)
-{
- ImageInput *in = NULL;
- int width, height, depth, components;
-
- if(!file_load_image_generic(img, &in, width, height, depth, components))
- return false;
-
- /* read RGBA pixels */
- float *pixels = (float*)tex_img.resize(width, height, depth);
+ /* Read RGBA pixels. */
+ StorageType *pixels = (StorageType*)tex_img.resize(width, height, depth);
if(pixels == NULL) {
return false;
}
bool cmyk = false;
-
if(in) {
- float *readpixels = pixels;
- vector<float> tmppixels;
-
+ StorageType *readpixels = pixels;
+ vector<StorageType> tmppixels;
if(components > 4) {
tmppixels.resize(((size_t)width)*height*components);
readpixels = &tmppixels[0];
}
-
if(depth <= 1) {
- size_t scanlinesize = ((size_t)width)*components*sizeof(float);
- in->read_image(TypeDesc::FLOAT,
+ size_t scanlinesize = ((size_t)width)*components*sizeof(StorageType);
+ in->read_image(FileFormat,
(uchar*)readpixels + (height-1)*scanlinesize,
AutoStride,
-scanlinesize,
AutoStride);
}
else {
- in->read_image(TypeDesc::FLOAT, (uchar*)readpixels);
+ in->read_image(FileFormat, (uchar*)readpixels);
}
-
if(components > 4) {
size_t dimensions = ((size_t)width)*height;
for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) {
@@ -606,30 +516,42 @@ bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_
pixels[i*4+1] = tmppixels[i*components+1];
pixels[i*4+0] = tmppixels[i*components+0];
}
-
tmppixels.clear();
}
-
cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4;
-
in->close();
delete in;
}
else {
- builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels);
+ if(FileFormat == TypeDesc::FLOAT) {
+ builtin_image_float_pixels_cb(img->filename,
+ img->builtin_data,
+ (float*)pixels);
+ }
+ else if(FileFormat == TypeDesc::UINT8) {
+ builtin_image_pixels_cb(img->filename,
+ img->builtin_data,
+ (uchar*)pixels);
+ }
+ else {
+ /* TODO(dingto): Support half for ImBuf. */
+ }
}
-
- /* Check if we actually have a float4 slot, in case components == 1, but device
- * doesn't support single channel textures. */
- if(type == IMAGE_DATA_TYPE_FLOAT4) {
+ /* Check if we actually have a float4 slot, in case components == 1,
+ * but device doesn't support single channel textures.
+ */
+ if(type == IMAGE_DATA_TYPE_FLOAT4 ||
+ type == IMAGE_DATA_TYPE_HALF4 ||
+ type == IMAGE_DATA_TYPE_BYTE4)
+ {
size_t num_pixels = ((size_t)width) * height * depth;
if(cmyk) {
/* CMYK */
for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
+ pixels[i*4+3] = alpha_one;
}
}
else if(components == 2) {
@@ -644,7 +566,7 @@ bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_
else if(components == 3) {
/* RGB */
for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
+ pixels[i*4+3] = alpha_one;
pixels[i*4+2] = pixels[i*3+2];
pixels[i*4+1] = pixels[i*3+1];
pixels[i*4+0] = pixels[i*3+0];
@@ -653,120 +575,18 @@ bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_
else if(components == 1) {
/* grayscale */
for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
+ pixels[i*4+3] = alpha_one;
pixels[i*4+2] = pixels[i];
pixels[i*4+1] = pixels[i];
pixels[i*4+0] = pixels[i];
}
}
-
if(img->use_alpha == false) {
for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
+ pixels[i*4+3] = alpha_one;
}
}
}
-
- return true;
-}
-
-template<typename T>
-bool ImageManager::file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img)
-{
- ImageInput *in = NULL;
- int width, height, depth, components;
-
- if(!file_load_image_generic(img, &in, width, height, depth, components))
- return false;
-
- /* read RGBA pixels */
- half *pixels = (half*)tex_img.resize(width, height, depth);
- if(pixels == NULL) {
- return false;
- }
-
- if(in) {
- half *readpixels = pixels;
- vector<half> tmppixels;
-
- if(components > 4) {
- tmppixels.resize(((size_t)width)*height*components);
- readpixels = &tmppixels[0];
- }
-
- if(depth <= 1) {
- size_t scanlinesize = ((size_t)width)*components*sizeof(half);
- in->read_image(TypeDesc::HALF,
- (uchar*)readpixels + (height-1)*scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
- }
- else {
- in->read_image(TypeDesc::HALF, (uchar*)readpixels);
- }
-
- if(components > 4) {
- size_t dimensions = ((size_t)width)*height;
- for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) {
- pixels[i*4+3] = tmppixels[i*components+3];
- pixels[i*4+2] = tmppixels[i*components+2];
- pixels[i*4+1] = tmppixels[i*components+1];
- pixels[i*4+0] = tmppixels[i*components+0];
- }
-
- tmppixels.clear();
- }
-
- in->close();
- delete in;
- }
-#if 0
- /* TODO(dingto): Support half for ImBuf. */
- else {
- builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels);
- }
-#endif
-
- /* Check if we actually have a half4 slot, in case components == 1, but device
- * doesn't support single channel textures. */
- if(type == IMAGE_DATA_TYPE_HALF4) {
- size_t num_pixels = ((size_t)width) * height * depth;
- if(components == 2) {
- /* grayscale + alpha */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = pixels[i*2+1];
- pixels[i*4+2] = pixels[i*2+0];
- pixels[i*4+1] = pixels[i*2+0];
- pixels[i*4+0] = pixels[i*2+0];
- }
- }
- else if(components == 3) {
- /* RGB */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
- pixels[i*4+2] = pixels[i*3+2];
- pixels[i*4+1] = pixels[i*3+1];
- pixels[i*4+0] = pixels[i*3+0];
- }
- }
- else if(components == 1) {
- /* grayscale */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
- pixels[i*4+2] = pixels[i];
- pixels[i*4+1] = pixels[i];
- pixels[i*4+0] = pixels[i];
- }
- }
-
- if(img->use_alpha == false) {
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
- }
- }
- }
-
return true;
}
@@ -802,7 +622,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_float_image(img, type, tex_img)) {
+ if(!file_load_image<TypeDesc::FLOAT, float>(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
float *pixels = (float*)tex_img.resize(1, 1);
@@ -828,7 +648,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_float_image(img, type, tex_img)) {
+ if(!file_load_image<TypeDesc::FLOAT, float>(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
float *pixels = (float*)tex_img.resize(1, 1);
@@ -851,7 +671,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_byte_image(img, type, tex_img)) {
+ if(!file_load_image<TypeDesc::UINT8, uchar>(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
uchar *pixels = (uchar*)tex_img.resize(1, 1);
@@ -877,7 +697,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_byte_image(img, type, tex_img)) {
+ if(!file_load_image<TypeDesc::UINT8, uchar>(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
uchar *pixels = (uchar*)tex_img.resize(1, 1);
@@ -900,7 +720,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_half_image(img, type, tex_img)) {
+ if(!file_load_image<TypeDesc::HALF, half>(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
half *pixels = (half*)tex_img.resize(1, 1);
@@ -926,7 +746,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_half_image(img, type, tex_img)) {
+ if(!file_load_image<TypeDesc::HALF, half>(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
half *pixels = (half*)tex_img.resize(1, 1);
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index cca71a6bb93..1dc4bf180f8 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -109,14 +109,12 @@ private:
bool file_load_image_generic(Image *img, ImageInput **in, int &width, int &height, int &depth, int &components);
- template<typename T>
- bool file_load_byte_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
-
- template<typename T>
- bool file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
-
- template<typename T>
- bool file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
+ template<TypeDesc::BASETYPE FileFormat,
+ typename StorageType,
+ typename DeviceType>
+ bool file_load_image(Image *img,
+ ImageDataType type,
+ device_vector<DeviceType>& tex_img);
int type_index_to_flattened_slot(int slot, ImageDataType type);
int flattened_slot_to_type_index(int flat_slot, ImageDataType *type);
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index c43d646f515..2245c861d5a 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -106,6 +106,7 @@ NODE_DEFINE(Light)
static NodeEnum type_enum;
type_enum.insert("point", LIGHT_POINT);
+ type_enum.insert("distant", LIGHT_DISTANT);
type_enum.insert("background", LIGHT_BACKGROUND);
type_enum.insert("area", LIGHT_AREA);
type_enum.insert("spot", LIGHT_SPOT);
diff --git a/intern/cycles/util/util_atomic.h b/intern/cycles/util/util_atomic.h
index 1d1e2963348..433e41fbbb6 100644
--- a/intern/cycles/util/util_atomic.h
+++ b/intern/cycles/util/util_atomic.h
@@ -39,7 +39,7 @@ ATOMIC_INLINE void atomic_update_max_z(size_t *maximum_value, size_t value)
/* Float atomics implementation credits:
* http://suhorukov.blogspot.in/2011/12/opencl-11-atomic-operations-on-floating.html
*/
-ccl_device_inline void atomic_add_float(volatile ccl_global float *source,
+ccl_device_inline void atomic_add_and_fetch_float(volatile ccl_global float *source,
const float operand)
{
union {
diff --git a/intern/cycles/util/util_path.cpp b/intern/cycles/util/util_path.cpp
index 62ef8fc0b48..5df262fcbbb 100644
--- a/intern/cycles/util/util_path.cpp
+++ b/intern/cycles/util/util_path.cpp
@@ -757,9 +757,9 @@ uint64_t path_modified_time(const string& path)
{
path_stat_t st;
if(path_stat(path, &st) != 0) {
- return st.st_mtime;
+ return 0;
}
- return 0;
+ return st.st_mtime;
}
bool path_remove(const string& path)
diff --git a/intern/cycles/util/util_stats.h b/intern/cycles/util/util_stats.h
index b970b017270..c21a8488c81 100644
--- a/intern/cycles/util/util_stats.h
+++ b/intern/cycles/util/util_stats.h
@@ -29,13 +29,13 @@ public:
explicit Stats(static_init_t) {}
void mem_alloc(size_t size) {
- atomic_add_z(&mem_used, size);
+ atomic_add_and_fetch_z(&mem_used, size);
atomic_update_max_z(&mem_peak, mem_used);
}
void mem_free(size_t size) {
assert(mem_used >= size);
- atomic_sub_z(&mem_used, size);
+ atomic_sub_and_fetch_z(&mem_used, size);
}
size_t mem_used;
diff --git a/intern/guardedalloc/intern/mallocn_guarded_impl.c b/intern/guardedalloc/intern/mallocn_guarded_impl.c
index 1933e9d3ee3..76b7e072321 100644
--- a/intern/guardedalloc/intern/mallocn_guarded_impl.c
+++ b/intern/guardedalloc/intern/mallocn_guarded_impl.c
@@ -505,8 +505,8 @@ static void make_memhead_header(MemHead *memh, size_t len, const char *str)
memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
memt->tag3 = MEMTAG3;
- atomic_add_u(&totblock, 1);
- atomic_add_z(&mem_in_use, len);
+ atomic_add_and_fetch_u(&totblock, 1);
+ atomic_add_and_fetch_z(&mem_in_use, len);
mem_lock_thread();
addtail(membase, &memh->next);
@@ -638,7 +638,7 @@ void *MEM_guarded_mapallocN(size_t len, const char *str)
if (memh != (MemHead *)-1) {
make_memhead_header(memh, len, str);
memh->mmap = 1;
- atomic_add_z(&mmap_in_use, len);
+ atomic_add_and_fetch_z(&mmap_in_use, len);
mem_lock_thread();
peak_mem = mmap_in_use > peak_mem ? mmap_in_use : peak_mem;
mem_unlock_thread();
@@ -1007,8 +1007,8 @@ static void rem_memblock(MemHead *memh)
}
mem_unlock_thread();
- atomic_sub_u(&totblock, 1);
- atomic_sub_z(&mem_in_use, memh->len);
+ atomic_sub_and_fetch_u(&totblock, 1);
+ atomic_sub_and_fetch_z(&mem_in_use, memh->len);
#ifdef DEBUG_MEMDUPLINAME
if (memh->need_free_name)
@@ -1016,7 +1016,7 @@ static void rem_memblock(MemHead *memh)
#endif
if (memh->mmap) {
- atomic_sub_z(&mmap_in_use, memh->len);
+ atomic_sub_and_fetch_z(&mmap_in_use, memh->len);
#if defined(WIN32)
/* our windows mmap implementation is not thread safe */
mem_lock_thread();
diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
index a80d67c3e80..ce8a5b29ece 100644
--- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c
+++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
@@ -142,11 +142,11 @@ void MEM_lockfree_freeN(void *vmemh)
return;
}
- atomic_sub_u(&totblock, 1);
- atomic_sub_z(&mem_in_use, len);
+ atomic_sub_and_fetch_u(&totblock, 1);
+ atomic_sub_and_fetch_z(&mem_in_use, len);
if (MEMHEAD_IS_MMAP(memh)) {
- atomic_sub_z(&mmap_in_use, len);
+ atomic_sub_and_fetch_z(&mmap_in_use, len);
#if defined(WIN32)
/* our windows mmap implementation is not thread safe */
mem_lock_thread();
@@ -287,8 +287,8 @@ void *MEM_lockfree_callocN(size_t len, const char *str)
if (LIKELY(memh)) {
memh->len = len;
- atomic_add_u(&totblock, 1);
- atomic_add_z(&mem_in_use, len);
+ atomic_add_and_fetch_u(&totblock, 1);
+ atomic_add_and_fetch_z(&mem_in_use, len);
update_maximum(&peak_mem, mem_in_use);
return PTR_FROM_MEMHEAD(memh);
@@ -312,8 +312,8 @@ void *MEM_lockfree_mallocN(size_t len, const char *str)
}
memh->len = len;
- atomic_add_u(&totblock, 1);
- atomic_add_z(&mem_in_use, len);
+ atomic_add_and_fetch_u(&totblock, 1);
+ atomic_add_and_fetch_z(&mem_in_use, len);
update_maximum(&peak_mem, mem_in_use);
return PTR_FROM_MEMHEAD(memh);
@@ -361,8 +361,8 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str
memh->len = len | (size_t) MEMHEAD_ALIGN_FLAG;
memh->alignment = (short) alignment;
- atomic_add_u(&totblock, 1);
- atomic_add_z(&mem_in_use, len);
+ atomic_add_and_fetch_u(&totblock, 1);
+ atomic_add_and_fetch_z(&mem_in_use, len);
update_maximum(&peak_mem, mem_in_use);
return PTR_FROM_MEMHEAD(memh);
@@ -396,9 +396,9 @@ void *MEM_lockfree_mapallocN(size_t len, const char *str)
if (memh != (MemHead *)-1) {
memh->len = len | (size_t) MEMHEAD_MMAP_FLAG;
- atomic_add_u(&totblock, 1);
- atomic_add_z(&mem_in_use, len);
- atomic_add_z(&mmap_in_use, len);
+ atomic_add_and_fetch_u(&totblock, 1);
+ atomic_add_and_fetch_z(&mem_in_use, len);
+ atomic_add_and_fetch_z(&mmap_in_use, len);
update_maximum(&peak_mem, mem_in_use);
update_maximum(&peak_mem, mmap_in_use);
diff --git a/intern/iksolver/intern/IK_QSegment.h b/intern/iksolver/intern/IK_QSegment.h
index 74f157aa763..247807dc5e0 100644
--- a/intern/iksolver/intern/IK_QSegment.h
+++ b/intern/iksolver/intern/IK_QSegment.h
@@ -60,6 +60,7 @@
class IK_QSegment
{
public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
virtual ~IK_QSegment();
// start: a user defined translation
diff --git a/intern/iksolver/intern/IK_Solver.cpp b/intern/iksolver/intern/IK_Solver.cpp
index cefb8c7ed7b..a00db4fa2f5 100644
--- a/intern/iksolver/intern/IK_Solver.cpp
+++ b/intern/iksolver/intern/IK_Solver.cpp
@@ -42,6 +42,7 @@ using namespace std;
class IK_QSolver {
public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
IK_QSolver() : root(NULL) {
}
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 343fcdb0d22..68a25acc2db 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -935,16 +935,23 @@ def _wm_doc_get_id(doc_id, do_url=True, url_prefix=""):
# detect if this is a inherited member and use that name instead
rna_parent = rna_class.bl_rna
- rna_prop = rna_parent.properties[class_prop]
- rna_parent = rna_parent.base
- while rna_parent and rna_prop == rna_parent.properties.get(class_prop):
- class_name = rna_parent.identifier
+ rna_prop = rna_parent.properties.get(class_prop)
+ if rna_prop:
rna_parent = rna_parent.base
+ while rna_parent and rna_prop == rna_parent.properties.get(class_prop):
+ class_name = rna_parent.identifier
+ rna_parent = rna_parent.base
- if do_url:
- url = ("%s/bpy.types.%s.html#bpy.types.%s.%s" % (url_prefix, class_name, class_name, class_prop))
+ if do_url:
+ url = ("%s/bpy.types.%s.html#bpy.types.%s.%s" % (url_prefix, class_name, class_name, class_prop))
+ else:
+ rna = ("bpy.types.%s.%s" % (class_name, class_prop))
else:
- rna = ("bpy.types.%s.%s" % (class_name, class_prop))
+ # We assume this is custom property, only try to generate generic url/rna_id...
+ if do_url:
+ url = ("%s/bpy.types.bpy_struct.html#bpy.types.bpy_struct.items" % (url_prefix,))
+ else:
+ rna = "bpy.types.bpy_struct"
return url if do_url else rna
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 bc40932018d..08e07b8ed93 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -61,6 +61,9 @@ def gpencil_stroke_placement_settings(context, layout):
def gpencil_active_brush_settings_simple(context, layout):
brush = context.active_gpencil_brush
+ if brush is None:
+ layout.label("No Active Brush")
+ return
col = layout.column()
col.label("Active Brush: ")
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index b6087184518..04b4cef9512 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -259,6 +259,20 @@ class IMAGE_MT_uvs_showhide(Menu):
layout.operator("uv.hide", text="Hide Unselected").unselected = True
+class IMAGE_MT_uvs_proportional(Menu):
+ bl_label = "Proportional Editing"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.props_enum(context.tool_settings, "proportional_edit")
+
+ layout.separator()
+
+ layout.label("Falloff:")
+ layout.props_enum(context.tool_settings, "proportional_edit_falloff")
+
+
class IMAGE_MT_uvs_transform(Menu):
bl_label = "Transform"
@@ -360,8 +374,7 @@ class IMAGE_MT_uvs(Menu):
layout.separator()
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("IMAGE_MT_uvs_proportional")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 43188c2b9fa..f0f345620c2 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2366,6 +2366,10 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.menu("VIEW3D_MT_vertex_group")
layout.menu("VIEW3D_MT_hook")
+ layout.separator()
+
+ layout.operator("object.vertex_parent_set")
+
class VIEW3D_MT_edit_mesh_edges(Menu):
bl_label = "Edges"
@@ -2620,6 +2624,10 @@ class VIEW3D_MT_edit_curve_ctrlpoints(Menu):
layout.menu("VIEW3D_MT_hook")
+ layout.separator()
+
+ layout.operator("object.vertex_parent_set")
+
class VIEW3D_MT_edit_curve_segments(Menu):
bl_label = "Segments"
@@ -2782,6 +2790,10 @@ class VIEW3D_MT_edit_lattice(Menu):
layout.separator()
+ layout.operator("object.vertex_parent_set")
+
+ layout.separator()
+
layout.menu("VIEW3D_MT_edit_proportional")
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 9d66ab55a0d..1671e26e8d4 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -1535,7 +1535,7 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
sub.active = (brush and brush.sculpt_tool != 'MASK')
if (sculpt.detail_type_method == 'CONSTANT'):
row = sub.row(align=True)
- row.prop(sculpt, "constant_detail")
+ row.prop(sculpt, "constant_detail_resolution")
row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
elif (sculpt.detail_type_method == 'BRUSH'):
sub.prop(sculpt, "detail_percent")
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index 9547eeb9838..84a6d07be7d 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -42,6 +42,7 @@ extern bool BKE_undo_is_valid(const char *name);
extern void BKE_undo_reset(void);
extern void BKE_undo_number(struct bContext *C, int nr);
extern const char *BKE_undo_get_name(int nr, bool *r_active);
+extern const char *BKE_undo_get_name_last(void);
extern bool BKE_undo_save_file(const char *filename);
extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 908e6f214f9..baf8510dd0d 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 278
-#define BLENDER_SUBVERSION 2
+#define BLENDER_SUBVERSION 3
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 5436ac20472..781b5edec30 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -65,7 +65,7 @@ struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_
/* library_remap.c (keep here since they're general functions) */
void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL();
-void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user) ATTR_NONNULL();
+void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user) ATTR_NONNULL();
void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL();
void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index c6b63754b57..a7470107c24 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -88,6 +88,7 @@ bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
void BKE_library_ID_test_usages(struct Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked);
-void BKE_library_tag_unused_linked_data(struct Main *bmain, const bool do_init_tag);
+void BKE_library_unused_linked_data_set_tag(struct Main *bmain, const bool do_init_tag);
+void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain);
#endif /* __BKE_LIBRARY_QUERY_H__ */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 470098f8c7c..dcbb667adca 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -433,8 +433,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
chan->scaleIn = chan->scaleOut = 1.0f;
- chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f;
- chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f;
+ chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI;
+ chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI;
chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
chan->ikrotweight = chan->iklinweight = 0.0f;
unit_m4(chan->constinv);
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index cc508aa0511..2b333941c6e 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1781,7 +1781,6 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
BLI_duplicatelist(&pose->agroups, &frompose->agroups);
pose->active_group = frompose->active_group;
- BKE_pose_channels_hash_make(frompose);
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
pchanp = BKE_pose_channel_find_name(frompose, pchan->name);
@@ -1795,6 +1794,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
/* copy posechannel to temp, but restore important pointers */
pchanw = *pchanp;
+ pchanw.bone = pchan->bone;
pchanw.prev = pchan->prev;
pchanw.next = pchan->next;
pchanw.parent = pchan->parent;
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index d64bf7ecf43..ce6d29bbfee 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -319,6 +319,13 @@ const char *BKE_undo_get_name(int nr, bool *r_active)
return NULL;
}
+/* return the name of the last item */
+const char *BKE_undo_get_name_last()
+{
+ UndoElem *uel = undobase.last;
+ return (uel ? uel->name : NULL);
+}
+
/**
* Saves .blend using undo buffer.
*
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6da68470ecc..54f709a1e5b 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -407,9 +407,9 @@ bool BKE_blendfile_read_from_memfile(
if (bfd) {
/* remove the unused screens and wm */
while (bfd->main->wm.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true);
+ BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true, true);
while (bfd->main->screen.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true);
+ BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true, true);
setup_app_data(C, bfd, "<memory1>", reports);
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 1c0b11e287c..d237de014fb 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -3096,7 +3096,7 @@ void DAG_threaded_update_handle_node_updated(void *node_v,
for (itA = node->child; itA; itA = itA->next) {
DagNode *child_node = itA->node;
if (child_node != node) {
- atomic_sub_uint32(&child_node->num_pending_parents, 1);
+ atomic_sub_and_fetch_uint32(&child_node->num_pending_parents, 1);
if (child_node->num_pending_parents == 0) {
bool need_schedule;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 587e4a35806..3f5c5cd7bf4 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -2218,7 +2218,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
* to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
*/
tPoint->neighbour_pixel = ind - 1;
- atomic_add_uint32(&tPoint->neighbour_pixel, 1);
+ atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1);
tPoint->tri_index = i;
/* Now calculate pixel data for this pixel as it was on polygon surface */
@@ -2243,7 +2243,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
/* Increase the final number of active surface points if relevant. */
if (tPoint->tri_index != -1)
- atomic_add_uint32(active_points, 1);
+ atomic_add_and_fetch_uint32(active_points, 1);
}
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 83549ae6879..1c630624ec8 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -263,9 +263,12 @@ void id_fake_user_clear(ID *id)
}
static int id_expand_local_callback(
- void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag))
+ void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag))
{
- if (*id_pointer) {
+ /* Can hapen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)...
+ * Just skip it, shape key can only be either indirectly linked, or fully local, period.
+ * And let's curse one more time that stupid useless shapekey ID type! */
+ if (*id_pointer && *id_pointer != id_self && BKE_idcode_is_linkable(GS((*id_pointer)->name))) {
id_lib_extern(*id_pointer);
}
@@ -1192,7 +1195,7 @@ void BKE_main_free(Main *mainvar)
while ( (id = lb->first) ) {
#if 1
- BKE_libblock_free_ex(mainvar, id, false);
+ BKE_libblock_free_ex(mainvar, id, false, false);
#else
/* errors freeing ID's can be hard to track down,
* enable this so valgrind will give the line number in its error log */
@@ -1231,6 +1234,7 @@ void BKE_main_free(Main *mainvar)
case 31: BKE_libblock_free_ex(mainvar, id, false); break;
case 32: BKE_libblock_free_ex(mainvar, id, false); break;
case 33: BKE_libblock_free_ex(mainvar, id, false); break;
+ case 34: BKE_libblock_free_ex(mainvar, id, false); break;
default:
BLI_assert(0);
break;
@@ -1612,31 +1616,28 @@ void BKE_main_id_clear_newpoins(Main *bmain)
* \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING.
* \param set_fake If true, set fake user on all localized datablocks (except group and objects ones).
*/
-/* XXX TODO This function should probably be reworked.
- *
- * Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether
+/* Note: Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether
* they were also indirectly used or not...
*
- * Current version uses regular id_make_local callback, but this is not super-efficient since this ends up
+ * Current version uses regular id_make_local callback, which is not super-efficient since this ends up
* duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID).
*
- * We could first check all IDs and detect those to be made local that are only used by other local or future-local
- * datablocks, and directly tag those as local (instead of going through id_make_local) maybe...
- *
- * We'll probably need at some point a true dependency graph between datablocks, but for now this should work
- * good enough (performances is not a critical point here anyway).
+ * However, we now have a first check that allows us to use 'direct localization' of a lot of IDs, so performances
+ * are now *reasonably* OK.
*/
void BKE_library_make_local(
Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
- ID *id, *id_next;
+ ID *id;
int a;
+ LinkNode *todo_ids = NULL;
LinkNode *copied_ids = NULL;
LinkNode *linked_loop_candidates = NULL;
- MemArena *linklist_mem = BLI_memarena_new(256 * sizeof(copied_ids), __func__);
+ MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__);
+ /* Step 1: Detect datablocks to make local. */
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
id = lbarray[a]->first;
@@ -1644,54 +1645,80 @@ void BKE_library_make_local(
* by real datablocks responsible of them. */
const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
- for (; id; id = id_next) {
+ for (; id; id = id->next) {
id->newid = NULL;
id->tag &= ~LIB_TAG_DOIT;
- id_next = id->next; /* id is possibly being inserted again */
- /* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
+ if (id->lib == NULL) {
+ id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+ }
+ /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its
* possible to tag data you don't want to be made local, used for
* appending data, so any libdata already linked wont become local
- * (very nasty to discover all your links are lost after appending)
- * */
- if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
- ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
+ * (very nasty to discover all your links are lost after appending).
+ * Also, never ever make proxified objects local, would not make any sense. */
+ else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
+ ELEM(lib, NULL, id->lib) &&
+ !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) &&
+ ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
{
- if (lib == NULL || id->lib == lib) {
- if (id->lib) {
- /* In this specific case, we do want to make ID local even if it has no local usage yet... */
- if (GS(id->name) == ID_OB) {
- /* Special case for objects because we don't want proxy pointers to be
- * cleared yet. This will happen down the road in this function.
- */
- BKE_object_make_local_ex(bmain, (Object*)id, true, false);
- }
- else {
- id_make_local(bmain, id, false, true);
- }
-
- if (id->newid) {
- BLI_linklist_prepend_arena(&copied_ids, id, linklist_mem);
- }
- }
- else {
- id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
- }
- }
+ BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
+ id->tag |= LIB_TAG_DOIT;
+ }
+ }
+ }
- if (set_fake) {
- if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
- /* do not set fake user on objects, groups (instancing) */
- id_fake_user_set(id);
- }
- }
+ /* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future,
+ * local data), others will need to be duplicated and further processed later. */
+ BKE_library_indirectly_used_data_tag_clear(bmain);
+
+ /* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
+ * which involves more complex checks and might instead create a local copy of original linked ID. */
+ for (LinkNode *it = todo_ids, *it_next; it; it = it_next) {
+ it_next = it->next;
+ id = it->link;
+
+ if (id->tag & LIB_TAG_DOIT) {
+ /* We know all users of this object are local or will be made fully local, even if currently there are
+ * some indirect usages. So instead of making a copy that se'll likely get rid of later, directly make
+ * that data block local. Saves a tremendous amount of time with complex scenes... */
+ id_clear_lib_data_ex(bmain, id, true);
+ BKE_id_expand_local(id);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ /* In this specific case, we do want to make ID local even if it has no local usage yet... */
+ if (GS(id->name) == ID_OB) {
+ /* Special case for objects because we don't want proxy pointers to be
+ * cleared yet. This will happen down the road in this function.
+ */
+ BKE_object_make_local_ex(bmain, (Object*)id, true, false);
+ }
+ else {
+ id_make_local(bmain, id, false, true);
+ }
+
+ if (id->newid) {
+ /* Reuse already allocated LinkNode (transferring it from todo_ids to copied_ids). */
+ BLI_linklist_prepend_nlink(&copied_ids, id, it);
+ }
+ }
+
+ if (set_fake) {
+ if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
+ /* do not set fake user on objects, groups (instancing) */
+ id_fake_user_set(id);
}
}
}
- /* We have to remap local usages of old (linked) ID to new (local) id in a second loop, as lbarray ordering is not
- * enough to ensure us we did catch all dependencies (e.g. if making local a parent object before its child...).
- * See T48907. */
+ /* At this point, we are done with directly made local IDs. Now we have to handle duplicated ones, since their
+ * remaining linked original counterpart may not be needed anymore... */
+ todo_ids = NULL;
+
+ /* Step 4: We have to remap local usages of old (linked) ID to new (local) id in a separated loop,
+ * as lbarray ordering is not enough to ensure us we did catch all dependencies
+ * (e.g. if making local a parent object before its child...). See T48907. */
for (LinkNode *it = copied_ids; it; it = it->next) {
id = it->link;
@@ -1702,9 +1729,15 @@ void BKE_library_make_local(
if (old_to_new_ids) {
BLI_ghash_insert(old_to_new_ids, id, id->newid);
}
+
+ /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
+ * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
+ if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id_us_ensure_real(id->newid);
+ }
}
- /* Third step: remove datablocks that have been copied to be localized and are no more used in the end...
+ /* Step 5: remove datablocks that have been copied to be localized and are no more used in the end...
* Note that we may have to loop more than once here, to tackle dependencies between linked objects... */
bool do_loop = true;
while (do_loop) {
@@ -1751,11 +1784,6 @@ void BKE_library_make_local(
ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
}
}
- /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
- * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
- else if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
- id_us_ensure_real(id->newid);
- }
if (!is_local) {
if (!is_lib) { /* Not used at all, we can free it! */
@@ -1782,9 +1810,9 @@ void BKE_library_make_local(
}
}
- /* Fourth step: Try to find circle dependencies between indirectly-linked-only datablocks.
+ /* Step 6: Try to find circle dependencies between indirectly-linked-only datablocks.
* Those are fake 'usages' that prevent their deletion. See T49775 for nice ugly case. */
- BKE_library_tag_unused_linked_data(bmain, false);
+ BKE_library_unused_linked_data_set_tag(bmain, false);
for (LinkNode *it = linked_loop_candidates; it; it = it->next) {
if (it->link == NULL) {
continue;
@@ -1797,12 +1825,18 @@ void BKE_library_make_local(
/* Note: in theory here we are only handling datablocks forming exclusive linked dependency-cycles-based
* archipelagos, so no need to check again after we have deleted one, as done in previous step. */
if (id->tag & LIB_TAG_DOIT) {
+ /* Object's deletion rely on valid ob->data, but ob->data may have already been freed here...
+ * Setting it to NULL may not be 100% correct, but should be safe and do the work. */
+ if (GS(id->name) == ID_OB) {
+ ((Object *)id)->data = NULL;
+ }
+
/* Note: *in theory* IDs tagged here are fully *outside* of file scope, totally unused, so we can
* directly wipe them out without caring about clearing their usages.
* However, this is a highly-risky presumption, and nice crasher in case something goes wrong here.
* So for 2.78a will keep the safe option, and switch to more efficient one in master later. */
-#if 0
- BKE_libblock_free_ex(bmain, id, false);
+#if 1
+ BKE_libblock_free_ex(bmain, id, false, true);
#else
BKE_libblock_unlink(bmain, id, false, false);
BKE_libblock_free(bmain, id);
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index e643c1647fa..a161d9c0879 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -1102,8 +1102,9 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
*is_used_linked = (iter.count_indirect != 0);
}
-
-static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
+/* ***** IDs usages.checking/tagging. ***** */
+static int foreach_libblock_used_linked_data_tag_clear_cb(
+ void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
{
bool *is_changed = user_data;
@@ -1138,7 +1139,7 @@ static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID
* \param do_init_tag if \a true, all linked data are checked, if \a false, only linked datablocks already tagged with
* LIB_TAG_DOIT are checked.
*/
-void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag)
+void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
{
ListBase *lb_array[MAX_LIBARRAY];
@@ -1164,7 +1165,38 @@ void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag)
while (i--) {
for (ID *id = lb_array[i]->first; id; id = id->next) {
- BKE_library_foreach_ID_link(id, foreach_libblock_tag_unused_linked_data_callback, &do_loop, IDWALK_NOP);
+ if (id->tag & LIB_TAG_DOIT) {
+ /* Unused ID (so far), no need to check it further. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
+ }
+ }
+ }
+}
+
+/**
+ * Untag linked data blocks used by other untagged linked datablocks.
+ * Used to detect datablocks that we can forcefully make local (instead of copying them to later get rid of original):
+ * All datablocks we want to make local are tagged by caller, after this function has ran caller knows datablocks still
+ * tagged can directly be made local, since they are only used by other datablocks that will also be made fully local.
+ */
+void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
+{
+ ListBase *lb_array[MAX_LIBARRAY];
+
+ bool do_loop = true;
+ while (do_loop) {
+ int i = set_listbasepointers(bmain, lb_array);
+ do_loop = false;
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ if (id->lib == NULL || id->tag & LIB_TAG_DOIT) {
+ /* Local or non-indirectly-used ID (so far), no need to check it further. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
}
}
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index b7f7f2c19cc..785fb44c946 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -665,46 +665,23 @@ void BKE_libblock_relink_ex(
}
}
-static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
-{
- ChannelDriver *driver;
- FCurve *fcu;
-
- /* find the driver this belongs to and update it */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- driver = fcu->driver;
-
- if (driver) {
- DriverVar *dvar;
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id == userdata)
- dtar->id = NULL;
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
- }
-}
-
-void BKE_libblock_free_data(Main *bmain, ID *id)
+void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id)
{
if (id->properties) {
IDP_FreeProperty(id->properties);
MEM_freeN(id->properties);
}
-
- /* this ID may be a driver target! */
- BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
}
/**
* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
*
* \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
+ * (only applies to main database)
+ * \param do_ui_user: similar to do_id_user but makes sure UI does not hold references to
+ * \a id.
*/
-void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
+void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user)
{
ID *id = idv;
short type = GS(id->name);
@@ -826,12 +803,14 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
/* avoid notifying on removed data */
BKE_main_lock(bmain);
- if (free_notifier_reference_cb) {
- free_notifier_reference_cb(id);
- }
+ if (do_ui_user) {
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(id);
+ }
- if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(id, NULL);
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(id, NULL);
+ }
}
BLI_remlink(lb, id);
@@ -844,7 +823,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
void BKE_libblock_free(Main *bmain, void *idv)
{
- BKE_libblock_free_ex(bmain, idv, true);
+ BKE_libblock_free_ex(bmain, idv, true, true);
}
void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 016c9c863f0..a3fe73e4b11 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -238,7 +238,7 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx)
/* accumulate */
for (int k = 3; k--; ) {
- atomic_add_fl(&vnors[ml[i].v][k], pnor[k] * fac);
+ atomic_add_and_fetch_fl(&vnors[ml[i].v][k], pnor[k] * fac);
}
prev_edge = cur_edge;
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index ff69f381b06..4fe4d6e75a6 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -977,7 +977,7 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n)
* Not exact equivalent though, since atomicity is only ensured for one component
* of the vector at a time, but here it shall not make any sensible difference. */
for (int k = 3; k--; ) {
- atomic_add_fl(&vnors[v][k], fn[k]);
+ atomic_add_and_fetch_fl(&vnors[v][k], fn[k]);
}
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 55f9f384081..a821578db1a 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -148,8 +148,7 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
*
* Its assumed that \a l_radial_first is never forming the target face.
*/
-static bool bm_face_exists_tri_from_loop_vert(
- BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing)
+static BMFace *bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert *v_opposite)
{
BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
if (l_radial_first->radial_next != l_radial_first) {
@@ -157,12 +156,11 @@ static bool bm_face_exists_tri_from_loop_vert(
do {
BLI_assert(l_radial_iter->f->len == 3);
if (l_radial_iter->prev->v == v_opposite) {
- *r_face_existing = l_radial_iter->f;
- return true;
+ return l_radial_iter->f;
}
} while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
}
- return false;
+ return NULL;
}
/**
@@ -519,7 +517,7 @@ static BMFace *pbvh_bmesh_face_create(
PBVHNode *node = &bvh->nodes[node_index];
/* ensure we never add existing face */
- BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
+ BLI_assert(!BM_face_exists(v_tri, 3));
BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
@@ -1313,18 +1311,17 @@ static void pbvh_bmesh_collapse_edge(
* deletion as well. Prevents extraneous "flaps" from being
* created. */
#if 0
- if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face)))
+ if (UNLIKELY(existing_face = BM_face_exists(v_tri, 3)))
#else
- if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face)))
+ if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn)))
#endif
{
- BLI_assert(existing_face);
BLI_buffer_append(deleted_faces, BMFace *, existing_face);
}
else {
BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v};
- BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
+ BLI_assert(!BM_face_exists(v_tri, 3));
BMEdge *e_tri[3];
PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
int ni = n - bvh->nodes;
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 436cd2b8fde..fc2d9674c2f 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -237,7 +237,7 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done)
BLI_assert(pool->num >= done);
pool->num -= done;
- atomic_sub_z(&pool->currently_running_tasks, done);
+ atomic_sub_and_fetch_z(&pool->currently_running_tasks, done);
pool->done += done;
if (pool->num == 0)
@@ -292,7 +292,7 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
continue;
}
- if (atomic_add_z(&pool->currently_running_tasks, 1) <= pool->num_threads ||
+ if (atomic_add_and_fetch_z(&pool->currently_running_tasks, 1) <= pool->num_threads ||
pool->num_threads == 0)
{
*task = current_task;
@@ -301,7 +301,7 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
break;
}
else {
- atomic_sub_z(&pool->currently_running_tasks, 1);
+ atomic_sub_and_fetch_z(&pool->currently_running_tasks, 1);
}
}
if (!found_task)
@@ -669,7 +669,7 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
/* if found task, do it, otherwise wait until other tasks are done */
if (found_task) {
/* run task */
- atomic_add_z(&pool->currently_running_tasks, 1);
+ atomic_add_and_fetch_z(&pool->currently_running_tasks, 1);
work_task->run(pool, work_task->taskdata, 0);
/* delete task */
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 529233c0dac..577c278e0e4 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1339,6 +1339,34 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
+ if (!MAIN_VERSION_ATLEAST(main, 278, 3)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyCon", "float", "spring_stiffness_ang_x")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc) {
+ rbc->spring_stiffness_ang_x = 10.0;
+ rbc->spring_stiffness_ang_y = 10.0;
+ rbc->spring_stiffness_ang_z = 10.0;
+ rbc->spring_damping_ang_x = 0.5;
+ rbc->spring_damping_ang_y = 0.5;
+ rbc->spring_damping_ang_z = 0.5;
+ }
+ }
+ }
+
+ /* constant detail for sculpting is now a resolution value instead of
+ * a percentage, we reuse old DNA struct member but convert it */
+ for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ if (scene->toolsettings != NULL) {
+ ToolSettings *ts = scene->toolsettings;
+ if (ts->sculpt && ts->sculpt->constant_detail != 0.0f) {
+ ts->sculpt->constant_detail = 100.0f / ts->sculpt->constant_detail;
+ }
+ }
+ }
+ }
+
{
if (!DNA_struct_elem_find(fd->filesdna, "View3DDebug", "char", "background")) {
bScreen *screen;
@@ -1360,20 +1388,5 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
-
- if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyCon", "float", "spring_stiffness_ang_x")) {
- Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- if (rbc) {
- rbc->spring_stiffness_ang_x = 10.0;
- rbc->spring_stiffness_ang_y = 10.0;
- rbc->spring_stiffness_ang_z = 10.0;
- rbc->spring_damping_ang_x = 0.5;
- rbc->spring_damping_ang_y = 0.5;
- rbc->spring_damping_ang_z = 0.5;
- }
- }
- }
}
}
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 4d92baab6eb..132a7ccd4fa 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -626,7 +626,7 @@ void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void
BM_elem_attrs_copy_ex(bm_src, bm_dst, ele_src, ele_dst, BM_ELEM_SELECT);
}
-void BM_elem_select_copy(BMesh *bm_dst, BMesh *UNUSED(bm_src), void *ele_dst_v, const void *ele_src_v)
+void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v)
{
BMHeader *ele_dst = ele_dst_v;
const BMHeader *ele_src = ele_src_v;
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index 06bc5465a19..9c6483de42b 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -58,7 +58,7 @@ void BM_elem_attrs_copy_ex(
BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v,
const char hflag_mask);
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v);
-void BM_elem_select_copy(BMesh *bm_dst, BMesh *bm_src, void *ele_dst_v, const void *ele_src_v);
+void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v);
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const struct BMAllocTemplate *allocsize);
BMesh *BM_mesh_copy(BMesh *bm_old);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index ac4eb2c33fd..0cd91107171 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -444,13 +444,10 @@ BMFace *BM_face_create(
if (create_flag & BM_CREATE_NO_DOUBLE) {
/* Check if face already exists */
- const bool is_overlap = BM_face_exists(verts, len, &f);
- if (is_overlap) {
+ f = BM_face_exists(verts, len);
+ if (f != NULL) {
return f;
}
- else {
- BLI_assert(f == NULL);
- }
}
f = bm_face_create__internal(bm);
@@ -1024,19 +1021,11 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
* \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
* (use when flipping normals, disable when mirroring, eg: symmetrize).
*/
-static void bm_loop_reverse_loop(
+void bmesh_loop_reverse(
BMesh *bm, BMFace *f,
-#ifdef USE_BMESH_HOLES
- BMLoopList *lst,
-#endif
const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
{
-
-#ifdef USE_BMESH_HOLES
- BMLoop *l_first = lst->first;
-#else
BMLoop *l_first = f->l_first;
-#endif
/* track previous cycles radial state */
BMEdge *e_prev = l_first->prev->e;
@@ -1052,7 +1041,7 @@ static void bm_loop_reverse_loop(
bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next;
#if 0
- bmesh_radial_loop_remove(e_curr, l_iter);
+ bmesh_radial_loop_remove(e_iter, l_iter);
bmesh_radial_loop_append(e_prev, l_iter);
#else
/* inline loop reversal */
@@ -1107,20 +1096,6 @@ static void bm_loop_reverse_loop(
bm->elem_index_dirty |= BM_LOOP;
}
-/**
- * \brief Flip the faces direction
- */
-void bmesh_loop_reverse(
- BMesh *bm, BMFace *f,
- const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
-{
-#ifdef USE_BMESH_HOLES
- bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip);
-#else
- bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
-#endif
-}
-
static void bm_elements_systag_enable(void *veles, int tot, const char api_flag)
{
BMHeader **eles = veles;
@@ -1339,22 +1314,15 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
#ifdef USE_BMESH_HOLES
/* add holes */
BLI_movelisttolist(&f_new->loops, &holes);
-#endif
/* update loop face pointer */
-#ifdef USE_BMESH_HOLES
- for (lst = f_new->loops.first; lst; lst = lst->next)
-#endif
- {
-#ifdef USE_BMESH_HOLES
+ for (lst = f_new->loops.first; lst; lst = lst->next) {
l_iter = l_first = lst->first;
-#else
- l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
-#endif
do {
l_iter->f = f_new;
} while ((l_iter = l_iter->next) != l_first);
}
+#endif
bm_elements_systag_disable(faces, totface, _FLAG_JF);
BM_ELEM_API_FLAG_DISABLE(f_new, _FLAG_JF);
@@ -2379,7 +2347,7 @@ void bmesh_vert_separate(
v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
if (copy_select) {
- BM_elem_select_copy(bm, bm, v_new, v);
+ BM_elem_select_copy(bm, v_new, v);
}
while ((e = BLI_SMALLSTACK_POP(edges))) {
@@ -2437,18 +2405,13 @@ static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
do {
BMEdge *e_orig = n_orig->link;
LinkNode *n_step = n_orig->next;
- LinkNode *n_prev = n_orig;
do {
BMEdge *e = n_step->link;
BLI_assert(e != e_orig);
if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) {
BM_edge_splice(bm, e_orig, e);
- n_prev->next = n_step->next;
- n_step = n_prev;
}
- } while ((void)
- (n_prev = n_step),
- (n_step = n_step->next));
+ } while ((n_step = n_step->next));
} while ((n_orig = n_orig->next) && n_orig->next);
} while ((edges_separate = edges_separate->next));
@@ -2638,7 +2601,7 @@ void bmesh_edge_separate(
l_sep->e = e_new;
if (copy_select) {
- BM_elem_select_copy(bm, bm, e_new, e);
+ BM_elem_select_copy(bm, e_new, e);
}
BLI_assert(bmesh_radial_length(e->l) == radlen - 1);
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index 961b10d848a..96154f051f9 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -485,9 +485,9 @@ void bmiter__face_of_vert_begin(struct BMIter__face_of_vert *iter)
{
((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
if (((BMIter *)iter)->count) {
- iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata);
+ iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
+ iter->e_first = iter->l_first->e;
iter->e_next = iter->e_first;
- iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata);
iter->l_next = iter->l_first;
}
else {
@@ -526,9 +526,9 @@ void bmiter__loop_of_vert_begin(struct BMIter__loop_of_vert *iter)
{
((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
if (((BMIter *)iter)->count) {
- iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata);
+ iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
+ iter->e_first = iter->l_first->e;
iter->e_next = iter->e_first;
- iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata);
iter->l_next = iter->l_first;
}
else {
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 3979374d8da..03165beb329 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -104,7 +104,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
*/
bool BM_disk_dissolve(BMesh *bm, BMVert *v)
{
- BMFace *f, *f2;
BMEdge *e, *keepedge = NULL, *baseedge = NULL;
int len = 0;
@@ -132,16 +131,17 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
#if 0
/* handle specific case for three-valence. solve it by
* increasing valence to four. this may be hackish. . */
- BMLoop *loop = e->l;
- if (loop->v == v) loop = loop->next;
- if (!BM_face_split(bm, loop->f, v, loop->v, NULL, NULL, false))
+ BMLoop *l_a = BM_face_vert_share_loop(e->l->f, v);
+ BMLoop *l_b = (e->l->v == v) ? e->l->next : e->l;
+
+ if (!BM_face_split(bm, e->l->f, l_a, l_b, NULL, NULL, false))
return false;
if (!BM_disk_dissolve(bm, v)) {
return false;
}
#else
- if (UNLIKELY(!BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true))) {
+ if (UNLIKELY(!BM_faces_join_pair(bm, e->l, e->l->radial_next, true))) {
return false;
}
else if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, true, false, true))) {
@@ -159,11 +159,10 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
}
/* handle two-valence */
- f = e->l->f;
- f2 = e->l->radial_next->f;
-
- if (f != f2 && !BM_faces_join_pair(bm, f, f2, e, true)) {
- return false;
+ if (e->l != e->l->radial_next) {
+ if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
+ return false;
+ }
}
return true;
@@ -176,9 +175,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
done = true;
e = v->e;
do {
- f = NULL;
+ BMFace *f = NULL;
if (BM_edge_is_manifold(e) && (e != baseedge) && (e != keepedge)) {
- f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true);
+ f = BM_faces_join_pair(bm, e->l, e->l->radial_next, true);
/* return if couldn't join faces in manifold
* conditions */
/* !disabled for testing why bad things happen */
@@ -204,12 +203,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
if (e->l) {
/* get remaining two faces */
- f = e->l->f;
- f2 = e->l->radial_next->f;
-
- if (f != f2) {
+ if (e->l != e->l->radial_next) {
/* join two remaining faces */
- if (!BM_faces_join_pair(bm, f, f2, e, true)) {
+ if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
return false;
}
}
@@ -224,30 +220,24 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
*
* Joins two adjacent faces together.
*
- * Because this method calls to #BM_faces_join to do its work, if a pair
- * of faces share multiple edges, the pair of faces will be joined at
- * every edge (not just edge \a e). This part of the functionality might need
- * to be reconsidered.
+ * \note This method calls to #BM_faces_join to do its work.
+ * This means connected edges which also share the two faces will be joined.
*
* If the windings do not match the winding of the new face will follow
- * \a f_a's winding (i.e. \a f_b will be reversed before the join).
+ * \a l_a's winding (i.e. \a l_b will be reversed before the join).
*
- * \return pointer to the combined face
+ * \return The combined face or NULL on failure.
*/
-BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const bool do_del)
+BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
{
- BMFace *faces[2] = {f_a, f_b};
-
- BMLoop *l_a = BM_face_edge_share_loop(f_a, e);
- BMLoop *l_b = BM_face_edge_share_loop(f_b, e);
-
- BLI_assert(l_a && l_b);
+ BLI_assert((l_a != l_b) && (l_a->e == l_b->e));
if (l_a->v == l_b->v) {
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
- bmesh_loop_reverse(bm, f_b, cd_loop_mdisp_offset, true);
+ bmesh_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true);
}
-
+
+ BMFace *faces[2] = {l_a->f, l_b->f};
return BM_faces_join(bm, faces, 2, do_del);
}
@@ -551,7 +541,7 @@ BMEdge *BM_vert_collapse_edge(
BMVert *tv2 = BM_edge_other_vert(e2, v_kill);
if (tv2) {
/* only action, other calls here only get the edge to return */
- e_new = bmesh_jekv(bm, e_kill, v_kill, do_del);
+ e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
}
}
}
@@ -989,6 +979,7 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
BMLoop *l1, *l2;
BMFace *f;
BMEdge *e_new = NULL;
+ char f_active_prev = 0;
char f_hflag_prev_1;
char f_hflag_prev_2;
@@ -1039,8 +1030,18 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
f_hflag_prev_1 = l1->f->head.hflag;
f_hflag_prev_2 = l2->f->head.hflag;
+ /* maintain active face */
+ if (bm->act_face == l1->f) {
+ f_active_prev = 1;
+ }
+ else if (bm->act_face == l2->f) {
+ f_active_prev = 2;
+ }
+
+ const bool is_flipped = !BM_edge_is_contiguous(e);
+
/* don't delete the edge, manually remove the edge after so we can copy its attributes */
- f = BM_faces_join_pair(bm, l1->f, l2->f, e, true);
+ f = BM_faces_join_pair(bm, BM_face_edge_share_loop(l1->f, e), BM_face_edge_share_loop(l2->f, e), true);
if (f == NULL) {
return NULL;
@@ -1060,6 +1061,22 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
if (BM_edge_face_pair(e_new, &fa, &fb)) {
fa->head.hflag = f_hflag_prev_1;
fb->head.hflag = f_hflag_prev_2;
+
+ if (f_active_prev == 1) {
+ bm->act_face = fa;
+ }
+ else if (f_active_prev == 2) {
+ bm->act_face = fb;
+ }
+
+ if (is_flipped) {
+ BM_face_normal_flip(bm, fb);
+
+ if (ccw) {
+ /* needed otherwise ccw toggles direction */
+ e_new->l = e_new->l->radial_next;
+ }
+ }
}
}
else {
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 2e557e3b606..5e95e9a2cc7 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -31,7 +31,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v);
bool BM_disk_dissolve(BMesh *bm, BMVert *v);
-BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del);
+BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del);
/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 22095214133..7ca5640578a 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -102,17 +102,10 @@ BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
*/
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
{
- BMIter liter;
- BMLoop *l_iter;
+ BMLoop *l_iter = BM_face_vert_share_loop(f, v);
BLI_assert(BM_edge_exists(v_prev, v) != NULL);
- BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) {
- if (l_iter->f == f) {
- break;
- }
- }
-
if (l_iter) {
if (l_iter->prev->v == v_prev) {
return l_iter->next;
@@ -149,7 +142,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
* The faces loop direction is ignored.
* </pre>
*/
-
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
{
#if 0 /* works but slow */
@@ -178,9 +170,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
return l->next->next;
}
}
-
-
-
#endif
}
@@ -392,17 +381,7 @@ BMFace *BM_vert_pair_share_face_by_angle(
*/
BMLoop *BM_vert_find_first_loop(BMVert *v)
{
- BMEdge *e;
-
- if (!v->e)
- return NULL;
-
- e = bmesh_disk_faceedge_find_first(v->e, v);
-
- if (!e)
- return NULL;
-
- return bmesh_radial_faceloop_find_first(e->l, v);
+ return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL;
}
/**
@@ -878,9 +857,18 @@ int BM_vert_face_count_ex(const BMVert *v, int count_max)
*
* same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL``
*/
-bool BM_vert_face_check(BMVert *v)
+bool BM_vert_face_check(const BMVert *v)
{
- return v->e && (bmesh_disk_faceedge_find_first(v->e, v) != NULL);
+ if (v->e != NULL) {
+ const BMEdge *e_iter, *e_first;
+ e_first = e_iter = v->e;
+ do {
+ if (e_iter->l != NULL) {
+ return true;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ return false;
}
/**
@@ -926,7 +914,8 @@ bool BM_vert_is_manifold(const BMVert *v)
/* count edges while looking for non-manifold edges */
e_first = e_iter = v->e;
- l_first = e_iter->l ? e_iter->l : NULL;
+ /* may be null */
+ l_first = e_iter->l;
do {
/* loose edge or edge shared by more than two faces,
* edges with 1 face user are OK, otherwise we could
@@ -1924,7 +1913,7 @@ BMEdge *BM_edge_find_double(BMEdge *e)
*
* \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
*/
-bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
+BMFace *BM_face_exists(BMVert **varr, int len)
{
if (varr[0]->e) {
BMEdge *e_iter, *e_first;
@@ -1963,10 +1952,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
}
if (i_walk == len) {
- if (r_existface) {
- *r_existface = l_iter_radial->f;
- }
- return true;
+ return l_iter_radial->f;
}
}
} while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
@@ -1975,10 +1961,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
} while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, varr[0])) != e_first);
}
- if (r_existface) {
- *r_existface = NULL;
- }
- return false;
+ return NULL;
}
@@ -2121,26 +2104,21 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len)
* \note The face may contain other verts \b not in \a varr.
*
* \note Its possible there are more than one overlapping faces,
- * in this case the first one found will be assigned to \a r_f_overlap.
+ * in this case the first one found will be returned.
*
* \param varr Array of unordered verts.
* \param len \a varr array length.
- * \param r_f_overlap The overlapping face to return.
- * \return Success
+ * \return The face or NULL.
*/
-bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap)
+BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
{
BMIter viter;
BMFace *f;
int i;
- bool is_overlap = false;
+ BMFace *f_overlap = NULL;
LinkNode *f_lnk = NULL;
- if (r_f_overlap) {
- *r_f_overlap = NULL;
- }
-
#ifdef DEBUG
/* check flag isn't already set */
for (i = 0; i < len; i++) {
@@ -2154,10 +2132,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap)
BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
if (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0) {
if (len <= BM_verts_in_face_count(varr, len, f)) {
- if (r_f_overlap)
- *r_f_overlap = f;
-
- is_overlap = true;
+ f_overlap = f;
break;
}
@@ -2171,7 +2146,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap)
BM_ELEM_API_FLAG_DISABLE((BMFace *)f_lnk->link, _FLAG_OVERLAP);
}
- return is_overlap;
+ return f_overlap;
}
/**
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index 10e4b9a15aa..a6a37767ee9 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -86,7 +86,7 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT AT
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b);
-bool BM_vert_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -135,12 +135,12 @@ BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNUL
BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) ATTR_NONNULL(1);
+BMFace* BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1);
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT;
bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index 6052de421dd..8e484841568 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -338,13 +338,28 @@ int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max)
*/
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
{
- const BMEdge *e_find = e;
+ const BMEdge *e_iter = e;
do {
- if (e_find->l && bmesh_radial_facevert_check(e_find->l, v)) {
- return (BMEdge *)e_find;
+ if (e_iter->l != NULL) {
+ return (BMEdge *)((e_iter->l->v == v) ? e_iter : e_iter->l->next->e);
}
- } while ((e_find = bmesh_disk_edge_next(e_find, v)) != e);
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
+ return NULL;
+}
+/**
+ * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
+ *
+ * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
+ */
+BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
+{
+ const BMEdge *e_iter = e;
+ do {
+ if (e_iter->l != NULL) {
+ return (e_iter->l->v == v) ? e_iter->l : e_iter->l->next;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
return NULL;
}
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index 679e7a269b3..0efb25da37c 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -52,6 +52,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_W
int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* RADIAL CYCLE MANAGMENT */
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 6ef0fd6b084..61179d7be70 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -398,7 +398,8 @@ static void bridge_loop_pair(
if (v_b != v_b_next) {
BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next};
- if (BM_face_exists(v_arr, 4, &f) == false) {
+ f = BM_face_exists(v_arr, 4);
+ if (f == NULL) {
/* copy if loop data if its is missing on one ring */
f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true);
@@ -411,7 +412,8 @@ static void bridge_loop_pair(
}
else {
BMVert *v_arr[3] = {v_a, v_b, v_a_next};
- if (BM_face_exists(v_arr, 3, &f) == false) {
+ f = BM_face_exists(v_arr, 3);
+ if (f == NULL) {
/* fan-fill a triangle */
f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true);
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 05efb14a699..6e3a8a1473d 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -322,12 +322,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
}
BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) {
- BMFace *fa, *fb;
- if (BM_edge_face_pair(e, &fa, &fb)) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
BMFace *f_new;
/* join faces */
- f_new = BM_faces_join_pair(bm, fa, fb, e, false);
+ f_new = BM_faces_join_pair(bm, l_a, l_b, false);
if (f_new) {
/* maintain active face */
@@ -437,12 +437,12 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) {
BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
- BMFace *fa, *fb;
- if (BM_edge_face_pair(e, &fa, &fb)) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
BMFace *f_new;
/* join faces */
- f_new = BM_faces_join_pair(bm, fa, fb, e, false);
+ f_new = BM_faces_join_pair(bm, l_a, l_b, false);
/* maintain active face */
if (act_face && bm->act_face == NULL) {
diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
index c68130bc11d..f33a60ccc5c 100644
--- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c
+++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
@@ -136,7 +136,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
i++;
} while ((v != f_verts[0]));
- if (BM_face_exists(f_verts, i, NULL) == false) {
+ if (!BM_face_exists(f_verts, i)) {
BMFace *f;
/* don't use calc_edges option because we already have the edges */
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 9c41e4f2115..81ec2860cf7 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -119,7 +119,8 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles)
};
BMFace *f, *example = NULL;
- if (BM_face_exists(t->v, 3, &f)) {
+ f = BM_face_exists(t->v, 3);
+ if (f != NULL) {
/* If the operator is run with "use_existing_faces"
* disabled, but an output face in the hull is the
* same as a face in the existing mesh, it should not
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index bc620e4a020..655fb346976 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -361,16 +361,16 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
qsort(jedges, totedge, sizeof(*jedges), BLI_sortutil_cmp_float);
for (i = 0; i < totedge; i++) {
- BMFace *f_a, *f_b;
+ BMLoop *l_a, *l_b;
e = jedges[i].data;
- f_a = e->l->f;
- f_b = e->l->radial_next->f;
+ l_a = e->l;
+ l_b = e->l->radial_next;
/* check if another edge already claimed this face */
- if ((f_a->len == 3) && (f_b->len == 3)) {
+ if ((l_a->f->len == 3) && (l_b->f->len == 3)) {
BMFace *f_new;
- f_new = BM_faces_join_pair(bm, f_a, f_b, e, true);
+ f_new = BM_faces_join_pair(bm, l_a, l_b, true);
if (f_new) {
BMO_face_flag_enable(bm, f_new, FACE_OUT);
}
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 6da591b23a0..0ad8247e539 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -160,7 +160,7 @@ finally:
}
if (STACK_SIZE(edges) >= 3) {
- if (!BM_face_exists(verts, STACK_SIZE(edges), NULL)) {
+ if (!BM_face_exists(verts, STACK_SIZE(edges))) {
BMFace *f_new = BM_face_create(bm, verts, edges, STACK_SIZE(edges), f, BM_CREATE_NOP);
BLI_assert(f_new != f);
diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c
index 8938d086c1a..6bd3174d27a 100644
--- a/source/blender/bmesh/operators/bmo_triangulate.c
+++ b/source/blender/bmesh/operators/bmo_triangulate.c
@@ -253,10 +253,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
if (BMO_edge_flag_test(bm, e, ELE_NEW)) {
/* in rare cases the edges face will have already been removed from the edge */
if (LIKELY(e->l)) {
- BMFace *f_new = BM_faces_join_pair(
- bm, e->l->f,
- e->l->radial_next->f, e,
- false); /* join faces */
+ BMFace *f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
if (f_new) {
BMO_face_flag_enable(bm, f_new, ELE_NEW);
BM_edge_kill(bm, e);
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index 978cceee37c..e2c36299ddf 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -322,9 +322,7 @@ void BM_mesh_decimate_dissolve_ex(
i = BM_elem_index_get(e);
if (BM_edge_is_manifold(e)) {
- f_new = BM_faces_join_pair(bm, e->l->f,
- e->l->radial_next->f, e,
- false); /* join faces */
+ f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
if (f_new) {
BMLoop *l_first, *l_iter;
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index 0fc571bc0a8..92300ae66a2 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -74,7 +74,7 @@ static bool bm_vert_dissolve_fan_test(BMVert *v)
((tot_edge == 3) && (tot_edge_boundary == 0) && (tot_edge_manifold == 3)) ||
((tot_edge == 3) && (tot_edge_boundary == 2) && (tot_edge_manifold == 1)))
{
- if (!BM_face_exists(varr, tot_edge, NULL)) {
+ if (!BM_face_exists(varr, tot_edge)) {
return true;
}
}
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 6ff6de33d56..8f3bf88af65 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -317,11 +317,6 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
}
}
- if (mesh->getPositions().empty()) {
- fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str());
- return false;
- }
-
return true;
}
@@ -329,11 +324,15 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
{
// vertices
COLLADAFW::MeshVertexData& pos = mesh->getPositions();
+ if (pos.empty()) {
+ return;
+ }
+
int stride = pos.getStride(0);
if (stride == 0) stride = 3;
-
- me->totvert = mesh->getPositions().getFloatValues()->getCount() / stride;
- me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+
+ me->totvert = pos.getFloatValues()->getCount() / stride;
+ me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
MVert *mvert;
int i;
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
index e5c2b8ace4e..9a47c6b2438 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
@@ -383,7 +383,7 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo
if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED)
this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
- atomic_add_u(&this->m_chunksFinished, 1);
+ atomic_add_and_fetch_u(&this->m_chunksFinished, 1);
if (memoryBuffers) {
for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) {
MemoryBuffer *buffer = memoryBuffers[index];
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 0945da439ef..fdc86540171 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -51,8 +51,12 @@ extern "C" {
/* Graph Building -------------------------------- */
-/* Build depsgraph for the given scene, and dump results in given graph container */
-void DEG_graph_build_from_scene(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene);
+/* Build depsgraph for the given scene, and dump results in given
+ * graph container.
+ */
+void DEG_graph_build_from_scene(struct Depsgraph *graph,
+ struct Main *bmain,
+ struct Scene *scene);
/* Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
@@ -85,31 +89,69 @@ struct CacheFile;
struct Object;
typedef enum eDepsSceneComponentType {
- DEG_SCENE_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
- DEG_SCENE_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
- DEG_SCENE_COMP_SEQUENCER, /* Sequencer Component (Scene Only) */
+ /* Parameters Component - Default when nothing else fits
+ * (i.e. just SDNA property setting).
+ */
+ DEG_SCENE_COMP_PARAMETERS,
+ /* Animation Component
+ * TODO(sergey): merge in with parameters?
+ */
+ DEG_SCENE_COMP_ANIMATION,
+ /* Sequencer Component (Scene Only). */
+ DEG_SCENE_COMP_SEQUENCER,
} eDepsSceneComponentType;
typedef enum eDepsObjectComponentType {
- DEG_OB_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
- DEG_OB_COMP_PROXY, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
- DEG_OB_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
- DEG_OB_COMP_TRANSFORM, /* Transform Component (Parenting/Constraints) */
- DEG_OB_COMP_GEOMETRY, /* Geometry Component (DerivedMesh/Displist) */
-
+ /* Parameters Component - Default when nothing else fits
+ * (i.e. just SDNA property setting).
+ */
+ DEG_OB_COMP_PARAMETERS,
+ /* Generic "Proxy-Inherit" Component.
+ * TODO(sergey): Also for instancing of subgraphs?
+ */
+ DEG_OB_COMP_PROXY,
+ /* Animation Component.
+ *
+ * TODO(sergey): merge in with parameters?
+ */
+ DEG_OB_COMP_ANIMATION,
+ /* Transform Component (Parenting/Constraints) */
+ DEG_OB_COMP_TRANSFORM,
+ /* Geometry Component (DerivedMesh/Displist) */
+ DEG_OB_COMP_GEOMETRY,
+
/* Evaluation-Related Outer Types (with Subdata) */
- DEG_OB_COMP_EVAL_POSE, /* Pose Component - Owner/Container of Bones Eval */
- DEG_OB_COMP_BONE, /* Bone Component - Child/Subcomponent of Pose */
-
- DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */
- DEG_OB_COMP_SHADING, /* Material Shading Component */
- DEG_OB_COMP_CACHE, /* Cache Component */
+
+ /* Pose Component - Owner/Container of Bones Eval */
+ DEG_OB_COMP_EVAL_POSE,
+ /* Bone Component - Child/Subcomponent of Pose */
+ DEG_OB_COMP_BONE,
+
+ /* Particle Systems Component */
+ DEG_OB_COMP_EVAL_PARTICLES,
+ /* Material Shading Component */
+ DEG_OB_COMP_SHADING,
+ /* Cache Component */
+ DEG_OB_COMP_CACHE,
} eDepsObjectComponentType;
-void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description);
-void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description);
-void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description);
-void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, struct CacheFile *cache_file, eDepsObjectComponentType component, const char *description);
+void DEG_add_scene_relation(struct DepsNodeHandle *node,
+ struct Scene *scene,
+ eDepsSceneComponentType component,
+ const char *description);
+void DEG_add_object_relation(struct DepsNodeHandle *node, struct
+ Object *ob,
+ eDepsObjectComponentType component,
+ const char *description);
+void DEG_add_bone_relation(struct DepsNodeHandle *handle,
+ struct Object *ob,
+ const char *bone_name,
+ eDepsObjectComponentType component,
+ const char *description);
+void DEG_add_object_cache_relation(struct DepsNodeHandle *handle,
+ struct CacheFile *cache_file,
+ eDepsObjectComponentType component,
+ const char *description);
/* TODO(sergey): Remove once all geometry update is granular. */
void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
@@ -117,8 +159,22 @@ void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short fla
/* Utility functions for physics modifiers */
typedef bool (*DEG_CollobjFilterFunction)(struct Object *obj, struct ModifierData *md);
-void DEG_add_collision_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name);
-void DEG_add_forcefield_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct EffectorWeights *eff, bool add_absorption, int skip_forcefield, const char *name);
+void DEG_add_collision_relations(struct DepsNodeHandle *handle,
+ struct Scene *scene,
+ Object *ob,
+ struct Group *group,
+ int layer,
+ unsigned int modifier_type,
+ DEG_CollobjFilterFunction fn,
+ bool dupli,
+ const char *name);
+void DEG_add_forcefield_relations(struct DepsNodeHandle *handle,
+ struct Scene *scene,
+ Object *ob,
+ struct EffectorWeights *eff,
+ bool add_absorption,
+ int skip_forcefield,
+ const char *name);
/* ************************************************ */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 6169100d574..8939e4cc93a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -34,6 +34,8 @@
#include <stack>
#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_ID.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -56,10 +58,46 @@ string deg_fcurve_id_name(const FCurve *fcu)
return string(fcu->rna_path) + index_buf;
}
+static bool check_object_needs_evaluation(Object *object)
+{
+ if (object->recalc & OB_RECALC_ALL) {
+ /* Object is tagged for update anyway, no need to re-tag it. */
+ return false;
+ }
+ if (object->type == OB_MESH) {
+ return object->derivedFinal == NULL;
+ }
+ else if (ELEM(object->type,
+ OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE))
+ {
+ return object->curve_cache == NULL;
+ }
+ return false;
+}
+
void deg_graph_build_finalize(Depsgraph *graph)
{
+ /* STEP 1: Make sure new invisible dependencies are ready for use.
+ *
+ * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice
+ * to do it ahead of a time and don't spend time on flushing updates on
+ * every frame change.
+ */
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ if (id_node->layers == 0 || 1) {
+ ID *id = id_node->id;
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (check_object_needs_evaluation(object)) {
+ id_node->tag_update(graph);
+ }
+ }
+ }
+ }
+ GHASH_FOREACH_END();
+ /* STEP 2: Flush visibility layers from children to parent. */
std::stack<OperationDepsNode *> stack;
-
foreach (OperationDepsNode *node, graph->operations) {
IDDepsNode *id_node = node->owner->owner;
node->done = 0;
@@ -78,7 +116,6 @@ void deg_graph_build_finalize(Depsgraph *graph)
node->owner->layers = id_node->layers;
id_node->id->tag |= LIB_TAG_DOIT;
}
-
while (!stack.empty()) {
OperationDepsNode *node = stack.top();
stack.pop();
@@ -104,8 +141,9 @@ void deg_graph_build_finalize(Depsgraph *graph)
}
}
}
-
- /* Re-tag IDs for update if it was tagged before the relations update tag. */
+ /* STEP 3: Re-tag IDs for update if it was tagged before the relations
+ * update tag.
+ */
GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
{
GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components)
@@ -121,6 +159,13 @@ void deg_graph_build_finalize(Depsgraph *graph)
id_node->tag_update(graph);
id->tag &= ~LIB_TAG_DOIT;
}
+ else if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (object->recalc & OB_RECALC_ALL) {
+ id_node->tag_update(graph);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ }
id_node->finalize_build();
}
GHASH_FOREACH_END();
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index d84a590b29f..9b37aaa12ff 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -88,7 +88,7 @@ void deg_graph_detect_cycles(Depsgraph *graph)
}
while (!traversal_stack.empty()) {
- StackEntry entry = traversal_stack.top();
+ StackEntry& entry = traversal_stack.top();
OperationDepsNode *node = entry.node;
bool all_child_traversed = true;
for (int i = node->done; i < node->outlinks.size(); ++i) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 5230e7a38b0..1abce2e6b18 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -106,6 +106,40 @@ extern "C" {
namespace DEG {
+namespace {
+
+struct BuilderWalkUserData {
+ DepsgraphNodeBuilder *builder;
+ Scene *scene;
+};
+
+static void modifier_walk(void *user_data,
+ struct Object * /*ob*/,
+ struct Object **obpoin,
+ int /*cd_flag*/)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*obpoin) {
+ data->builder->build_object(data->scene, NULL, *obpoin);
+ }
+}
+
+void constraint_walk(bConstraint * /*con*/,
+ ID **idpoin,
+ bool /*is_reference*/,
+ void *user_data)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*idpoin) {
+ ID *id = *idpoin;
+ if (GS(id->name) == ID_OB) {
+ data->builder->build_object(data->scene, NULL, (Object *)id);
+ }
+ }
+}
+
+} /* namespace */
+
/* ************ */
/* Node Builder */
@@ -403,19 +437,22 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
{
/*Object *ob = go->ob;*/
- /* Each "group object" is effectively a separate instance of the underlying
- * object data. When the group is evaluated, the transform results and/or
- * some other attributes end up getting overridden by the group
+ /* Each "group object" is effectively a separate instance of the
+ * underlying object data. When the group is evaluated, the transform
+ * results and/or some other attributes end up getting overridden by
+ * the group.
*/
}
- /* create a node for representing subgraph */
+ /* Create a node for representing subgraph. */
SubgraphDepsNode *subgraph_node = m_graph->add_subgraph_node(&group->id);
subgraph_node->graph = subgraph;
- /* make a copy of the data this node will need? */
- // XXX: do we do this now, or later?
- // TODO: need API function which queries graph's ID's hash, and duplicates those blocks thoroughly with all outside links removed...
+ /* Make a copy of the data this node will need? */
+ /* XXX: do we do this now, or later? */
+ /* TODO: need API function which queries graph's ID's hash, and duplicates
+ * those blocks thoroughly with all outside links removed.
+ */
return subgraph_node;
}
@@ -424,18 +461,40 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
{
if (ob->id.tag & LIB_TAG_DOIT) {
IDDepsNode *id_node = m_graph->find_id_node(&ob->id);
- id_node->layers |= base->lay;
+ if (base != NULL) {
+ id_node->layers |= base->lay;
+ }
return;
}
+ ob->id.tag |= LIB_TAG_DOIT;
IDDepsNode *id_node = add_id_node(&ob->id);
- id_node->layers |= base->lay;
+ if (base != NULL) {
+ id_node->layers |= base->lay;
+ }
ob->customdata_mask = 0;
- /* standard components */
+ /* Standard components. */
build_object_transform(scene, ob);
- /* object data */
+ if (ob->parent != NULL) {
+ build_object(scene, NULL, ob->parent);
+ }
+ if (ob->modifiers.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.scene = scene;
+ modifiers_foreachObjectLink(ob, modifier_walk, &data);
+ }
+ if (ob->constraints.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.scene = scene;
+ modifiers_foreachObjectLink(ob, modifier_walk, &data);
+ BKE_constraints_id_loop(&ob->constraints, constraint_walk, &data);
+ }
+
+ /* Object data. */
if (ob->data) {
/* type-specific data... */
switch (ob->type) {
@@ -445,15 +504,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
case OB_SURF:
case OB_MBALL:
case OB_LATTICE:
- {
- /* TODO(sergey): This way using this object's
- * properties as driver target works fine.
- *
- * Does this depend on other nodes?
- */
- add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL,
- DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
-
build_obdata_geom(scene, ob);
/* TODO(sergey): Only for until we support granular
* update of curves.
@@ -465,7 +515,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
}
}
break;
- }
case OB_ARMATURE: /* Pose */
if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) {
@@ -949,6 +998,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
{
ID *obdata = (ID *)ob->data;
+ /* TODO(sergey): This way using this object's properties as driver target
+ * works fine.
+ *
+ * Does this depend on other nodes?
+ */
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_POST,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Parameters Eval");
+
/* Temporary uber-update node, which does everything.
* It is for the being we're porting old dependencies into the new system.
* We'll get rid of this node as soon as all the granular update functions
@@ -956,35 +1017,45 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
*
* TODO(sergey): Get rid of this node.
*/
- add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_POST, function_bind(BKE_object_eval_uber_data, _1, scene, ob),
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_POST,
+ function_bind(BKE_object_eval_uber_data, _1, scene, ob),
DEG_OPCODE_GEOMETRY_UBEREVAL);
- add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, NULL,
- DEG_OPCODE_PLACEHOLDER, "Eval Init");
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Eval Init");
// TODO: "Done" operation
/* Modifiers */
if (ob->modifiers.first) {
- ModifierData *md;
-
- for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
- add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_modifier, _1, scene, ob, md),
- DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+ for (ModifierData *md = (ModifierData *)ob->modifiers.first;
+ md != NULL;
+ md = md->next)
+ {
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_EXEC,
+ function_bind(BKE_object_eval_modifier,
+ _1,
+ scene,
+ ob,
+ md),
+ DEG_OPCODE_GEOMETRY_MODIFIER,
+ md->name);
}
}
/* materials */
if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
+ for (int a = 1; a <= ob->totcol; a++) {
Material *ma = give_current_material(ob, a);
-
- if (ma) {
+ if (ma != NULL) {
// XXX?!
ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
build_material(geom_node, ma);
@@ -1009,16 +1080,23 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
build_animdata(obdata);
- /* nodes for result of obdata's evaluation, and geometry evaluation on object */
+ /* Nodes for result of obdata's evaluation, and geometry
+ * evaluation on object.
+ */
switch (ob->type) {
case OB_MESH:
{
//Mesh *me = (Mesh *)ob->data;
/* evaluation operations */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_mesh_eval_geometry, _1, (Mesh *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_mesh_eval_geometry,
+ _1,
+ (Mesh *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
break;
}
@@ -1026,48 +1104,76 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
{
Object *mom = BKE_mball_basis_find(scene, ob);
- /* motherball - mom depends on children! */
+ /* Motherball - mom depends on children! */
if (mom == ob) {
/* metaball evaluation operations */
/* NOTE: only the motherball gets evaluated! */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_mball_eval_geometry, _1, (MetaBall *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_mball_eval_geometry,
+ _1,
+ (MetaBall *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
}
break;
}
case OB_CURVE:
+ case OB_SURF:
case OB_FONT:
{
- /* curve evaluation operations */
+ /* Curve/nurms evaluation operations. */
/* - calculate curve geometry (including path) */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
-
- /* - calculate curve path - this is used by constraints, etc. */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_EXEC, function_bind(BKE_curve_eval_path, _1, (Curve *)obdata),
- DEG_OPCODE_GEOMETRY_PATH, "Path");
- break;
- }
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_curve_eval_geometry,
+ _1,
+ (Curve *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+
+ /* Calculate curve path - this is used by constraints, etc. */
+ if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_EXEC,
+ function_bind(BKE_curve_eval_path,
+ _1,
+ (Curve *)obdata),
+ DEG_OPCODE_GEOMETRY_PATH,
+ "Path");
+ }
- case OB_SURF: /* Nurbs Surface */
- {
- /* nurbs evaluation operations */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ /* Make sure objects used for bevel.taper are in the graph.
+ * NOTE: This objects might be not linked to the scene.
+ */
+ Curve *cu = (Curve *)obdata;
+ if (cu->bevobj != NULL) {
+ build_object(scene, NULL, cu->bevobj);
+ }
+ if (cu->taperobj != NULL) {
+ build_object(scene, NULL, cu->bevobj);
+ }
+ if (ob->type == OB_FONT && cu->textoncurve != NULL) {
+ build_object(scene, NULL, cu->textoncurve);
+ }
break;
}
- case OB_LATTICE: /* Lattice */
+ case OB_LATTICE:
{
- /* lattice evaluation operations */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_lattice_eval_geometry, _1, (Lattice *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ /* Lattice evaluation operations. */
+ add_operation_node(obdata,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_lattice_eval_geometry,
+ _1,
+ (Lattice *)obdata),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
break;
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index ccc4ea3d47b..bd628338461 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -433,6 +433,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
if (ob->id.tag & LIB_TAG_DOIT) {
return;
}
+ ob->id.tag |= LIB_TAG_DOIT;
/* Object Transforms */
eDepsOperation_Code base_op = (ob->parent) ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
@@ -1273,10 +1274,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
if (data->poletar != NULL) {
if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
// XXX: same armature issues - ready vs done?
- ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->subtarget);
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget);
add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
}
- else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
+ else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) {
/* vertex group target */
/* NOTE: for now, we don't need to represent vertex groups separately... */
ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
@@ -1765,15 +1766,18 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
// XXX: these needs geom data, but where is geom stored?
if (cu->bevobj) {
ComponentKey bevob_key(&cu->bevobj->id, DEPSNODE_TYPE_GEOMETRY);
+ build_object(bmain, scene, cu->bevobj);
add_relation(bevob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Bevel");
}
if (cu->taperobj) {
ComponentKey taperob_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ build_object(bmain, scene, cu->taperobj);
add_relation(taperob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Taper");
}
if (ob->type == OB_FONT) {
if (cu->textoncurve) {
- ComponentKey textoncurve_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey textoncurve_key(&cu->textoncurve->id, DEPSNODE_TYPE_GEOMETRY);
+ build_object(bmain, scene, cu->textoncurve);
add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve");
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index e139ff1f2bc..171cd4529be 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -324,7 +324,15 @@ void DEG_scene_graph_free(Scene *scene)
}
}
-void DEG_add_collision_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name)
+void DEG_add_collision_relations(DepsNodeHandle *handle,
+ Scene *scene,
+ Object *ob,
+ Group *group,
+ int layer,
+ unsigned int modifier_type,
+ DEG_CollobjFilterFunction fn,
+ bool dupli,
+ const char *name)
{
unsigned int numcollobj;
Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli);
@@ -342,7 +350,13 @@ void DEG_add_collision_relations(DepsNodeHandle *handle, Scene *scene, Object *o
MEM_freeN(collobjs);
}
-void DEG_add_forcefield_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name)
+void DEG_add_forcefield_relations(DepsNodeHandle *handle,
+ Scene *scene,
+ Object *ob,
+ EffectorWeights *effector_weights,
+ bool add_absorption,
+ int skip_forcefield,
+ const char *name)
{
ListBase *effectors = pdInitEffectors(scene, ob, effector_weights, false);
@@ -352,12 +366,26 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle, Scene *scene, Object *
DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_TRANSFORM, name);
if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_TRANSFORM, "Smoke Force Domain");
- DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_GEOMETRY, "Smoke Force Domain");
+ DEG_add_object_relation(handle,
+ eff->pd->f_source,
+ DEG_OB_COMP_TRANSFORM,
+ "Smoke Force Domain");
+ DEG_add_object_relation(handle,
+ eff->pd->f_source,
+ DEG_OB_COMP_GEOMETRY,
+ "Smoke Force Domain");
}
if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
- DEG_add_collision_relations(handle, scene, ob, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption");
+ DEG_add_collision_relations(handle,
+ scene,
+ ob,
+ NULL,
+ eff->ob->lay,
+ eModifierType_Collision,
+ NULL,
+ true,
+ "Force Absorption");
}
}
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index c3fd202d832..e926f83bcbe 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -152,7 +152,7 @@ static void deg_task_run_func(TaskPool *pool,
}
if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
BLI_assert(child->num_links_pending > 0);
- atomic_sub_uint32(&child->num_links_pending, 1);
+ atomic_sub_and_fetch_uint32(&child->num_links_pending, 1);
}
if (child->num_links_pending == 0) {
bool is_scheduled = atomic_fetch_and_or_uint8(
@@ -287,7 +287,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
{
if (dec_parents) {
BLI_assert(node->num_links_pending > 0);
- atomic_sub_uint32(&node->num_links_pending, 1);
+ atomic_sub_and_fetch_uint32(&node->num_links_pending, 1);
}
if (node->num_links_pending == 0) {
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
new file mode 100644
index 00000000000..60449ebc600
--- /dev/null
+++ b/source/blender/draw/CMakeLists.txt
@@ -0,0 +1,62 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2016, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Blender Institute
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ nodes
+ operations
+ ../blenkernel
+ ../blenlib
+ ../blentranslation
+ ../imbuf
+ ../makesdna
+ ../makesrna
+ ../windowmanager
+ ../nodes
+ ../nodes/composite
+ ../nodes/intern
+ ../render/extern/include
+ ../render/intern/include
+ ../../../extern/clew/include
+ ../../../intern/guardedalloc
+ ../../../intern/atomic
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ DRW_defines.h
+
+)
+
+list(APPEND INC
+)
+
+endif()
+
+blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/draw/DRW_defines.h b/source/blender/draw/DRW_defines.h
new file mode 100644
index 00000000000..212c39e203b
--- /dev/null
+++ b/source/blender/draw/DRW_defines.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+#ifndef __DRW_DEFINES_H__
+#define __DRW_DEFINES_H__
+
+#endif /* __DRW_DEFINES_H__ */
diff --git a/source/blender/draw/DRW_engines.h b/source/blender/draw/DRW_engines.h
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/draw/DRW_engines.h
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index d7899061218..c0d6963acbb 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -57,6 +57,7 @@
#include "ED_anim_api.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
+#include "ED_util.h"
#include "anim_intern.h"
@@ -263,7 +264,8 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
ot->poll = change_frame_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* rna */
ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index ece0f18e96e..47e73f9b777 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -1328,6 +1328,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
ED_armature_sync_selection(arm->edbo);
+ BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 5015829f868..322476dcca0 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -626,7 +626,7 @@ void POSE_OT_flip_names(wmOperatorType *ot)
/* api callbacks */
ot->exec = pose_flip_names_exec;
- ot->poll = ED_operator_posemode;
+ ot->poll = ED_operator_posemode_local;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index cd0ea23e2d3..8e8345d34c9 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -685,6 +685,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE: /* confirm */
case RETKEY:
+ case PADENTER:
{
/* return to normal cursor and header status */
ED_area_headerprint(pso->sa, NULL);
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 7dcbe2cc24c..ae83e899649 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -84,7 +84,8 @@
static int gp_data_add_exec(bContext *C, wmOperator *op)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
return OPERATOR_CANCELLED;
@@ -95,6 +96,15 @@ static int gp_data_add_exec(bContext *C, wmOperator *op)
id_us_min(&gpd->id);
*gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
+
+ /* if not exist brushes, create a new set */
+ if (ts) {
+ if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+ /* create new brushes */
+ BKE_gpencil_brush_init_presets(ts);
+ }
+ }
+
}
/* notifiers */
@@ -174,7 +184,8 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
static int gp_layer_add_exec(bContext *C, wmOperator *op)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
/* if there's no existing Grease-Pencil data there, add some */
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
@@ -183,6 +194,14 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op)
if (*gpd_ptr == NULL)
*gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil"));
+ /* if not exist brushes, create a new set */
+ if (ts) {
+ if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+ /* create new brushes */
+ BKE_gpencil_brush_init_presets(ts);
+ }
+ }
+
/* add new layer now */
BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 6a558d1c185..ec09add56b8 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -183,6 +183,7 @@ int ED_operator_uvmap(struct bContext *C);
int ED_operator_posemode_exclusive(struct bContext *C);
int ED_operator_posemode_context(struct bContext *C);
int ED_operator_posemode(struct bContext *C);
+int ED_operator_posemode_local(struct bContext *C);
int ED_operator_mask(struct bContext *C);
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index f5968397f65..a4afa958450 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -52,6 +52,8 @@ void ED_OT_flush_edits(struct wmOperatorType *ot);
/* undo.c */
void ED_undo_push(struct bContext *C, const char *str);
void ED_undo_push_op(struct bContext *C, struct wmOperator *op);
+void ED_undo_grouped_push(struct bContext *C, const char *str);
+void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op);
void ED_undo_pop_op(struct bContext *C, struct wmOperator *op);
void ED_undo_pop(struct bContext *C);
void ED_undo_redo(struct bContext *C);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 31598a44b09..d7f06b7db13 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -1083,6 +1083,15 @@ static int depthdropper_poll(bContext *C)
return 1;
}
}
+ else {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d && rv3d->persp == RV3D_CAMOB) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->camera && v3d->camera->data && !ID_IS_LINKED_DATABLOCK(v3d->camera->data)) {
+ return 1;
+ }
+ }
+ }
return 0;
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 02812f6a842..650ef4d012e 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -213,173 +213,6 @@ static void viconutil_set_point(GLint pt[2], int x, int y)
pt[1] = y;
}
-static void viconutil_draw_tri(GLint(*pts)[2])
-{
- glBegin(GL_TRIANGLES);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glVertex2iv(pts[2]);
- glEnd();
-}
-
-static void viconutil_draw_lineloop(GLint(*pts)[2], int numPoints)
-{
- int i;
-
- glBegin(GL_LINE_LOOP);
- for (i = 0; i < numPoints; i++) {
- glVertex2iv(pts[i]);
- }
- glEnd();
-}
-
-static void viconutil_draw_lineloop_smooth(GLint(*pts)[2], int numPoints)
-{
- glEnable(GL_LINE_SMOOTH);
- viconutil_draw_lineloop(pts, numPoints);
- glDisable(GL_LINE_SMOOTH);
-}
-
-static void viconutil_draw_points(GLint(*pts)[2], int numPoints, int pointSize)
-{
- int i;
-
- glBegin(GL_QUADS);
- for (i = 0; i < numPoints; i++) {
- int x = pts[i][0], y = pts[i][1];
-
- glVertex2i(x - pointSize, y - pointSize);
- glVertex2i(x + pointSize, y - pointSize);
- glVertex2i(x + pointSize, y + pointSize);
- glVertex2i(x - pointSize, y + pointSize);
- }
- glEnd();
-}
-
-/* Drawing functions */
-
-static void vicon_x_draw(int x, int y, int w, int h, float alpha)
-{
- x += 3;
- y += 3;
- w -= 6;
- h -= 6;
-
- glEnable(GL_LINE_SMOOTH);
-
- glLineWidth(2.5);
-
- glColor4f(0.0, 0.0, 0.0, alpha);
- glBegin(GL_LINES);
- glVertex2i(x, y);
- glVertex2i(x + w, y + h);
- glVertex2i(x + w, y);
- glVertex2i(x, y + h);
- glEnd();
-
- glDisable(GL_LINE_SMOOTH);
-}
-
-static void vicon_view3d_draw(int x, int y, int w, int h, float alpha)
-{
- int cx = x + w / 2;
- int cy = y + h / 2;
- int d = MAX2(2, h / 3);
-
- glColor4f(0.5, 0.5, 0.5, alpha);
- glBegin(GL_LINES);
- glVertex2i(x, cy - d);
- glVertex2i(x + w, cy - d);
- glVertex2i(x, cy + d);
- glVertex2i(x + w, cy + d);
-
- glVertex2i(cx - d, y);
- glVertex2i(cx - d, y + h);
- glVertex2i(cx + d, y);
- glVertex2i(cx + d, y + h);
- glEnd();
-
- glColor4f(0.0, 0.0, 0.0, alpha);
- glBegin(GL_LINES);
- glVertex2i(x, cy);
- glVertex2i(x + w, cy);
- glVertex2i(cx, y);
- glVertex2i(cx, y + h);
- glEnd();
-}
-
-static void vicon_edit_draw(int x, int y, int w, int h, float alpha)
-{
- GLint pts[4][2];
-
- viconutil_set_point(pts[0], x + 3, y + 3);
- viconutil_set_point(pts[1], x + w - 3, y + 3);
- viconutil_set_point(pts[2], x + w - 3, y + h - 3);
- viconutil_set_point(pts[3], x + 3, y + h - 3);
-
- glColor4f(0.0, 0.0, 0.0, alpha);
- viconutil_draw_lineloop(pts, 4);
-
- glColor3f(1, 1, 0.0);
- viconutil_draw_points(pts, 4, 1);
-}
-
-static void vicon_editmode_hlt_draw(int x, int y, int w, int h, float alpha)
-{
- GLint pts[3][2];
-
- viconutil_set_point(pts[0], x + w / 2, y + h - 2);
- viconutil_set_point(pts[1], x + 3, y + 4);
- viconutil_set_point(pts[2], x + w - 3, y + 4);
-
- glColor4f(0.5, 0.5, 0.5, alpha);
- viconutil_draw_tri(pts);
-
- glColor4f(0.0, 0.0, 0.0, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-
- glColor3f(1, 1, 0.0);
- viconutil_draw_points(pts, 3, 1);
-}
-
-static void vicon_editmode_dehlt_draw(int x, int y, int w, int h, float UNUSED(alpha))
-{
- GLint pts[3][2];
-
- viconutil_set_point(pts[0], x + w / 2, y + h - 2);
- viconutil_set_point(pts[1], x + 3, y + 4);
- viconutil_set_point(pts[2], x + w - 3, y + 4);
-
- glColor4f(0.0f, 0.0f, 0.0f, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-
- glColor3f(0.9f, 0.9f, 0.9f);
- viconutil_draw_points(pts, 3, 1);
-}
-
-static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
-{
- GLint pts[3][2];
- int cx = x + w / 2;
- int cy = y + w / 2;
- int d = w / 3, d2 = w / 5;
-
- viconutil_set_point(pts[0], cx - d2, cy + d);
- viconutil_set_point(pts[1], cx - d2, cy - d);
- viconutil_set_point(pts[2], cx + d2, cy);
-
- glBegin(GL_TRIANGLES);
- glColor4f(0.8f, 0.8f, 0.8f, alpha);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glColor4f(0.3f, 0.3f, 0.3f, alpha);
- glVertex2iv(pts[2]);
- glEnd();
-
- glColor4f(0.0f, 0.0f, 0.0f, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-}
-
static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
{
GLint pts[3][2];
@@ -400,63 +233,6 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float
glEnd();
}
-static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha)
-{
- GLint pts[3][2];
- int cx = x + w / 2;
- int cy = y + w / 2;
- int d = w / 3, d2 = w / 5;
-
- viconutil_set_point(pts[0], cx + d, cy + d2);
- viconutil_set_point(pts[1], cx - d, cy + d2);
- viconutil_set_point(pts[2], cx, cy - d2);
-
- glBegin(GL_TRIANGLES);
- glColor4f(0.8f, 0.8f, 0.8f, alpha);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glColor4f(0.3f, 0.3f, 0.3f, alpha);
- glVertex2iv(pts[2]);
- glEnd();
-
- glColor4f(0.0f, 0.0f, 0.0f, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-}
-
-static void vicon_move_up_draw(int x, int y, int w, int h, float UNUSED(alpha))
-{
- int d = -2;
-
- glEnable(GL_LINE_SMOOTH);
- glLineWidth(1);
- glColor3f(0.0, 0.0, 0.0);
-
- glBegin(GL_LINE_STRIP);
- glVertex2i(x + w / 2 - d * 2, y + h / 2 + d);
- glVertex2i(x + w / 2, y + h / 2 - d + 1);
- glVertex2i(x + w / 2 + d * 2, y + h / 2 + d);
- glEnd();
-
- glDisable(GL_LINE_SMOOTH);
-}
-
-static void vicon_move_down_draw(int x, int y, int w, int h, float UNUSED(alpha))
-{
- int d = 2;
-
- glEnable(GL_LINE_SMOOTH);
- glLineWidth(1);
- glColor3f(0.0, 0.0, 0.0);
-
- glBegin(GL_LINE_STRIP);
- glVertex2i(x + w / 2 - d * 2, y + h / 2 + d);
- glVertex2i(x + w / 2, y + h / 2 - d - 1);
- glVertex2i(x + w / 2 + d * 2, y + h / 2 + d);
- glEnd();
-
- glDisable(GL_LINE_SMOOTH);
-}
-
static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type)
{
/* init dummy theme state for Action Editor - where these colors are defined
@@ -781,15 +557,6 @@ static void init_internal_icons(void)
}
}
- def_internal_vicon(VICO_VIEW3D_VEC, vicon_view3d_draw);
- def_internal_vicon(VICO_EDIT_VEC, vicon_edit_draw);
- def_internal_vicon(VICO_EDITMODE_VEC_DEHLT, vicon_editmode_dehlt_draw);
- def_internal_vicon(VICO_EDITMODE_VEC_HLT, vicon_editmode_hlt_draw);
- def_internal_vicon(VICO_DISCLOSURE_TRI_RIGHT_VEC, vicon_disclosure_tri_right_draw);
- def_internal_vicon(VICO_DISCLOSURE_TRI_DOWN_VEC, vicon_disclosure_tri_down_draw);
- def_internal_vicon(VICO_MOVE_UP_VEC, vicon_move_up_draw);
- def_internal_vicon(VICO_MOVE_DOWN_VEC, vicon_move_down_draw);
- def_internal_vicon(VICO_X_VEC, vicon_x_draw);
def_internal_vicon(VICO_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw);
def_internal_vicon(VICO_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index bdd492beb1e..73a9ea928cc 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -2799,17 +2799,21 @@ void init_userdef_do_versions(void)
}
}
+ if (!USER_VERSION_ATLEAST(278, 3)) {
+ for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) {
+ /* Keyframe Indicators (were using wrong alpha) */
+ btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255;
+ btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255;
+ }
+ }
+
/**
* Include next version bump.
*
* (keep this block even if it becomes empty).
*/
{
- for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* Keyframe Indicators (were using wrong alpha) */
- btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255;
- btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255;
- }
+
}
if (U.pixelsize == 0.0f)
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index e31e4096ded..e05ce727e22 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -496,7 +496,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u
}
/* face should never exist */
- BLI_assert(BM_face_exists(f_verts, f_verts[3] ? 4 : 3, &f) == false);
+ BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3));
f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 7e31deba2c7..c57b0215d46 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -1561,6 +1561,18 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
/* edges may rotate into hidden vertices, if this does _not_ run we get an ilogical state */
BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true);
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+
+ const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out");
+ const int tot_failed = tot - tot_rotate;
+ if (tot_failed != 0) {
+ /* If some edges fail to rotate, we need to re-select them,
+ * otherwise we can end up with invalid selection
+ * (unselected edge between 2 selected faces). */
+ BM_mesh_elem_hflag_enable_test(em->bm, BM_EDGE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+
+ BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed);
+ }
+
EDBM_selectmode_flush(em);
if (!EDBM_op_finish(em, &bmop, op, true)) {
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 4fc61e0912e..438c3acdb11 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -1139,7 +1139,6 @@ BMEdge *EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e)
BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
{
- BMFace *f_mirr = NULL;
BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len);
BMLoop *l_iter, *l_first;
@@ -1152,8 +1151,7 @@ BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
}
} while ((l_iter = l_iter->next) != l_first);
- BM_face_exists(v_mirr_arr, f->len, &f_mirr);
- return f_mirr;
+ return BM_face_exists(v_mirr_arr, f->len);
}
void EDBM_verts_mirror_cache_clear(BMEditMesh *em, BMVert *v)
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 82da6f58912..56f59dca9a1 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -886,7 +886,7 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
/* warning, this lookup is _not_ fast */
- if (cd_dvert_offset != -1) {
+ if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) {
BMVert *eve;
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
eve = BM_vert_at_index(em->bm, vertnum);
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 9d9ccf2f3ba..16842efb436 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -315,6 +315,12 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
IMB_freeImBuf(out);
}
+ else if (gpd){
+ /* If there are no strips, Grease Pencil still needs a buffer to draw on */
+ ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect);
+ RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
+ IMB_freeImBuf(out);
+ }
if (gpd) {
int i;
@@ -479,23 +485,24 @@ static void add_gpencil_renderpass(OGLRender *oglrender, RenderResult *rr, Rende
/* copy image data from rectf */
// XXX: Needs conversion.
unsigned char *src = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
- float *dest = rp->rect;
-
- int x, y, rectx, recty;
- rectx = rr->rectx;
- recty = rr->recty;
- for (y = 0; y < recty; y++) {
- for (x = 0; x < rectx; x++) {
- unsigned char *pixSrc = src + 4 * (rectx * y + x);
- if (pixSrc[3] > 0) {
- float *pixDest = dest + 4 * (rectx * y + x);
- float float_src[4];
- srgb_to_linearrgb_uchar4(float_src, pixSrc);
- addAlphaOverFloat(pixDest, float_src);
+ if (src != NULL) {
+ float *dest = rp->rect;
+
+ int x, y, rectx, recty;
+ rectx = rr->rectx;
+ recty = rr->recty;
+ for (y = 0; y < recty; y++) {
+ for (x = 0; x < rectx; x++) {
+ unsigned char *pixSrc = src + 4 * (rectx * y + x);
+ if (pixSrc[3] > 0) {
+ float *pixDest = dest + 4 * (rectx * y + x);
+ float float_src[4];
+ srgb_to_linearrgb_uchar4(float_src, pixSrc);
+ addAlphaOverFloat(pixDest, float_src);
+ }
}
}
}
-
/* back layer status */
i = 0;
for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 860a865466a..c69e01422e0 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -442,6 +442,17 @@ int ED_operator_posemode(bContext *C)
return 0;
}
+int ED_operator_posemode_local(bContext *C)
+{
+ if (ED_operator_posemode(C)) {
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+ return !(ID_IS_LINKED_DATABLOCK(&ob->id) ||
+ ID_IS_LINKED_DATABLOCK(&arm->id));
+ }
+ return false;
+}
+
/* wrapper for ED_space_image_show_uvedit */
int ED_operator_uvedit(bContext *C)
{
@@ -2136,7 +2147,8 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot)
ot->exec = frame_offset_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = 0;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* rna */
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
@@ -2189,7 +2201,8 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot)
ot->exec = frame_jump_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* rna */
RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range");
@@ -2295,7 +2308,8 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
ot->exec = keyframe_jump_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* properties */
RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
@@ -2357,7 +2371,8 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
ot->exec = marker_jump_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* properties */
RNA_def_boolean(ot->srna, "next", true, "Next Marker", "");
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index fe0fb3f5035..53434b18d06 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -4688,7 +4688,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
sculpt_restore_mesh(sd, ob);
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail);
}
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f);
@@ -5406,7 +5406,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
if (!ts->sculpt->detail_percent)
ts->sculpt->detail_percent = 25;
if (ts->sculpt->constant_detail == 0.0f)
- ts->sculpt->constant_detail = 30.0f;
+ ts->sculpt->constant_detail = 3.0f;
/* Set sane default tiling offsets */
if (!ts->sculpt->paint.tile_offset[0]) ts->sculpt->paint.tile_offset[0] = 1.0f;
@@ -5543,7 +5543,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
size = max_fff(bb_max[0], bb_max[1], bb_max[2]);
/* update topology size */
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail);
sculpt_undo_push_begin("Dynamic topology flood fill");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
@@ -5608,7 +5608,8 @@ static void sample_detail(bContext *C, int ss_co[2])
ray_start, ray_normal, false);
if (srd.hit) {
- sd->constant_detail = srd.detail * 100.0f;
+ /* convert edge length to detail resolution */
+ sd->constant_detail = 1.0f / srd.detail;
}
}
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index d72b7dbd8dc..87cf0e8c9e3 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -537,6 +537,8 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS
last_category = user->category;
}
+
+ UI_block_flag_enable(block, UI_BLOCK_NO_FLIP);
}
void uiTemplateTextureUser(uiLayout *layout, bContext *C)
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 6af36ea6778..83469a48165 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -2510,7 +2510,7 @@ static void filelist_readjob_do(
* Using an atomic operation to avoid having to lock thread...
* Note that we do not really need this here currently, since there is a single listing thread, but better
* remain consistent about threading! */
- *((uint32_t *)entry->uuid) = atomic_add_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1);
+ *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1);
/* Only thing we change in direntry here, so we need to free it first. */
MEM_freeN(entry->relpath);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 7ff66c21af5..489f3776c78 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -3392,7 +3392,9 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
}
protectedTransBits(td->protectflag, vec);
- add_v3_v3v3(td->loc, td->iloc, vec);
+ if (td->loc) {
+ add_v3_v3v3(td->loc, td->iloc, vec);
+ }
constraintTransLim(t, td);
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 6271f80570a..f5b5faa4ad2 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -5413,7 +5413,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
if (tmode == TFM_TRANSLATION) {
do_loc = true;
}
- else if (tmode == TFM_ROTATION) {
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
if (v3d->around == V3D_AROUND_ACTIVE) {
if (ob != OBACT)
do_loc = true;
@@ -5558,7 +5558,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
else
do_loc = true;
}
- else if (tmode == TFM_ROTATION) {
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE))
do_loc = true;
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 805238bd2af..7fd67849414 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -205,6 +205,19 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
return OPERATOR_FINISHED;
}
+void ED_undo_grouped_push(bContext *C, const char *str)
+{
+ /* do nothing if previous undo task is the same as this one (or from the same undo group) */
+ const char *last_undo = BKE_undo_get_name_last();
+
+ if (last_undo && STREQ(str, last_undo)) {
+ return;
+ }
+
+ /* push as usual */
+ ED_undo_push(C, str);
+}
+
void ED_undo_pop(bContext *C)
{
ed_undo_step(C, 1, NULL);
@@ -220,6 +233,16 @@ void ED_undo_push_op(bContext *C, wmOperator *op)
ED_undo_push(C, op->type->name);
}
+void ED_undo_grouped_push_op(bContext *C, wmOperator *op)
+{
+ if (op->type->undo_group[0] != '\0') {
+ ED_undo_grouped_push(C, op->type->undo_group);
+ }
+ else {
+ ED_undo_grouped_push(C, op->type->name);
+ }
+}
+
void ED_undo_pop_op(bContext *C, wmOperator *op)
{
/* search back a couple of undo's, in case something else added pushes */
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index b8ed780397f..d58340965a7 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1763,20 +1763,15 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime)
}
// if at least one tree, create the scenes from the PoseTree stored in the channels
// postpone until execute_tree: this way the pose constraint are included
- //if (count)
- // create_scene(scene, ob, ctime);
- //itasc_update_param(ob->pose);
+ if (count)
+ create_scene(scene, ob, ctime);
+ itasc_update_param(ob->pose);
// make sure we don't rebuilt until the user changes something important
ob->pose->flag &= ~POSE_WAS_REBUILT;
}
void itasc_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
- if (!ob->pose->ikdata) {
- // IK tree not yet created, no it now
- create_scene(scene, ob, ctime);
- itasc_update_param(ob->pose);
- }
if (ob->pose->ikdata) {
IK_Data *ikdata = (IK_Data *)ob->pose->ikdata;
bItasc *ikparam = (bItasc *) ob->pose->ikparam;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index a050eee79f1..cf367bf3205 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1070,7 +1070,7 @@ typedef struct Sculpt {
float gravity_factor;
/* scale for constant detail size */
- float constant_detail;
+ float constant_detail; /* Constant detail resolution (Blender unit / constant_detail) */
float detail_percent;
float pad;
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index c63fbf272d8..ee662bc2b0d 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -35,6 +35,7 @@
#include "BLI_utildefines.h"
#include "BKE_icons.h"
+#include "BKE_object.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -335,6 +336,20 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
}
}
+static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_proxy)
+{
+ /* Special case, as we can't rely on id_make_local(); it clears proxies. */
+ if (!clear_proxy && GS(self->name) == ID_OB) {
+ BKE_object_make_local_ex(bmain, (Object *)self, false, clear_proxy);
+ }
+ else {
+ id_make_local(bmain, self, false, false);
+ }
+
+ return self->newid ? self->newid : self;
+}
+
+
static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain)
{
AnimData *adt = BKE_animdata_add_id(id);
@@ -987,6 +1002,17 @@ static void rna_def_ID(BlenderRNA *brna)
parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ func = RNA_def_function(srna, "make_local", "rna_ID_make_local");
+ RNA_def_function_ui_description(func, "Make this datablock local, return local one "
+ "(may be a copy of the original, in case it is also indirectly used)");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ RNA_def_boolean(func, "clear_proxy", true, "",
+ "Whether to clear proxies (the default behavior); can cause proxies to be duplicated"
+ " when still referred to from another library");
+ RNA_def_property_flag(parm, PROP_PYFUNC_OPTIONAL);
+ parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied");
+ RNA_def_function_return(func, parm);
+
func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID");
RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one");
parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages");
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index e5cea63db1f..30a0825267d 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -575,7 +575,7 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this camera before deleting it "
"(WARNING: will also delete objects instancing that camera data)");
@@ -614,7 +614,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this scene before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -655,7 +655,7 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this object before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_objects_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -692,7 +692,7 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this material before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_materials_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -736,7 +736,7 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this node tree before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -795,7 +795,7 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this mesh before deleting it "
"(WARNING: will also delete objects instancing that mesh data)");
@@ -835,7 +835,7 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this lamp before deleting it "
"(WARNING: will also delete objects instancing that lamp data)");
@@ -953,7 +953,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this image before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_images_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -990,7 +990,7 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this lattice before deleting it "
"(WARNING: will also delete objects instancing that lattice data)");
@@ -1030,7 +1030,7 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this curve before deleting it "
"(WARNING: will also delete objects instancing that curve data)");
@@ -1068,7 +1068,7 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this metaball before deleting it "
"(WARNING: will also delete objects instancing that metaball data)");
@@ -1108,7 +1108,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this font before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1146,7 +1146,7 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this texture before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_textures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1183,7 +1183,7 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this brush before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1220,7 +1220,7 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "world", "World", "", "World to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this world before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1257,7 +1257,7 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1294,7 +1294,7 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this speaker before deleting it "
"(WARNING: will also delete objects instancing that speaker data)");
@@ -1333,7 +1333,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this text before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_texts_load");
@@ -1383,7 +1383,7 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this sound before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1420,7 +1420,7 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ RNA_def_boolean(func, "do_unlink", true, "",
"Unlink all usages of this armature before deleting it "
"(WARNING: will also delete objects instancing that armature data)");
@@ -1458,7 +1458,7 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this action before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_actions_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1468,6 +1468,7 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Main_actions_is_updated_get", NULL);
}
+
void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -1494,7 +1495,7 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this palette before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1564,7 +1565,7 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this grease pencil before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1593,7 +1594,7 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this movie clip before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_movieclip_load");
@@ -1645,7 +1646,7 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mask before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1682,7 +1683,7 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this line style before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index edc7324d3fd..d1974005fce 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -463,10 +463,12 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Detail Percentage", "Maximum edge length for dynamic topology sculpting (in brush percenage)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "constant_detail", PROP_FLOAT, PROP_PERCENTAGE);
- RNA_def_property_range(prop, 0.001, 10000.0);
- RNA_def_property_ui_range(prop, 0.1, 100.0, 10, 2);
- RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (as percentage of blender unit)");
+ prop = RNA_def_property(srna, "constant_detail_resolution", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "constant_detail");
+ RNA_def_property_range(prop, 0.0001, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001, 1000.0, 10, 2);
+ RNA_def_property_ui_text(prop, "Resolution", "Maximum edge length for dynamic topology sculpting (as divisor "
+ "of blender unit - higher value means smaller edge length)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_smooth_shading", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 7580bd900e6..ab5e44c7c76 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1970,7 +1970,7 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
static EnumPropertyItem other_uv_filter_items[] = {
{SI_FILTER_ALL, "ALL", 0, "All", "No filter, show all islands from other objects"},
{SI_FILTER_SAME_IMAGE, "SAME_IMAGE", ICON_IMAGE_DATA, "Same Image",
- "Only show others' UV islads who's active image matches image of the active face"},
+ "Only show others' UV islands whose active image matches image of the active face"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 90081a93188..35c9c9bcc89 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -419,6 +419,7 @@ static EnumPropertyItem keymap_modifiers_items[] = {
static EnumPropertyItem operator_flag_items[] = {
{OPTYPE_REGISTER, "REGISTER", 0, "Register", "Display in the info window and support the redo toolbar panel"},
{OPTYPE_UNDO, "UNDO", 0, "Undo", "Push an undo event (needed for operator redo)"},
+ {OPTYPE_UNDO_GROUPED, "UNDO_GROUPED", 0, "Grouped Undo", "Push a single undo event for repetead instances of this operator"},
{OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"},
{OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"},
{OPTYPE_GRAB_CURSOR, "GRAB_CURSOR", 0, "Grab Pointer",
@@ -1139,6 +1140,7 @@ static char _operator_idname[OP_MAX_TYPENAME];
static char _operator_name[OP_MAX_TYPENAME];
static char _operator_descr[RNA_DYN_DESCR_MAX];
static char _operator_ctxt[RNA_DYN_DESCR_MAX];
+static char _operator_undo_group[OP_MAX_TYPENAME];
static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
@@ -1153,10 +1155,11 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
+ dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr);
/* clear in case they are left unset */
- _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0';
+ _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0';
/* We have to set default op context! */
strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
@@ -1210,9 +1213,10 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
int namelen = strlen(_operator_name) + 1;
int desclen = strlen(_operator_descr) + 1;
int ctxtlen = strlen(_operator_ctxt) + 1;
+ int ugrouplen = strlen(_operator_undo_group) + 1;
char *ch;
/* 2 terminators and 3 to convert a.b -> A_OT_b */
- ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
+ ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname");
WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
dummyot.idname = ch;
ch += idlen;
@@ -1224,6 +1228,9 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
ch += desclen;
strcpy(ch, _operator_ctxt);
dummyot.translation_context = ch;
+ ch += ctxtlen;
+ strcpy(ch, _operator_undo_group);
+ dummyot.undo_group = ch;
}
}
@@ -1280,10 +1287,11 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
+ dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr);
/* clear in case they are left unset */
- _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0';
+ _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0';
/* We have to set default op context! */
strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
@@ -1297,9 +1305,10 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
int namelen = strlen(_operator_name) + 1;
int desclen = strlen(_operator_descr) + 1;
int ctxtlen = strlen(_operator_ctxt) + 1;
+ int ugrouplen = strlen(_operator_undo_group) + 1;
char *ch;
/* 2 terminators and 3 to convert a.b -> A_OT_b */
- ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
+ ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname");
WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
dummyot.idname = ch;
ch += idlen;
@@ -1311,6 +1320,9 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
ch += desclen;
strcpy(ch, _operator_ctxt);
dummyot.translation_context = ch;
+ ch += ctxtlen;
+ strcpy(ch, _operator_undo_group);
+ dummyot.undo_group = ch;
}
if (strlen(identifier) >= sizeof(dummyop.idname)) {
@@ -1401,6 +1413,16 @@ static void rna_Operator_bl_description_set(PointerRNA *ptr, const char *value)
assert(!"setting the bl_description on a non-builtin operator");
}
+static void rna_Operator_bl_undo_group_set(PointerRNA *ptr, const char *value)
+{
+ wmOperator *data = (wmOperator *)(ptr->data);
+ char *str = (char *)data->type->undo_group;
+ if (!str[0])
+ BLI_strncpy(str, value, OP_MAX_TYPENAME); /* utf8 already ensured */
+ else
+ assert(!"setting the bl_undo_group on a non-builtin operator");
+}
+
static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
wmKeyMapItem *kmi = ptr->data;
@@ -1509,6 +1531,14 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+ prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->undo_group");
+ RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+
prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->flag");
RNA_def_property_enum_items(prop, operator_flag_items);
@@ -1587,6 +1617,14 @@ static void rna_def_macro_operator(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+ prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->undo_group");
+ RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+
prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->flag");
RNA_def_property_enum_items(prop, operator_flag_items);
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index ecbc3891e8c..b049457e640 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -143,17 +143,17 @@ static void updateDepsgraph(ModifierData *md,
{
ArrayModifierData *amd = (ArrayModifierData *)md;
if (amd->start_cap != NULL) {
- DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier Start Cap");
+ DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap");
}
if (amd->end_cap != NULL) {
- DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap");
+ DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap");
}
if (amd->curve_ob) {
- DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve");
+ DEG_add_object_relation(node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve");
DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
}
if (amd->offset_ob != NULL) {
- DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier Offset");
+ DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
}
}
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 1d951bae48b..b20c03bee28 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -2233,7 +2233,7 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args)
}
/* check if the face exists */
- if (BM_face_exists(vert_array, vert_seq_len, NULL)) {
+ if (BM_face_exists(vert_array, vert_seq_len) != NULL) {
PyErr_SetString(PyExc_ValueError,
"faces.new(verts): face already exists");
goto cleanup;
@@ -2426,7 +2426,8 @@ static PyObject *bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args)
return NULL;
}
- if (BM_face_exists(vert_array, vert_seq_len, &f)) {
+ f = BM_face_exists(vert_array, vert_seq_len);
+ if (f != NULL) {
ret = BPy_BMFace_CreatePyObject(bm, f);
}
else {
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 547968e2906..f51b6b2aafd 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -139,6 +139,7 @@ enum {
OPTYPE_INTERNAL = (1 << 6),
OPTYPE_LOCK_BYPASS = (1 << 7), /* Allow operator to run when interface is locked */
+ OPTYPE_UNDO_GROUPED = (1 << 8), /* Special type of undo which doesn't store itself multiple times */
};
/* context to call operator in for WM_operator_name_call */
@@ -523,6 +524,7 @@ typedef struct wmOperatorType {
const char *idname; /* unique identifier */
const char *translation_context;
const char *description; /* tooltips and python docs */
+ const char *undo_group; /* identifier to group operators together */
/* this callback executes the operator without any interactive input,
* parameters may be provided through operator properties. cannot use
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index cadc3ac8b6e..1a831846af7 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -725,10 +725,13 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat)
/* we don't want to do undo pushes for operators that are being
* called from operators that already do an undo push. usually
* this will happen for python operators that call C operators */
- if (wm->op_undo_depth == 0)
+ if (wm->op_undo_depth == 0) {
if (op->type->flag & OPTYPE_UNDO)
ED_undo_push_op(C, op);
-
+ else if (op->type->flag & OPTYPE_UNDO_GROUPED)
+ ED_undo_grouped_push_op(C, op);
+ }
+
if (repeat == 0) {
if (G.debug & G_DEBUG_WM) {
char *buf = WM_operator_pystring(C, op, false, true);
@@ -1860,9 +1863,12 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
wm->op_undo_depth--;
/* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
- if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0)
+ if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) {
if (handler->op->type->flag & OPTYPE_UNDO)
ED_undo_push_op(C, handler->op);
+ else if (handler->op->type->flag & OPTYPE_UNDO_GROUPED)
+ ED_undo_grouped_push_op(C, handler->op);
+ }
if (handler->op->reports->list.first) {
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp
index 4f5e34896fc..c588a4b33cf 100644
--- a/source/gameengine/VideoTexture/VideoDeckLink.cpp
+++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp
@@ -544,12 +544,12 @@ HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/,
ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void)
{
- return atomic_add_uint32(&mRefCount, 1U);
+ return atomic_add_and_fetch_uint32(&mRefCount, 1U);
}
ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void)
{
- uint32_t newCount = atomic_sub_uint32(&mRefCount, 1U);
+ uint32_t newCount = atomic_sub_and_fetch_uint32(&mRefCount, 1U);
if (newCount == 0)
delete this;
return (ULONG)newCount;