diff options
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; |