diff options
author | Antony Riakiotakis <kalast@gmail.com> | 2015-02-16 15:02:00 +0300 |
---|---|---|
committer | Antony Riakiotakis <kalast@gmail.com> | 2015-02-16 15:02:00 +0300 |
commit | 5a14dd7476a2c499da61ae0525f97f29cb4c3305 (patch) | |
tree | cee2bdcab4fbbc14a1db0610a3fed65643681cea | |
parent | 84ea48d58b90218f97025f94e0b924d7aea665cb (diff) | |
parent | 7c3d5a3337313663befef4c603341f6c1adf78b5 (diff) |
Merge branch 'master' into gooseberry
Conflicts:
source/blender/editors/space_sequencer/sequencer_draw.c
78 files changed, 2423 insertions, 889 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 026386a876b..561d7f18ff5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,7 +369,7 @@ endif() mark_as_advanced(LLVM_STATIC) # disable for now, but plan to support on all platforms eventually -option(WITH_MEM_JEMALLOC "Enable malloc replacement (http://www.canonware.com/jemalloc)" OFF) +option(WITH_MEM_JEMALLOC "Enable malloc replacement (http://www.canonware.com/jemalloc)" ON) mark_as_advanced(WITH_MEM_JEMALLOC) # currently only used for BLI_mempool @@ -838,17 +838,21 @@ if(UNIX AND NOT APPLE) if(WITH_SDL) if(WITH_SDL_DYNLOAD) - set(SDLMAIN_LIBRARY) set(SDL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extern/sdlew/include/SDL2") set(SDL_LIBRARY) - set(SDL_LIBRARY_TEMP) else() - find_package_wrapper(SDL) + find_package_wrapper(SDL2) + if(SDL2_FOUND) + # Use same names for both versions of SDL until we move to 2.x. + set(SDL_INCLUDE_DIR "${SDL2_INCLUDE_DIR}") + set(SDL_LIBRARY "${SDL2_LIBRARY}") + set(SDL_FOUND "${SDL2_FOUND}") + else() + find_package_wrapper(SDL) + endif() mark_as_advanced( - SDLMAIN_LIBRARY SDL_INCLUDE_DIR SDL_LIBRARY - SDL_LIBRARY_TEMP ) # unset(SDLMAIN_LIBRARY CACHE) if(NOT SDL_FOUND) diff --git a/build_files/cmake/Modules/FindJeMalloc.cmake b/build_files/cmake/Modules/FindJeMalloc.cmake index 5c7aa2cf1e1..466456baf32 100644 --- a/build_files/cmake/Modules/FindJeMalloc.cmake +++ b/build_files/cmake/Modules/FindJeMalloc.cmake @@ -33,6 +33,7 @@ SET(_jemalloc_SEARCH_DIRS /sw # Fink /opt/local # DarwinPorts /opt/csw # Blastwave + /opt/lib/jemalloc ) FIND_PATH(JEMALLOC_INCLUDE_DIR diff --git a/build_files/cmake/Modules/FindSDL2.cmake b/build_files/cmake/Modules/FindSDL2.cmake new file mode 100644 index 00000000000..2a835cf94fa --- /dev/null +++ b/build_files/cmake/Modules/FindSDL2.cmake @@ -0,0 +1,72 @@ +# - Find SDL library +# Find the native SDL includes and library +# This module defines +# SDL2_INCLUDE_DIRS, where to find SDL.h, Set when SDL2_INCLUDE_DIR is found. +# SDL2_LIBRARIES, libraries to link against to use SDL. +# SDL2_ROOT_DIR, The base directory to search for SDL. +# This can also be an environment variable. +# SDL2_FOUND, If false, do not try to use SDL. +# +# also defined, but not for general use are +# SDL2_LIBRARY, where to find the SDL library. + +#============================================================================= +# Copyright 2015 Blender Foundation. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= + +# If SDL2_ROOT_DIR was defined in the environment, use it. +IF(NOT SDL2_ROOT_DIR AND NOT $ENV{SDL2_ROOT_DIR} STREQUAL "") + SET(SDL2_ROOT_DIR $ENV{SDL2_ROOT_DIR}) +ENDIF() + +SET(_sdl2_SEARCH_DIRS + ${SDL2_ROOT_DIR} + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave +) + +FIND_PATH(SDL2_INCLUDE_DIR + NAMES + SDL.h + HINTS + ${_sdl2_SEARCH_DIRS} + PATH_SUFFIXES + include/SDL2 include +) + +FIND_LIBRARY(SDL2_LIBRARY + NAMES + SDL2 + HINTS + ${_sdl2_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib + ) + +# handle the QUIETLY and REQUIRED arguments and set SDL2_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 DEFAULT_MSG + SDL2_LIBRARY SDL2_INCLUDE_DIR) + +IF(SDL2_FOUND) + SET(SDL2_LIBRARIES ${SDL2_LIBRARY}) + SET(SDL2_INCLUDE_DIRS ${SDL2_INCLUDE_DIR}) +ENDIF(SDL2_FOUND) + +MARK_AS_ADVANCED( + SDL2_INCLUDE_DIR + SDL2_LIBRARY +) diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index f6a6f96280f..b000266cac2 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -45,7 +45,9 @@ if(CYCLES_STANDALONE_REPOSITORY) endif() else() list(APPEND LIBRARIES bf_intern_glew_mx) - list(APPEND LIBRARIES extern_glog) + if(WITH_CYCLES_LOGGING) + list(APPEND LIBRARIES extern_glog) + endif() endif() if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI) diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 20dced2fe00..71086f2e764 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -338,7 +338,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons { float alpha_x = sc->data0; float alpha_y = sc->data1; - int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; float3 N = sc->N; if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) @@ -429,7 +429,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, con float alpha_x = sc->data0; float alpha_y = sc->data1; float m_eta = sc->data2; - int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; float3 N = sc->N; if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) @@ -486,7 +486,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure { float alpha_x = sc->data0; float alpha_y = sc->data1; - int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; float3 N = sc->N; float cosNO = dot(N, I); @@ -688,7 +688,7 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, { float alpha_x = sc->data0; float alpha_y = sc->data1; - int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; float3 N = sc->N; if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) @@ -782,7 +782,7 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc float alpha_x = sc->data0; float alpha_y = sc->data1; float m_eta = sc->data2; - int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; float3 N = sc->N; if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) @@ -838,7 +838,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl { float alpha_x = sc->data0; float alpha_y = sc->data1; - int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; float3 N = sc->N; float cosNO = dot(N, I); diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index a1012cf2b72..151e762020b 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -130,9 +130,6 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, rphase, rscatter, &volume_segment, NULL, true); } - if(result != VOLUME_PATH_SCATTERED) - throughput *= volume_segment.accum_transmittance; - /* free cached steps */ kernel_volume_decoupled_free(kg, &volume_segment); @@ -142,6 +139,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, else break; } + else { + throughput *= volume_segment.accum_transmittance; + } } else #endif @@ -575,9 +575,6 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, rphase, rscatter, &volume_segment, NULL, true); } - if(result != VOLUME_PATH_SCATTERED) - throughput *= volume_segment.accum_transmittance; - /* free cached steps */ kernel_volume_decoupled_free(kg, &volume_segment); @@ -587,6 +584,9 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, else break; } + else { + throughput *= volume_segment.accum_transmittance; + } } else #endif diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 24d36a1fb0a..9c7310d4a05 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -750,8 +750,49 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce device->tex_alloc("__attributes_map", dscene->attributes_map); } -static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_float, vector<float4>& attr_float3, vector<uchar4>& attr_uchar4, - Attribute *mattr, TypeDesc& type, int& offset, AttributeElement& element) +static void update_attribute_element_size(Mesh *mesh, + Attribute *mattr, + size_t *attr_float_size, + size_t *attr_float3_size, + size_t *attr_uchar4_size) +{ + if(mattr) { + size_t size = mattr->element_size( + mesh->verts.size(), + mesh->triangles.size(), + mesh->motion_steps, + mesh->curves.size(), + mesh->curve_keys.size()); + + if(mattr->element == ATTR_ELEMENT_VOXEL) { + /* pass */ + } + else if(mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + *attr_uchar4_size += size; + } + else if(mattr->type == TypeDesc::TypeFloat) { + *attr_float_size += size; + } + else if(mattr->type == TypeDesc::TypeMatrix) { + *attr_float3_size += size * 4; + } + else { + *attr_float3_size += size; + } + } +} + +static void update_attribute_element_offset(Mesh *mesh, + vector<float>& attr_float, + size_t& attr_float_offset, + vector<float4>& attr_float3, + size_t& attr_float3_offset, + vector<uchar4>& attr_uchar4, + size_t& attr_uchar4_offset, + Attribute *mattr, + TypeDesc& type, + int& offset, + AttributeElement& element) { if(mattr) { /* store element and type */ @@ -773,39 +814,43 @@ static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_floa } else if(mattr->element == ATTR_ELEMENT_CORNER_BYTE) { uchar4 *data = mattr->data_uchar4(); - offset = attr_uchar4.size(); + offset = attr_uchar4_offset; - attr_uchar4.resize(attr_uchar4.size() + size); - - for(size_t k = 0; k < size; k++) + assert(attr_uchar4.capacity() >= offset + size); + for(size_t k = 0; k < size; k++) { attr_uchar4[offset+k] = data[k]; + } + attr_uchar4_offset += size; } else if(mattr->type == TypeDesc::TypeFloat) { float *data = mattr->data_float(); - offset = attr_float.size(); - - attr_float.resize(attr_float.size() + size); + offset = attr_float_offset; - for(size_t k = 0; k < size; k++) + assert(attr_float.capacity() >= offset + size); + for(size_t k = 0; k < size; k++) { attr_float[offset+k] = data[k]; + } + attr_float_offset += size; } else if(mattr->type == TypeDesc::TypeMatrix) { Transform *tfm = mattr->data_transform(); - offset = attr_float3.size(); - - attr_float3.resize(attr_float3.size() + size*4); + offset = attr_float3_offset; - for(size_t k = 0; k < size*4; k++) + assert(attr_float3.capacity() >= offset + size * 4); + for(size_t k = 0; k < size*4; k++) { attr_float3[offset+k] = (&tfm->x)[k]; + } + attr_float3_offset += size * 4; } else { float4 *data = mattr->data_float4(); - offset = attr_float3.size(); + offset = attr_float3_offset; - attr_float3.resize(attr_float3.size() + size); - - for(size_t k = 0; k < size; k++) + assert(attr_float3.capacity() >= offset + size); + for(size_t k = 0; k < size; k++) { attr_float3[offset+k] = data[k]; + } + attr_float3_offset += size; } /* mesh vertex/curve index is global, not per object, so we sneak @@ -855,16 +900,16 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, /* mesh attribute are stored in a single array per data type. here we fill * those arrays, and set the offset and element type to create attribute * maps next */ - vector<float> attr_float; - vector<float4> attr_float3; - vector<uchar4> attr_uchar4; + /* Pre-allocate attributes to avoid arrays re-allocation which would + * take 2x of overall attribute memory usage. + */ + size_t attr_float_size = 0; + size_t attr_float3_size = 0; + size_t attr_uchar4_size = 0; for(size_t i = 0; i < scene->meshes.size(); i++) { Mesh *mesh = scene->meshes[i]; AttributeRequestSet& attributes = mesh_attributes[i]; - - /* todo: we now store std and name attributes from requests even if - * they actually refer to the same mesh attributes, optimize */ foreach(AttributeRequest& req, attributes.requests) { Attribute *triangle_mattr = mesh->attributes.find(req); Attribute *curve_mattr = mesh->curve_attributes.find(req); @@ -878,12 +923,56 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size()); } - update_attribute_element_offset(mesh, attr_float, attr_float3, attr_uchar4, triangle_mattr, - req.triangle_type, req.triangle_offset, req.triangle_element); + update_attribute_element_size(mesh, + triangle_mattr, + &attr_float_size, + &attr_float3_size, + &attr_uchar4_size); + update_attribute_element_size(mesh, + curve_mattr, + &attr_float_size, + &attr_float3_size, + &attr_uchar4_size); + } + } + + vector<float> attr_float(attr_float_size); + vector<float4> attr_float3(attr_float3_size); + vector<uchar4> attr_uchar4(attr_uchar4_size); + + size_t attr_float_offset = 0; + size_t attr_float3_offset = 0; + size_t attr_uchar4_offset = 0; + + /* Fill in attributes. */ + for(size_t i = 0; i < scene->meshes.size(); i++) { + Mesh *mesh = scene->meshes[i]; + AttributeRequestSet& attributes = mesh_attributes[i]; + + /* todo: we now store std and name attributes from requests even if + * they actually refer to the same mesh attributes, optimize */ + foreach(AttributeRequest& req, attributes.requests) { + Attribute *triangle_mattr = mesh->attributes.find(req); + Attribute *curve_mattr = mesh->curve_attributes.find(req); + + update_attribute_element_offset(mesh, + attr_float, attr_float_offset, + attr_float3, attr_float3_offset, + attr_uchar4, attr_uchar4_offset, + triangle_mattr, + req.triangle_type, + req.triangle_offset, + req.triangle_element); + + update_attribute_element_offset(mesh, + attr_float, attr_float_offset, + attr_float3, attr_float3_offset, + attr_uchar4, attr_uchar4_offset, + curve_mattr, + req.curve_type, + req.curve_offset, + req.curve_element); - update_attribute_element_offset(mesh, attr_float, attr_float3, attr_uchar4, curve_mattr, - req.curve_type, req.curve_offset, req.curve_element); - if(progress.get_cancel()) return; } } diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 64d6fa4b9b9..524574f096d 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -36,6 +36,11 @@ #include "util_foreach.h" #include "util_progress.h" +#ifdef WITH_CYCLES_DEBUG +# include "util_guarded_allocator.h" +# include "util_logging.h" +#endif + CCL_NAMESPACE_BEGIN Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_) @@ -239,6 +244,12 @@ void Scene::device_update(Device *device_, Progress& progress) progress.set_status("Updating Device", "Writing constant memory"); device->const_copy_to("__data", &dscene.data, sizeof(dscene.data)); } + +#ifdef WITH_CYCLES_DEBUG + VLOG(1) << "System memory statistics after full device sync:\n" + << " Usage: " << util_guarded_get_mem_used() << "\n" + << " Peak: " << util_guarded_get_mem_peak(); +#endif } Scene::MotionType Scene::need_motion(bool advanced_shading) diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index 1961ee8addc..bfe46ce6f67 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -9,6 +9,7 @@ set(INC_SYS ) set(SRC + util_aligned_malloc.cpp util_cache.cpp util_logging.cpp util_md5.cpp @@ -33,6 +34,7 @@ endif() set(SRC_HEADERS util_algorithm.h + util_aligned_malloc.h util_args.h util_atomic.h util_boundbox.h @@ -72,6 +74,11 @@ set(SRC_HEADERS util_xml.h ) +if(WITH_CYCLES_DEBUG) + list(APPEND SRC util_guarded_allocator.cpp) + list(APPEND SRC_HEADERS util_guarded_allocator.h) +endif() + include_directories(${INC}) include_directories(SYSTEM ${INC_SYS}) diff --git a/intern/cycles/util/util_aligned_malloc.cpp b/intern/cycles/util/util_aligned_malloc.cpp new file mode 100644 index 00000000000..51f21db2dc3 --- /dev/null +++ b/intern/cycles/util/util_aligned_malloc.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2011-2015 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util_aligned_malloc.h" + +#include <cassert> + +/* Adopted from Libmv. */ + +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) +/* Needed for memalign on Linux and _aligned_alloc on Windows. */ +# ifdef FREE_WINDOWS +/* Make sure _aligned_malloc is included. */ +# ifdef __MSVCRT_VERSION__ +# undef __MSVCRT_VERSION__ +# endif +# define __MSVCRT_VERSION__ 0x0700 +# endif /* FREE_WINDOWS */ +# include <malloc.h> +#else +/* Apple's malloc is 16-byte aligned, and does not have malloc.h, so include + * stdilb instead. + */ +# include <cstdlib> +#endif + +CCL_NAMESPACE_BEGIN + +void *util_aligned_malloc(int size, int alignment) +{ +#ifdef _WIN32 + return _aligned_malloc(size, alignment); +#elif defined(__APPLE__) + /* On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so + * they work natively with SSE types with no further work. + */ + assert(alignment == 16); + return malloc(size); +#elif defined(__FreeBSD__) || defined(__NetBSD__) + void *result; + if (posix_memalign(&result, alignment, size)) { + /* Non-zero means allocation error + * either no allocation or bad alignment value. + */ + return NULL; + } + return result; +#else /* This is for Linux. */ + return memalign(alignment, size); +#endif +} + +void util_aligned_free(void *ptr) +{ +#ifdef _WIN32 + _aligned_free(ptr); +#else + free(ptr); +#endif +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_aligned_malloc.h b/intern/cycles/util/util_aligned_malloc.h new file mode 100644 index 00000000000..28c240a20e7 --- /dev/null +++ b/intern/cycles/util/util_aligned_malloc.h @@ -0,0 +1,30 @@ +/* + * Copyright 2011-2015 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_ALIGNED_MALLOC_H__ +#define __UTIL_ALIGNED_MALLOC_H__ + +CCL_NAMESPACE_BEGIN + +/* Allocate block of size bytes at least aligned to a given value. */ +void *util_aligned_malloc(int size, int alignment); + +/* Free memory allocated by util_aligned_malloc. */ +void util_aligned_free(void *ptr); + +CCL_NAMESPACE_END + +#endif /* __UTIL_ALIGNED_MALLOC_H__ */ diff --git a/intern/cycles/util/util_guarded_allocator.cpp b/intern/cycles/util/util_guarded_allocator.cpp new file mode 100644 index 00000000000..8de6e254cbf --- /dev/null +++ b/intern/cycles/util/util_guarded_allocator.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2011-2015 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util_guarded_allocator.h" +#include "util_stats.h" + +CCL_NAMESPACE_BEGIN + +static Stats global_stats; + +/* Internal API. */ + +void util_guarded_mem_alloc(size_t n) +{ + global_stats.mem_alloc(n); +} + +void util_guarded_mem_free(size_t n) +{ + global_stats.mem_free(n); +} + +/* Public API. */ + +size_t util_guarded_get_mem_used(void) +{ + return global_stats.mem_used; +} + +size_t util_guarded_get_mem_peak(void) +{ + return global_stats.mem_peak; +} + + +CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_guarded_allocator.h b/intern/cycles/util/util_guarded_allocator.h new file mode 100644 index 00000000000..263199417c4 --- /dev/null +++ b/intern/cycles/util/util_guarded_allocator.h @@ -0,0 +1,85 @@ +/* + * Copyright 2011-2015 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_GUARDED_ALLOCATOR_H__ +#define __UTIL_GUARDED_ALLOCATOR_H__ + +/* Define this in order to use Blender's guarded allocator to keep + * track of allocated buffers, their sizes and peak memory usage. + * + * This is usually a bad level call, but it's really handy to keep + * track of overall peak memory consumption during the scene + * synchronization step. + */ +#undef WITH_BLENDER_GUARDEDALLOC + +#include <memory> + +#include "util_types.h" + +#ifdef WITH_BLENDER_GUARDEDALLOC +# include "../../guardedalloc/MEM_guardedalloc.h" +#endif + +CCL_NAMESPACE_BEGIN + +/* Internal use only. */ +void util_guarded_mem_alloc(size_t n); +void util_guarded_mem_free(size_t n); + +/* Guarded allocator for the use with STL. */ +template <typename T> +class GuardedAllocator: public std::allocator<T> { +public: + template<typename _Tp1> + struct rebind { + typedef GuardedAllocator<_Tp1> other; + }; + + T *allocate(size_t n, const void *hint = 0) + { + util_guarded_mem_alloc(n * sizeof(T)); +#ifdef WITH_BLENDER_GUARDEDALLOC + return (T*)MEM_mallocN(n * sizeof(T), "Cycles Alloc"); +#else + return std::allocator<T>::allocate(n, hint); +#endif + } + + void deallocate(T *p, size_t n) + { + util_guarded_mem_free(n * sizeof(T)); +#ifdef WITH_BLENDER_GUARDEDALLOC + MEM_freeN((void*)p); +#else + std::allocator<T>::deallocate(p, n); +#endif + } + + GuardedAllocator() : std::allocator<T>() { } + GuardedAllocator(const GuardedAllocator &a) : std::allocator<T>(a) { } + template <class U> + GuardedAllocator(const GuardedAllocator<U> &a) : std::allocator<T>(a) { } + ~GuardedAllocator() { } +}; + +/* Get memory usage and peak from the guarded STL allocator. */ +size_t util_guarded_get_mem_used(void); +size_t util_guarded_get_mem_peak(void); + +CCL_NAMESPACE_END + +#endif /* __UTIL_GUARDED_ALLOCATOR_H__ */ diff --git a/intern/cycles/util/util_sseb.h b/intern/cycles/util/util_sseb.h index 61892f4a71f..ea38e53b59f 100644 --- a/intern/cycles/util/util_sseb.h +++ b/intern/cycles/util/util_sseb.h @@ -153,6 +153,10 @@ __forceinline bool none ( const sseb& b ) { return _mm_movemask_ps(b) == 0x __forceinline size_t movemask( const sseb& a ) { return _mm_movemask_ps(a); } +//////////////////////////////////////////////////////////////////////////////// +/// Debug Functions +//////////////////////////////////////////////////////////////////////////////// + ccl_device_inline void print_sseb(const char *label, const sseb &a) { printf("%s: %df %df %df %d\n", diff --git a/intern/cycles/util/util_ssef.h b/intern/cycles/util/util_ssef.h index 80911cd7282..a9503d60979 100644 --- a/intern/cycles/util/util_ssef.h +++ b/intern/cycles/util/util_ssef.h @@ -580,6 +580,10 @@ ccl_device_inline const ssef set_sign_bit(const ssef &a) return a ^ cast(ssei(S1 << 31, S2 << 31, S3 << 31, S4 << 31)); } +//////////////////////////////////////////////////////////////////////////////// +/// Debug Functions +//////////////////////////////////////////////////////////////////////////////// + ccl_device_inline void print_ssef(const char *label, const ssef &a) { printf("%s: %.8f %.8f %.8f %.8f\n", diff --git a/intern/cycles/util/util_ssei.h b/intern/cycles/util/util_ssei.h index b2a71a8d396..ddd7a858941 100644 --- a/intern/cycles/util/util_ssei.h +++ b/intern/cycles/util/util_ssei.h @@ -286,6 +286,10 @@ __forceinline void store4i_nt(void* ptr, const ssei& v) { #endif } +//////////////////////////////////////////////////////////////////////////////// +/// Debug Functions +//////////////////////////////////////////////////////////////////////////////// + ccl_device_inline void print_ssei(const char *label, const ssei &a) { printf("%s: %df %df %df %d\n", diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h index 269fe04a4ae..92c3f116c69 100644 --- a/intern/cycles/util/util_vector.h +++ b/intern/cycles/util/util_vector.h @@ -22,31 +22,73 @@ #include <string.h> #include <vector> +#include "util_aligned_malloc.h" #include "util_types.h" -CCL_NAMESPACE_BEGIN +#ifdef WITH_CYCLES_DEBUG +# include "util_guarded_allocator.h" +#endif -using std::vector; +CCL_NAMESPACE_BEGIN -static inline void *malloc_aligned(size_t size, size_t alignment) +/* Vector + * + * Own subclass-ed vestion of std::vector. Subclass is needed because: + * + * - When building with WITH_CYCLES_DEBUG we need to use own allocator which + * keeps track of used/peak memory. + * + * - Have method to ensure capacity is re-set to 0. + */ +template<typename value_type> +class vector : public std::vector<value_type +#ifdef WITH_CYCLES_DEBUG + , GuardedAllocator<value_type> +#endif + > { - void *data = (void*)malloc(size + sizeof(void*) + alignment - 1); +public: +#ifdef WITH_CYCLES_DEBUG + typedef GuardedAllocator<value_type> allocator_type; +#else + typedef std::allocator<value_type> allocator_type; +#endif - union { void *ptr; size_t offset; } u; - u.ptr = (char*)data + sizeof(void*); - u.offset = (u.offset + alignment - 1) & ~(alignment - 1); - *(((void**)u.ptr) - 1) = data; + /* Default constructor. */ + explicit vector() : std::vector<value_type, allocator_type>() { } - return u.ptr; -} + /* Fill constructor. */ + explicit vector(size_t n, const value_type& val = value_type()) + : std::vector<value_type, allocator_type>(n, val) { } -static inline void free_aligned(void *ptr) -{ - if(ptr) { - void *data = *(((void**)ptr) - 1); - free(data); + /* Range constructor. */ + template <class InputIterator> + vector (InputIterator first, InputIterator last) + : std::vector<value_type, allocator_type>(first, last) { } + + /* Copy constructor. */ + vector(const vector &x) : std::vector<value_type, allocator_type>(x) { } + + void shrink_to_fit(void) + { +#if __cplusplus < 201103L + vector<value_type>().swap(*this); +#else + std::vector<value_type, allocator_type>::shrink_to_fit(); +#endif + } + + void free_memory(void) { + std::vector<value_type, allocator_type>::resize(0); + shrink_to_fit(); } -} + + /* Some external API might demand working with std::vector. */ + operator std::vector<value_type>() + { + return std::vector<value_type>(*this); + } +}; /* Array * @@ -74,7 +116,7 @@ public: datasize = 0; } else { - data = (T*)malloc_aligned(sizeof(T)*newsize, alignment); + data = (T*)util_aligned_malloc(sizeof(T)*newsize, alignment); datasize = newsize; } } @@ -91,7 +133,7 @@ public: datasize = 0; } else { - data = (T*)malloc_aligned(sizeof(T)*from.datasize, alignment); + data = (T*)util_aligned_malloc(sizeof(T)*from.datasize, alignment); memcpy(data, from.data, from.datasize*sizeof(T)); datasize = from.datasize; } @@ -105,7 +147,7 @@ public: data = NULL; if(datasize > 0) { - data = (T*)malloc_aligned(sizeof(T)*datasize, alignment); + data = (T*)util_aligned_malloc(sizeof(T)*datasize, alignment); memcpy(data, &from[0], datasize*sizeof(T)); } @@ -114,7 +156,7 @@ public: ~array() { - free_aligned(data); + util_aligned_free(data); } void resize(size_t newsize) @@ -123,10 +165,10 @@ public: clear(); } else if(newsize != datasize) { - T *newdata = (T*)malloc_aligned(sizeof(T)*newsize, alignment); + T *newdata = (T*)util_aligned_malloc(sizeof(T)*newsize, alignment); if(data) { memcpy(newdata, data, ((datasize < newsize)? datasize: newsize)*sizeof(T)); - free_aligned(data); + util_aligned_free(data); } data = newdata; @@ -136,7 +178,7 @@ public: void clear() { - free_aligned(data); + util_aligned_free(data); data = NULL; datasize = 0; } diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index f333bff4bf3..d3e1a866e43 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -41,8 +41,6 @@ class GRAPH_HT_header(Header): dopesheet_filter(layout, context) - layout.prop(st, "use_auto_view_selected", text="Auto View") - layout.prop(st, "use_normalization", text="Normalize") row = layout.row() row.active = st.use_normalization diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 47c8cc65247..9c6018965a7 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -57,6 +57,8 @@ class OUTLINER_HT_header(Header): else: row = layout.row() row.label(text="No Keying Set active") + elif space.display_mode == 'ORPHANED_DATABLOCKS': + layout.operator("outliner.orphans_purge") class OUTLINER_MT_editor_menus(Menu): diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index a9b10017472..a7164c00e53 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2218,7 +2218,8 @@ class VIEW3D_MT_edit_mesh_vertices(Menu): layout.operator("mesh.rip_edge_move") layout.operator("mesh.split") layout.operator_menu_enum("mesh.separate", "type") - layout.operator("mesh.vert_connect", text="Connect") + layout.operator("mesh.vert_connect_path", text="Connect Vertex Path") + layout.operator("mesh.vert_connect", text="Connect Vertices") layout.operator("transform.vert_slide", text="Slide") layout.separator() @@ -2943,30 +2944,6 @@ class VIEW3D_PT_view3d_shading(Panel): if obj and obj.mode == 'EDIT': col.prop(view, "show_occlude_wire") -<<<<<<< HEAD - fxoptions = view.fxoptions - - col.prop(view, "depth_of_field") - if view.depth_of_field: - if (view.region_3d.view_perspective == 'CAMERA'): - col.label("check dof properties in camera settings", icon='INFO') - else: - dof_options = fxoptions.dof_options - subcol = col.column(align=True) - subcol.prop(dof_options, "dof_focus_distance") - subcol.prop(dof_options, "dof_fstop") - subcol.prop(dof_options, "dof_focal_length") - subcol.prop(dof_options, "dof_sensor") - col.prop(view, "ssao") - if view.ssao: - ssao_options = fxoptions.ssao_options - subcol = col.column(align=True) - subcol.prop(ssao_options, "ssao_darkening") - subcol.prop(ssao_options, "ssao_distance_max") - subcol.prop(ssao_options, "ssao_attenuation") - subcol.prop(ssao_options, "ssao_ray_sample_mode") - subcol.prop(ssao_options, "ssao_color") -======= fx_settings = view.fx_settings sub = col.column() @@ -2982,7 +2959,6 @@ class VIEW3D_PT_view3d_shading(Panel): subcol.prop(ssao_settings, "attenuation") subcol.prop(ssao_settings, "samples") subcol.prop(ssao_settings, "color") ->>>>>>> master class VIEW3D_PT_view3d_motion_tracking(Panel): diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 573fa60f703..30ce656f46d 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -84,8 +84,9 @@ struct ColorManagedViewSettings; struct ColorManagedDisplaySettings; struct bNodeInstanceHash; - -/* ************** NODE TYPE DEFINITIONS ***** */ +/* -------------------------------------------------------------------- */ +/** \name Node Type Definitions + * \{ */ /** Compact definition of a node socket. * Can be used to quickly define a list of static sockets for a node, @@ -314,8 +315,11 @@ typedef struct bNodeTreeType { ExtensionRNA ext; } bNodeTreeType; +/** \} */ -/* ************** GENERIC API, TREES *************** */ +/* -------------------------------------------------------------------- */ +/** \name Generic API, Trees + * \{ */ struct bNodeTreeType *ntreeTypeFind(const char *idname); void ntreeTypeAdd(struct bNodeTreeType *nt); @@ -377,8 +381,12 @@ struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree); void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree); void ntreeLocalMerge(struct bNodeTree *localtree, struct bNodeTree *ntree); -/* ************** NODE TREE INTERFACE *************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Node Tree Interface + * \{ */ struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree, int in_out, const char *identifier); struct bNodeSocket *ntreeAddSocketInterface(struct bNodeTree *ntree, int in_out, const char *idname, const char *name); struct bNodeSocket *ntreeInsertSocketInterface(struct bNodeTree *ntree, int in_out, const char *idname, @@ -392,7 +400,12 @@ struct StructRNA *ntreeInterfaceTypeGet(struct bNodeTree *ntree, int create); void ntreeInterfaceTypeFree(struct bNodeTree *ntree); void ntreeInterfaceTypeUpdate(struct bNodeTree *ntree); -/* ************** GENERIC API, NODES *************** */ +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Generic API, Nodes + * \{ */ struct bNodeType *nodeTypeFind(const char *idname); void nodeRegisterType(struct bNodeType *ntype); @@ -558,8 +571,12 @@ void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree, struct b void BKE_node_preview_set_pixel(struct bNodePreview *preview, const float col[4], int x, int y, bool do_manage); +/** \} */ + -/* ************** NODE TYPE ACCESS *************** */ +/* -------------------------------------------------------------------- */ +/** \name Node Type Access + * \{ */ void nodeLabel(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); @@ -586,7 +603,11 @@ void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufu void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *)); void node_type_compatibility(struct bNodeType *ntype, short compatibility); -/* ************** GENERIC NODE FUNCTIONS *************** */ + +/* -------------------------------------------------------------------- */ +/** \name Node Generic Functions + * \{ */ + bool BKE_node_is_connected_to_output(struct bNodeTree *ntree, struct bNode *node); /* ************** COMMON NODES *************** */ @@ -603,7 +624,12 @@ bool BKE_node_is_connected_to_output(struct bNodeTree *ntree, struct bNode *node void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree); -/* Utility macro for visiting every node tree in the library data, including local bNodeTree blocks in other IDs. +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Node Tree Iterator + * + * Utility macro for visiting every node tree in the library data, including local bNodeTree blocks in other IDs. * This avoids the need for callback functions and allows executing code in a single inner code block. * * Variables: @@ -616,6 +642,7 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree); * * Examples: * + * \code{.c} * FOREACH_NODETREE(bmain, nodetree) { * if (id == nodetree) * printf("This is a linkable node tree"); @@ -627,6 +654,9 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree); * if (GS(id) == ID_MA) * printf(" and it's owned by a material"); * } FOREACH_NODETREE_END + * \endcode + * + * \{ */ /* should be an opaque type, only for internal use by BKE_node_tree_iter_*** */ @@ -658,9 +688,11 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, } \ } \ } +/** \} */ -/* ************** SHADER NODES *************** */ - +/* -------------------------------------------------------------------- */ +/** \name Shader Nodes + */ struct ShadeInput; struct ShadeResult; @@ -783,8 +815,11 @@ void set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInp void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat, short compatibility); +/** \} */ -/* ************** COMPOSITE NODES *************** */ +/* -------------------------------------------------------------------- */ +/** \name Composite Nodes + */ /* output socket defines */ #define RRES_OUT_IMAGE 0 @@ -964,7 +999,11 @@ void ntreeCompositOutputFileUniqueLayer(struct ListBase *list, struct bNodeSocke void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node); void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node); -/* ************** TEXTURE NODES *************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Texture Nodes + */ struct TexResult; @@ -1005,11 +1044,9 @@ void ntreeTexEndExecTree(struct bNodeTreeExec *exec); int ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target, float coord[3], float dxt[3], float dyt[3], int osatex, const short thread, struct Tex *tex, short which_output, int cfra, int preview, struct ShadeInput *shi, struct MTex *mtex); - - -/*************************************************/ +/** \} */ void init_nodesystem(void); void free_nodesystem(void); -#endif +#endif /* __BKE_NODE_H__ */ diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index f001f61541a..5923fc43448 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -437,7 +437,7 @@ float psys_get_dietime_from_cache(struct PointCache *cache, int index); void psys_free_pdd(struct ParticleSystem *psys); float *psys_cache_vgroup(struct DerivedMesh *dm, struct ParticleSystem *psys, int vgroup); -bool psys_get_texture(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleTexture *ptex, int event, float cfra); +void psys_get_texture(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleTexture *ptex, int event, float cfra); void psys_interpolate_face(struct MVert *mvert, struct MFace *mface, struct MTFace *tface, float (*orcodata)[3], float w[4], float vec[3], float nor[3], float utan[3], float vtan[3], float orco[3], float ornor[3]); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 8be5a3b5f37..3ffc05f33e6 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3089,7 +3089,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti CLAMP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1); CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist); } -bool psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTexture *ptex, int event, float cfra) +void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTexture *ptex, int event, float cfra) { Object *ob = sim->ob; Mesh *me = (Mesh *)ob->data; @@ -3099,7 +3099,6 @@ bool psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex int m; float value, rgba[4], co[3], texvec[3]; int setvars = 0; - bool has_texture = false; /* initialize ptex */ ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp = @@ -3175,8 +3174,6 @@ bool psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex SET_PARTICLE_TEXTURE(PAMAP_GRAVITY, ptex->gravity, mtex->gravityfac); SET_PARTICLE_TEXTURE(PAMAP_DAMP, ptex->damp, mtex->dampfac); SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac); - - has_texture = true; } } @@ -3189,8 +3186,6 @@ bool psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_GRAVITY, ptex->gravity); CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp); CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length); - - return has_texture; } /************************************************/ /* Particle State */ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index b22ac6aa042..4a17e20dbb9 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -522,25 +522,22 @@ static void initialize_particle_texture(ParticleSimulationData *sim, ParticleDat ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; ParticleTexture ptex; - bool has_texture = false; - has_texture = psys_get_texture(sim, pa, &ptex, PAMAP_INIT, 0.f); + psys_get_texture(sim, pa, &ptex, PAMAP_INIT, 0.f); - if (has_texture) { - switch (part->type) { - case PART_EMITTER: - if (ptex.exist < psys_frand(psys, p+125)) - pa->flag |= PARS_UNEXIST; - pa->time = part->sta + (part->end - part->sta)*ptex.time; - break; - case PART_HAIR: - if (ptex.exist < psys_frand(psys, p+125)) - pa->flag |= PARS_UNEXIST; - pa->time = 0.f; - break; - case PART_FLUID: - break; - } + switch (part->type) { + case PART_EMITTER: + if (ptex.exist < psys_frand(psys, p+125)) + pa->flag |= PARS_UNEXIST; + pa->time = part->sta + (part->end - part->sta)*ptex.time; + break; + case PART_HAIR: + if (ptex.exist < psys_frand(psys, p+125)) + pa->flag |= PARS_UNEXIST; + pa->time = 0.f; + break; + case PART_FLUID: + break; } } @@ -973,7 +970,6 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, ParticleSettings *part; ParticleTexture ptex; int p = pa - psys->particles; - part=psys->part; /* get precise emitter matrix if particle is born */ diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index 4be75344133..9159c9e9afc 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -323,15 +323,23 @@ void unlink_actuators(ListBase *lb) void free_actuator(bActuator *act) { - bSoundActuator *sa; - if (act->data) { switch (act->type) { - case ACT_SOUND: - sa = (bSoundActuator *) act->data; - if (sa->sound) - id_us_min((ID *) sa->sound); - break; + case ACT_ACTION: + case ACT_SHAPEACTION: + { + bActionActuator *aa = (bActionActuator *)act->data; + if (aa->act) + id_us_min((ID *)aa->act); + break; + } + case ACT_SOUND: + { + bSoundActuator *sa = (bSoundActuator *) act->data; + if (sa->sound) + id_us_min((ID *)sa->sound); + break; + } } MEM_freeN(act->data); @@ -351,7 +359,6 @@ void free_actuators(ListBase *lb) bActuator *copy_actuator(bActuator *act) { bActuator *actn; - bSoundActuator *sa; act->mynew=actn= MEM_dupallocN(act); actn->flag |= ACT_NEW; @@ -360,11 +367,21 @@ bActuator *copy_actuator(bActuator *act) } switch (act->type) { + case ACT_ACTION: + case ACT_SHAPEACTION: + { + bActionActuator *aa = (bActionActuator *)act->data; + if (aa->act) + id_us_plus((ID *)aa->act); + break; + } case ACT_SOUND: - sa= (bSoundActuator *)act->data; + { + bSoundActuator *sa = (bSoundActuator *)act->data; if (sa->sound) - id_us_plus((ID *) sa->sound); + id_us_plus((ID *)sa->sound); break; + } } return actn; } diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h index db33c5cec8b..c645ff06c00 100644 --- a/source/blender/blenlib/BLI_array.h +++ b/source/blender/blenlib/BLI_array.h @@ -34,9 +34,10 @@ */ /* -------------------------------------------------------------------- */ -/* internal defines */ +/** \name Internal defines + * \{ */ -/* this returns the entire size of the array, including any buffering. */ +/** this returns the entire size of the array, including any buffering. */ #define _bli_array_totalsize_dynamic(arr) ( \ ((arr) == NULL) ? \ 0 : \ @@ -53,7 +54,10 @@ _bli_array_totalsize_dynamic(arr)) \ ) -/* BLI_array.c +/** \} */ + + +/** BLI_array.c * * Doing the realloc in a macro isn't so simple, * so use a function the macros can use. @@ -64,23 +68,27 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, /* -------------------------------------------------------------------- */ -/* public defines */ -/* use sizeof(*(arr)) to ensure the array exists and is an array */ +/** \name Public defines + * \{ */ + +/** use ``sizeof(*(arr))`` to ensure the array exists and is an array */ #define BLI_array_declare(arr) \ int _##arr##_count = ((void)(sizeof(*(arr))), 0); \ void *_##arr##_static = NULL -/* this will use stack space, up to maxstatic array elements, before +/** + * this will use stack space, up to maxstatic array elements, before * switching to dynamic heap allocation */ #define BLI_array_staticdeclare(arr, maxstatic) \ int _##arr##_count = 0; \ char _##arr##_static[maxstatic * sizeof(*(arr))] -/* this returns the logical size of the array, not including buffering. */ +/** returns the logical size of the array, not including buffering. */ #define BLI_array_count(arr) ((void)0, _##arr##_count) -/* Grow the array by a fixed number of items. +/** + * Grow the array by a fixed number of items. * * Allow for a large 'num' value when the new size is more than double * to allocate the exact sized array. */ @@ -101,22 +109,21 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, ) -/* returns length of array */ - +/** returns length of array */ #define BLI_array_grow_items(arr, num) \ (BLI_array_reserve(arr, num), (_##arr##_count += num)) #define BLI_array_grow_one(arr) \ BLI_array_grow_items(arr, 1) - -/* appends an item to the array. */ +/** appends an item to the array. */ #define BLI_array_append(arr, item) ( \ (void) BLI_array_grow_one(arr), \ (void) (arr[_##arr##_count - 1] = item) \ ) -/* appends an item to the array and returns a pointer to the item in the array. +/** + * appends an item to the array and returns a pointer to the item in the array. * item is not a pointer, but actual data value.*/ #define BLI_array_append_r(arr, item) ( \ (void) BLI_array_grow_one(arr), \ @@ -124,7 +131,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, (&arr[_##arr##_count - 1]) \ ) -/* appends (grows) & returns a pointer to the uninitialized memory */ +/** appends (grows) & returns a pointer to the uninitialized memory */ #define BLI_array_append_ret(arr) \ (BLI_array_reserve(arr, 1), &arr[(_##arr##_count++)]) @@ -140,28 +147,37 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, NULL \ ) -/* resets the logical size of an array to zero, but doesn't +/** + * resets the logical size of an array to zero, but doesn't * free the memory. */ #define BLI_array_empty(arr) \ { _##arr##_count = 0; } (void)0 -/* set the count of the array, doesn't actually increase the allocated array +/** + * set the count of the array, doesn't actually increase the allocated array * size. don't use this unless you know what you're doing. */ #define BLI_array_count_set(arr, count) \ { _##arr##_count = (count); }(void)0 -/* only to prevent unused warnings */ +/** only to prevent unused warnings */ #define BLI_array_fake_user(arr) \ ((void)_##arr##_count, \ (void)_##arr##_static) +/** \} */ + /* -------------------------------------------------------------------- */ -/* other useful defines - * (unrelated to the main array macros) */ -/* not part of the 'API' but handy funcs, - * same purpose as BLI_array_staticdeclare() +/** \name Generic Array Utils + * other useful defines + * (unrelated to the main array macros) + * + * \{ */ + +/** + * not part of the 'API' but handy funcs, + * same purpose as #BLI_array_staticdeclare() * but use when the max size is known ahead of time */ #define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \ char _##arr##_static[maxstatic * sizeof(*(arr))]; \ @@ -176,17 +192,6 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, MEM_freeN(arr); \ } (void)0 - -void _bli_array_reverse(void *arr, unsigned int arr_len, size_t arr_stride); -#define BLI_array_reverse(arr, arr_len) \ - _bli_array_reverse(arr, arr_len, sizeof(*(arr))) - -void _bli_array_wrap(void *arr, unsigned int arr_len, size_t arr_stride, int dir); -#define BLI_array_wrap(arr, arr_len, dir) \ - _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir) - -int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p); -#define BLI_array_findindex(arr, arr_len, p) \ - _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p) +/** \} */ #endif /* __BLI_ARRAY_H__ */ diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h new file mode 100644 index 00000000000..0dd1439e58c --- /dev/null +++ b/source/blender/blenlib/BLI_array_utils.h @@ -0,0 +1,41 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_ARRAY_UTILS_H__ +#define __BLI_ARRAY_UTILS_H__ + +/** \file BLI_array_utils.h + * \ingroup bli + * \brief Generic array manipulation API. + */ + +void _bli_array_reverse(void *arr, unsigned int arr_len, size_t arr_stride); +#define BLI_array_reverse(arr, arr_len) \ + _bli_array_reverse(arr, arr_len, sizeof(*(arr))) + +void _bli_array_wrap(void *arr, unsigned int arr_len, size_t arr_stride, int dir); +#define BLI_array_wrap(arr, arr_len, dir) \ + _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir) + +int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p); +#define BLI_array_findindex(arr, arr_len, p) \ + _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p) + +#endif /* __BLI_ARRAY_UTILS_H__ */ diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h index 700abcad9bd..4e5b61da532 100644 --- a/source/blender/blenlib/BLI_buffer.h +++ b/source/blender/blenlib/BLI_buffer.h @@ -29,7 +29,7 @@ * declared in since. * * Usage examples: - * \code + * \code{.c} * BLI_buffer_declare_static(int, my_int_array, BLI_BUFFER_NOP, 32); * * BLI_buffer_append(my_int_array, int, 42); diff --git a/source/blender/blenlib/BLI_compiler_typecheck.h b/source/blender/blenlib/BLI_compiler_typecheck.h index 46c57772f64..652c4a954b9 100644 --- a/source/blender/blenlib/BLI_compiler_typecheck.h +++ b/source/blender/blenlib/BLI_compiler_typecheck.h @@ -81,12 +81,12 @@ * ``CHECK_TYPE_ANY(var, Foo *, Bar *, Baz *)`` * * excuse ridiculously long generated args. - * <pre> + * \code{.py} * for i in range(63): * args = [(chr(ord('a') + (c % 26)) + (chr(ord('0') + (c // 26)))) for c in range(i + 1)] * print("#define _VA_CHECK_TYPE_ANY%d(v, %s) \\" % (i + 2, ", ".join(args))) * print(" ((void)_Generic((v), %s))" % (": 0, ".join(args) + ": 0")) - * </pre> + * \endcode */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) diff --git a/source/blender/blenlib/BLI_dial.h b/source/blender/blenlib/BLI_dial.h index c8b57e803d2..ad7680fe03e 100644 --- a/source/blender/blenlib/BLI_dial.h +++ b/source/blender/blenlib/BLI_dial.h @@ -34,7 +34,8 @@ * current and previous directions of the digit, and returned to the user. * * Usage examples: - * \code + * + * \code{.c} * float start_position[2] = {0.0f, 0.0f}; * float current_position[2]; * float threshold = 0.5f; @@ -46,7 +47,6 @@ * angle = BLI_dial_angle(dial, curent_position); * * MEM_freeN(dial); - * * \endcode */ diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 495aa6b2465..f9cce27b1cb 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -104,6 +104,10 @@ float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float dist_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]); float dist_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3]); float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]); +float dist_signed_squared_to_corner_v3v3v3( + const float p[3], + const float v1[3], const float v2[3], const float v3[3], + const float axis_fallback[3]); float closest_to_line_v3(float r[3], const float p[3], const float l1[3], const float l2[3]); float closest_to_line_v2(float r[2], const float p[2], const float l1[2], const float l2[2]); void closest_to_line_segment_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]); diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index c91bedc6578..079352fc061 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -541,14 +541,13 @@ extern "C" { /** * UNUSED_VARS#(a, ...): quiet unused warnings * - * <pre> + * \code{.py} * for i in range(16): * args = [(chr(ord('a') + (c % 26)) + (chr(ord('0') + (c // 26)))) for c in range(i + 1)] * print("#define _VA_UNUSED_VARS_%d(%s) \\" % (i + 1, ", ".join(args))) * print("\t((void)(%s)%s)" % * (args[0], ((", _VA_UNUSED_VARS_" + str(i) + "(%s)") if i else "%s") % ", ".join((args[1:])))) - * </pre> - * + * \endcode */ #define _VA_UNUSED_VARS_1(a0) \ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index fa08856517a..e614a2a0663 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -52,6 +52,7 @@ set(SRC intern/BLI_memarena.c intern/BLI_mempool.c intern/DLRB_tree.c + intern/array_utils.c intern/astar.c intern/boxpack2d.c intern/buffer.c @@ -114,6 +115,7 @@ set(SRC BLI_alloca.h BLI_args.h BLI_array.h + BLI_array_utils.h BLI_astar.h BLI_bitmap.h BLI_blenlib.h diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c index da2eef8ab6a..01550ad1008 100644 --- a/source/blender/blenlib/intern/BLI_array.c +++ b/source/blender/blenlib/intern/BLI_array.c @@ -43,6 +43,7 @@ * * little array macro library. example of usage: * + * \code{.c} * int *arr = NULL; * BLI_array_declare(arr); * int i; @@ -52,6 +53,7 @@ * arr[i] = something; * } * BLI_array_free(arr); + * \endcode * * arrays are buffered, using double-buffering (so on each reallocation, * the array size is doubled). supposedly this should give good Big Oh @@ -59,13 +61,10 @@ */ #include <string.h> -#include <stdlib.h> #include "BLI_array.h" #include "BLI_sys_types.h" -#include "BLI_utildefines.h" -#include "BLI_alloca.h" #include "MEM_guardedalloc.h" @@ -100,55 +99,3 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, arr_count += num; #endif } - -void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride) -{ - const unsigned int arr_half_stride = (arr_len / 2) * arr_stride; - unsigned int i, i_end; - char *arr = arr_v; - char *buf = BLI_array_alloca(buf, arr_stride); - - for (i = 0, i_end = (arr_len - 1) * arr_stride; - i < arr_half_stride; - i += arr_stride, i_end -= arr_stride) - { - memcpy(buf, &arr[i], arr_stride); - memcpy(&arr[i], &arr[i_end], arr_stride); - memcpy(&arr[i_end], buf, arr_stride); - } -} - -void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int dir) -{ - char *arr = arr_v; - char *buf = BLI_array_alloca(buf, arr_stride); - - if (dir == -1) { - memcpy(buf, arr, arr_stride); - memmove(arr, arr + arr_stride, arr_stride * (arr_len - 1)); - memcpy(arr + (arr_stride * (arr_len - 1)), buf, arr_stride); - } - else if (dir == 1) { - memcpy(buf, arr + (arr_stride * (arr_len - 1)), arr_stride); - memmove(arr + arr_stride, arr, arr_stride * (arr_len - 1)); - memcpy(arr, buf, arr_stride); - } - else { - BLI_assert(0); - } -} - -/** - * \note Not efficient, use for error checks/asserts. - */ -int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) -{ - const char *arr_step = (const char *)arr; - unsigned int i; - for (i = 0; i < arr_len; i++, arr_step += arr_stride) { - if (memcmp(arr_step, p, arr_stride) == 0) { - return (int)i; - } - } - return -1; -} diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c new file mode 100644 index 00000000000..173effbc434 --- /dev/null +++ b/source/blender/blenlib/intern/array_utils.c @@ -0,0 +1,85 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/array_utils.c + * \ingroup bli + * \brief Generic array manipulation API. + */ +#include <string.h> +#include <stdlib.h> + +#include "BLI_array_utils.h" + +#include "BLI_sys_types.h" +#include "BLI_utildefines.h" +#include "BLI_alloca.h" + + +void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride) +{ + const unsigned int arr_half_stride = (arr_len / 2) * arr_stride; + unsigned int i, i_end; + char *arr = arr_v; + char *buf = BLI_array_alloca(buf, arr_stride); + + for (i = 0, i_end = (arr_len - 1) * arr_stride; + i < arr_half_stride; + i += arr_stride, i_end -= arr_stride) + { + memcpy(buf, &arr[i], arr_stride); + memcpy(&arr[i], &arr[i_end], arr_stride); + memcpy(&arr[i_end], buf, arr_stride); + } +} + +void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int dir) +{ + char *arr = arr_v; + char *buf = BLI_array_alloca(buf, arr_stride); + + if (dir == -1) { + memcpy(buf, arr, arr_stride); + memmove(arr, arr + arr_stride, arr_stride * (arr_len - 1)); + memcpy(arr + (arr_stride * (arr_len - 1)), buf, arr_stride); + } + else if (dir == 1) { + memcpy(buf, arr + (arr_stride * (arr_len - 1)), arr_stride); + memmove(arr + arr_stride, arr, arr_stride * (arr_len - 1)); + memcpy(arr, buf, arr_stride); + } + else { + BLI_assert(0); + } +} + +/** + * \note Not efficient, use for error checks/asserts. + */ +int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) +{ + const char *arr_step = (const char *)arr; + unsigned int i; + for (i = 0; i < arr_len; i++, arr_step += arr_stride) { + if (memcmp(arr_step, p, arr_stride) == 0) { + return (int)i; + } + } + return -1; +} diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 05a527c4f7a..92fa52afb80 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -477,6 +477,63 @@ float dist_to_line_v3(const float v1[3], const float l1[3], const float l2[3]) return sqrtf(dist_squared_to_line_v3(v1, l1, l2)); } +/** + * Check if \a p is inside the 2x planes defined by ``(v1, v2, v3)`` + * where the 3x points define 2x planes. + * + * \param axis_fallback used when v1,v2,v3 form a line. + * + * \note the distance from \a v1 & \a v3 to \a v2 doesnt matter + * (it just defines the planes). + * + * \return the lowest squared distance to eithe of the planes. + * where ``(return < 0.0)`` is outside. + * + * <pre> + * v1 + * + + * / + * x - out / x - inside + * / + * +----+ + * v2 v3 + * x - also outside + * </pre> + */ +float dist_signed_squared_to_corner_v3v3v3( + const float p[3], + const float v1[3], const float v2[3], const float v3[3], + const float axis_fallback[3]) +{ + float dir_a[3], dir_b[3]; + float plane_a[4], plane_b[4]; + float axis[3]; + + sub_v3_v3v3(dir_a, v1, v2); + sub_v3_v3v3(dir_b, v3, v2); + + cross_v3_v3v3(axis, dir_a, dir_b); + + if ((len_squared_v3(axis) < FLT_EPSILON) && axis_fallback) { + copy_v3_v3(axis, axis_fallback); + } + + cross_v3_v3v3(plane_a, axis, dir_a); + cross_v3_v3v3(plane_b, dir_b, axis); + +#if 0 + plane_from_point_normal_v3(plane_a, center, l1); + plane_from_point_normal_v3(plane_b, center, l2); +#else + /* do inline */ + plane_a[3] = -dot_v3v3(plane_a, v2); + plane_b[3] = -dot_v3v3(plane_b, v2); +#endif + + return min_ff(dist_signed_squared_to_plane_v3(p, plane_a), + dist_signed_squared_to_plane_v3(p, plane_b)); +} + /* Adapted from "Real-Time Collision Detection" by Christer Ericson, * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. * diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 38a15ab0a6d..05b6d6daf27 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -219,7 +219,6 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname) DIR *dir; if ((dir = opendir(dirname)) != NULL) { - const struct dirent *fname; while ((fname = readdir(dir)) != NULL) { struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink)); @@ -231,20 +230,19 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname) } if (newnum) { - if (dir_ctx->files) { - void * const tmp = realloc(dir_ctx->files, (dir_ctx->nrfiles + newnum) * sizeof(struct direntry)); + void * const tmp = MEM_reallocN(dir_ctx->files, (dir_ctx->nrfiles + newnum) * sizeof(struct direntry)); if (tmp) { dir_ctx->files = (struct direntry *)tmp; } else { /* realloc fail */ - free(dir_ctx->files); + MEM_freeN(dir_ctx->files); dir_ctx->files = NULL; } } if (dir_ctx->files == NULL) - dir_ctx->files = (struct direntry *)malloc(newnum * sizeof(struct direntry)); + dir_ctx->files = (struct direntry *)MEM_mallocN(newnum * sizeof(struct direntry), __func__); if (dir_ctx->files) { struct dirlink * dlink = (struct dirlink *) dirbase.first; @@ -405,7 +403,7 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **f else { // keep blender happy. Blender stores this in a variable // where 0 has special meaning..... - *filelist = malloc(sizeof(struct direntry)); + *filelist = MEM_mallocN(sizeof(**filelist), __func__); } return dir_ctx.nrfiles; @@ -422,7 +420,7 @@ void BLI_filelist_duplicate( { unsigned int i; - *dest_filelist = malloc(sizeof(**dest_filelist) * (size_t)(nrentries)); + *dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__); for (i = 0; i < nrentries; ++i) { struct direntry * const src = &src_filelist[i]; struct direntry *dest = &(*dest_filelist)[i]; @@ -461,7 +459,7 @@ void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void ( free_poin(entry->poin); } - free(filelist); + MEM_freeN(filelist); } diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 7a6107a974a..419d8c0f137 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -37,7 +37,6 @@ extern "C" { #endif struct bScreen; -struct direntry; struct LinkNode; struct Main; struct MemFile; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 85df6793cb8..3c5a2dd8bf5 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4521,11 +4521,11 @@ static void lib_link_object(FileData *fd, Main *main) } else if (act->type == ACT_ACTION) { bActionActuator *aa = act->data; - aa->act= newlibadr(fd, ob->id.lib, aa->act); + aa->act= newlibadr_us(fd, ob->id.lib, aa->act); } else if (act->type == ACT_SHAPEACTION) { bActionActuator *aa = act->data; - aa->act= newlibadr(fd, ob->id.lib, aa->act); + aa->act= newlibadr_us(fd, ob->id.lib, aa->act); } else if (act->type == ACT_PROPERTY) { bPropertyActuator *pa = act->data; diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index a88f38caf78..d60c01bd0ff 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -925,12 +925,15 @@ struct LoopWalkCtx { /* reference for this contiguous fan */ const void *data_ref; int data_len; + + /* accumulate 'LoopGroupCD.weight' to make unit length */ + float weight_accum; + /* both arrays the size of the 'BM_vert_face_count(v)' * each contiguous fan gets a slide of these arrays */ void **data_array; + int *data_index_array; float *weight_array; - /* accumulate 'LoopGroupCD.weight' to make unit length */ - float weight_accum; }; /* Store vars to pass into 'CustomData_bmesh_interp' */ @@ -939,6 +942,8 @@ struct LoopGroupCD { void **data; /* weights (aligned with 'data') */ float *data_weights; + /* index-in-face */ + int *data_index; /* number of loops in the fan */ int data_len; }; @@ -948,6 +953,7 @@ static void bm_loop_walk_add(struct LoopWalkCtx *lwc, BMLoop *l) const float w = BM_loop_calc_face_angle(l); BM_elem_flag_enable(l, BM_ELEM_INTERNAL_TAG); lwc->data_array[lwc->data_len] = BM_ELEM_CD_GET_VOID_P(l, lwc->cd_layer_offset); + lwc->data_index_array[lwc->data_len] = BM_elem_index_get(l); lwc->weight_array[lwc->data_len] = w; lwc->weight_accum += w; @@ -1001,11 +1007,14 @@ LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_ loop_num = 0; BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { BM_elem_flag_disable(l, BM_ELEM_INTERNAL_TAG); + BM_elem_index_set(l, loop_num); /* set_dirty! */ loop_num++; } + bm->elem_index_dirty |= BM_LOOP; lwc.data_len = 0; lwc.data_array = BLI_memarena_alloc(lwc.arena, sizeof(void *) * loop_num); + lwc.data_index_array = BLI_memarena_alloc(lwc.arena, sizeof(int) * loop_num); lwc.weight_array = BLI_memarena_alloc(lwc.arena, sizeof(float) * loop_num); BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { @@ -1017,6 +1026,7 @@ LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_ /* assign len-last */ lf->data = &lwc.data_array[lwc.data_len]; + lf->data_index = &lwc.data_index_array[lwc.data_len]; lf->data_weights = &lwc.weight_array[lwc.data_len]; lwc.weight_accum = 0.0f; @@ -1040,12 +1050,48 @@ LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_ return groups; } -static void bm_vert_loop_groups_data_layer_merge__single(BMesh *bm, void *lf_p, void *data, int type) +static void bm_vert_loop_groups_data_layer_merge__single( + BMesh *bm, void *lf_p, void *data, int type) +{ + struct LoopGroupCD *lf = lf_p; + int i; + const float *data_weights; + + data_weights = lf->data_weights; + + CustomData_bmesh_interp(&bm->ldata, lf->data, data_weights, NULL, lf->data_len, data); + + for (i = 0; i < lf->data_len; i++) { + CustomData_copy_elements(type, data, lf->data[i], 1); + } +} + +static void bm_vert_loop_groups_data_layer_merge_weights__single( + BMesh *bm, void *lf_p, void *data, int type, const float *loop_weights) { struct LoopGroupCD *lf = lf_p; int i; + const float *data_weights; + + /* re-weight */ + float *temp_weights = BLI_array_alloca(temp_weights, lf->data_len); + float weight_accum = 0.0f; - CustomData_bmesh_interp(&bm->ldata, lf->data, lf->data_weights, NULL, lf->data_len, data); + for (i = 0; i < lf->data_len; i++) { + float w = loop_weights[lf->data_index[i]] * lf->data_weights[i]; + temp_weights[i] = w; + weight_accum += w; + } + + if (LIKELY(weight_accum != 0.0f)) { + mul_vn_fl(temp_weights, lf->data_len, 1.0f / weight_accum); + data_weights = temp_weights; + } + else { + data_weights = lf->data_weights; + } + + CustomData_bmesh_interp(&bm->ldata, lf->data, data_weights, NULL, lf->data_len, data); for (i = 0; i < lf->data_len; i++) { CustomData_copy_elements(type, data, lf->data[i], 1); @@ -1066,4 +1112,19 @@ void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, int layer } while ((groups = groups->next)); } +/** + * A version of #BM_vert_loop_groups_data_layer_merge + * that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator) + */ +void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm, LinkNode *groups, int layer_n, const float *loop_weights) +{ + int type = bm->ldata.layers[layer_n].type; + int size = CustomData_sizeof(type); + void *data = alloca(size); + + do { + bm_vert_loop_groups_data_layer_merge_weights__single(bm, groups->link, data, type, loop_weights); + } while ((groups = groups->next)); +} + /** \} */
\ No newline at end of file diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h index cd6d5e2731d..1c1c063b7ed 100644 --- a/source/blender/bmesh/intern/bmesh_interp.h +++ b/source/blender/bmesh/intern/bmesh_interp.h @@ -54,5 +54,6 @@ void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source, void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f); struct LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_n, struct MemArena *arena); void BM_vert_loop_groups_data_layer_merge(BMesh *bm, struct LinkNode *groups, int layer_n); +void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm, struct LinkNode *groups, int layer_n, const float *loop_weights); #endif /* __BMESH_INTERP_H__ */ diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 26b53a21709..064dbd7405b 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -45,7 +45,9 @@ #include "BLI_linklist_stack.h" #include "BLI_stackdefines.h" -#include "BLI_array.h" +#ifndef NDEBUG +# include "BLI_array_utils.h" +#endif #include "BLI_kdopbvh.h" diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 512784437d6..93ebbbcf620 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -883,7 +883,6 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) const int verts_len = bm->totvertsel; BMVert **verts; - verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__); { BMIter iter; @@ -954,7 +953,7 @@ void MESH_OT_vert_connect(wmOperatorType *ot) /* identifiers */ ot->name = "Vertex Connect"; ot->idname = "MESH_OT_vert_connect"; - ot->description = "Connect 2 vertices of a face by an edge, splitting the face in two"; + ot->description = "Connect selected vertices of faces, splitting the face"; /* api callbacks */ ot->exec = edbm_vert_connect_exec; @@ -964,6 +963,191 @@ void MESH_OT_vert_connect(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** + * check that endpoints are verts and only have a single selected edge connected. + */ +static bool bm_vert_is_select_history_open(BMesh *bm) +{ + BMEditSelection *ele_a = bm->selected.first; + BMEditSelection *ele_b = bm->selected.last; + if ((ele_a->htype == BM_VERT) && + (ele_b->htype == BM_VERT)) + { + if ((BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_a->ele, BM_ELEM_SELECT, true) == 1) && + (BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_b->ele, BM_ELEM_SELECT, true) == 1)) + { + return true; + } + } + + return false; +} + +static bool bm_vert_connect_pair(BMesh *bm, BMVert *v_a, BMVert *v_b) +{ + BMOperator bmop; + BMVert **verts; + const int totedge_orig = bm->totedge; + + BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, "connect_vert_pair"); + + verts = BMO_slot_buffer_alloc(&bmop, bmop.slots_in, "verts", 2); + verts[0] = v_a; + verts[1] = v_b; + + BM_vert_normal_update(verts[0]); + BM_vert_normal_update(verts[1]); + + BMO_op_exec(bm, &bmop); + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + BMO_op_finish(bm, &bmop); + return (bm->totedge != totedge_orig); +} + +static bool bm_vert_connect_select_history(BMesh *bm) +{ + /* Logic is as follows: + * + * - If there are any isolated/wire verts - connect as edges. + * - Otherwise connect faces. + * - If all edges have been created already, closed the loop. + */ + if (BLI_listbase_count_ex(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) { + BMEditSelection *ese; + int tot = 0; + bool changed = false; + bool has_wire = false; + // bool all_verts; + + /* ensure all verts have history */ + for (ese = bm->selected.first; ese; ese = ese->next, tot++) { + BMVert *v; + if (ese->htype != BM_VERT) { + break; + } + v = (BMVert *)ese->ele; + if ((has_wire == false) && ((v->e == NULL) || BM_vert_is_wire(v))) { + has_wire = true; + } + } + // all_verts = (ese == NULL); + + if (has_wire == false) { + /* all verts have faces , connect verts via faces! */ + if (tot == bm->totvertsel) { + BMEditSelection *ese_last; + ese_last = bm->selected.first; + ese = ese_last->next; + + do { + + if (BM_edge_exists((BMVert *)ese_last->ele, (BMVert *)ese->ele)) { + /* pass, edge exists (and will be selected) */ + } + else { + changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele); + } + } while ((ese_last = ese), + (ese = ese->next)); + + if (changed) { + return true; + } + } + + if (changed == false) { + /* existing loops: close the selection */ + if (bm_vert_is_select_history_open(bm)) { + changed |= bm_vert_connect_pair( + bm, + (BMVert *)((BMEditSelection *)bm->selected.first)->ele, + (BMVert *)((BMEditSelection *)bm->selected.last)->ele); + + if (changed) { + return true; + } + } + } + } + + else { + /* no faces, simply connect the verts by edges */ + BMEditSelection *ese_prev; + ese_prev = bm->selected.first; + ese = ese_prev->next; + + + do { + if (BM_edge_exists((BMVert *)ese_prev->ele, (BMVert *)ese->ele)) { + /* pass, edge exists (and will be selected) */ + } + else { + BMEdge *e; + e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0); + BM_edge_select_set(bm, e, true); + changed = true; + } + } while ((ese_prev = ese), + (ese = ese->next)); + + if (changed == false) { + /* existing loops: close the selection */ + if (bm_vert_is_select_history_open(bm)) { + BMEdge *e; + ese_prev = bm->selected.first; + ese = bm->selected.last; + e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0); + BM_edge_select_set(bm, e, true); + } + } + + return true; + } + } + + return false; +} + + +static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bool is_pair = (em->bm->totvertsel == 2); + + /* when there is only 2 vertices, we can ignore selection order */ + if (is_pair) { + return edbm_vert_connect_exec(C, op); + } + + if (bm_vert_connect_select_history(em->bm)) { + EDBM_selectmode_flush(em); + EDBM_update_generic(em, true, true); + + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "Invalid selection order"); + return OPERATOR_CANCELLED; + } +} + +void MESH_OT_vert_connect_path(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Connect Path"; + ot->idname = "MESH_OT_vert_connect_path"; + ot->description = "Connect vertices by their selection order, creating edges, splitting faces"; + + /* api callbacks */ + ot->exec = edbm_vert_connect_path_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 8f5ecaed524..8611872a1a0 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -175,6 +175,7 @@ void MESH_OT_normals_make_consistent(struct wmOperatorType *ot); void MESH_OT_vertices_smooth(struct wmOperatorType *ot); void MESH_OT_vertices_smooth_laplacian(struct wmOperatorType *ot); void MESH_OT_vert_connect(struct wmOperatorType *ot); +void MESH_OT_vert_connect_path(struct wmOperatorType *ot); void MESH_OT_vert_connect_concave(struct wmOperatorType *ot); void MESH_OT_vert_connect_nonplanar(struct wmOperatorType *ot); void MESH_OT_edge_split(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 59d0de87de6..2855af063c0 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -163,6 +163,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_solidify); WM_operatortype_append(MESH_OT_select_nth); WM_operatortype_append(MESH_OT_vert_connect); + WM_operatortype_append(MESH_OT_vert_connect_path); WM_operatortype_append(MESH_OT_vert_connect_concave); WM_operatortype_append(MESH_OT_vert_connect_nonplanar); WM_operatortype_append(MESH_OT_knife_tool); @@ -401,7 +402,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "MESH_OT_vert_connect", JKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "MESH_OT_vert_connect_path", JKEY, KM_PRESS, 0, 0); /* Vertex Slide */ WM_keymap_add_item(keymap, "TRANSFORM_OT_vert_slide", VKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 9fe6ed73205..a00799c360d 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -287,8 +287,9 @@ static void file_draw_icon(uiBlock *block, char *path, int sx, int sy, int icon, but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, ""); - if (drag) + if (drag) { UI_but_drag_set_path(but, path); + } } @@ -324,70 +325,70 @@ void file_calc_previews(const bContext *C, ARegion *ar) static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, bool dropshadow, bool drag) { - if (imb) { - uiBut *but; - float fx, fy; - float dx, dy; - int xco, yco; - float scaledx, scaledy; - float scale; - int ex, ey; - - if ((imb->x * UI_DPI_FAC > layout->prv_w) || - (imb->y * UI_DPI_FAC > layout->prv_h)) - { - if (imb->x > imb->y) { - scaledx = (float)layout->prv_w; - scaledy = ( (float)imb->y / (float)imb->x) * layout->prv_w; - scale = scaledx / imb->x; - } - else { - scaledy = (float)layout->prv_h; - scaledx = ( (float)imb->x / (float)imb->y) * layout->prv_h; - scale = scaledy / imb->y; - } + uiBut *but; + float fx, fy; + float dx, dy; + int xco, yco; + float scaledx, scaledy; + float scale; + int ex, ey; + + BLI_assert(imb != NULL); + + if ((imb->x * UI_DPI_FAC > layout->prv_w) || + (imb->y * UI_DPI_FAC > layout->prv_h)) + { + if (imb->x > imb->y) { + scaledx = (float)layout->prv_w; + scaledy = ( (float)imb->y / (float)imb->x) * layout->prv_w; + scale = scaledx / imb->x; } else { - scaledx = (float)imb->x * UI_DPI_FAC; - scaledy = (float)imb->y * UI_DPI_FAC; - scale = UI_DPI_FAC; + scaledy = (float)layout->prv_h; + scaledx = ( (float)imb->x / (float)imb->y) * layout->prv_h; + scale = scaledy / imb->y; } + } + else { + scaledx = (float)imb->x * UI_DPI_FAC; + scaledy = (float)imb->y * UI_DPI_FAC; + scale = UI_DPI_FAC; + } - ex = (int)scaledx; - ey = (int)scaledy; - fx = ((float)layout->prv_w - (float)ex) / 2.0f; - fy = ((float)layout->prv_h - (float)ey) / 2.0f; - dx = (fx + 0.5f + layout->prv_border_x); - dy = (fy + 0.5f - layout->prv_border_y); - xco = sx + (int)dx; - yco = sy - layout->prv_h + (int)dy; - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - /* shadow */ - if (dropshadow) - UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + ex = (int)scaledx; + ey = (int)scaledy; + fx = ((float)layout->prv_w - (float)ex) / 2.0f; + fy = ((float)layout->prv_h - (float)ey) / 2.0f; + dx = (fx + 0.5f + layout->prv_border_x); + dy = (fy + 0.5f - layout->prv_border_y); + xco = sx + (int)dx; + yco = sy - layout->prv_h + (int)dy; - glEnable(GL_BLEND); - - /* the image */ - glColor4f(1.0, 1.0, 1.0, 1.0); - glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale); - - /* border */ - if (dropshadow) { - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); - } - - /* dragregion */ - if (drag) { - but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, ""); - UI_but_drag_set_image(but, file->path, get_file_icon(file), imb, scale); - } - - glDisable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* shadow */ + if (dropshadow) + UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + + glEnable(GL_BLEND); + + /* the image */ + glColor4f(1.0, 1.0, 1.0, 1.0); + glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale); + + /* border */ + if (dropshadow) { + glColor4f(0.0f, 0.0f, 0.0f, 0.4f); + fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); } + + /* dragregion */ + if (drag) { + but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, ""); + UI_but_drag_set_image(but, file->path, get_file_icon(file), imb, scale); + } + + glDisable(GL_BLEND); } static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) @@ -519,7 +520,7 @@ void file_draw_list(const bContext *C, ARegion *ar) sy = (int)(v2d->tot.ymax - sy); file = filelist_file(files, i); - + UI_ThemeColor4(TH_TEXT); @@ -547,7 +548,7 @@ void file_draw_list(const bContext *C, ARegion *ar) imb = filelist_geticon(files, i); is_icon = 1; } - + file_draw_preview(block, file, sx, sy, imb, layout, !is_icon && (file->flags & FILE_TYPE_IMAGE), do_drag); } else { diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index ddf9545289e..6cc4446274a 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -179,16 +179,18 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) params->active_file = selected_idx; if (S_ISDIR(file->type)) { + const bool is_parent_dir = FILENAME_IS_PARENT(file->relname); + if (do_diropen == false) { params->file[0] = '\0'; retval = FILE_SELECT_DIR; } /* the path is too long and we are not going up! */ - else if (!FILENAME_IS_PARENT(file->relname) && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) { + else if (!is_parent_dir && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) { // XXX error("Path too long, cannot enter this directory"); } else { - if (FILENAME_IS_PARENT(file->relname)) { + if (is_parent_dir) { /* avoids /../../ */ BLI_parent_dir(params->dir); } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index f0180c3c841..66acd7d05e3 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -37,10 +37,10 @@ #include <string.h> #ifndef WIN32 -#include <unistd.h> +# include <unistd.h> #else -#include <io.h> -#include <direct.h> +# include <io.h> +# include <direct.h> #endif #include "MEM_guardedalloc.h" @@ -58,10 +58,10 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_icons.h" +#include "BKE_idcode.h" #include "BKE_main.h" #include "BKE_report.h" #include "BLO_readfile.h" -#include "BKE_idcode.h" #include "DNA_space_types.h" @@ -91,7 +91,7 @@ typedef struct FolderList { ListBase *folderlist_new(void) { - ListBase *p = MEM_callocN(sizeof(ListBase), "folderlist"); + ListBase *p = MEM_callocN(sizeof(*p), __func__); return p; } @@ -128,7 +128,7 @@ void folderlist_pushdir(ListBase *folderlist, const char *dir) } /* create next folder element */ - folder = (FolderList *)MEM_mallocN(sizeof(FolderList), "FolderList"); + folder = MEM_mallocN(sizeof(*folder), __func__); folder->foldername = BLI_strdup(dir); /* add it to the end of the list */ @@ -178,7 +178,7 @@ ListBase *folderlist_duplicate(ListBase *folderlist) { if (folderlist) { - ListBase *folderlistn = MEM_callocN(sizeof(ListBase), "copy folderlist"); + ListBase *folderlistn = MEM_callocN(sizeof(*folderlistn), __func__); FolderList *folder; BLI_duplicatelist(folderlistn, folderlist); @@ -286,25 +286,30 @@ static int compare_direntry_generic(const struct direntry *entry1, const struct /* type is equal to stat.st_mode */ if (compare_is_directory(entry1)) { - if (compare_is_directory(entry2) == 0) return (-1); + if (compare_is_directory(entry2) == 0) { + return -1; + } } - else { - if (compare_is_directory(entry2)) return (1); + else if (compare_is_directory(entry2)) { + return 1; } + if (S_ISREG(entry1->type)) { - if (S_ISREG(entry2->type) == 0) return (-1); + if (!S_ISREG(entry2->type)) { + return -1; + } } - else { - if (S_ISREG(entry2->type)) return (1); + else if (S_ISREG(entry2->type)) { + return 1; } - if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); - if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); + if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return -1; + if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return 1; /* make sure "." and ".." are always first */ - if (FILENAME_IS_CURRENT(entry1->relname)) return (-1); - if (FILENAME_IS_CURRENT(entry2->relname)) return (1); - if (FILENAME_IS_PARENT(entry1->relname)) return (-1); - if (FILENAME_IS_PARENT(entry2->relname)) return (1); + if (FILENAME_IS_CURRENT(entry1->relname)) return -1; + if (FILENAME_IS_CURRENT(entry2->relname)) return 1; + if (FILENAME_IS_PARENT(entry1->relname)) return -1; + if (FILENAME_IS_PARENT(entry2->relname)) return 1; return 0; } @@ -325,15 +330,15 @@ static int compare_date(const void *a1, const void *a2) { const struct direntry *entry1 = a1, *entry2 = a2; int ret; - + if ((ret = compare_direntry_generic(entry1, entry2))) { return ret; } if (entry1->s.st_mtime < entry2->s.st_mtime) return 1; if (entry1->s.st_mtime > entry2->s.st_mtime) return -1; - - else return BLI_natstrcmp(entry1->relname, entry2->relname); + + return BLI_natstrcmp(entry1->relname, entry2->relname); } static int compare_size(const void *a1, const void *a2) @@ -347,7 +352,8 @@ static int compare_size(const void *a1, const void *a2) if (entry1->s.st_size < entry2->s.st_size) return 1; if (entry1->s.st_size > entry2->s.st_size) return -1; - else return BLI_natstrcmp(entry1->relname, entry2->relname); + + return BLI_natstrcmp(entry1->relname, entry2->relname); } static int compare_extension(const void *a1, const void *a2) @@ -368,7 +374,7 @@ static int compare_extension(const void *a1, const void *a2) if (!sufix1) sufix1 = nil; if (!sufix2) sufix2 = nil; - return (BLI_strcasecmp(sufix1, sufix2)); + return BLI_strcasecmp(sufix1, sufix2); } bool filelist_need_sorting(struct FileList *filelist) @@ -521,7 +527,7 @@ void filelist_filter(FileList *filelist) } /* Note: maybe we could even accept filelist->fidx to be filelist->numfiles -len allocated? */ - filelist->fidx = (int *)MEM_mallocN(sizeof(*filelist->fidx) * (size_t)num_filtered, __func__); + filelist->fidx = MEM_mallocN(sizeof(*filelist->fidx) * (size_t)num_filtered, __func__); memcpy(filelist->fidx, fidx_tmp, sizeof(*filelist->fidx) * (size_t)num_filtered); filelist->numfiltered = num_filtered; @@ -677,7 +683,8 @@ ImBuf *filelist_geticon(struct FileList *filelist, const int index) FileList *filelist_new(short type) { - FileList *p = MEM_callocN(sizeof(FileList), "filelist"); + FileList *p = MEM_callocN(sizeof(*p), __func__); + switch (type) { case FILE_MAIN: p->readf = filelist_read_main; @@ -691,7 +698,6 @@ FileList *filelist_new(short type) p->readf = filelist_read_dir; p->filterf = is_filtered_file; break; - } return p; } @@ -890,9 +896,9 @@ static void filelist_setfiletypes(struct FileList *filelist) { struct direntry *file; int num; - + file = filelist->filelist; - + for (num = 0; num < filelist->numfiles; num++, file++) { file->type = file->s.st_mode; /* restore the mess below */ #ifndef __APPLE__ @@ -901,13 +907,14 @@ static void filelist_setfiletypes(struct FileList *filelist) continue; } #endif - file->flags = file_extension_type(filelist->dir, file->relname); - if (filelist->filter_data.filter_glob[0] && BLI_testextensie_glob(file->relname, filelist->filter_data.filter_glob)) { file->flags = FILE_TYPE_OPERATOR; } + else { + file->flags = file_extension_type(filelist->dir, file->relname); + } } } @@ -1047,7 +1054,7 @@ static int groupname_to_code(const char *group) { char buf[BLO_GROUP_MAX]; char *lslash; - + BLI_strncpy(buf, group, sizeof(buf)); lslash = (char *)BLI_last_slash(buf); if (lslash) @@ -1063,7 +1070,7 @@ static void filelist_from_library(struct FileList *filelist) int ok, i, nprevs, nnames, idcode; char filename[FILE_MAX]; char dir[FILE_MAX], group[BLO_GROUP_MAX]; - + /* name test */ ok = filelist_islibrary(filelist, dir, group); if (!ok) { @@ -1102,7 +1109,7 @@ static void filelist_from_library(struct FileList *filelist) } filelist->numfiles = nnames + 1; - filelist->filelist = malloc(filelist->numfiles * sizeof(*filelist->filelist)); + filelist->filelist = MEM_mallocN(filelist->numfiles * sizeof(*filelist->filelist), __func__); memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist)); filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT); @@ -1119,14 +1126,14 @@ static void filelist_from_library(struct FileList *filelist) filelist->filelist[i + 1].type |= S_IFDIR; } } - + if (previews && (nnames != nprevs)) { printf("filelist_from_library: error, found %d items, %d previews\n", nnames, nprevs); } else if (previews) { for (i = 0, l = previews; i < nnames; i++, l = l->next) { PreviewImage *img = l->link; - + if (img) { unsigned int w = img->w[ICON_SIZE_PREVIEW]; unsigned int h = img->h[ICON_SIZE_PREVIEW]; @@ -1144,7 +1151,9 @@ static void filelist_from_library(struct FileList *filelist) } BLI_linklist_free(names, free); - if (previews) BLI_linklist_free(previews, BKE_previewimg_freefunc); + if (previews) { + BLI_linklist_free(previews, BKE_previewimg_freefunc); + } BLI_strncpy(G.main->name, filename, sizeof(filename)); /* prevent G.main->name to change */ } @@ -1155,31 +1164,30 @@ static void filelist_from_main(struct FileList *filelist) struct direntry *files, *firstlib = NULL; ListBase *lb; int a, fake, idcode, ok, totlib, totbl; - + // filelist->type = FILE_MAIN; // XXXXX TODO: add modes to filebrowser if (filelist->dir[0] == '/') filelist->dir[0] = 0; - + if (filelist->dir[0]) { idcode = groupname_to_code(filelist->dir); if (idcode == 0) filelist->dir[0] = 0; } - + if (filelist->dir[0] == 0) { - /* make directories */ #ifdef WITH_FREESTYLE filelist->numfiles = 24; #else filelist->numfiles = 23; #endif - filelist->filelist = (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry)); - + filelist->filelist = MEM_mallocN(sizeof(*filelist->filelist) * filelist->numfiles, __func__); + for (a = 0; a < filelist->numfiles; a++) { memset(&(filelist->filelist[a]), 0, sizeof(struct direntry)); filelist->filelist[a].type |= S_IFDIR; } - + filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT); filelist->filelist[1].relname = BLI_strdup("Scene"); filelist->filelist[2].relname = BLI_strdup("Object"); @@ -1208,41 +1216,35 @@ static void filelist_from_main(struct FileList *filelist) #endif } else { - /* make files */ idcode = groupname_to_code(filelist->dir); - + lb = which_libbase(G.main, idcode); if (lb == NULL) return; - - id = lb->first; + filelist->numfiles = 0; - while (id) { + for (id = lb->first; id; id = id->next) { if (!filelist->filter_data.hide_dot || id->name[2] != '.') { filelist->numfiles++; } - - id = id->next; } - + /* XXXXX TODO: if databrowse F4 or append/link filelist->hide_parent has to be set */ if (!filelist->filter_data.hide_parent) filelist->numfiles += 1; - filelist->filelist = filelist->numfiles > 0 ? (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry)) : NULL; + filelist->filelist = filelist->numfiles > 0 ? MEM_mallocN(sizeof(*filelist->filelist) * filelist->numfiles, __func__) : NULL; files = filelist->filelist; - + if (!filelist->filter_data.hide_parent) { memset(&(filelist->filelist[0]), 0, sizeof(struct direntry)); filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT); filelist->filelist[0].type |= S_IFDIR; - + files++; } - - id = lb->first; + totlib = totbl = 0; - - while (id) { + for (id = lb->first; id; id = id->next) { ok = 1; if (ok) { if (!filelist->filter_data.hide_dot || id->name[2] != '.') { @@ -1251,7 +1253,7 @@ static void filelist_from_main(struct FileList *filelist) files->relname = BLI_strdup(id->name + 2); } else { - files->relname = MEM_mallocN(FILE_MAX + (MAX_ID_NAME - 2), "filename for lib"); + files->relname = MEM_mallocN(sizeof(*files->relname) * (FILE_MAX + (MAX_ID_NAME - 2)), __func__); BLI_snprintf(files->relname, FILE_MAX + (MAX_ID_NAME - 2) + 3, "%s | %s", id->lib->name, id->name + 2); } files->type |= S_IFREG; @@ -1275,20 +1277,18 @@ static void filelist_from_main(struct FileList *filelist) else if (id->lib) BLI_snprintf(files->extra, sizeof(files->extra), "L %d", id->us); else if (fake) BLI_snprintf(files->extra, sizeof(files->extra), "F %d", id->us); else BLI_snprintf(files->extra, sizeof(files->extra), " %d", id->us); - + if (id->lib) { if (totlib == 0) firstlib = files; totlib++; } - + files++; } totbl++; } - - id = id->next; } - + /* only qsort of library blocks */ if (totlib > 1) { qsort(firstlib, totlib, sizeof(struct direntry), compare_name); @@ -1362,13 +1362,15 @@ static void thumbnails_update(void *tjv) FileImage *limg = tj->loadimages.first; while (limg) { if (!limg->done && limg->img) { - tj->filelist->filelist[limg->index].image = limg->img; + tj->filelist->filelist[limg->index].image = IMB_dupImBuf(limg->img); /* update flag for movie files where thumbnail can't be created */ if (limg->flags & FILE_TYPE_MOVIE_ICON) { tj->filelist->filelist[limg->index].flags &= ~FILE_TYPE_MOVIE; tj->filelist->filelist[limg->index].flags |= FILE_TYPE_MOVIE_ICON; } limg->done = true; + IMB_freeImBuf(limg->img); + limg->img = NULL; } limg = limg->next; } @@ -1397,17 +1399,20 @@ void thumbnails_start(FileList *filelist, const bContext *C) wmJob *wm_job; ThumbnailJob *tj; int idx; - + /* prepare job data */ - tj = MEM_callocN(sizeof(ThumbnailJob), "thumbnails\n"); + tj = MEM_callocN(sizeof(*tj), __func__); tj->filelist = filelist; for (idx = 0; idx < filelist->numfiles; idx++) { + if (!filelist->filelist[idx].path) { + continue; + } if (!filelist->filelist[idx].image) { if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - FileImage *limg = MEM_callocN(sizeof(FileImage), "loadimage"); - BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX); + FileImage *limg = MEM_callocN(sizeof(*limg), __func__); + BLI_strncpy(limg->path, filelist->filelist[idx].path, sizeof(limg->path)); limg->index = idx; limg->flags = filelist->filelist[idx].flags; BLI_addtail(&tj->loadimages, limg); diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 46a39806ad7..78dbae7618b 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -66,15 +66,6 @@ /* ************************************************************************** */ /* KEYFRAMES STUFF */ -static void graphkeys_auto_view(bContext *C) -{ - const SpaceIpo *sipo = CTX_wm_space_graph(C); - - if (sipo && sipo->flag & SIPO_AUTO_VIEW_SELECTED) { - WM_operator_name_call(C, "GRAPH_OT_view_selected", WM_OP_INVOKE_DEFAULT, NULL); - } -} - /* ******************** Deselect All Operator ***************************** */ /* This operator works in one of three ways: * 1) (de)select all (AKEY) - test if select all or deselect all @@ -92,7 +83,7 @@ static void graphkeys_auto_view(bContext *C) * 2 = invert * - do_channels: whether to affect selection status of channels */ -static short deselect_graph_keys(bAnimContext *ac, short test, short sel, short do_channels) +static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short do_channels) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -151,8 +142,6 @@ static short deselect_graph_keys(bAnimContext *ac, short test, short sel, short /* Cleanup */ ANIM_animdata_freelist(&anim_data); - - return sel; } /* ------------------- */ @@ -161,7 +150,6 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op) { bAnimContext ac; bAnimListElem *ale_active = NULL; - short sel; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) @@ -175,9 +163,9 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op) /* 'standard' behavior - check if selected, then apply relevant selection */ if (RNA_boolean_get(op->ptr, "invert")) - sel = deselect_graph_keys(&ac, 0, SELECT_INVERT, true); + deselect_graph_keys(&ac, 0, SELECT_INVERT, true); else - sel = deselect_graph_keys(&ac, 1, SELECT_ADD, true); + deselect_graph_keys(&ac, 1, SELECT_ADD, true); /* restore active F-Curve... */ if (ale_active) { @@ -192,9 +180,6 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op) ale_active = NULL; } - if (sel != SELECT_SUBTRACT) - graphkeys_auto_view(C); - /* set notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -389,8 +374,6 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op) /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, mode, selectmode, incl_handles, NULL); - graphkeys_auto_view(C); - /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -478,8 +461,6 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) MEM_freeN((void *)data_lasso.mcords); - graphkeys_auto_view(C); - /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -510,14 +491,6 @@ void GRAPH_OT_select_lasso(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); } -static int graph_circle_select_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - if (event->type == EVT_MODAL_MAP && event->val == GESTURE_MODAL_NOP) - graphkeys_auto_view(C); - - return WM_gesture_circle_modal(C, op, event); -} - static int graph_circle_select_exec(bContext *C, wmOperator *op) { bAnimContext ac; @@ -579,7 +552,7 @@ void GRAPH_OT_select_circle(wmOperatorType *ot) ot->idname = "GRAPH_OT_select_circle"; ot->invoke = WM_gesture_circle_invoke; - ot->modal = graph_circle_select_modal; + ot->modal = WM_gesture_circle_modal; ot->exec = graph_circle_select_exec; ot->poll = graphop_visible_keyframes_poll; ot->cancel = WM_gesture_circle_cancel; @@ -752,8 +725,6 @@ static int graphkeys_columnselect_exec(bContext *C, wmOperator *op) else columnselect_graph_keys(&ac, mode); - graphkeys_auto_view(C); - /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -812,8 +783,6 @@ static int graphkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op)) /* Cleanup */ ANIM_animdata_freelist(&anim_data); - graphkeys_auto_view(C); - /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -838,13 +807,12 @@ void GRAPH_OT_select_linked(wmOperatorType *ot) /* ******************** Select More/Less Operators *********************** */ /* Common code to perform selection */ -static void select_moreless_graph_keys(bContext *C, bAnimContext *ac, short mode) +static void select_moreless_graph_keys(bAnimContext *ac, short mode) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; - const SpaceIpo *sipo = (SpaceIpo *)ac->sl; KeyframeEditData ked; KeyframeEditFunc build_cb; @@ -874,24 +842,6 @@ static void select_moreless_graph_keys(bContext *C, bAnimContext *ac, short mode /* free the selmap used here */ MEM_freeN(ked.data); ked.data = NULL; - - /* only do auto view if a bezier point is selected */ - if (sipo->flag & SIPO_AUTO_VIEW_SELECTED) { - const FCurve *fcu = (FCurve *)ale->key_data; - const BezTriple *bezt; - unsigned int i; - - /* only continue if F-Curve has keyframes */ - if (fcu->bezt == NULL) - continue; - - for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { - if (BEZSELECTED(bezt)) { - graphkeys_auto_view(C); - break; - } - } - } } /* Cleanup */ @@ -909,7 +859,7 @@ static int graphkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* perform select changes */ - select_moreless_graph_keys(C, &ac, SELMAP_MORE); + select_moreless_graph_keys(&ac, SELMAP_MORE); /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -943,7 +893,7 @@ static int graphkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* perform select changes */ - select_moreless_graph_keys(C, &ac, SELMAP_LESS); + select_moreless_graph_keys(&ac, SELMAP_LESS); /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -1058,8 +1008,6 @@ static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op) /* do the selecting now */ graphkeys_select_leftright(&ac, leftright, selectmode); - graphkeys_auto_view(C); - /* set notifier that keyframe selection (and channels too) have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 3aaa1165c19..9fd763dda0d 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -176,16 +176,20 @@ static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob { Main *bmain = CTX_data_main(C); Object *ob; + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (BKE_object_is_child_recursive(ob_parent, ob)) { - if (state) { - ob->restrictflag |= flag; - if (deselect) { - ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT); + /* only do if child object is selectable */ + if ((flag == OB_RESTRICT_SELECT) || (ob->restrictflag & OB_RESTRICT_SELECT) == 0) { + if (state) { + ob->restrictflag |= flag; + if (deselect) { + ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT); + } + } + else { + ob->restrictflag &= ~flag; } - } - else { - ob->restrictflag &= ~flag; } if (rnapropname) { @@ -443,6 +447,20 @@ static void restrictbutton_gr_restrict_render(bContext *C, void *poin, void *poi WM_event_add_notifier(C, NC_GROUP, NULL); } +static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2)) +{ + ID *id = (ID *)poin; + + BLI_assert(id != NULL); + + if (id->flag & LIB_FAKEUSER) { + id_us_plus(id); + } + else { + id_us_min(id); + } +} + static void namebutton_cb(bContext *C, void *tsep, char *oldname) { @@ -788,6 +806,65 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar } } +static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops, ListBase *lb) +{ + uiBut *bt; + TreeElement *te; + TreeStoreElem *tselem; + + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { + if (tselem->type == 0) { + ID *id = tselem->id; + const char *tip = NULL; + int icon = ICON_NONE; + char buf[16] = ""; + int but_flag = UI_BUT_DRAG_LOCK; + + if (id->lib) + but_flag |= UI_BUT_DISABLED; + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + if (id->flag & LIB_FAKEUSER) { + icon = ICON_FILE_TICK; + tip = TIP_("Datablock will be retained using a fake user"); + } + else { + icon = ICON_X; + tip = TIP_("Datablock has no users and will be deleted"); + } + bt = uiDefIconButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, icon, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, + &id->flag, 0, 0, 0, 0, tip); + UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); + UI_but_flag_enable(bt, but_flag); + + + BLI_str_format_int_grouped(buf, id->us); + bt = uiDefBut(block, UI_BTYPE_BUT, 1, buf, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, + UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, + TIP_("Number of users of this datablock")); + UI_but_flag_enable(bt, but_flag); + + + bt = uiDefButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ", + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y, + &id->flag, 0, 0, 0, 0, + TIP_("Datablock has a 'fake' user which will keep it in the flie even if nothing else uses it")); + UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); + UI_but_flag_enable(bt, but_flag); + + UI_block_emboss_set(block, UI_EMBOSS); + } + } + + if (TSELEM_OPEN(tselem, soops)) outliner_draw_userbuts(block, ar, soops, &te->subtree); + } +} + static void outliner_draw_rnacols(ARegion *ar, int sizex) { View2D *v2d = &ar->v2d; @@ -1775,6 +1852,11 @@ void draw_outliner(const bContext *C) outliner_draw_rnacols(ar, sizex_rna); outliner_draw_rnabuts(block, scene, ar, soops, sizex_rna, &soops->tree); } + else if ((soops->outlinevis == SO_ID_ORPHANS) && !(soops->flag & SO_HIDE_RESTRICTCOLS)) { + /* draw user toggle columns */ + outliner_draw_restrictcols(ar); + outliner_draw_userbuts(block, ar, soops, &soops->tree); + } else if (!(soops->flag & SO_HIDE_RESTRICTCOLS)) { /* draw restriction columns */ outliner_draw_restrictcols(ar); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index d17ab33d0fa..020bd480954 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -1458,6 +1458,62 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/* ************************************************************** */ +/* ORPHANED DATABLOCKS */ + +static int ed_operator_outliner_id_orphans_active(bContext *C) +{ + ScrArea *sa = CTX_wm_area(C); + if ((sa) && (sa->spacetype == SPACE_OUTLINER)) { + SpaceOops *so = CTX_wm_space_outliner(C); + return (so->outlinevis == SO_ID_ORPHANS); + } + return 0; +} + +/* Purge Orphans Operator --------------------------------------- */ + +static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt)) +{ + /* present a prompt to informing users that this change is irreversible */ + return WM_operator_confirm_message(C, op, + "Purging unused datablocks cannot be undone. " + "Click here to proceed..."); +} + +static int outliner_orphans_purge_exec(bContext *C, wmOperator *UNUSED(op)) +{ + /* Firstly, ensure that the file has been saved, + * so that the latest changes since the last save + * are retained... + */ + WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, NULL); + + /* Now, reload the file to get rid of the orphans... */ + WM_operator_name_call(C, "WM_OT_revert_mainfile", WM_OP_EXEC_DEFAULT, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_orphans_purge(wmOperatorType *ot) +{ + /* identifiers */ + ot->idname = "OUTLINER_OT_orphans_purge"; + ot->name = "Purge All"; + ot->description = "Clears all orphaned datablocks without any users from the file (cannot be undone)"; + + /* callbacks */ + ot->invoke = outliner_orphans_purge_invoke; + ot->exec = outliner_orphans_purge_exec; + ot->poll = ed_operator_outliner_id_orphans_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ************************************************************** */ +/* DRAG AND DROP OPERATORS */ + /* ******************** Parent Drop Operator *********************** */ static int parent_drop_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index aa2a8896b17..50fecebb742 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -235,6 +235,8 @@ void OUTLINER_OT_keyingset_remove_selected(struct wmOperatorType *ot); void OUTLINER_OT_drivers_add_selected(struct wmOperatorType *ot); void OUTLINER_OT_drivers_delete_selected(struct wmOperatorType *ot); +void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot); + void OUTLINER_OT_parent_drop(struct wmOperatorType *ot); void OUTLINER_OT_parent_clear(struct wmOperatorType *ot); void OUTLINER_OT_scene_drop(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index fbfaf26104e..f5869575cc6 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -74,6 +74,8 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_drivers_add_selected); WM_operatortype_append(OUTLINER_OT_drivers_delete_selected); + + WM_operatortype_append(OUTLINER_OT_orphans_purge); WM_operatortype_append(OUTLINER_OT_parent_drop); WM_operatortype_append(OUTLINER_OT_parent_clear); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index b493e2eb0a6..42fefd16090 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -1597,6 +1597,9 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) { /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/ } + else if (datalevel == TSE_ID_BASE) { + /* do nothing... there are no ops needed here yet */ + } else if (datalevel == TSE_CONSTRAINT) { WM_operator_name_call(C, "OUTLINER_OT_constraint_operation", WM_OP_INVOKE_REGION_WIN, NULL); } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index c956d77d64a..7aac6a7797c 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1227,6 +1227,84 @@ static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *t } } + +/* ----------------------------------------------- */ + + +static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib) +{ + TreeElement *ten; + ListBase *lbarray[MAX_LIBARRAY]; + int a, tot; + + tot = set_listbasepointers(mainvar, lbarray); + for (a = 0; a < tot; a++) { + if (lbarray[a]->first) { + ID *id = lbarray[a]->first; + + /* check if there's data in current lib */ + for (; id; id = id->next) + if (id->lib == lib) + break; + + if (id) { + ten = outliner_add_element(soops, &te->subtree, (void *)lbarray[a], NULL, TSE_ID_BASE, 0); + ten->directdata = lbarray[a]; + + ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name)); + if (ten->name == NULL) + ten->name = "UNKNOWN"; + + for (id = lbarray[a]->first; id; id = id->next) { + if (id->lib == lib) + outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); + } + } + } + } + +} + +static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) +{ + TreeElement *ten; + ListBase *lbarray[MAX_LIBARRAY]; + int a, tot; + + tot = set_listbasepointers(mainvar, lbarray); + for (a = 0; a < tot; a++) { + if (lbarray[a]->first) { + ID *id = lbarray[a]->first; + + /* check if there are any datablocks of this type which are orphans */ + for (; id; id = id->next) { + if (ID_REAL_USERS(id) <= 0) + break; + } + + if (id) { + /* header for this type of datablock */ + /* TODO's: + * - Add a parameter to BKE_idcode_to_name_plural to get a sane "user-visible" name instead? + * - Ensure that this uses nice icons for the datablock type involved instead of the dot? + */ + ten = outliner_add_element(soops, &soops->tree, (void *)lbarray[a], NULL, TSE_ID_BASE, 0); + ten->directdata = lbarray[a]; + + ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name)); + if (ten->name == NULL) + ten->name = "UNKNOWN"; + + /* add the orphaned datablocks - these will not be added with any subtrees attached */ + for (id = lbarray[a]->first; id; id = id->next) { + if (ID_REAL_USERS(id) <= 0) + outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); + } + } + } + } +} + /* ======================================================= */ /* Generic Tree Building helpers - order these are called is top to bottom */ @@ -1474,42 +1552,6 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb) return (BLI_listbase_is_empty(lb) == false); } -static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib) -{ - TreeElement *ten; - ListBase *lbarray[MAX_LIBARRAY]; - int a, tot; - - tot = set_listbasepointers(mainvar, lbarray); - for (a = 0; a < tot; a++) { - if (lbarray[a]->first) { - ID *id = lbarray[a]->first; - - /* check if there's data in current lib */ - for (; id; id = id->next) - if (id->lib == lib) - break; - - if (id) { - - ten = outliner_add_element(soops, &te->subtree, (void *)lbarray[a], NULL, TSE_ID_BASE, 0); - ten->directdata = lbarray[a]; - - ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name)); - if (ten->name == NULL) - ten->name = "UNKNOWN"; - - for (id = lbarray[a]->first; id; id = id->next) { - if (id->lib == lib) - outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); - } - } - } - } - -} - - /* ======================================================= */ /* Main Tree Building API */ @@ -1713,6 +1755,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) tselem->flag &= ~TSE_CLOSED; } } + else if (soops->outlinevis == SO_ID_ORPHANS) { + outliner_add_orphaned_datablocks(mainvar, soops); + } else { ten = outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0); if (ten) ten->directdata = BASACT; diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 1644efb2adf..13a15e19b7e 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -971,16 +971,40 @@ static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scop return scope; } -void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs, bool draw_overlay, bool draw_overdrop) +static void sequencer_display_size(Scene *scene, SpaceSeq *sseq, float r_viewrect[2]) +{ + float render_size, proxy_size; + + if (sseq->render_size == SEQ_PROXY_RENDER_SIZE_SCENE) { + render_size = (float)scene->r.size / 100.0f; + proxy_size = 1.0f; + } + else { + render_size = (float)sseq->render_size / 100.0f; + proxy_size = render_size; + } + + r_viewrect[0] = (render_size * (float)scene->r.xsch); + r_viewrect[1] = (render_size * (float)scene->r.ysch); + + /* rectx = viewrectx + 0.5f; */ /* UNUSED */ + /* recty = viewrecty + 0.5f; */ /* UNUSED */ + + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { + r_viewrect[0] *= scene->r.xasp / scene->r.yasp; + r_viewrect[0] /= proxy_size; + r_viewrect[1] /= proxy_size; + } +} + +void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs, bool draw_overlay, bool draw_backdrop) { struct Main *bmain = CTX_data_main(C); struct ImBuf *ibuf = NULL; struct ImBuf *scope = NULL; struct View2D *v2d = &ar->v2d; /* int rectx, recty; */ /* UNUSED */ - float viewrectx, viewrecty; - float render_size = 0.0; - float proxy_size = 100.0; + float viewrect[2]; float col[3]; GLuint texid; GLuint last_texid; @@ -1004,30 +1028,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq } } - render_size = sseq->render_size; - if (render_size == 0) { - render_size = scene->r.size; - } - else { - proxy_size = render_size; - } - if (render_size < 0) { - return; - } - - viewrectx = (render_size * (float)scene->r.xsch) / 100.0f; - viewrecty = (render_size * (float)scene->r.ysch) / 100.0f; - - /* rectx = viewrectx + 0.5f; */ /* UNUSED */ - /* recty = viewrecty + 0.5f; */ /* UNUSED */ - - if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { - viewrectx *= scene->r.xasp / scene->r.yasp; - viewrectx /= proxy_size / 100.0f; - viewrecty /= proxy_size / 100.0f; - } - - if ((!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) && !draw_overdrop) { + if ((!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) && !draw_backdrop) { UI_GetThemeColor3fv(TH_SEQ_PREVIEW, col); glClearColor(col[0], col[1], col[2], 0.0); glClear(GL_COLOR_BUFFER_BIT); @@ -1037,6 +1038,10 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq if (G.is_rendering) return; + if (sseq->render_size == SEQ_PROXY_RENDER_SIZE_NONE) { + return; + } + ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs); if (ibuf == NULL) @@ -1045,6 +1050,8 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq if (ibuf->rect == NULL && ibuf->rect_float == NULL) return; + sequencer_display_size(scene, sseq, viewrect); + if (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0) { SequencerScopes *scopes = &sseq->scopes; @@ -1091,8 +1098,8 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq /* future files may have new scopes we don't catch above */ if (scope) { scopes->reference_ibuf = ibuf; - viewrectx = scope->x; - viewrecty = scope->y; + viewrect[0] = scope->x; + viewrect[1] = scope->y; } else { scopes->reference_ibuf = NULL; @@ -1102,8 +1109,8 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq /* without this colors can flicker from previous opengl state */ glColor4ub(255, 255, 255, 255); - if (!draw_overdrop) { - UI_view2d_totRect_set(v2d, viewrectx + 0.5f, viewrecty + 0.5f); + if (!draw_backdrop) { + UI_view2d_totRect_set(v2d, viewrect[0] + 0.5f, viewrect[1] + 0.5f); UI_view2d_curRect_validate(v2d); /* setting up the view - actual drawing starts here */ @@ -1210,7 +1217,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, format, type, display_buffer); - if (draw_overdrop) { + if (draw_backdrop) { UI_view2d_view_restore(C); } glBegin(GL_QUADS); @@ -1235,7 +1242,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin); } } - else if (draw_overdrop) { + else if (draw_backdrop) { float imagex = (scene->r.size * scene->r.xsch) / 200.0f * sseq->overdrop_zoom; float imagey = (scene->r.size * scene->r.ysch) / 200.0f * sseq->overdrop_zoom; float xofs = BLI_rcti_size_x(&ar->winrct)/2.0f + sseq->overdrop_offset[0]; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index b4ea727d3f5..1518dddc9b0 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -3674,6 +3674,12 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) } } +static bool object_is_halo(Scene *scene, Object *ob) +{ + const Material *ma = give_current_material(ob, 1); + return (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene)); +} + static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, const char dt, const unsigned char ob_wire_col[4], const short dflag) { @@ -3683,8 +3689,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D Object *ob = base->object; #endif Mesh *me = ob->data; - Material *ma = give_current_material(ob, 1); - const bool hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene)); eWireDrawMode draw_wire = OBDRAW_WIRE_OFF; int /* totvert,*/ totedge, totface; DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); @@ -3720,7 +3724,9 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0) draw_bounding_volume(ob, ob->boundtype); } - else if (hasHaloMat || (totface == 0 && totedge == 0)) { + else if ((totface == 0 && totedge == 0) || + ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob))) + { glPointSize(1.5); dm->drawVerts(dm); glPointSize(1.0); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index c14812f8dea..c8f73999cce 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1922,7 +1922,7 @@ static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d) { View3DAfter *v3da, *next; - glDepthMask(0); + glDepthMask(GL_FALSE); v3d->transp = true; for (v3da = v3d->afterdraw_transp.first; v3da; v3da = next) { @@ -1942,17 +1942,19 @@ static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d) } v3d->transp = false; - glDepthMask(1); + glDepthMask(GL_TRUE); } /* clears zbuffer and draws it over */ -static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, const bool clear) +static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear) { View3DAfter *v3da, *next; - if (clear && v3d->zbuf) + if (*clear && v3d->zbuf) { glClear(GL_DEPTH_BUFFER_BIT); + *clear = false; + } v3d->xray = true; for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) { @@ -1977,6 +1979,8 @@ static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const v3d->xray = true; v3d->transp = true; + glDepthMask(GL_FALSE); + for (v3da = v3d->afterdraw_xraytransp.first; v3da; v3da = next) { next = v3da->next; if (v3da->base->flag & OB_FROMDUPLI) { @@ -1995,6 +1999,7 @@ static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const v3d->transp = false; v3d->xray = false; + glDepthMask(GL_TRUE); } /* *********************** */ @@ -2702,6 +2707,7 @@ static void view3d_draw_objects( const bool is_wire_color = V3D_IS_WIRECOLOR(scene, v3d); const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO); const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0; + bool xrayclear = true; if (!draw_offscreen) { ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); @@ -2834,16 +2840,16 @@ static void view3d_draw_objects( if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } - /* transp and X-ray afterdraw stuff */ - if (v3d->afterdraw_transp.first) view3d_draw_transp(scene, ar, v3d); - if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, ar, v3d, true); - if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, true); - /* perspective floor goes last to use scene depth and avoid writing to depth buffer */ if (draw_grids && draw_floor) { drawfloor(scene, v3d, grid_unit); } + /* transp and X-ray afterdraw stuff */ + if (v3d->afterdraw_transp.first) view3d_draw_transp(scene, ar, v3d); + if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, ar, v3d, &xrayclear); + if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, xrayclear); + if (!draw_offscreen) { ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 843161a1a22..0c28a8ef35d 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -44,6 +44,7 @@ #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" /* PET modes */ +#include "BLI_alloca.h" #include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_rect.h" @@ -5303,9 +5304,12 @@ static void slide_origdata_create_data( sod->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + sod->origverts = BLI_ghash_ptr_new_ex(__func__, v_num); + for (i = 0; i < v_num; i++, sv = (void *)(((char *)sv) + v_stride)) { BMIter fiter; BMFace *f; + bool has_faces = false; /* copy face data */ BM_ITER_ELEM (f, &fiter, sv->v, BM_FACES_OF_VERT) { @@ -5313,14 +5317,78 @@ static void slide_origdata_create_data( BMFace *f_copy = BM_face_copy(sod->bm_origfaces, bm, f, true, true); BLI_ghash_insert(sod->origfaces, f, f_copy); } + has_faces = true; } /* store cd_loop_groups */ - sv->cd_loop_groups = BLI_memarena_alloc(sod->arena, layer_groups_array_size); - for (j = 0; j < layer_index_dst; j++) { - const int layer_nr = layer_math_map[j]; - sv->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create(bm, sv->v, layer_nr, sod->arena); + if (has_faces) { + sv->cd_loop_groups = BLI_memarena_alloc(sod->arena, layer_groups_array_size); + for (j = 0; j < layer_index_dst; j++) { + const int layer_nr = layer_math_map[j]; + sv->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create(bm, sv->v, layer_nr, sod->arena); + } } + else { + sv->cd_loop_groups = NULL; + } + + BLI_ghash_insert(sod->origverts, sv->v, sv); + } + } +} + +/** + * If we're sliding the vert, return its original location, if not, the current location is good. + */ +static const float *slide_origdata_orig_vert_co(SlideOrigData *sod, BMVert *v) +{ + TransDataGenericSlideVert *sv = BLI_ghash_lookup(sod->origverts, v); + return sv ? sv->co_orig_3d : v->co; +} + +static void slide_origdata_interp_data_vert( + SlideOrigData *sod, BMesh *bm, bool is_final, + TransDataGenericSlideVert *sv) +{ + BMIter liter; + BMLoop *l; + int j; + float *loop_weights; + const bool do_loop_weight = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON); + + // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) { + l = BM_iter_new(&liter, bm, BM_LOOPS_OF_VERT, sv->v); + loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, liter.count) : NULL; + for (j = 0 ; l; l = BM_iter_step(&liter), j++) { + BMFace *f_copy; /* the copy of 'f' */ + + f_copy = BLI_ghash_lookup(sod->origfaces, l->f); + + /* only loop data, no vertex data since that contains shape keys, + * and we do not want to mess up other shape keys */ + BM_loop_interp_from_face(bm, l, f_copy, false, is_final); + + /* make sure face-attributes are correct (e.g. MTexPoly) */ + BM_elem_attrs_copy(sod->bm_origfaces, bm, f_copy, l->f); + + /* weight the loop */ + if (do_loop_weight) { + const float *v_prev = slide_origdata_orig_vert_co(sod, l->prev->v); + const float *v_next = slide_origdata_orig_vert_co(sod, l->next->v); + const float dist = dist_signed_squared_to_corner_v3v3v3(sv->v->co, v_prev, sv->co_orig_3d, v_next, f_copy->no); + const float eps = 0.00001f; + loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps))); + } + } + + if (do_loop_weight) { + for (j = 0; j < sod->layer_math_map_num; j++) { + BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights); + } + } + else { + for (j = 0; j < sod->layer_math_map_num; j++) { + BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]); } } } @@ -5332,30 +5400,13 @@ static void slide_origdata_interp_data( { if (sod->use_origfaces) { BMEditMesh *em = BKE_editmesh_from_object(t->obedit); + BMesh *bm = em->bm; unsigned int i; - const int *layer_math_map = sod->layer_math_map; - for (i = 0; i < v_num; i++, sv = (void *)(((char *)sv) + v_stride)) { - BMIter fiter; - BMLoop *l; - int j; - - BM_ITER_ELEM (l, &fiter, sv->v, BM_LOOPS_OF_VERT) { - BMFace *f_copy; /* the copy of 'f' */ - - f_copy = BLI_ghash_lookup(sod->origfaces, l->f); - - /* only loop data, no vertex data since that contains shape keys, - * and we do not want to mess up other shape keys */ - BM_loop_interp_from_face(em->bm, l, f_copy, false, is_final); - /* make sure face-attributes are correct (e.g. MTexPoly) */ - BM_elem_attrs_copy(sod->bm_origfaces, em->bm, f_copy, l->f); - } - - for (j = 0; j < sod->layer_math_map_num; j++) { - BM_vert_loop_groups_data_layer_merge(em->bm, sv->cd_loop_groups[j], layer_math_map[j]); + if (sv->cd_loop_groups) { + slide_origdata_interp_data_vert(sod, bm, is_final, sv); } } } @@ -5375,6 +5426,11 @@ static void slide_origdata_free_date( sod->origfaces = NULL; } + if (sod->origverts) { + BLI_ghash_free(sod->origverts, NULL, NULL); + sod->origverts = NULL; + } + if (sod->arena) { BLI_memarena_free(sod->arena); sod->arena = NULL; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index e11aacef1ff..d65d1dee7cc 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -204,19 +204,20 @@ struct GHash; typedef struct TransDataGenericSlideVert { struct BMVert *v; struct LinkNode **cd_loop_groups; + float co_orig_3d[3]; } TransDataGenericSlideVert; typedef struct TransDataEdgeSlideVert { /* TransDataGenericSlideVert */ struct BMVert *v; struct LinkNode **cd_loop_groups; - /* end generic */ - - struct BMVert *v_a, *v_b; float v_co_orig[3]; + /* end generic */ float edge_len; + struct BMVert *v_a, *v_b; + /* add origvert.co to get the original locations */ float dir_a[3], dir_b[3]; @@ -228,6 +229,7 @@ typedef struct TransDataEdgeSlideVert { typedef struct SlideOrigData { /* flag that is set when origfaces is initialized */ bool use_origfaces; + struct GHash *origverts; /* map {BMVert: TransDataGenericSlideVert} */ struct GHash *origfaces; struct BMesh *bm_origfaces; @@ -261,9 +263,9 @@ typedef struct TransDataVertSlideVert { /* TransDataGenericSlideVert */ BMVert *v; struct LinkNode **cd_loop_groups; + float co_orig_3d[3]; /* end generic */ - float co_orig_3d[3]; float co_orig_2d[2]; float (*co_link_orig_3d)[3]; float (*co_link_orig_2d)[2]; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 499025e902d..5a64b6fed38 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -293,6 +293,7 @@ typedef enum eSpaceOutliner_Mode { SO_DATABLOCKS = 11, SO_USERDEF = 12, /* SO_KEYMAP = 13, */ /* deprecated! */ + SO_ID_ORPHANS = 14, } eSpaceOutliner_Mode; /* SpaceOops->storeflag */ @@ -371,8 +372,6 @@ typedef enum eGraphEdit_Flag { /* normalize curves on display */ SIPO_NORMALIZE = (1 << 14), SIPO_NORMALIZE_FREEZE = (1 << 15), - /* automatically set view on selection */ - SIPO_AUTO_VIEW_SELECTED = (1 << 16), } eGraphEdit_Flag; /* SpaceIpo->mode (Graph Editor Mode) */ @@ -496,7 +495,7 @@ typedef struct SpaceSeq { float xof DNA_DEPRECATED, yof DNA_DEPRECATED; /* deprecated: offset for drawing the image preview */ short mainb; /* weird name for the sequencer subtype (seq, image, luma... etc) */ - short render_size; + short render_size; /* eSpaceSeq_Proxy_RenderSize */ short chanshown; short zebra; int flag; diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 691a7432275..6f2c968764c 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -531,14 +531,6 @@ static void rna_Actuator_editobject_mesh_set(PointerRNA *ptr, PointerRNA value) eoa->me = value.data; } -static void rna_Actuator_action_action_set(PointerRNA *ptr, PointerRNA value) -{ - bActuator *act = (bActuator *)ptr->data; - bActionActuator *aa = (bActionActuator *) act->data; - - aa->act = value.data; -} - #else static void rna_def_actuator(BlenderRNA *brna) @@ -618,10 +610,8 @@ static void rna_def_action_actuator(BlenderRNA *brna) prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "act"); RNA_def_property_struct_type(prop, "Action"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Action", ""); - /* note: custom set function is ONLY to avoid rna setting a user for this. */ - RNA_def_property_pointer_funcs(prop, NULL, "rna_Actuator_action_action_set", NULL, NULL); RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "use_continue_last_frame", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 569b12590dc..c5c4dc50d0c 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1027,25 +1027,18 @@ static void rna_MeshLoopColorLayer_active_set(PointerRNA *ptr, int value) rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPCOL, 0); } -static void rna_MeshFloatPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) -{ - Mesh *me = rna_mesh(ptr); - CustomDataLayer *layer = (CustomDataLayer *)ptr->data; - rna_iterator_array_begin(iter, layer->data, sizeof(MFloatProperty), me->totpoly, 0, NULL); -} - -static int rna_MeshFloatPropertyLayer_data_length(PointerRNA *ptr) -{ - Mesh *me = rna_mesh(ptr); - return me->totpoly; -} - static int rna_float_layer_check(CollectionPropertyIterator *UNUSED(iter), void *data) { CustomDataLayer *layer = (CustomDataLayer *)data; return (layer->type != CD_PROP_FLT); } +static void rna_Mesh_vertex_float_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + CustomData *vdata = rna_mesh_vdata(ptr); + rna_iterator_array_begin(iter, (void *)vdata->layers, sizeof(CustomDataLayer), vdata->totlayer, 0, + rna_float_layer_check); +} static void rna_Mesh_polygon_float_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { CustomData *pdata = rna_mesh_pdata(ptr); @@ -1053,6 +1046,10 @@ static void rna_Mesh_polygon_float_layers_begin(CollectionPropertyIterator *iter rna_float_layer_check); } +static int rna_Mesh_vertex_float_layers_length(PointerRNA *ptr) +{ + return CustomData_number_of_layers(rna_mesh_vdata(ptr), CD_PROP_FLT); +} static int rna_Mesh_polygon_float_layers_length(PointerRNA *ptr) { return CustomData_number_of_layers(rna_mesh_pdata(ptr), CD_PROP_FLT); @@ -1064,19 +1061,12 @@ static int rna_int_layer_check(CollectionPropertyIterator *UNUSED(iter), void *d return (layer->type != CD_PROP_INT); } -static void rna_MeshIntPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) -{ - Mesh *me = rna_mesh(ptr); - CustomDataLayer *layer = (CustomDataLayer *)ptr->data; - rna_iterator_array_begin(iter, layer->data, sizeof(MIntProperty), me->totpoly, 0, NULL); -} - -static int rna_MeshIntPropertyLayer_data_length(PointerRNA *ptr) +static void rna_Mesh_vertex_int_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { - Mesh *me = rna_mesh(ptr); - return me->totpoly; + CustomData *vdata = rna_mesh_vdata(ptr); + rna_iterator_array_begin(iter, (void *)vdata->layers, sizeof(CustomDataLayer), vdata->totlayer, 0, + rna_int_layer_check); } - static void rna_Mesh_polygon_int_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { CustomData *pdata = rna_mesh_pdata(ptr); @@ -1084,6 +1074,10 @@ static void rna_Mesh_polygon_int_layers_begin(CollectionPropertyIterator *iter, rna_int_layer_check); } +static int rna_Mesh_vertex_int_layers_length(PointerRNA *ptr) +{ + return CustomData_number_of_layers(rna_mesh_vdata(ptr), CD_PROP_INT); +} static int rna_Mesh_polygon_int_layers_length(PointerRNA *ptr) { return CustomData_number_of_layers(rna_mesh_pdata(ptr), CD_PROP_INT); @@ -1095,19 +1089,12 @@ static int rna_string_layer_check(CollectionPropertyIterator *UNUSED(iter), void return (layer->type != CD_PROP_STR); } -static void rna_MeshStringPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) -{ - Mesh *me = rna_mesh(ptr); - CustomDataLayer *layer = (CustomDataLayer *)ptr->data; - rna_iterator_array_begin(iter, layer->data, sizeof(MStringProperty), me->totpoly, 0, NULL); -} - -static int rna_MeshStringPropertyLayer_data_length(PointerRNA *ptr) +static void rna_Mesh_vertex_string_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { - Mesh *me = rna_mesh(ptr); - return me->totpoly; + CustomData *vdata = rna_mesh_vdata(ptr); + rna_iterator_array_begin(iter, (void *)vdata->layers, sizeof(CustomDataLayer), vdata->totlayer, 0, + rna_string_layer_check); } - static void rna_Mesh_polygon_string_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { CustomData *pdata = rna_mesh_pdata(ptr); @@ -1115,6 +1102,10 @@ static void rna_Mesh_polygon_string_layers_begin(CollectionPropertyIterator *ite rna_string_layer_check); } +static int rna_Mesh_vertex_string_layers_length(PointerRNA *ptr) +{ + return CustomData_number_of_layers(rna_mesh_vdata(ptr), CD_PROP_STR); +} static int rna_Mesh_polygon_string_layers_length(PointerRNA *ptr) { return CustomData_number_of_layers(rna_mesh_pdata(ptr), CD_PROP_STR); @@ -1498,43 +1489,151 @@ static char *rna_MeshColor_path(PointerRNA *ptr) return rna_LoopCustomData_data_path(ptr, "vertex_colors", CD_MLOOPCOL); } -static char *rna_MeshIntPropertyLayer_path(PointerRNA *ptr) +/**** Float Property Layer API ****/ +static char *rna_MeshVertexFloatPropertyLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); - return BLI_sprintfN("int_layers[\"%s\"]", name_esc); + return BLI_sprintfN("vertex_float_layers[\"%s\"]", name_esc); +} +static char *rna_MeshPolygonFloatPropertyLayer_path(PointerRNA *ptr) +{ + CustomDataLayer *cdl = ptr->data; + char name_esc[sizeof(cdl->name) * 2]; + BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + return BLI_sprintfN("polygon_float_layers[\"%s\"]", name_esc); +} + +static char *rna_MeshVertexFloatProperty_path(PointerRNA *ptr) +{ + return rna_VertCustomData_data_path(ptr, "vertex_layers_float", CD_PROP_FLT); +} +static char *rna_MeshPolygonFloatProperty_path(PointerRNA *ptr) +{ + return rna_PolyCustomData_data_path(ptr, "polygon_layers_float", CD_PROP_FLT); +} + +static void rna_MeshVertexFloatPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + rna_iterator_array_begin(iter, layer->data, sizeof(MFloatProperty), me->totvert, 0, NULL); +} +static void rna_MeshPolygonFloatPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + rna_iterator_array_begin(iter, layer->data, sizeof(MFloatProperty), me->totpoly, 0, NULL); } -static char *rna_MeshIntProperty_path(PointerRNA *ptr) +static int rna_MeshVertexFloatPropertyLayer_data_length(PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + return me->totvert; +} +static int rna_MeshPolygonFloatPropertyLayer_data_length(PointerRNA *ptr) { - return rna_PolyCustomData_data_path(ptr, "layers_int", CD_PROP_INT); + Mesh *me = rna_mesh(ptr); + return me->totpoly; } -static char *rna_MeshFloatPropertyLayer_path(PointerRNA *ptr) +/**** Int Property Layer API ****/ +static char *rna_MeshVertexIntPropertyLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); - return BLI_sprintfN("float_layers[\"%s\"]", name_esc); + return BLI_sprintfN("vertex_int_layers[\"%s\"]", name_esc); +} +static char *rna_MeshPolygonIntPropertyLayer_path(PointerRNA *ptr) +{ + CustomDataLayer *cdl = ptr->data; + char name_esc[sizeof(cdl->name) * 2]; + BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + return BLI_sprintfN("polygon_int_layers[\"%s\"]", name_esc); } -static char *rna_MeshFloatProperty_path(PointerRNA *ptr) +static char *rna_MeshVertexIntProperty_path(PointerRNA *ptr) +{ + return rna_VertCustomData_data_path(ptr, "vertex_layers_int", CD_PROP_INT); +} +static char *rna_MeshPolygonIntProperty_path(PointerRNA *ptr) +{ + return rna_PolyCustomData_data_path(ptr, "polygon_layers_int", CD_PROP_INT); +} + +static void rna_MeshVertexIntPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + rna_iterator_array_begin(iter, layer->data, sizeof(MIntProperty), me->totvert, 0, NULL); +} +static void rna_MeshPolygonIntPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + rna_iterator_array_begin(iter, layer->data, sizeof(MIntProperty), me->totpoly, 0, NULL); +} + +static int rna_MeshVertexIntPropertyLayer_data_length(PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + return me->totvert; +} +static int rna_MeshPolygonIntPropertyLayer_data_length(PointerRNA *ptr) { - return rna_PolyCustomData_data_path(ptr, "layers_float", CD_PROP_FLT); + Mesh *me = rna_mesh(ptr); + return me->totpoly; } -static char *rna_MeshStringPropertyLayer_path(PointerRNA *ptr) +/**** String Property Layer API ****/ +static char *rna_MeshVertexStringPropertyLayer_path(PointerRNA *ptr) +{ + CustomDataLayer *cdl = ptr->data; + char name_esc[sizeof(cdl->name) * 2]; + BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + return BLI_sprintfN("vertex_string_layers[\"%s\"]", name_esc); +} +static char *rna_MeshPolygonStringPropertyLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); - return BLI_sprintfN("string_layers[\"%s\"]", name_esc); + return BLI_sprintfN("polygon_string_layers[\"%s\"]", name_esc); } -static char *rna_MeshStringProperty_path(PointerRNA *ptr) +static char *rna_MeshVertexStringProperty_path(PointerRNA *ptr) { - return rna_PolyCustomData_data_path(ptr, "layers_string", CD_PROP_STR); + return rna_VertCustomData_data_path(ptr, "vertex_layers_string", CD_PROP_STR); +} +static char *rna_MeshPolygonStringProperty_path(PointerRNA *ptr) +{ + return rna_PolyCustomData_data_path(ptr, "polygon_layers_string", CD_PROP_STR); +} + +static void rna_MeshVertexStringPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + rna_iterator_array_begin(iter, layer->data, sizeof(MStringProperty), me->totvert, 0, NULL); +} +static void rna_MeshPolygonStringPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + rna_iterator_array_begin(iter, layer->data, sizeof(MStringProperty), me->totpoly, 0, NULL); +} + +static int rna_MeshVertexStringPropertyLayer_data_length(PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + return me->totvert; +} +static int rna_MeshPolygonStringPropertyLayer_data_length(PointerRNA *ptr) +{ + Mesh *me = rna_mesh(ptr); + return me->totpoly; } /* XXX, we dont have propper byte string support yet, so for now use the (bytes + 1) @@ -1556,6 +1655,7 @@ void rna_MeshStringProperty_s_set(PointerRNA *ptr, const char *value) MStringProperty *ms = (MStringProperty *)ptr->data; BLI_strncpy(ms->s, value, sizeof(ms->s)); } +/***************************************/ static int rna_Mesh_tot_vert_get(PointerRNA *ptr) { @@ -1624,50 +1724,29 @@ static PointerRNA rna_Mesh_tessface_vertex_color_new(struct Mesh *me, ReportList return ptr; } -static PointerRNA rna_Mesh_polygon_int_property_new(struct Mesh *me, const char *name) -{ - PointerRNA ptr; - CustomDataLayer *cdl = NULL; - int index; - - CustomData_add_layer_named(&me->pdata, CD_PROP_INT, CD_DEFAULT, NULL, me->totpoly, name); - index = CustomData_get_named_layer_index(&me->pdata, CD_PROP_INT, name); - - cdl = (index == -1) ? NULL : &(me->pdata.layers[index]); - - RNA_pointer_create(&me->id, &RNA_MeshIntPropertyLayer, cdl, &ptr); - return ptr; -} - -static PointerRNA rna_Mesh_polygon_float_property_new(struct Mesh *me, const char *name) -{ - PointerRNA ptr; - CustomDataLayer *cdl = NULL; - int index; - - CustomData_add_layer_named(&me->pdata, CD_PROP_FLT, CD_DEFAULT, NULL, me->totpoly, name); - index = CustomData_get_named_layer_index(&me->pdata, CD_PROP_FLT, name); - - cdl = (index == -1) ? NULL : &(me->pdata.layers[index]); - - RNA_pointer_create(&me->id, &RNA_MeshFloatPropertyLayer, cdl, &ptr); - return ptr; -} - -static PointerRNA rna_Mesh_polygon_string_property_new(struct Mesh *me, const char *name) -{ - PointerRNA ptr; - CustomDataLayer *cdl = NULL; - int index; - - CustomData_add_layer_named(&me->pdata, CD_PROP_STR, CD_DEFAULT, NULL, me->totpoly, name); - index = CustomData_get_named_layer_index(&me->pdata, CD_PROP_STR, name); - - cdl = (index == -1) ? NULL : &(me->pdata.layers[index]); - - RNA_pointer_create(&me->id, &RNA_MeshStringPropertyLayer, cdl, &ptr); - return ptr; -} +#define DEFINE_CUSTOMDATA_PROPERTY_API(elemname, datatype, cdata, countvar, layertype) \ +static PointerRNA rna_Mesh_##elemname##_##datatype##_property_new(struct Mesh *me, const char *name) \ +{ \ + PointerRNA ptr; \ + CustomDataLayer *cdl = NULL; \ + int index; \ + \ + CustomData_add_layer_named(&me->cdata, CD_PROP_FLT, CD_DEFAULT, NULL, me->countvar, name); \ + index = CustomData_get_named_layer_index(&me->cdata, CD_PROP_FLT, name); \ + \ + cdl = (index == -1) ? NULL : &(me->cdata.layers[index]); \ + \ + RNA_pointer_create(&me->id, &RNA_##layertype, cdl, &ptr); \ + return ptr; \ +} + +DEFINE_CUSTOMDATA_PROPERTY_API(vertex, float, vdata, totvert, MeshVertexFloatPropertyLayer) +DEFINE_CUSTOMDATA_PROPERTY_API(vertex, int, vdata, totvert, MeshVertexIntPropertyLayer) +DEFINE_CUSTOMDATA_PROPERTY_API(vertex, string, vdata, totvert, MeshVertexStringPropertyLayer) +DEFINE_CUSTOMDATA_PROPERTY_API(polygon, float, pdata, totpoly, MeshPolygonFloatPropertyLayer) +DEFINE_CUSTOMDATA_PROPERTY_API(polygon, int, pdata, totpoly, MeshPolygonIntPropertyLayer) +DEFINE_CUSTOMDATA_PROPERTY_API(polygon, string, pdata, totpoly, MeshPolygonStringPropertyLayer) +#undef DEFINE_CUSTOMDATA_PROPERTY_API static PointerRNA rna_Mesh_uv_texture_new(struct Mesh *me, const char *name) { @@ -2494,96 +2573,108 @@ static void rna_def_mproperties(BlenderRNA *brna) PropertyRNA *prop; /* Float */ - srna = RNA_def_struct(brna, "MeshFloatPropertyLayer", NULL); - RNA_def_struct_sdna(srna, "CustomDataLayer"); - RNA_def_struct_ui_text(srna, "Mesh Float Property Layer", "User defined layer of floating point number values"); - RNA_def_struct_path_func(srna, "rna_MeshFloatPropertyLayer_path"); - - prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_struct_name_property(srna, prop); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshAnyLayer_name_set"); - RNA_def_property_ui_text(prop, "Name", ""); - RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); - - prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "MeshFloatProperty"); - RNA_def_property_ui_text(prop, "Data", ""); - RNA_def_property_collection_funcs(prop, "rna_MeshFloatPropertyLayer_data_begin", "rna_iterator_array_next", - "rna_iterator_array_end", "rna_iterator_array_get", - "rna_MeshFloatPropertyLayer_data_length", NULL, NULL, NULL); - - srna = RNA_def_struct(brna, "MeshFloatProperty", NULL); - RNA_def_struct_sdna(srna, "MFloatProperty"); - RNA_def_struct_ui_text(srna, "Mesh Float Property", - "User defined floating point number value in a float properties layer"); - RNA_def_struct_path_func(srna, "rna_MeshFloatProperty_path"); - - prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "f"); - RNA_def_property_ui_text(prop, "Value", ""); +#define MESH_FLOAT_PROPERTY_LAYER(elemname) \ + srna = RNA_def_struct(brna, "Mesh" elemname "FloatPropertyLayer", NULL); \ + RNA_def_struct_sdna(srna, "CustomDataLayer"); \ + RNA_def_struct_ui_text(srna, "Mesh " elemname " Float Property Layer", "User defined layer of floating point number values"); \ + RNA_def_struct_path_func(srna, "rna_Mesh" elemname "FloatPropertyLayer_path"); \ + \ + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); \ + RNA_def_struct_name_property(srna, prop); \ + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshAnyLayer_name_set"); \ + RNA_def_property_ui_text(prop, "Name", ""); \ + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \ + \ + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \ + RNA_def_property_struct_type(prop, "Mesh" elemname "FloatProperty"); \ + RNA_def_property_ui_text(prop, "Data", ""); \ + RNA_def_property_collection_funcs(prop, "rna_Mesh" elemname "FloatPropertyLayer_data_begin", "rna_iterator_array_next", \ + "rna_iterator_array_end", "rna_iterator_array_get", \ + "rna_Mesh" elemname "FloatPropertyLayer_data_length", NULL, NULL, NULL); \ + \ + srna = RNA_def_struct(brna, "Mesh" elemname "FloatProperty", NULL); \ + RNA_def_struct_sdna(srna, "MFloatProperty"); \ + RNA_def_struct_ui_text(srna, "Mesh " elemname " Float Property", \ + "User defined floating point number value in a float properties layer"); \ + RNA_def_struct_path_func(srna, "rna_Mesh" elemname "FloatProperty_path"); \ + \ + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); \ + RNA_def_property_float_sdna(prop, NULL, "f"); \ + RNA_def_property_ui_text(prop, "Value", ""); \ RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); /* Int */ - srna = RNA_def_struct(brna, "MeshIntPropertyLayer", NULL); - RNA_def_struct_sdna(srna, "CustomDataLayer"); - RNA_def_struct_ui_text(srna, "Mesh Int Property Layer", "User defined layer of integer number values"); - RNA_def_struct_path_func(srna, "rna_MeshIntPropertyLayer_path"); - - prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_struct_name_property(srna, prop); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshAnyLayer_name_set"); - RNA_def_property_ui_text(prop, "Name", ""); - RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); - - prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "MeshIntProperty"); - RNA_def_property_ui_text(prop, "Data", ""); - RNA_def_property_collection_funcs(prop, "rna_MeshIntPropertyLayer_data_begin", "rna_iterator_array_next", - "rna_iterator_array_end", "rna_iterator_array_get", - "rna_MeshIntPropertyLayer_data_length", NULL, NULL, NULL); - - srna = RNA_def_struct(brna, "MeshIntProperty", NULL); - RNA_def_struct_sdna(srna, "MIntProperty"); - RNA_def_struct_ui_text(srna, "Mesh Int Property", - "User defined integer number value in an integer properties layer"); - RNA_def_struct_path_func(srna, "rna_MeshIntProperty_path"); - - prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "i"); - RNA_def_property_ui_text(prop, "Value", ""); - RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); +#define MESH_INT_PROPERTY_LAYER(elemname) \ + srna = RNA_def_struct(brna, "Mesh" elemname "IntPropertyLayer", NULL); \ + RNA_def_struct_sdna(srna, "CustomDataLayer"); \ + RNA_def_struct_ui_text(srna, "Mesh " elemname " Int Property Layer", "User defined layer of integer number values"); \ + RNA_def_struct_path_func(srna, "rna_Mesh" elemname "IntPropertyLayer_path"); \ + \ + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); \ + RNA_def_struct_name_property(srna, prop); \ + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshAnyLayer_name_set"); \ + RNA_def_property_ui_text(prop, "Name", ""); \ + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \ + \ + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \ + RNA_def_property_struct_type(prop, "Mesh" elemname "IntProperty"); \ + RNA_def_property_ui_text(prop, "Data", ""); \ + RNA_def_property_collection_funcs(prop, "rna_Mesh" elemname "IntPropertyLayer_data_begin", "rna_iterator_array_next", \ + "rna_iterator_array_end", "rna_iterator_array_get", \ + "rna_Mesh" elemname "IntPropertyLayer_data_length", NULL, NULL, NULL); \ + \ + srna = RNA_def_struct(brna, "Mesh" elemname "IntProperty", NULL); \ + RNA_def_struct_sdna(srna, "MIntProperty"); \ + RNA_def_struct_ui_text(srna, "Mesh " elemname " Int Property", \ + "User defined integer number value in an integer properties layer"); \ + RNA_def_struct_path_func(srna, "rna_Mesh" elemname "IntProperty_path"); \ + \ + prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE); \ + RNA_def_property_int_sdna(prop, NULL, "i"); \ + RNA_def_property_ui_text(prop, "Value", ""); \ + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \ /* String */ - srna = RNA_def_struct(brna, "MeshStringPropertyLayer", NULL); - RNA_def_struct_sdna(srna, "CustomDataLayer"); - RNA_def_struct_ui_text(srna, "Mesh String Property Layer", "User defined layer of string text values"); - RNA_def_struct_path_func(srna, "rna_MeshStringPropertyLayer_path"); +#define MESH_STRING_PROPERTY_LAYER(elemname) \ + srna = RNA_def_struct(brna, "Mesh" elemname "StringPropertyLayer", NULL); \ + RNA_def_struct_sdna(srna, "CustomDataLayer"); \ + RNA_def_struct_ui_text(srna, "Mesh " elemname " String Property Layer", "User defined layer of string text values"); \ + RNA_def_struct_path_func(srna, "rna_Mesh" elemname "StringPropertyLayer_path"); \ + \ + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); \ + RNA_def_struct_name_property(srna, prop); \ + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshAnyLayer_name_set"); \ + RNA_def_property_ui_text(prop, "Name", ""); \ + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \ + \ + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \ + RNA_def_property_struct_type(prop, "Mesh" elemname "StringProperty"); \ + RNA_def_property_ui_text(prop, "Data", ""); \ + RNA_def_property_collection_funcs(prop, "rna_Mesh" elemname "StringPropertyLayer_data_begin", "rna_iterator_array_next", \ + "rna_iterator_array_end", "rna_iterator_array_get", \ + "rna_Mesh" elemname "StringPropertyLayer_data_length", NULL, NULL, NULL); \ + \ + srna = RNA_def_struct(brna, "Mesh" elemname "StringProperty", NULL); \ + RNA_def_struct_sdna(srna, "MStringProperty"); \ + RNA_def_struct_ui_text(srna, "Mesh " elemname " String Property", \ + "User defined string text value in a string properties layer"); \ + RNA_def_struct_path_func(srna, "rna_Mesh" elemname "StringProperty_path"); \ + \ + /* low level mesh data access, treat as bytes */ \ + prop = RNA_def_property(srna, "value", PROP_STRING, PROP_BYTESTRING); \ + RNA_def_property_string_sdna(prop, NULL, "s"); \ + RNA_def_property_string_funcs(prop, "rna_MeshStringProperty_s_get", "rna_MeshStringProperty_s_length", "rna_MeshStringProperty_s_set"); \ + RNA_def_property_ui_text(prop, "Value", ""); \ + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); \ + + MESH_FLOAT_PROPERTY_LAYER("Vertex") + MESH_FLOAT_PROPERTY_LAYER("Polygon") + MESH_INT_PROPERTY_LAYER("Vertex") + MESH_INT_PROPERTY_LAYER("Polygon") + MESH_STRING_PROPERTY_LAYER("Vertex") + MESH_STRING_PROPERTY_LAYER("Polygon") +#undef MESH_PROPERTY_LAYER - prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_struct_name_property(srna, prop); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshAnyLayer_name_set"); - RNA_def_property_ui_text(prop, "Name", ""); - RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); - - prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "MeshStringProperty"); - RNA_def_property_ui_text(prop, "Data", ""); - RNA_def_property_collection_funcs(prop, "rna_MeshStringPropertyLayer_data_begin", "rna_iterator_array_next", - "rna_iterator_array_end", "rna_iterator_array_get", - "rna_MeshStringPropertyLayer_data_length", NULL, NULL, NULL); - - srna = RNA_def_struct(brna, "MeshStringProperty", NULL); - RNA_def_struct_sdna(srna, "MStringProperty"); - RNA_def_struct_ui_text(srna, "Mesh String Property", - "User defined string text value in a string properties layer"); - RNA_def_struct_path_func(srna, "rna_MeshStringProperty_path"); - - /* low level mesh data access, treat as bytes */ - prop = RNA_def_property(srna, "value", PROP_STRING, PROP_BYTESTRING); - RNA_def_property_string_sdna(prop, NULL, "s"); - RNA_def_property_string_funcs(prop, "rna_MeshStringProperty_s_get", "rna_MeshStringProperty_s_length", "rna_MeshStringProperty_s_set"); - RNA_def_property_ui_text(prop, "Value", ""); - RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); } void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable) @@ -2859,23 +2950,65 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); } +/* mesh float layers */ +static void rna_def_vertex_float_layers(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "VertexFloatProperties"); + srna = RNA_def_struct(brna, "VertexFloatProperties", NULL); + RNA_def_struct_sdna(srna, "Mesh"); + RNA_def_struct_ui_text(srna, "Vertex Float Properties", "Collection of float properties"); + + func = RNA_def_function(srna, "new", "rna_Mesh_vertex_float_property_new"); + RNA_def_function_ui_description(func, "Add a float property layer to Mesh"); + RNA_def_string(func, "name", "Float Prop", 0, "", "Float property name"); + parm = RNA_def_pointer(func, "layer", "MeshVertexFloatPropertyLayer", "", "The newly created layer"); + RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_function_return(func, parm); +} + /* mesh int layers */ -static void rna_def_polygon_int_layers(BlenderRNA *brna, PropertyRNA *cprop) +static void rna_def_vertex_int_layers(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; FunctionRNA *func; PropertyRNA *parm; - RNA_def_property_srna(cprop, "IntProperties"); - srna = RNA_def_struct(brna, "IntProperties", NULL); + RNA_def_property_srna(cprop, "VertexIntProperties"); + srna = RNA_def_struct(brna, "VertexIntProperties", NULL); RNA_def_struct_sdna(srna, "Mesh"); - RNA_def_struct_ui_text(srna, "Int Properties", "Collection of int properties"); + RNA_def_struct_ui_text(srna, "Vertex Int Properties", "Collection of int properties"); - func = RNA_def_function(srna, "new", "rna_Mesh_polygon_int_property_new"); + func = RNA_def_function(srna, "new", "rna_Mesh_vertex_int_property_new"); RNA_def_function_ui_description(func, "Add a integer property layer to Mesh"); RNA_def_string(func, "name", "Int Prop", 0, "", "Int property name"); - parm = RNA_def_pointer(func, "layer", "MeshIntPropertyLayer", "", "The newly created layer"); + parm = RNA_def_pointer(func, "layer", "MeshVertexIntPropertyLayer", "", "The newly created layer"); + RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_function_return(func, parm); +} + +/* mesh string layers */ +static void rna_def_vertex_string_layers(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "VertexStringProperties"); + srna = RNA_def_struct(brna, "VertexStringProperties", NULL); + RNA_def_struct_sdna(srna, "Mesh"); + RNA_def_struct_ui_text(srna, "Vertex String Properties", "Collection of string properties"); + + func = RNA_def_function(srna, "new", "rna_Mesh_vertex_string_property_new"); + RNA_def_function_ui_description(func, "Add a string property layer to Mesh"); + RNA_def_string(func, "name", "String Prop", 0, "", "String property name"); + parm = RNA_def_pointer(func, "layer", "MeshVertexStringPropertyLayer", "", "The newly created layer"); RNA_def_property_flag(parm, PROP_RNAPTR); RNA_def_function_return(func, parm); } @@ -2888,15 +3021,36 @@ static void rna_def_polygon_float_layers(BlenderRNA *brna, PropertyRNA *cprop) FunctionRNA *func; PropertyRNA *parm; - RNA_def_property_srna(cprop, "FloatProperties"); - srna = RNA_def_struct(brna, "FloatProperties", NULL); + RNA_def_property_srna(cprop, "PolygonFloatProperties"); + srna = RNA_def_struct(brna, "PolygonFloatProperties", NULL); RNA_def_struct_sdna(srna, "Mesh"); - RNA_def_struct_ui_text(srna, "Float Properties", "Collection of float properties"); + RNA_def_struct_ui_text(srna, "Polygon Float Properties", "Collection of float properties"); func = RNA_def_function(srna, "new", "rna_Mesh_polygon_float_property_new"); RNA_def_function_ui_description(func, "Add a float property layer to Mesh"); RNA_def_string(func, "name", "Float Prop", 0, "", "Float property name"); - parm = RNA_def_pointer(func, "layer", "MeshFloatPropertyLayer", "", "The newly created layer"); + parm = RNA_def_pointer(func, "layer", "MeshPolygonFloatPropertyLayer", "", "The newly created layer"); + RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_function_return(func, parm); +} + +/* mesh int layers */ +static void rna_def_polygon_int_layers(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "PolygonIntProperties"); + srna = RNA_def_struct(brna, "PolygonIntProperties", NULL); + RNA_def_struct_sdna(srna, "Mesh"); + RNA_def_struct_ui_text(srna, "Polygon Int Properties", "Collection of int properties"); + + func = RNA_def_function(srna, "new", "rna_Mesh_polygon_int_property_new"); + RNA_def_function_ui_description(func, "Add a integer property layer to Mesh"); + RNA_def_string(func, "name", "Int Prop", 0, "", "Int property name"); + parm = RNA_def_pointer(func, "layer", "MeshPolygonIntPropertyLayer", "", "The newly created layer"); RNA_def_property_flag(parm, PROP_RNAPTR); RNA_def_function_return(func, parm); } @@ -2909,15 +3063,15 @@ static void rna_def_polygon_string_layers(BlenderRNA *brna, PropertyRNA *cprop) FunctionRNA *func; PropertyRNA *parm; - RNA_def_property_srna(cprop, "StringProperties"); - srna = RNA_def_struct(brna, "StringProperties", NULL); + RNA_def_property_srna(cprop, "PolygonStringProperties"); + srna = RNA_def_struct(brna, "PolygonStringProperties", NULL); RNA_def_struct_sdna(srna, "Mesh"); - RNA_def_struct_ui_text(srna, "String Properties", "Collection of string properties"); + RNA_def_struct_ui_text(srna, "Polygon String Properties", "Collection of string properties"); func = RNA_def_function(srna, "new", "rna_Mesh_polygon_string_property_new"); RNA_def_function_ui_description(func, "Add a string property layer to Mesh"); RNA_def_string(func, "name", "String Prop", 0, "", "String property name"); - parm = RNA_def_pointer(func, "layer", "MeshStringPropertyLayer", "", "The newly created layer"); + parm = RNA_def_pointer(func, "layer", "MeshPolygonStringPropertyLayer", "", "The newly created layer"); RNA_def_property_flag(parm, PROP_RNAPTR); RNA_def_function_return(func, parm); } @@ -3225,12 +3379,36 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Vertex Colors", "All vertex colors"); rna_def_loop_colors(brna, prop); - /* TODO, vertex, edge customdata layers (bmesh py api can access already) */ + /* TODO, edge customdata layers (bmesh py api can access already) */ + prop = RNA_def_property(srna, "vertex_layers_float", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer"); + RNA_def_property_collection_funcs(prop, "rna_Mesh_vertex_float_layers_begin", NULL, NULL, NULL, + "rna_Mesh_vertex_float_layers_length", NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "MeshVertexFloatPropertyLayer"); + RNA_def_property_ui_text(prop, "Float Property Layers", ""); + rna_def_vertex_float_layers(brna, prop); + + prop = RNA_def_property(srna, "vertex_layers_int", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer"); + RNA_def_property_collection_funcs(prop, "rna_Mesh_vertex_int_layers_begin", NULL, NULL, NULL, + "rna_Mesh_vertex_int_layers_length", NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "MeshVertexIntPropertyLayer"); + RNA_def_property_ui_text(prop, "Int Property Layers", ""); + rna_def_vertex_int_layers(brna, prop); + + prop = RNA_def_property(srna, "vertex_layers_string", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer"); + RNA_def_property_collection_funcs(prop, "rna_Mesh_vertex_string_layers_begin", NULL, NULL, NULL, + "rna_Mesh_vertex_string_layers_length", NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "MeshVertexStringPropertyLayer"); + RNA_def_property_ui_text(prop, "String Property Layers", ""); + rna_def_vertex_string_layers(brna, prop); + prop = RNA_def_property(srna, "polygon_layers_float", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer"); RNA_def_property_collection_funcs(prop, "rna_Mesh_polygon_float_layers_begin", NULL, NULL, NULL, "rna_Mesh_polygon_float_layers_length", NULL, NULL, NULL); - RNA_def_property_struct_type(prop, "MeshFloatPropertyLayer"); + RNA_def_property_struct_type(prop, "MeshPolygonFloatPropertyLayer"); RNA_def_property_ui_text(prop, "Float Property Layers", ""); rna_def_polygon_float_layers(brna, prop); @@ -3238,7 +3416,7 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer"); RNA_def_property_collection_funcs(prop, "rna_Mesh_polygon_int_layers_begin", NULL, NULL, NULL, "rna_Mesh_polygon_int_layers_length", NULL, NULL, NULL); - RNA_def_property_struct_type(prop, "MeshIntPropertyLayer"); + RNA_def_property_struct_type(prop, "MeshPolygonIntPropertyLayer"); RNA_def_property_ui_text(prop, "Int Property Layers", ""); rna_def_polygon_int_layers(brna, prop); @@ -3246,7 +3424,7 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer"); RNA_def_property_collection_funcs(prop, "rna_Mesh_polygon_string_layers_begin", NULL, NULL, NULL, "rna_Mesh_polygon_string_layers_length", NULL, NULL, NULL); - RNA_def_property_struct_type(prop, "MeshStringPropertyLayer"); + RNA_def_property_struct_type(prop, "MeshPolygonStringPropertyLayer"); RNA_def_property_ui_text(prop, "String Property Layers", ""); rna_def_polygon_string_layers(brna, prop); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 792306bff0d..ba6a3f43423 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1841,6 +1841,8 @@ static void rna_def_space_outliner(BlenderRNA *brna) {SO_LIBRARIES, "LIBRARIES", 0, "Blender File", "Display data of current file and linked libraries"}, {SO_DATABLOCKS, "DATABLOCKS", 0, "Datablocks", "Display all raw datablocks"}, {SO_USERDEF, "USER_PREFERENCES", 0, "User Preferences", "Display the user preference datablocks"}, + {SO_ID_ORPHANS, "ORPHANED_DATABLOCKS", 0, "Orphaned Datablocks", + "Display datablocks which are unused and/or will be lost when the file is reloaded"}, {0, NULL, 0, NULL, NULL} }; @@ -2895,7 +2897,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "chanshown"); RNA_def_property_ui_text(prop, "Display Channel", "The channel number shown in the image preview. 0 is the result of all strips combined"); - RNA_def_property_range(prop, 1, MAXSEQ); + RNA_def_property_range(prop, -5, MAXSEQ); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); prop = RNA_def_property(srna, "preview_channels", PROP_ENUM, PROP_NONE); @@ -3299,12 +3301,6 @@ static void rna_def_space_graph(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Has Ghost Curves", "Graph Editor instance has some ghost curves stored"); - /* auto view */ - prop = RNA_def_property(srna, "use_auto_view_selected", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_AUTO_VIEW_SELECTED); - RNA_def_property_ui_text(prop, "Auto View Selected", "Automatically adjust view based on selection"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); - /* nromalize curves */ prop = RNA_def_property(srna, "use_normalization", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_NORMALIZE); diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 2dca3218e41..acb58f6b767 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -37,6 +37,7 @@ #include "DNA_object_types.h" #include "BKE_customdata.h" +#include "BKE_cdderivedmesh.h" #include "BKE_data_transfer.h" #include "BKE_DerivedMesh.h" #include "BKE_library.h" @@ -152,6 +153,12 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) } #define HIGH_POLY_WARNING 10000 +#define DT_TYPES_AFFECT_MESH ( \ + DT_TYPE_BWEIGHT_VERT | \ + DT_TYPE_BWEIGHT_EDGE | DT_TYPE_CREASE | DT_TYPE_SHARP_EDGE | \ + DT_TYPE_LNOR | \ + DT_TYPE_SHARP_FACE \ +) static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) @@ -160,6 +167,10 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der DerivedMesh *dm = derivedData; ReportList reports; + /* Only used to check wehther we are operating on org data or not... */ + Mesh *me = ob->data; + MVert *mvert; + const bool invert_vgroup = (dtmd->flags & MOD_DATATRANSFER_INVERT_VGROUP) != 0; const float max_dist = (dtmd->flags & MOD_DATATRANSFER_MAP_MAXDIST) ? dtmd->map_max_distance : FLT_MAX; @@ -171,6 +182,13 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der BLI_SPACE_TRANSFORM_SETUP(space_transform, ob, dtmd->ob_source); } + mvert = dm->getVertArray(dm); + if ((me->mvert == mvert) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) { + /* We need to duplicate data here, otherwise setting custom normals, edges' shaprness, etc., could + * modify org mesh, see T43671. */ + dm = CDDM_copy(dm); + } + BKE_reports_init(&reports, RPT_STORE); /* Note: no islands precision for now here. */ @@ -190,6 +208,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der return dm; } +#undef HIGH_POLY_WARNING +#undef DT_TYPES_AFFECT_MESH ModifierTypeInfo modifierType_DataTransfer = { /* name */ "DataTransfer", diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 58ef850bb4f..db20823bf0c 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -323,7 +323,7 @@ static bool is_valid_target(NormalEditModifierData *smd) return false; } -static void normalEditModifier_do(NormalEditModifierData *smd, Object *ob, DerivedMesh *dm) +static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *ob, DerivedMesh *dm) { Mesh *me = ob->data; @@ -331,10 +331,10 @@ static void normalEditModifier_do(NormalEditModifierData *smd, Object *ob, Deriv const int num_edges = dm->getNumEdges(dm); const int num_loops = dm->getNumLoops(dm); const int num_polys = dm->getNumPolys(dm); - MVert *mvert = dm->getVertArray(dm); - MEdge *medge = dm->getEdgeArray(dm); - MLoop *mloop = dm->getLoopArray(dm); - MPoly *mpoly = dm->getPolyArray(dm); + MVert *mvert; + MEdge *medge; + MLoop *mloop; + MPoly *mpoly; const bool use_invert_vgroup = ((smd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0); const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) && @@ -352,14 +352,24 @@ static void normalEditModifier_do(NormalEditModifierData *smd, Object *ob, Deriv /* Do not run that modifier at all if autosmooth is disabled! */ if (!is_valid_target(smd) || !num_loops) { - return; + return dm; } if (!(me->flag & ME_AUTOSMOOTH)) { modifier_setError((ModifierData *)smd, "Enable 'Auto Smooth' option in mesh settings"); - return; + return dm; } + medge = dm->getEdgeArray(dm); + if (me->medge == medge) { + /* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could + * modify org mesh, see T43671. */ + dm = CDDM_copy(dm); + medge = dm->getEdgeArray(dm); + } + mvert = dm->getVertArray(dm); + mloop = dm->getLoopArray(dm); + mpoly = dm->getPolyArray(dm); if (use_current_clnors) { dm->calcLoopNormals(dm, true, me->smoothresh); @@ -397,6 +407,8 @@ static void normalEditModifier_do(NormalEditModifierData *smd, Object *ob, Deriv if (free_polynors) { MEM_freeN(polynors); } + + return dm; } static void initData(ModifierData *md) @@ -467,8 +479,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UN static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { - normalEditModifier_do((NormalEditModifierData *)md, ob, dm); - return dm; + return normalEditModifier_do((NormalEditModifierData *)md, ob, dm); } ModifierTypeInfo modifierType_NormalEdit = { diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index ca20f837b4a..7b51b08451b 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -79,6 +79,37 @@ static int mathutils_array_parse_fast(float *array, return size; } +/** + * helper function that returns a Python ``__hash__``. + * + * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash') + */ +Py_hash_t mathutils_array_hash(const float *array, size_t array_len) +{ + int i; + Py_uhash_t x; /* Unsigned for defined overflow behavior. */ + Py_hash_t y; + Py_uhash_t mult; + Py_ssize_t len; + + mult = _PyHASH_MULTIPLIER; + len = array_len; + x = 0x345678UL; + i = 0; + while (--len >= 0) { + y = _Py_HashDouble((double)(array[i++])); + if (y == -1) + return -1; + x = (x ^ y) * mult; + /* the cast might truncate len; that doesn't change hash stability */ + mult += (Py_hash_t)(82520UL + len + len); + } + x += 97531UL; + if (x == (Py_uhash_t)-1) + x = -2; + return x; +} + /* helper functionm returns length of the 'value', -1 on error */ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix) { @@ -452,6 +483,20 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index) return -1; } +void _BaseMathObject_RaiseFrozenExc(const BaseMathObject *self) +{ + PyErr_Format(PyExc_TypeError, + "%s is frozen (immutable)", + Py_TYPE(self)->tp_name); +} + +void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self) +{ + PyErr_Format(PyExc_TypeError, + "%s is not frozen (mutable), call freeze first", + Py_TYPE(self)->tp_name); +} + /* BaseMathObject generic functions for all mathutils types */ char BaseMathObject_owner_doc[] = "The item this is wrapping or None (read-only)."; PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *UNUSED(closure)) @@ -466,6 +511,33 @@ PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *UNUSED(closu return PyBool_FromLong((self->flag & BASE_MATH_FLAG_IS_WRAP) != 0); } +char BaseMathObject_is_frozen_doc[] = "True when this object has been frozen (read-only).\n\n:type: boolean"; +PyObject *BaseMathObject_is_frozen_get(BaseMathObject *self, void *UNUSED(closure)) +{ + return PyBool_FromLong((self->flag & BASE_MATH_FLAG_IS_FROZEN) != 0); +} + +char BaseMathObject_freeze_doc[] = +".. function:: freeze()\n" +"\n" +" Make this object immutable.\n" +"\n" +" After this the object can be hashed, used in dictionaries & sets.\n" +"\n" +" :return: An instance of this object.\n" +; +PyObject *BaseMathObject_freeze(BaseMathObject *self) +{ + if (self->flag & BASE_MATH_FLAG_IS_WRAP) { + PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped data"); + return NULL; + } + + self->flag |= BASE_MATH_FLAG_IS_FROZEN; + + return Py_INCREF_RET((PyObject *)self);; +} + int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg) { Py_VISIT(self->cb_user); diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h index 296b8cf9559..e653b45389b 100644 --- a/source/blender/python/mathutils/mathutils.h +++ b/source/blender/python/mathutils/mathutils.h @@ -34,6 +34,7 @@ struct DynStr; extern char BaseMathObject_is_wrapped_doc[]; +extern char BaseMathObject_is_frozen_doc[]; extern char BaseMathObject_owner_doc[]; #define BASE_MATH_NEW(struct_name, root_type, base_type) \ @@ -43,6 +44,7 @@ extern char BaseMathObject_owner_doc[]; /* BaseMathObject.flag */ enum { BASE_MATH_FLAG_IS_WRAP = (1 << 0), + BASE_MATH_FLAG_IS_FROZEN = (1 << 1), }; #define BASE_MATH_FLAG_DEFAULT 0 @@ -69,6 +71,10 @@ typedef struct { PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *); PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *); +PyObject *BaseMathObject_is_frozen_get(BaseMathObject *self, void *); + +extern char BaseMathObject_freeze_doc[]; +PyObject *BaseMathObject_freeze(BaseMathObject *self); int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg); int BaseMathObject_clear(BaseMathObject *self); @@ -102,6 +108,9 @@ int _BaseMathObject_WriteCallback(BaseMathObject *self); int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index); int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index); +void _BaseMathObject_RaiseFrozenExc(const BaseMathObject *self); +void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self); + /* since this is called so often avoid where possible */ #define BaseMath_ReadCallback(_self) \ (((_self)->cb_user ? _BaseMathObject_ReadCallback((BaseMathObject *)_self):0)) @@ -112,12 +121,31 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index); #define BaseMath_WriteIndexCallback(_self, _index) \ (((_self)->cb_user ? _BaseMathObject_WriteIndexCallback((BaseMathObject *)_self, _index):0)) +/* support BASE_MATH_FLAG_IS_FROZEN */ +#define BaseMath_ReadCallback_ForWrite(_self) \ + (UNLIKELY((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) ? \ + (_BaseMathObject_RaiseFrozenExc((BaseMathObject *)_self), -1) : (BaseMath_ReadCallback(_self))) + +#define BaseMath_ReadIndexCallback_ForWrite(_self, _index) \ + (UNLIKELY((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) ? \ + (_BaseMathObject_RaiseFrozenExc((BaseMathObject *)_self), -1) : (BaseMath_ReadIndexCallback(_self, _index))) + +#define BaseMath_Prepare_ForWrite(_self) \ + (UNLIKELY((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) ? \ + (_BaseMathObject_RaiseFrozenExc((BaseMathObject *)_self), -1) : 0) + +#define BaseMathObject_Prepare_ForHash(_self) \ + (UNLIKELY(((_self)->flag & BASE_MATH_FLAG_IS_FROZEN) == 0) ? \ + (_BaseMathObject_RaiseNotFrozenExc((BaseMathObject *)_self), -1) : 0) + /* utility func */ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix); int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, const char *error_prefix); int mathutils_array_parse_alloc_v(float **array, int array_dim, PyObject *value, const char *error_prefix); int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix); +Py_hash_t mathutils_array_hash(const float *float_array, size_t array_len); + /* zero remaining unused elements of the array */ #define MU_ARRAY_ZERO (1 << 30) /* ignore larger py sequences than requested (just use first elements), diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c index ce590999bc1..add8c2451ff 100644 --- a/source/blender/python/mathutils/mathutils_Color.c +++ b/source/blender/python/mathutils/mathutils_Color.c @@ -192,6 +192,17 @@ static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op) return Py_INCREF_RET(res); } +static Py_hash_t Color_hash(ColorObject *self) +{ + if (BaseMath_ReadCallback(self) == -1) + return -1; + + if (BaseMathObject_Prepare_ForHash(self) == -1) + return -1; + + return mathutils_array_hash(self->col, COLOR_SIZE); +} + /* ---------------------SEQUENCE PROTOCOLS------------------------ */ /* ----------------------------len(object)------------------------ */ /* sequence length */ @@ -222,8 +233,12 @@ static PyObject *Color_item(ColorObject *self, int i) /* sequence accessor (set) */ static int Color_ass_item(ColorObject *self, int i, PyObject *value) { - float f = PyFloat_AsDouble(value); + float f; + if (BaseMath_Prepare_ForWrite(self) == -1) + return -1; + + f = PyFloat_AsDouble(value); if (f == -1 && PyErr_Occurred()) { /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "color[item] = x: " @@ -275,7 +290,7 @@ static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq) int i, size; float col[COLOR_SIZE]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; CLAMP(begin, 0, COLOR_SIZE); @@ -431,7 +446,7 @@ static PyObject *Color_iadd(PyObject *v1, PyObject *v2) color1 = (ColorObject *)v1; color2 = (ColorObject *)v2; - if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1) + if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1) return NULL; add_vn_vn(color1->col, color2->col, COLOR_SIZE); @@ -480,7 +495,7 @@ static PyObject *Color_isub(PyObject *v1, PyObject *v2) color1 = (ColorObject *)v1; color2 = (ColorObject *)v2; - if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1) + if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1) return NULL; sub_vn_vn(color1->col, color2->col, COLOR_SIZE); @@ -579,7 +594,7 @@ static PyObject *Color_imul(PyObject *v1, PyObject *v2) ColorObject *color = (ColorObject *)v1; float scalar; - if (BaseMath_ReadCallback(color) == -1) + if (BaseMath_ReadCallback_ForWrite(color) == -1) return NULL; /* only support color *= float */ @@ -605,7 +620,7 @@ static PyObject *Color_idiv(PyObject *v1, PyObject *v2) ColorObject *color = (ColorObject *)v1; float scalar; - if (BaseMath_ReadCallback(color) == -1) + if (BaseMath_ReadCallback_ForWrite(color) == -1) return NULL; /* only support color /= float */ @@ -728,7 +743,7 @@ static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type) return -1; } - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; rgb_to_hsv_v(self->col, hsv); @@ -769,6 +784,9 @@ static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closur if (mathutils_array_parse(hsv, 3, 3, value, "mathutils.Color.hsv = value") == -1) return -1; + if (BaseMath_Prepare_ForWrite(self) == -1) + return -1; + CLAMP(hsv[0], 0.0f, 1.0f); CLAMP(hsv[1], 0.0f, 1.0f); CLAMP(hsv[2], 0.0f, 1.0f); @@ -796,6 +814,7 @@ static PyGetSetDef Color_getseters[] = { {(char *)"hsv", (getter)Color_hsv_get, (setter)Color_hsv_set, (char *)Color_hsv_doc, (void *)0}, {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL}, + {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL}, {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; @@ -806,6 +825,9 @@ static struct PyMethodDef Color_methods[] = { {"copy", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc}, {"__copy__", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc}, {"__deepcopy__", (PyCFunction) Color_deepcopy, METH_VARARGS, Color_copy_doc}, + + /* base-math methods */ + {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc}, {NULL, NULL, 0, NULL} }; @@ -832,7 +854,7 @@ PyTypeObject color_Type = { &Color_NumMethods, /* tp_as_number */ &Color_SeqMethods, /* tp_as_sequence */ &Color_AsMapping, /* tp_as_mapping */ - NULL, /* tp_hash */ + (hashfunc)Color_hash, /* tp_hash */ NULL, /* tp_call */ #ifndef MATH_STANDALONE (reprfunc) Color_str, /* tp_str */ diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c index edb4af0aa1d..54adc826af7 100644 --- a/source/blender/python/mathutils/mathutils_Euler.c +++ b/source/blender/python/mathutils/mathutils_Euler.c @@ -182,6 +182,9 @@ PyDoc_STRVAR(Euler_zero_doc, ); static PyObject *Euler_zero(EulerObject *self) { + if (BaseMath_Prepare_ForWrite(self) == -1) + return NULL; + zero_v3(self->eul); if (BaseMath_WriteCallback(self) == -1) @@ -220,7 +223,7 @@ static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args) return NULL; } - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; @@ -243,7 +246,7 @@ static PyObject *Euler_rotate(EulerObject *self, PyObject *value) { float self_rmat[3][3], other_rmat[3][3], rmat[3][3]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1) @@ -270,7 +273,7 @@ static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value) { float teul[EULER_SIZE]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (mathutils_array_parse(teul, EULER_SIZE, EULER_SIZE, value, @@ -386,6 +389,17 @@ static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op) return Py_INCREF_RET(res); } +static Py_hash_t Euler_hash(EulerObject *self) +{ + if (BaseMath_ReadCallback(self) == -1) + return -1; + + if (BaseMathObject_Prepare_ForHash(self) == -1) + return -1; + + return mathutils_array_hash(self->eul, EULER_SIZE); +} + /* ---------------------SEQUENCE PROTOCOLS------------------------ */ /* ----------------------------len(object)------------------------ */ /* sequence length */ @@ -416,8 +430,12 @@ static PyObject *Euler_item(EulerObject *self, int i) /* sequence accessor (set) */ static int Euler_ass_item(EulerObject *self, int i, PyObject *value) { - float f = PyFloat_AsDouble(value); + float f; + if (BaseMath_Prepare_ForWrite(self) == -1) + return -1; + + f = PyFloat_AsDouble(value); if (f == -1 && PyErr_Occurred()) { /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "euler[attribute] = x: " @@ -470,7 +488,7 @@ static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq) int i, size; float eul[EULER_SIZE]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; CLAMP(begin, 0, EULER_SIZE); @@ -615,12 +633,18 @@ static PyObject *Euler_order_get(EulerObject *self, void *UNUSED(closure)) static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(closure)) { - const char *order_str = _PyUnicode_AsString(value); - short order = euler_order_from_string(order_str, "euler.order"); + const char *order_str; + short order; - if (order == -1) + if (BaseMath_Prepare_ForWrite(self) == -1) return -1; + if (((order_str = _PyUnicode_AsString(value)) == NULL) || + ((order = euler_order_from_string(order_str, "euler.order")) == -1)) + { + return -1; + } + self->order = order; (void)BaseMath_WriteCallback(self); /* order can be written back */ return 0; @@ -636,6 +660,7 @@ static PyGetSetDef Euler_getseters[] = { {(char *)"order", (getter)Euler_order_get, (setter)Euler_order_set, Euler_order_doc, (void *)NULL}, {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL}, + {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL}, {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; @@ -652,6 +677,9 @@ static struct PyMethodDef Euler_methods[] = { {"copy", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc}, {"__copy__", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc}, {"__deepcopy__", (PyCFunction) Euler_deepcopy, METH_VARARGS, Euler_copy_doc}, + + /* base-math methods */ + {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc}, {NULL, NULL, 0, NULL} }; @@ -680,7 +708,7 @@ PyTypeObject euler_Type = { NULL, /* tp_as_number */ &Euler_SeqMethods, /* tp_as_sequence */ &Euler_AsMapping, /* tp_as_mapping */ - NULL, /* tp_hash */ + (hashfunc)Euler_hash, /* tp_hash */ NULL, /* tp_call */ #ifndef MATH_STANDALONE (reprfunc) Euler_str, /* tp_str */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 95b53256eac..d4ed859fd5c 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -111,7 +111,7 @@ static int mathutils_matrix_row_set(BaseMathObject *bmo, int row) MatrixObject *self = (MatrixObject *)bmo->cb_user; int col; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) return -1; @@ -141,7 +141,7 @@ static int mathutils_matrix_row_set_index(BaseMathObject *bmo, int row, int col) { MatrixObject *self = (MatrixObject *)bmo->cb_user; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) return -1; @@ -200,7 +200,7 @@ static int mathutils_matrix_col_set(BaseMathObject *bmo, int col) int num_row; int row; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; if (!matrix_col_vector_check(self, (VectorObject *)bmo, col)) return -1; @@ -233,7 +233,7 @@ static int mathutils_matrix_col_set_index(BaseMathObject *bmo, int col, int row) { MatrixObject *self = (MatrixObject *)bmo->cb_user; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; if (!matrix_col_vector_check(self, (VectorObject *)bmo, col)) return -1; @@ -286,7 +286,7 @@ static int mathutils_matrix_translation_set(BaseMathObject *bmo, int col) MatrixObject *self = (MatrixObject *)bmo->cb_user; int row; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; for (row = 0; row < 3; row++) { @@ -312,7 +312,7 @@ static int mathutils_matrix_translation_set_index(BaseMathObject *bmo, int col, { MatrixObject *self = (MatrixObject *)bmo->cb_user; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; MATRIX_ITEM(self, row, col) = bmo->data[row]; @@ -895,6 +895,19 @@ static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src) memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->num_col * mat_dst->num_row)); } +/* transposes memory layout, rol/col's don't have to match */ +static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src) +{ + unsigned short col, row; + unsigned int i = 0; + + for (row = 0; row < mat_src->num_row; row++) { + for (col = 0; col < mat_src->num_col; col++) { + mat_dst_fl[i++] = MATRIX_ITEM(mat_src, row, col); + } + } +} + /* assumes rowsize == colsize is checked and the read callback has run */ static float matrix_determinant_internal(const MatrixObject *self) { @@ -1385,7 +1398,7 @@ PyDoc_STRVAR(Matrix_invert_doc, ); static PyObject *Matrix_invert(MatrixObject *self, PyObject *args) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (matrix_invert_is_compat(self) == false) { @@ -1466,7 +1479,7 @@ static PyObject *Matrix_inverted(MatrixObject *self, PyObject *args) static PyObject *Matrix_inverted_noargs(MatrixObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (matrix_invert_is_compat(self) == false) { @@ -1496,7 +1509,7 @@ PyDoc_STRVAR(Matrix_invert_safe_doc, ); static PyObject *Matrix_invert_safe(MatrixObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (matrix_invert_is_compat(self) == false) { @@ -1547,7 +1560,7 @@ PyDoc_STRVAR(Matrix_adjugate_doc, ); static PyObject *Matrix_adjugate(MatrixObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (self->num_col != self->num_row) { @@ -1602,7 +1615,7 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value) { float self_rmat[3][3], other_rmat[3][3], rmat[3][3]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1) @@ -1746,7 +1759,7 @@ PyDoc_STRVAR(Matrix_transpose_doc, ); static PyObject *Matrix_transpose(MatrixObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (self->num_col != self->num_row) { @@ -1793,7 +1806,7 @@ PyDoc_STRVAR(Matrix_normalize_doc, ); static PyObject *Matrix_normalize(MatrixObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (self->num_col != self->num_row) { @@ -1842,6 +1855,9 @@ PyDoc_STRVAR(Matrix_zero_doc, ); static PyObject *Matrix_zero(MatrixObject *self) { + if (BaseMath_Prepare_ForWrite(self) == -1) + return NULL; + fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f); if (BaseMath_WriteCallback(self) == -1) @@ -1878,7 +1894,7 @@ PyDoc_STRVAR(Matrix_identity_doc, ); static PyObject *Matrix_identity(MatrixObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (self->num_col != self->num_row) { @@ -2037,6 +2053,21 @@ static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op) return Py_INCREF_RET(res); } +static Py_hash_t Matrix_hash(MatrixObject *self) +{ + float mat[SQUARE(MATRIX_MAX_DIM)]; + + if (BaseMath_ReadCallback(self) == -1) + return -1; + + if (BaseMathObject_Prepare_ForHash(self) == -1) + return -1; + + matrix_transpose_internal(mat, self); + + return mathutils_array_hash(mat, self->num_row * self->num_col); +} + /*---------------------SEQUENCE PROTOCOLS------------------------ * ----------------------------len(object)------------------------ * sequence length */ @@ -2049,7 +2080,7 @@ static int Matrix_len(MatrixObject *self) * the wrapped vector gives direct access to the matrix data */ static PyObject *Matrix_item_row(MatrixObject *self, int row) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (row < 0 || row >= self->num_row) { @@ -2063,7 +2094,7 @@ static PyObject *Matrix_item_row(MatrixObject *self, int row) /* same but column access */ static PyObject *Matrix_item_col(MatrixObject *self, int col) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (col < 0 || col >= self->num_col) { @@ -2082,7 +2113,7 @@ static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value) { int col; float vec[MATRIX_MAX_DIM]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; if (row >= self->num_row || row < 0) { @@ -2107,7 +2138,7 @@ static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value) { int row; float vec[MATRIX_MAX_DIM]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; if (col >= self->num_col || col < 0) { @@ -2159,7 +2190,7 @@ static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *va { PyObject *value_fast = NULL; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; CLAMP(begin, 0, self->num_row); @@ -2525,7 +2556,7 @@ static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *UNU { float tvec[3]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; /*must be 4x4 square matrix*/ @@ -2661,6 +2692,7 @@ static PyGetSetDef Matrix_getseters[] = { {(char *)"is_orthogonal", (getter)Matrix_is_orthogonal_get, (setter)NULL, Matrix_is_orthogonal_doc, NULL}, {(char *)"is_orthogonal_axis_vectors", (getter)Matrix_is_orthogonal_axis_vectors_get, (setter)NULL, Matrix_is_orthogonal_axis_vectors_doc, NULL}, {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL}, + {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL}, {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; @@ -2704,6 +2736,9 @@ static struct PyMethodDef Matrix_methods[] = { {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc}, {"__deepcopy__", (PyCFunction) Matrix_deepcopy, METH_VARARGS, Matrix_copy_doc}, + /* base-math methods */ + {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc}, + /* class methods */ {"Identity", (PyCFunction) C_Matrix_Identity, METH_VARARGS | METH_CLASS, C_Matrix_Identity_doc}, {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc}, @@ -2739,7 +2774,7 @@ PyTypeObject matrix_Type = { &Matrix_NumMethods, /*tp_as_number*/ &Matrix_SeqMethods, /*tp_as_sequence*/ &Matrix_AsMapping, /*tp_as_mapping*/ - NULL, /*tp_hash*/ + (hashfunc)Matrix_hash, /*tp_hash*/ NULL, /*tp_call*/ #ifndef MATH_STANDALONE (reprfunc) Matrix_str, /*tp_str*/ diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c index 42be316bc9b..1752be6e306 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.c +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -340,7 +340,7 @@ static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value) float self_rmat[3][3], other_rmat[3][3], rmat[3][3]; float tquat[4], length; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (mathutils_any_to_rotmat(other_rmat, value, "Quaternion.rotate(value)") == -1) @@ -367,7 +367,7 @@ PyDoc_STRVAR(Quaternion_normalize_doc, ); static PyObject *Quaternion_normalize(QuaternionObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; normalize_qt(self->quat); @@ -395,7 +395,7 @@ PyDoc_STRVAR(Quaternion_invert_doc, ); static PyObject *Quaternion_invert(QuaternionObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; invert_qt(self->quat); @@ -425,7 +425,7 @@ PyDoc_STRVAR(Quaternion_identity_doc, ); static PyObject *Quaternion_identity(QuaternionObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; unit_qt(self->quat); @@ -443,7 +443,7 @@ PyDoc_STRVAR(Quaternion_negate_doc, ); static PyObject *Quaternion_negate(QuaternionObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; mul_qt_fl(self->quat, -1.0f); @@ -459,7 +459,7 @@ PyDoc_STRVAR(Quaternion_conjugate_doc, ); static PyObject *Quaternion_conjugate(QuaternionObject *self) { - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; conjugate_qt(self->quat); @@ -575,6 +575,17 @@ static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op) return Py_INCREF_RET(res); } +static Py_hash_t Quaternion_hash(QuaternionObject *self) +{ + if (BaseMath_ReadCallback(self) == -1) + return -1; + + if (BaseMathObject_Prepare_ForHash(self) == -1) + return -1; + + return mathutils_array_hash(self->quat, QUAT_SIZE); +} + /* ---------------------SEQUENCE PROTOCOLS------------------------ */ /* ----------------------------len(object)------------------------ */ /* sequence length */ @@ -605,8 +616,14 @@ static PyObject *Quaternion_item(QuaternionObject *self, int i) /* sequence accessor (set) */ static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob) { - float scalar = (float)PyFloat_AsDouble(ob); - if (scalar == -1.0f && PyErr_Occurred()) { /* parsed item not a number */ + float f; + + if (BaseMath_Prepare_ForWrite(self) == -1) + return -1; + + f = (float)PyFloat_AsDouble(ob); + + if (f == -1.0f && PyErr_Occurred()) { /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "quaternion[index] = x: " "assigned value not a number"); @@ -621,7 +638,7 @@ static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob) "array assignment index out of range"); return -1; } - self->quat[i] = scalar; + self->quat[i] = f; if (BaseMath_WriteIndexCallback(self, i) == -1) return -1; @@ -657,7 +674,7 @@ static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyOb int i, size; float quat[QUAT_SIZE]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; CLAMP(begin, 0, QUAT_SIZE); @@ -1004,7 +1021,7 @@ static int Quaternion_angle_set(QuaternionObject *self, PyObject *value, void *U float axis[3], angle_dummy; float angle; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; len = normalize_qt_qt(tquat, self->quat); @@ -1060,7 +1077,7 @@ static int Quaternion_axis_vector_set(QuaternionObject *self, PyObject *value, v float axis[3]; float angle; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; len = normalize_qt_qt(tquat, self->quat); @@ -1204,6 +1221,9 @@ static struct PyMethodDef Quaternion_methods[] = { {"slerp", (PyCFunction) Quaternion_slerp, METH_VARARGS, Quaternion_slerp_doc}, {"rotate", (PyCFunction) Quaternion_rotate, METH_O, Quaternion_rotate_doc}, + /* base-math methods */ + {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc}, + {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc}, {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc}, {"__deepcopy__", (PyCFunction) Quaternion_deepcopy, METH_VARARGS, Quaternion_copy_doc}, @@ -1222,6 +1242,7 @@ static PyGetSetDef Quaternion_getseters[] = { {(char *)"angle", (getter)Quaternion_angle_get, (setter)Quaternion_angle_set, Quaternion_angle_doc, NULL}, {(char *)"axis", (getter)Quaternion_axis_vector_get, (setter)Quaternion_axis_vector_set, Quaternion_axis_vector_doc, NULL}, {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL}, + {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL}, {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; @@ -1266,7 +1287,7 @@ PyTypeObject quaternion_Type = { &Quaternion_NumMethods, /* tp_as_number */ &Quaternion_SeqMethods, /* tp_as_sequence */ &Quaternion_AsMapping, /* tp_as_mapping */ - NULL, /* tp_hash */ + (hashfunc)Quaternion_hash, /* tp_hash */ NULL, /* tp_call */ #ifndef MATH_STANDALONE (reprfunc) Quaternion_str, /* tp_str */ diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index 091412b0f53..5cb7d71d52c 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -336,6 +336,9 @@ PyDoc_STRVAR(Vector_zero_doc, ); static PyObject *Vector_zero(VectorObject *self) { + if (BaseMath_Prepare_ForWrite(self) == -1) + return NULL; + fill_vn_fl(self->vec, self->size, 0.0f); if (BaseMath_WriteCallback(self) == -1) @@ -357,7 +360,7 @@ PyDoc_STRVAR(Vector_normalize_doc, static PyObject *Vector_normalize(VectorObject *self) { int size = (self->size == 4 ? 3 : self->size); - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; normalize_vn(self->vec, size); @@ -1123,9 +1126,6 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value) double dot = 0.0f, dot2 = 0.0f; int x; - if (BaseMath_ReadCallback(self) == -1) - return NULL; - if (mathutils_array_parse(tvec, size, size, value, "Vector.project(other), invalid 'other' arg") == -1) return NULL; @@ -1167,9 +1167,8 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args) { const int size = self->size; PyObject *value = NULL; - float fac, ifac; - float *tvec, *vec; - int x; + float fac; + float *tvec; if (!PyArg_ParseTuple(args, "Of:lerp", &value, &fac)) return NULL; @@ -1182,23 +1181,9 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args) return NULL; } - vec = PyMem_Malloc(size * sizeof(float)); - if (vec == NULL) { - PyErr_SetString(PyExc_MemoryError, - "Vector.lerp(): " - "problem allocating pointer space"); - return NULL; - } - - ifac = 1.0f - fac; - - for (x = 0; x < size; x++) { - vec[x] = (ifac * self->vec[x]) + (fac * tvec[x]); - } - - PyMem_Free(tvec); + interp_vn_vn(tvec, self->vec, 1.0f - fac, size); - return Vector_CreatePyObject_alloc(vec, size, Py_TYPE(self)); + return Vector_CreatePyObject_alloc(tvec, size, Py_TYPE(self)); } PyDoc_STRVAR(Vector_slerp_doc, @@ -1302,7 +1287,7 @@ static PyObject *Vector_rotate(VectorObject *self, PyObject *value) { float other_rmat[3][3]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return NULL; if (mathutils_any_to_rotmat(other_rmat, value, "Vector.rotate(value)") == -1) @@ -1420,6 +1405,10 @@ static PyObject *Vector_item(VectorObject *self, int i) static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, const bool is_attr) { float scalar; + + if (BaseMath_Prepare_ForWrite(self) == -1) + return -1; + if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { /* parsed item not a number */ PyErr_SetString(PyExc_TypeError, "vector[index] = x: " @@ -1481,7 +1470,7 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *se int size = 0; float *vec = NULL; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; CLAMP(begin, 0, self->size); @@ -1574,7 +1563,7 @@ static PyObject *Vector_iadd(PyObject *v1, PyObject *v2) return NULL; } - if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) + if (BaseMath_ReadCallback_ForWrite(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) return NULL; add_vn_vn(vec1->vec, vec2->vec, vec1->size); @@ -1645,7 +1634,7 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2) return NULL; } - if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) + if (BaseMath_ReadCallback_ForWrite(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) return NULL; sub_vn_vn(vec1->vec, vec2->vec, vec1->size); @@ -1818,7 +1807,7 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2) VectorObject *vec = (VectorObject *)v1; float scalar; - if (BaseMath_ReadCallback(vec) == -1) + if (BaseMath_ReadCallback_ForWrite(vec) == -1) return NULL; /* only support vec*=float and vec*=mat @@ -1938,7 +1927,7 @@ static PyObject *Vector_idiv(PyObject *v1, PyObject *v2) float scalar; VectorObject *vec1 = (VectorObject *)v1; - if (BaseMath_ReadCallback(vec1) == -1) + if (BaseMath_ReadCallback_ForWrite(vec1) == -1) return NULL; if ((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) { /* parsed item not a number */ @@ -2062,6 +2051,17 @@ static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int compa } } +static Py_hash_t Vector_hash(VectorObject *self) +{ + if (BaseMath_ReadCallback(self) == -1) + return -1; + + if (BaseMathObject_Prepare_ForHash(self) == -1) + return -1; + + return mathutils_array_hash(self->vec, self->size); +} + /*-----------------PROTCOL DECLARATIONS--------------------------*/ static PySequenceMethods Vector_SeqMethods = { (lenfunc) Vector_len, /* sq_length */ @@ -2225,7 +2225,7 @@ static int Vector_length_set(VectorObject *self, PyObject *value) { double dot = 0.0f, param; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; if ((param = PyFloat_AsDouble(value)) == -1.0 && PyErr_Occurred()) { @@ -2331,7 +2331,7 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure float tvec[MAX_DIMENSIONS]; float vec_assign[MAX_DIMENSIONS]; - if (BaseMath_ReadCallback(self) == -1) + if (BaseMath_ReadCallback_ForWrite(self) == -1) return -1; /* Check that the closure can be used with this vector: even 2D vectors have @@ -2412,6 +2412,7 @@ static PyGetSetDef Vector_getseters[] = { {(char *)"length_squared", (getter)Vector_length_squared_get, (setter)NULL, Vector_length_squared_doc, NULL}, {(char *)"magnitude", (getter)Vector_length_get, (setter)Vector_length_set, Vector_length_doc, NULL}, {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL}, + {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL}, {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, /* autogenerated swizzle attrs, see python script below */ @@ -2890,6 +2891,9 @@ static struct PyMethodDef Vector_methods[] = { {"slerp", (PyCFunction) Vector_slerp, METH_VARARGS, Vector_slerp_doc}, {"rotate", (PyCFunction) Vector_rotate, METH_O, Vector_rotate_doc}, + /* base-math methods */ + {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc}, + {"copy", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc}, {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL}, {"__deepcopy__", (PyCFunction) Vector_deepcopy, METH_VARARGS, NULL}, @@ -2935,7 +2939,7 @@ PyTypeObject vector_Type = { /* More standard operations (here for binary compatibility) */ - NULL, /* hashfunc tp_hash; */ + (hashfunc)Vector_hash, /* hashfunc tp_hash; */ NULL, /* ternaryfunc tp_call; */ #ifndef MATH_STANDALONE (reprfunc)Vector_str, /* reprfunc tp_str; */ diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c index 48ef29150d3..ab680cbd15a 100644 --- a/source/blender/render/intern/source/bake_api.c +++ b/source/blender/render/intern/source/bake_api.c @@ -45,14 +45,14 @@ * * pixel_array is a Python object storing BakePixel elements: * - * <pre> + * \code{.c} * struct BakePixel { * int primitive_id; * float uv[2]; * float du_dx, du_dy; * float dv_dx, dv_dy; * }; - * </pre> + * \endcode * * In python you have access to: * - ``primitive_id``, ``uv``, ``du_dx``, ``du_dy``, ``next`` diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index caa2fd8f2f6..5204e9d2d1b 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -94,12 +94,12 @@ * </pre> * * A common way to get the space from the ScrArea: - * <pre> - * if (sa->spacetype == SPACE_VIEW3D) { - * View3D *v3d = sa->spacedata.first; - * ... - * } - * </pre> + * \code{.c} + * if (sa->spacetype == SPACE_VIEW3D) { + * View3D *v3d = sa->spacedata.first; + * ... + * } + * \endcode */ #ifdef __cplusplus diff --git a/source/creator/creator.c b/source/creator/creator.c index 23a32af4dd0..4b523b66b04 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -195,6 +195,7 @@ static void setCallbacks(void); #ifndef WITH_PYTHON_MODULE static bool use_crash_handler = true; +static bool use_abort_handler = true; /* set breakpoints here when running in debug mode, useful to catch floating point errors */ #if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE) @@ -418,6 +419,12 @@ static int disable_crash_handler(int UNUSED(argc), const char **UNUSED(argv), vo return 0; } +static int disable_abort_handler(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) +{ + use_abort_handler = false; + return 0; +} + static int background_mode(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { G.background = 1; @@ -590,6 +597,11 @@ static void blender_crash_handler(int signum) #endif } +static void blender_abort_handler(int UNUSED(signum)) +{ + /* Delete content of temp dir! */ + BKE_tempdir_session_purge(); +} static int set_factory_startup(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { @@ -1354,6 +1366,7 @@ static void setupArguments(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle) BLI_argsAdd(ba, 1, "-Y", "--disable-autoexec", "\n\tDisable automatic python script execution (pydrivers & startup scripts)" PY_DISABLE_AUTO, disable_python, NULL); BLI_argsAdd(ba, 1, NULL, "--disable-crash-handler", "\n\tDisable the crash handler", disable_crash_handler, NULL); + BLI_argsAdd(ba, 1, NULL, "--disable-abort-handler", "\n\tDisable the abort handler", disable_abort_handler, NULL); #undef PY_ENABLE_AUTO #undef PY_DISABLE_AUTO @@ -1614,6 +1627,10 @@ int main( /* after parsing args */ signal(SIGSEGV, blender_crash_handler); } + + if (use_abort_handler) { + signal(SIGABRT, blender_abort_handler); + } #else G.factory_startup = true; /* using preferences or user startup makes no sense for py-as-module */ (void)syshandle; diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index e01130a8970..bc2fc0179fd 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -234,6 +234,9 @@ BL_ArmatureObject::BL_ArmatureObject( // need this to get iTaSC working ok in the BGE m_pose->flag |= POSE_GAME_ENGINE; memcpy(m_obmat, m_objArma->obmat, sizeof(m_obmat)); + + // The side-effect of this method registers this object as "animatable" with the KX_Scene. + GetActionManager(); } BL_ArmatureObject::~BL_ArmatureObject() diff --git a/tests/gtests/blenlib/BLI_polyfill2d_test.cc b/tests/gtests/blenlib/BLI_polyfill2d_test.cc index fac5c6f7674..8ca19b11632 100644 --- a/tests/gtests/blenlib/BLI_polyfill2d_test.cc +++ b/tests/gtests/blenlib/BLI_polyfill2d_test.cc @@ -10,7 +10,7 @@ #define USE_BEAUTIFY extern "C" { -#include "BLI_array.h" +#include "BLI_array_utils.h" #include "BLI_polyfill2d.h" #include "BLI_math.h" #include "BLI_edgehash.h" |