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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntony Riakiotakis <kalast@gmail.com>2015-02-16 15:02:00 +0300
committerAntony Riakiotakis <kalast@gmail.com>2015-02-16 15:02:00 +0300
commit5a14dd7476a2c499da61ae0525f97f29cb4c3305 (patch)
treecee2bdcab4fbbc14a1db0610a3fed65643681cea
parent84ea48d58b90218f97025f94e0b924d7aea665cb (diff)
parent7c3d5a3337313663befef4c603341f6c1adf78b5 (diff)
Merge branch 'master' into gooseberry
Conflicts: source/blender/editors/space_sequencer/sequencer_draw.c
-rw-r--r--CMakeLists.txt16
-rw-r--r--build_files/cmake/Modules/FindJeMalloc.cmake1
-rw-r--r--build_files/cmake/Modules/FindSDL2.cmake72
-rw-r--r--intern/cycles/app/CMakeLists.txt4
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h12
-rw-r--r--intern/cycles/kernel/kernel_path.h12
-rw-r--r--intern/cycles/render/mesh.cpp147
-rw-r--r--intern/cycles/render/scene.cpp11
-rw-r--r--intern/cycles/util/CMakeLists.txt7
-rw-r--r--intern/cycles/util/util_aligned_malloc.cpp75
-rw-r--r--intern/cycles/util/util_aligned_malloc.h30
-rw-r--r--intern/cycles/util/util_guarded_allocator.cpp49
-rw-r--r--intern/cycles/util/util_guarded_allocator.h85
-rw-r--r--intern/cycles/util/util_sseb.h4
-rw-r--r--intern/cycles/util/util_ssef.h4
-rw-r--r--intern/cycles/util/util_ssei.h4
-rw-r--r--intern/cycles/util/util_vector.h88
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py2
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py28
-rw-r--r--source/blender/blenkernel/BKE_node.h69
-rw-r--r--source/blender/blenkernel/BKE_particle.h2
-rw-r--r--source/blender/blenkernel/intern/particle.c7
-rw-r--r--source/blender/blenkernel/intern/particle_system.c32
-rw-r--r--source/blender/blenkernel/intern/sca.c37
-rw-r--r--source/blender/blenlib/BLI_array.h71
-rw-r--r--source/blender/blenlib/BLI_array_utils.h41
-rw-r--r--source/blender/blenlib/BLI_buffer.h2
-rw-r--r--source/blender/blenlib/BLI_compiler_typecheck.h4
-rw-r--r--source/blender/blenlib/BLI_dial.h4
-rw-r--r--source/blender/blenlib/BLI_math_geom.h4
-rw-r--r--source/blender/blenlib/BLI_utildefines.h5
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_array.c57
-rw-r--r--source/blender/blenlib/intern/array_utils.c85
-rw-r--r--source/blender/blenlib/intern/math_geom.c57
-rw-r--r--source/blender/blenlib/intern/storage.c14
-rw-r--r--source/blender/blenloader/BLO_readfile.h1
-rw-r--r--source/blender/blenloader/intern/readfile.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c69
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h1
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c4
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c188
-rw-r--r--source/blender/editors/mesh/mesh_intern.h1
-rw-r--r--source/blender/editors/mesh/mesh_ops.c3
-rw-r--r--source/blender/editors/space_file/file_draw.c123
-rw-r--r--source/blender/editors/space_file/file_ops.c6
-rw-r--r--source/blender/editors/space_file/filelist.c145
-rw-r--r--source/blender/editors/space_graph/graph_select.c66
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c96
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c56
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h2
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c117
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c75
-rw-r--r--source/blender/editors/space_view3d/drawobject.c12
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c24
-rw-r--r--source/blender/editors/transform/transform.c104
-rw-r--r--source/blender/editors/transform/transform.h10
-rw-r--r--source/blender/makesdna/DNA_space_types.h5
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c12
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c564
-rw-r--r--source/blender/makesrna/intern/rna_space.c10
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c20
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c29
-rw-r--r--source/blender/python/mathutils/mathutils.c72
-rw-r--r--source/blender/python/mathutils/mathutils.h28
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c38
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c46
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c77
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c47
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c68
-rw-r--r--source/blender/render/intern/source/bake_api.c4
-rw-r--r--source/blender/windowmanager/WM_types.h12
-rw-r--r--source/creator/creator.c17
-rw-r--r--source/gameengine/Converter/BL_ArmatureObject.cpp3
-rw-r--r--tests/gtests/blenlib/BLI_polyfill2d_test.cc2
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"