diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2016-07-25 20:33:55 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2016-07-25 20:33:55 +0300 |
commit | bcc020b1bc1b60f6cbd6d2c9bf400744931e57e1 (patch) | |
tree | fef4d83d0e5addb59c8389adf125281a4c7e35f8 | |
parent | 99bb1accbbb8e1ba38f30b073b22deb107bf3220 (diff) | |
parent | 3f36cd3f33e52d53d82a3a221e2a576cf26390a5 (diff) |
Merge branch 'asset-engine' into asset-experimentsasset-experiments
Conflicts:
source/blender/blenloader/intern/readfile.c
323 files changed, 7196 insertions, 3468 deletions
diff --git a/.gitmodules b/.gitmodules index 132f6cffada..0b8228e3f14 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,7 @@ path = release/datafiles/locale url = ../blender-translations.git ignore = all +[submodule "source/tools"] + path = source/tools + url = ../blender-dev-tools.git + ignore = all diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c933d38ab9..1dfa838a5a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1283,11 +1283,21 @@ elseif(WIN32) if(MSVC) # Minimum MSVC Version - set(_min_ver "18.0.31101") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver}) - message(FATAL_ERROR - "Visual Studio 2013 (Update 4, ${_min_ver}) required, " - "found (${CMAKE_CXX_COMPILER_VERSION})") + if(MSVC_VERSION EQUAL 1800) + set(_min_ver "18.0.31101") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver}) + message(FATAL_ERROR + "Visual Studio 2013 (Update 4, ${_min_ver}) required, " + "found (${CMAKE_CXX_COMPILER_VERSION})") + endif() + endif() + if(MSVC_VERSION EQUAL 1900) + set(_min_ver "19.0.24210") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver}) + message(FATAL_ERROR + "Visual Studio 2015 (Update 3, ${_min_ver}) required, " + "found (${CMAKE_CXX_COMPILER_VERSION})") + endif() endif() unset(_min_ver) @@ -1353,17 +1363,6 @@ elseif(WIN32) set(PLATFORM_LINKFLAGS_DEBUG "/IGNORE:4099 /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libc.lib") - # Use dynamic loading for OpenMP - if(WITH_OPENMP) - if(MSVC_VERSION EQUAL 1800) - set(OPENMP_DLL_NAME "vcomp120") - else() - set(OPENMP_DLL_NAME "vcomp140") - endif() - set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib") - set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib") - endif() - if(NOT DEFINED LIBDIR) # Setup 64bit and 64bit windows systems @@ -3162,6 +3161,14 @@ add_subdirectory(tests) # CPack for generating packages include(build_files/cmake/packaging.cmake) +#----------------------------------------------------------------------------- +# Use dynamic loading for OpenMP +if(WITH_BLENDER) + openmp_delayload(blender) +endif(WITH_BLENDER) +if(WITH_PLAYER) + openmp_delayload(blenderplayer) +endif(WITH_PLAYER) #----------------------------------------------------------------------------- # Print Final Configuration diff --git a/GNUmakefile b/GNUmakefile index d9c895c214a..1fda1a25a92 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -182,14 +182,20 @@ help: .FORCE @echo " * package_archive - build an archive package" @echo "" @echo "Testing Targets (not associated with building blender)" - @echo " * test - run ctest, currently tests import/export, operator execution and that python modules load" - @echo " * test_cmake - runs our own cmake file checker which detects errors in the cmake file list definitions" - @echo " * test_pep8 - checks all python script are pep8 which are tagged to use the stricter formatting" + @echo " * test - run ctest, currently tests import/export," + @echo " operator execution and that python modules load" + @echo " * test_cmake - runs our own cmake file checker" + @echo " which detects errors in the cmake file list definitions" + @echo " * test_pep8 - checks all python script are pep8" + @echo " which are tagged to use the stricter formatting" @echo " * test_deprecated - checks for deprecation tags in our code which may need to be removed" - @echo " * test_style_c - checks C/C++ conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" + @echo " * test_style_c - checks C/C++ conforms with blenders style guide:" + @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" @echo " * test_style_c_qtc - same as test_style but outputs QtCreator tasks format" - @echo " * test_style_osl - checks OpenShadingLanguage conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" - @echo " * test_style_osl_qtc - checks OpenShadingLanguage conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" + @echo " * test_style_osl - checks OpenShadingLanguage conforms with blenders style guide:" + @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" + @echo " * test_style_osl_qtc - checks OpenShadingLanguage conforms with blenders style guide:" + @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" @echo "" @echo "Static Source Code Checking (not associated with building blender)" @echo " * check_cppcheck - run blender source through cppcheck (C & C++)" @@ -405,7 +411,8 @@ update: .FORCE # Simple version of ./doc/python_api/sphinx_doc_gen.sh with no PDF generation. doc_py: .FORCE - "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup --python doc/python_api/sphinx_doc_gen.py + "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup \ + --python doc/python_api/sphinx_doc_gen.py cd doc/python_api ; sphinx-build -b html sphinx-in sphinx-out @echo "docs written into: '$(BLENDER_DIR)/doc/python_api/sphinx-out/contents.html'" @@ -414,7 +421,8 @@ doc_doxy: .FORCE @echo "docs written into: '$(BLENDER_DIR)/doc/doxygen/html/index.html'" doc_dna: .FORCE - "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup --python doc/blender_file_format/BlendFileDnaExporter_25.py + "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup \ + --python doc/blender_file_format/BlendFileDnaExporter_25.py @echo "docs written into: '$(BLENDER_DIR)/doc/blender_file_format/dna.html'" doc_man: .FORCE diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index d29f086069a..f57a6952164 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -196,8 +196,33 @@ function(blender_source_group endfunction() +# Support per-target CMake flags +# Read from: CMAKE_C_FLAGS_**** (made upper case) when set. +# +# 'name' should alway match the target name, +# use this macro before add_library or add_executable. +# +# Optionally takes an arg passed to set(), eg PARENT_SCOPE. +macro(add_cc_flags_custom_test + name + ) + + string(TOUPPER ${name} _name_upper) + if(DEFINED CMAKE_C_FLAGS_${_name_upper}) + message(STATUS "Using custom CFLAGS: CMAKE_C_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${_name_upper}}" ${ARGV1}) + endif() + if(DEFINED CMAKE_CXX_FLAGS_${_name_upper}) + message(STATUS "Using custom CXXFLAGS: CMAKE_CXX_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${_name_upper}}" ${ARGV1}) + endif() + unset(_name_upper) + +endmacro() + + # only MSVC uses SOURCE_GROUP -function(blender_add_lib_nolist +function(blender_add_lib__impl name sources includes @@ -225,6 +250,18 @@ function(blender_add_lib_nolist endfunction() +function(blender_add_lib_nolist + name + sources + includes + includes_sys + ) + + add_cc_flags_custom_test(${name} PARENT_SCOPE) + + blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}") +endfunction() + function(blender_add_lib name sources @@ -232,7 +269,9 @@ function(blender_add_lib includes_sys ) - blender_add_lib_nolist(${name} "${sources}" "${includes}" "${includes_sys}") + add_cc_flags_custom_test(${name} PARENT_SCOPE) + + blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}") set_property(GLOBAL APPEND PROPERTY BLENDER_LINK_LIBS ${name}) endfunction() @@ -1508,3 +1547,21 @@ function(print_all_vars) message("${_var}=${${_var}}") endforeach() endfunction() + +macro(openmp_delayload + projectname + ) + if(MSVC) + if(WITH_OPENMP) + if(MSVC_VERSION EQUAL 1800) + set(OPENMP_DLL_NAME "vcomp120") + else() + set(OPENMP_DLL_NAME "vcomp140") + endif() + SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELEASE "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib") + SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_DEBUG "/DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib") + SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib") + SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_MINSIZEREL "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib") + endif(WITH_OPENMP) + endif(MSVC) +endmacro() diff --git a/extern/curve_fit_nd/CMakeLists.txt b/extern/curve_fit_nd/CMakeLists.txt index 6669971aa2d..cc9efe1c470 100644 --- a/extern/curve_fit_nd/CMakeLists.txt +++ b/extern/curve_fit_nd/CMakeLists.txt @@ -26,10 +26,14 @@ set(INC_SYS set(SRC intern/curve_fit_cubic.c + intern/curve_fit_cubic_refit.c intern/curve_fit_corners_detect.c - intern/curve_fit_inline.h curve_fit_nd.h + intern/curve_fit_inline.h + intern/generic_alloc_impl.h + intern/generic_heap.c + intern/generic_heap.h ) blender_add_lib(extern_curve_fit_nd "${SRC}" "${INC}" "${INC_SYS}") diff --git a/extern/curve_fit_nd/curve_fit_nd.h b/extern/curve_fit_nd/curve_fit_nd.h index 3649802a425..cfb1881fe00 100644 --- a/extern/curve_fit_nd/curve_fit_nd.h +++ b/extern/curve_fit_nd/curve_fit_nd.h @@ -86,6 +86,7 @@ int curve_fit_cubic_to_points_fl( * * \param points, points_len: The array of points to calculate a cubics from. * \param dims: The number of dimensions for for each element in \a points. + * \param points_length_cache: Optional pre-calculated lengths between points. * \param error_threshold: the error threshold to allow for, * \param tan_l, tan_r: Normalized tangents the handles will be aligned to. * Note that tangents must both point along the direction of the \a points, @@ -98,6 +99,7 @@ int curve_fit_cubic_to_points_fl( int curve_fit_cubic_to_points_single_db( const double *points, const unsigned int points_len, + const double *points_length_cache, const unsigned int dims, const double error_threshold, const double tan_l[], @@ -110,6 +112,7 @@ int curve_fit_cubic_to_points_single_db( int curve_fit_cubic_to_points_single_fl( const float *points, const unsigned int points_len, + const float *points_length_cache, const unsigned int dims, const float error_threshold, const float tan_l[], @@ -121,8 +124,40 @@ int curve_fit_cubic_to_points_single_fl( enum { CURVE_FIT_CALC_HIGH_QUALIY = (1 << 0), + CURVE_FIT_CALC_CYCLIC = (1 << 1), }; + +/* curve_fit_cubic_refit.c */ + +int curve_fit_cubic_to_points_refit_db( + const double *points, + const unsigned int points_len, + const unsigned int dims, + const double error_threshold, + const unsigned int calc_flag, + const unsigned int *corners, + unsigned int corners_len, + const double corner_angle, + + double **r_cubic_array, unsigned int *r_cubic_array_len, + unsigned int **r_cubic_orig_index, + unsigned int **r_corner_index_array, unsigned int *r_corner_index_len); + +int curve_fit_cubic_to_points_refit_fl( + const float *points, + const unsigned int points_len, + const unsigned int dims, + const float error_threshold, + const unsigned int calc_flag, + const unsigned int *corners, + unsigned int corners_len, + const float corner_angle, + + float **r_cubic_array, unsigned int *r_cubic_array_len, + unsigned int **r_cubic_orig_index, + unsigned int **r_corner_index_array, unsigned int *r_corner_index_len); + /* curve_fit_corners_detect.c */ /** diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic.c b/extern/curve_fit_nd/intern/curve_fit_cubic.c index 1a0f7dcfdee..24b216d32ff 100644 --- a/extern/curve_fit_nd/intern/curve_fit_cubic.c +++ b/extern/curve_fit_nd/intern/curve_fit_cubic.c @@ -474,7 +474,7 @@ static double points_calc_circumference_factor( * We could try support this but will likely cause extreme >1 scales which could cause other issues. */ // assert(angle >= len_tangent); double factor = (angle / len_tangent); - assert(factor < (M_PI / 2) + DBL_EPSILON); + assert(factor < (M_PI / 2) + (DBL_EPSILON * 10)); return factor; } else { @@ -876,7 +876,6 @@ static double points_calc_coord_length( #ifdef USE_LENGTH_CACHE length = points_length_cache[i]; - assert(len_vnvn(pt, pt_prev, dims) == points_length_cache[i]); #else length = len_vnvn(pt, pt_prev, dims); @@ -1435,6 +1434,7 @@ int curve_fit_cubic_to_points_fl( int curve_fit_cubic_to_points_single_db( const double *points, const uint points_len, + const double *points_length_cache, const uint dims, const double error_threshold, const double tan_l[], @@ -1451,10 +1451,14 @@ int curve_fit_cubic_to_points_single_db( /* in this instance theres no advantage in using length cache, * since we're not recursively calculating values. */ #ifdef USE_LENGTH_CACHE - double *points_length_cache = malloc(sizeof(double) * points_len); - points_calc_coord_length_cache( - points, points_len, dims, - points_length_cache); + double *points_length_cache_alloc = NULL; + if (points_length_cache == NULL) { + points_length_cache_alloc = malloc(sizeof(double) * points_len); + points_calc_coord_length_cache( + points, points_len, dims, + points_length_cache_alloc); + points_length_cache = points_length_cache_alloc; + } #endif fit_cubic_to_points( @@ -1467,7 +1471,9 @@ int curve_fit_cubic_to_points_single_db( cubic, r_error_max_sq, &split_index); #ifdef USE_LENGTH_CACHE - free(points_length_cache); + if (points_length_cache_alloc) { + free(points_length_cache_alloc); + } #endif copy_vnvn(r_handle_l, CUBIC_PT(cubic, 1, dims), dims); @@ -1479,6 +1485,7 @@ int curve_fit_cubic_to_points_single_db( int curve_fit_cubic_to_points_single_fl( const float *points, const uint points_len, + const float *points_length_cache, const uint dims, const float error_threshold, const float tan_l[], @@ -1490,9 +1497,15 @@ int curve_fit_cubic_to_points_single_fl( { const uint points_flat_len = points_len * dims; double *points_db = malloc(sizeof(double) * points_flat_len); + double *points_length_cache_db = NULL; copy_vndb_vnfl(points_db, points, points_flat_len); + if (points_length_cache) { + points_length_cache_db = malloc(sizeof(double) * points_len); + copy_vndb_vnfl(points_length_cache_db, points_length_cache, points_len); + } + #ifdef USE_VLA double tan_l_db[dims]; double tan_r_db[dims]; @@ -1510,7 +1523,7 @@ int curve_fit_cubic_to_points_single_fl( copy_vndb_vnfl(tan_r_db, tan_r, dims); int result = curve_fit_cubic_to_points_single_db( - points_db, points_len, dims, + points_db, points_len, points_length_cache_db, dims, (double)error_threshold, tan_l_db, tan_r_db, r_handle_l_db, r_handle_r_db, @@ -1518,6 +1531,10 @@ int curve_fit_cubic_to_points_single_fl( free(points_db); + if (points_length_cache_db) { + free(points_length_cache_db); + } + copy_vnfl_vndb(r_handle_l, r_handle_l_db, dims); copy_vnfl_vndb(r_handle_r, r_handle_r_db, dims); *r_error_sq = (float)r_error_sq_db; diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c new file mode 100644 index 00000000000..46445467869 --- /dev/null +++ b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c @@ -0,0 +1,1420 @@ +/* + * Copyright (c) 2016, Campbell Barton. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the <organization> nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Curve Re-fitting Method + * ======================= + * + * This is a more processor intensive method of fitting, + * compared to #curve_fit_cubic_to_points_db, and works as follows: + * + * - First iteratively remove all points under the error threshold. + * - If corner calculation is enabled: + * - Find adjacent knots that exceed the angle limit + * - Find a 'split' point between the knots (could include the knots) + * - If copying the tangents to this split point doesn't exceed the error threshold: + * - Assign the tangents of the two knots to the split point, define it as a corner. + * (after this, we have many points which are too close). + * - Run a re-fit pass, where knots are re-positioned between their adjacent knots + * when their re-fit position has a lower 'error'. + * While re-fitting, remove knots that fall below the error threshold. + */ + +#include <math.h> +#include <float.h> +#include <stdbool.h> +#include <assert.h> + +#include <string.h> +#include <stdlib.h> + +typedef unsigned int uint; + +#include "curve_fit_inline.h" +#include "../curve_fit_nd.h" + +#include "generic_heap.h" + +#ifdef _MSC_VER +# define alloca(size) _alloca(size) +#endif + +#if !defined(_MSC_VER) +# define USE_VLA +#endif + +#ifdef USE_VLA +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wvla" +# endif +#else +# ifdef __GNUC__ +# pragma GCC diagnostic error "-Wvla" +# endif +#endif + +/* adjust the knots after simplifying */ +#define USE_KNOT_REFIT +/* remove knots under the error threshold while re-fitting */ +#define USE_KNOT_REFIT_REMOVE +/* detect corners over an angle threshold */ +#define USE_CORNER_DETECT +/* avoid re-calculating lengths multiple times */ +#define USE_LENGTH_CACHE +/* use pool allocator */ +#define USE_TPOOL + + +#define SPLIT_POINT_INVALID ((uint)-1) + +#define MAX2(x, y) ((x) > (y) ? (x) : (y)) + +#define SQUARE(a) ((a) * (a)) + +#ifdef __GNUC__ +# define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +# define UNLIKELY(x) (x) +#endif + +struct PointData { + const double *points; + uint points_len; +#ifdef USE_LENGTH_CACHE + const double *points_length_cache; +#endif +}; + +struct Knot { + struct Knot *next, *prev; + + HeapNode *heap_node; + + /** + * Currently the same, access as different for now + * since we may want to support different point/knot indices + */ + uint index; + + uint can_remove : 1; + uint is_removed : 1; + uint is_corner : 1; + + double handles[2]; + /** + * Store the error value, to see if we can improve on it + * (without having to re-calculate each time) + * + * This is the error between this knot and the next */ + double error_sq_next; + + /* Initially point to contiguous memory, however we may re-assign */ + double *tan[2]; +} Knot; + + +struct KnotRemoveState { + uint index; + /* Handles for prev/next knots */ + double handles[2]; +}; + +#ifdef USE_TPOOL +/* rstate_* pool allocator */ +#define TPOOL_IMPL_PREFIX rstate +#define TPOOL_ALLOC_TYPE struct KnotRemoveState +#define TPOOL_STRUCT ElemPool_KnotRemoveState +#include "generic_alloc_impl.h" +#undef TPOOL_IMPL_PREFIX +#undef TPOOL_ALLOC_TYPE +#undef TPOOL_STRUCT +#endif /* USE_TPOOL */ + +#ifdef USE_KNOT_REFIT +struct KnotRefitState { + uint index; + /** When SPLIT_POINT_INVALID - remove this item */ + uint index_refit; + /** Handles for prev/next knots */ + double handles_prev[2], handles_next[2]; + double error_sq[2]; +}; + +#ifdef USE_TPOOL +/* refit_* pool allocator */ +#define TPOOL_IMPL_PREFIX refit +#define TPOOL_ALLOC_TYPE struct KnotRefitState +#define TPOOL_STRUCT ElemPool_KnotRefitState +#include "generic_alloc_impl.h" +#undef TPOOL_IMPL_PREFIX +#undef TPOOL_ALLOC_TYPE +#undef TPOOL_STRUCT +#endif /* USE_TPOOL */ +#endif /* USE_KNOT_REFIT */ + + +#ifdef USE_CORNER_DETECT +/** Result of collapsing a corner. */ +struct KnotCornerState { + uint index; + /* Merge adjacent handles into this one (may be shared with the 'index') */ + uint index_adjacent[2]; + + /* Handles for prev/next knots */ + double handles_prev[2], handles_next[2]; + double error_sq[2]; +}; + +/* refit_* pool allocator */ +#ifdef USE_TPOOL +#define TPOOL_IMPL_PREFIX corner +#define TPOOL_ALLOC_TYPE struct KnotCornerState +#define TPOOL_STRUCT ElemPool_KnotCornerState +#include "generic_alloc_impl.h" +#undef TPOOL_IMPL_PREFIX +#undef TPOOL_ALLOC_TYPE +#undef TPOOL_STRUCT +#endif /* USE_TPOOL */ +#endif /* USE_CORNER_DETECT */ + + +/* Utility functions */ + +#ifdef USE_KNOT_REFIT +/** + * Find the most distant point between the 2 knots. + */ +static uint knot_find_split_point( + const struct PointData *pd, + const struct Knot *knot_l, const struct Knot *knot_r, + const uint knots_len, + const uint dims) +{ + uint split_point = SPLIT_POINT_INVALID; + double split_point_dist_best = -DBL_MAX; + + const double *offset = &pd->points[knot_l->index * dims]; + +#ifdef USE_VLA + double v_plane[dims]; + double v_proj[dims]; + double v_offset[dims]; +#else + double *v_plane = alloca(sizeof(double) * dims); + double *v_proj = alloca(sizeof(double) * dims); + double *v_offset = alloca(sizeof(double) * dims); +#endif + + sub_vn_vnvn( + v_plane, + &pd->points[knot_l->index * dims], + &pd->points[knot_r->index * dims], + dims); + + normalize_vn(v_plane, dims); + + const uint knots_end = knots_len - 1; + const struct Knot *k_step = knot_l; + do { + if (k_step->index != knots_end) { + k_step += 1; + } + else { + /* wrap around */ + k_step = k_step - knots_end; + } + + if (k_step != knot_r) { + sub_vn_vnvn(v_offset, &pd->points[k_step->index * dims], offset, dims); + project_plane_vn_vnvn_normalized(v_proj, v_offset, v_plane, dims); + + double split_point_dist_test = len_squared_vn(v_proj, dims); + if (split_point_dist_test > split_point_dist_best) { + split_point_dist_best = split_point_dist_test; + split_point = k_step->index; + } + } + else { + break; + } + + } while (true); + + return split_point; +} +#endif /* USE_KNOT_REFIT */ + + +#ifdef USE_CORNER_DETECT +/** + * Find the knot furthest from the line between \a knot_l & \a knot_r. + * This is to be used as a split point. + */ +static uint knot_find_split_point_on_axis( + const struct PointData *pd, + const struct Knot *knot_l, const struct Knot *knot_r, + const uint knots_len, + const double *plane_no, + const uint dims) +{ + uint split_point = SPLIT_POINT_INVALID; + double split_point_dist_best = -DBL_MAX; + + const uint knots_end = knots_len - 1; + const struct Knot *k_step = knot_l; + do { + if (k_step->index != knots_end) { + k_step += 1; + } + else { + /* wrap around */ + k_step = k_step - knots_end; + } + + if (k_step != knot_r) { + double split_point_dist_test = dot_vnvn(plane_no, &pd->points[k_step->index * dims], dims); + if (split_point_dist_test > split_point_dist_best) { + split_point_dist_best = split_point_dist_test; + split_point = k_step->index; + } + } + else { + break; + } + + } while (true); + + return split_point; +} +#endif /* USE_CORNER_DETECT */ + + +static double knot_remove_error_value( + const double *tan_l, const double *tan_r, + const double *points_offset, const uint points_offset_len, + const double *points_offset_length_cache, + const uint dims, + /* Avoid having to re-calculate again */ + double r_handle_factors[2]) +{ + double error_sq = FLT_MAX; + +#ifdef USE_VLA + double handle_factor_l[dims]; + double handle_factor_r[dims]; +#else + double *handle_factor_l = alloca(sizeof(double) * dims); + double *handle_factor_r = alloca(sizeof(double) * dims); +#endif + + curve_fit_cubic_to_points_single_db( + points_offset, points_offset_len, points_offset_length_cache, dims, 0.0, + tan_l, tan_r, + handle_factor_l, handle_factor_r, + &error_sq); + + assert(error_sq != FLT_MAX); + + isub_vnvn(handle_factor_l, points_offset, dims); + r_handle_factors[0] = dot_vnvn(tan_l, handle_factor_l, dims); + + isub_vnvn(handle_factor_r, &points_offset[(points_offset_len - 1) * dims], dims); + r_handle_factors[1] = dot_vnvn(tan_r, handle_factor_r, dims); + + return error_sq; +} + +static double knot_calc_curve_error_value( + const struct PointData *pd, + const struct Knot *knot_l, const struct Knot *knot_r, + const double *tan_l, const double *tan_r, + const uint dims, + double r_handle_factors[2]) +{ + const uint points_offset_len = ((knot_l->index < knot_r->index) ? + (knot_r->index - knot_l->index) : + ((knot_r->index + pd->points_len) - knot_l->index)) + 1; + + if (points_offset_len != 2) { + return knot_remove_error_value( + tan_l, tan_r, + &pd->points[knot_l->index * dims], points_offset_len, +#ifdef USE_LENGTH_CACHE + &pd->points_length_cache[knot_l->index], +#else + NULL, +#endif + dims, + r_handle_factors); + } + else { + /* No points between, use 1/3 handle length with no error as a fallback. */ + assert(points_offset_len == 2); +#ifdef USE_LENGTH_CACHE + r_handle_factors[0] = r_handle_factors[1] = pd->points_length_cache[knot_l->index] / 3.0; +#else + r_handle_factors[0] = r_handle_factors[1] = len_vnvn( + &pd->points[(knot_l->index + 0) * dims], + &pd->points[(knot_l->index + 1) * dims], dims) / 3.0; +#endif + return 0.0; + } +} + +struct KnotRemove_Params { + Heap *heap; + const struct PointData *pd; +#ifdef USE_TPOOL + struct ElemPool_KnotRemoveState *epool; +#endif +}; + +static void knot_remove_error_recalculate( + struct KnotRemove_Params *p, + struct Knot *k, const double error_sq_max, + const uint dims) +{ + assert(k->can_remove); + double handles[2]; + + const double cost_sq = knot_calc_curve_error_value( + p->pd, k->prev, k->next, + k->prev->tan[1], k->next->tan[0], + dims, + handles); + + if (cost_sq < error_sq_max) { + struct KnotRemoveState *r; + if (k->heap_node) { + r = HEAP_node_ptr(k->heap_node); + HEAP_remove(p->heap, k->heap_node); + } + else { +#ifdef USE_TPOOL + r = rstate_pool_elem_alloc(p->epool); +#else + r = malloc(sizeof(*r)); +#endif + + r->index = k->index; + } + + r->handles[0] = handles[0]; + r->handles[1] = handles[1]; + + k->heap_node = HEAP_insert(p->heap, cost_sq, r); + } + else { + if (k->heap_node) { + struct KnotRemoveState *r; + r = HEAP_node_ptr(k->heap_node); + HEAP_remove(p->heap, k->heap_node); + +#ifdef USE_TPOOL + rstate_pool_elem_free(p->epool, r); +#else + free(r); +#endif + + k->heap_node = NULL; + } + } +} + +/** + * Return length after being reduced. + */ +static uint curve_incremental_simplify( + const struct PointData *pd, + struct Knot *knots, const uint knots_len, uint knots_len_remaining, + double error_sq_max, const uint dims) +{ + +#ifdef USE_TPOOL + struct ElemPool_KnotRemoveState epool; + + rstate_pool_create(&epool, 0); +#endif + + Heap *heap = HEAP_new(knots_len); + + struct KnotRemove_Params params = { + .pd = pd, + .heap = heap, +#ifdef USE_TPOOL + .epool = &epool, +#endif + }; + + for (uint i = 0; i < knots_len; i++) { + struct Knot *k = &knots[i]; + if (k->can_remove && (k->is_removed == false) && (k->is_corner == false)) { + knot_remove_error_recalculate(¶ms, k, error_sq_max, dims); + } + } + + while (HEAP_is_empty(heap) == false) { + struct Knot *k; + + { + const double error_sq = HEAP_top_value(heap); + struct KnotRemoveState *r = HEAP_popmin(heap); + k = &knots[r->index]; + k->heap_node = NULL; + k->prev->handles[1] = r->handles[0]; + k->next->handles[0] = r->handles[1]; + + k->prev->error_sq_next = error_sq; + +#ifdef USE_TPOOL + rstate_pool_elem_free(&epool, r); +#else + free(r); +#endif + } + + if (UNLIKELY(knots_len_remaining <= 2)) { + continue; + } + + struct Knot *k_prev = k->prev; + struct Knot *k_next = k->next; + + /* Remove ourselves */ + k_next->prev = k_prev; + k_prev->next = k_next; + + k->next = NULL; + k->prev = NULL; + k->is_removed = true; + + if (k_prev->can_remove && (k_prev->is_corner == false) && (k_prev->prev && k_prev->next)) { + knot_remove_error_recalculate(¶ms, k_prev, error_sq_max, dims); + } + + if (k_next->can_remove && (k_next->is_corner == false) && (k_next->prev && k_next->next)) { + knot_remove_error_recalculate(¶ms, k_next, error_sq_max, dims); + } + + knots_len_remaining -= 1; + } + +#ifdef USE_TPOOL + rstate_pool_destroy(&epool); +#endif + + HEAP_free(heap, free); + + return knots_len_remaining; +} + + +#ifdef USE_KNOT_REFIT + +struct KnotRefit_Params { + Heap *heap; + const struct PointData *pd; +#ifdef USE_TPOOL + struct ElemPool_KnotRefitState *epool; +#endif +}; + +static void knot_refit_error_recalculate( + struct KnotRefit_Params *p, + struct Knot *knots, const uint knots_len, + struct Knot *k, + const double error_sq_max, + const uint dims) +{ + assert(k->can_remove); + +#ifdef USE_KNOT_REFIT_REMOVE + { + double handles[2]; + + /* First check if we can remove, this allows to refit and remove as we go. */ + const double cost_sq = knot_calc_curve_error_value( + p->pd, k->prev, k->next, + k->prev->tan[1], k->next->tan[0], + dims, + handles); + + if (cost_sq < error_sq_max) { + struct KnotRefitState *r; + if (k->heap_node) { + r = HEAP_node_ptr(k->heap_node); + HEAP_remove(p->heap, k->heap_node); + } + else { +#ifdef USE_TPOOL + r = refit_pool_elem_alloc(p->epool); +#else + r = malloc(sizeof(*r)); +#endif + r->index = k->index; + } + + r->index_refit = SPLIT_POINT_INVALID; + + r->handles_prev[0] = handles[0]; + r->handles_prev[1] = 0.0; /* unused */ + r->handles_next[0] = 0.0; /* unused */ + r->handles_next[1] = handles[1]; + + r->error_sq[0] = r->error_sq[1] = cost_sq; + + /* Always perform removal before refitting, (make a negative number) */ + k->heap_node = HEAP_insert(p->heap, cost_sq - error_sq_max, r); + + return; + } + } +#else + (void)error_sq_max; +#endif /* USE_KNOT_REFIT_REMOVE */ + + const uint refit_index = knot_find_split_point( + p->pd, k->prev, k->next, + knots_len, + dims); + + if ((refit_index == SPLIT_POINT_INVALID) || + (refit_index == k->index)) + { + goto remove; + } + + struct Knot *k_refit = &knots[refit_index]; + + const double cost_sq_src_max = MAX2(k->prev->error_sq_next, k->error_sq_next); + assert(cost_sq_src_max <= error_sq_max); + + double cost_sq_dst[2]; + double handles_prev[2], handles_next[2]; + + if ((((cost_sq_dst[0] = knot_calc_curve_error_value( + p->pd, k->prev, k_refit, + k->prev->tan[1], k_refit->tan[0], + dims, + handles_prev)) < cost_sq_src_max) && + ((cost_sq_dst[1] = knot_calc_curve_error_value( + p->pd, k_refit, k->next, + k_refit->tan[1], k->next->tan[0], + dims, + handles_next)) < cost_sq_src_max))) + { + { + struct KnotRefitState *r; + if (k->heap_node) { + r = HEAP_node_ptr(k->heap_node); + HEAP_remove(p->heap, k->heap_node); + } + else { +#ifdef USE_TPOOL + r = refit_pool_elem_alloc(p->epool); +#else + r = malloc(sizeof(*r)); +#endif + r->index = k->index; + } + + r->index_refit = refit_index; + + r->handles_prev[0] = handles_prev[0]; + r->handles_prev[1] = handles_prev[1]; + + r->handles_next[0] = handles_next[0]; + r->handles_next[1] = handles_next[1]; + + r->error_sq[0] = cost_sq_dst[0]; + r->error_sq[1] = cost_sq_dst[1]; + + const double cost_sq_dst_max = MAX2(cost_sq_dst[0], cost_sq_dst[1]); + + assert(cost_sq_dst_max < cost_sq_src_max); + + /* Weight for the greatest improvement */ + k->heap_node = HEAP_insert(p->heap, cost_sq_src_max - cost_sq_dst_max, r); + } + } + else { +remove: + if (k->heap_node) { + struct KnotRefitState *r; + r = HEAP_node_ptr(k->heap_node); + HEAP_remove(p->heap, k->heap_node); + +#ifdef USE_TPOOL + refit_pool_elem_free(p->epool, r); +#else + free(r); +#endif + + k->heap_node = NULL; + } + } +} + +/** + * Re-adjust the curves by re-fitting points. + * test the error from moving using points between the adjacent. + */ +static uint curve_incremental_simplify_refit( + const struct PointData *pd, + struct Knot *knots, const uint knots_len, uint knots_len_remaining, + const double error_sq_max, + const uint dims) +{ +#ifdef USE_TPOOL + struct ElemPool_KnotRefitState epool; + + refit_pool_create(&epool, 0); +#endif + + Heap *heap = HEAP_new(knots_len); + + struct KnotRefit_Params params = { + .pd = pd, + .heap = heap, +#ifdef USE_TPOOL + .epool = &epool, +#endif + }; + + for (uint i = 0; i < knots_len; i++) { + struct Knot *k = &knots[i]; + if (k->can_remove && + (k->is_removed == false) && + (k->is_corner == false) && + (k->prev && k->next)) + { + knot_refit_error_recalculate(¶ms, knots, knots_len, k, error_sq_max, dims); + } + } + + while (HEAP_is_empty(heap) == false) { + struct Knot *k_old, *k_refit; + + { + struct KnotRefitState *r = HEAP_popmin(heap); + k_old = &knots[r->index]; + k_old->heap_node = NULL; + +#ifdef USE_KNOT_REFIT_REMOVE + if (r->index_refit == SPLIT_POINT_INVALID) { + k_refit = NULL; + } + else +#endif + { + k_refit = &knots[r->index_refit]; + k_refit->handles[0] = r->handles_prev[1]; + k_refit->handles[1] = r->handles_next[0]; + } + + k_old->prev->handles[1] = r->handles_prev[0]; + k_old->next->handles[0] = r->handles_next[1]; + +#ifdef USE_TPOOL + refit_pool_elem_free(&epool, r); +#else + free(r); +#endif + } + + if (UNLIKELY(knots_len_remaining <= 2)) { + continue; + } + + struct Knot *k_prev = k_old->prev; + struct Knot *k_next = k_old->next; + + k_old->next = NULL; + k_old->prev = NULL; + k_old->is_removed = true; + +#ifdef USE_KNOT_REFIT_REMOVE + if (k_refit == NULL) { + k_next->prev = k_prev; + k_prev->next = k_next; + + knots_len_remaining -= 1; + } + else +#endif + { + /* Remove ourselves */ + k_next->prev = k_refit; + k_prev->next = k_refit; + + k_refit->prev = k_prev; + k_refit->next = k_next; + k_refit->is_removed = false; + } + + if (k_prev->can_remove && (k_prev->is_corner == false) && (k_prev->prev && k_prev->next)) { + knot_refit_error_recalculate(¶ms, knots, knots_len, k_prev, error_sq_max, dims); + } + + if (k_next->can_remove && (k_next->is_corner == false) && (k_next->prev && k_next->next)) { + knot_refit_error_recalculate(¶ms, knots, knots_len, k_next, error_sq_max, dims); + } + } + +#ifdef USE_TPOOL + refit_pool_destroy(&epool); +#endif + + HEAP_free(heap, free); + + return knots_len_remaining; +} + +#endif /* USE_KNOT_REFIT */ + + +#ifdef USE_CORNER_DETECT + +struct KnotCorner_Params { + Heap *heap; + const struct PointData *pd; +#ifdef USE_TPOOL + struct ElemPool_KnotCornerState *epool; +#endif +}; + +/** + * (Re)calculate the error incurred from turning this into a corner. + */ +static void knot_corner_error_recalculate( + struct KnotCorner_Params *p, + struct Knot *k_split, + struct Knot *k_prev, struct Knot *k_next, + const double error_sq_max, + const uint dims) +{ + assert(k_prev->can_remove && k_next->can_remove); + + double handles_prev[2], handles_next[2]; + /* Test skipping 'k_prev' by using points (k_prev->prev to k_split) */ + double cost_sq_dst[2]; + + if (((cost_sq_dst[0] = knot_calc_curve_error_value( + p->pd, k_prev, k_split, + k_prev->tan[1], k_prev->tan[1], + dims, + handles_prev)) < error_sq_max) && + ((cost_sq_dst[1] = knot_calc_curve_error_value( + p->pd, k_split, k_next, + k_next->tan[0], k_next->tan[0], + dims, + handles_next)) < error_sq_max)) + { + struct KnotCornerState *c; + if (k_split->heap_node) { + c = HEAP_node_ptr(k_split->heap_node); + HEAP_remove(p->heap, k_split->heap_node); + } + else { +#ifdef USE_TPOOL + c = corner_pool_elem_alloc(p->epool); +#else + c = malloc(sizeof(*c)); +#endif + c->index = k_split->index; + } + + c->index_adjacent[0] = k_prev->index; + c->index_adjacent[1] = k_next->index; + + /* Need to store handle lengths for both sides */ + c->handles_prev[0] = handles_prev[0]; + c->handles_prev[1] = handles_prev[1]; + + c->handles_next[0] = handles_next[0]; + c->handles_next[1] = handles_next[1]; + + c->error_sq[0] = cost_sq_dst[0]; + c->error_sq[1] = cost_sq_dst[1]; + + const double cost_max_sq = MAX2(cost_sq_dst[0], cost_sq_dst[1]); + k_split->heap_node = HEAP_insert(p->heap, cost_max_sq, c); + } + else { + if (k_split->heap_node) { + struct KnotCornerState *c; + c = HEAP_node_ptr(k_split->heap_node); + HEAP_remove(p->heap, k_split->heap_node); +#ifdef USE_TPOOL + corner_pool_elem_free(p->epool, c); +#else + free(c); +#endif + k_split->heap_node = NULL; + } + } +} + + +/** + * Attempt to collapse close knots into corners, + * as long as they fall below the error threshold. + */ +static uint curve_incremental_simplify_corners( + const struct PointData *pd, + struct Knot *knots, const uint knots_len, uint knots_len_remaining, + const double error_sq_max, const double error_sq_2x_max, + const double corner_angle, + const uint dims, + uint *r_corner_index_len) +{ +#ifdef USE_TPOOL + struct ElemPool_KnotCornerState epool; + + corner_pool_create(&epool, 0); +#endif + + Heap *heap = HEAP_new(0); + + struct KnotCorner_Params params = { + .pd = pd, + .heap = heap, +#ifdef USE_TPOOL + .epool = &epool, +#endif + }; + +#ifdef USE_VLA + double plane_no[dims]; + double k_proj_ref[dims]; + double k_proj_split[dims]; +#else + double *plane_no = alloca(sizeof(double) * dims); + double *k_proj_ref = alloca(sizeof(double) * dims); + double *k_proj_split = alloca(sizeof(double) * dims); +#endif + + const double corner_angle_cos = cos(corner_angle); + + uint corner_index_len = 0; + + for (uint i = 0; i < knots_len; i++) { + if ((knots[i].is_removed == false) && + (knots[i].can_remove == true) && + (knots[i].next && knots[i].next->can_remove)) + { + struct Knot *k_prev = &knots[i]; + struct Knot *k_next = k_prev->next; + + /* Angle outside threshold */ + if (dot_vnvn(k_prev->tan[0], k_next->tan[1], dims) < corner_angle_cos) { + /* Measure distance projected onto a plane, + * since the points may be offset along their own tangents. */ + sub_vn_vnvn(plane_no, k_next->tan[0], k_prev->tan[1], dims); + + /* Compare 2x so as to allow both to be changed by maximum of error_sq_max */ + const uint split_index = knot_find_split_point_on_axis( + pd, k_prev, k_next, + knots_len, + plane_no, + dims); + + if (split_index != SPLIT_POINT_INVALID) { + + project_vn_vnvn(k_proj_ref, &pd->points[k_prev->index * dims], k_prev->tan[1], dims); + project_vn_vnvn(k_proj_split, &pd->points[split_index * dims], k_prev->tan[1], dims); + + if (len_squared_vnvn(k_proj_ref, k_proj_split, dims) < error_sq_2x_max) { + + project_vn_vnvn(k_proj_ref, &pd->points[k_next->index * dims], k_next->tan[0], dims); + project_vn_vnvn(k_proj_split, &pd->points[split_index * dims], k_next->tan[0], dims); + + if (len_squared_vnvn(k_proj_ref, k_proj_split, dims) < error_sq_2x_max) { + + struct Knot *k_split = &knots[split_index]; + + knot_corner_error_recalculate( + ¶ms, + k_split, k_prev, k_next, + error_sq_max, + dims); + } + } + } + } + } + } + + while (HEAP_is_empty(heap) == false) { + struct KnotCornerState *c = HEAP_popmin(heap); + + struct Knot *k_split = &knots[c->index]; + + /* Remove while collapsing */ + struct Knot *k_prev = &knots[c->index_adjacent[0]]; + struct Knot *k_next = &knots[c->index_adjacent[1]]; + + /* Insert */ + k_split->is_removed = false; + k_split->prev = k_prev; + k_split->next = k_next; + k_prev->next = k_split; + k_next->prev = k_split; + + /* Update tangents */ + k_split->tan[0] = k_prev->tan[1]; + k_split->tan[1] = k_next->tan[0]; + + /* Own handles */ + k_prev->handles[1] = c->handles_prev[0]; + k_split->handles[0] = c->handles_prev[1]; + k_split->handles[1] = c->handles_next[0]; + k_next->handles[0] = c->handles_next[1]; + + k_prev->error_sq_next = c->error_sq[0]; + k_split->error_sq_next = c->error_sq[1]; + + k_split->heap_node = NULL; + +#ifdef USE_TPOOL + corner_pool_elem_free(&epool, c); +#else + free(c); +#endif + + k_split->is_corner = true; + + knots_len_remaining++; + + corner_index_len++; + } + +#ifdef USE_TPOOL + corner_pool_destroy(&epool); +#endif + + HEAP_free(heap, free); + + *r_corner_index_len = corner_index_len; + + return knots_len_remaining; +} + +#endif /* USE_CORNER_DETECT */ + +int curve_fit_cubic_to_points_refit_db( + const double *points, + const uint points_len, + const uint dims, + const double error_threshold, + const uint calc_flag, + const uint *corners, + const uint corners_len, + const double corner_angle, + + double **r_cubic_array, uint *r_cubic_array_len, + uint **r_cubic_orig_index, + uint **r_corner_index_array, uint *r_corner_index_len) +{ + const uint knots_len = points_len; + struct Knot *knots = malloc(sizeof(Knot) * knots_len); + knots[0].next = NULL; + +#ifndef USE_CORNER_DETECT + (void)r_corner_index_array; + (void)r_corner_index_len; +#endif + +(void)corners; +(void)corners_len; + + const bool is_cyclic = (calc_flag & CURVE_FIT_CALC_CYCLIC) != 0 && (points_len > 2); +#ifdef USE_CORNER_DETECT + const bool use_corner = (corner_angle < M_PI); +#else + (void)corner_angle; +#endif + + /* Over alloc the list x2 for cyclic curves, + * so we can evaluate across the start/end */ + double *points_alloc = NULL; + if (is_cyclic) { + points_alloc = malloc((sizeof(double) * points_len * dims) * 2); + memcpy(points_alloc, points, sizeof(double) * points_len * dims); + memcpy(points_alloc + (points_len * dims), points_alloc, sizeof(double) * points_len * dims); + points = points_alloc; + } + + double *tangents = malloc(sizeof(double) * knots_len * 2 * dims); + + { + double *t_step = tangents; + for (uint i = 0; i < knots_len; i++) { + knots[i].next = (knots + i) + 1; + knots[i].prev = (knots + i) - 1; + + knots[i].heap_node = NULL; + knots[i].index = i; + knots[i].index = i; + knots[i].can_remove = true; + knots[i].is_removed = false; + knots[i].is_corner = false; + knots[i].error_sq_next = 0.0; + knots[i].tan[0] = t_step; t_step += dims; + knots[i].tan[1] = t_step; t_step += dims; + } + assert(t_step == &tangents[knots_len * 2 * dims]); + } + + if (is_cyclic) { + knots[0].prev = &knots[knots_len - 1]; + knots[knots_len - 1].next = &knots[0]; + } + else { + knots[0].prev = NULL; + knots[knots_len - 1].next = NULL; + + /* always keep end-points */ + knots[0].can_remove = false; + knots[knots_len - 1].can_remove = false; + } + +#ifdef USE_LENGTH_CACHE + double *points_length_cache = malloc(sizeof(double) * points_len * (is_cyclic ? 2 : 1)); +#endif + + /* Initialize tangents, + * also set the values for knot handles since some may not collapse. */ + { +#ifdef USE_VLA + double tan_prev[dims]; + double tan_next[dims]; +#else + double *tan_prev = alloca(sizeof(double) * dims); + double *tan_next = alloca(sizeof(double) * dims); +#endif + double len_prev, len_next; + +#if 0 + /* 2x normalize calculations, but correct */ + + for (uint i = 0; i < knots_len; i++) { + Knot *k = &knots[i]; + + if (k->prev) { + sub_vn_vnvn(tan_prev, &points[k->prev->index * dims], &points[k->index * dims], dims); +#ifdef USE_LENGTH_CACHE + points_length_cache[i] = +#endif + len_prev = normalize_vn(tan_prev, dims); + } + else { + zero_vn(tan_prev, dims); + len_prev = 0.0; + } + + if (k->next) { + sub_vn_vnvn(tan_next, &points[k->index * dims], &points[k->next->index * dims], dims); + len_next = normalize_vn(tan_next, dims); + } + else { + zero_vn(tan_next, dims); + len_next = 0.0; + } + + add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims); + normalize_vn(k->tan[0], dims); + copy_vnvn(k->tan[1], k->tan[0], dims); + k->handles[0] = len_prev / 3; + k->handles[1] = len_next / 3; + } +#else + if (is_cyclic) { + len_prev = normalize_vn_vnvn(tan_prev, &points[(knots_len - 2) * dims], &points[(knots_len - 1) * dims], dims); + for (uint i_curr = knots_len - 1, i_next = 0; i_next < knots_len; i_curr = i_next++) { + struct Knot *k = &knots[i_curr]; +#ifdef USE_LENGTH_CACHE + points_length_cache[i_next] = +#endif + len_next = normalize_vn_vnvn(tan_next, &points[i_curr * dims], &points[i_next * dims], dims); + + add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims); + normalize_vn(k->tan[0], dims); + copy_vnvn(k->tan[1], k->tan[0], dims); + k->handles[0] = len_prev / 3; + k->handles[1] = len_next / 3; + + copy_vnvn(tan_prev, tan_next, dims); + len_prev = len_next; + } + } + else { +#ifdef USE_LENGTH_CACHE + points_length_cache[0] = 0.0; + points_length_cache[1] = +#endif + len_prev = normalize_vn_vnvn(tan_prev, &points[0 * dims], &points[1 * dims], dims); + copy_vnvn(knots[0].tan[0], tan_prev, dims); + copy_vnvn(knots[0].tan[1], tan_prev, dims); + knots[0].handles[0] = len_prev / 3; + knots[0].handles[1] = len_prev / 3; + + for (uint i_curr = 1, i_next = 2; i_next < knots_len; i_curr = i_next++) { + struct Knot *k = &knots[i_curr]; + +#ifdef USE_LENGTH_CACHE + points_length_cache[i_next] = +#endif + len_next = normalize_vn_vnvn(tan_next, &points[i_curr * dims], &points[i_next * dims], dims); + + add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims); + normalize_vn(k->tan[0], dims); + copy_vnvn(k->tan[1], k->tan[0], dims); + k->handles[0] = len_prev / 3; + k->handles[1] = len_next / 3; + + copy_vnvn(tan_prev, tan_next, dims); + len_prev = len_next; + } + copy_vnvn(knots[knots_len - 1].tan[0], tan_next, dims); + copy_vnvn(knots[knots_len - 1].tan[1], tan_next, dims); + + knots[knots_len - 1].handles[0] = len_next / 3; + knots[knots_len - 1].handles[1] = len_next / 3; + } +#endif + } + +#ifdef USE_LENGTH_CACHE + if (is_cyclic) { + memcpy(&points_length_cache[points_len], points_length_cache, sizeof(double) * points_len); + } +#endif + + +#if 0 + for (uint i = 0; i < knots_len; i++) { + Knot *k = &knots[i]; + printf("TAN %.8f %.8f %.8f %.8f\n", k->tan[0][0], k->tan[0][1], k->tan[1][0], k->tan[0][1]); + } +#endif + + const struct PointData pd = { + .points = points, + .points_len = points_len, +#ifdef USE_LENGTH_CACHE + .points_length_cache = points_length_cache, +#endif + }; + + uint knots_len_remaining = knots_len; + + /* 'curve_incremental_simplify_refit' can be called here, but its very slow + * just remove all within the threshold first. */ + knots_len_remaining = curve_incremental_simplify( + &pd, knots, knots_len, knots_len_remaining, + SQUARE(error_threshold), dims); + +#ifdef USE_CORNER_DETECT + if (use_corner) { + for (uint i = 0; i < knots_len; i++) { + assert(knots[i].heap_node == NULL); + } + + knots_len_remaining = curve_incremental_simplify_corners( + &pd, knots, knots_len, knots_len_remaining, + SQUARE(error_threshold), SQUARE(error_threshold * 3), + corner_angle, + dims, + r_corner_index_len); + } +#endif /* USE_CORNER_DETECT */ + +#ifdef USE_KNOT_REFIT + knots_len_remaining = curve_incremental_simplify_refit( + &pd, knots, knots_len, knots_len_remaining, + SQUARE(error_threshold), + dims); +#endif /* USE_KNOT_REFIT */ + + +#ifdef USE_CORNER_DETECT + if (use_corner) { + if (is_cyclic == false) { + *r_corner_index_len += 2; + } + + uint *corner_index_array = malloc(sizeof(uint) * (*r_corner_index_len)); + uint k_index = 0, c_index = 0; + uint i = 0; + + if (is_cyclic == false) { + corner_index_array[c_index++] = k_index; + k_index++; + i++; + } + + for (; i < knots_len; i++) { + if (knots[i].is_removed == false) { + if (knots[i].is_corner == true) { + corner_index_array[c_index++] = k_index; + } + k_index++; + } + } + + if (is_cyclic == false) { + corner_index_array[c_index++] = k_index; + k_index++; + } + + assert(c_index == *r_corner_index_len); + *r_corner_index_array = corner_index_array; + } +#endif /* USE_CORNER_DETECT */ + +#ifdef USE_LENGTH_CACHE + free(points_length_cache); +#endif + + uint *cubic_orig_index = NULL; + + if (r_cubic_orig_index) { + cubic_orig_index = malloc(sizeof(uint) * knots_len_remaining); + } + + struct Knot *knots_first = NULL; + { + struct Knot *k; + for (uint i = 0; i < knots_len; i++) { + if (knots[i].is_removed == false) { + knots_first = &knots[i]; + break; + } + } + + if (cubic_orig_index) { + k = knots_first; + for (uint i = 0; i < knots_len_remaining; i++, k = k->next) { + cubic_orig_index[i] = k->index; + } + } + } + + /* Correct unused handle endpoints - not essential, but nice behavior */ + if (is_cyclic == false) { + struct Knot *knots_last = knots_first; + while (knots_last->next) { + knots_last = knots_last->next; + } + knots_first->handles[0] = -knots_first->handles[1]; + knots_last->handles[1] = -knots_last->handles[0]; + } + + /* 3x for one knot and two handles */ + double *cubic_array = malloc(sizeof(double) * knots_len_remaining * 3 * dims); + + { + double *c_step = cubic_array; + struct Knot *k = knots_first; + for (uint i = 0; i < knots_len_remaining; i++, k = k->next) { + const double *p = &points[k->index * dims]; + + madd_vn_vnvn_fl(c_step, p, k->tan[0], k->handles[0], dims); + c_step += dims; + copy_vnvn(c_step, p, dims); + c_step += dims; + madd_vn_vnvn_fl(c_step, p, k->tan[1], k->handles[1], dims); + c_step += dims; + } + assert(c_step == &cubic_array[knots_len_remaining * 3 * dims]); + } + + if (points_alloc) { + free(points_alloc); + points_alloc = NULL; + } + + free(knots); + free(tangents); + + if (r_cubic_orig_index) { + *r_cubic_orig_index = cubic_orig_index; + } + + *r_cubic_array = cubic_array; + *r_cubic_array_len = knots_len_remaining; + + return 0; +} + + +int curve_fit_cubic_to_points_refit_fl( + const float *points, + const unsigned int points_len, + const unsigned int dims, + const float error_threshold, + const unsigned int calc_flag, + const unsigned int *corners, + unsigned int corners_len, + const float corner_angle, + + float **r_cubic_array, unsigned int *r_cubic_array_len, + unsigned int **r_cubic_orig_index, + unsigned int **r_corner_index_array, unsigned int *r_corner_index_len) +{ + const uint points_flat_len = points_len * dims; + double *points_db = malloc(sizeof(double) * points_flat_len); + + copy_vndb_vnfl(points_db, points, points_flat_len); + + double *cubic_array_db = NULL; + float *cubic_array_fl = NULL; + uint cubic_array_len = 0; + + int result = curve_fit_cubic_to_points_refit_db( + points_db, points_len, dims, error_threshold, calc_flag, corners, corners_len, + corner_angle, + &cubic_array_db, &cubic_array_len, + r_cubic_orig_index, + r_corner_index_array, r_corner_index_len); + free(points_db); + + if (!result) { + uint cubic_array_flat_len = cubic_array_len * 3 * dims; + cubic_array_fl = malloc(sizeof(float) * cubic_array_flat_len); + for (uint i = 0; i < cubic_array_flat_len; i++) { + cubic_array_fl[i] = (float)cubic_array_db[i]; + } + free(cubic_array_db); + } + + *r_cubic_array = cubic_array_fl; + *r_cubic_array_len = cubic_array_len; + + return result; +} + diff --git a/extern/curve_fit_nd/intern/curve_fit_inline.h b/extern/curve_fit_nd/intern/curve_fit_inline.h index c77e5c6e062..f9eaa4c647c 100644 --- a/extern/curve_fit_nd/intern/curve_fit_inline.h +++ b/extern/curve_fit_nd/intern/curve_fit_inline.h @@ -290,14 +290,12 @@ MINLINE bool equals_vnvn( return true; } -#if 0 MINLINE void project_vn_vnvn( double v_out[], const double p[], const double v_proj[], const uint dims) { const double mul = dot_vnvn(p, v_proj, dims) / dot_vnvn(v_proj, v_proj, dims); mul_vnvn_fl(v_out, v_proj, mul, dims); } -#endif MINLINE void project_vn_vnvn_normalized( double v_out[], const double p[], const double v_proj[], const uint dims) diff --git a/extern/curve_fit_nd/intern/generic_alloc_impl.h b/extern/curve_fit_nd/intern/generic_alloc_impl.h new file mode 100644 index 00000000000..687c154f14a --- /dev/null +++ b/extern/curve_fit_nd/intern/generic_alloc_impl.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2016, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the <organization> nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file generic_alloc_impl.c + * \ingroup curve_fit + * + * Simple Memory Chunking Allocator + * ================================ + * + * Defines need to be set: + * - #TPOOL_IMPL_PREFIX: Prefix to use for the API. + * - #TPOOL_ALLOC_TYPE: Struct type this pool handles. + * - #TPOOL_STRUCT: Name for pool struct name. + * - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined. + * + * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``. + * + * Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function. + * + * - *_pool_create() + * - *_pool_destroy() + * - *_pool_clear() + * + * - *_pool_elem_alloc() + * - *_pool_elem_calloc() + * - *_pool_elem_free() + */ + +/* check we're not building directly */ +#if !defined(TPOOL_IMPL_PREFIX) || \ + !defined(TPOOL_ALLOC_TYPE) || \ + !defined(TPOOL_STRUCT) +# error "This file can't be compiled directly, include in another source file" +#endif + +#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2 +#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) +#define _TPOOL_PREFIX(id) _CONCAT(TPOOL_IMPL_PREFIX, _##id) + +/* local identifiers */ +#define pool_create _TPOOL_PREFIX(pool_create) +#define pool_destroy _TPOOL_PREFIX(pool_destroy) +#define pool_clear _TPOOL_PREFIX(pool_clear) + +#define pool_elem_alloc _TPOOL_PREFIX(pool_elem_alloc) +#define pool_elem_calloc _TPOOL_PREFIX(pool_elem_calloc) +#define pool_elem_free _TPOOL_PREFIX(pool_elem_free) + +/* private identifiers (only for this file, undefine after) */ +#define pool_alloc_chunk _TPOOL_PREFIX(pool_alloc_chunk) +#define TPoolChunk _TPOOL_PREFIX(TPoolChunk) +#define TPoolChunkElemFree _TPOOL_PREFIX(TPoolChunkElemFree) + +#ifndef TPOOL_CHUNK_SIZE +#define TPOOL_CHUNK_SIZE (1 << 16) /* 64kb */ +#define _TPOOL_CHUNK_SIZE_UNDEF +#endif + +#ifndef UNLIKELY +# ifdef __GNUC__ +# define UNLIKELY(x) __builtin_expect(!!(x), 0) +# else +# define UNLIKELY(x) (x) +# endif +#endif + +#ifdef __GNUC__ +# define MAYBE_UNUSED __attribute__((unused)) +#else +# define MAYBE_UNUSED +#endif + + +struct TPoolChunk { + struct TPoolChunk *prev; + unsigned int size; + unsigned int bufsize; + TPOOL_ALLOC_TYPE buf[0]; +}; + +struct TPoolChunkElemFree { + struct TPoolChunkElemFree *next; +}; + +struct TPOOL_STRUCT { + /* Always keep at least one chunk (never NULL) */ + struct TPoolChunk *chunk; + /* when NULL, allocate a new chunk */ + struct TPoolChunkElemFree *free; +}; + +/** + * Number of elems to include per #TPoolChunk when no reserved size is passed, + * or we allocate past the reserved number. + * + * \note Optimize number for 64kb allocs. + */ +#define _TPOOL_CHUNK_DEFAULT_NUM \ + (((1 << 16) - sizeof(struct TPoolChunk)) / sizeof(TPOOL_ALLOC_TYPE)) + + +/** \name Internal Memory Management + * \{ */ + +static struct TPoolChunk *pool_alloc_chunk( + unsigned int tot_elems, struct TPoolChunk *chunk_prev) +{ + struct TPoolChunk *chunk = malloc( + sizeof(struct TPoolChunk) + (sizeof(TPOOL_ALLOC_TYPE) * tot_elems)); + chunk->prev = chunk_prev; + chunk->bufsize = tot_elems; + chunk->size = 0; + return chunk; +} + +static TPOOL_ALLOC_TYPE *pool_elem_alloc(struct TPOOL_STRUCT *pool) +{ + TPOOL_ALLOC_TYPE *elem; + + if (pool->free) { + elem = (TPOOL_ALLOC_TYPE *)pool->free; + pool->free = pool->free->next; + } + else { + struct TPoolChunk *chunk = pool->chunk; + if (UNLIKELY(chunk->size == chunk->bufsize)) { + chunk = pool->chunk = pool_alloc_chunk(_TPOOL_CHUNK_DEFAULT_NUM, chunk); + } + elem = &chunk->buf[chunk->size++]; + } + + return elem; +} + +MAYBE_UNUSED +static TPOOL_ALLOC_TYPE *pool_elem_calloc(struct TPOOL_STRUCT *pool) +{ + TPOOL_ALLOC_TYPE *elem = pool_elem_alloc(pool); + memset(elem, 0, sizeof(*elem)); + return elem; +} + +static void pool_elem_free(struct TPOOL_STRUCT *pool, TPOOL_ALLOC_TYPE *elem) +{ + struct TPoolChunkElemFree *elem_free = (struct TPoolChunkElemFree *)elem; + elem_free->next = pool->free; + pool->free = elem_free; +} + +static void pool_create(struct TPOOL_STRUCT *pool, unsigned int tot_reserve) +{ + pool->chunk = pool_alloc_chunk((tot_reserve > 1) ? tot_reserve : _TPOOL_CHUNK_DEFAULT_NUM, NULL); + pool->free = NULL; +} + +MAYBE_UNUSED +static void pool_clear(struct TPOOL_STRUCT *pool) +{ + /* Remove all except the last chunk */ + while (pool->chunk->prev) { + struct TPoolChunk *chunk_prev = pool->chunk->prev; + free(pool->chunk); + pool->chunk = chunk_prev; + } + pool->chunk->size = 0; + pool->free = NULL; +} + +static void pool_destroy(struct TPOOL_STRUCT *pool) +{ + struct TPoolChunk *chunk = pool->chunk; + do { + struct TPoolChunk *chunk_prev; + chunk_prev = chunk->prev; + free(chunk); + chunk = chunk_prev; + } while (chunk); + + pool->chunk = NULL; + pool->free = NULL; +} + +/** \} */ + +#undef _TPOOL_CHUNK_DEFAULT_NUM +#undef _CONCAT_AUX +#undef _CONCAT +#undef _TPOOL_PREFIX + +#undef TPoolChunk +#undef TPoolChunkElemFree + +#ifdef _TPOOL_CHUNK_SIZE_UNDEF +# undef TPOOL_CHUNK_SIZE +# undef _TPOOL_CHUNK_SIZE_UNDEF +#endif diff --git a/extern/curve_fit_nd/intern/generic_heap.c b/extern/curve_fit_nd/intern/generic_heap.c new file mode 100644 index 00000000000..1e2efa5b43d --- /dev/null +++ b/extern/curve_fit_nd/intern/generic_heap.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2016, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the <organization> nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file generic_heap.c + * \ingroup curve_fit + */ + +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <assert.h> + +#include "generic_heap.h" + +/* swap with a temp value */ +#define SWAP_TVAL(tval, a, b) { \ + (tval) = (a); \ + (a) = (b); \ + (b) = (tval); \ +} (void)0 + +#ifdef __GNUC__ +# define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +# define UNLIKELY(x) (x) +#endif + + +/***/ + +struct HeapNode { + void *ptr; + double value; + unsigned int index; +}; + +/* heap_* pool allocator */ +#define TPOOL_IMPL_PREFIX heap +#define TPOOL_ALLOC_TYPE HeapNode +#define TPOOL_STRUCT HeapMemPool +#include "generic_alloc_impl.h" +#undef TPOOL_IMPL_PREFIX +#undef TPOOL_ALLOC_TYPE +#undef TPOOL_STRUCT + +struct Heap { + unsigned int size; + unsigned int bufsize; + HeapNode **tree; + + struct HeapMemPool pool; +}; + +/** \name Internal Functions + * \{ */ + +#define HEAP_PARENT(i) (((i) - 1) >> 1) +#define HEAP_LEFT(i) (((i) << 1) + 1) +#define HEAP_RIGHT(i) (((i) << 1) + 2) +#define HEAP_COMPARE(a, b) ((a)->value < (b)->value) + +#if 0 /* UNUSED */ +#define HEAP_EQUALS(a, b) ((a)->value == (b)->value) +#endif + +static void heap_swap(Heap *heap, const unsigned int i, const unsigned int j) +{ + +#if 0 + SWAP(unsigned int, heap->tree[i]->index, heap->tree[j]->index); + SWAP(HeapNode *, heap->tree[i], heap->tree[j]); +#else + HeapNode **tree = heap->tree; + union { + unsigned int index; + HeapNode *node; + } tmp; + SWAP_TVAL(tmp.index, tree[i]->index, tree[j]->index); + SWAP_TVAL(tmp.node, tree[i], tree[j]); +#endif +} + +static void heap_down(Heap *heap, unsigned int i) +{ + /* size won't change in the loop */ + const unsigned int size = heap->size; + + while (1) { + const unsigned int l = HEAP_LEFT(i); + const unsigned int r = HEAP_RIGHT(i); + unsigned int smallest; + + smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i; + + if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) { + smallest = r; + } + + if (smallest == i) { + break; + } + + heap_swap(heap, i, smallest); + i = smallest; + } +} + +static void heap_up(Heap *heap, unsigned int i) +{ + while (i > 0) { + const unsigned int p = HEAP_PARENT(i); + + if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) { + break; + } + heap_swap(heap, p, i); + i = p; + } +} + +/** \} */ + + +/** \name Public Heap API + * \{ */ + +/* use when the size of the heap is known in advance */ +Heap *HEAP_new(unsigned int tot_reserve) +{ + Heap *heap = malloc(sizeof(Heap)); + /* ensure we have at least one so we can keep doubling it */ + heap->size = 0; + heap->bufsize = tot_reserve ? tot_reserve : 1; + heap->tree = malloc(heap->bufsize * sizeof(HeapNode *)); + + heap_pool_create(&heap->pool, tot_reserve); + + return heap; +} + +void HEAP_free(Heap *heap, HeapFreeFP ptrfreefp) +{ + if (ptrfreefp) { + unsigned int i; + + for (i = 0; i < heap->size; i++) { + ptrfreefp(heap->tree[i]->ptr); + } + } + + heap_pool_destroy(&heap->pool); + + free(heap->tree); + free(heap); +} + +void HEAP_clear(Heap *heap, HeapFreeFP ptrfreefp) +{ + if (ptrfreefp) { + unsigned int i; + + for (i = 0; i < heap->size; i++) { + ptrfreefp(heap->tree[i]->ptr); + } + } + heap->size = 0; + + heap_pool_clear(&heap->pool); +} + +HeapNode *HEAP_insert(Heap *heap, double value, void *ptr) +{ + HeapNode *node; + + if (UNLIKELY(heap->size >= heap->bufsize)) { + heap->bufsize *= 2; + heap->tree = realloc(heap->tree, heap->bufsize * sizeof(*heap->tree)); + } + + node = heap_pool_elem_alloc(&heap->pool); + + node->ptr = ptr; + node->value = value; + node->index = heap->size; + + heap->tree[node->index] = node; + + heap->size++; + + heap_up(heap, node->index); + + return node; +} + +bool HEAP_is_empty(Heap *heap) +{ + return (heap->size == 0); +} + +unsigned int HEAP_size(Heap *heap) +{ + return heap->size; +} + +HeapNode *HEAP_top(Heap *heap) +{ + return heap->tree[0]; +} + +double HEAP_top_value(Heap *heap) +{ + return heap->tree[0]->value; +} + +void *HEAP_popmin(Heap *heap) +{ + void *ptr = heap->tree[0]->ptr; + + assert(heap->size != 0); + + heap_pool_elem_free(&heap->pool, heap->tree[0]); + + if (--heap->size) { + heap_swap(heap, 0, heap->size); + heap_down(heap, 0); + } + + return ptr; +} + +void HEAP_remove(Heap *heap, HeapNode *node) +{ + unsigned int i = node->index; + + assert(heap->size != 0); + + while (i > 0) { + unsigned int p = HEAP_PARENT(i); + + heap_swap(heap, p, i); + i = p; + } + + HEAP_popmin(heap); +} + +double HEAP_node_value(HeapNode *node) +{ + return node->value; +} + +void *HEAP_node_ptr(HeapNode *node) +{ + return node->ptr; +} diff --git a/extern/curve_fit_nd/intern/generic_heap.h b/extern/curve_fit_nd/intern/generic_heap.h new file mode 100644 index 00000000000..e39344cf076 --- /dev/null +++ b/extern/curve_fit_nd/intern/generic_heap.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the <organization> nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GENERIC_HEAP_H__ +#define __GENERIC_HEAP_H__ + +/** \file generic_heap.h + * \ingroup curve_fit + */ + +struct Heap; +struct HeapNode; +typedef struct Heap Heap; +typedef struct HeapNode HeapNode; + +typedef void (*HeapFreeFP)(void *ptr); + +Heap *HEAP_new(unsigned int tot_reserve); +bool HEAP_is_empty(Heap *heap); +void HEAP_free(Heap *heap, HeapFreeFP ptrfreefp); +void *HEAP_node_ptr(HeapNode *node); +void HEAP_remove(Heap *heap, HeapNode *node); +HeapNode *HEAP_insert(Heap *heap, double value, void *ptr); +void *HEAP_popmin(Heap *heap); +void HEAP_clear(Heap *heap, HeapFreeFP ptrfreefp); +unsigned int HEAP_size(Heap *heap); +HeapNode *HEAP_top(Heap *heap); +double HEAP_top_value(Heap *heap); +double HEAP_node_value(HeapNode *node); + +#endif /* __GENERIC_HEAP_IMPL_H__ */ diff --git a/intern/atomic/intern/atomic_ops_utils.h b/intern/atomic/intern/atomic_ops_utils.h index fcbb2346243..bfec9918c16 100644 --- a/intern/atomic/intern/atomic_ops_utils.h +++ b/intern/atomic/intern/atomic_ops_utils.h @@ -81,7 +81,9 @@ # endif #endif -#ifdef UINTPTR_MAX +#if defined(__SIZEOF_POINTER__) +# define LG_SIZEOF_PTR __SIZEOF_POINTER__ +#elif defined(UINTPTR_MAX) # if (UINTPTR_MAX == 0xFFFFFFFF) # define LG_SIZEOF_PTR 4 # elif (UINTPTR_MAX == 0xFFFFFFFFFFFFFFFF) diff --git a/intern/audaspace/Python/AUD_PyAPI.cpp b/intern/audaspace/Python/AUD_PyAPI.cpp index 300fd55e23b..de5c0a2f463 100644 --- a/intern/audaspace/Python/AUD_PyAPI.cpp +++ b/intern/audaspace/Python/AUD_PyAPI.cpp @@ -861,7 +861,7 @@ Factory_filter(Factory* self, PyObject *args) py_a_len= py_a ? PySequence_Size(py_a) : 0; py_b_len= PySequence_Size(py_b); - if(!py_b_len || ((py_a != NULL) && !py_b_len)) + if(!py_b_len || ((py_a != NULL) && !py_a_len)) { PyErr_SetString(PyExc_ValueError, "The sequence has to contain at least one value!"); return NULL; diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 140862721a8..0b3dd552f62 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -503,6 +503,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Use BVH spatial splits: longer builder time, faster render", default=False, ) + cls.debug_use_hair_bvh = BoolProperty( + name="Use Hair BVH", + description="Use special type BVH optimized for hair (uses more ram but renders faster)", + default=True, + ) cls.tile_order = EnumProperty( name="Tile Order", description="Tile order for rendering", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 120199479fe..6656beb4478 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -401,6 +401,7 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): col.label(text="Acceleration structure:") col.prop(cscene, "debug_use_spatial_splits") + col.prop(cscene, "debug_use_hair_bvh") class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel): @@ -458,7 +459,9 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel): col.prop(rl, "use_pass_z") col.prop(rl, "use_pass_mist") col.prop(rl, "use_pass_normal") - col.prop(rl, "use_pass_vector") + row = col.row() + row.prop(rl, "use_pass_vector") + row.active = not rd.use_motion_blur col.prop(rl, "use_pass_uv") col.prop(rl, "use_pass_object_index") col.prop(rl, "use_pass_material_index") diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 4bd385c4200..ec11a893b5a 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -680,6 +680,43 @@ static void create_subd_mesh(Scene *scene, /* Sync */ +static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh) +{ + if(scene->need_motion() == Scene::MOTION_NONE) + return; + + BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); + + if(!b_fluid_domain) + return; + + /* If the mesh has modifiers following the fluid domain we can't export motion. */ + if(b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size()) + return; + + /* Find or add attribute */ + float3 *P = &mesh->verts[0]; + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if(!attr_mP) { + attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + } + + /* Only export previous and next frame, we don't have any in between data. */ + float motion_times[2] = {-1.0f, 1.0f}; + for (int step = 0; step < 2; step++) { + float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; + float3 *mP = attr_mP->data_float3() + step*mesh->verts.size(); + + BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi; + int i = 0; + + for(b_fluid_domain.fluid_mesh_vertices.begin(fvi); fvi != b_fluid_domain.fluid_mesh_vertices.end(); ++fvi, ++i) { + mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time; + } + } +} + Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, bool object_updated, bool hide_tris) @@ -821,6 +858,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, mesh->displacement_method = Mesh::DISPLACE_BOTH; } + /* fluid motion */ + sync_mesh_fluid_motion(b_ob, scene, mesh); + /* tag update */ bool rebuild = false; @@ -910,6 +950,11 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, * would need a more extensive check to see which objects are animated */ BL::Mesh b_mesh(PointerRNA_NULL); + /* fluid motion is exported immediate with mesh, skip here */ + BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); + if (b_fluid_domain) + return; + if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { /* get derived mesh */ b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false); diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 80768c096e3..22a0b3988c8 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -253,11 +253,10 @@ static bool object_boundbox_clip(Scene *scene, boundbox[3 * i + 1], boundbox[3 * i + 2]); p = transform_point(&tfm, p); - p = transform_point(&worldtondc, p); + p = transform_perspective(&worldtondc, p); if(p.z >= -margin) { all_behind = false; } - p /= p.z; bb_min = min(bb_min, p); bb_max = max(bb_max, p); } @@ -720,12 +719,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render, << relative_time << "."; /* fixed shutter time to get previous and next frame for motion pass */ - float shuttertime; - - if(scene->need_motion() == Scene::MOTION_PASS) - shuttertime = 2.0f; - else - shuttertime = scene->camera->shuttertime; + float shuttertime = scene->motion_shutter_time(); /* compute frame and subframe time */ float time = frame_center + frame_center_delta + relative_time * shuttertime * 0.5f; diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 33084f1c163..e7e57b2be36 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -492,6 +492,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, SceneParams::BVH_STATIC); params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits"); + params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh"); if(background && params.shadingsystem != SHADINGSYSTEM_OSL) params.persistent_data = r.use_persistent_data(); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index d690adb5662..b8b9597914e 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -131,7 +131,9 @@ private: Transform& tfm, bool *use_portal); void sync_background_light(bool use_portal); - void sync_mesh_motion(BL::Object& b_ob, Object *object, float motion_time); + void sync_mesh_motion(BL::Object& b_ob, + Object *object, + float motion_time); void sync_camera_motion(BL::RenderSettings& b_render, BL::Object& b_ob, int width, int height, diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 2510cebcdc0..188d23d0c59 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -519,6 +519,23 @@ static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object& b_ob) return BL::SmokeDomainSettings(PointerRNA_NULL); } +static inline BL::DomainFluidSettings object_fluid_domain_find(BL::Object b_ob) +{ + BL::Object::modifiers_iterator b_mod; + + for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) { + if(b_mod->is_a(&RNA_FluidSimulationModifier)) { + BL::FluidSimulationModifier b_fmd(*b_mod); + BL::FluidSettings fss = b_fmd.settings(); + + if(fss.type() == BL::FluidSettings::type_DOMAIN) + return (BL::DomainFluidSettings)b_fmd.settings(); + } + } + + return BL::DomainFluidSettings(PointerRNA_NULL); +} + /* ID Map * * Utility class to keep in sync with blender data. diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index e92526ac1c4..1bb3e95c810 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -463,8 +463,7 @@ void RegularBVH::pack_aligned_inner(const BVHStackEntry& e, pack_aligned_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), - e0.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED, - e1.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED); + e0.node->m_visibility, e1.node->m_visibility); } void RegularBVH::pack_aligned_node(int idx, @@ -475,7 +474,8 @@ void RegularBVH::pack_aligned_node(int idx, { int4 data[BVH_NODE_SIZE] = { - make_int4(visibility0, visibility1, c0, c1), + make_int4(visibility0 & ~PATH_RAY_NODE_UNALIGNED, + visibility1 & ~PATH_RAY_NODE_UNALIGNED, c0, c1), make_int4(__float_as_int(b0.min.x), __float_as_int(b1.min.x), __float_as_int(b0.max.x), __float_as_int(b1.max.x)), make_int4(__float_as_int(b0.min.y), __float_as_int(b1.min.y), __float_as_int(b0.max.y), __float_as_int(b1.max.y)), make_int4(__float_as_int(b0.min.z), __float_as_int(b1.min.z), __float_as_int(b0.max.z), __float_as_int(b1.max.z)), @@ -688,9 +688,7 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility leaf_data[0].y = __int_as_float(c1); leaf_data[0].z = __uint_as_float(visibility); leaf_data[0].w = __uint_as_float(data[0].w); - memcpy(&pack.leaf_nodes[idx * BVH_NODE_LEAF_SIZE], - leaf_data, - sizeof(float4)*BVH_NODE_LEAF_SIZE); + memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_NODE_LEAF_SIZE); } else { int4 *data = &pack.nodes[idx]; diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index afe21c49730..50490f3a20e 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -795,7 +795,7 @@ public: bool load_binary(const string& /*kernel_path*/, const string& clbin, - string custom_kernel_build_options, + const string& custom_kernel_build_options, cl_program *program, const string *debug_src = NULL) { @@ -848,7 +848,7 @@ public: } bool build_kernel(cl_program *kernel_program, - string custom_kernel_build_options, + const string& custom_kernel_build_options, const string *debug_src = NULL) { string build_options; @@ -881,30 +881,39 @@ public: return true; } - bool compile_kernel(const string& kernel_path, - string source, - string custom_kernel_build_options, + bool compile_kernel(const string& kernel_name, + const string& kernel_path, + const string& source, + const string& custom_kernel_build_options, cl_program *kernel_program, const string *debug_src = NULL) { - /* we compile kernels consisting of many files. unfortunately opencl + /* We compile kernels consisting of many files. unfortunately OpenCL * kernel caches do not seem to recognize changes in included files. - * so we force recompile on changes by adding the md5 hash of all files */ - source = path_source_replace_includes(source, kernel_path); + * so we force recompile on changes by adding the md5 hash of all files. + */ + string inlined_source = path_source_replace_includes(source, + kernel_path); - if(debug_src) - path_write_text(*debug_src, source); + if(debug_src) { + path_write_text(*debug_src, inlined_source); + } - size_t source_len = source.size(); - const char *source_str = source.c_str(); + size_t source_len = inlined_source.size(); + const char *source_str = inlined_source.c_str(); - *kernel_program = clCreateProgramWithSource(cxContext, 1, &source_str, &source_len, &ciErr); + *kernel_program = clCreateProgramWithSource(cxContext, + 1, + &source_str, + &source_len, + &ciErr); - if(opencl_error(ciErr)) + if(opencl_error(ciErr)) { return false; + } double starttime = time_dt(); - printf("Compiling OpenCL kernel ...\n"); + printf("Compiling %s OpenCL kernel ...\n", kernel_name.c_str()); /* TODO(sergey): Report which kernel is being compiled * as well (megakernel or which of split kernels etc..). */ @@ -1004,7 +1013,8 @@ public: string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " + kernel_md5 + "\n"; /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(kernel_path, + if(!compile_kernel("base_kernel", + kernel_path, init_kernel_source, build_flags, &cpProgram, @@ -1694,7 +1704,8 @@ public: string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " + kernel_md5 + "\n"; /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(kernel_path, + if(!compile_kernel("mega_kernel", + kernel_path, init_kernel_source, custom_kernel_build_options, &path_trace_program, @@ -2078,30 +2089,33 @@ public: /* TODO(sergey): Seems really close to load_kernel(), * could it be de-duplicated? */ - bool load_split_kernel(string kernel_path, - string kernel_init_source, - string clbin, - string custom_kernel_build_options, + bool load_split_kernel(const string& kernel_name, + const string& kernel_path, + const string& kernel_init_source, + const string& clbin, + const string& custom_kernel_build_options, cl_program *program, const string *debug_src = NULL) { - if(!opencl_version_check()) + if(!opencl_version_check()) { return false; + } - clbin = path_user_get(path_join("cache", clbin)); + string cache_clbin = path_user_get(path_join("cache", clbin)); /* If exists already, try use it. */ - if(path_exists(clbin) && load_binary(kernel_path, - clbin, - custom_kernel_build_options, - program, - debug_src)) + if(path_exists(cache_clbin) && load_binary(kernel_path, + cache_clbin, + custom_kernel_build_options, + program, + debug_src)) { /* Kernel loaded from binary. */ } else { /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(kernel_path, + if(!compile_kernel(kernel_name, + kernel_path, kernel_init_source, custom_kernel_build_options, program, @@ -2110,7 +2124,7 @@ public: return false; } /* Save binary for reuse. */ - if(!save_binary(program, clbin)) { + if(!save_binary(program, cache_clbin)) { return false; } } @@ -2208,7 +2222,10 @@ public: clsrc = path_user_get(path_join("cache", clsrc)); \ debug_src = &clsrc; \ } \ - if(!load_split_kernel(kernel_path, kernel_init_source, clbin, \ + if(!load_split_kernel(#name, \ + kernel_path, \ + kernel_init_source, \ + clbin, \ build_options, \ &GLUE(name, _program), \ debug_src)) \ diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index 1869457f0c3..b27afaa9869 100644 --- a/intern/cycles/kernel/bvh/bvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -283,7 +283,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, return true; } /* if maximum number of hits reached, block all light */ - else if(*num_hits == max_hits) { + else if(*num_hits >= max_hits) { return true; } diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h index b5405e8e57b..d7f6bf86c71 100644 --- a/intern/cycles/kernel/bvh/bvh_volume_all.h +++ b/intern/cycles/kernel/bvh/bvh_volume_all.h @@ -206,7 +206,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; #endif - if(num_hits == max_hits) { + if(num_hits >= max_hits) { #if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); @@ -252,7 +252,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, # if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; # endif - if(num_hits == max_hits) { + if(num_hits >= max_hits) { # if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index 34753ff067d..eb98eaf7455 100644 --- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -366,7 +366,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, return true; } /* if maximum number of hits reached, block all light */ - else if(*num_hits == max_hits) { + else if(*num_hits >= max_hits) { return true; } diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h index a877e5bb341..90cad9d91c0 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume_all.h +++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h @@ -273,7 +273,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; #endif - if(num_hits == max_hits) { + if(num_hits >= max_hits) { #if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); @@ -312,7 +312,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, # if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; # endif - if(num_hits == max_hits) { + if(num_hits >= max_hits) { # if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index aa21633070a..7bf7c2806d4 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -615,6 +615,36 @@ ccl_device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */ } +ccl_device_inline float bsdf_beckmann_G1(float alpha, float cos_n) +{ + cos_n *= cos_n; + float invA = alpha * safe_sqrtf((1.0f - cos_n) / cos_n); + if(invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f); +} + +ccl_device_inline float bsdf_beckmann_aniso_G1(float alpha_x, float alpha_y, float cos_n, float cos_phi, float sin_phi) +{ + cos_n *= cos_n; + sin_phi *= sin_phi; + cos_phi *= cos_phi; + alpha_x *= alpha_x; + alpha_y *= alpha_y; + + float alphaO2 = (cos_phi*alpha_x + sin_phi*alpha_y) / (cos_phi + sin_phi); + float invA = safe_sqrtf(alphaO2 * (1 - cos_n) / cos_n); + if(invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f); +} + ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { float alpha_x = sc->data0; @@ -646,10 +676,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1o = bsdf_beckmann_G1(alpha_x, cosNO); + G1i = bsdf_beckmann_G1(alpha_x, cosNI); } else { /* anisotropic */ @@ -668,24 +696,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4); /* G1(i,m) and G1(o,m) */ - float tanThetaO2 = (1 - cosNO * cosNO) / (cosNO * cosNO); - float cosPhiO = dot(I, X); - float sinPhiO = dot(I, Y); - - float alphaO2 = (cosPhiO*cosPhiO)*(alpha_x*alpha_x) + (sinPhiO*sinPhiO)*(alpha_y*alpha_y); - alphaO2 /= cosPhiO*cosPhiO + sinPhiO*sinPhiO; - - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(omega_in, X); - float sinPhiI = dot(omega_in, Y); - - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); - alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; - - float ao = 1 / (safe_sqrtf(alphaO2 * tanThetaO2)); - float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2)); - G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1o = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNO, dot(I, X), dot(I, Y)); + G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNI, dot(omega_in, X), dot(omega_in, Y)); } float G = G1o * G1i; @@ -740,10 +752,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; - float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G1o = bsdf_beckmann_G1(alpha_x, cosNO); + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); float G = G1o * G1i; /* probability */ @@ -820,8 +830,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl float cosNI = dot(N, *omega_in); /* eq. 26, 27: now calculate G1(i,m) */ - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1i = bsdf_beckmann_G1(alpha_x, cosNI); } else { /* anisotropic distribution */ @@ -836,16 +845,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4); /* G1(i,m) */ - float cosNI = dot(N, *omega_in); - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(*omega_in, X); - float sinPhiI = dot(*omega_in, Y); - - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); - alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; - - float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2)); - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, dot(*omega_in, N), dot(*omega_in, X), dot(*omega_in, Y)); } float G = G1o * G1i; @@ -906,8 +906,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl float cosNI = dot(N, *omega_in); /* eq. 26, 27: now calculate G1(i,m) */ - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); float G = G1o * G1i; /* eq. 21 */ diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h index 6060d7d8ccb..acb50ce6faa 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -42,7 +42,7 @@ ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha) /* Sample slope distribution (based on page 14 of the supplemental implementation). */ ccl_device_inline float2 mf_sampleP22_11(const float cosI, const float2 randU) { - if(cosI > 0.9999f) { + if(cosI > 0.9999f || cosI < 1e-6f) { const float r = sqrtf(randU.x / (1.0f - randU.x)); const float phi = M_2PI_F * randU.y; return make_float2(r*cosf(phi), r*sinf(phi)); @@ -117,7 +117,7 @@ ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda if(dotW_WH < 0.0f) return make_float3(0.0f, 0.0f, 0.0f); - float phase = max(0.0f, dotW_WH) * 0.25f / (pArea * dotW_WH); + float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f); if(alpha.x == alpha.y) phase *= D_ggx(wh, alpha.x); else @@ -200,9 +200,9 @@ ccl_device_inline float mf_lambda(const float3 w, const float2 alpha) if(w.z > 0.9999f) return 0.0f; else if(w.z < -0.9999f) - return -1.0f; + return -0.9999f; - const float inv_wz2 = 1.0f / (w.z*w.z); + const float inv_wz2 = 1.0f / max(w.z*w.z, 1e-7f); const float2 wa = make_float2(w.x, w.y)*alpha; float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2); if(w.z <= 0.0f) @@ -271,7 +271,10 @@ ccl_device_inline float mf_ggx_albedo(float r) ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha) { - return 0.25f * D_ggx(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, make_float2(alpha, alpha))) * wi.z) + (1.0f - mf_ggx_albedo(alpha)) * wo.z; + float D = D_ggx(normalize(wi+wo), alpha); + float lambda = mf_lambda(wi, make_float2(alpha, alpha)); + float albedo = mf_ggx_albedo(alpha); + return 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f) + (1.0f - albedo) * wo.z; } ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha) @@ -348,11 +351,7 @@ ccl_device int bsdf_microfacet_multi_ggx_common_setup(ShaderClosure *sc) ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(ShaderClosure *sc) { -#ifdef __KERNEL_OPENCL__ - if(all(sc->T == 0.0f)) -#else - if(sc->T == make_float3(0.0f, 0.0f, 0.0f)) -#endif + if(is_zero(sc->T)) sc->T = make_float3(1.0f, 0.0f, 0.0f); return bsdf_microfacet_multi_ggx_common_setup(sc); @@ -410,6 +409,10 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderC *eval *= *pdf; *omega_in = X*localO.x + Y*localO.y + Z*localO.z; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; +#endif return LABEL_REFLECT|LABEL_GLOSSY; } @@ -467,10 +470,23 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const S *eval *= *pdf; *omega_in = X*localO.x + Y*localO.y + Z*localO.z; - if(localO.z*localI.z > 0.0f) + if(localO.z*localI.z > 0.0f) { +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; +#endif return LABEL_REFLECT|LABEL_GLOSSY; - else + } + else { +#ifdef __RAY_DIFFERENTIALS__ + float cosI = dot(Z, I); + float dnp = max(sqrtf(1.0f - (sc->data2 * sc->data2 * (1.0f - cosI*cosI))), 1e-7f); + *domega_in_dx = -(sc->data2 * dIdx) + ((sc->data2 - sc->data2 * sc->data2 * cosI / dnp) * dot(dIdx, Z)) * Z; + *domega_in_dy = -(sc->data2 * dIdy) + ((sc->data2 - sc->data2 * sc->data2 * cosI / dnp) * dot(dIdy, Z)) * Z; +#endif + return LABEL_TRANSMIT|LABEL_GLOSSY; + } } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index 89b1998d1ce..b0c5280b6cb 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -80,7 +80,7 @@ ccl_device float fresnel_dielectric( return 1; // total internal reflection } else { - float dnp = sqrtf(arg); + float dnp = max(sqrtf(arg), 1e-7f); float nK = (neta * cos)- dnp; *T = -(neta * I)+(nK * Nn); #ifdef __RAY_DIFFERENTIALS__ diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index 2fb8e219884..dabba3fb1f0 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -387,6 +387,12 @@ ccl_device_inline void motion_triangle_intersect_subsurface( float t, u, v; if(ray_triangle_intersect_uv(P, dir, tmax, verts[2], verts[0], verts[1], &u, &v, &t)) { + for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { + if(ss_isect->hits[i].t == t) { + return; + } + } + ss_isect->num_hits++; int hit; diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index fc081bda525..eb0decc800b 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -255,6 +255,13 @@ ccl_device_inline void triangle_intersect_subsurface( /* Normalize U, V, W, and T. */ const float inv_det = 1.0f / det; + const float t = T * inv_det; + for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { + if(ss_isect->hits[i].t == t) { + return; + } + } + ss_isect->num_hits++; int hit; @@ -277,7 +284,7 @@ ccl_device_inline void triangle_intersect_subsurface( isect->type = PRIMITIVE_TRIANGLE; isect->u = U * inv_det; isect->v = V * inv_det; - isect->t = T * inv_det; + isect->t = t; /* Record geometric normal. */ /* TODO(sergey): Use float4_to_float3() on just an edges. */ @@ -335,9 +342,16 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg, float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z); float3 qvec = cross(tvec, edge1); float3 pvec = cross(D, edge2); - float rt = dot(edge2, qvec) / dot(edge1, pvec); - - P = P + D*rt; + float det = dot(edge1, pvec); + if(det != 0.0f) { + /* If determinant is zero it means ray lies in the plane of + * the triangle. It is possible in theory due to watertight + * nature of triangle intersection. For suc hcases we simply + * don't refine intersection hoping it'll go all fine. + */ + float rt = dot(edge2, qvec) / det; + P = P + D*rt; + } if(isect->object != OBJECT_NONE) { # ifdef __OBJECT_MOTION__ @@ -393,9 +407,16 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z); float3 qvec = cross(tvec, edge1); float3 pvec = cross(D, edge2); - float rt = dot(edge2, qvec) / dot(edge1, pvec); - - P = P + D*rt; + float det = dot(edge1, pvec); + if(det != 0.0f) { + /* If determinant is zero it means ray lies in the plane of + * the triangle. It is possible in theory due to watertight + * nature of triangle intersection. For such cases we simply + * don't refine intersection hoping it'll go all fine. + */ + float rt = dot(edge2, qvec) / det; + P = P + D*rt; + } #endif /* __INTERSECTION_REFINE__ */ if(isect->object != OBJECT_NONE) { diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index 5f5a3609ded..0e13b22bd2c 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -50,7 +50,7 @@ ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 v else eval->diffuse = value; #else - *eval = value; + eval->diffuse = value; #endif } @@ -80,7 +80,7 @@ void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value) else eval->diffuse += value; #else - *eval += value; + eval->diffuse += value; #endif } @@ -98,7 +98,7 @@ ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval) else return is_zero(eval->diffuse); #else - return is_zero(*eval); + return is_zero(eval->diffuse); #endif } @@ -117,7 +117,7 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value) else eval->diffuse *= value; #else - *eval *= value; + eval->diffuse *= value; #endif } @@ -172,7 +172,7 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass) else L->emission = make_float3(0.0f, 0.0f, 0.0f); #else - *L = make_float3(0.0f, 0.0f, 0.0f); + L->emission = make_float3(0.0f, 0.0f, 0.0f); #endif } @@ -207,7 +207,7 @@ ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space else *throughput *= bsdf_eval->diffuse*inverse_pdf; #else - *throughput *= *bsdf_eval*inverse_pdf; + *throughput *= bsdf_eval->diffuse*inverse_pdf; #endif } @@ -225,7 +225,7 @@ ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 thro else L->emission += throughput*value; #else - *L += throughput*value; + L->emission += throughput*value; #endif } @@ -246,7 +246,7 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput else L->emission += throughput*bsdf*ao; #else - *L += throughput*bsdf*ao; + L->emission += throughput*bsdf*ao; #endif } @@ -277,7 +277,7 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 through else L->emission += throughput*bsdf_eval->diffuse*shadow; #else - *L += throughput*(*bsdf_eval)*shadow; + L->emission += throughput*bsdf_eval->diffuse*shadow; #endif } @@ -295,7 +295,7 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 th else L->emission += throughput*value; #else - *L += throughput*value; + L->emission += throughput*value; #endif } @@ -441,7 +441,7 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi else L_sum = L->emission; #else - L_sum = *L; + L_sum = L->emission; #endif /* Reject invalid value */ @@ -477,7 +477,7 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance L->shadow += L_sample->shadow*fac; L->mist += L_sample->mist*fac; #else - *L += *L_sample * fac; + L->emission += L_sample->emission * fac; #endif } diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index db2fc84834a..d1576754d2e 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -75,7 +75,12 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, } uint num_hits; - blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits); + if(max_hits == 0) { + blocked = true; + num_hits = 0; + } else { + blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits); + } /* if no opaque surface found but we did find transparent hits, shade them */ if(!blocked && num_hits > 0) { diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 5de58ba28ed..a9be2ae717a 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -387,12 +387,13 @@ typedef enum BakePassFilterCombos { BAKE_FILTER_SUBSURFACE_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_SUBSURFACE), } BakePassFilterCombos; -#ifdef __PASSES__ - typedef ccl_addr_space struct PathRadiance { +#ifdef __PASSES__ int use_light_pass; +#endif float3 emission; +#ifdef __PASSES__ float3 background; float3 ao; @@ -426,25 +427,23 @@ typedef ccl_addr_space struct PathRadiance { float4 shadow; float mist; +#endif } PathRadiance; typedef struct BsdfEval { +#ifdef __PASSES__ int use_light_pass; +#endif float3 diffuse; +#ifdef __PASSES__ float3 glossy; float3 transmission; float3 transparent; float3 subsurface; float3 scatter; -} BsdfEval; - -#else - -typedef ccl_addr_space float3 PathRadiance; -typedef float3 BsdfEval; - #endif +} BsdfEval; /* Shader Flag */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h index 962196ccbdd..ec82d4b4c22 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h @@ -109,6 +109,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg, { if(type >= SHADER_EVAL_BAKE) { kernel_assert(output_luma == NULL); +#ifdef __BAKING__ kernel_bake_evaluate(kg, input, output, @@ -117,6 +118,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg, i, offset, sample); +#endif } else { kernel_shader_evaluate(kg, diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 27fed89fdf7..276b6f26f5e 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -312,7 +312,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st /* apply normal map */ float3 B = sign * cross(normal, tangent); - N = normalize(color.x * tangent + color.y * B + color.z * normal); + N = safe_normalize(color.x * tangent + color.y * B + color.z * normal); /* transform to world space */ object_normal_transform(kg, sd, &N); @@ -330,14 +330,18 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st if(space == NODE_NORMAL_MAP_OBJECT || space == NODE_NORMAL_MAP_BLENDER_OBJECT) object_normal_transform(kg, sd, &N); else - N = normalize(N); + N = safe_normalize(N); } float strength = stack_load_float(stack, strength_offset); if(strength != 1.0f) { strength = max(strength, 0.0f); - N = normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength); + N = safe_normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength); + } + + if(is_zero(N)) { + N = ccl_fetch(sd, N); } stack_store_float3(stack, normal_offset, N); diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index b14da3e63d0..a632ddc0598 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -22,6 +22,7 @@ set(SRC bake.cpp buffers.cpp camera.cpp + constant_fold.cpp film.cpp graph.cpp image.cpp @@ -49,6 +50,7 @@ set(SRC_HEADERS background.h buffers.h camera.h + constant_fold.h film.h graph.h image.h diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp new file mode 100644 index 00000000000..1fee6b2c081 --- /dev/null +++ b/intern/cycles/render/constant_fold.cpp @@ -0,0 +1,122 @@ +/* + * Copyright 2011-2013 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 "constant_fold.h" +#include "graph.h" + +#include "util_foreach.h" + +CCL_NAMESPACE_BEGIN + +ConstantFolder::ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output) +: graph(graph), node(node), output(output) +{ +} + +bool ConstantFolder::all_inputs_constant() const +{ + foreach(ShaderInput *input, node->inputs) { + if(input->link) { + return false; + } + } + + return true; +} + +void ConstantFolder::make_constant(float value) const +{ + foreach(ShaderInput *sock, output->links) { + sock->set(value); + } + + graph->disconnect(output); +} + +void ConstantFolder::make_constant(float3 value) const +{ + foreach(ShaderInput *sock, output->links) { + sock->set(value); + } + + graph->disconnect(output); +} + +void ConstantFolder::make_constant_clamp(float value, bool clamp) const +{ + make_constant(clamp ? saturate(value) : value); +} + +void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const +{ + if (clamp) { + value.x = saturate(value.x); + value.y = saturate(value.y); + value.z = saturate(value.z); + } + + make_constant(value); +} + +void ConstantFolder::bypass(ShaderOutput *new_output) const +{ + assert(new_output); + + /* Remove all outgoing links from socket and connect them to new_output instead. + * The graph->relink method affects node inputs, so it's not safe to use in constant + * folding if the node has multiple outputs and will thus be folded multiple times. */ + vector<ShaderInput*> outputs = output->links; + + graph->disconnect(output); + + foreach(ShaderInput *sock, outputs) { + graph->connect(new_output, sock); + } +} + +void ConstantFolder::discard() const +{ + assert(output->type() == SocketType::CLOSURE); + graph->disconnect(output); +} + +void ConstantFolder::bypass_or_discard(ShaderInput *input) const +{ + assert(input->type() == SocketType::CLOSURE); + + if (input->link) { + bypass(input->link); + } + else { + discard(); + } +} + +bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, float3 input_value, bool clamp) const +{ + if(!input->link) { + make_constant_clamp(input_value, clamp); + return true; + } + else if(!clamp) { + bypass(input->link); + return true; + } + + return false; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h new file mode 100644 index 00000000000..978c8e5335a --- /dev/null +++ b/intern/cycles/render/constant_fold.h @@ -0,0 +1,59 @@ +/* + * Copyright 2011-2013 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 __CONSTANT_FOLD_H__ +#define __CONSTANT_FOLD_H__ + +#include "util_types.h" + +CCL_NAMESPACE_BEGIN + +class ShaderGraph; +class ShaderInput; +class ShaderNode; +class ShaderOutput; + +class ConstantFolder { +public: + ShaderGraph *const graph; + ShaderNode *const node; + ShaderOutput *const output; + + ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output); + + bool all_inputs_constant() const; + + /* Constant folding helpers, always return true for convenience. */ + void make_constant(float value) const; + void make_constant(float3 value) const; + void make_constant_clamp(float value, bool clamp) const; + void make_constant_clamp(float3 value, bool clamp) const; + + /* Bypass node, relinking to another output socket. */ + void bypass(ShaderOutput *output) const; + + /* For closure nodes, discard node entirely or bypass to one of its inputs. */ + void discard() const; + void bypass_or_discard(ShaderInput *input) const; + + /* Bypass or make constant, unless we can't due to clamp being true. */ + bool try_bypass_or_make_constant(ShaderInput *input, float3 input_value, bool clamp) const; +}; + +CCL_NAMESPACE_END + +#endif /* __CONSTANT_FOLD_H__ */ + diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index fd48bf2631e..66601fa3502 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 Blender Foundation + * Copyright 2011-2016 Blender Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ #include "graph.h" #include "nodes.h" #include "shader.h" +#include "constant_fold.h" #include "util_algorithm.h" #include "util_debug.h" @@ -126,17 +127,6 @@ ShaderOutput *ShaderNode::output(ustring name) return NULL; } -bool ShaderNode::all_inputs_constant() const -{ - foreach(ShaderInput *input, inputs) { - if(input->link) { - return false; - } - } - - return true; -} - void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) { foreach(ShaderInput *input, inputs) { @@ -278,6 +268,17 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) } } +void ShaderGraph::disconnect(ShaderOutput *from) +{ + assert(!finalized); + + foreach(ShaderInput *sock, from->links) { + sock->link = NULL; + } + + from->links.clear(); +} + void ShaderGraph::disconnect(ShaderInput *to) { assert(!finalized); @@ -373,24 +374,12 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap) ShaderNode *nnode = node->clone(); nnodemap[node] = nnode; + /* create new inputs and outputs to recreate links and ensure + * that we still point to valid SocketType if the NodeType + * changed in cloning, as it does for OSL nodes */ nnode->inputs.clear(); nnode->outputs.clear(); - - foreach(ShaderInput *input, node->inputs) { - ShaderInput *ninput = new ShaderInput(*input); - nnode->inputs.push_back(ninput); - - ninput->parent = nnode; - ninput->link = NULL; - } - - foreach(ShaderOutput *output, node->outputs) { - ShaderOutput *noutput = new ShaderOutput(*output); - nnode->outputs.push_back(noutput); - - noutput->parent = nnode; - noutput->links.clear(); - } + nnode->create_inputs_outputs(nnode->type); } /* recreate links */ @@ -525,15 +514,8 @@ void ShaderGraph::constant_fold() } } /* Optimize current node. */ - if(node->constant_fold(this, output, output->links[0])) { - /* Apply optimized value to other connected sockets and disconnect. */ - vector<ShaderInput*> links(output->links); - for(size_t i = 0; i < links.size(); i++) { - if(i > 0) - links[i]->parent->copy_value(links[i]->socket_type, *links[0]->parent, links[0]->socket_type); - disconnect(links[i]); - } - } + ConstantFolder folder(this, node, output); + node->constant_fold(folder); } } } diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 61100cda60b..b35be48d8ca 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 Blender Foundation + * Copyright 2011-2016 Blender Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ class ShaderGraph; class SVMCompiler; class OSLCompiler; class OutputNode; +class ConstantFolder; /* Bump * @@ -140,9 +141,7 @@ public: /* ** Node optimization ** */ /* Check whether the node can be replaced with single constant. */ - virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, ShaderInput * /*optimized*/) { return false; } - - bool all_inputs_constant() const; + virtual void constant_fold(const ConstantFolder& /*folder*/) {} /* Simplify settings used by artists to the ones which are simpler to * evaluate in the kernel but keep the final result unchanged. @@ -251,6 +250,7 @@ public: OutputNode *output(); void connect(ShaderOutput *from, ShaderInput *to); + void disconnect(ShaderOutput *from); void disconnect(ShaderInput *to); void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to); diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 2a10eb474a4..63914e57319 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -176,7 +176,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene max_samples = max(max_samples, volume_samples); } - max_samples *= (max_bounce + transparent_max_bounce + 3); + max_samples *= (max_bounce + transparent_max_bounce + 3 + BSSRDF_MAX_HITS); int dimensions = PRNG_BASE_NUM + max_samples*PRNG_BOUNCE_NUM; dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS); diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 661719ed545..8b0ed9f77b2 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -588,7 +588,8 @@ void Mesh::compute_bvh(DeviceScene *dscene, BVHParams bparams; bparams.use_spatial_split = params->use_bvh_spatial_split; bparams.use_qbvh = params->use_qbvh; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + params->use_bvh_unaligned_nodes; delete bvh; bvh = BVH::create(bparams, objects); @@ -1222,7 +1223,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * bparams.top_level = true; bparams.use_qbvh = scene->params.use_qbvh; bparams.use_spatial_split = scene->params.use_bvh_spatial_split; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + scene->params.use_bvh_unaligned_nodes; delete bvh; bvh = BVH::create(bparams, scene->objects); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 15b55d17301..e26084c690b 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -22,6 +22,7 @@ #include "svm_color_util.h" #include "svm_math_util.h" #include "osl.h" +#include "constant_fold.h" #include "util_sky_model.h" #include "util_foreach.h" @@ -1576,14 +1577,11 @@ RGBToBWNode::RGBToBWNode() { } -bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void RGBToBWNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(linear_rgb_to_gray(color)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(linear_rgb_to_gray(color)); } - - return false; } void RGBToBWNode::compile(SVMCompiler& compiler) @@ -1661,38 +1659,35 @@ ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool auto special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; } -bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void ConvertNode::constant_fold(const ConstantFolder& folder) { /* proxy nodes should have been removed at this point */ assert(special_type != SHADER_SPECIAL_TYPE_PROXY); /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ - if(all_inputs_constant()) { + if(folder.all_inputs_constant()) { if(from == SocketType::FLOAT) { if(SocketType::is_float3(to)) { - optimized->set(make_float3(value_float, value_float, value_float)); - return true; + folder.make_constant(make_float3(value_float, value_float, value_float)); } } else if(SocketType::is_float3(from)) { if(to == SocketType::FLOAT) { - if(from == SocketType::COLOR) + if(from == SocketType::COLOR) { /* color to float */ - optimized->set(linear_rgb_to_gray(value_color)); - else + folder.make_constant(linear_rgb_to_gray(value_color)); + } + else { /* vector/point/normal to float */ - optimized->set(average(value_vector)); - return true; + folder.make_constant(average(value_vector)); + } } else if(SocketType::is_float3(to)) { - optimized->set(value_color); - return true; + folder.make_constant(value_color); } } } - - return false; } void ConvertNode::compile(SVMCompiler& compiler) @@ -2362,13 +2357,15 @@ void EmissionNode::compile(OSLCompiler& compiler) compiler.add(this, "node_emission"); } -bool EmissionNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) +void EmissionNode::constant_fold(const ConstantFolder& folder) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 0.0f)); + if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) { + folder.discard(); + } } /* Background Closure */ @@ -2412,13 +2409,15 @@ void BackgroundNode::compile(OSLCompiler& compiler) compiler.add(this, "node_background"); } -bool BackgroundNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) +void BackgroundNode::constant_fold(const ConstantFolder& folder) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 0.0f)); + if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) { + folder.discard(); + } } /* Holdout Closure */ @@ -3380,10 +3379,9 @@ ValueNode::ValueNode() { } -bool ValueNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void ValueNode::constant_fold(const ConstantFolder& folder) { - optimized->set(value); - return true; + folder.make_constant(value); } void ValueNode::compile(SVMCompiler& compiler) @@ -3416,10 +3414,9 @@ ColorNode::ColorNode() { } -bool ColorNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void ColorNode::constant_fold(const ConstantFolder& folder) { - optimized->set(value); - return true; + folder.make_constant(value); } void ColorNode::compile(SVMCompiler& compiler) @@ -3468,6 +3465,20 @@ void AddClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_add_closure"); } +void AddClosureNode::constant_fold(const ConstantFolder& folder) +{ + ShaderInput *closure1_in = input("Closure1"); + ShaderInput *closure2_in = input("Closure2"); + + /* remove useless add closures nodes */ + if(!closure1_in->link) { + folder.bypass_or_discard(closure2_in); + } + else if(!closure2_in->link) { + folder.bypass_or_discard(closure1_in); + } +} + /* Mix Closure */ NODE_DEFINE(MixClosureNode) @@ -3499,35 +3510,28 @@ void MixClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix_closure"); } -bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) +void MixClosureNode::constant_fold(const ConstantFolder& folder) { ShaderInput *fac_in = input("Fac"); ShaderInput *closure1_in = input("Closure1"); ShaderInput *closure2_in = input("Closure2"); - ShaderOutput *closure_out = output("Closure"); /* remove useless mix closures nodes */ if(closure1_in->link == closure2_in->link) { - graph->relink(this, closure_out, closure1_in->link); - return true; + folder.bypass_or_discard(closure1_in); } - - /* remove unused mix closure input when factor is 0.0 or 1.0 */ - /* check for closure links and make sure factor link is disconnected */ - if(closure1_in->link && closure2_in->link && !fac_in->link) { + /* remove unused mix closure input when factor is 0.0 or 1.0 + * check for closure links and make sure factor link is disconnected */ + else if(!fac_in->link) { /* factor 0.0 */ - if(fac == 0.0f) { - graph->relink(this, closure_out, closure1_in->link); - return true; + if(fac <= 0.0f) { + folder.bypass_or_discard(closure1_in); } /* factor 1.0 */ - else if(fac == 1.0f) { - graph->relink(this, closure_out, closure2_in->link); - return true; + else if(fac >= 1.0f) { + folder.bypass_or_discard(closure2_in); } } - - return false; } /* Mix Closure */ @@ -3589,26 +3593,21 @@ InvertNode::InvertNode() { } -bool InvertNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) +void InvertNode::constant_fold(const ConstantFolder& folder) { ShaderInput *fac_in = input("Fac"); ShaderInput *color_in = input("Color"); - ShaderOutput *color_out = output("Color"); if(!fac_in->link) { /* evaluate fully constant node */ if(!color_in->link) { - optimized->set(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); - return true; + folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); } /* remove no-op node */ else if(fac == 0.0f) { - graph->relink(this, color_out, color_in->link); - return true; + folder.bypass(color_in->link); } } - - return false; } void InvertNode::compile(SVMCompiler& compiler) @@ -3697,61 +3696,47 @@ void MixNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix"); } -bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) +void MixNode::constant_fold(const ConstantFolder& folder) { ShaderInput *fac_in = input("Fac"); ShaderInput *color1_in = input("Color1"); ShaderInput *color2_in = input("Color2"); - ShaderOutput *color_out = output("Color"); /* evaluate fully constant node */ - if(all_inputs_constant()) { - float3 result = svm_mix(type, fac, color1, color2); - optimized->set(use_clamp ? svm_mix_clamp(result) : result); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp); + return; } /* remove no-op node when factor is 0.0 */ if(!fac_in->link && fac <= 0.0f) { /* note that some of the modes will clamp out of bounds values even without use_clamp */ - if(!color1_in->link) { - float3 result = svm_mix(type, 0.0f, color1, color1); - optimized->set(use_clamp ? svm_mix_clamp(result) : result); - return true; + if(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN) { + if(!color1_in->link) { + folder.make_constant_clamp(svm_mix(type, 0.0f, color1, color1), use_clamp); + return; + } } - else if(!use_clamp && type != NODE_MIX_LIGHT && type != NODE_MIX_DODGE && type != NODE_MIX_BURN) { - graph->relink(this, color_out, color1_in->link); - return true; + else if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { + return; } } - if(type != NODE_MIX_BLEND) { - return false; - } - - /* remove useless mix colors nodes */ - if(color1_in->link && color1_in->link == color2_in->link && !use_clamp) { - graph->relink(this, color_out, color1_in->link); - return true; - } - if(!color1_in->link && !color2_in->link && color1 == color2) { - optimized->set(use_clamp ? svm_mix_clamp(color1) : color1); - return true; - } - - /* remove no-op mix color node when factor is 1.0 */ - if(!fac_in->link && fac >= 1.0f) { - if(!color2_in->link) { - optimized->set(use_clamp ? svm_mix_clamp(color2) : color2); - return true; + if(type == NODE_MIX_BLEND) { + /* remove useless mix colors nodes */ + if(color1_in->link ? (color1_in->link == color2_in->link) : (!color2_in->link && color1 == color2)) { + if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { + return; + } } - else if(!use_clamp) { - graph->relink(this, color_out, color2_in->link); - return true; + + /* remove no-op mix color node when factor is 1.0 */ + if(!fac_in->link && fac >= 1.0f) { + if(folder.try_bypass_or_make_constant(color2_in, color2, use_clamp)) { + return; + } } } - - return false; } /* Combine RGB */ @@ -3774,14 +3759,11 @@ CombineRGBNode::CombineRGBNode() { } -bool CombineRGBNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void CombineRGBNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(make_float3(r, g, b)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(make_float3(r, g, b)); } - - return false; } void CombineRGBNode::compile(SVMCompiler& compiler) @@ -3829,14 +3811,11 @@ CombineXYZNode::CombineXYZNode() { } -bool CombineXYZNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void CombineXYZNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(make_float3(x, y, z)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(make_float3(x, y, z)); } - - return false; } void CombineXYZNode::compile(SVMCompiler& compiler) @@ -3884,14 +3863,11 @@ CombineHSVNode::CombineHSVNode() { } -bool CombineHSVNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void CombineHSVNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(hsv_to_rgb(make_float3(h, s, v))); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(hsv_to_rgb(make_float3(h, s, v))); } - - return false; } void CombineHSVNode::compile(SVMCompiler& compiler) @@ -3932,14 +3908,11 @@ GammaNode::GammaNode() { } -bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void GammaNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(svm_math_gamma_color(color, gamma)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(svm_math_gamma_color(color, gamma)); } - - return false; } void GammaNode::compile(SVMCompiler& compiler) @@ -3979,14 +3952,11 @@ BrightContrastNode::BrightContrastNode() { } -bool BrightContrastNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void BrightContrastNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(svm_brightness_contrast(color, bright, contrast)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(svm_brightness_contrast(color, bright, contrast)); } - - return false; } void BrightContrastNode::compile(SVMCompiler& compiler) @@ -4029,18 +3999,16 @@ SeparateRGBNode::SeparateRGBNode() { } -bool SeparateRGBNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +void SeparateRGBNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { + if(folder.all_inputs_constant()) { for(int channel = 0; channel < 3; channel++) { - if(outputs[channel] == socket) { - optimized->set(color[channel]); - return true; + if(outputs[channel] == folder.output) { + folder.make_constant(color[channel]); + return; } } } - - return false; } void SeparateRGBNode::compile(SVMCompiler& compiler) @@ -4088,18 +4056,16 @@ SeparateXYZNode::SeparateXYZNode() { } -bool SeparateXYZNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +void SeparateXYZNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { + if(folder.all_inputs_constant()) { for(int channel = 0; channel < 3; channel++) { - if(outputs[channel] == socket) { - optimized->set(vector[channel]); - return true; + if(outputs[channel] == folder.output) { + folder.make_constant(vector[channel]); + return; } } } - - return false; } void SeparateXYZNode::compile(SVMCompiler& compiler) @@ -4147,20 +4113,18 @@ SeparateHSVNode::SeparateHSVNode() { } -bool SeparateHSVNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +void SeparateHSVNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { + if(folder.all_inputs_constant()) { float3 hsv = rgb_to_hsv(color); for(int channel = 0; channel < 3; channel++) { - if(outputs[channel] == socket) { - optimized->set(hsv[channel]); - return true; + if(outputs[channel] == folder.output) { + folder.make_constant(hsv[channel]); + return; } } } - - return false; } void SeparateHSVNode::compile(SVMCompiler& compiler) @@ -4546,14 +4510,11 @@ BlackbodyNode::BlackbodyNode() { } -bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void BlackbodyNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(svm_math_blackbody_color(temperature)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(svm_math_blackbody_color(temperature)); } - - return false; } void BlackbodyNode::compile(SVMCompiler& compiler) @@ -4655,15 +4616,11 @@ MathNode::MathNode() { } -bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void MathNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - float value = svm_math(type, value1, value2); - optimized->set(use_clamp ? saturate(value) : value); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp); } - - return false; } void MathNode::compile(SVMCompiler& compiler) @@ -4717,29 +4674,25 @@ VectorMathNode::VectorMathNode() { } -bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +void VectorMathNode::constant_fold(const ConstantFolder& folder) { float value; float3 vector; - if(all_inputs_constant()) { + if(folder.all_inputs_constant()) { svm_vector_math(&value, &vector, type, vector1, vector2); - if(socket == output("Value")) { - optimized->set(value); - return true; + if(folder.output == output("Value")) { + folder.make_constant(value); } - else if(socket == output("Vector")) { - optimized->set(vector); - return true; + else if(folder.output == output("Vector")) { + folder.make_constant(vector); } } - - return false; } void VectorMathNode::compile(SVMCompiler& compiler) @@ -4873,7 +4826,7 @@ void BumpNode::compile(OSLCompiler& compiler) compiler.add(this, "node_bump"); } -bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) +void BumpNode::constant_fold(const ConstantFolder& folder) { ShaderInput *height_in = input("Height"); ShaderInput *normal_in = input("Normal"); @@ -4881,18 +4834,15 @@ bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) if(height_in->link == NULL) { if(normal_in->link == NULL) { GeometryNode *geom = new GeometryNode(); - graph->add(geom); - graph->relink(this, outputs[0], geom->output("Normal")); + folder.graph->add(geom); + folder.bypass(geom->output("Normal")); } else { - graph->relink(this, outputs[0], normal_in->link); + folder.bypass(normal_in->link); } - return true; } /* TODO(sergey): Ignore bump with zero strength. */ - - return false; } @@ -5112,12 +5062,10 @@ OSLNode::~OSLNode() ShaderNode *OSLNode::clone() const { - OSLNode *node = new OSLNode(*this); - node->type = new NodeType(*type); - return node; + return OSLNode::create(this->inputs.size(), this); } -OSLNode* OSLNode::create(size_t num_inputs) +OSLNode* OSLNode::create(size_t num_inputs, const OSLNode *from) { /* allocate space for the node itself and parameters, aligned to 16 bytes * assuming that's the most parameter types need */ @@ -5127,7 +5075,17 @@ OSLNode* OSLNode::create(size_t num_inputs) char *node_memory = (char*) operator new(node_size + inputs_size); memset(node_memory, 0, node_size + inputs_size); - return new(node_memory) OSLNode(); + if (!from) { + return new(node_memory) OSLNode(); + } + else { + /* copy input default values and node type for cloning */ + memcpy(node_memory + node_size, (char*)from + node_size, inputs_size); + + OSLNode *node = new(node_memory) OSLNode(*from); + node->type = new NodeType(*(from->type)); + return node; + } } char* OSLNode::input_default_value() diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 3245fdfb6d9..caad11af0f8 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -289,7 +289,7 @@ public: class RGBToBWNode : public ShaderNode { public: SHADER_NODE_CLASS(RGBToBWNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float3 color; }; @@ -299,7 +299,7 @@ public: ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false); SHADER_NODE_BASE_CLASS(ConvertNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); SocketType::Type from, to; @@ -436,7 +436,7 @@ public: class EmissionNode : public ShaderNode { public: SHADER_NODE_CLASS(EmissionNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; } bool has_surface_emission() { return true; } @@ -449,7 +449,7 @@ public: class BackgroundNode : public ShaderNode { public: SHADER_NODE_CLASS(BackgroundNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; } float3 color; @@ -605,7 +605,7 @@ class ValueNode : public ShaderNode { public: SHADER_NODE_CLASS(ValueNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float value; }; @@ -614,7 +614,7 @@ class ColorNode : public ShaderNode { public: SHADER_NODE_CLASS(ColorNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float3 value; }; @@ -622,12 +622,13 @@ public: class AddClosureNode : public ShaderNode { public: SHADER_NODE_CLASS(AddClosureNode) + void constant_fold(const ConstantFolder& folder); }; class MixClosureNode : public ShaderNode { public: SHADER_NODE_CLASS(MixClosureNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float fac; }; @@ -643,7 +644,7 @@ public: class InvertNode : public ShaderNode { public: SHADER_NODE_CLASS(InvertNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float fac; @@ -653,7 +654,7 @@ public: class MixNode : public ShaderNode { public: SHADER_NODE_CLASS(MixNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } @@ -667,7 +668,7 @@ public: class CombineRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineRGBNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float r, g, b; @@ -676,7 +677,7 @@ public: class CombineHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineHSVNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float h, s, v; @@ -685,7 +686,7 @@ public: class CombineXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineXYZNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float x, y, z; @@ -694,7 +695,7 @@ public: class GammaNode : public ShaderNode { public: SHADER_NODE_CLASS(GammaNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_1; } float3 color; @@ -704,7 +705,7 @@ public: class BrightContrastNode : public ShaderNode { public: SHADER_NODE_CLASS(BrightContrastNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_1; } float3 color; @@ -715,7 +716,7 @@ public: class SeparateRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateRGBNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float3 color; @@ -724,7 +725,7 @@ public: class SeparateHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateHSVNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float3 color; @@ -733,7 +734,7 @@ public: class SeparateXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateXYZNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float3 vector; @@ -806,7 +807,7 @@ public: class BlackbodyNode : public ShaderNode { public: SHADER_NODE_CLASS(BlackbodyNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float temperature; @@ -816,7 +817,7 @@ class MathNode : public ShaderNode { public: SHADER_NODE_CLASS(MathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float value1; float value2; @@ -837,7 +838,7 @@ class VectorMathNode : public ShaderNode { public: SHADER_NODE_CLASS(VectorMathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float3 vector1; float3 vector2; @@ -859,7 +860,7 @@ public: class BumpNode : public ShaderNode { public: SHADER_NODE_CLASS(BumpNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); bool has_spatial_varying() { return true; } virtual int get_feature() { return NODE_FEATURE_BUMP; @@ -920,7 +921,7 @@ public: class OSLNode : public ShaderNode { public: - static OSLNode *create(size_t num_inputs); + static OSLNode *create(size_t num_inputs, const OSLNode *from = NULL); ~OSLNode(); ShaderNode *clone() const; diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index ff1f678c2d2..662d87e8b6b 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -184,7 +184,7 @@ void Object::apply_transform(bool apply_to_motion) } /* tfm is not reset to identity, all code that uses it needs to check the - transform_applied boolean */ + * transform_applied boolean */ } void Object::tag_update(Scene *scene) diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index e8367e1eb36..b341837b7e8 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -263,6 +263,14 @@ Scene::MotionType Scene::need_motion(bool advanced_shading) return MOTION_NONE; } +float Scene::motion_shutter_time() +{ + if(need_motion() == Scene::MOTION_PASS) + return 2.0f; + else + return camera->shuttertime; +} + bool Scene::need_global_attribute(AttributeStandard std) { if(std == ATTR_STD_UV) diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 925e84ad96d..05e807ff60c 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -136,6 +136,7 @@ public: BVH_NUM_TYPES, } bvh_type; bool use_bvh_spatial_split; + bool use_bvh_unaligned_nodes; bool use_qbvh; bool persistent_data; @@ -144,6 +145,7 @@ public: shadingsystem = SHADINGSYSTEM_SVM; bvh_type = BVH_DYNAMIC; use_bvh_spatial_split = false; + use_bvh_unaligned_nodes = true; use_qbvh = false; persistent_data = false; } @@ -152,6 +154,7 @@ public: { return !(shadingsystem == params.shadingsystem && bvh_type == params.bvh_type && use_bvh_spatial_split == params.use_bvh_spatial_split + && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes && use_qbvh == params.use_qbvh && persistent_data == params.persistent_data); } }; @@ -210,6 +213,7 @@ public: enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR }; MotionType need_motion(bool advanced_shading = true); + float motion_shutter_time(); bool need_update(); bool need_reset(); diff --git a/intern/cycles/util/util_math_fast.h b/intern/cycles/util/util_math_fast.h index deb2013daae..d3960deb3b4 100644 --- a/intern/cycles/util/util_math_fast.h +++ b/intern/cycles/util/util_math_fast.h @@ -547,6 +547,9 @@ ccl_device_inline float fast_erff(float x) const float a5 = 0.0002765672f; const float a6 = 0.0000430638f; const float a = fabsf(x); + if(a >= 12.3f) { + return copysignf(1.0f, x); + } const float b = 1.0f - (1.0f - a); /* Crush denormals. */ const float r = madd(madd(madd(madd(madd(madd(a6, b, a5), b, a4), b, a3), b, a2), b, a1), b, 1.0f); const float s = r * r; /* ^2 */ diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 7e77ba3a41f..0dd5d15b011 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -530,7 +530,7 @@ typedef struct { #ifdef _WIN32 -typedef long GHOST_TEmbedderWindowID; +typedef void* GHOST_TEmbedderWindowID; #endif // _WIN32 #ifndef _WIN32 diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index eeb6a2469ee..abce3ea6588 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -707,6 +707,7 @@ int GHOST_ContextWGL::choose_pixel_format( PIXELFORMATDESCRIPTOR preferredPFD = { sizeof(PIXELFORMATDESCRIPTOR), /* size */ 1, /* version */ + (DWORD) ( PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_SWAP_COPY | /* support swap copy */ @@ -717,16 +718,16 @@ int GHOST_ContextWGL::choose_pixel_format( needAlpha ? PFD_SUPPORT_COMPOSITION : /* support composition for transparent background */ #endif 0 - ), + )), PFD_TYPE_RGBA, /* color type */ - (needAlpha ? 32 : 24), /* preferred color depth */ + (BYTE) (needAlpha ? 32 : 24), /* preferred color depth */ 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ - needAlpha ? 8 : 0, /* alpha buffer */ + (BYTE) (needAlpha ? 8 : 0), /* alpha buffer */ 0, /* alpha shift (ignored) */ 0, /* no accumulation buffer */ 0, 0, 0, 0, /* accum bits (ignored) */ 24, /* depth buffer */ - needStencil ? 8 : 0, /* stencil buffer */ + (BYTE) (needStencil ? 8 : 0), /* stencil buffer */ 0, /* no auxiliary buffers */ PFD_MAIN_PLANE, /* main layer */ 0, /* reserved */ diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp index af5a2ed7097..96bd12faef8 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.cpp +++ b/intern/ghost/intern/GHOST_ImeWin32.cpp @@ -64,7 +64,7 @@ bool GHOST_ImeWin32::SetInputLanguage() * while composing a text. */ HKL keyboard_layout = ::GetKeyboardLayout(0); - input_language_id_ = reinterpret_cast<LANGID>(keyboard_layout); + input_language_id_ = LOWORD(keyboard_layout); ime_status_ = ::ImmIsIME(keyboard_layout); return ime_status_; } diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 55d013f6e5f..6f349543eed 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -1985,9 +1985,8 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType, ); } #endif -/* +/** * These callbacks can be used for debugging, so we can breakpoint on an X11 error. - * * Dummy function to get around IO Handler exiting if device invalid * Basically it will not crash blender now if you have a X device that diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index c9bcb38ab68..6a27d7aadf9 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -95,31 +95,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_parentWindowHwnd(parentwindowhwnd), m_debug_context(is_debug) { - OSVERSIONINFOEX versionInfo; - bool hasMinVersionForTaskbar = false; - - ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX)); - - versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - if (!GetVersionEx((OSVERSIONINFO *)&versionInfo)) { - versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (GetVersionEx((OSVERSIONINFO *)&versionInfo)) { - if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) || - (versionInfo.dwMajorVersion >= 7)) - { - hasMinVersionForTaskbar = true; - } - } - } - else { - if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) || - (versionInfo.dwMajorVersion >= 7)) - { - hasMinVersionForTaskbar = true; - } - } - if (state != GHOST_kWindowStateFullScreen) { RECT rect; MONITORINFO monitor; @@ -341,11 +316,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, } } } - - if (hasMinVersionForTaskbar) - CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (LPVOID *)&m_Bar); - else - m_Bar = NULL; + CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar); } diff --git a/intern/guardedalloc/test/simpletest/memtest.c b/intern/guardedalloc/test/simpletest/memtest.c index 841b47bd4f1..79d55dd02cc 100644 --- a/intern/guardedalloc/test/simpletest/memtest.c +++ b/intern/guardedalloc/test/simpletest/memtest.c @@ -26,7 +26,6 @@ */ /** - * Copyright (C) 2001 NaN Technologies B.V. * Simple test of memory. */ diff --git a/intern/libmv/intern/autotrack.cc b/intern/libmv/intern/autotrack.cc index f0cbc68f11e..3b7c9c5a010 100644 --- a/intern/libmv/intern/autotrack.cc +++ b/intern/libmv/intern/autotrack.cc @@ -67,12 +67,12 @@ int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack, libmv_apiMarkerToMarker(*libmv_tracked_marker, &tracked_marker); libmv_configureTrackRegionOptions(*libmv_options, &options); - (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker, - &result, - &options)); + bool ok = (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker, + &result, + &options)); libmv_markerToApiMarker(tracked_marker, libmv_tracked_marker); libmv_regionTrackergetResult(result, libmv_result); - return result.is_usable(); + return ok && result.is_usable(); } void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack, diff --git a/intern/libmv/libmv/multiview/projection.h b/intern/libmv/libmv/multiview/projection.h index 3220bc2dbbc..8f304f31ec6 100644 --- a/intern/libmv/libmv/multiview/projection.h +++ b/intern/libmv/libmv/multiview/projection.h @@ -122,7 +122,7 @@ inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) { inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) { Vec3 hx; - Project(P, X, x); + Project(P, X, &hx); *x = hx.head<2>() / hx(2); } diff --git a/intern/libmv/libmv/numeric/numeric.cc b/intern/libmv/libmv/numeric/numeric.cc index 9007663c8e2..3fc1e3b2bfd 100644 --- a/intern/libmv/libmv/numeric/numeric.cc +++ b/intern/libmv/libmv/numeric/numeric.cc @@ -109,7 +109,7 @@ void MeanAndVarianceAlongRows(const Mat &A, } void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked) { - assert(left.rows() == left.rows()); + assert(left.rows() == right.rows()); int n = left.rows(); int m1 = left.cols(); int m2 = right.cols(); diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h index 20a4a29e5ba..a42dab8c7a2 100644 --- a/intern/libmv/libmv/numeric/numeric.h +++ b/intern/libmv/libmv/numeric/numeric.h @@ -148,7 +148,7 @@ using Eigen::Matrix; // A = U * diag(s) * VT // template <typename TMat, typename TVec> -inline void SVD(TMat *A, Vec *s, Mat *U, Mat *VT) { +inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) { assert(0); } diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index 311b89b97cf..f8e80de7f8f 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -47,6 +47,7 @@ set(SRC opensubdiv_device_context_cuda.h opensubdiv_device_context_opencl.h opensubdiv_intern.h + opensubdiv_topology_refiner.h ) macro(OPENSUBDIV_DEFINE_COMPONENT component) @@ -69,6 +70,7 @@ add_definitions(-DGLEW_STATIC) if(WIN32) add_definitions(-DNOMINMAX) + add_definitions(-D_USE_MATH_DEFINES) endif() # TODO(sergey): Put CUEW back when CUDA is officially supported by OSD. diff --git a/intern/opensubdiv/gpu_shader_opensubd_display.glsl b/intern/opensubdiv/gpu_shader_opensubd_display.glsl index a17dcef81c7..5193d3a71dc 100644 --- a/intern/opensubdiv/gpu_shader_opensubd_display.glsl +++ b/intern/opensubdiv/gpu_shader_opensubd_display.glsl @@ -99,6 +99,7 @@ in block { } uniform samplerBuffer FVarDataBuffer; +uniform isamplerBuffer FVarDataOffsetBuffer; out block { VertexData v; @@ -208,6 +209,7 @@ struct LightSource { float spotCutoff; float spotExponent; float spotCosCutoff; + float pad, pad2; #endif }; @@ -240,6 +242,7 @@ void main() vec3 L_diffuse = vec3(0.0); vec3 L_specular = vec3(0.0); +#ifdef USE_LIGHTING #ifndef USE_COLOR_MATERIAL /* Assume NUM_SOLID_LIGHTS directional lights. */ for (int i = 0; i < NUM_SOLID_LIGHTS; i++) { @@ -310,6 +313,9 @@ void main() L_specular += light_specular * specular_bsdf * intensity; } #endif /* USE_COLOR_MATERIAL */ +#else /* USE_LIGHTING */ + L_diffuse = vec3(1.0); +#endif /* Compute diffuse color. */ #ifdef USE_TEXTURE_2D diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc index 9b9f4baa39e..ab904953c70 100644 --- a/intern/opensubdiv/opensubdiv_capi.cc +++ b/intern/opensubdiv/opensubdiv_capi.cc @@ -67,8 +67,10 @@ #include <opensubdiv/osd/glPatchTable.h> #include <opensubdiv/far/stencilTable.h> +#include <opensubdiv/far/primvarRefiner.h> #include "opensubdiv_intern.h" +#include "opensubdiv_topology_refiner.h" #include "MEM_guardedalloc.h" @@ -142,11 +144,73 @@ typedef Mesh<GLVertexBuffer, GLPatchTable> OsdGLSLComputeMesh; #endif +namespace { + +struct FVarVertex { + float u, v; + void Clear() { + u = v = 0.0f; + } + void AddWithWeight(FVarVertex const & src, float weight) { + u += weight * src.u; + v += weight * src.v; + } +}; + +static void interpolate_fvar_data(OpenSubdiv::Far::TopologyRefiner& refiner, + const std::vector<float> uvs, + std::vector<float> &fvar_data) { + /* TODO(sergey): Make it somehow more generic way. */ + const int fvar_width = 2; + const int max_level = refiner.GetMaxLevel(); + size_t fvar_data_offset = 0, values_offset = 0; + for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) { + const int num_values = refiner.GetLevel(0).GetNumFVarValues(0) * 2, + num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel), + num_values_total = refiner.GetNumFVarValuesTotal(channel); + if (num_values_total <= 0) { + continue; + } + OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner); + if (refiner.IsUniform()) { + /* For uniform we only keep the highest level of refinement. */ + fvar_data.resize(fvar_data.size() + num_values_max * fvar_width); + std::vector<FVarVertex> buffer(num_values_total - num_values_max); + FVarVertex *src = &buffer[0]; + memcpy(src, &uvs[values_offset], num_values * sizeof(float)); + /* Defer the last level to treat separately with its alternate + * destination. + */ + for (int level = 1; level < max_level; ++level) { + FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel); + primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); + src = dst; + } + FVarVertex *dst = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]); + primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel); + fvar_data_offset += num_values_max * fvar_width; + } else { + /* For adaptive we keep all levels. */ + fvar_data.resize(fvar_data.size() + num_values_total * fvar_width); + FVarVertex *src = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]); + memcpy(src, &uvs[values_offset], num_values * sizeof(float)); + for (int level = 1; level <= max_level; ++level) { + FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel); + primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); + src = dst; + } + fvar_data_offset += num_values_total * fvar_width; + } + values_offset += num_values; + } +} + +} // namespace + struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( OpenSubdiv_TopologyRefinerDescr *topology_refiner, int evaluator_type, - int level, - int /*subdivide_uvs*/) + int level) { using OpenSubdiv::Far::TopologyRefiner; @@ -164,7 +228,7 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( const int num_varying_elements = 3; GLMeshInterface *mesh = NULL; - TopologyRefiner *refiner = (TopologyRefiner*)topology_refiner; + TopologyRefiner *refiner = topology_refiner->osd_refiner; switch(evaluator_type) { #define CHECK_EVALUATOR_TYPE(type, class) \ @@ -210,13 +274,23 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( (OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh); gl_mesh->evaluator_type = evaluator_type; gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh; - gl_mesh->topology_refiner = (OpenSubdiv_TopologyRefinerDescr*)refiner; + gl_mesh->topology_refiner = topology_refiner; + + if (refiner->GetNumFVarChannels() > 0) { + std::vector<float> fvar_data; + interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data); + openSubdiv_osdGLAllocFVar(topology_refiner, gl_mesh, &fvar_data[0]); + } + else { + gl_mesh->fvar_data = NULL; + } return gl_mesh; } void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh) { + openSubdiv_osdGLDestroyFVar(gl_mesh); switch (gl_mesh->evaluator_type) { #define CHECK_EVALUATOR_TYPE(type, class) \ case OPENSUBDIV_EVALUATOR_ ## type: \ @@ -249,6 +323,8 @@ void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh) #undef CHECK_EVALUATOR_TYPE } + /* NOTE: OSD refiner was owned by gl_mesh, no need to free it here. */ + OBJECT_GUARDED_DELETE(gl_mesh->topology_refiner, OpenSubdiv_TopologyRefinerDescr); OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh); } @@ -299,6 +375,9 @@ int openSubdiv_supportGPUDisplay(void) return openSubdiv_gpu_legacy_support() && (GLEW_VERSION_3_2 || (GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) || - (GLEW_VERSION_3_0 && GLEW_EXT_geometry_shader4 && GLEW_ARB_uniform_buffer_object && (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object))); + (GLEW_VERSION_3_0 && + GLEW_EXT_geometry_shader4 && + GLEW_ARB_uniform_buffer_object && + (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object))); /* also ARB_explicit_attrib_location? */ } diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h index b40505b197d..c3a194813e6 100644 --- a/intern/opensubdiv/opensubdiv_capi.h +++ b/intern/opensubdiv/opensubdiv_capi.h @@ -32,16 +32,19 @@ extern "C" { // Types declaration. struct OpenSubdiv_GLMesh; +struct OpenSubdiv_GLMeshFVarData; struct OpenSubdiv_TopologyRefinerDescr; typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh; #ifdef __cplusplus struct OpenSubdiv_GLMeshDescr; + typedef struct OpenSubdiv_GLMesh { int evaluator_type; OpenSubdiv_GLMeshDescr *descriptor; OpenSubdiv_TopologyRefinerDescr *topology_refiner; + OpenSubdiv_GLMeshFVarData *fvar_data; } OpenSubdiv_GLMesh; #endif @@ -66,8 +69,7 @@ enum { OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( struct OpenSubdiv_TopologyRefinerDescr *topology_refiner, int evaluator_type, - int level, - int subdivide_uvs); + int level); void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh); unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer( @@ -138,6 +140,11 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, int start_patch, int num_patches); +void openSubdiv_osdGLAllocFVar(struct OpenSubdiv_TopologyRefinerDescr *topology_refiner, + OpenSubdiv_GLMesh *gl_mesh, + const float *fvar_data); +void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh); + /* ** Utility functions ** */ int openSubdiv_supportGPUDisplay(void); int openSubdiv_getAvailableEvaluators(void); diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc index 3fadde68d32..ea41a56768f 100644 --- a/intern/opensubdiv/opensubdiv_converter.cc +++ b/intern/opensubdiv/opensubdiv_converter.cc @@ -32,8 +32,12 @@ #include <opensubdiv/far/topologyRefinerFactory.h> +#include "MEM_guardedalloc.h" + #include "opensubdiv_converter_capi.h" #include "opensubdiv_intern.h" +#include "opensubdiv_topology_refiner.h" + #include <stack> @@ -49,6 +53,11 @@ inline void reverse_face_verts(int *face_verts, int num_verts) face_verts[0] = last_vert; } +struct TopologyRefinerData { + const OpenSubdiv_Converter& conv; + std::vector<float> *uvs; +}; + } /* namespace */ #endif /* OPENSUBDIV_ORIENT_TOPOLOGY */ @@ -137,10 +146,11 @@ inline void check_oriented_vert_connectivity(const int num_vert_edges, } /* namespace */ template <> -inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopology( +inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology( TopologyRefiner& refiner, - const OpenSubdiv_Converter& conv) + const TopologyRefinerData& cb_data) { + const OpenSubdiv_Converter& conv = cb_data.conv; /* Faces and face-verts */ const int num_faces = conv.get_num_faces(&conv); setNumBaseFaces(refiner, num_faces); @@ -168,10 +178,11 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopolog } template <> -inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopology( +inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology( TopologyRefiner& refiner, - const OpenSubdiv_Converter& conv) + const TopologyRefinerData &cb_data) { + const OpenSubdiv_Converter& conv = cb_data.conv; using Far::IndexArray; /* Face relations. */ const int num_faces = conv.get_num_faces(&conv); @@ -332,7 +343,6 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog else { /* Special handle of non-manifold vertex. */ for (int i = 0; i < num_vert_edges; ++i) { - bool start_found = false; edge_start = vert_edges[i]; IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start); if (edge_faces.size() == 1) { @@ -343,14 +353,10 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog face_edges = getBaseFaceEdges(refiner, face_start); face_vert_start = findInArray(face_verts, vert); if (edge_start == face_edges[face_vert_start]) { - start_found = true; break; } } } - if (start_found) { - break; - } /* Reset indices for sanity check below. */ face_start = edge_start = face_vert_start = -1; } @@ -431,10 +437,11 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog }; template <> -inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags( +inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( TopologyRefiner& refiner, - const OpenSubdiv_Converter& conv) + const TopologyRefinerData& cb_data) { + const OpenSubdiv_Converter& conv = cb_data.conv; typedef OpenSubdiv::Sdc::Crease Crease; int num_edges = conv.get_num_edges(&conv); @@ -481,14 +488,52 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags( } template <> -inline void TopologyRefinerFactory<OpenSubdiv_Converter>::reportInvalidTopology( +inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology( TopologyError /*errCode*/, const char *msg, - const OpenSubdiv_Converter& /*mesh*/) + const TopologyRefinerData& /*mesh*/) { printf("OpenSubdiv Error: %s\n", msg); } +template <> +inline bool TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology( + TopologyRefiner& refiner, + const TopologyRefinerData& cb_data) +{ + const OpenSubdiv_Converter& conv = cb_data.conv; + const int num_layers = conv.get_num_uv_layers(&conv); + if (num_layers <= 0) { + /* No UV maps, we can skip any face-varying data. */ + return true; + } + const int num_faces = getNumBaseFaces(refiner); + size_t uvs_offset = 0; + for (int layer = 0; layer < num_layers; ++layer) { + conv.precalc_uv_layer(&conv, layer); + const int num_uvs = conv.get_num_uvs(&conv); + /* Fill in UV coordinates. */ + cb_data.uvs->resize(cb_data.uvs->size() + num_uvs * 2); + conv.get_uvs(&conv, &cb_data.uvs->at(uvs_offset)); + uvs_offset += num_uvs * 2; + /* Fill in per-corner index of the UV. */ + const int channel = createBaseFVarChannel(refiner, num_uvs); + for (int face = 0; face < num_faces; ++face) { + Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner, + face, + channel); + for (int corner = 0; corner < dst_face_uvs.size(); ++corner) { + const int uv_index = conv.get_face_corner_uv_index(&conv, + face, + corner); + dst_face_uvs[corner] = uv_index; + } + } + conv.finish_uv_layer(&conv); + } + return true; +} + } /* namespace Far */ } /* namespace OPENSUBDIV_VERSION */ } /* namespace OpenSubdiv */ @@ -522,33 +567,43 @@ struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr( Options options; options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY); options.SetCreasingMethod(Options::CREASE_UNIFORM); - options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL); + if (converter->get_subdiv_uvs(converter)) { + options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_CORNERS_ONLY); + } + else { + options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL); + } - TopologyRefinerFactory<OpenSubdiv_Converter>::Options + TopologyRefinerFactory<TopologyRefinerData>::Options topology_options(scheme_type, options); #ifdef OPENSUBDIV_VALIDATE_TOPOLOGY topology_options.validateFullTopology = true; #endif + OpenSubdiv_TopologyRefinerDescr *result = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerDescr); + TopologyRefinerData cb_data = {*converter, &result->uvs}; /* We don't use guarded allocation here so we can re-use the refiner * for GL mesh creation directly. */ - return (struct OpenSubdiv_TopologyRefinerDescr*) - TopologyRefinerFactory<OpenSubdiv_Converter>::Create( - *converter, + result->osd_refiner = + TopologyRefinerFactory<TopologyRefinerData>::Create( + cb_data, topology_options); + + return result; } void openSubdiv_deleteTopologyRefinerDescr( OpenSubdiv_TopologyRefinerDescr *topology_refiner) { - delete (OpenSubdiv::Far::TopologyRefiner *)topology_refiner; + delete topology_refiner->osd_refiner; + OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefinerDescr); } int openSubdiv_topologyRefinerGetSubdivLevel( const OpenSubdiv_TopologyRefinerDescr *topology_refiner) { using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; return refiner->GetMaxLevel(); } @@ -557,7 +612,7 @@ int openSubdiv_topologyRefinerGetNumVerts( { using OpenSubdiv::Far::TopologyLevel; using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); return base_level.GetNumVertices(); } @@ -567,7 +622,7 @@ int openSubdiv_topologyRefinerGetNumEdges( { using OpenSubdiv::Far::TopologyLevel; using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); return base_level.GetNumEdges(); } @@ -577,7 +632,7 @@ int openSubdiv_topologyRefinerGetNumFaces( { using OpenSubdiv::Far::TopologyLevel; using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); return base_level.GetNumFaces(); } @@ -588,7 +643,7 @@ int openSubdiv_topologyRefinerGetNumFaceVerts( { using OpenSubdiv::Far::TopologyLevel; using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); return base_level.GetFaceVertices(face).size(); } @@ -597,10 +652,11 @@ int openSubdiv_topologyRefnerCompareConverter( const OpenSubdiv_TopologyRefinerDescr *topology_refiner, OpenSubdiv_Converter *converter) { + typedef OpenSubdiv::Sdc::Options Options; using OpenSubdiv::Far::ConstIndexArray; using OpenSubdiv::Far::TopologyRefiner; using OpenSubdiv::Far::TopologyLevel; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); const int num_verts = base_level.GetNumVertices(); const int num_edges = base_level.GetNumEdges(); @@ -611,6 +667,12 @@ int openSubdiv_topologyRefnerCompareConverter( if (scheme_type != refiner->GetSchemeType()) { return false; } + const Options options = refiner->GetSchemeOptions(); + Options::FVarLinearInterpolation interp = options.GetFVarLinearInterpolation(); + const bool subdiv_uvs = (interp != Options::FVAR_LINEAR_ALL); + if (converter->get_subdiv_uvs(converter) != subdiv_uvs) { + return false; + } if (converter->get_num_verts(converter) != num_verts || converter->get_num_edges(converter) != num_edges || converter->get_num_faces(converter) != num_faces) diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h index 1f09fa074d8..6eda6ae5d8a 100644 --- a/intern/opensubdiv/opensubdiv_converter_capi.h +++ b/intern/opensubdiv/opensubdiv_converter_capi.h @@ -47,6 +47,8 @@ typedef struct OpenSubdiv_Converter { OpenSubdiv_SchemeType (*get_type)(const OpenSubdiv_Converter *converter); + bool (*get_subdiv_uvs)(const OpenSubdiv_Converter *converter); + int (*get_num_faces)(const OpenSubdiv_Converter *converter); int (*get_num_edges)(const OpenSubdiv_Converter *converter); int (*get_num_verts)(const OpenSubdiv_Converter *converter); @@ -83,6 +85,20 @@ typedef struct OpenSubdiv_Converter { int vert, int *vert_faces); + /* Face-varying data. */ + + int (*get_num_uv_layers)(const OpenSubdiv_Converter *converter); + + void (*precalc_uv_layer)(const OpenSubdiv_Converter *converter, int layer); + void (*finish_uv_layer)(const OpenSubdiv_Converter *converter); + + int (*get_num_uvs)(const OpenSubdiv_Converter *converter); + void (*get_uvs)(const OpenSubdiv_Converter *converter, float *uvs); + + int (*get_face_corner_uv_index)(const OpenSubdiv_Converter *converter, + int face, + int corner); + void (*free_user_data)(const OpenSubdiv_Converter *converter); void *user_data; } OpenSubdiv_Converter; diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc index 698fdfee00f..0cf6fcfef43 100644 --- a/intern/opensubdiv/opensubdiv_gpu_capi.cc +++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc @@ -42,11 +42,29 @@ #include <opensubdiv/osd/cpuGLVertexBuffer.h> #include <opensubdiv/osd/cpuEvaluator.h> +#include "MEM_guardedalloc.h" + +#include "opensubdiv_capi.h" +#include "opensubdiv_topology_refiner.h" + using OpenSubdiv::Osd::GLMeshInterface; extern "C" char datatoc_gpu_shader_opensubd_display_glsl[]; +/* TODO(sergey): This is bit of bad level calls :S */ +extern "C" { +void copy_m3_m3(float m1[3][3], float m2[3][3]); +void copy_m3_m4(float m1[3][3], float m2[4][4]); +void adjoint_m3_m3(float m1[3][3], float m[3][3]); +float determinant_m3_array(float m[3][3]); +bool invert_m3_m3(float m1[3][3], float m2[3][3]); +bool invert_m3(float m[3][3]); +void transpose_m3(float mat[3][3]); +} + #define MAX_LIGHTS 8 +#define SUPPORT_COLOR_MATERIAL + typedef struct Light { float position[4]; float ambient[4]; @@ -60,6 +78,7 @@ typedef struct Light { float spot_cutoff; float spot_exponent; float spot_cos_cutoff; + float pad, pad2; #endif } Light; @@ -75,114 +94,116 @@ typedef struct Transform { } Transform; static bool g_use_osd_glsl = false; -static int g_active_uv_index = -1; +static int g_active_uv_index = 0; static GLuint g_flat_fill_solid_program = 0; static GLuint g_flat_fill_texture2d_program = 0; static GLuint g_smooth_fill_solid_program = 0; static GLuint g_smooth_fill_texture2d_program = 0; + +static GLuint g_flat_fill_solid_shadeless_program = 0; +static GLuint g_flat_fill_texture2d_shadeless_program = 0; +static GLuint g_smooth_fill_solid_shadeless_program = 0; +static GLuint g_smooth_fill_texture2d_shadeless_program = 0; + static GLuint g_wireframe_program = 0; static GLuint g_lighting_ub = 0; static Lighting g_lighting_data; static Transform g_transform; -/* TODO(sergey): This is actually duplicated code from BLI. */ -namespace { -void copy_m3_m3(float m1[3][3], float m2[3][3]) -{ - /* destination comes first: */ - memcpy(&m1[0], &m2[0], 9 * sizeof(float)); -} - -void copy_m3_m4(float m1[3][3], float m2[4][4]) -{ - m1[0][0] = m2[0][0]; - m1[0][1] = m2[0][1]; - m1[0][2] = m2[0][2]; - - m1[1][0] = m2[1][0]; - m1[1][1] = m2[1][1]; - m1[1][2] = m2[1][2]; - - m1[2][0] = m2[2][0]; - m1[2][1] = m2[2][1]; - m1[2][2] = m2[2][2]; -} - -void adjoint_m3_m3(float m1[3][3], float m[3][3]) -{ - m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1]; - m1[0][1] = -m[0][1] * m[2][2] + m[0][2] * m[2][1]; - m1[0][2] = m[0][1] * m[1][2] - m[0][2] * m[1][1]; - - m1[1][0] = -m[1][0] * m[2][2] + m[1][2] * m[2][0]; - m1[1][1] = m[0][0] * m[2][2] - m[0][2] * m[2][0]; - m1[1][2] = -m[0][0] * m[1][2] + m[0][2] * m[1][0]; - - m1[2][0] = m[1][0] * m[2][1] - m[1][1] * m[2][0]; - m1[2][1] = -m[0][0] * m[2][1] + m[0][1] * m[2][0]; - m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0]; -} - -float determinant_m3_array(float m[3][3]) +struct OpenSubdiv_GLMeshFVarData { - return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - - m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) + - m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1])); -} - -bool invert_m3_m3(float m1[3][3], float m2[3][3]) -{ - float det; - int a, b; - bool success; - - /* calc adjoint */ - adjoint_m3_m3(m1, m2); + OpenSubdiv_GLMeshFVarData() : + texture_buffer(0) { + } - /* then determinant old matrix! */ - det = determinant_m3_array(m2); + ~OpenSubdiv_GLMeshFVarData() + { + Release(); + } - success = (det != 0.0f); + void Release() + { + if (texture_buffer) { + glDeleteTextures(1, &texture_buffer); + } + if (offset_buffer) { + glDeleteTextures(1, &offset_buffer); + } + texture_buffer = 0; + offset_buffer = 0; + fvar_width = 0; + channel_offsets.clear(); + } - if (det != 0.0f) { - det = 1.0f / det; - for (a = 0; a < 3; a++) { - for (b = 0; b < 3; b++) { - m1[a][b] *= det; + void Create(const OpenSubdiv::Far::TopologyRefiner *refiner, + const OpenSubdiv::Far::PatchTable *patch_table, + int fvar_width, + const float *fvar_src_data) + { + Release(); + + this->fvar_width = fvar_width; + + /* Expand fvar data to per-patch array */ + const int max_level = refiner->GetMaxLevel(); + const int num_channels = patch_table->GetNumFVarChannels(); + std::vector<float> data; + int fvar_data_offset = 0; + channel_offsets.resize(num_channels); + for (int channel = 0; channel < num_channels; ++channel) { + OpenSubdiv::Far::ConstIndexArray indices = + patch_table->GetFVarValues(channel); + + channel_offsets[channel] = data.size(); + data.reserve(data.size() + indices.size() * fvar_width); + + for (int fvert = 0; fvert < (int)indices.size(); ++fvert) { + int index = indices[fvert] * fvar_width; + for (int i = 0; i < fvar_width; ++i) { + data.push_back(fvar_src_data[fvar_data_offset + index++]); + } + } + if (refiner->IsUniform()) { + const int num_values_max = refiner->GetLevel(max_level).GetNumFVarValues(channel); + fvar_data_offset += num_values_max * fvar_width; + } else { + const int num_values_total = refiner->GetNumFVarValuesTotal(channel); + fvar_data_offset += num_values_total * fvar_width; } } - } - return success; -} + GLuint buffer; + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, data.size()*sizeof(float), + &data[0], GL_STATIC_DRAW); -bool invert_m3(float m[3][3]) -{ - float tmp[3][3]; - bool success; + glGenTextures(1, &texture_buffer); + glBindTexture(GL_TEXTURE_BUFFER, texture_buffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer); - success = invert_m3_m3(tmp, m); - copy_m3_m3(m, tmp); + glDeleteBuffers(1, &buffer); - return success; -} + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, channel_offsets.size()*sizeof(int), + &channel_offsets[0], GL_STATIC_DRAW); -void transpose_m3(float mat[3][3]) -{ - float t; - - t = mat[0][1]; - mat[0][1] = mat[1][0]; - mat[1][0] = t; - t = mat[0][2]; - mat[0][2] = mat[2][0]; - mat[2][0] = t; - t = mat[1][2]; - mat[1][2] = mat[2][1]; - mat[2][1] = t; -} + glGenTextures(1, &offset_buffer); + glBindTexture(GL_TEXTURE_BUFFER, offset_buffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + GLuint texture_buffer; + GLuint offset_buffer; + std::vector<int> channel_offsets; + int fvar_width; +}; + +namespace { GLuint compileShader(GLenum shaderType, const char *section, @@ -196,11 +217,14 @@ GLuint compileShader(GLenum shaderType, version, define, sdefine, +#ifdef SUPPORT_COLOR_MATERIAL + "#define SUPPORT_COLOR_MATERIAL\n", +#endif datatoc_gpu_shader_opensubd_display_glsl }; GLuint shader = glCreateShader(shaderType); - glShaderSource(shader, 4, sources, NULL); + glShaderSource(shader, 5, sources, NULL); glCompileShader(shader); GLint status; @@ -295,14 +319,17 @@ GLuint linkProgram(const char *version, const char *define) 0); /* GL_TEXTURE0 */ glProgramUniform1i(program, + glGetUniformLocation(program, "FVarDataOffsetBuffer"), + 30); /* GL_TEXTURE30 */ + + glProgramUniform1i(program, glGetUniformLocation(program, "FVarDataBuffer"), 31); /* GL_TEXTURE31 */ return program; } -void bindProgram(GLMeshInterface * /*mesh*/, - int program) +void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program) { glUseProgram(program); @@ -346,23 +373,34 @@ void bindProgram(GLMeshInterface * /*mesh*/, glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color); } - /* TODO(sergey): Bring face varying back. */ -#if 0 /* Face-vertex data */ - if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) { - glActiveTexture(GL_TEXTURE31); - glBindTexture(GL_TEXTURE_BUFFER, - mesh->GetDrawContext()->GetFvarDataTextureBuffer()); - glActiveTexture(GL_TEXTURE0); - } -#endif + if (gl_mesh->fvar_data != NULL) { + if (gl_mesh->fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } - /* TODO(sergey): Bring face varying back. */ - glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), - 0/* * mesh->GetFVarCount()*/); + if (gl_mesh->fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } - glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), - g_active_uv_index * 2); + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), + gl_mesh->fvar_data->fvar_width); + if (gl_mesh->fvar_data->channel_offsets.size() > 0 && + g_active_uv_index >= 0) + { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), + gl_mesh->fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } } } /* namespace */ @@ -390,11 +428,51 @@ bool openSubdiv_osdGLDisplayInit(void) /* minimum supported for OpenSubdiv */ } - g_flat_fill_solid_program = linkProgram(version, "#define FLAT_SHADING\n"); - g_flat_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define FLAT_SHADING\n"); - g_smooth_fill_solid_program = linkProgram(version, "#define SMOOTH_SHADING\n"); - g_smooth_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n"); - g_wireframe_program = linkProgram(version, "#define WIREFRAME\n"); + g_flat_fill_solid_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + + g_flat_fill_solid_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + + g_wireframe_program = linkProgram( + version, + "#define WIREFRAME\n"); glGenBuffers(1, &g_lighting_ub); glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); @@ -416,28 +494,31 @@ void openSubdiv_osdGLDisplayDeinit(void) if (g_lighting_ub != 0) { glDeleteBuffers(1, &g_lighting_ub); } - if (g_flat_fill_solid_program) { - glDeleteProgram(g_flat_fill_solid_program); - } - if (g_flat_fill_texture2d_program) { - glDeleteProgram(g_flat_fill_texture2d_program); - } - if (g_smooth_fill_solid_program) { - glDeleteProgram(g_flat_fill_solid_program); - } - if (g_smooth_fill_texture2d_program) { - glDeleteProgram(g_smooth_fill_texture2d_program); - } - if (g_wireframe_program) { - glDeleteProgram(g_wireframe_program); - } +#define SAFE_DELETE_PROGRAM(program) \ + do { \ + if (program) { \ + glDeleteProgram(program); \ + } \ + } while (false) + + SAFE_DELETE_PROGRAM(g_flat_fill_solid_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_wireframe_program); + +#undef SAFE_DELETE_PROGRAM } void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, int active_uv_index) { - g_use_osd_glsl = use_osd_glsl != 0; g_active_uv_index = active_uv_index; + g_use_osd_glsl = (use_osd_glsl != 0); /* Update transformation matrices. */ glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix); @@ -494,7 +575,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, } } -static GLuint prepare_patchDraw(GLMeshInterface *mesh, +static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh, bool fill_quads) { GLint program = 0; @@ -509,51 +590,74 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh, glUniform1i(location, model == GL_FLAT); } - /* TODO(sergey): Bring this back. */ -#if 0 /* Face-vertex data */ - if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) { - glActiveTexture(GL_TEXTURE31); - glBindTexture(GL_TEXTURE_BUFFER, - mesh->GetDrawContext()->GetFvarDataTextureBuffer()); - glActiveTexture(GL_TEXTURE0); + if (gl_mesh->fvar_data != NULL) { + if (gl_mesh->fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, + gl_mesh->fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } + + if (gl_mesh->fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, + gl_mesh->fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } GLint location = glGetUniformLocation(program, "osd_fvar_count"); if (location != -1) { - glUniform1i(location, mesh->GetFVarCount()); + glUniform1i(location, gl_mesh->fvar_data->fvar_width); } location = glGetUniformLocation(program, "osd_active_uv_offset"); if (location != -1) { - glUniform1i(location, - g_active_uv_index * 2); + if (gl_mesh->fvar_data->channel_offsets.size() > 0 && + g_active_uv_index >= 0) + { + glUniform1i(location, + gl_mesh->fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(location, 0); + } } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); } -#endif - } return program; } if (fill_quads) { int model; - GLboolean use_texture_2d; + GLboolean use_texture_2d, use_lighting; glGetIntegerv(GL_SHADE_MODEL, &model); glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d); + glGetBooleanv(GL_LIGHTING, &use_lighting); if (model == GL_FLAT) { if (use_texture_2d) { - program = g_flat_fill_texture2d_program; + program = use_lighting + ? g_flat_fill_texture2d_program + : g_flat_fill_texture2d_shadeless_program; } else { - program = g_flat_fill_solid_program; + program = use_lighting + ? g_flat_fill_solid_program + : g_flat_fill_solid_shadeless_program; } } else { if (use_texture_2d) { - program = g_smooth_fill_texture2d_program; + program = use_lighting + ? g_smooth_fill_texture2d_program + : g_smooth_fill_texture2d_shadeless_program; } else { - program = g_smooth_fill_solid_program; + program = use_lighting + ? g_smooth_fill_solid_program + : g_smooth_fill_solid_shadeless_program; } } } @@ -562,7 +666,7 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh, program = g_wireframe_program; } - bindProgram(mesh, program); + bindProgram(gl_mesh, program); return program; } @@ -623,7 +727,7 @@ static void draw_partition_patches_range(GLMeshInterface *mesh, const int num_draw_patches = std::min(num_remained_patches, num_block_patches - start_draw_patch); perform_drawElements(program, - i, + i + start_draw_patch, num_draw_patches * num_control_verts, patch.GetIndexBase() + start_draw_patch * num_control_verts); num_remained_patches -= num_draw_patches; @@ -669,7 +773,7 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, } /* Setup GLSL/OpenGL to draw patches in current context. */ - GLuint program = prepare_patchDraw(mesh, fill_quads != 0); + GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0); if (start_patch != -1) { draw_partition_patches_range(mesh, @@ -684,3 +788,23 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, /* Finish patch drawing by restoring all changes to the OpenGL context. */ finish_patchDraw(fill_quads != 0); } + +void openSubdiv_osdGLAllocFVar(OpenSubdiv_TopologyRefinerDescr *topology_refiner, + OpenSubdiv_GLMesh *gl_mesh, + const float *fvar_data) +{ + GLMeshInterface *mesh = + (GLMeshInterface *)(gl_mesh->descriptor); + gl_mesh->fvar_data = OBJECT_GUARDED_NEW(OpenSubdiv_GLMeshFVarData); + gl_mesh->fvar_data->Create(topology_refiner->osd_refiner, + mesh->GetFarPatchTable(), + 2, + fvar_data); +} + +void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh) +{ + if (gl_mesh->fvar_data != NULL) { + OBJECT_GUARDED_DELETE(gl_mesh->fvar_data, OpenSubdiv_GLMeshFVarData); + } +} diff --git a/intern/opensubdiv/opensubdiv_topology_refiner.h b/intern/opensubdiv/opensubdiv_topology_refiner.h new file mode 100644 index 00000000000..b00f6a54201 --- /dev/null +++ b/intern/opensubdiv/opensubdiv_topology_refiner.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. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __OPENSUBDIV_TOPOLOGY_REFINER_H__ +#define __OPENSUBDIV_TOPOLOGY_REFINER_H__ + +#include <opensubdiv/far/topologyRefiner.h> + +typedef struct OpenSubdiv_TopologyRefinerDescr { + OpenSubdiv::Far::TopologyRefiner *osd_refiner; + + /* TODO(sergey): For now only, need to find better place + * after revisiting whole OSD drawing pipeline and Blender + * integration. + */ + std::vector<float> uvs; +} OpenSubdiv_TopologyRefinerDescr; + +#endif /* __OPENSUBDIV_TOPOLOGY_REFINER_H__ */ diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py index dd6b79f6686..07fc9f0c338 100644 --- a/release/scripts/modules/bl_i18n_utils/settings.py +++ b/release/scripts/modules/bl_i18n_utils/settings.py @@ -329,16 +329,21 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = { "available with", "brown fox", "can't save image while rendering", + "constructive modifier", + "edge data", "expected a timeline/animation area to be active", "expected a view3d region", "expected a view3d region & editcurve", "expected a view3d region & editmesh", + "face data", "image file not found", "image format is read-only", "image path can't be written to", "in memory to enable editing!", "jumps over", "left", + "multi-res modifier", + "non-triangle face", "right", "the lazy dog", "unable to load movie clip", @@ -351,6 +356,7 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = { "unsupported format", "unsupported image format", "unsupported movie clip format", + "vertex data", "verts only", "virtual parents", } diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py index 98a117e95a6..ba782160edd 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py +++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py @@ -565,7 +565,9 @@ class SpellChecker: "ui", "unix", "vbo", "vbos", + "wxyz", "ycc", "ycca", + "yrgb", "yuv", "yuva", # Blender acronyms diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py index 021a8bbb530..0cc6462e8d1 100644 --- a/release/scripts/modules/bpy_extras/anim_utils.py +++ b/release/scripts/modules/bpy_extras/anim_utils.py @@ -155,6 +155,11 @@ def bake_action(frame_start, atd = obj.animation_data_create() if action is None: action = bpy.data.actions.new("Action") + + # Leave tweak mode before trying to modify the action (T48397) + if atd.use_tweak_mode: + atd.use_tweak_mode = False + atd.action = action # ------------------------------------------------------------------------- diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index a120e2b2461..3b095c883a3 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -285,8 +285,7 @@ def lightmap_uvpack(meshes, for face_sel in face_groups: print("\nStarting unwrap") - if len(face_sel) < 4: - print("\tWarning, less then 4 faces, skipping") + if not face_sel: continue pretty_faces = [prettyface(f) for f in face_sel if f.loop_total >= 4] diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index af8431ba1dc..33af812b6c4 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -125,7 +125,7 @@ class DATA_PT_shape_curve(CurveButtonsPanel, Panel): col.prop(curve, "use_fill_deform") if is_curve: - col.label(text="Path / Curve-Deform:") + col.label(text="Path/Curve-Deform:") sub = col.column() subsub = sub.row() subsub.prop(curve, "use_radius") diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 7863c075344..c6bb6ccf05f 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -151,21 +151,16 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column() col.label(text="Operation:") col.prop(md, "operation", text="") + row = layout.row() + row.label("Solver:") + row.prop(md, "solver", expand=True) col = split.column() col.label(text="Object:") col.prop(md, "object", text="") - """ - layout.prop(md, "use_bmesh") - if md.use_bmesh: - box = layout.box() - box.label("BMesh Options:") - box.prop(md, "use_bmesh_separate") - box.prop(md, "use_bmesh_dissolve") - box.prop(md, "use_bmesh_connect_regions") - box.prop(md, "threshold") - """ + if md.solver == 'BMESH': + layout.prop(md, "double_threshold") def BUILD(self, layout, ob, md): split = layout.split() diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index 8bb3cf2814c..58bb956f653 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -950,7 +950,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel): class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel): bl_space_type = 'CLIP_EDITOR' bl_region_type = 'UI' - bl_label = "Proxy / Timecode" + bl_label = "Proxy/Timecode" bl_options = {'DEFAULT_CLOSED'} def draw_header(self, context): diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index ab95ea7f4a4..9a28776ef10 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -310,19 +310,36 @@ class INFO_MT_help(Menu): def draw(self, context): layout = self.layout - layout.operator("wm.url_open", text="Manual", icon='HELP').url = "https://www.blender.org/manual" - layout.operator("wm.url_open", text="Release Log", icon='URL').url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2] + layout.operator( + "wm.url_open", text="Manual", icon='HELP', + ).url = "https://www.blender.org/manual" + layout.operator( + "wm.url_open", text="Release Log", icon='URL', + ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2] layout.separator() - layout.operator("wm.url_open", text="Blender Website", icon='URL').url = "https://www.blender.org" - layout.operator("wm.url_open", text="Blender Store", icon='URL').url = "https://store.blender.org" - layout.operator("wm.url_open", text="Developer Community", icon='URL').url = "https://www.blender.org/get-involved/" - layout.operator("wm.url_open", text="User Community", icon='URL').url = "https://www.blender.org/support/user-community" + layout.operator( + "wm.url_open", text="Blender Website", icon='URL', + ).url = "https://www.blender.org" + layout.operator( + "wm.url_open", text="Blender Store", icon='URL', + ).url = "https://store.blender.org" + layout.operator( + "wm.url_open", text="Developer Community", icon='URL', + ).url = "https://www.blender.org/get-involved/" + layout.operator( + "wm.url_open", text="User Community", icon='URL', + ).url = "https://www.blender.org/support/user-community" layout.separator() - layout.operator("wm.url_open", text="Report a Bug", icon='URL').url = "https://developer.blender.org/maniphest/task/create/?project=2&type=Bug" + layout.operator( + "wm.url_open", text="Report a Bug", icon='URL', + ).url = "https://developer.blender.org/maniphest/task/edit/form/1" layout.separator() - layout.operator("wm.url_open", text="Python API Reference", icon='URL').url = bpy.types.WM_OT_doc_view._prefix + layout.operator( + "wm.url_open", text="Python API Reference", icon='URL', + ).url = bpy.types.WM_OT_doc_view._prefix + layout.operator("wm.operator_cheat_sheet", icon='TEXT') layout.operator("wm.sysinfo", icon='TEXT') layout.separator() diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 539ee7a6af4..4d1b9104344 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -972,7 +972,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): - bl_label = "Proxy / Timecode" + bl_label = "Proxy/Timecode" @classmethod def poll(cls, context): diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index dc46aed08c0..1512f4f4600 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -489,7 +489,7 @@ class USERPREF_PT_system(Panel): col.separator() - col.label(text="Sequencer / Clip Editor:") + col.label(text="Sequencer/Clip Editor:") # currently disabled in the code # col.prop(system, "prefetch_frames") col.prop(system, "memory_cache_limit") @@ -1416,7 +1416,7 @@ class USERPREF_PT_addons(Panel): split.operator("wm.url_open", text="Documentation", icon='HELP').url = info["wiki_url"] split.operator("wm.url_open", text="Report a Bug", icon='URL').url = info.get( "tracker_url", - "http://developer.blender.org/maniphest/task/create/?project=3&type=Bug") + "https://developer.blender.org/maniphest/task/edit/form/2") if user_addon: split.operator("wm.addon_remove", text="Remove", icon='CANCEL').module = mod.__name__ diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 09e3bf38333..fdf0996ac1e 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -367,6 +367,7 @@ class VIEW3D_MT_snap(Menu): layout.operator("view3d.snap_selected_to_grid", text="Selection to Grid") layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor").use_offset = False layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Offset)").use_offset = True + layout.operator("view3d.snap_selected_to_active", text="Selection to Active") layout.separator() @@ -2471,6 +2472,7 @@ class VIEW3D_MT_edit_mesh_edges(Menu): layout.operator("mesh.edge_face_add") layout.operator("mesh.subdivide") + layout.operator("mesh.subdivide_edgering") layout.operator("mesh.unsubdivide") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index ca1ab4c37dd..e9f4d715ec2 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -570,6 +570,7 @@ class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel): if cps.curve_type == 'BEZIER': col.label("Bezier Options:") col.prop(cps, "error_threshold") + col.prop(cps, "fit_method") col.prop(cps, "use_corners_detect") col = layout.column() @@ -1607,7 +1608,7 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel): class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel): bl_category = "Tools" - bl_label = "Symmetry / Lock" + bl_label = "Symmetry/Lock" bl_options = {'DEFAULT_CLOSED'} @classmethod diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index dfebaecb96e..44a1d08f1fd 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -370,12 +370,10 @@ static void blf_font_draw_buffer_ex( fbuf[3] = 1.0f; } else { - float alphatest; fbuf[0] = (b_col_float[0] * a) + (fbuf[0] * (1.0f - a)); fbuf[1] = (b_col_float[1] * a) + (fbuf[1] * (1.0f - a)); fbuf[2] = (b_col_float[2] * a) + (fbuf[2] * (1.0f - a)); - fbuf[3] = (alphatest = (fbuf[3] + a)) < 1.0f ? - alphatest : 1.0f; + fbuf[3] = MIN2(fbuf[3] + a, 1.0f); /* clamp to 1.0 */ } } } @@ -407,12 +405,10 @@ static void blf_font_draw_buffer_ex( cbuf[3] = 255; } else { - int alphatest; cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a))); cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a))); cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a))); - cbuf[3] = (unsigned char)(((alphatest = ((int)cbuf[3] + (int)(a * 255))) < 255) ? - alphatest : 255); + cbuf[3] = (unsigned char)MIN2((int)cbuf[3] + (int)(a * 255), 255); /* clamp to 255 */ } } } diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 5874f95502b..6527ba7f94f 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -63,7 +63,7 @@ struct bAction *BKE_action_copy(struct Main *bmain, struct bAction *src); /* Deallocate all of the Action's data, but not the Action itself */ void BKE_action_free(struct bAction *act); -void BKE_action_make_local(struct Main *bmain, struct bAction *act); +void BKE_action_make_local(struct Main *bmain, struct bAction *act, const bool lib_local); /* Action API ----------------- */ diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 326c335338f..c2323100205 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -76,7 +76,7 @@ struct bArmature *BKE_armature_from_object(struct Object *ob); int BKE_armature_bonelist_count(struct ListBase *lb); void BKE_armature_bonelist_free(struct ListBase *lb); void BKE_armature_free(struct bArmature *arm); -void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm); +void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm, const bool lib_local); struct bArmature *BKE_armature_copy(struct Main *bmain, struct bArmature *arm); /* Bounding box. */ @@ -95,6 +95,7 @@ float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3 void BKE_armature_where_is(struct bArmature *arm); void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion); +void BKE_pose_clear_pointers(struct bPose *pose); void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm); void BKE_pose_where_is(struct Scene *scene, struct Object *ob); void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra); diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset_engine.h index 4a5ed587c3f..db6769e1c74 100644 --- a/source/blender/blenkernel/BKE_asset.h +++ b/source/blender/blenkernel/BKE_asset_engine.h @@ -25,12 +25,12 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file BKE_asset.h +/** \file BKE_asset_engine.h * \ingroup bke */ -#ifndef __BKE_ASSET_H__ -#define __BKE_ASSET_H__ +#ifndef __BKE_ASSET_ENGINE_H__ +#define __BKE_ASSET_ENGINE_H__ #ifdef __cplusplus extern "C" { @@ -234,12 +234,13 @@ void BKE_filedir_entryarr_clear(struct FileDirEntryArr *array); ASSETUUID_SUB_COMPARE(_uuida, _uuidb, uuid_variant) && \ ASSETUUID_SUB_COMPARE(_uuida, _uuidb, uuid_revision)) -/* GHash helpers */ +/* Various helpers */ unsigned int BKE_asset_uuid_hash(const void *key); bool BKE_asset_uuid_cmp(const void *a, const void *b); +void BKE_asset_uuid_print(const struct AssetUUID *uuid); #ifdef __cplusplus } #endif -#endif /* __BKE_ASSET_H__ */ +#endif /* __BKE_ASSET_ENGINE_H__ */ diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index c7116bf2ef6..8bd4bdf89e1 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -45,7 +45,7 @@ void BKE_brush_init(struct Brush *brush); struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode); struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode); struct Brush *BKE_brush_copy(struct Main *bmain, struct Brush *brush); -void BKE_brush_make_local(struct Main *bmain, struct Brush *brush); +void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local); void BKE_brush_unlink(struct Main *bmain, struct Brush *brush); void BKE_brush_free(struct Brush *brush); diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index 97f4b30894b..31a732cf7e5 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -53,7 +53,7 @@ struct GPUFXSettings; void BKE_camera_init(struct Camera *cam); void *BKE_camera_add(struct Main *bmain, const char *name); struct Camera *BKE_camera_copy(struct Main *bmain, struct Camera *cam); -void BKE_camera_make_local(struct Main *bmain, struct Camera *cam); +void BKE_camera_make_local(struct Main *bmain, struct Camera *cam, const bool lib_local); void BKE_camera_free(struct Camera *ca); /* Camera Usage */ diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 89dbe246910..5558786d254 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -71,7 +71,7 @@ void BKE_curve_editfont_free(struct Curve *cu); void BKE_curve_init(struct Curve *cu); struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type); struct Curve *BKE_curve_copy(struct Main *bmain, struct Curve *cu); -void BKE_curve_make_local(struct Main *bmain, struct Curve *cu); +void BKE_curve_make_local(struct Main *bmain, struct Curve *cu, const bool lib_local); short BKE_curve_type_get(struct Curve *cu); void BKE_curve_type_test(struct Object *ob); void BKE_curve_curve_dimension_update(struct Curve *cu); diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h index 0711c423d1c..6775639125f 100644 --- a/source/blender/blenkernel/BKE_font.h +++ b/source/blender/blenkernel/BKE_font.h @@ -82,6 +82,8 @@ struct VFont *BKE_vfont_load(struct Main *bmain, const char *filepath); struct VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists); struct VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath); +void BKE_vfont_make_local(struct Main *bmain, struct VFont *vfont, const bool lib_local); + bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, int mode, struct ListBase *r_nubase, const wchar_t **r_text, int *r_text_len, bool *r_text_free, diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 6159531d8bd..e9e3cd3b16e 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -56,6 +56,8 @@ struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src); struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src); struct bGPdata *gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy); +void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local); + void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 4f2c89070cb..09a069ee36f 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -43,6 +43,7 @@ struct Scene; void BKE_group_free(struct Group *group); struct Group *BKE_group_add(struct Main *bmain, const char *name); struct Group *BKE_group_copy(struct Main *bmain, struct Group *group); +void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local); bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); struct Group *BKE_group_object_find(struct Group *group, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index 763a3874d4e..efef8d4be78 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -55,7 +55,7 @@ void BKE_icons_init(int first_dyn_id); /* return icon id for library object or create new icon if not found */ int BKE_icon_id_ensure(struct ID *id); -int BKE_icon_preview_ensure(struct PreviewImage *preview); +int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview); /* retrieve icon for id */ struct Icon *BKE_icon_get(int icon_id); @@ -99,6 +99,8 @@ struct PreviewImage *BKE_previewimg_create(void); /* create a copy of the preview image */ struct PreviewImage *BKE_previewimg_copy(struct PreviewImage *prv); +void BKE_previewimg_id_copy(struct ID *new_id, struct ID *old_id); + /* retrieve existing or create new preview image */ struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 0895feef983..132c73209d1 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -108,7 +108,7 @@ struct anim *openanim_noload(const char *name, int flags, int streamindex, char void BKE_image_de_interlace(struct Image *ima, int odd); -void BKE_image_make_local(struct Main *bmain, struct Image *ima); +void BKE_image_make_local(struct Main *bmain, struct Image *ima, const bool lib_local); void BKE_image_tag_time(struct Image *ima); diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index f30f9eac4e8..e590ff148d7 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -53,7 +53,6 @@ void BKE_key_free_nolib(struct Key *key); struct Key *BKE_key_add(struct ID *id); struct Key *BKE_key_copy(struct Main *bmain, struct Key *key); struct Key *BKE_key_copy_nolib(struct Key *key); -void BKE_key_make_local(struct Main *bmain, struct Key *key); void BKE_key_sort(struct Key *key); void key_curve_position_weights(float t, float data[4], int type); diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h index 49b43550e67..4d53850c572 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -46,7 +46,7 @@ void BKE_lamp_init(struct Lamp *la); struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; struct Lamp *BKE_lamp_copy(struct Main *bmain, struct Lamp *la) ATTR_WARN_UNUSED_RESULT; struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; -void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la); +void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local); void BKE_lamp_free(struct Lamp *la); void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 606df9dcec8..226c82da295 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -49,7 +49,7 @@ void BKE_lattice_init(struct Lattice *lt); struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); struct Lattice *BKE_lattice_copy(struct Main *bmain, struct Lattice *lt); void BKE_lattice_free(struct Lattice *lt); -void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt); +void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); struct LatticeDeformData; diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 396a3486b06..95d50fbd396 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -82,15 +82,17 @@ void id_us_min(struct ID *id); void id_fake_user_set(struct ID *id); void id_fake_user_clear(struct ID *id); -bool id_make_local(struct Main *bmain, struct ID *id, bool test); +void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_in_mainlist, const bool lib_local); +bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local); bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test); void id_sort_by_name(struct ListBase *lb, struct ID *id); void BKE_id_expand_local(struct ID *id); +void BKE_id_copy_ensure_local(struct Main *bmain, struct ID *old_id, struct ID *new_id); bool new_id(struct ListBase *lb, struct ID *id, const char *name); void id_clear_lib_data(struct Main *bmain, struct ID *id); -void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, bool id_in_mainlist); +void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_mainlist); struct ListBase *which_libbase(struct Main *mainlib, short type); diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index e343cd29622..e96ef4e7be3 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -54,6 +54,8 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name); void BKE_linestyle_free(FreestyleLineStyle *linestyle); FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle); +void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local); + FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene); LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 97bfd0f3f07..3349bffac85 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -125,6 +125,8 @@ struct Mask *BKE_mask_new(struct Main *bmain, const char *name); struct Mask *BKE_mask_copy_nolib(struct Mask *mask); struct Mask *BKE_mask_copy(struct Main *bmain, struct Mask *mask); +void BKE_mask_make_local(struct Main *bmain, struct Mask *mask, const bool lib_local); + void BKE_mask_free(struct Mask *mask); void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]); diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 0bc54ee4a16..df739996c54 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -57,7 +57,7 @@ struct Material *BKE_material_add(struct Main *bmain, const char *name); struct Material *BKE_material_copy(struct Main *bmain, struct Material *ma); struct Material *localize_material(struct Material *ma); struct Material *give_node_material(struct Material *ma); /* returns node material or self */ -void BKE_material_make_local(struct Main *bmain, struct Material *ma); +void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local); /* UNUSED */ // void automatname(struct Material *); @@ -78,15 +78,13 @@ enum { }; struct Material *give_current_material(struct Object *ob, short act); -struct ID *material_from(struct Object *ob, short act); void assign_material_id(struct ID *id, struct Material *ma, short act); void assign_material(struct Object *ob, struct Material *ma, short act, int assign_type); void assign_matarar(struct Object *ob, struct Material ***matar, short totcol); -short find_material_index(struct Object *ob, struct Material *ma); - -bool object_add_material_slot(struct Object *ob); -bool object_remove_material_slot(struct Object *ob); +short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma); +bool BKE_object_material_slot_add(struct Object *ob); +bool BKE_object_material_slot_remove(struct Object *ob); void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma); void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 42704c1b2db..64320a20281 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -43,7 +43,7 @@ void BKE_mball_init(struct MetaBall *mb); struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name); struct MetaBall *BKE_mball_copy(struct Main *bmain, struct MetaBall *mb); -void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb); +void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool lib_local); bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2); bool BKE_mball_is_basis(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index d3bb34d7a41..d41878825bb 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -91,7 +91,7 @@ struct Mesh *BKE_mesh_copy(struct Main *bmain, struct Mesh *me); void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd); void BKE_mesh_ensure_skin_customdata(struct Mesh *me); -void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me); +void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool lib_local); void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]); void BKE_mesh_texspace_calc(struct Mesh *me); float (*BKE_mesh_orco_verts_get(struct Object *ob))[3]; diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index dff79b6cc22..b5b5443574c 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -125,6 +125,11 @@ void BKE_mesh_vert_edge_map_create( void BKE_mesh_vert_edge_vert_map_create( MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge); +void BKE_mesh_edge_loop_map_create( + MeshElemMap **r_map, int **r_mem, + const struct MEdge *medge, const int totedge, + const struct MPoly *mpoly, const int totpoly, + const struct MLoop *mloop, const int totloop); void BKE_mesh_edge_poly_map_create( MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, const int totedge, @@ -186,11 +191,19 @@ typedef bool (*MeshRemapIslandsCalc)( /* Above vert/UV mapping stuff does not do what we need here, but does things we do not need here. * So better keep them separated for now, I think. */ -bool BKE_mesh_calc_islands_loop_poly_uv( +bool BKE_mesh_calc_islands_loop_poly_edgeseam( + struct MVert *verts, const int totvert, + struct MEdge *edges, const int totedge, + struct MPoly *polys, const int totpoly, + struct MLoop *loops, const int totloop, + MeshIslandStore *r_island_store); + +bool BKE_mesh_calc_islands_loop_poly_uvmap( struct MVert *verts, const int totvert, struct MEdge *edges, const int totedge, struct MPoly *polys, const int totpoly, struct MLoop *loops, const int totloop, + const struct MLoopUV *luvs, MeshIslandStore *r_island_store); int *BKE_mesh_calc_smoothgroups( diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index b44cb226f0d..95f06e9f695 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -346,7 +346,7 @@ void ntreeUserDecrefID(struct bNodeTree *ntree); struct bNodeTree *ntreeFromID(struct ID *id); -void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist); +void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist, const bool lib_local); struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type); bool ntreeHasType(const struct bNodeTree *ntree, int type); bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 1f0dc5f1814..1b3e05d11ae 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -107,7 +107,7 @@ struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene); struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches); struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob); -void BKE_object_make_local(struct Main *bmain, struct Object *ob); +void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool lib_local); bool BKE_object_is_libdata(struct Object *ob); bool BKE_object_obdata_is_libdata(struct Object *ob); @@ -206,8 +206,6 @@ void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); -void BKE_object_eval_proxy_backlink(struct EvaluationContext *eval_ctx, struct Object *ob); - void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 0b2e2383457..37831728e6f 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -324,7 +324,7 @@ struct ModifierData *object_add_particle_system(struct Scene *scene, struct Obje void object_remove_particle_system(struct Scene *scene, struct Object *ob); struct ParticleSettings *psys_new_settings(const char *name, struct Main *main); struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, struct ParticleSettings *part); -void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part); +void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool lib_local); void psys_reset(struct ParticleSystem *psys, int mode); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 03af0b7d6c9..d2152950bff 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -101,6 +101,8 @@ struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name); struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type); void BKE_scene_groups_relink(struct Scene *sce); +void BKE_scene_make_local(struct Main *bmain, struct Scene *sce, const bool lib_local); + struct Object *BKE_scene_camera_find(struct Scene *sc); #ifdef DURIAN_CAMERA_SWITCH struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 18d9fe061a8..28b15b2a310 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -80,6 +80,8 @@ void BKE_sound_load(struct Main *main, struct bSound *sound); void BKE_sound_free(struct bSound *sound); +void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool lib_local); + #if defined(__AUD_C_API_H__) || defined(WITH_SYSTEM_AUDASPACE) AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume); #endif diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h index 89b948a2126..b91b64c4b74 100644 --- a/source/blender/blenkernel/BKE_speaker.h +++ b/source/blender/blenkernel/BKE_speaker.h @@ -34,7 +34,7 @@ struct Speaker; void BKE_speaker_init(struct Speaker *spk); void *BKE_speaker_add(struct Main *bmain, const char *name); struct Speaker *BKE_speaker_copy(struct Main *bmain, struct Speaker *spk); -void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk); +void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk, const bool lib_local); void BKE_speaker_free(struct Speaker *spk); #endif diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 858feeeab10..081b7589af6 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -53,6 +53,7 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha const bool is_internal); struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath); struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta); +void BKE_text_make_local (struct Main *bmain, struct Text *text, const bool lib_local); void BKE_text_clear (struct Text *text); void BKE_text_write (struct Text *text, const char *str); int BKE_text_file_modified_check(struct Text *text); diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 56f056c681a..1c5ea946f59 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -72,7 +72,7 @@ void BKE_texture_default(struct Tex *tex); struct Tex *BKE_texture_copy(struct Main *bmain, struct Tex *tex); struct Tex *BKE_texture_add(struct Main *bmain, const char *name); struct Tex *BKE_texture_localize(struct Tex *tex); -void BKE_texture_make_local(struct Main *bmain, struct Tex *tex); +void BKE_texture_make_local(struct Main *bmain, struct Tex *tex, const bool lib_local); void BKE_texture_type_set(struct Tex *tex, int type); void BKE_texture_mtex_default(struct MTex *mtex); diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index da5cca09b27..23bf9ec3d22 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -41,7 +41,7 @@ void BKE_world_init(struct World *wrld); struct World *add_world(struct Main *bmian, const char *name); struct World *BKE_world_copy(struct Main *bmain, struct World *wrld); struct World *localize_world(struct World *wrld); -void BKE_world_make_local(struct Main *bmain, struct World *wrld); +void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local); #endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 9007a6794a1..848ad252c45 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -70,7 +70,7 @@ set(SRC intern/appdir.c intern/armature.c intern/armature_update.c - intern/asset.c + intern/asset_engine.c intern/autoexec.c intern/blender.c intern/blender_copybuffer.c @@ -119,6 +119,7 @@ set(SRC intern/lamp.c intern/lattice.c intern/library.c + intern/library_asset.c intern/library_idmap.c intern/library_query.c intern/library_remap.c @@ -195,7 +196,7 @@ set(SRC BKE_animsys.h BKE_appdir.h BKE_armature.h - BKE_asset.h + BKE_asset_engine.h BKE_autoexec.h BKE_blender.h BKE_blender_copybuffer.h diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index 828a6bb16ac..792e9195f12 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -313,12 +313,10 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *a ss->osd_vao = 0; ss->skip_grids = false; ss->osd_compute = 0; - ss->osd_uvs_invalid = true; - ss->osd_subsurf_uv = 0; - ss->osd_uv_index = -1; ss->osd_next_face_ptex_index = 0; ss->osd_coarse_coords = NULL; ss->osd_num_coarse_coords = 0; + ss->osd_subdiv_uvs = false; #endif return ss; diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index a825cffe7a0..4c913e79586 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -205,7 +205,7 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, struct DerivedMesh *dm); void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, struct DerivedMesh *dm); /* Make sure GL mesh exists, up to date and ready to draw. */ -bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl); +bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index); /* Draw given partitions of the GL mesh. * @@ -244,6 +244,8 @@ void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss); void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]); +void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subsurf_uvs); + #endif #endif /* __CCGSUBSURF_H__ */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h index 7ec9f329444..9df1c9021ef 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h +++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h @@ -86,7 +86,7 @@ void ccg_ehashIterator_next(EHashIterator *ehi); int ccg_ehashIterator_isStopped(EHashIterator *ehi); /** - * Standard allocator implementarion. + * Standard allocator implementation. */ CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void); @@ -255,10 +255,7 @@ struct CCGSubSurf { */ int osd_next_face_ptex_index; - /* ** Needs review. ** */ - bool osd_subsurf_uv; - int osd_uv_index; - bool osd_uvs_invalid; + bool osd_subdiv_uvs; #endif }; diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c index 2bb55c2d1ed..65cf899b42b 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c @@ -190,7 +190,6 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm) /* ** Make sure both GPU and CPU backends are properly reset. ** */ ss->osd_coarse_coords_invalid = true; - ss->osd_uvs_invalid = true; /* Reset GPU part. */ ss->osd_mesh_invalid = true; @@ -216,7 +215,9 @@ static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss) ss->osd_num_coarse_coords); } -bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl) +bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, + bool use_osd_glsl, + int active_uv_index) { int compute_type; @@ -256,8 +257,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl) ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner( ss->osd_topology_refiner, compute_type, - ss->subdivLevels, - ss->osd_subsurf_uv); + ss->subdivLevels); ss->osd_topology_refiner = NULL; if (UNLIKELY(ss->osd_mesh == NULL)) { @@ -290,7 +290,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl) ss->osd_coarse_coords_invalid = false; } - openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, ss->osd_uv_index); + openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, active_uv_index); return true; } @@ -984,6 +984,11 @@ void ccgSubSurf__delete_pending(void) BLI_spin_unlock(&delete_spin); } +void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs) +{ + ss->osd_subdiv_uvs = subdiv_uvs; +} + /* ** Public API ** */ void BKE_subsurf_osd_init(void) diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c index c4317f4d740..f1f82f458aa 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c @@ -62,6 +62,16 @@ typedef struct ConvDMStorage { *vert_poly_mem, *edge_poly_mem; #endif + + MVert *mvert; + MEdge *medge; + MLoop *mloop; + MPoly *mpoly; + + MeshIslandStore island_store; + int num_uvs; + float *uvs; + int *face_uvs; } ConvDMStorage; static OpenSubdiv_SchemeType conv_dm_get_type( @@ -74,6 +84,13 @@ static OpenSubdiv_SchemeType conv_dm_get_type( return OSD_SCHEME_CATMARK; } +static bool conv_dm_get_subdiv_uvs( + const OpenSubdiv_Converter *converter) +{ + ConvDMStorage *storage = converter->user_data; + return (storage->ss->osd_subdiv_uvs); +} + static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter) { ConvDMStorage *storage = converter->user_data; @@ -99,9 +116,7 @@ static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter, int face) { ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - const MPoly *mp = dm->getPolyArray(dm); - const MPoly *mpoly = &mp[face]; + const MPoly *mpoly = &storage->mpoly[face]; return mpoly->totloop; } @@ -110,13 +125,10 @@ static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter, int *face_verts) { ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - const MLoop *ml = dm->getLoopArray(dm); - const MPoly *mp = dm->getPolyArray(dm); - const MPoly *mpoly = &mp[face]; + const MPoly *mpoly = &storage->mpoly[face]; int loop; for (loop = 0; loop < mpoly->totloop; loop++) { - face_verts[loop] = ml[mpoly->loopstart + loop].v; + face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v; } } @@ -125,13 +137,10 @@ static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter, int *face_edges) { ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - const MLoop *ml = dm->getLoopArray(dm); - const MPoly *mp = dm->getPolyArray(dm); - const MPoly *mpoly = &mp[face]; + const MPoly *mpoly = &storage->mpoly[face]; int loop; for (loop = 0; loop < mpoly->totloop; loop++) { - face_edges[loop] = ml[mpoly->loopstart + loop].e; + face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e; } } @@ -140,9 +149,7 @@ static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter, int *edge_verts) { ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - const MEdge *me = dm->getEdgeArray(dm); - const MEdge *medge = &me[edge]; + const MEdge *medge = &storage->medge[edge]; edge_verts[0] = medge->v1; edge_verts[1] = medge->v2; } @@ -153,14 +160,12 @@ static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter, ConvDMStorage *storage = converter->user_data; #ifndef USE_MESH_ELEMENT_MAPPING DerivedMesh *dm = storage->dm; - const MLoop *ml = dm->getLoopArray(dm); - const MPoly *mp = dm->getPolyArray(dm); int num = 0, poly; for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &mp[poly]; + const MPoly *mpoly = &user_data->mpoly[poly]; int loop; for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &ml[mpoly->loopstart + loop]; + const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; if (mloop->e == edge) { ++num; break; @@ -180,14 +185,12 @@ static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter, ConvDMStorage *storage = converter->user_data; #ifndef USE_MESH_ELEMENT_MAPPING DerivedMesh *dm = storage->dm; - const MLoop *ml = dm->getLoopArray(dm); - const MPoly *mp = dm->getPolyArray(dm); int num = 0, poly; for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &mp[poly]; + const MPoly *mpoly = &user_data->mpoly[poly]; int loop; for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &ml[mpoly->loopstart + loop]; + const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; if (mloop->e == edge) { edge_faces[num++] = poly; break; @@ -205,9 +208,8 @@ static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge) { ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; CCGSubSurf *ss = storage->ss; - const MEdge *medge = dm->getEdgeArray(dm); + const MEdge *medge = storage->medge; return (float)medge[edge].crease / 255.0f * ss->subdivLevels; } @@ -217,10 +219,9 @@ static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter, ConvDMStorage *storage = converter->user_data; #ifndef USE_MESH_ELEMENT_MAPPING DerivedMesh *dm = storage->dm; - const MEdge *me = dm->getEdgeArray(dm); int num = 0, edge; for (edge = 0; edge < dm->getNumEdges(dm); edge++) { - const MEdge *medge = &me[edge]; + const MEdge *medge = &user_data->medge[edge]; if (medge->v1 == vert || medge->v2 == vert) { ++num; } @@ -238,10 +239,9 @@ static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter, ConvDMStorage *storage = converter->user_data; #ifndef USE_MESH_ELEMENT_MAPPING DerivedMesh *dm = storage->dm; - const MEdge *me = dm->getEdgeArray(dm); int num = 0, edge; for (edge = 0; edge < dm->getNumEdges(dm); edge++) { - const MEdge *medge = &me[edge]; + const MEdge *medge = &user_data->medge[edge]; if (medge->v1 == vert || medge->v2 == vert) { vert_edges[num++] = edge; } @@ -259,14 +259,12 @@ static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter, ConvDMStorage *storage = converter->user_data; #ifndef USE_MESH_ELEMENT_MAPPING DerivedMesh *dm = storage->dm; - const MLoop *ml = dm->getLoopArray(dm); - const MPoly *mp = dm->getPolyArray(dm); int num = 0, poly; for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &mp[poly]; + const MPoly *mpoly = &user_data->mpoly[poly]; int loop; for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &ml[mpoly->loopstart + loop]; + const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; if (mloop->v == vert) { ++num; break; @@ -286,14 +284,12 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter, ConvDMStorage *storage = converter->user_data; #ifndef USE_MESH_ELEMENT_MAPPING DerivedMesh *dm = storage->dm; - const MLoop *ml = dm->getLoopArray(dm); - const MPoly *mp = dm->getPolyArray(dm); int num = 0, poly; for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &mp[poly]; + const MPoly *mpoly = &storage->mpoly[poly]; int loop; for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &ml[mpoly->loopstart + loop]; + const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; if (mloop->v == vert) { vert_faces[num++] = poly; break; @@ -307,9 +303,114 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter, #endif } +static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter) +{ + ConvDMStorage *storage = converter->user_data; + DerivedMesh *dm = storage->dm; + int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV); + return num_uv_layers; +} + +static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter, + int layer) +{ + ConvDMStorage *storage = converter->user_data; + DerivedMesh *dm = storage->dm; + + const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer); + const int num_loops = dm->getNumLoops(dm); + + /* Initialize memory required for the operations. */ + if (storage->uvs == NULL) { + storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs"); + } + if (storage->face_uvs == NULL) { + storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs"); + } + + /* Calculate islands connectivity of the UVs. */ + BKE_mesh_calc_islands_loop_poly_uvmap( + storage->mvert, dm->getNumVerts(dm), + storage->medge, dm->getNumEdges(dm), + storage->mpoly, dm->getNumPolys(dm), + storage->mloop, dm->getNumLoops(dm), + mloopuv, + &storage->island_store); + + /* Here we "weld" duplicated vertices from island to the same UV value. + * The idea here is that we need to pass individual islands to OpenSubdiv. + */ + storage->num_uvs = 0; + for (int island = 0; island < storage->island_store.islands_num; ++island) { + MeshElemMap *island_poly_map = storage->island_store.islands[island]; + for (int poly = 0; poly < island_poly_map->count; ++poly) { + int poly_index = island_poly_map->indices[poly]; + /* Within the same UV island we should share UV points across + * loops. Otherwise each poly will be subdivided individually + * which we don't really want. + */ + const MPoly *mpoly = &storage->mpoly[poly_index]; + for (int loop = 0; loop < mpoly->totloop; ++loop) { + const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop]; + bool found = false; + /* TODO(sergey): Quite bad loop, which gives us O(N^2) + * complexity here. But how can we do it smarter, hopefully + * without requiring lots of additional memory. + */ + for (int i = 0; i < storage->num_uvs; ++i) { + if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) { + storage->face_uvs[mpoly->loopstart + loop] = i; + found = true; + break; + } + } + if (!found) { + copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv); + storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs; + ++storage->num_uvs; + } + } + } + } +} + +static void conv_dm_finish_uv_layer(const OpenSubdiv_Converter *converter) +{ + ConvDMStorage *storage = converter->user_data; + BKE_mesh_loop_islands_free(&storage->island_store); +} + +static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter) +{ + ConvDMStorage *storage = converter->user_data; + return storage->num_uvs; +} + +static void conv_dm_get_uvs(const OpenSubdiv_Converter *converter, float *uvs) +{ + ConvDMStorage *storage = converter->user_data; + memcpy(uvs, storage->uvs, sizeof(float) * 2 * storage->num_uvs); +} + +static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter, + int face, + int corner) +{ + ConvDMStorage *storage = converter->user_data; + const MPoly *mpoly = &storage->mpoly[face]; + return storage->face_uvs[mpoly->loopstart + corner]; +} + static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter) { ConvDMStorage *user_data = converter->user_data; + if (user_data->uvs != NULL) { + MEM_freeN(user_data->uvs); + } + if (user_data->face_uvs != NULL) { + MEM_freeN(user_data->face_uvs); + } + #ifdef USE_MESH_ELEMENT_MAPPING MEM_freeN(user_data->vert_edge_map); MEM_freeN(user_data->vert_edge_mem); @@ -330,6 +431,8 @@ void ccgSubSurf_converter_setup_from_derivedmesh( converter->get_type = conv_dm_get_type; + converter->get_subdiv_uvs = conv_dm_get_subdiv_uvs; + converter->get_num_faces = conv_dm_get_num_faces; converter->get_num_edges = conv_dm_get_num_edges; converter->get_num_verts = conv_dm_get_num_verts; @@ -348,9 +451,27 @@ void ccgSubSurf_converter_setup_from_derivedmesh( converter->get_num_vert_faces = conv_dm_get_num_vert_faces; converter->get_vert_faces = conv_dm_get_vert_faces; + converter->get_num_uv_layers = conv_dm_get_num_uv_layers; + converter->precalc_uv_layer = conv_dm_precalc_uv_layer; + converter->finish_uv_layer = conv_dm_finish_uv_layer; + converter->get_num_uvs = conv_dm_get_num_uvs; + converter->get_uvs = conv_dm_get_uvs; + converter->get_face_corner_uv_index = conv_dm_get_face_corner_uv_index; + user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__); user_data->ss = ss; user_data->dm = dm; + + user_data->mvert = dm->getVertArray(dm); + user_data->medge = dm->getEdgeArray(dm); + user_data->mloop = dm->getLoopArray(dm); + user_data->mpoly = dm->getPolyArray(dm); + + memset(&user_data->island_store, 0, sizeof(user_data->island_store)); + + user_data->uvs = NULL; + user_data->face_uvs = NULL; + converter->free_user_data = conv_dm_free_user_data; converter->user_data = user_data; @@ -405,6 +526,13 @@ static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type( } } +static bool conv_ccg_get_subdiv_uvs( + const OpenSubdiv_Converter *converter) +{ + CCGSubSurf *ss = converter->user_data; + return (ss->osd_subdiv_uvs); +} + static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter) { CCGSubSurf *ss = converter->user_data; @@ -548,11 +676,44 @@ static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter, } } +static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter)) +{ + return 0; +} + +static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter * UNUSED(converter), + int UNUSED(layer)) +{ +} + +static void conv_ccg_finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter)) +{ +} + +static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter)) +{ + return 0; +} + +static void conv_ccg_get_uvs(const OpenSubdiv_Converter * UNUSED(converter), + float *UNUSED(uvs)) +{ +} + +static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter), + int UNUSED(face), + int UNUSED(corner_)) +{ + return 0; +} + void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, OpenSubdiv_Converter *converter) { converter->get_type = conv_ccg_get_bilinear_type; + converter->get_subdiv_uvs = conv_ccg_get_subdiv_uvs; + converter->get_num_faces = conv_ccg_get_num_faces; converter->get_num_edges = conv_ccg_get_num_edges; converter->get_num_verts = conv_ccg_get_num_verts; @@ -571,6 +732,13 @@ void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, converter->get_num_vert_faces = conv_ccg_get_num_vert_faces; converter->get_vert_faces = conv_ccg_get_vert_faces; + converter->get_num_uv_layers = conv_ccg_get_num_uv_layers; + converter->precalc_uv_layer = conv_ccg_precalc_uv_layer; + converter->finish_uv_layer = conv_ccg_finish_uv_layer; + converter->get_num_uvs = conv_ccg_get_num_uvs; + converter->get_uvs = conv_ccg_get_uvs; + converter->get_face_corner_uv_index = conv_ccg_get_face_corner_uv_index; + converter->free_user_data = NULL; converter->user_data = ss; } diff --git a/source/blender/blenkernel/intern/CCGSubSurf_util.c b/source/blender/blenkernel/intern/CCGSubSurf_util.c index 9af69115559..c7ef528c02f 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_util.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_util.c @@ -184,7 +184,7 @@ int ccg_ehashIterator_isStopped(EHashIterator *ehi) } /** - * Standard allocator implementarion. + * Standard allocator implementation. */ static void *_stdAllocator_alloc(CCGAllocatorHDL UNUSED(a), int numBytes) diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index f7ff1261c8a..470098f8c7c 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -95,34 +95,9 @@ bAction *add_empty_action(Main *bmain, const char name[]) /* .................................. */ // does copy_fcurve... -void BKE_action_make_local(Main *bmain, bAction *act) +void BKE_action_make_local(Main *bmain, bAction *act, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(act)) { - return; - } - - BKE_library_ID_test_usages(bmain, act, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &act->id); - BKE_id_expand_local(&act->id); - } - else { - bAction *act_new = BKE_action_copy(bmain, act); - - act_new->id.us = 0; - - BKE_libblock_remap(bmain, act, act_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &act->id, true, lib_local); } /* .................................. */ @@ -181,10 +156,7 @@ bAction *BKE_action_copy(Main *bmain, bAction *src) } } - if (ID_IS_LINKED_DATABLOCK(src)) { - BKE_id_expand_local(&dst->id); - BKE_id_lib_local_paths(bmain, src->id.lib, &dst->id); - } + BKE_id_copy_ensure_local(bmain, &src->id, &dst->id); return dst; } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index d6f93528262..d04b950c043 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -400,8 +400,8 @@ static void make_local_strips(ListBase *strips) NlaStrip *strip; for (strip = strips->first; strip; strip = strip->next) { - if (strip->act) BKE_action_make_local(G.main, strip->act); - if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target); + if (strip->act) BKE_action_make_local(G.main, strip->act, false); + if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target, false); make_local_strips(&strip->strips); } @@ -413,10 +413,10 @@ void BKE_animdata_make_local(AnimData *adt) NlaTrack *nlt; /* Actions - Active and Temp */ - if (adt->action) BKE_action_make_local(G.main, adt->action); - if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact); + if (adt->action) BKE_action_make_local(G.main, adt->action, false); + if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact, false); /* Remaps */ - if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target); + if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target, false); /* Drivers */ /* TODO: need to remap the ID-targets too? */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 5f564e1c4d2..c644fe09364 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -144,34 +144,9 @@ void BKE_armature_free(bArmature *arm) } } -void BKE_armature_make_local(Main *bmain, bArmature *arm) +void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(arm)) { - return; - } - - BKE_library_ID_test_usages(bmain, arm, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &arm->id); - BKE_id_expand_local(&arm->id); - } - else { - bArmature *arm_new = BKE_armature_copy(bmain, arm); - - arm_new->id.us = 0; - - BKE_libblock_remap(bmain, arm, arm_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &arm->id, true, lib_local); } static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone **newActBone) @@ -219,10 +194,7 @@ bArmature *BKE_armature_copy(Main *bmain, bArmature *arm) newArm->act_edbone = NULL; newArm->sketch = NULL; - if (ID_IS_LINKED_DATABLOCK(arm)) { - BKE_id_expand_local(&newArm->id); - BKE_id_lib_local_paths(bmain, arm->id.lib, &newArm->id); - } + BKE_id_copy_ensure_local(bmain, &arm->id, &newArm->id); return newArm; } @@ -1931,6 +1903,17 @@ static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int return counter; } +/** + * Clear pointers of object's pose (needed in remap case, since we cannot always wait for a complete pose rebuild). + */ +void BKE_pose_clear_pointers(bPose *pose) +{ + for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + pchan->bone = NULL; + pchan->child = NULL; + } +} + /* only after leave editmode, duplicating, validating older files, library syncing */ /* NOTE: pose->flag is set for it */ void BKE_pose_rebuild(Object *ob, bArmature *arm) @@ -1951,10 +1934,7 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) pose = ob->pose; /* clear */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - pchan->bone = NULL; - pchan->child = NULL; - } + BKE_pose_clear_pointers(pose); /* first step, check if all channels are there */ for (bone = arm->bonebase.first; bone; bone = bone->next) { diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index ece17335fa0..ef8a2f100dc 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -224,7 +224,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos } /* make a new Spline-IK chain, and store it in the IK chains */ - /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */ + /* TODO: we should check if there is already an IK chain on this, since that would take precedence... */ { /* make new tree */ tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree"); @@ -696,7 +696,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx), void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob) { - BLI_assert(ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL); + BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL); DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { printf("Proxy copy error, lib Object: %s proxy Object: %s\n", diff --git a/source/blender/blenkernel/intern/asset.c b/source/blender/blenkernel/intern/asset_engine.c index 3f4894d41c5..8fa651bdef1 100644 --- a/source/blender/blenkernel/intern/asset.c +++ b/source/blender/blenkernel/intern/asset_engine.c @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/blenkernel/intern/asset.c +/** \file blender/blenkernel/intern/asset_engine.c * \ingroup bke */ @@ -48,7 +48,7 @@ #include "PIL_time.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" @@ -405,7 +405,7 @@ void BKE_filedir_entryarr_clear(FileDirEntryArr *array) array->nbr_entries_filtered = 0; } -/* GHash helpers */ +/* Various helpers */ unsigned int BKE_asset_uuid_hash(const void *key) { return BLI_hash_mm2((const unsigned char *)key, sizeof(AssetUUID), 0); @@ -418,4 +418,11 @@ bool BKE_asset_uuid_cmp(const void *a, const void *b) return !ASSETUUID_COMPARE(uuid1, uuid2); /* Expects false when compared equal... */ } - +void BKE_asset_uuid_print(const AssetUUID *uuid) +{ + /* TODO print nicer (as 128bit hexadecimal...). */ + printf("[%d,%d,%d,%d][%d,%d,%d,%d][%d,%d,%d,%d]\n", + uuid->uuid_asset[0], uuid->uuid_asset[1], uuid->uuid_asset[2], uuid->uuid_asset[3], + uuid->uuid_variant[0], uuid->uuid_variant[1], uuid->uuid_variant[2], uuid->uuid_variant[3], + uuid->uuid_revision[0], uuid->uuid_revision[1], uuid->uuid_revision[2], uuid->uuid_revision[3]); +} diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 25491bcb998..3740fdca740 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -47,7 +47,7 @@ #include "IMB_imbuf.h" #include "IMB_moviecache.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_blender.h" /* own include */ #include "BKE_blender_version.h" /* own include */ #include "BKE_blendfile.h" diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index a708c59fa97..d079583f9a8 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -424,7 +424,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int { const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL; - if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED_DATABLOCK(id)) { + if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED(id)) { return; } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 20621feac6c..da58ad332ba 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -197,10 +197,7 @@ Brush *BKE_brush_copy(Main *bmain, Brush *brush) /* enable fake user by default */ id_fake_user_set(&brush->id); - if (ID_IS_LINKED_DATABLOCK(brush)) { - BKE_id_expand_local(&brushn->id); - BKE_id_lib_local_paths(bmain, brush->id.lib, &brushn->id); - } + BKE_id_copy_ensure_local(bmain, &brush->id, &brushn->id); return brushn; } @@ -219,27 +216,27 @@ void BKE_brush_free(Brush *brush) BKE_previewimg_free(&(brush->preview)); } -void BKE_brush_make_local(Main *bmain, Brush *brush) +void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local) { bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - if (!ID_IS_LINKED_DATABLOCK(brush)) { + if (!ID_IS_LINKED(brush)) { return; } if (brush->clone.image) { /* Special case: ima always local immediately. Clone image should only have one user anyway. */ - id_make_local(bmain, &brush->clone.image->id, false); + id_make_local(bmain, &brush->clone.image->id, false, false); } BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib); - if (is_local) { + if (lib_local || is_local) { if (!is_lib) { id_clear_lib_data(bmain, &brush->id); BKE_id_expand_local(&brush->id); @@ -252,7 +249,9 @@ void BKE_brush_make_local(Main *bmain, Brush *brush) brush_new->id.us = 0; - BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE); + if (!lib_local) { + BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE); + } } } } diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index ae7aac8b54f..85ce399b770 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -78,8 +78,8 @@ void BKE_camera_init(Camera *cam) /* stereoscopy 3d */ cam->stereo.interocular_distance = 0.065f; cam->stereo.convergence_distance = 30.f * 0.065f; - cam->stereo.pole_merge_angle_from = DEG2RAD(60.0f); - cam->stereo.pole_merge_angle_to = DEG2RAD(75.0f); + cam->stereo.pole_merge_angle_from = DEG2RADF(60.0f); + cam->stereo.pole_merge_angle_to = DEG2RADF(75.0f); } void *BKE_camera_add(Main *bmain, const char *name) @@ -99,42 +99,14 @@ Camera *BKE_camera_copy(Main *bmain, Camera *cam) camn = BKE_libblock_copy(bmain, &cam->id); - if (ID_IS_LINKED_DATABLOCK(cam)) { - BKE_id_expand_local(&camn->id); - BKE_id_lib_local_paths(bmain, cam->id.lib, &camn->id); - } + BKE_id_copy_ensure_local(bmain, &cam->id, &camn->id); return camn; } -void BKE_camera_make_local(Main *bmain, Camera *cam) +void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(cam)) { - return; - } - - BKE_library_ID_test_usages(bmain, cam, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &cam->id); - BKE_id_expand_local(&cam->id); - } - else { - Camera *cam_new = BKE_camera_copy(bmain, cam); - - cam_new->id.us = 0; - - BKE_libblock_remap(bmain, cam, cam_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &cam->id, true, lib_local); } /** Free (or release) any data used by this camera (does not free the camera itself). */ diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 2932939b208..53a74024c51 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -982,6 +982,7 @@ static void save_sample_line(Scopes *scopes, const int idx, const float fx, cons /* waveform */ switch (scopes->wavefrm_mode) { case SCOPES_WAVEFRM_RGB: + case SCOPES_WAVEFRM_RGB_PARADE: scopes->waveform_1[idx + 0] = fx; scopes->waveform_1[idx + 1] = rgb[0]; scopes->waveform_2[idx + 0] = fx; @@ -1265,6 +1266,8 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * switch (scopes->wavefrm_mode) { case SCOPES_WAVEFRM_RGB: + /* fall-through */ + case SCOPES_WAVEFRM_RGB_PARADE: ycc_mode = -1; break; case SCOPES_WAVEFRM_LUMA: diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 4c9ddd495e3..1f2cc2e4ad8 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4649,7 +4649,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use /* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */ static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData)) { - if (*idpoin && ID_IS_LINKED_DATABLOCK(*idpoin)) + if (*idpoin && ID_IS_LINKED(*idpoin)) id_lib_extern(*idpoin); } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 0e634e21ea3..90a514781d7 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -207,45 +207,14 @@ Curve *BKE_curve_copy(Main *bmain, Curve *cu) id_us_plus((ID *)cun->vfonti); id_us_plus((ID *)cun->vfontbi); - if (ID_IS_LINKED_DATABLOCK(cu)) { - BKE_id_expand_local(&cun->id); - BKE_id_lib_local_paths(bmain, cu->id.lib, &cun->id); - } + BKE_id_copy_ensure_local(bmain, &cu->id, &cun->id); return cun; } -void BKE_curve_make_local(Main *bmain, Curve *cu) +void BKE_curve_make_local(Main *bmain, Curve *cu, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - when there are only lib users: don't do - * - when there are only local users: set flag - * - mixed: do a copy - */ - - if (!ID_IS_LINKED_DATABLOCK(cu)) { - return; - } - - BKE_library_ID_test_usages(bmain, cu, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &cu->id); - if (cu->key) { - BKE_key_make_local(bmain, cu->key); - } - BKE_id_expand_local(&cu->id); - } - else { - Curve *cu_new = BKE_curve_copy(bmain, cu); - - cu_new->id.us = 0; - - BKE_libblock_remap(bmain, cu, cu_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &cu->id, true, lib_local); } /* Get list of nurbs from editnurbs structure */ diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 7292ed2b5c5..839673c192b 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -356,7 +356,7 @@ static MeshRemapIslandsCalc data_transfer_get_loop_islands_generator(const int c { switch (cddata_type) { case CD_FAKE_UV: - return BKE_mesh_calc_islands_loop_poly_uv; + return BKE_mesh_calc_islands_loop_poly_edgeseam; default: break; } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 2b097f31c59..d35de6fc5d3 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -4483,7 +4483,7 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus CLAMP_MIN(max_velocity, vel); } - steps = (int)ceil(max_velocity / bData->average_dist * timescale); + steps = (int)ceil((double)max_velocity / bData->average_dist * (double)timescale); CLAMP(steps, 0, 12); eff_scale = brush->smudge_strength / (float)steps * timescale; @@ -4634,7 +4634,7 @@ static int dynamicPaint_prepareEffectStep( /* calculate average values (single thread) */ for (int index = 0; index < sData->total_points; index++) { - average_force += (*force)[index * 4 + 3]; + average_force += (double)(*force)[index * 4 + 3]; } average_force /= sData->total_points; } @@ -4651,7 +4651,7 @@ static int dynamicPaint_prepareEffectStep( shrink_speed = surface->shrink_speed; fastest_effect = max_fff(spread_speed, shrink_speed, average_force); - avg_dist = bData->average_dist * CANVAS_REL_SIZE / getSurfaceDimension(sData); + avg_dist = bData->average_dist * (double)CANVAS_REL_SIZE / (double)getSurfaceDimension(sData); steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale); CLAMP(steps, 1, 20); @@ -5009,7 +5009,8 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal const float wave_scale = CANVAS_REL_SIZE / canvas_size; /* allocate memory */ - PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), "Temp previous points for wave simulation"); + PaintWavePoint *prevPoint = MEM_mallocN( + sData->total_points * sizeof(PaintWavePoint), __func__); if (!prevPoint) return; @@ -5019,13 +5020,14 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal int numOfNeighs = sData->adj_data->n_num[index]; for (i = 0; i < numOfNeighs; i++) { - average_dist += bNeighs[sData->adj_data->n_index[index] + i].dist; + average_dist += (double)bNeighs[sData->adj_data->n_index[index] + i].dist; } } - average_dist *= wave_scale / sData->adj_data->total_targets; + average_dist *= (double)wave_scale / sData->adj_data->total_targets; /* determine number of required steps */ - steps = (int)ceil((WAVE_TIME_FAC * timescale * surface->wave_timescale) / (average_dist / wave_speed / 3)); + steps = (int)ceil((double)(WAVE_TIME_FAC * timescale * surface->wave_timescale) / + (average_dist / (double)wave_speed / 3)); CLAMP(steps, 1, 20); timescale /= steps; diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 5e1f8814ed6..580842fe176 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -309,6 +309,11 @@ VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath) return BKE_vfont_load_exists_ex(bmain, filepath, NULL); } +void BKE_vfont_make_local(Main *bmain, VFont *vfont, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &vfont->id, true, lib_local); +} + static VFont *which_vfont(Curve *cu, CharInfo *info) { switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) { diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index ac4f566dc62..8621da0d42e 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -390,6 +390,11 @@ bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *src, bool internal_copy) return dst; } +void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local); +} + /* -------- GP-Stroke API --------- */ /* ensure selection status of stroke is in sync with its points */ diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 11bbd91e9c9..9b011dbb003 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -97,14 +97,16 @@ Group *BKE_group_copy(Main *bmain, Group *group) /* Do not copy group's preview (same behavior as for objects). */ groupn->preview = NULL; - if (ID_IS_LINKED_DATABLOCK(group)) { - BKE_id_expand_local(&groupn->id); - BKE_id_lib_local_paths(bmain, group->id.lib, &groupn->id); - } + BKE_id_copy_ensure_local(bmain, &group->id, &groupn->id); return groupn; } +void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &group->id, true, lib_local); +} + /* external */ static bool group_object_add_internal(Group *group, Object *ob) { diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index f3e86b44459..2d5b15c8f9d 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -221,6 +221,24 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv) return prv_img; } +/** Duplicate preview image from \a id and clear icon_id, to be used by datablock copy functions. */ +void BKE_previewimg_id_copy(ID *new_id, ID *old_id) +{ + PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id); + PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id); + + if (old_prv_p && *old_prv_p) { + BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p)); +// const int new_icon_id = get_next_free_id(); + +// if (new_icon_id == 0) { +// return; /* Failure. */ +// } + *new_prv_p = BKE_previewimg_copy(*old_prv_p); + new_id->icon_id = (*new_prv_p)->icon_id = 0; + } +} + PreviewImage **BKE_previewimg_id_get_p(ID *id) { switch (GS(id->name)) { @@ -423,10 +441,26 @@ void BKE_icon_changed(int id) } } -int BKE_icon_id_ensure(struct ID *id) +static int icon_id_ensure_create_icon(struct ID *id) { Icon *new_icon = NULL; + new_icon = MEM_mallocN(sizeof(Icon), __func__); + + new_icon->obj = id; + new_icon->type = GS(id->name); + + /* next two lines make sure image gets created */ + new_icon->drawinfo = NULL; + new_icon->drawinfo_free = NULL; + + BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon); + + return id->icon_id; +} + +int BKE_icon_id_ensure(struct ID *id) +{ if (!id || G.background) return 0; @@ -440,32 +474,39 @@ int BKE_icon_id_ensure(struct ID *id) return 0; } - new_icon = MEM_mallocN(sizeof(Icon), __func__); - - new_icon->obj = id; - new_icon->type = GS(id->name); - - /* next two lines make sure image gets created */ - new_icon->drawinfo = NULL; - new_icon->drawinfo_free = NULL; + /* Ensure we synchronize ID icon_id with its previewimage if it has one. */ + PreviewImage **p_prv = BKE_previewimg_id_get_p(id); + if (p_prv && *p_prv) { + BLI_assert(ELEM((*p_prv)->icon_id, 0, id->icon_id)); + (*p_prv)->icon_id = id->icon_id; + } - BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon); - - return id->icon_id; + return icon_id_ensure_create_icon(id); } /** * Return icon id of given preview, or create new icon if not found. */ -int BKE_icon_preview_ensure(PreviewImage *preview) +int BKE_icon_preview_ensure(ID *id, PreviewImage *preview) { Icon *new_icon = NULL; if (!preview || G.background) return 0; - if (preview->icon_id) + if (id) { + BLI_assert(BKE_previewimg_id_ensure(id) == preview); + } + + if (preview->icon_id) { + BLI_assert(!id || !id->icon_id || id->icon_id == preview->icon_id); + return preview->icon_id; + } + + if (id && id->icon_id) { + preview->icon_id = id->icon_id; return preview->icon_id; + } preview->icon_id = get_next_free_id(); @@ -474,6 +515,12 @@ int BKE_icon_preview_ensure(PreviewImage *preview) return 0; } + /* Ensure we synchronize ID icon_id with its previewimage if available, and generate suitable 'ID' icon. */ + if (id) { + id->icon_id = preview->icon_id; + return icon_id_ensure_create_icon(id); + } + new_icon = MEM_mallocN(sizeof(Icon), __func__); new_icon->obj = preview; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f6f38977402..ea28dabb945 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -456,47 +456,20 @@ Image *BKE_image_copy(Main *bmain, Image *ima) copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles); - nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format); + /* nima->stere3d_format is already allocated by image_alloc... */ + *nima->stereo3d_format = *ima->stereo3d_format; BLI_duplicatelist(&nima->views, &ima->views); - nima->preview = BKE_previewimg_copy(ima->preview); + BKE_previewimg_id_copy(&nima->id, &ima->id); - if (ID_IS_LINKED_DATABLOCK(ima)) { - BKE_id_expand_local(&nima->id); - BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id); - } + BKE_id_copy_ensure_local(bmain, &ima->id, &nima->id); return nima; } -void BKE_image_make_local(Main *bmain, Image *ima) +void BKE_image_make_local(Main *bmain, Image *ima, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(ima)) { - return; - } - - BKE_library_ID_test_usages(bmain, ima, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &ima->id); - BKE_id_expand_local(&ima->id); - } - else { - Image *ima_new = BKE_image_copy(bmain, ima); - - ima_new->id.us = 0; - - BKE_libblock_remap(bmain, ima, ima_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &ima->id, true, lib_local); } void BKE_image_merge(Image *dest, Image *source) @@ -1083,43 +1056,55 @@ int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options) { memset(r_options, 0, sizeof(*r_options)); - if (imtype == R_IMF_IMTYPE_TARGA) + if (imtype == R_IMF_IMTYPE_TARGA) { return IMB_FTYPE_TGA; + } else if (imtype == R_IMF_IMTYPE_RAWTGA) { r_options->flag = RAWTGA; return IMB_FTYPE_TGA; } - else if (imtype == R_IMF_IMTYPE_IRIS) + else if (imtype == R_IMF_IMTYPE_IRIS) { return IMB_FTYPE_IMAGIC; + } #ifdef WITH_HDR - else if (imtype == R_IMF_IMTYPE_RADHDR) + else if (imtype == R_IMF_IMTYPE_RADHDR) { return IMB_FTYPE_RADHDR; + } #endif else if (imtype == R_IMF_IMTYPE_PNG) { r_options->quality = 15; return IMB_FTYPE_PNG; } #ifdef WITH_DDS - else if (imtype == R_IMF_IMTYPE_DDS) + else if (imtype == R_IMF_IMTYPE_DDS) { return IMB_FTYPE_DDS; + } #endif - else if (imtype == R_IMF_IMTYPE_BMP) + else if (imtype == R_IMF_IMTYPE_BMP) { return IMB_FTYPE_BMP; + } #ifdef WITH_TIFF - else if (imtype == R_IMF_IMTYPE_TIFF) + else if (imtype == R_IMF_IMTYPE_TIFF) { return IMB_FTYPE_TIF; + } #endif - else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) + else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) { return IMB_FTYPE_OPENEXR; + } #ifdef WITH_CINEON - else if (imtype == R_IMF_IMTYPE_CINEON) + else if (imtype == R_IMF_IMTYPE_CINEON) { return IMB_FTYPE_CINEON; - else if (imtype == R_IMF_IMTYPE_DPX) + } + else if (imtype == R_IMF_IMTYPE_DPX) { return IMB_FTYPE_DPX; + } #endif #ifdef WITH_OPENJPEG - else if (imtype == R_IMF_IMTYPE_JP2) + else if (imtype == R_IMF_IMTYPE_JP2) { + r_options->flag |= JP2_JP2; + r_options->quality = 90; return IMB_FTYPE_JP2; + } #endif else { r_options->quality = 90; @@ -1129,46 +1114,60 @@ int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options) char BKE_image_ftype_to_imtype(const int ftype, const ImbFormatOptions *options) { - if (ftype == 0) + if (ftype == 0) { return R_IMF_IMTYPE_TARGA; - else if (ftype == IMB_FTYPE_IMAGIC) + } + else if (ftype == IMB_FTYPE_IMAGIC) { return R_IMF_IMTYPE_IRIS; + } #ifdef WITH_HDR - else if (ftype == IMB_FTYPE_RADHDR) + else if (ftype == IMB_FTYPE_RADHDR) { return R_IMF_IMTYPE_RADHDR; + } #endif - else if (ftype == IMB_FTYPE_PNG) + else if (ftype == IMB_FTYPE_PNG) { return R_IMF_IMTYPE_PNG; + } #ifdef WITH_DDS - else if (ftype == IMB_FTYPE_DDS) + else if (ftype == IMB_FTYPE_DDS) { return R_IMF_IMTYPE_DDS; + } #endif - else if (ftype == IMB_FTYPE_BMP) + else if (ftype == IMB_FTYPE_BMP) { return R_IMF_IMTYPE_BMP; + } #ifdef WITH_TIFF - else if (ftype == IMB_FTYPE_TIF) + else if (ftype == IMB_FTYPE_TIF) { return R_IMF_IMTYPE_TIFF; + } #endif - else if (ftype == IMB_FTYPE_OPENEXR) + else if (ftype == IMB_FTYPE_OPENEXR) { return R_IMF_IMTYPE_OPENEXR; + } #ifdef WITH_CINEON - else if (ftype == IMB_FTYPE_CINEON) + else if (ftype == IMB_FTYPE_CINEON) { return R_IMF_IMTYPE_CINEON; - else if (ftype == IMB_FTYPE_DPX) + } + else if (ftype == IMB_FTYPE_DPX) { return R_IMF_IMTYPE_DPX; + } #endif else if (ftype == IMB_FTYPE_TGA) { - if (options && (options->flag & RAWTGA)) + if (options && (options->flag & RAWTGA)) { return R_IMF_IMTYPE_RAWTGA; - else + } + else { return R_IMF_IMTYPE_TARGA; + } } #ifdef WITH_OPENJPEG - else if (ftype == IMB_FTYPE_JP2) + else if (ftype == IMB_FTYPE_JP2) { return R_IMF_IMTYPE_JP2; + } #endif - else + else { return R_IMF_IMTYPE_JPEG90; + } } diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index e59facd3c39..6cdeaf5e59b 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -170,10 +170,7 @@ Key *BKE_key_copy(Main *bmain, Key *key) kb = kb->next; } - if (ID_IS_LINKED_DATABLOCK(key)) { - BKE_id_expand_local(&keyn->id); - BKE_id_lib_local_paths(bmain, key->id.lib, &keyn->id); - } + BKE_id_copy_ensure_local(bmain, &key->id, &keyn->id); return keyn; } @@ -203,18 +200,6 @@ Key *BKE_key_copy_nolib(Key *key) return keyn; } -void BKE_key_make_local(Main *bmain, Key *key) -{ - /* Note that here for now we simply just make it local... - * Sounds fishy behavior, but since skeys are not *real* IDs... */ - - if (!ID_IS_LINKED_DATABLOCK(key)) { - return; - } - - id_clear_lib_data(bmain, &key->id); -} - /* Sort shape keys and Ipo curves after a change. This assumes that at most * one key was moved, which is a valid assumption for the places it's * currently being called. diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 003b154a70b..e9d039ad480 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -135,13 +135,10 @@ Lamp *BKE_lamp_copy(Main *bmain, Lamp *la) if (la->nodetree) lan->nodetree = ntreeCopyTree(bmain, la->nodetree); - - lan->preview = BKE_previewimg_copy(la->preview); - if (ID_IS_LINKED_DATABLOCK(la)) { - BKE_id_expand_local(&lan->id); - BKE_id_lib_local_paths(bmain, la->id.lib, &lan->id); - } + BKE_previewimg_id_copy(&lan->id, &la->id); + + BKE_id_copy_ensure_local(bmain, &la->id, &lan->id); return lan; } @@ -172,34 +169,9 @@ Lamp *localize_lamp(Lamp *la) return lan; } -void BKE_lamp_make_local(Main *bmain, Lamp *la) +void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(la)) { - return; - } - - BKE_library_ID_test_usages(bmain, la, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &la->id); - BKE_id_expand_local(&la->id); - } - else { - Lamp *la_new = BKE_lamp_copy(bmain, la); - - la_new->id.us = 0; - - BKE_libblock_remap(bmain, la, la_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &la->id, true, lib_local); } void BKE_lamp_free(Lamp *la) diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 67f49266efc..b0671f33094 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -297,10 +297,7 @@ Lattice *BKE_lattice_copy(Main *bmain, Lattice *lt) ltn->editlatt = NULL; - if (ID_IS_LINKED_DATABLOCK(lt)) { - BKE_id_expand_local(<n->id); - BKE_id_lib_local_paths(bmain, lt->id.lib, <n->id); - } + BKE_id_copy_ensure_local(bmain, <->id, <n->id); return ltn; } @@ -330,37 +327,9 @@ void BKE_lattice_free(Lattice *lt) } -void BKE_lattice_make_local(Main *bmain, Lattice *lt) +void BKE_lattice_make_local(Main *bmain, Lattice *lt, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(lt)) { - return; - } - - BKE_library_ID_test_usages(bmain, lt, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, <->id); - if (lt->key) { - BKE_key_make_local(bmain, lt->key); - } - BKE_id_expand_local(<->id); - } - else { - Lattice *lt_new = BKE_lattice_copy(bmain, lt); - - lt_new->id.us = 0; - - BKE_libblock_remap(bmain, lt, lt_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, <->id, true, lib_local); } typedef struct LatticeDeformData { diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 5fd929d6732..f19f1b45be6 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -76,12 +76,10 @@ #include "BLT_translation.h" #include "RNA_access.h" -#include "RNA_types.h" #include "BKE_action.h" #include "BKE_animsys.h" #include "BKE_armature.h" -#include "BKE_asset.h" #include "BKE_bpath.h" #include "BKE_brush.h" #include "BKE_camera.h" @@ -100,6 +98,7 @@ #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_linestyle.h" #include "BKE_mesh.h" #include "BKE_material.h" @@ -110,6 +109,7 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_packedFile.h" +#include "BKE_sound.h" #include "BKE_speaker.h" #include "BKE_scene.h" #include "BKE_text.h" @@ -134,6 +134,10 @@ * also note that the id _must_ have a library - campbell */ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id) { + if (lib->flag & LIBRARY_FLAG_VIRTUAL) { + return; + } + const char *bpath_user_data[2] = {bmain->name, lib->filepath}; BKE_bpath_traverse_id(bmain, id, @@ -144,7 +148,7 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id) void id_lib_extern(ID *id) { - if (id && ID_IS_LINKED_DATABLOCK(id)) { + if (id && ID_IS_LINKED(id)) { BLI_assert(BKE_idcode_is_linkable(GS(id->name))); if (id->tag & LIB_TAG_INDIRECT) { id->tag -= LIB_TAG_INDIRECT; @@ -271,90 +275,158 @@ void BKE_id_expand_local(ID *id) BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0); } -/* calls the appropriate make_local method for the block, unless test. Returns true - * if the block can be made local. */ -bool id_make_local(Main *bmain, ID *id, bool test) +/** + * Ensure new (copied) ID is fully made local. + */ +void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id) +{ + if (ID_IS_LINKED(old_id)) { + BKE_id_expand_local(new_id); + BKE_id_lib_local_paths(bmain, old_id->lib, new_id); + } +} + +/** + * Generic 'make local' function, works for most of datablock types... + */ +void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, const bool lib_local) +{ + bool is_local = false, is_lib = false; + + /* - only lib users: do nothing (unless force_local is set) + * - only local users: set flag + * - mixed: make copy + * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later). + */ + + if (!ID_IS_LINKED(id)) { + return; + } + + BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); + + if (lib_local || is_local) { + if (!is_lib) { + id_clear_lib_data_ex(bmain, id, id_in_mainlist); + BKE_id_expand_local(id); + } + else { + ID *id_new; + + /* Should not fail in expected usecases, but id_copy does not copy Scene e.g. */ + if (id_copy(bmain, id, &id_new, false)) { + id_new->us = 0; + + if (!lib_local) { + BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE); + } + } + } + } + +} + +/** + * Calls the appropriate make_local method for the block, unless test is set. + * + * \param lib_local Special flag used when making a whole library's content local, it needs specific handling. + * + * \return true if the block can be made local. + */ +bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) { if (id->tag & LIB_TAG_INDIRECT) return false; switch (GS(id->name)) { case ID_SCE: - return false; /* not implemented */ + /* Partially implemented (has no copy...). */ + if (!test) BKE_scene_make_local(bmain, (Scene *)id, lib_local); + return true; case ID_LI: return false; /* can't be linked */ case ID_OB: - if (!test) BKE_object_make_local(bmain, (Object *)id); + if (!test) BKE_object_make_local(bmain, (Object *)id, lib_local); return true; case ID_ME: - if (!test) BKE_mesh_make_local(bmain, (Mesh *)id); + if (!test) BKE_mesh_make_local(bmain, (Mesh *)id, lib_local); return true; case ID_CU: - if (!test) BKE_curve_make_local(bmain, (Curve *)id); + if (!test) BKE_curve_make_local(bmain, (Curve *)id, lib_local); return true; case ID_MB: - if (!test) BKE_mball_make_local(bmain, (MetaBall *)id); + if (!test) BKE_mball_make_local(bmain, (MetaBall *)id, lib_local); return true; case ID_MA: - if (!test) BKE_material_make_local(bmain, (Material *)id); + if (!test) BKE_material_make_local(bmain, (Material *)id, lib_local); return true; case ID_TE: - if (!test) BKE_texture_make_local(bmain, (Tex *)id); + if (!test) BKE_texture_make_local(bmain, (Tex *)id, lib_local); return true; case ID_IM: - if (!test) BKE_image_make_local(bmain, (Image *)id); + if (!test) BKE_image_make_local(bmain, (Image *)id, lib_local); return true; case ID_LT: - if (!test) BKE_lattice_make_local(bmain, (Lattice *)id); + if (!test) BKE_lattice_make_local(bmain, (Lattice *)id, lib_local); return true; case ID_LA: - if (!test) BKE_lamp_make_local(bmain, (Lamp *)id); + if (!test) BKE_lamp_make_local(bmain, (Lamp *)id, lib_local); return true; case ID_CA: - if (!test) BKE_camera_make_local(bmain, (Camera *)id); + if (!test) BKE_camera_make_local(bmain, (Camera *)id, lib_local); return true; case ID_SPK: - if (!test) BKE_speaker_make_local(bmain, (Speaker *)id); + if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local); return true; case ID_IP: return false; /* deprecated */ case ID_KE: - if (!test) BKE_key_make_local(bmain, (Key *)id); - return true; + return false; /* can't be linked */ case ID_WO: - if (!test) BKE_world_make_local(bmain, (World *)id); + if (!test) BKE_world_make_local(bmain, (World *)id, lib_local); return true; case ID_SCR: return false; /* can't be linked */ case ID_VF: - return false; /* not implemented */ + /* Partially implemented (has no copy...). */ + if (!test) BKE_vfont_make_local(bmain, (VFont *)id, lib_local); + return true; case ID_TXT: - return false; /* not implemented */ + if (!test) BKE_text_make_local(bmain, (Text *)id, lib_local); + return true; case ID_SO: - return false; /* not implemented */ + /* Partially implemented (has no copy...). */ + if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local); + return true; case ID_GR: - return false; /* not implemented */ + if (!test) BKE_group_make_local(bmain, (Group *)id, lib_local); + return true; case ID_AR: - if (!test) BKE_armature_make_local(bmain, (bArmature *)id); + if (!test) BKE_armature_make_local(bmain, (bArmature *)id, lib_local); return true; case ID_AC: - if (!test) BKE_action_make_local(bmain, (bAction *)id); + if (!test) BKE_action_make_local(bmain, (bAction *)id, lib_local); return true; case ID_NT: - if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true); + if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true, lib_local); return true; case ID_BR: - if (!test) BKE_brush_make_local(bmain, (Brush *)id); + if (!test) BKE_brush_make_local(bmain, (Brush *)id, lib_local); return true; case ID_PA: - if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id); + if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id, lib_local); return true; case ID_WM: return false; /* can't be linked */ case ID_GD: - return false; /* not implemented */ + if (!test) BKE_gpencil_make_local(bmain, (bGPdata *)id, lib_local); + return true; + case ID_MSK: + if (!test) BKE_mask_make_local(bmain, (Mask *)id, lib_local); + return true; case ID_LS: - return false; /* not implemented */ + if (!test) BKE_linestyle_make_local(bmain, (FreestyleLineStyle *)id, lib_local); + return true; } return false; @@ -643,7 +715,7 @@ void BKE_main_lib_objects_recalc_all(Main *bmain) /* flag for full recalc */ for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ID_IS_LINKED_DATABLOCK(ob)) { + if (ID_IS_LINKED(ob)) { DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } } @@ -1069,7 +1141,7 @@ static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **i void BKE_libblock_relink(ID *id) { - if (ID_IS_LINKED_DATABLOCK(id)) + if (ID_IS_LINKED(id)) return; BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0); @@ -1285,7 +1357,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name) for (idtest = lb->first; idtest; idtest = idtest->next) { /* if idtest is not a lib */ - if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) { + if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) { /* Virtual lib IDs are considered as local ones here. */ /* do not test alphabetic! */ /* optimized */ if (idtest->name[2] == name[0]) { @@ -1426,7 +1498,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname) bool result; char name[MAX_ID_NAME - 2]; - /* if library, don't rename */ + /* if real library, don't rename */ if (ID_IS_LINKED_DATABLOCK(id)) return false; @@ -1472,9 +1544,10 @@ bool new_id(ListBase *lb, ID *id, const char *tname) * Pull an ID out of a library (make it local). Only call this for IDs that * don't have other library users. */ -void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist) +void id_clear_lib_data_ex(Main *bmain, ID *id, const bool id_in_mainlist) { bNodeTree *ntree = NULL; + Key *key = NULL; BKE_id_lib_local_paths(bmain, id->lib, id); @@ -1485,13 +1558,14 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist) if (id_in_mainlist) new_id(which_libbase(bmain, GS(id->name)), id, NULL); - /* internal bNodeTree blocks inside ID types below - * also stores id->lib, make sure this stays in sync. - */ - ntree = ntreeFromID(id); + /* Internal bNodeTree blocks inside datablocks also stores id->lib, make sure this stays in sync. */ + if ((ntree = ntreeFromID(id))) { + id_clear_lib_data_ex(bmain, &ntree->id, false); /* Datablocks' nodetree is never in Main. */ + } - if (ntree) { - ntreeMakeLocal(bmain, ntree, false); + /* Same goes for shapekeys. */ + if ((key = BKE_key_from_id(id))) { + id_clear_lib_data_ex(bmain, &key->id, id_in_mainlist); /* sigh, why are keys in Main? */ } if (GS(id->name) == ID_OB) { @@ -1527,53 +1601,6 @@ void BKE_main_id_clear_newpoins(Main *bmain) } } -static void lib_indirect_test_id(ID *id, const Library *lib) -{ -#define LIBTAG(a) \ - if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0 - - if (ID_IS_LINKED_DATABLOCK(id)) { - /* datablocks that were indirectly related are now direct links - * without this, appending data that has a link to other data will fail to write */ - if (lib && id->lib->parent == lib) { - id_lib_extern(id); - } - return; - } - - if (GS(id->name) == ID_OB) { - Object *ob = (Object *)id; - Mesh *me; - - int a; - -#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */ - /* XXX old animation system! -------------------------------------- */ - { - bActionStrip *strip; - for (strip = ob->nlastrips.first; strip; strip = strip->next) { - LIBTAG(strip->object); - LIBTAG(strip->act); - LIBTAG(strip->ipo); - } - } - /* XXX: new animation system needs something like this? */ -#endif - - for (a = 0; a < ob->totcol; a++) { - LIBTAG(ob->mat[a]); - } - - LIBTAG(ob->dup_group); - LIBTAG(ob->proxy); - - me = ob->data; - LIBTAG(me); - } - -#undef LIBTAG -} - /** Make linked datablocks local. * * \param bmain Almost certainly G.main. @@ -1581,19 +1608,30 @@ static void lib_indirect_test_id(ID *id, const Library *lib) * \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING. * \param set_fake If true, set fake user on all localized datablocks (except group and objects ones). */ +/* XXX TODO This function should probably be reworked. + * + * Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether + * they were also indirectly used or not... + * + * Current version uses regular id_make_local callback, but this is not super-efficient since this ends up + * duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID). + * + * We could first check all IDs and detect those to be made local that are only used by other local or future-local + * datablocks, and directly tag those as local (instead of going through id_make_local) maybe... + * + * We'll probably need at some point a true dependency graph between datablocks, but for now this should work + * good enough (performances is not a critical point here anyway). + */ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake) { ListBase *lbarray[MAX_LIBARRAY]; - ID *id, *idn; + ID *id, *id_next; int a; - a = set_listbasepointers(bmain, lbarray); - while (a--) { - id = lbarray[a]->first; - - while (id) { + for (a = set_listbasepointers(bmain, lbarray); a--; ) { + for (id = lbarray[a]->first; id; id = id_next) { id->newid = NULL; - idn = id->next; /* id is possibly being inserted again */ + id_next = id->next; /* id is possibly being inserted again */ /* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its * possible to tag data you don't want to be made local, used for @@ -1605,14 +1643,8 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged { if (lib == NULL || id->lib == lib) { if (id->lib) { - /* for Make Local > All we should be calling id_make_local, - * but doing that breaks append (see #36003 and #36006), we - * we should make it work with all datablocks and id.us==0 */ - id_clear_lib_data(bmain, id); /* sets 'id->tag' */ - - /* why sort alphabetically here but not in - * id_clear_lib_data() ? - campbell */ - id_sort_by_name(lbarray[a], id); + /* In this specific case, we do want to make ID local even if it has no local usage yet... */ + id_make_local(bmain, id, false, true); } else { id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW); @@ -1626,231 +1658,40 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged } } } - - id = idn; - } - } - - a = set_listbasepointers(bmain, lbarray); - while (a--) { - for (id = lbarray[a]->first; id; id = id->next) - lib_indirect_test_id(id, lib); - } -} - -/* Asset managing - TODO: we most likely want to turn this into a hashing at some point, could become a bit slow - * when having huge assets (or many of them)... */ -void BKE_library_asset_repository_init(Library *lib, const AssetEngineType *aet, const char *repo_root) -{ - BKE_library_asset_repository_free(lib); - lib->asset_repository = MEM_mallocN(sizeof(*lib->asset_repository), __func__); - - BLI_strncpy(lib->asset_repository->asset_engine, aet->idname, sizeof(lib->asset_repository->asset_engine)); - lib->asset_repository->asset_engine_version = aet->version; - BLI_strncpy(lib->asset_repository->root, repo_root, sizeof(lib->asset_repository->root)); - - BLI_listbase_clear(&lib->asset_repository->assets); -} - -void BKE_library_asset_repository_clear(Library *lib) -{ - if (lib->asset_repository) { - for (AssetRef *aref; (aref = BLI_pophead(&lib->asset_repository->assets)); ) { - BLI_freelistN(&aref->id_list); - MEM_freeN(aref); - } - } -} - -void BKE_library_asset_repository_free(Library *lib) -{ - if (lib->asset_repository) { - BKE_library_asset_repository_clear(lib); - MEM_freeN(lib->asset_repository); - lib->asset_repository = NULL; - } -} - -AssetRef *BKE_library_asset_repository_asset_add(Library *lib, const void *idv) -{ - const ID *id = idv; - BLI_assert(id->uuid != NULL); - - AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv); - if (!aref) { - aref = MEM_callocN(sizeof(*aref), __func__); - aref->uuid = *id->uuid; - BKE_library_asset_repository_subdata_add(aref, idv); - BLI_addtail(&lib->asset_repository->assets, aref); - } - - return aref; -} - -AssetRef *BKE_library_asset_repository_asset_find(Library *lib, const void *idv) -{ - const ID *id = idv; - BLI_assert(id->uuid != NULL); - - for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) { - if (ASSETUUID_COMPARE(&aref->uuid, id->uuid)) { -#ifndef NDEBUG - LinkData *link = aref->id_list.first; - BLI_assert(link && (link->data == idv)); -#endif - return aref; - } - } - return NULL; -} - -void BKE_library_asset_repository_asset_remove(Library *lib, const void *idv) -{ - AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv); - BLI_remlink(&lib->asset_repository->assets, aref); - BLI_freelistN(&aref->id_list); - MEM_freeN(aref); -} - -void BKE_library_asset_repository_subdata_add(AssetRef *aref, const void *idv) -{ - if (BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data)) == NULL) { - BLI_addtail(&aref->id_list, BLI_genericNodeN((void *)idv)); - } -} - -void BKE_library_asset_repository_subdata_remove(AssetRef *aref, const void *idv) -{ - LinkData *link = BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data)); - if (link) { - BLI_freelinkN(&aref->id_list, link); - } -} - -void BKE_libraries_asset_subdata_remove(Main *bmain, const void *idv) -{ - const ID *id = idv; - - if (id->lib == NULL) { - return; - } - - ListBase *lb = which_libbase(bmain, ID_LI); - for (Library *lib = lb->first; lib; lib = lib->id.next) { - if (lib->asset_repository) { - for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) { - BLI_freelinkN(&aref->id_list, BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data))); - } } } -} - -void BKE_libraries_asset_repositories_clear(Main *bmain) -{ - ListBase *lb = which_libbase(bmain, ID_LI); - for (Library *lib = lb->first; lib; lib = lib->id.next) { - BKE_library_asset_repository_clear(lib); - } - BKE_main_id_tag_all(bmain, LIB_TAG_ASSET, false); -} - -static int library_asset_dependencies_rebuild_cb(void *userdata, ID *id_self, ID **idp, int UNUSED(cd_flag)) -{ - if (!idp || !*idp) { - return IDWALK_RET_NOP; - } - AssetRef *aref = userdata; - ID *id = *idp; - - if (id->uuid) { - return IDWALK_RET_STOP_RECURSION; - } - - printf("%s (from %s)\n", id->name, id_self->name); - - BKE_library_asset_repository_subdata_add(aref, (const void *)id); - id->tag |= LIB_TAG_ASSET; - return IDWALK_RET_NOP; -} - -static void library_asset_dependencies_rebuild(ID *asset) -{ - Library *lib = asset->lib; - BLI_assert(lib && lib->asset_repository); - - if (!(lib && lib->asset_repository)) { - printf("asset: %s\n", asset->name); - printf("lib: %p\n", lib); - printf("lib: %s\n", lib->id.name); - printf("lib: %s\n", lib->name); - printf("lib: %p\n\n\n", lib->asset_repository); - } - - asset->tag |= LIB_TAG_ASSET; - - AssetRef *aref = BKE_library_asset_repository_asset_add(lib, asset); - - BKE_library_foreach_ID_link(asset, library_asset_dependencies_rebuild_cb, aref, IDWALK_RECURSE); -} - -void BKE_libraries_asset_repositories_rebuild(Main *bmain) -{ - ListBase *lbarray[MAX_LIBARRAY]; - ID *id; - int a; - - BKE_libraries_asset_repositories_clear(bmain); - - a = set_listbasepointers(bmain, lbarray); - while (a--) { + /* We have to remap local usages of old (linked) ID to new (local) id in a second loop, as lbarray ordering is not + * enough to ensure us we did catch all dependencies (e.g. if making local a parent object before its child...). + * See T48907. */ + for (a = set_listbasepointers(bmain, lbarray); a--; ) { for (id = lbarray[a]->first; id; id = id->next) { - if (id->uuid) { - library_asset_dependencies_rebuild(id); + if (id->newid) { + BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE); } } } -} -AssetRef *BKE_libraries_asset_repository_uuid_find(Main *bmain, const AssetUUID *uuid) -{ - ListBase *lb = which_libbase(bmain, ID_LI); - for (Library *lib = lb->first; lib; lib = lib->id.next) { - for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) { - if (ASSETUUID_COMPARE(&aref->uuid, uuid)) { -#ifndef NDEBUG - LinkData *link = aref->id_list.first; - BLI_assert(link && ((ID *)link->data)->uuid && ASSETUUID_COMPARE(((ID *)link->data)->uuid, uuid)); -#endif - return aref; + /* Third step: remove datablocks that have been copied to be localized and are no more used in the end... + * Note that we may have to loop more than once here, to tackle dependencies between linked objects... */ + bool do_loop = true; + while (do_loop) { + do_loop = false; + for (a = set_listbasepointers(bmain, lbarray); a--; ) { + for (id = lbarray[a]->first; id; id = id_next) { + id_next = id->next; + if (id->newid) { + bool is_local = false, is_lib = false; + + BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); + if (!is_local && !is_lib) { + BKE_libblock_free(bmain, id); + do_loop = true; + } + } } } } - return NULL; -} - -/** Find or add the 'virtual' library datablock matching this asset engine, used for non-blend-data assets. */ -Library *BKE_library_asset_virtual_ensure(Main *bmain, const AssetEngineType *aet) -{ - Library *lib; - ListBase *lb = which_libbase(bmain, ID_LI); - - for (lib = lb->first; lib; lib = lib->id.next) { - if (!(lib->flag & LIBRARY_FLAG_VIRTUAL) || !lib->asset_repository) { - continue; - } - - if (STREQ(lib->asset_repository->asset_engine, aet->idname) && - lib->asset_repository->asset_engine_version == aet->version) - { - return lib; - } - } - - lib = BKE_libblock_alloc(bmain, ID_LI, "VirtualLib"); - BKE_library_asset_repository_init(lib, aet, ""); - lib->flag |= LIBRARY_FLAG_VIRTUAL; - return lib; } diff --git a/source/blender/blenkernel/intern/library_asset.c b/source/blender/blenkernel/intern/library_asset.c new file mode 100644 index 00000000000..9ee6a2e426e --- /dev/null +++ b/source/blender/blenkernel/intern/library_asset.c @@ -0,0 +1,269 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015,2016 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/library_asset.c + * \ingroup bke + * + * Contains asset-related management of ID's and libraries. + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "RNA_types.h" + +#include "BKE_asset_engine.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_main.h" + + +/* Asset managing - TODO: we most likely want to turn this into a hashing at some point, could become a bit slow + * when having huge assets (or many of them)... */ +void BKE_library_asset_repository_init(Library *lib, const AssetEngineType *aet, const char *repo_root) +{ + BKE_library_asset_repository_free(lib); + lib->asset_repository = MEM_mallocN(sizeof(*lib->asset_repository), __func__); + + BLI_strncpy(lib->asset_repository->asset_engine, aet->idname, sizeof(lib->asset_repository->asset_engine)); + lib->asset_repository->asset_engine_version = aet->version; + BLI_strncpy(lib->asset_repository->root, repo_root, sizeof(lib->asset_repository->root)); + + BLI_listbase_clear(&lib->asset_repository->assets); +} + +void BKE_library_asset_repository_clear(Library *lib) +{ + if (lib->asset_repository) { + for (AssetRef *aref; (aref = BLI_pophead(&lib->asset_repository->assets)); ) { + BLI_freelistN(&aref->id_list); + MEM_freeN(aref); + } + } +} + +void BKE_library_asset_repository_free(Library *lib) +{ + if (lib->asset_repository) { + BKE_library_asset_repository_clear(lib); + MEM_freeN(lib->asset_repository); + lib->asset_repository = NULL; + } +} + +AssetRef *BKE_library_asset_repository_asset_add(Library *lib, const void *idv) +{ + const ID *id = idv; + BLI_assert(id->uuid != NULL); + + AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv); + if (!aref) { + aref = MEM_callocN(sizeof(*aref), __func__); + aref->uuid = *id->uuid; + BKE_library_asset_repository_subdata_add(aref, idv); + BLI_addtail(&lib->asset_repository->assets, aref); + } + + return aref; +} + +AssetRef *BKE_library_asset_repository_asset_find(Library *lib, const void *idv) +{ + const ID *id = idv; + BLI_assert(id->uuid != NULL); + + for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) { + if (ASSETUUID_COMPARE(&aref->uuid, id->uuid)) { +#ifndef NDEBUG + LinkData *link = aref->id_list.first; + BLI_assert(link && (link->data == idv)); +#endif + return aref; + } + } + return NULL; +} + +void BKE_library_asset_repository_asset_remove(Library *lib, const void *idv) +{ + AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv); + BLI_remlink(&lib->asset_repository->assets, aref); + BLI_freelistN(&aref->id_list); + MEM_freeN(aref); +} + +void BKE_library_asset_repository_subdata_add(AssetRef *aref, const void *idv) +{ + if (BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data)) == NULL) { + BLI_addtail(&aref->id_list, BLI_genericNodeN((void *)idv)); + } +} + +void BKE_library_asset_repository_subdata_remove(AssetRef *aref, const void *idv) +{ + LinkData *link = BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data)); + if (link) { + BLI_freelinkN(&aref->id_list, link); + } +} + +void BKE_libraries_asset_subdata_remove(Main *bmain, const void *idv) +{ + const ID *id = idv; + + if (id->lib == NULL) { + return; + } + + ListBase *lb = &bmain->library; + for (Library *lib = lb->first; lib; lib = lib->id.next) { + if (lib->asset_repository) { + for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) { + LinkData *subdata = aref->id_list.first; + /* Skip first one, it's main asset, not subdata! */ + for (subdata = subdata->next; subdata; subdata = subdata->next) { + if (subdata->data == idv) { + BLI_freelinkN(&aref->id_list, subdata); + break; + } + } + } + } + } +} + +void BKE_libraries_asset_repositories_clear(Main *bmain) +{ + ListBase *lb = which_libbase(bmain, ID_LI); + for (Library *lib = lb->first; lib; lib = lib->id.next) { + BKE_library_asset_repository_clear(lib); + } + BKE_main_id_tag_all(bmain, LIB_TAG_ASSET, false); +} + +static int library_asset_dependencies_rebuild_cb(void *userdata, ID *id_self, ID **idp, int UNUSED(cd_flag)) +{ + if (!idp || !*idp) { + return IDWALK_RET_NOP; + } + + AssetRef *aref = userdata; + ID *id = *idp; + + if (id->uuid) { + return IDWALK_RET_STOP_RECURSION; + } + + printf("%s (from %s)\n", id->name, id_self->name); + + BKE_library_asset_repository_subdata_add(aref, (const void *)id); + id->tag |= LIB_TAG_ASSET; + return IDWALK_RET_NOP; +} + +static void library_asset_dependencies_rebuild(ID *asset) +{ + Library *lib = asset->lib; + BLI_assert(lib && lib->asset_repository); + + if (!(lib && lib->asset_repository)) { + printf("asset: %s\n", asset->name); + printf("lib: %p\n", lib); + printf("lib: %s\n", lib->id.name); + printf("lib: %s\n", lib->name); + printf("lib: %p\n\n\n", lib->asset_repository); + } + + asset->tag |= LIB_TAG_ASSET; + + AssetRef *aref = BKE_library_asset_repository_asset_add(lib, asset); + + BKE_library_foreach_ID_link(asset, library_asset_dependencies_rebuild_cb, aref, IDWALK_RECURSE); +} + +void BKE_libraries_asset_repositories_rebuild(Main *bmain) +{ + ListBase *lbarray[MAX_LIBARRAY]; + ID *id; + int a; + + BKE_libraries_asset_repositories_clear(bmain); + + a = set_listbasepointers(bmain, lbarray); + while (a--) { + for (id = lbarray[a]->first; id; id = id->next) { + if (id->uuid) { + library_asset_dependencies_rebuild(id); + } + } + } +} + +AssetRef *BKE_libraries_asset_repository_uuid_find(Main *bmain, const AssetUUID *uuid) +{ + ListBase *lb = which_libbase(bmain, ID_LI); + for (Library *lib = lb->first; lib; lib = lib->id.next) { + for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) { + if (ASSETUUID_COMPARE(&aref->uuid, uuid)) { +#ifndef NDEBUG + LinkData *link = aref->id_list.first; + BLI_assert(link && ((ID *)link->data)->uuid && ASSETUUID_COMPARE(((ID *)link->data)->uuid, uuid)); +#endif + return aref; + } + } + } + return NULL; +} + +/** Find or add the 'virtual' library datablock matching this asset engine, used for non-blend-data assets. */ +Library *BKE_library_asset_virtual_ensure(Main *bmain, const AssetEngineType *aet) +{ + Library *lib; + ListBase *lb = which_libbase(bmain, ID_LI); + + for (lib = lb->first; lib; lib = lib->id.next) { + if (!(lib->flag & LIBRARY_FLAG_VIRTUAL) || !lib->asset_repository) { + continue; + } + + if (STREQ(lib->asset_repository->asset_engine, aet->idname) && + lib->asset_repository->asset_engine_version == aet->version) + { + return lib; + } + } + + lib = BKE_libblock_alloc(bmain, ID_LI, "VirtualLib"); + BKE_library_asset_repository_init(lib, aet, ""); + lib->flag |= LIBRARY_FLAG_VIRTUAL; + return lib; +} diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index f86f5fa01ec..a33c63c07af 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -298,7 +298,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u do { data.self_id = id; - data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0; + data.cd_flag = ID_IS_LINKED(id) ? IDWALK_INDIRECT_USAGE : 0; AnimData *adt = BKE_animdata_from_id(id); if (adt) { @@ -442,7 +442,16 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u /* object->proxy is refcounted, but not object->proxy_group... *sigh* */ CALLBACK_INVOKE(object->proxy, IDWALK_USER); CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP); + + /* Special case! + * Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage + * if proxy object is linked... Twisted. */ + if (object->proxy_from) { + data.cd_flag = ID_IS_LINKED(object->proxy_from) ? IDWALK_INDIRECT_USAGE : 0; + } CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP); + data.cd_flag = data_cd_flag; + CALLBACK_INVOKE(object->poselib, IDWALK_USER); data.cd_flag |= proxy_cd_flag; @@ -856,9 +865,10 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag) /** * Say whether given \a id_type_owner can use (in any way) a datablock of \a id_type_used. + * + * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above, quite useful to reduce + * useless iterations in some cases. */ -/* This is a 'simplified' abstract version of BKE_library_foreach_ID_link() above, quite useful to reduce - * useless ietrations in some cases. */ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used) { if (id_type_used == ID_AC) { diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index b158b3f968b..9ac795ddf44 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -296,6 +296,9 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) if (ob->pose && (!old_id || ob->data == old_id)) { BLI_assert(ob->type == OB_ARMATURE); ob->pose->flag |= POSE_RECALC; + /* We need to clear pose bone pointers immediately, things like undo writefile may be called + * before pose is actually recomputed, can lead to segfault... */ + BKE_pose_clear_pointers(ob->pose); } } break; @@ -641,6 +644,7 @@ void BKE_libblock_relink_ex( libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL); } } + break; } case ID_OB: if (new_id) { /* Only affects us in case obdata was relinked (changed). */ @@ -682,6 +686,10 @@ void BKE_libblock_free_data(Main *bmain, ID *id) MEM_freeN(id->properties); } + if (id->uuid) { + MEM_freeN(id->uuid); + } + /* this ID may be a driver target! */ BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); } diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index c4a0d0074fb..430935a5fad 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -218,14 +218,16 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next) BKE_linestyle_geometry_modifier_copy(new_linestyle, m); - if (ID_IS_LINKED_DATABLOCK(linestyle)) { - BKE_id_expand_local(&new_linestyle->id); - BKE_id_lib_local_paths(bmain, linestyle->id.lib, &new_linestyle->id); - } + BKE_id_copy_ensure_local(bmain, &linestyle->id, &new_linestyle->id); return new_linestyle; } +void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &linestyle->id, true, lib_local); +} + FreestyleLineStyle *BKE_linestyle_active_from_scene(Scene *scene) { SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay); diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 9e070bbef22..21023d9f53c 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -853,14 +853,16 @@ Mask *BKE_mask_copy(Main *bmain, Mask *mask) /* enable fake user by default */ id_fake_user_set(&mask->id); - if (ID_IS_LINKED_DATABLOCK(mask)) { - BKE_id_expand_local(&mask_new->id); - BKE_id_lib_local_paths(bmain, mask->id.lib, &mask_new->id); - } + BKE_id_copy_ensure_local(bmain, &mask->id, &mask_new->id); return mask_new; } +void BKE_mask_make_local(Main *bmain, Mask *mask, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &mask->id, true, lib_local); +} + void BKE_mask_point_free(MaskSplinePoint *point) { if (point->uw) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 17811893c03..0be32c9b84c 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -243,14 +243,11 @@ Material *BKE_material_copy(Main *bmain, Material *ma) man->nodetree = ntreeCopyTree(bmain, ma->nodetree); } - man->preview = BKE_previewimg_copy(ma->preview); + BKE_previewimg_id_copy(&man->id, &ma->id); BLI_listbase_clear(&man->gpumaterial); - if (ID_IS_LINKED_DATABLOCK(ma)) { - BKE_id_expand_local(&man->id); - BKE_id_lib_local_paths(bmain, ma->id.lib, &man->id); - } + BKE_id_copy_ensure_local(bmain, &ma->id, &man->id); return man; } @@ -285,34 +282,9 @@ Material *localize_material(Material *ma) return man; } -void BKE_material_make_local(Main *bmain, Material *ma) +void BKE_material_make_local(Main *bmain, Material *ma, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(ma)) { - return; - } - - BKE_library_ID_test_usages(bmain, ma, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &ma->id); - BKE_id_expand_local(&ma->id); - } - else { - Material *ma_new = BKE_material_copy(bmain, ma); - - ma_new->id.us = 0; - - BKE_libblock_remap(bmain, ma, ma_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &ma->id, true, lib_local); } Material ***give_matarar(Object *ob) @@ -569,18 +541,6 @@ Material *give_current_material(Object *ob, short act) return ma; } -ID *material_from(Object *ob, short act) -{ - - if (ob == NULL) return NULL; - - if (ob->totcol == 0) return ob->data; - if (act == 0) act = 1; - - if (ob->matbits[act - 1]) return (ID *)ob; - else return ob->data; -} - Material *give_node_material(Material *ma) { if (ma && ma->use_nodes && ma->nodetree) { @@ -886,7 +846,11 @@ void assign_matarar(struct Object *ob, struct Material ***matar, short totcol) int actcol_orig = ob->actcol; short i; - while (object_remove_material_slot(ob)) {} + while ((ob->totcol > totcol) && + BKE_object_material_slot_remove(ob)) + { + /* pass */ + } /* now we have the right number of slots */ for (i = 0; i < totcol; i++) @@ -899,7 +863,7 @@ void assign_matarar(struct Object *ob, struct Material ***matar, short totcol) } -short find_material_index(Object *ob, Material *ma) +short BKE_object_material_slot_find_index(Object *ob, Material *ma) { Material ***matarar; short a, *totcolp; @@ -919,7 +883,7 @@ short find_material_index(Object *ob, Material *ma) return 0; } -bool object_add_material_slot(Object *ob) +bool BKE_object_material_slot_add(Object *ob) { if (ob == NULL) return false; if (ob->totcol >= MAXMAT) return false; @@ -1201,7 +1165,7 @@ void material_drivers_update(Scene *scene, Material *ma, float ctime) ma->id.tag &= ~LIB_TAG_DOIT; } -bool object_remove_material_slot(Object *ob) +bool BKE_object_material_slot_remove(Object *ob) { Material *mao, ***matarar; Object *obt; diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 9a0a6e3540c..8d024ea9aa5 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -119,42 +119,14 @@ MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb) mbn->editelems = NULL; mbn->lastelem = NULL; - if (ID_IS_LINKED_DATABLOCK(mb)) { - BKE_id_expand_local(&mbn->id); - BKE_id_lib_local_paths(bmain, mb->id.lib, &mbn->id); - } + BKE_id_copy_ensure_local(bmain, &mb->id, &mbn->id); return mbn; } -void BKE_mball_make_local(Main *bmain, MetaBall *mb) +void BKE_mball_make_local(Main *bmain, MetaBall *mb, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(mb)) { - return; - } - - BKE_library_ID_test_usages(bmain, mb, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &mb->id); - BKE_id_expand_local(&mb->id); - } - else { - MetaBall *mb_new = BKE_mball_copy(bmain, mb); - - mb_new->id.us = 0; - - BKE_libblock_remap(bmain, mb, mb_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &mb->id, true, lib_local); } /* most simple meta-element adding function diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 787b9905734..733e9030056 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -31,6 +31,7 @@ #include "DNA_scene_types.h" #include "DNA_material_types.h" +#include "DNA_meta_types.h" #include "DNA_object_types.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" @@ -530,10 +531,7 @@ Mesh *BKE_mesh_copy(Main *bmain, Mesh *me) men->key->from = (ID *)men; } - if (ID_IS_LINKED_DATABLOCK(me)) { - BKE_id_expand_local(&men->id); - BKE_id_lib_local_paths(bmain, me->id.lib, &men->id); - } + BKE_id_copy_ensure_local(bmain, &me->id, &men->id); return men; } @@ -555,37 +553,9 @@ BMesh *BKE_mesh_to_bmesh( return bm; } -void BKE_mesh_make_local(Main *bmain, Mesh *me) +void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(me)) { - return; - } - - BKE_library_ID_test_usages(bmain, me, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &me->id); - if (me->key) { - BKE_key_make_local(bmain, me->key); - } - BKE_id_expand_local(&me->id); - } - else { - Mesh *me_new = BKE_mesh_copy(bmain, me); - - me_new->id.us = 0; - - BKE_libblock_remap(bmain, me, me_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &me->id, true, lib_local); } bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int loop_index, const int face_index, @@ -2227,7 +2197,6 @@ Mesh *BKE_mesh_new_from_object( { Mesh *tmpmesh; Curve *tmpcu = NULL, *copycu; - Object *tmpobj = NULL; int render = settings == eModifierMode_Render, i; int cage = !apply_modifiers; @@ -2242,7 +2211,7 @@ Mesh *BKE_mesh_new_from_object( int uv_from_orco; /* copies object and modifiers (but not the data) */ - tmpobj = BKE_object_copy_ex(bmain, ob, true); + Object *tmpobj = BKE_object_copy_ex(bmain, ob, true); tmpcu = (Curve *)tmpobj->data; id_us_min(&tmpcu->id); @@ -2398,23 +2367,25 @@ Mesh *BKE_mesh_new_from_object( } break; -#if 0 - /* Crashes when assigning the new material, not sure why */ case OB_MBALL: - tmpmb = (MetaBall *)ob->data; + { + MetaBall *tmpmb = (MetaBall *)ob->data; + tmpmesh->mat = MEM_dupallocN(tmpmb->mat); tmpmesh->totcol = tmpmb->totcol; /* free old material list (if it exists) and adjust user counts */ if (tmpmb->mat) { for (i = tmpmb->totcol; i-- > 0; ) { - tmpmesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */ + /* are we an object material or data based? */ + tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpmb->mat[i]; + if (tmpmesh->mat[i]) { - id_us_plus(&tmpmb->mat[i]->id); + id_us_plus(&tmpmesh->mat[i]->id); } } } break; -#endif + } case OB_MESH: if (!cage) { @@ -2442,9 +2413,6 @@ Mesh *BKE_mesh_new_from_object( BKE_mesh_tessface_ensure(tmpmesh); } - /* make sure materials get updated in object */ - test_object_materials(tmpobj ? tmpobj : ob, &tmpmesh->id); - return tmpmesh; } diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index a472b6e5bc1..8562988b5e1 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -393,6 +393,60 @@ void BKE_mesh_vert_edge_vert_map_create( } /** + * Generates a map where the key is the edge and the value is a list of loops that use that edge. + * Loops indices of a same poly are contiguous and in winding order. + * The lists are allocated from one memory pool. + */ +void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map, int **r_mem, + const MEdge *UNUSED(medge), const int totedge, + const MPoly *mpoly, const int totpoly, + const MLoop *mloop, const int totloop) +{ + MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map"); + int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop * 2, "edge-poly map mem"); + int *index_step; + const MPoly *mp; + int i; + + /* count face users */ + for (i = 0, mp = mpoly; i < totpoly; mp++, i++) { + const MLoop *ml; + int j = mp->totloop; + for (ml = &mloop[mp->loopstart]; j--; ml++) { + map[ml->e].count += 2; + } + } + + /* create offsets */ + index_step = indices; + for (i = 0; i < totedge; i++) { + map[i].indices = index_step; + index_step += map[i].count; + + /* re-count, using this as an index below */ + map[i].count = 0; + } + + /* assign loop-edge users */ + for (i = 0, mp = mpoly; i < totpoly; mp++, i++) { + const MLoop *ml; + MeshElemMap *map_ele; + const int max_loop = mp->loopstart + mp->totloop; + int j = mp->loopstart; + for (ml = &mloop[j]; j < max_loop; j++, ml++) { + map_ele = &map[ml->e]; + map_ele->indices[map_ele->count++] = j; + map_ele->indices[map_ele->count++] = j + 1; + } + /* last edge/loop of poly, must point back to first loop! */ + map_ele->indices[map_ele->count - 1] = mp->loopstart; + } + + *r_map = map; + *r_mem = indices; +} + +/** * Generates a map where the key is the edge and the value is a list of polygons that use that edge. * The lists are allocated from one memory pool. */ @@ -539,12 +593,12 @@ void BKE_mesh_origindex_map_create_looptri( */ typedef bool (*MeshRemap_CheckIslandBoundary)( const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge, - const int nbr_egde_users); + const int nbr_egde_users, void *user_data); static void poly_edge_loop_islands_calc( const MEdge *medge, const int totedge, const MPoly *mpoly, const int totpoly, const MLoop *mloop, const int totloop, MeshElemMap *edge_poly_map, - const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check, + const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check, void *edge_boundary_check_data, int **r_poly_groups, int *r_totgroup, BLI_bitmap **r_edge_borders, int *r_totedgeborder) { int *poly_groups; @@ -626,7 +680,7 @@ static void poly_edge_loop_islands_calc( const MeshElemMap *map_ele = &edge_poly_map[me_idx]; const int *p = map_ele->indices; int i = map_ele->count; - if (!edge_boundary_check(mp, ml, me, i)) { + if (!edge_boundary_check(mp, ml, me, i, edge_boundary_check_data)) { for (; i--; p++) { /* if we meet other non initialized its a bug */ BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id)); @@ -718,7 +772,7 @@ static void poly_edge_loop_islands_calc( } static bool poly_is_island_boundary_smooth_cb( - const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users) + const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users, void *UNUSED(user_data)) { /* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */ return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2)); @@ -741,7 +795,7 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, poly_edge_loop_islands_calc( medge, totedge, mpoly, totpoly, mloop, totloop, NULL, use_bitflags, - poly_is_island_boundary_smooth_cb, &poly_groups, r_totgroup, NULL, NULL); + poly_is_island_boundary_smooth_cb, NULL, &poly_groups, r_totgroup, NULL, NULL); return poly_groups; } @@ -848,28 +902,60 @@ void BKE_mesh_loop_islands_add( * Would make things much more complex though, and each UVMap would then need its own mesh mapping, * not sure we want that at all! */ +typedef struct MeshCheckIslandBoundaryUv { + const MLoop *loops; + const MLoopUV *luvs; + const MeshElemMap *edge_loop_map; +} MeshCheckIslandBoundaryUv; + static bool mesh_check_island_boundary_uv( - const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, const int UNUSED(nbr_egde_users)) + const MPoly *UNUSED(mp), const MLoop *ml, const MEdge *me, + const int UNUSED(nbr_egde_users), void *user_data) { - /* Edge is UV boundary if tagged as seam. */ - return (me->flag & ME_SEAM) != 0; + if (user_data) { + const MeshCheckIslandBoundaryUv *data = user_data; + const MLoop *loops = data->loops; + const MLoopUV *luvs = data->luvs; + const MeshElemMap *edge_to_loops = &data->edge_loop_map[ml->e]; + + BLI_assert(edge_to_loops->count >= 2 && (edge_to_loops->count % 2) == 0); + + const unsigned int v1 = loops[edge_to_loops->indices[0]].v; + const unsigned int v2 = loops[edge_to_loops->indices[1]].v; + const float *uvco_v1 = luvs[edge_to_loops->indices[0]].uv; + const float *uvco_v2 = luvs[edge_to_loops->indices[1]].uv; + for (int i = 2; i < edge_to_loops->count; i += 2) { + if (loops[edge_to_loops->indices[i]].v == v1) { + if (!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i]].uv) || + !equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i + 1]].uv)) + { + return true; + } + } + else { + BLI_assert(loops[edge_to_loops->indices[i]].v == v2); + UNUSED_VARS_NDEBUG(v2); + if (!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i]].uv) || + !equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i + 1]].uv)) + { + return true; + } + } + } + return false; + } + else { + /* Edge is UV boundary if tagged as seam. */ + return (me->flag & ME_SEAM) != 0; + } } -/** - * Calculate UV islands. - * - * \note Currently we only consider edges tagges as seams as UV boundaries. This has the advantages of simplicity, - * and being valid/common to all UV maps. However, it means actual UV islands whithout matching UV seams - * will not be handled correctly... - * - * \note All this could be optimized... - * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do... - */ -bool BKE_mesh_calc_islands_loop_poly_uv( +static bool mesh_calc_islands_loop_poly_uv( MVert *UNUSED(verts), const int UNUSED(totvert), MEdge *edges, const int totedge, MPoly *polys, const int totpoly, MLoop *loops, const int totloop, + const MLoopUV *luvs, MeshIslandStore *r_island_store) { int *poly_groups = NULL; @@ -879,6 +965,11 @@ bool BKE_mesh_calc_islands_loop_poly_uv( MeshElemMap *edge_poly_map; int *edge_poly_mem; + MeshElemMap *edge_loop_map; + int *edge_loop_mem; + + MeshCheckIslandBoundaryUv edge_boundary_check_data; + int *poly_indices; int *loop_indices; int num_pidx, num_lidx; @@ -899,9 +990,18 @@ bool BKE_mesh_calc_islands_loop_poly_uv( BKE_mesh_edge_poly_map_create(&edge_poly_map, &edge_poly_mem, edges, totedge, polys, totpoly, loops, totloop); + if (luvs) { + BKE_mesh_edge_loop_map_create(&edge_loop_map, &edge_loop_mem, + edges, totedge, polys, totpoly, loops, totloop); + edge_boundary_check_data.loops = loops; + edge_boundary_check_data.luvs = luvs; + edge_boundary_check_data.edge_loop_map = edge_loop_map; + } + poly_edge_loop_islands_calc( - edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false, - mesh_check_island_boundary_uv, &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders); + edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false, + mesh_check_island_boundary_uv, luvs ? &edge_boundary_check_data : NULL, + &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders); if (!num_poly_groups) { /* Should never happen... */ @@ -958,6 +1058,11 @@ bool BKE_mesh_calc_islands_loop_poly_uv( MEM_freeN(edge_poly_map); MEM_freeN(edge_poly_mem); + if (luvs) { + MEM_freeN(edge_loop_map); + MEM_freeN(edge_loop_mem); + } + MEM_freeN(poly_indices); MEM_freeN(loop_indices); MEM_freeN(poly_groups); @@ -973,4 +1078,42 @@ bool BKE_mesh_calc_islands_loop_poly_uv( return true; } +/** + * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams), not some UV layers coordinates. + */ +bool BKE_mesh_calc_islands_loop_poly_edgeseam( + MVert *verts, const int totvert, + MEdge *edges, const int totedge, + MPoly *polys, const int totpoly, + MLoop *loops, const int totloop, + MeshIslandStore *r_island_store) +{ + return mesh_calc_islands_loop_poly_uv( + verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store); +} + +/** + * Calculate UV islands. + * + * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries. + * This has the advantages of simplicity, and being valid/common to all UV maps. + * However, it means actual UV islands whithout matching UV seams will not be handled correctly... + * If a valid UV layer is passed as \a luvs parameter, UV coordinates are also used to detect islands boundaries. + * + * \note All this could be optimized... + * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do... + */ +bool BKE_mesh_calc_islands_loop_poly_uvmap( + MVert *verts, const int totvert, + MEdge *edges, const int totedge, + MPoly *polys, const int totpoly, + MLoop *loops, const int totloop, + const MLoopUV *luvs, + MeshIslandStore *r_island_store) +{ + BLI_assert(luvs != NULL); + return mesh_calc_islands_loop_poly_uv( + verts, totvert, edges, totedge, polys, totpoly, loops, totloop, luvs, r_island_store); +} + /** \} */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 41e4c21d814..349e99bab61 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -707,7 +707,7 @@ void test_object_modifiers(Object *ob) */ const char *modifier_path_relbase(Object *ob) { - if (G.relbase_valid || ID_IS_LINKED_DATABLOCK(ob)) { + if (G.relbase_valid || ID_IS_LINKED(ob)) { return ID_BLEND_PATH(G.main, &ob->id); } else { diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 296a00388c4..fad7b3b098e 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1211,7 +1211,6 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski } else { newtree = BKE_libblock_copy_nolib(&ntree->id, true); - newtree->id.lib = NULL; /* same as owning datablock id.lib */ } id_us_plus((ID *)newtree->gpd); @@ -1291,10 +1290,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski /* node tree will generate its own interface type */ newtree->interface_type = NULL; - if (ID_IS_LINKED_DATABLOCK(ntree)) { - BKE_id_expand_local(&newtree->id); - BKE_id_lib_local_paths(bmain, ntree->id.lib, &newtree->id); - } + BKE_id_copy_ensure_local(bmain, &ntree->id, &newtree->id); return newtree; } @@ -1951,34 +1947,9 @@ bNodeTree *ntreeFromID(ID *id) } } -void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist) +void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist, const bool lib_local) { - bool is_lib = false, is_local = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(ntree)) { - return; - } - - BKE_library_ID_test_usages(bmain, ntree, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist); - BKE_id_expand_local(&ntree->id); - } - else { - bNodeTree *ntree_new = ntreeCopyTree(bmain, ntree); - - ntree_new->id.us = 0; - - BKE_libblock_remap(bmain, ntree, ntree_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &ntree->id, id_in_mainlist, lib_local); } int ntreeNodeExists(bNodeTree *ntree, bNode *testnode) @@ -2681,7 +2652,7 @@ void BKE_node_clipboard_add_node(bNode *node) node_info->id = node->id; if (node->id) { BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name)); - if (ID_IS_LINKED_DATABLOCK(node->id)) { + if (ID_IS_LINKED_DATABLOCK(node->id)) { /* Don't want virtual libraries here... */ BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name)); } else { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 30a193506a6..4bf92c30c6a 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1169,10 +1169,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) /* Copy runtime surve data. */ obn->curve_cache = NULL; - if (ID_IS_LINKED_DATABLOCK(ob)) { - BKE_id_expand_local(&obn->id); - BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id); - } + BKE_id_copy_ensure_local(bmain, &ob->id, &obn->id); /* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */ obn->preview = NULL; @@ -1186,22 +1183,23 @@ Object *BKE_object_copy(Main *bmain, Object *ob) return BKE_object_copy_ex(bmain, ob, false); } -void BKE_object_make_local(Main *bmain, Object *ob) +void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local) { bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy + * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later). */ - if (!ID_IS_LINKED_DATABLOCK(ob)) { + if (!ID_IS_LINKED(ob)) { return; } BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib); - if (is_local) { + if (lib_local || is_local) { if (!is_lib) { id_clear_lib_data(bmain, &ob->id); BKE_id_expand_local(&ob->id); @@ -1212,7 +1210,9 @@ void BKE_object_make_local(Main *bmain, Object *ob) ob_new->id.us = 0; ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL; - BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE); + if (!lib_local) { + BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE); + } } } } @@ -1220,15 +1220,15 @@ void BKE_object_make_local(Main *bmain, Object *ob) /* Returns true if the Object is from an external blend file (libdata) */ bool BKE_object_is_libdata(Object *ob) { - return (ob && ID_IS_LINKED_DATABLOCK(ob)); + return (ob && ID_IS_LINKED(ob)); } /* Returns true if the Object data is from an external blend file (libdata) */ bool BKE_object_obdata_is_libdata(Object *ob) { /* Linked objects with local obdata are forbidden! */ - BLI_assert(!ob || !ob->data || (ID_IS_LINKED_DATABLOCK(ob) ? ID_IS_LINKED_DATABLOCK(ob->data) : true)); - return (ob && ob->data && ID_IS_LINKED_DATABLOCK(ob->data)); + BLI_assert(!ob || !ob->data || (ID_IS_LINKED(ob) ? ID_IS_LINKED(ob->data) : true)); + return (ob && ob->data && ID_IS_LINKED(ob->data)); } /* *************** PROXY **************** */ @@ -1275,7 +1275,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) /* only on local objects because this causes indirect links * 'a -> b -> c', blend to point directly to a.blend * when a.blend has a proxy thats linked into c.blend */ - if (!ID_IS_LINKED_DATABLOCK(ob)) + if (!ID_IS_LINKED(ob)) id_lib_extern((ID *)dtar->id); } } @@ -1293,7 +1293,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) { /* paranoia checks */ - if (ID_IS_LINKED_DATABLOCK(ob) || !ID_IS_LINKED_DATABLOCK(target)) { + if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) { printf("cannot make proxy\n"); return; } @@ -2670,7 +2670,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx, printf("recalcob %s\n", ob->id.name + 2); /* handle proxy copy for target */ - if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) { + if (ID_IS_LINKED(ob) && ob->proxy_from) { // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); if (ob->proxy_from->proxy_group) { /* transform proxy into group space */ Object *obg = ob->proxy_from->proxy_group; diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 457263f854b..ebd090bcc5b 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -203,7 +203,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx, break; } case OB_ARMATURE: - if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) { + if (ID_IS_LINKED(ob) && ob->proxy_from) { if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { printf("Proxy copy error, lib Object: %s proxy Object: %s\n", ob->id.name + 2, ob->proxy_from->id.name + 2); @@ -315,7 +315,7 @@ void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx), // XXX: it's almost redundant now... /* Handle proxy copy for target, */ - if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) { + if (ID_IS_LINKED(ob) && ob->proxy_from) { if (ob->proxy_from->proxy_group) { /* Transform proxy into group space. */ Object *obg = ob->proxy_from->proxy_group; @@ -347,10 +347,3 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx, ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); } - -void BKE_object_eval_proxy_backlink(EvaluationContext *UNUSED(eval_ctx), Object *ob) -{ - if (ob->proxy) { - ob->proxy->proxy_from = ob; - } -} diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 489fc2f3710..08aca2a44a3 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -232,7 +232,7 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) int tot = 0; for (ima = bmain->image.first; ima; ima = ima->id.next) { - if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED_DATABLOCK(ima)) { + if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED(ima)) { if (ima->source == IMA_SRC_FILE) { BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id)); tot ++; @@ -245,14 +245,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) } for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) { - if (vfont->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(vfont) && BKE_vfont_is_builtin(vfont) == false) { + if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) && BKE_vfont_is_builtin(vfont) == false) { vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name); tot ++; } } for (sound = bmain->sound.first; sound; sound = sound->id.next) { - if (sound->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(sound)) { + if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) { sound->packedfile = newPackedFile(reports, sound->name, bmain->name); tot++; } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 934c5b9ff06..42b818b35a5 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3335,42 +3335,14 @@ ParticleSettings *BKE_particlesettings_copy(Main *bmain, ParticleSettings *part) BLI_duplicatelist(&partn->dupliweights, &part->dupliweights); - if (ID_IS_LINKED_DATABLOCK(part)) { - BKE_id_expand_local(&partn->id); - BKE_id_lib_local_paths(bmain, part->id.lib, &partn->id); - } + BKE_id_copy_ensure_local(bmain, &part->id, &partn->id); return partn; } -void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part) +void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(part)) { - return; - } - - BKE_library_ID_test_usages(bmain, part, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &part->id); - BKE_id_expand_local(&part->id); - } - else { - ParticleSettings *part_new = BKE_particlesettings_copy(bmain, part); - - part_new->id.us = 0; - - BKE_libblock_remap(bmain, part, part_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &part->id, true, lib_local); } /************************************************/ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 858b6bd927b..3e37ee83cea 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -344,7 +344,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) } } - scen->preview = BKE_previewimg_copy(sce->preview); + BKE_previewimg_id_copy(&scen->id, &sce->id); return scen; } @@ -355,6 +355,13 @@ void BKE_scene_groups_relink(Scene *sce) BKE_rigidbody_world_groups_relink(sce->rigidbody_world); } +void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local) +{ + /* For now should work, may need more work though to support all possible corner cases + * (also scene_copy probably needs some love). */ + BKE_id_make_local_generic(bmain, &sce->id, true, lib_local); +} + /** Free (or release) any data used by this scene (does not free the scene itself). */ void BKE_scene_free(Scene *sce) { @@ -1123,7 +1130,7 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame) Base *BKE_scene_base_add(Scene *sce, Object *ob) { - Base *b = MEM_callocN(sizeof(*b), "BKE_scene_base_add"); + Base *b = MEM_callocN(sizeof(*b), __func__); BLI_addhead(&sce->base, b); b->object = ob; diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 3de4a426973..ce7c520438a 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -123,28 +123,34 @@ static ImBuf *prepare_effect_imbufs(const SeqRenderData *context, ImBuf *ibuf1, out = IMB_allocImBuf(x, y, 32, IB_rect); } - if (ibuf1 && !ibuf1->rect_float && out->rect_float) { - BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true); - } - if (ibuf2 && !ibuf2->rect_float && out->rect_float) { - BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true); - } - if (ibuf3 && !ibuf3->rect_float && out->rect_float) { - BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true); - } + if (out->rect_float) { + if (ibuf1 && !ibuf1->rect_float) { + BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true); + } + + if (ibuf2 && !ibuf2->rect_float) { + BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true); + } + + if (ibuf3 && !ibuf3->rect_float) { + BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true); + } - if (ibuf1 && !ibuf1->rect && !out->rect_float) { - IMB_rect_from_float(ibuf1); - } - if (ibuf2 && !ibuf2->rect && !out->rect_float) { - IMB_rect_from_float(ibuf2); - } - if (ibuf3 && !ibuf3->rect && !out->rect_float) { - IMB_rect_from_float(ibuf3); + IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name); } + else { + if (ibuf1 && !ibuf1->rect) { + IMB_rect_from_float(ibuf1); + } - if (out->rect_float) - IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name); + if (ibuf2 && !ibuf2->rect) { + IMB_rect_from_float(ibuf2); + } + + if (ibuf3 && !ibuf3->rect) { + IMB_rect_from_float(ibuf3); + } + } /* If effect only affecting a single channel, forward input's metadata to the output. */ if (ibuf1 != NULL && ibuf1 == ibuf2 && ibuf2 == ibuf3) { diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 5ef502e0182..6067a8b2d9b 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -1308,41 +1308,40 @@ StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra) static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfra, int chanshown) { - Sequence *seq; - Sequence *effect_inputs[MAXSEQ + 1]; - int i, totseq = 0, num_effect_inputs = 0; + /* Use arbitrary sized linked list, the size could be over MAXSEQ. */ + LinkNodePair effect_inputs = {NULL, NULL}; + int totseq = 0; memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1)); - seq = seqbase->first; - while (seq) { - if (seq->startdisp <= cfra && seq->enddisp > cfra) { + for (Sequence *seq = seqbase->first; seq; seq = seq->next) { + if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) { if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) { + if (seq->seq1) { - effect_inputs[num_effect_inputs++] = seq->seq1; + BLI_linklist_append_alloca(&effect_inputs, seq->seq1); } if (seq->seq2) { - effect_inputs[num_effect_inputs++] = seq->seq2; + BLI_linklist_append_alloca(&effect_inputs, seq->seq2); } if (seq->seq3) { - effect_inputs[num_effect_inputs++] = seq->seq3; + BLI_linklist_append_alloca(&effect_inputs, seq->seq3); } } seq_arr[seq->machine] = seq; totseq++; } - seq = seq->next; } /* Drop strips which are used for effect inputs, we don't want * them to blend into render stack in any other way than effect * string rendering. */ - for (i = 0; i < num_effect_inputs; i++) { - seq = effect_inputs[i]; + for (LinkNode *seq_item = effect_inputs.list; seq_item; seq_item = seq_item->next) { + Sequence *seq = seq_item->link; /* It's possible that effetc strip would be placed to the same * 'machine' as it's inputs. We don't want to clear such strips * from the stack. @@ -1826,8 +1825,10 @@ static void seq_proxy_build_frame( IMB_freeImBuf(ibuf); } -/* returns whether the file this context would read from even exist, if not, don't create the context -*/ +/** + * Returns whether the file this context would read from even exist, + * if not, don't create the context + */ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const int view_id) { if ((scene->r.scemode & R_MULTIVIEW) == 0) @@ -1862,8 +1863,9 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con return false; } -/** This returns the maximum possible number of required contexts -*/ +/** + * This returns the maximum possible number of required contexts + */ static int seq_proxy_context_count(Sequence *seq, Scene *scene) { int num_views = 1; @@ -3556,7 +3558,7 @@ static ImBuf *seq_render_strip( if (ibuf == NULL) { /* MOVIECLIPs have their own proxy management */ - if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) { + if (seq->type != SEQ_TYPE_MOVIECLIP) { ibuf = seq_proxy_fetch(context, seq, cfra); is_proxy_image = (ibuf != NULL); } diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 414be73e234..2f47966ec55 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -155,6 +155,11 @@ void BKE_sound_free(bSound *sound) #endif /* WITH_AUDASPACE */ } +void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &sound->id, true, lib_local); +} + #ifdef WITH_AUDASPACE static const char *force_device = NULL; diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index a91d8657179..ee6886e3fb2 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -77,42 +77,14 @@ Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk) if (spkn->sound) id_us_plus(&spkn->sound->id); - if (ID_IS_LINKED_DATABLOCK(spk)) { - BKE_id_expand_local(&spkn->id); - BKE_id_lib_local_paths(G.main, spk->id.lib, &spkn->id); - } + BKE_id_copy_ensure_local(bmain, &spk->id, &spkn->id); return spkn; } -void BKE_speaker_make_local(Main *bmain, Speaker *spk) +void BKE_speaker_make_local(Main *bmain, Speaker *spk, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(spk)) { - return; - } - - BKE_library_ID_test_usages(bmain, spk, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &spk->id); - BKE_id_expand_local(&spk->id); - } - else { - Speaker *spk_new = BKE_speaker_copy(bmain, spk); - - spk_new->id.us = 0; - - BKE_libblock_remap(bmain, spk, spk_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &spk->id, true, lib_local); } void BKE_speaker_free(Speaker *spk) diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index b0d19320230..04bcd366c3f 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -794,14 +794,20 @@ static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss, static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, float (*vertexCos)[3], - int use_flat_subdiv) + int use_flat_subdiv, + bool use_subdiv_uvs) { +#ifndef WITH_OPENSUBDIV + UNUSED_VARS(use_subdiv_uvs); +#endif + #ifdef WITH_OPENSUBDIV /* Reset all related descriptors if actual mesh topology changed or if * other evaluation-related settings changed. */ if (!ccgSubSurf_needGrids(ss)) { /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */ + ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs); ccgSubSurf_checkTopologyChanged(ss, dm); ss_sync_osd_from_derivedmesh(ss, dm); } @@ -1801,7 +1807,7 @@ static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEd #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { /* TODO(sergey): We currently only support all edges drawing. */ - if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true)) { + if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) { ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1); } return; @@ -2638,7 +2644,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes) int mat_nr = -1; bool draw_smooth = false; int start_draw_patch = -1, num_draw_patches = 0; - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL) == false)) { + if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) { return; } if (setMaterial == NULL) { @@ -2750,7 +2756,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, bool draw_smooth = false; int start_draw_patch = -1, num_draw_patches = 0; GPU_draw_update_fvar_offset(dm); - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false) == false)) { + if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) { return; } for (i = 0; i < num_base_faces; ++i) { @@ -3193,7 +3199,7 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm, int new_matnr; bool draw_smooth; GPU_draw_update_fvar_offset(dm); - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) { + if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) { return; } /* TODO(sergey): Single matierial currently. */ @@ -3386,19 +3392,6 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, int mat_index; int tot_element, start_element, tot_drawn; -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - if (ccgSubSurf_prepareGLMesh(ss, true) == false) { - return; - } - ccgSubSurf_drawGLMesh(ss, true, -1, -1); - return; - } -#endif - - CCG_key_top_level(&key, ss); - ccgdm_pbvh_update(ccgdm); - if (use_colors) { colType = CD_TEXTURE_MLOOPCOL; mloopcol = dm->getLoopDataArray(dm, colType); @@ -3412,6 +3405,87 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, } } +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV); + if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) { + return; + } + if (drawParams == NULL) { + ccgSubSurf_drawGLMesh(ss, true, -1, -1); + return; + } + const int level = ccgSubSurf_getSubdivisionLevels(ss); + const int face_side = 1 << level; + const int grid_side = 1 << (level - 1); + const int face_patches = face_side * face_side; + const int grid_patches = grid_side * grid_side; + const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); + int current_patch = 0; + int mat_nr = -1; + int start_draw_patch = 0, num_draw_patches = 0; + bool draw_smooth = false; + for (i = 0; i < num_base_faces; ++i) { + const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); + const int num_patches = (num_face_verts == 4) ? face_patches + : num_face_verts * grid_patches; + if (faceFlags) { + mat_nr = faceFlags[i].mat_nr; + draw_smooth = (faceFlags[i].flag & ME_SMOOTH); + } + else { + mat_nr = 0; + draw_smooth = false; + } + + if (drawParams != NULL) { + MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL; + draw_option = drawParams(tp, (mloopcol != NULL), mat_nr); + } + else { + draw_option = (drawParamsMapped) + ? drawParamsMapped(userData, i, mat_nr) + : DM_DRAW_OPTION_NORMAL; + } + + flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1); + + const int next_face = min_ii(i + 1, num_base_faces - 1); + if (!flush && compareDrawOptions) { + flush |= compareDrawOptions(userData, i, next_face) == 0; + } + if (!flush && faceFlags) { + bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH); + flush |= (new_draw_smooth != draw_smooth); + } + + current_patch += num_patches; + + if (flush) { + if (draw_option != DM_DRAW_OPTION_SKIP) { + num_draw_patches += num_patches; + } + if (num_draw_patches != 0) { + glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); + ccgSubSurf_drawGLMesh(ss, + true, + start_draw_patch, + num_draw_patches); + } + start_draw_patch = current_patch; + num_draw_patches = 0; + } + else { + num_draw_patches += num_patches; + } + } + return; + } +#endif + + CCG_key_top_level(&key, ss); + ccgdm_pbvh_update(ccgdm); + GPU_vertex_setup(dm); GPU_normal_setup(dm); GPU_triangle_setup(dm); @@ -3472,7 +3546,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, if (!flush && compareDrawOptions) { /* also compare draw options and flush buffer if they're different - * need for face selection highlight in edit mode */ + * need for face selection highlight in edit mode */ flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; } @@ -3581,7 +3655,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, */ glColor3f(0.8f, 0.8f, 0.8f); } - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) { + if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) { return; } if (faceFlags) { @@ -3780,7 +3854,7 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm, #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { /* TODO(sergey): Only draw edges from base mesh. */ - if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true)) { + if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) { if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) { ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1); } @@ -4970,7 +5044,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( #ifdef WITH_OPENSUBDIV ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend); #endif - ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple); + ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv); result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend); @@ -4985,7 +5059,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( ss = _getSubSurf(NULL, levels, 3, useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS); - ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); + ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, false); @@ -5016,7 +5090,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( if (useIncremental && (flags & SUBSURF_IS_FINAL_CALC)) { smd->mCache = ss = _getSubSurf(smd->mCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS); - ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); + ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, @@ -5056,7 +5130,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( #ifdef WITH_OPENSUBDIV ccgSubSurf_setSkipGrids(ss, use_gpu_backend); #endif - ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); + ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend); @@ -5085,7 +5159,7 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3]) CCGVertIterator vi; DerivedMesh *dm = CDDM_from_mesh(me); - ss_sync_from_derivedmesh(ss, dm, NULL, 0); + ss_sync_from_derivedmesh(ss, dm, NULL, 0, 0); for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { CCGVert *v = ccgVertIterator_getCurrent(&vi); diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 269d6d32b31..1636042f479 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -491,14 +491,16 @@ Text *BKE_text_copy(Main *bmain, Text *ta) init_undo_text(tan); - if (ID_IS_LINKED_DATABLOCK(ta)) { - BKE_id_expand_local(&tan->id); - BKE_id_lib_local_paths(bmain, ta->id.lib, &tan->id); - } + BKE_id_copy_ensure_local(bmain, &ta->id, &tan->id); return tan; } +void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &text->id, true, lib_local); +} + void BKE_text_clear(Text *text) /* called directly from rna */ { int oldstate; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index e34d632f2ca..2d3ecad19ad 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -863,7 +863,6 @@ Tex *BKE_texture_copy(Main *bmain, Tex *tex) if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd); if (texn->vd) texn->vd = MEM_dupallocN(texn->vd); if (texn->ot) texn->ot = BKE_texture_ocean_copy(texn->ot); - if (tex->preview) texn->preview = BKE_previewimg_copy(tex->preview); if (tex->nodetree) { if (tex->nodetree->execdata) { @@ -871,13 +870,10 @@ Tex *BKE_texture_copy(Main *bmain, Tex *tex) } texn->nodetree = ntreeCopyTree(bmain, tex->nodetree); } - - texn->preview = BKE_previewimg_copy(tex->preview); - if (ID_IS_LINKED_DATABLOCK(tex)) { - BKE_id_expand_local(&texn->id); - BKE_id_lib_local_paths(bmain, tex->id.lib, &texn->id); - } + BKE_previewimg_id_copy(&texn->id, &tex->id); + + BKE_id_copy_ensure_local(bmain, &tex->id, &texn->id); return texn; } @@ -918,34 +914,9 @@ Tex *BKE_texture_localize(Tex *tex) /* ------------------------------------------------------------------------- */ -void BKE_texture_make_local(Main *bmain, Tex *tex) +void BKE_texture_make_local(Main *bmain, Tex *tex, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(tex)) { - return; - } - - BKE_library_ID_test_usages(bmain, tex, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &tex->id); - BKE_id_expand_local(&tex->id); - } - else { - Tex *tex_new = BKE_texture_copy(bmain, tex); - - tex_new->id.us = 0; - - BKE_libblock_remap(bmain, tex, tex_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &tex->id, true, lib_local); } Tex *give_current_object_texture(Object *ob) diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index 9df30a8acc9..3b56ea271d0 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -376,6 +376,9 @@ bool BKE_autotrack_context_step(AutoTrackContext *context) #pragma omp parallel for if (context->num_tracks > 1) for (track = 0; track < context->num_tracks; ++track) { AutoTrackOptions *options = &context->options[track]; + if (options->is_failed) { + continue; + } libmv_Marker libmv_current_marker, libmv_reference_marker, libmv_tracked_marker; @@ -463,16 +466,25 @@ void BKE_autotrack_context_sync(AutoTrackContext *context) AutoTrackOptions *options = &context->options[track]; int track_frame = BKE_movieclip_remap_scene_to_clip_frame( context->clips[options->clip_index], frame); - if (options->is_failed && options->failed_frame == track_frame) { - MovieTrackingMarker *prev_marker = - BKE_tracking_marker_get_exact(options->track, frame); - if (prev_marker) { - marker = *prev_marker; - marker.framenr = context->backwards ? - track_frame - 1 : - track_frame + 1; - marker.flag |= MARKER_DISABLED; - BKE_tracking_marker_insert(options->track, &marker); + if (options->is_failed) { + if (options->failed_frame == track_frame) { + MovieTrackingMarker *prev_marker = + BKE_tracking_marker_get_exact( + options->track, + context->backwards + ? frame + 1 + : frame - 1); + if (prev_marker) { + marker = *prev_marker; + marker.framenr = track_frame; + marker.flag |= MARKER_DISABLED; + BKE_tracking_marker_insert(options->track, &marker); + continue; + } + } + if ((context->backwards && options->failed_frame > track_frame) || + (!context->backwards && options->failed_frame < track_frame)) + { continue; } } diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index a40e4f72636..a90b1dee927 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -762,8 +762,8 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, final_ibuf = IMB_dupImBuf(orig_ibuf); } IMB_scaleImBuf(final_ibuf, - ibuf->x / (1 << downscale), - ibuf->y / (1 << downscale)); + orig_ibuf->x / (1 << downscale), + orig_ibuf->y / (1 << downscale)); } if (transform != NULL) { @@ -780,7 +780,7 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, } if (input_mode == LIBMV_IMAGE_MODE_RGBA) { - BLI_assert(ibuf->channels == 3 || ibuf->channels == 4); + BLI_assert(orig_ibuf->channels == 3 || orig_ibuf->channels == 4); /* pass */ } else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ { diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 9795a8174f8..de1e3187a70 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -138,14 +138,11 @@ World *BKE_world_copy(Main *bmain, World *wrld) wrldn->nodetree = ntreeCopyTree(bmain, wrld->nodetree); } - wrldn->preview = BKE_previewimg_copy(wrld->preview); + BKE_previewimg_id_copy(&wrldn->id, &wrld->id); BLI_listbase_clear(&wrldn->gpumaterial); - if (ID_IS_LINKED_DATABLOCK(wrld)) { - BKE_id_expand_local(&wrldn->id); - BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrldn->id); - } + BKE_id_copy_ensure_local(bmain, &wrld->id, &wrldn->id); return wrldn; } @@ -176,32 +173,7 @@ World *localize_world(World *wrld) return wrldn; } -void BKE_world_make_local(Main *bmain, World *wrld) +void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - - if (!ID_IS_LINKED_DATABLOCK(wrld)) { - return; - } - - BKE_library_ID_test_usages(bmain, wrld, &is_local, &is_lib); - - if (is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &wrld->id); - BKE_id_expand_local(&wrld->id); - } - else { - World *wrld_new = BKE_world_copy(bmain, wrld); - - wrld_new->id.us = 0; - - BKE_libblock_remap(bmain, wrld, wrld_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } - } + BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local); } diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index edeccf472c8..9dbc045f1b0 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -1672,9 +1672,6 @@ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd) if (codec == AV_CODEC_ID_PNG) return true; - if (codec == AV_CODEC_ID_PNG) - return true; - if (codec == AV_CODEC_ID_HUFFYUV) return true; diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index b4a465bbc74..0b1b4d8ee8c 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -42,7 +42,7 @@ extern "C" { #endif /* for tables, button in UI, etc */ -#define BLENDER_MAX_THREADS 64 +#define BLENDER_MAX_THREADS 1024 struct ListBase; struct TaskScheduler; diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c index 4bd404e5d73..0a8dafc2dc1 100644 --- a/source/blender/blenlib/intern/BLI_heap.c +++ b/source/blender/blenlib/intern/BLI_heap.c @@ -32,7 +32,6 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_memarena.h" #include "BLI_heap.h" #include "BLI_strict_flags.h" @@ -44,15 +43,37 @@ struct HeapNode { unsigned int index; }; +struct HeapNode_Chunk { + struct HeapNode_Chunk *prev; + unsigned int size; + unsigned int bufsize; + struct HeapNode buf[0]; +}; + +/** + * Number of nodes to include per #HeapNode_Chunk when no reserved size is passed, + * or we allocate past the reserved number. + * + * \note Optimize number for 64kb allocs. + */ +#define HEAP_CHUNK_DEFAULT_NUM \ + ((MEM_SIZE_OPTIMAL((1 << 16) - sizeof(struct HeapNode_Chunk))) / sizeof(HeapNode)) + struct Heap { unsigned int size; unsigned int bufsize; - MemArena *arena; - HeapNode *freenodes; HeapNode **tree; + + struct { + /* Always keep at least one chunk (never NULL) */ + struct HeapNode_Chunk *chunk; + /* when NULL, allocate a new chunk */ + HeapNode *free; + } nodes; }; -/* internal functions */ +/** \name Internal Functions + * \{ */ #define HEAP_PARENT(i) (((i) - 1) >> 1) #define HEAP_LEFT(i) (((i) << 1) + 1) @@ -92,11 +113,13 @@ static void heap_down(Heap *heap, unsigned int i) smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i; - if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) + if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) { smallest = r; + } - if (smallest == i) + if (smallest == i) { break; + } heap_swap(heap, i, smallest); i = smallest; @@ -108,25 +131,73 @@ static void heap_up(Heap *heap, unsigned int i) while (i > 0) { const unsigned int p = HEAP_PARENT(i); - if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) + if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) { break; - + } heap_swap(heap, p, i); i = p; } } +/** \} */ -/***/ + +/** \name Internal Memory Management + * \{ */ + +static struct HeapNode_Chunk *heap_node_alloc_chunk( + unsigned int tot_nodes, struct HeapNode_Chunk *chunk_prev) +{ + struct HeapNode_Chunk *chunk = MEM_mallocN( + sizeof(struct HeapNode_Chunk) + (sizeof(HeapNode) * tot_nodes), __func__); + chunk->prev = chunk_prev; + chunk->bufsize = tot_nodes; + chunk->size = 0; + return chunk; +} + +static struct HeapNode *heap_node_alloc(Heap *heap) +{ + HeapNode *node; + + if (heap->nodes.free) { + node = heap->nodes.free; + heap->nodes.free = heap->nodes.free->ptr; + } + else { + struct HeapNode_Chunk *chunk = heap->nodes.chunk; + if (UNLIKELY(chunk->size == chunk->bufsize)) { + chunk = heap->nodes.chunk = heap_node_alloc_chunk(HEAP_CHUNK_DEFAULT_NUM, chunk); + } + node = &chunk->buf[chunk->size++]; + } + + return node; +} + +static void heap_node_free(Heap *heap, HeapNode *node) +{ + node->ptr = heap->nodes.free; + heap->nodes.free = node; +} + +/** \} */ + + +/** \name Public Heap API + * \{ */ /* use when the size of the heap is known in advance */ Heap *BLI_heap_new_ex(unsigned int tot_reserve) { - Heap *heap = (Heap *)MEM_callocN(sizeof(Heap), __func__); + Heap *heap = MEM_mallocN(sizeof(Heap), __func__); /* ensure we have at least one so we can keep doubling it */ + heap->size = 0; heap->bufsize = MAX2(1u, tot_reserve); - heap->tree = (HeapNode **)MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree"); - heap->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "heap arena"); + heap->tree = MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree"); + + heap->nodes.chunk = heap_node_alloc_chunk((tot_reserve > 1) ? tot_reserve : HEAP_CHUNK_DEFAULT_NUM, NULL); + heap->nodes.free = NULL; return heap; } @@ -146,8 +217,15 @@ void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) } } + struct HeapNode_Chunk *chunk = heap->nodes.chunk; + do { + struct HeapNode_Chunk *chunk_prev; + chunk_prev = chunk->prev; + MEM_freeN(chunk); + chunk = chunk_prev; + } while (chunk); + MEM_freeN(heap->tree); - BLI_memarena_free(heap->arena); MEM_freeN(heap); } @@ -160,10 +238,16 @@ void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ptrfreefp(heap->tree[i]->ptr); } } - heap->size = 0; - BLI_memarena_clear(heap->arena); - heap->freenodes = NULL; + + /* Remove all except the last chunk */ + while (heap->nodes.chunk->prev) { + struct HeapNode_Chunk *chunk_prev = heap->nodes.chunk->prev; + MEM_freeN(heap->nodes.chunk); + heap->nodes.chunk = chunk_prev; + } + heap->nodes.chunk->size = 0; + heap->nodes.free = NULL; } HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) @@ -175,13 +259,7 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) heap->tree = MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree)); } - if (heap->freenodes) { - node = heap->freenodes; - heap->freenodes = heap->freenodes->ptr; - } - else { - node = (HeapNode *)BLI_memarena_alloc(heap->arena, sizeof(*node)); - } + node = heap_node_alloc(heap); node->ptr = ptr; node->value = value; @@ -217,8 +295,7 @@ void *BLI_heap_popmin(Heap *heap) BLI_assert(heap->size != 0); - heap->tree[0]->ptr = heap->freenodes; - heap->freenodes = heap->tree[0]; + heap_node_free(heap, heap->tree[0]); if (--heap->size) { heap_swap(heap, 0, heap->size); @@ -254,3 +331,4 @@ void *BLI_heap_node_ptr(HeapNode *node) return node->ptr; } +/** \} */ diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 92f4e998206..b14007a88cb 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -1917,7 +1917,7 @@ static void dist_squared_ray_to_aabb_scaled_v3_precalc( } /* un-normalize ray */ if (ray_is_normalized && scale && - (data->scale[0] != 1.0f || data->scale[1] != 1.0f || data->scale[2] != 1.0f)) + (data->scale[0] != 1.0f || data->scale[1] != 1.0f || data->scale[2] != 1.0f)) { data->ray.direction[0] = ray_direction[0] * data->scale[0]; data->ray.direction[1] = ray_direction[1] * data->scale[1]; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2f7b1386a27..7fd08569984 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -115,7 +115,7 @@ #include "BKE_action.h" #include "BKE_armature.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_brush.h" #include "BKE_cloth.h" #include "BKE_constraint.h" @@ -1283,7 +1283,7 @@ void blo_freefiledata(FileData *fd) if (fd->filesdna) DNA_sdna_free(fd->filesdna); if (fd->compflags) - MEM_freeN(fd->compflags); + MEM_freeN((void *)fd->compflags); if (fd->datamap) oldnewmap_free(fd->datamap); @@ -2147,6 +2147,7 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p } prv->gputexture[i] = NULL; } + prv->icon_id = 0; } return prv; @@ -2718,7 +2719,7 @@ static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } -/* singe node tree (also used for material/scene trees), ntree is not NULL */ +/* Single node tree (also used for material/scene trees), ntree is not NULL */ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree) { bNode *node; @@ -2761,22 +2762,6 @@ static void lib_link_nodetree(FileData *fd, Main *main) } } -/* get node tree stored locally in other IDs */ -static bNodeTree *nodetree_from_id(ID *id) -{ - if (!id) - return NULL; - switch (GS(id->name)) { - case ID_SCE: return ((Scene *)id)->nodetree; - case ID_MA: return ((Material *)id)->nodetree; - case ID_WO: return ((World *)id)->nodetree; - case ID_LA: return ((Lamp *)id)->nodetree; - case ID_TE: return ((Tex *)id)->nodetree; - case ID_LS: return ((FreestyleLineStyle *)id)->nodetree; - } - return NULL; -} - /* updates group node socket identifier so that * external links to/from the group node are preserved. */ @@ -6355,11 +6340,9 @@ static void lib_link_screen(FileData *fd, Main *main) snode->id = newlibadr(fd, sc->id.lib, snode->id); snode->from = newlibadr(fd, sc->id.lib, snode->from); - ntree = nodetree_from_id(snode->id); - if (ntree) - snode->nodetree = ntree; - else { - snode->nodetree = newlibadr_us(fd, sc->id.lib, snode->nodetree); + if (snode->id) { + ntree = ntreeFromID(snode->id); + snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree); } for (path = snode->treepath.first; path; path = path->next) { @@ -6739,11 +6722,11 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL); snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE); - ntree = nodetree_from_id(snode->id); - if (ntree) - snode->nodetree = ntree; - else - snode->nodetree = restore_pointer_by_name(id_map, (ID*)snode->nodetree, USER_REAL); + if (snode->id) { + ntree = ntreeFromID(snode->id); + snode->nodetree = ntree ? ntree : + restore_pointer_by_name(id_map, (ID *)snode->nodetree, USER_REAL); + } for (path = snode->treepath.first; path; path = path->next) { if (path == snode->treepath.first) { diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index b054cd0031d..7719aaa2b0d 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -75,7 +75,7 @@ typedef struct FileData { // general reading variables struct SDNA *filesdna; const struct SDNA *memsdna; - char *compflags; /* array of eSDNA_StructCompare */ + const char *compflags; /* array of eSDNA_StructCompare */ int fileversion; int id_name_offs; /* used to retrieve ID names from (bhead+1) */ diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index b7b6ace3c1a..a254a854c66 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1194,8 +1194,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (camera->stereo.pole_merge_angle_from == 0.0f && camera->stereo.pole_merge_angle_to == 0.0f) { - camera->stereo.pole_merge_angle_from = DEG2RAD(60.0f); - camera->stereo.pole_merge_angle_to = DEG2RAD(75.0f); + camera->stereo.pole_merge_angle_from = DEG2RADF(60.0f); + camera->stereo.pole_merge_angle_to = DEG2RADF(75.0f); } } @@ -1212,5 +1212,24 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + if (!DNA_struct_elem_find(fd->filesdna, "BooleanModifierData", "float", "double_threshold")) { + Object *ob; + for (ob = main->object.first; ob; ob = ob->id.next) { + ModifierData *md; + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Boolean) { + BooleanModifierData *bmd = (BooleanModifierData *)md; + bmd->double_threshold = 1e-6f; + } + } + } + } + + for (Brush *br = main->brush.first; br; br = br->id.next) { + if (br->sculpt_tool == SCULPT_TOOL_FLATTEN) { + br->flag |= BRUSH_ACCUMULATE; + } + } } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index ad7a3c5b9c4..0ed7a397e0b 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -256,6 +256,11 @@ void BLO_update_defaults_startup_blend(Main *bmain) if (br) { br->alpha = 1.0f; } + + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Flatten/Contrast"); + if (br) { + br->flag |= BRUSH_ACCUMULATE; + } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index d949dcf48c7..903cae48858 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2275,7 +2275,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase) mesh->edit_btmesh = NULL; /* now fill in polys to mfaces */ - /* XXX This breaks writing desing, by using temp allocated memory, which will likely generate + /* XXX This breaks writing design, by using temp allocated memory, which will likely generate * duplicates in stored 'old' addresses. * This is very bad, but do not see easy way to avoid this, aside from generating those data * outside of save process itself. diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 13b6a3c13c5..c500d7b9ec2 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -48,31 +48,6 @@ #include "intern/bmesh_private.h" /** - * \brief TEST EDGE SIDE and POINT IN TRIANGLE - * - * Point in triangle tests stolen from scanfill.c. - * Used for tessellator - */ - -static bool testedgesidef(const float v1[2], const float v2[2], const float v3[2]) -{ - /* is v3 to the right of v1 - v2 ? With exception: v3 == v1 || v3 == v2 */ - double inp; - - //inp = (v2[cox] - v1[cox]) * (v1[coy] - v3[coy]) + (v1[coy] - v2[coy]) * (v1[cox] - v3[cox]); - inp = (v2[0] - v1[0]) * (v1[1] - v3[1]) + (v1[1] - v2[1]) * (v1[0] - v3[0]); - - if (inp < 0.0) { - return false; - } - else if (inp == 0) { - if (v1[0] == v3[0] && v1[1] == v3[1]) return false; - if (v2[0] == v3[0] && v2[1] == v3[1]) return false; - } - return true; -} - -/** * \brief COMPUTE POLY NORMAL (BMFace) * * Same as #normal_poly_v3 but operates directly on a bmesh face. @@ -603,29 +578,6 @@ void BM_face_calc_center_mean_weighted(const BMFace *f, float r_cent[3]) } /** - * \brief BM LEGAL EDGES - * - * takes in a face and a list of edges, and sets to NULL any edge in - * the list that bridges a concave region of the face or intersects - * any of the faces's edges. - */ -static void scale_edge_v2f(float v1[2], float v2[2], const float fac) -{ - float mid[2]; - - mid_v2_v2v2(mid, v1, v2); - - sub_v2_v2v2(v1, v1, mid); - sub_v2_v2v2(v2, v2, mid); - - mul_v2_fl(v1, fac); - mul_v2_fl(v2, fac); - - add_v2_v2v2(v1, v1, mid); - add_v2_v2v2(v2, v2, mid); -} - -/** * \brief POLY ROTATE PLANE * * Rotates a polygon so that it's @@ -910,67 +862,6 @@ void BM_face_normal_flip(BMesh *bm, BMFace *f) BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true); } -/* detects if two line segments cross each other (intersects). - * note, there could be more winding cases then there needs to be. */ -static bool line_crosses_v2f(const float v1[2], const float v2[2], const float v3[2], const float v4[2]) -{ - -#define GETMIN2_AXIS(a, b, ma, mb, axis) \ - { \ - ma[axis] = min_ff(a[axis], b[axis]); \ - mb[axis] = max_ff(a[axis], b[axis]); \ - } (void)0 - -#define GETMIN2(a, b, ma, mb) \ - { \ - GETMIN2_AXIS(a, b, ma, mb, 0); \ - GETMIN2_AXIS(a, b, ma, mb, 1); \ - } (void)0 - -#define EPS (FLT_EPSILON * 15) - - int w1, w2, w3, w4, w5 /*, re */; - float mv1[2], mv2[2], mv3[2], mv4[2]; - - /* now test winding */ - w1 = testedgesidef(v1, v3, v2); - w2 = testedgesidef(v2, v4, v1); - w3 = !testedgesidef(v1, v2, v3); - w4 = testedgesidef(v3, v2, v4); - w5 = !testedgesidef(v3, v1, v4); - - if (w1 == w2 && w2 == w3 && w3 == w4 && w4 == w5) { - return true; - } - - GETMIN2(v1, v2, mv1, mv2); - GETMIN2(v3, v4, mv3, mv4); - - /* do an interval test on the x and y axes */ - /* first do x axis */ - if (fabsf(v1[1] - v2[1]) < EPS && - fabsf(v3[1] - v4[1]) < EPS && - fabsf(v1[1] - v3[1]) < EPS) - { - return (mv4[0] >= mv1[0] && mv3[0] <= mv2[0]); - } - - /* now do y axis */ - if (fabsf(v1[0] - v2[0]) < EPS && - fabsf(v3[0] - v4[0]) < EPS && - fabsf(v1[0] - v3[0]) < EPS) - { - return (mv4[1] >= mv1[1] && mv3[1] <= mv2[1]); - } - - return false; - -#undef GETMIN2_AXIS -#undef GETMIN2 -#undef EPS - -} - /** * BM POINT IN FACE * @@ -1268,121 +1159,103 @@ void BM_face_triangulate( */ void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) { - const int len2 = len * 2; - BMLoop *l; - float v1[2], v2[2], v3[2], mid[2], *p1, *p2, *p3, *p4; float out[2] = {-FLT_MAX, -FLT_MAX}; + float center[2] = {0.0f, 0.0f}; float axis_mat[3][3]; float (*projverts)[2] = BLI_array_alloca(projverts, f->len); - float (*edgeverts)[2] = BLI_array_alloca(edgeverts, len2); - float fac1 = 1.0000001f, fac2 = 0.9f; //9999f; //0.999f; - int i, j, a = 0, clen; + const float *(*edgeverts)[2] = BLI_array_alloca(edgeverts, len); + BMLoop *l; + int i, i_prev, j; BLI_assert(BM_face_is_normal_valid(f)); axis_dominant_v3_to_m3(axis_mat, f->no); for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) { - BM_elem_index_set(l, i); /* set_dirty */ mul_v2_m3v3(projverts[i], axis_mat, l->v->co); + add_v2_v2(center, projverts[i]); } - bm->elem_index_dirty |= BM_LOOP; /* first test for completely convex face */ if (is_poly_convex_v2((const float (*)[2])projverts, f->len)) { return; } + mul_v2_fl(center, 1.0f / f->len); + for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) { + BM_elem_index_set(l, i); /* set_dirty */ + + /* center the projection for maximum accuracy */ + sub_v2_v2(projverts[i], center); + out[0] = max_ff(out[0], projverts[i][0]); out[1] = max_ff(out[1], projverts[i][1]); } + bm->elem_index_dirty |= BM_LOOP; /* ensure we are well outside the face bounds (value is arbitrary) */ add_v2_fl(out, 1.0f); for (i = 0; i < len; i++) { - copy_v2_v2(edgeverts[a + 0], projverts[BM_elem_index_get(loops[i][0])]); - copy_v2_v2(edgeverts[a + 1], projverts[BM_elem_index_get(loops[i][1])]); - scale_edge_v2f(edgeverts[a + 0], edgeverts[a + 1], fac2); - a += 2; + edgeverts[i][0] = projverts[BM_elem_index_get(loops[i][0])]; + edgeverts[i][1] = projverts[BM_elem_index_get(loops[i][1])]; } /* do convexity test */ for (i = 0; i < len; i++) { - copy_v2_v2(v2, edgeverts[i * 2 + 0]); - copy_v2_v2(v3, edgeverts[i * 2 + 1]); - - mid_v2_v2v2(mid, v2, v3); + float mid[2]; + mid_v2_v2v2(mid, edgeverts[i][0], edgeverts[i][1]); - clen = 0; - for (j = 0; j < f->len; j++) { - p1 = projverts[j]; - p2 = projverts[(j + 1) % f->len]; - -#if 0 - copy_v2_v2(v1, p1); - copy_v2_v2(v2, p2); - - scale_edge_v2f(v1, v2, fac1); - if (line_crosses_v2f(v1, v2, mid, out)) { - clen++; + int isect = 0; + int j_prev; + for (j = 0, j_prev = f->len - 1; j < f->len; j_prev = j++) { + const float *f_edge[2] = {projverts[j_prev], projverts[j]}; + if (isect_seg_seg_v2(UNPACK2(f_edge), mid, out) == ISECT_LINE_LINE_CROSS) { + isect++; } -#else - if (line_crosses_v2f(p1, p2, mid, out)) { - clen++; - } -#endif } - if (clen % 2 == 0) { + if (isect % 2 == 0) { loops[i][0] = NULL; } } - /* do line crossing tests */ - for (i = 0; i < f->len; i++) { - p1 = projverts[i]; - p2 = projverts[(i + 1) % f->len]; - - copy_v2_v2(v1, p1); - copy_v2_v2(v2, p2); - - scale_edge_v2f(v1, v2, fac1); +#define EDGE_SHARE_VERT(e1, e2) \ + ((ELEM((e1)[0], (e2)[0], (e2)[1])) || \ + (ELEM((e1)[1], (e2)[0], (e2)[1]))) + /* do line crossing tests */ + for (i = 0, i_prev = f->len - 1; i < f->len; i_prev = i++) { + const float *f_edge[2] = {projverts[i_prev], projverts[i]}; for (j = 0; j < len; j++) { - if (!loops[j][0]) { - continue; - } - - p3 = edgeverts[j * 2]; - p4 = edgeverts[j * 2 + 1]; - - if (line_crosses_v2f(v1, v2, p3, p4)) { - loops[j][0] = NULL; + if ((loops[j][0] != NULL) && + !EDGE_SHARE_VERT(f_edge, edgeverts[j])) + { + if (isect_seg_seg_v2(UNPACK2(f_edge), UNPACK2(edgeverts[j])) == ISECT_LINE_LINE_CROSS) { + loops[j][0] = NULL; + } } } } + /* self intersect tests */ for (i = 0; i < len; i++) { - for (j = 0; j < len; j++) { - if (j != i && loops[i][0] && loops[j][0]) { - p1 = edgeverts[i * 2]; - p2 = edgeverts[i * 2 + 1]; - p3 = edgeverts[j * 2]; - p4 = edgeverts[j * 2 + 1]; - - copy_v2_v2(v1, p1); - copy_v2_v2(v2, p2); - - scale_edge_v2f(v1, v2, fac1); - - if (line_crosses_v2f(v1, v2, p3, p4)) { - loops[i][0] = NULL; + if (loops[i][0]) { + for (j = i + 1; j < len; j++) { + if ((loops[j][0] != NULL) && + !EDGE_SHARE_VERT(edgeverts[i], edgeverts[j])) + { + if (isect_seg_seg_v2(UNPACK2(edgeverts[i]), UNPACK2(edgeverts[j])) == ISECT_LINE_LINE_CROSS) { + loops[i][0] = NULL; + break; + } } } } } + +#undef EDGE_SHARE_VERT } /** diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c index 9b3e1d38feb..b8acc9d09b8 100644 --- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c +++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c @@ -63,7 +63,7 @@ static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const f return delta_z; } -static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle) +static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle_cos) { BMLoop *l_iter, *l_first; BMLoop **l_arr = BLI_array_alloca(l_arr, f->len); @@ -73,7 +73,7 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r /* angle finding */ float err_best = FLT_MAX; - float angle_best = FLT_MAX; + float angle_best_cos = -FLT_MAX; l_iter = l_first = BM_FACE_FIRST_LOOP(f); i_a = 0; @@ -108,7 +108,7 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r l_pair[0] = l_a; l_pair[1] = l_b; - angle_best = angle_normalized_v3v3(no_a, no_b); + angle_best_cos = dot_v3v3(no_a, no_b); found = true; } } @@ -117,17 +117,17 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r } } - *r_angle = angle_best; + *r_angle_cos = angle_best_cos; return found; } -static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit) +static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit_cos) { BMLoop *l_pair[2]; - float angle; + float angle_cos; - if (bm_face_split_find(bm, f, l_pair, &angle) && (angle > angle_limit)) { + if (bm_face_split_find(bm, f, l_pair, &angle_cos) && (angle_cos < angle_limit_cos)) { BMFace *f_new; BMLoop *l_new; @@ -154,7 +154,7 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op) bool changed = false; BLI_LINKSTACK_DECLARE(fstack, BMFace *); - const float angle_limit = BMO_slot_float_get(op->slots_in, "angle_limit"); + const float angle_limit_cos = cosf(BMO_slot_float_get(op->slots_in, "angle_limit")); BLI_LINKSTACK_INIT(fstack); @@ -166,7 +166,7 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op) while ((f = BLI_LINKSTACK_POP(fstack))) { BMFace *f_pair[2]; - if (bm_face_split_by_angle(bm, f, f_pair, angle_limit)) { + if (bm_face_split_by_angle(bm, f, f_pair, angle_limit_cos)) { int j; for (j = 0; j < 2; j++) { BM_face_normal_update(f_pair[j]); diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index 3eb6fe0cb97..05322a570a7 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -124,8 +124,8 @@ typedef struct PathLinkState { } PathLinkState; /** - \name Min Dist Dir Util - + * \name Min Dist Dir Util + * * Simply getting the closest intersecting vert/edge is _not_ good enough. see T43792 * we need to get the closest in both directions since the absolute closest may be a dead-end. * diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index f0738303d5c..73dbee25be3 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -86,7 +86,7 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f int f_start_index; int i; - /* Search for the best loop. Members are comapred in-order defined here. */ + /* Search for the best loop. Members are compared in-order defined here. */ struct { /* Squared distance from the center to the loops vertex 'l->v'. * The normalized direction between the center and this vertex is also used for the dot-products below. */ diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index b4a77bf1a38..ce031e1c230 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -1099,7 +1099,8 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) BMFace *f; BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (!BMO_face_flag_test(bm, f, FACE_OUT)) { + /* could support ngons, other areas would need updating too, see T48926. */ + if ((f->len <= 4) && !BMO_face_flag_test(bm, f, FACE_OUT)) { BMIter liter; BMLoop *l; bool ok = false; diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 4dc1c8a9f00..b647f5a667d 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1648,9 +1648,11 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr } } -/* Special case of build_boundary when a single edge is beveled. - * The 'width adjust' part of build_boundary has been done already, and - * efirst is the first beveled edge at vertex bv. */ +/** + * Special case of build_boundary when a single edge is beveled. + * The 'width adjust' part of build_boundary has been done already, + * and \a efirst is the first beveled edge at vertex \a bv. +*/ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct) { MemArena *mem_arena = bp->mem_arena; diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index f06f299d381..226f319cefd 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -904,6 +904,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia i++; } } + // EMISSION // color if (ef->getEmission().isColor()) { @@ -919,8 +920,22 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia i++; } } - - if (ef->getOpacity().isTexture()) { + + // TRANSPARENT + // color + if (ef->getOpacity().isColor()) { + col = ef->getTransparent().getColor(); + float alpha = ef->getTransparency().getFloatValue(); + if (col.isValid()) { + alpha *= col.getAlpha(); // Assuming A_ONE opaque mode + } + if (col.isValid() || alpha < 1.0) { + ma->alpha = alpha; + ma->mode |= MA_ZTRANSP | MA_TRANSP; + } + } + // texture + else if (ef->getOpacity().isTexture()) { COLLADAFW::Texture ctex = ef->getOpacity().getTexture(); mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); if (mtex != NULL) { @@ -930,22 +945,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia ma->mode |= MA_ZTRANSP | MA_TRANSP; } } - // TRANSPARENT - // color -#if 0 - if (ef->getOpacity().isColor()) { - // XXX don't know what to do here - } - // texture - else if (ef->getOpacity().isTexture()) { - ctex = ef->getOpacity().getTexture(); - if (mtex != NULL) mtex->mapto &= MAP_ALPHA; - else { - mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); - if (mtex != NULL) mtex->mapto = MAP_ALPHA; - } - } -#endif + material_texture_mapping_map[ma] = texindex_texarray_map; } diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index 13dc1eda580..76b51148509 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -30,6 +30,7 @@ #include <set> #include "COLLADASWEffectProfile.h" +#include "COLLADAFWColorOrTexture.h" #include "EffectExporter.h" #include "DocumentExporter.h" @@ -217,9 +218,9 @@ void EffectsExporter::operator()(Material *ma, Object *ob) // transparency if (ma->mode & MA_TRANSP) { // Tod: because we are in A_ONE mode transparency is calculated like this: - ep.setTransparency(ma->alpha, false, "transparency"); - // cot = getcol(1.0f, 1.0f, 1.0f, 1.0f); - // ep.setTransparent(cot); + cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha); + ep.setTransparent(cot); + ep.setOpaque(COLLADASW::EffectProfile::A_ONE); } // emission diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp index b271604f839..98aa85f8a9b 100644 --- a/source/blender/collada/ErrorHandler.cpp +++ b/source/blender/collada/ErrorHandler.cpp @@ -79,7 +79,7 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error) COLLADASaxFWL::SaxFWLError *saxFWLError = (COLLADASaxFWL::SaxFWLError *) error; /* * Accept non critical errors as warnings (i.e. texture not found) - * This makes the importer more gracefull, so it now imports what makes sense. + * This makes the importer more graceful, so it now imports what makes sense. */ if (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL) { isError = false; diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index 649c86edd25..abe5130b9c1 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -539,8 +539,8 @@ void BoneExtended::set_bone_layers(std::string layerString, std::vector<std::str } /* If numeric layers and labeled layers are used in parallel (unlikely), - we get a potential mixup. Just leave as is for now. - */ + * we get a potential mixup. Just leave as is for now. + */ this->bone_layers = bc_set_layer(this->bone_layers, pos); } diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp index d6e5fdf86bb..caafdfe8f0c 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.cpp +++ b/source/blender/compositor/operations/COM_MaskOperation.cpp @@ -1,5 +1,4 @@ /* - * Copyright 2012, Blender Foundation. * * This program is free software; you can redistribute it and/or diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 2d67ef1d584..a397b48e19c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -296,15 +296,16 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) for (Base *base = (Base *)scene->base.first; base; base = base->next) { Object *ob = base->object; + /* object itself */ + build_object(scene, base, ob); + /* object that this is a proxy for */ // XXX: the way that proxies work needs to be completely reviewed! if (ob->proxy) { ob->proxy->proxy_from = ob; + build_object(scene, base, ob->proxy); } - /* object itself */ - build_object(scene, base, ob); - /* Object dupligroup. */ if (ob->dup_group) { build_group(scene, base, ob->dup_group); @@ -397,12 +398,12 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) { if (ob->id.tag & LIB_TAG_DOIT) { IDDepsNode *id_node = m_graph->find_id_node(&ob->id); - id_node->layers = base->lay; + id_node->layers |= base->lay; return; } IDDepsNode *id_node = add_id_node(&ob->id); - id_node->layers = base->lay; + id_node->layers |= base->lay; ob->customdata_mask = 0; /* standard components */ @@ -441,7 +442,7 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) } case OB_ARMATURE: /* Pose */ - if (ob->id.lib != NULL && ob->proxy_from != NULL) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) { build_proxy_rig(ob); } else { @@ -485,12 +486,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) if (ob->gpd) { build_gpencil(ob->gpd); } - - if (ob->proxy != NULL) { - add_operation_node(&ob->id, DEPSNODE_TYPE_PROXY, DEPSOP_TYPE_POST, - function_bind(BKE_object_eval_proxy_backlink, _1, ob), - DEG_OPCODE_PLACEHOLDER, "Parameters Eval"); - } } void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 34c661b21f3..42b8260c05a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -266,18 +266,12 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) for (Base *base = (Base *)scene->base.first; base; base = base->next) { Object *ob = base->object; - /* Object that this is a proxy for. - * Just makes sure backlink is correct. - */ - if (ob->proxy) { - ob->proxy->proxy_from = ob; - } - /* object itself */ build_object(bmain, scene, ob); /* object that this is a proxy for */ if (ob->proxy) { + ob->proxy->proxy_from = ob; build_object(bmain, scene, ob->proxy); /* TODO(sergey): This is an inverted relation, matches old depsgraph * behavior and need to be investigated if it still need to be inverted. @@ -441,7 +435,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o } case OB_ARMATURE: /* Pose */ - if (ob->id.lib != NULL && ob->proxy_from != NULL) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) { build_proxy_rig(ob); } else { @@ -926,6 +920,12 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } } else { + if (dtar->id == id) { + /* Ignore input dependency if we're driving properties of the same ID, + * otherwise we'll be ending up in a cyclic dependency here. + */ + continue; + } /* resolve path to get node */ RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : ""); add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[RNA Target -> Driver]"); diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 9ba0b61a4f1..f9e1504b3ce 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -85,9 +85,6 @@ static void flush_init_func(void *data_v, int i) id_node->done = 0; comp_node->done = 0; node->scheduled = false; - if (comp_node->type == DEPSNODE_TYPE_PROXY) { - node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - } } /* Flush updates from tagged nodes outwards until all affected nodes diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index 12d5ee00a63..db807d22b89 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -181,6 +181,11 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata)) this->layers = (1 << 20) - 1; this->eval_flags = 0; + /* For object we initialize layers to layer from base. */ + if (GS(id) == ID_OB) { + this->layers = 0; + } + components = BLI_ghash_new(id_deps_node_hash_key, id_deps_node_hash_key_cmp, "Depsgraph id components hash"); diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 6306926e0b2..6979a324b69 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -424,7 +424,9 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone for (curBone = bones->first; curBone; curBone = curBone->next) { eBone = MEM_callocN(sizeof(EditBone), "make_editbone"); - /* Copy relevant data from bone to eBone */ + /* Copy relevant data from bone to eBone + * Keep selection logic in sync with ED_armature_sync_selection. + */ eBone->parent = parent; BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name)); eBone->flag = curBone->flag; @@ -435,11 +437,11 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone eBone->flag |= BONE_TIPSEL; if (eBone->parent && (eBone->flag & BONE_CONNECTED)) { eBone->parent->flag |= BONE_TIPSEL; - eBone->flag &= ~BONE_ROOTSEL; /* this is ignored when there is a connected parent, so unset it */ - } - else { - eBone->flag |= BONE_ROOTSEL; } + + /* For connected bones, take care when changing the selection when we have a connected parent, + * this flag is a copy of '(eBone->parent->flag & BONE_TIPSEL)'. */ + eBone->flag |= BONE_ROOTSEL; } else { /* if the bone is not selected, but connected to its parent diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 72b48a32477..e40dde24ce2 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -5843,7 +5843,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op)) normalize_v3(tan_r); curve_fit_cubic_to_points_single_fl( - points, points_len, dims, FLT_EPSILON, + points, points_len, NULL, dims, FLT_EPSILON, tan_l, tan_r, bezt_prev->vec[2], bezt_next->vec[0], &error_sq_dummy); diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 38018541929..4d0a2fa53cd 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -55,6 +55,8 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" + #define USE_SPLINE_FIT #ifdef USE_SPLINE_FIT @@ -65,6 +67,9 @@ #define STROKE_SAMPLE_DIST_MIN_PX 3 #define STROKE_SAMPLE_DIST_MAX_PX 6 +/* Distance between start/end points to consider cyclic */ +#define STROKE_CYCLIC_DIST_PX 8 + /* -------------------------------------------------------------------- */ @@ -730,6 +735,11 @@ static void curve_draw_exec_precalc(wmOperator *op) const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings; PropertyRNA *prop; + prop = RNA_struct_find_property(op->ptr, "fit_method"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, cps->fit_method); + } + prop = RNA_struct_find_property(op->ptr, "corner_angle"); if (!RNA_property_is_set(op->ptr, prop)) { const float corner_angle = (cps->flag & CURVE_PAINT_FLAG_CORNERS_DETECT) ? cps->corner_angle : (float)M_PI; @@ -759,6 +769,32 @@ static void curve_draw_exec_precalc(wmOperator *op) RNA_property_float_set(op->ptr, prop, error_threshold); } + prop = RNA_struct_find_property(op->ptr, "use_cyclic"); + if (!RNA_property_is_set(op->ptr, prop)) { + bool use_cyclic = false; + + if (BLI_mempool_count(cdd->stroke_elem_pool) > 2) { + BLI_mempool_iter iter; + const struct StrokeElem *selem, *selem_first, *selem_last; + + BLI_mempool_iternew(cdd->stroke_elem_pool, &iter); + selem_first = BLI_mempool_iterstep(&iter); + for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) { + selem_last = selem; + } + + if (len_squared_v2v2( + selem_first->mval, + selem_last->mval) <= SQUARE(STROKE_CYCLIC_DIST_PX * U.pixelsize)) + { + use_cyclic = true; + } + } + + RNA_property_boolean_set(op->ptr, prop, use_cyclic); + } + + if ((cps->radius_taper_start != 0.0f) || (cps->radius_taper_end != 0.0f)) { @@ -868,8 +904,10 @@ static int curve_draw_exec(bContext *C, wmOperator *op) unsigned int cubic_spline_len = 0; /* error in object local space */ + const int fit_method = RNA_enum_get(op->ptr, "fit_method"); const float error_threshold = RNA_float_get(op->ptr, "error_threshold"); const float corner_angle = RNA_float_get(op->ptr, "corner_angle"); + const bool use_cyclic = RNA_boolean_get(op->ptr, "use_cyclic"); { BLI_mempool_iter iter; @@ -894,14 +932,14 @@ static int curve_draw_exec(bContext *C, wmOperator *op) unsigned int *corners = NULL; unsigned int corners_len = 0; - if (corner_angle < (float)M_PI) { + if ((fit_method == CURVE_PAINT_FIT_METHOD_SPLIT) && (corner_angle < (float)M_PI)) { /* this could be configurable... */ const float corner_radius_min = error_threshold / 8; const float corner_radius_max = error_threshold * 2; const unsigned int samples_max = 16; curve_fit_corners_detect_fl( - (const float *)coords, stroke_len, dims, + coords, stroke_len, dims, corner_radius_min, corner_radius_max, samples_max, corner_angle, &corners, &corners_len); @@ -909,13 +947,29 @@ static int curve_draw_exec(bContext *C, wmOperator *op) unsigned int *corners_index = NULL; unsigned int corners_index_len = 0; + unsigned int calc_flag = CURVE_FIT_CALC_HIGH_QUALIY; - const int result = curve_fit_cubic_to_points_fl( - coords, stroke_len, dims, error_threshold, CURVE_FIT_CALC_HIGH_QUALIY, - corners, corners_len, - &cubic_spline, &cubic_spline_len, - NULL, - &corners_index, &corners_index_len); + if ((stroke_len > 2) && use_cyclic) { + calc_flag |= CURVE_FIT_CALC_CYCLIC; + } + + int result; + if (fit_method == CURVE_PAINT_FIT_METHOD_REFIT) { + result = curve_fit_cubic_to_points_refit_fl( + coords, stroke_len, dims, error_threshold, calc_flag, + NULL, 0, corner_angle, + &cubic_spline, &cubic_spline_len, + NULL, + &corners_index, &corners_index_len); + } + else { + result = curve_fit_cubic_to_points_fl( + coords, stroke_len, dims, error_threshold, calc_flag, + corners, corners_len, + &cubic_spline, &cubic_spline_len, + NULL, + &corners_index, &corners_index_len); + } MEM_freeN(coords); if (corners) { @@ -950,11 +1004,24 @@ static int curve_draw_exec(bContext *C, wmOperator *op) if (corners_index) { /* ignore the first and last */ - for (unsigned int i = 1; i < corners_index_len - 1; i++) { + unsigned int i_start = 0, i_end = corners_index_len; + + if ((corners_index_len >= 2) && + (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0) + { + i_start += 1; + i_end -= 1; + } + + for (unsigned int i = i_start; i < i_end; i++) { bezt = &nu->bezt[corners_index[i]]; bezt->h1 = bezt->h2 = HD_FREE; } } + + if (calc_flag & CURVE_FIT_CALC_CYCLIC) { + nu->flagu |= CU_NURB_CYCLIC; + } } if (corners_index) { @@ -1220,13 +1287,19 @@ void CURVE_OT_draw(wmOperatorType *ot) 0.0001f, 10.0f); RNA_def_property_ui_range(prop, 0.0, 10, 1, 4); + RNA_def_enum(ot->srna, "fit_method", rna_enum_curve_fit_method_items, CURVE_PAINT_FIT_METHOD_REFIT, + "Fit Method", ""); + prop = RNA_def_float_distance( ot->srna, "corner_angle", DEG2RADF(70.0f), 0.0f, M_PI, "Corner Angle", "", 0.0f, M_PI); RNA_def_property_subtype(prop, PROP_ANGLE); - prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); + prop = RNA_def_boolean(ot->srna, "use_cyclic", true, "Cyclic", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index a29266294b4..cad70443657 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -294,11 +294,11 @@ static void select_adjacent_cp( if (next < 0) bezt = &nu->bezt[a - 1]; while (a--) { if (a - abs(next) < 0) break; - if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) { + if ((lastsel == false) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) { bezt += next; if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) { - short sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE); - if ((sel == 1) && (cont == 0)) lastsel = true; + bool sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE); + if (sel && !cont) lastsel = true; } } else { @@ -315,11 +315,11 @@ static void select_adjacent_cp( if (next < 0) bp = &nu->bp[a - 1]; while (a--) { if (a - abs(next) < 0) break; - if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) { + if ((lastsel == false) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) { bp += next; if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) { - short sel = select_bpoint(bp, selstatus, SELECT, VISIBLE); - if ((sel == 1) && (cont == 0)) lastsel = true; + bool sel = select_bpoint(bp, selstatus, SELECT, VISIBLE); + if (sel && !cont) lastsel = true; } } else { @@ -820,7 +820,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) BezTriple *bezt; int a; int sel = 0; - short lastsel = false; + bool lastsel = false; if (obedit->type == OB_SURF) { for (nu = editnurb->first; nu; nu = nu->next) { @@ -935,9 +935,8 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a--) { - if ((lastsel == 0) && (bp->hide == 0) && (bp->f1 & SELECT)) { - if (lastsel != 0) sel = 1; - else sel = 0; + if ((lastsel == false) && (bp->hide == 0) && (bp->f1 & SELECT)) { + sel = 0; /* first and last are exceptions */ if (a == nu->pntsu * nu->pntsv - 1) { diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 053a7ee5023..b40b51e337f 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1695,7 +1695,7 @@ static int font_open_exec(bContext *C, wmOperator *op) if (pprop->prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer use also increases user, so this compensates it */ id_us_min(&font->id); RNA_id_pointer_create(&font->id, &idptr); diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 81e2558e765..602e203a381 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -325,18 +325,18 @@ bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool /* Notes: * - All the defines for this (User-Pref settings and Per-Scene settings) * are defined in DNA_userdef_types.h - * - Scene settings take presidence over those for userprefs, with old files + * - Scene settings take precedence over those for userprefs, with old files * inheriting userpref settings for the scene settings * - "On/Off + Mode" are stored per Scene, but "settings" are currently stored * as userprefs */ /* Auto-Keying macros for use by various tools */ -/* check if auto-keyframing is enabled (per scene takes presidence) */ +/* check if auto-keyframing is enabled (per scene takes precedence) */ #define IS_AUTOKEY_ON(scene) ((scene) ? (scene->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON)) -/* check the mode for auto-keyframing (per scene takes presidence) */ +/* check the mode for auto-keyframing (per scene takes precedence) */ #define IS_AUTOKEY_MODE(scene, mode) ((scene) ? (scene->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : (U.autokey_mode == AUTOKEY_MODE_##mode)) -/* check if a flag is set for auto-keyframing (per scene takes presidence) */ +/* check if a flag is set for auto-keyframing (per scene takes precedence) */ #define IS_AUTOKEY_FLAG(scene, flag) \ ((scene) ? \ ((scene->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || (U.autokey_flag & AUTOKEY_FLAG_##flag)) \ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index b09284aa759..48c1e2d1996 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -208,6 +208,7 @@ eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const fl eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip); +bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]); bool ED_view3d_win_to_ray( const struct ARegion *ar, const struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3], const bool do_clip); @@ -218,6 +219,7 @@ void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coo void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]); void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]); void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac); +void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]); void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]); bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index ba7240be5d8..cbe8654ceb6 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1138,7 +1138,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, * as new items are added to the menu later on. It also optimises efficiency - * a radial menu is best kept symmetrical, with as large an angle between * items as possible, so that the gestural mouse movements can be fast and inexact. - + * * It starts off with two opposite sides for the first two items * then joined by the one below for the third (this way, even with three items, * the menu seems to still be 'in order' reading left to right). Then the fourth is diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 72a6a04feec..9ce863dc8f7 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -734,24 +734,50 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), CLAMP(max, rect.ymin, rect.ymax); fdrawline(rect.xmax - 3, min, rect.xmax - 3, max); } + /* RGB (3 channel) */ + else if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB) { + glBlendFunc(GL_ONE, GL_ONE); + + glEnableClientState(GL_VERTEX_ARRAY); + + glPushMatrix(); + + glTranslatef(rect.xmin, yofs, 0.f); + glScalef(w, h, 0.f); + + glColor3fv( colors_alpha[0] ); + glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1); + glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); + + glColor3fv( colors_alpha[1] ); + glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2); + glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - /* RGB / YCC (3 channels) */ + glColor3fv( colors_alpha[2] ); + glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3); + glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); + + glDisableClientState(GL_VERTEX_ARRAY); + glPopMatrix(); + } + /* PARADE / YCC (3 channels) */ else if (ELEM(scopes->wavefrm_mode, - SCOPES_WAVEFRM_RGB, + SCOPES_WAVEFRM_RGB_PARADE, SCOPES_WAVEFRM_YCC_601, SCOPES_WAVEFRM_YCC_709, - SCOPES_WAVEFRM_YCC_JPEG)) + SCOPES_WAVEFRM_YCC_JPEG + )) { - int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB); - + int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB_PARADE); + glBlendFunc(GL_ONE, GL_ONE); - + glPushMatrix(); glEnableClientState(GL_VERTEX_ARRAY); - + glTranslatef(rect.xmin, yofs, 0.f); glScalef(w3, h, 0.f); - + glColor3fv((rgb) ? colors_alpha[0] : colorsycc_alpha[0]); glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1); glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); @@ -760,19 +786,19 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), glColor3fv((rgb) ? colors_alpha[1] : colorsycc_alpha[1]); glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2); glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - + glTranslatef(1.f, 0.f, 0.f); glColor3fv((rgb) ? colors_alpha[2] : colorsycc_alpha[2]); glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3); glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - + glDisableClientState(GL_VERTEX_ARRAY); glPopMatrix(); - - - /* min max */ + } + /* min max */ + if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA ) { for (int c = 0; c < 3; c++) { - if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB) + if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_RGB_PARADE, SCOPES_WAVEFRM_RGB)) glColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f); else glColor3f(colorsycc[c][0] * 0.75f, colorsycc[c][1] * 0.75f, colorsycc[c][2] * 0.75f); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 0a0ecf93d17..11703208b2a 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1057,7 +1057,9 @@ static void ui_multibut_free(uiHandleButtonData *data, uiBlock *block) } } -static bool ui_multibut_states_tag(uiBut *but_active, uiHandleButtonData *data, const wmEvent *event) +static bool ui_multibut_states_tag( + uiBut *but_active, + uiHandleButtonData *data, const wmEvent *event) { uiBut *but; float seg[2][2]; @@ -1668,7 +1670,9 @@ static bool ui_but_contains_point_px_icon(uiBut *but, ARegion *ar, const wmEvent return BLI_rcti_isect_pt(&rect, x, y); } -static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static bool ui_but_drag_init( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { /* prevent other WM gestures to start while we try to drag */ WM_gestures_remove(C); @@ -1740,11 +1744,16 @@ static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, } } else { - wmDrag *drag; + wmDrag *drag = WM_event_start_drag( + C, but->icon, but->dragtype, but->dragpoin, + ui_but_value_get(but), WM_DRAG_NOP); - drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_but_value_get(but), WM_DRAG_NOP); - if (but->imb) - WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect)); + if (but->imb) { + WM_event_drag_image( + drag, but->imb, but->imb_scale, + BLI_rctf_size_x(&but->rect), + BLI_rctf_size_y(&but->rect)); + } } return true; } @@ -1872,11 +1881,15 @@ static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to) /* (3) add a new controller */ if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, &props_ptr) & OPERATOR_FINISHED) { cont = (bController *)ob->controllers.last; - cont->type = CONT_LOGIC_AND; /* Quick fix to make sure we always have an AND controller. It might be nicer to make sure the operator gives us the right one though... */ + /* Quick fix to make sure we always have an AND controller. + * It might be nicer to make sure the operator gives us the right one though... */ + cont->type = CONT_LOGIC_AND; /* (4) link the sensor->controller->actuator */ tmp_but = MEM_callocN(sizeof(uiBut), "uiBut"); - UI_but_link_set(tmp_but, (void **)&cont, (void ***)&(cont->links), &(cont->totlinks), from->link->tocode, (int)to->hardmin); + UI_but_link_set( + tmp_but, (void **)&cont, (void ***)&(cont->links), + &cont->totlinks, from->link->tocode, (int)to->hardmin); tmp_but->hardmin = from->link->tocode; tmp_but->poin = (char *)cont; @@ -3180,7 +3193,9 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa } -static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static void ui_do_but_textedit( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int retval = WM_UI_HANDLER_CONTINUE; bool changed = false, inbox = false, update = false; @@ -3233,7 +3248,8 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle if (data->searchbox) inbox = ui_searchbox_inside(data->searchbox, event->x, event->y); - /* for double click: we do a press again for when you first click on button (selects all text, no cursor pos) */ + /* for double click: we do a press again for when you first click on button + * (selects all text, no cursor pos) */ if (event->val == KM_PRESS || event->val == KM_DBL_CLICK) { float mx, my; @@ -3477,7 +3493,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle ED_region_tag_redraw(data->region); } -static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static void ui_do_but_textedit_select( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my, retval = WM_UI_HANDLER_CONTINUE; @@ -3682,7 +3700,9 @@ static uiBut *ui_but_list_row_text_activate( /* ***************** events for different button types *************** */ -static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_BUT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (event->type == LEFTMOUSE && event->val == KM_PRESS) { @@ -3713,7 +3733,9 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HOTKEYEVT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { @@ -3776,7 +3798,9 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_KEYEVT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { @@ -3802,7 +3826,9 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_TEX( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) { @@ -3830,7 +3856,9 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_SEARCH_UNLINK( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { uiButExtraIconType extra_icon_type; @@ -3877,7 +3905,9 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa return ui_do_but_TEX(C, block, but, data, event); } -static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_TOG( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { #ifdef USE_DRAG_TOGGLE if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -3944,7 +3974,9 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_EXIT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -4092,7 +4124,7 @@ static float ui_numedit_apply_snap( static bool ui_numedit_but_NUM( uiBut *but, uiHandleButtonData *data, - int mx, + int mx, const bool is_motion, const enum eSnapType snap, float fac) { float deler, tempf, softmin, softmax, softrange; @@ -4100,8 +4132,10 @@ static bool ui_numedit_but_NUM( bool changed = false; const bool is_float = ui_but_is_float(but); - /* prevent unwanted drag adjustments */ - if (ui_but_dragedit_update_mval(data, mx) == false) { + /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */ + if ((is_motion || data->draglock) && + (ui_but_dragedit_update_mval(data, mx) == false)) + { return changed; } @@ -4242,7 +4276,9 @@ static bool ui_numedit_but_NUM( return changed; } -static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_NUM( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; /* mouse location scaled to fit the UI */ int screen_mx, screen_my; /* mouse location kept at screen pixel coords */ @@ -4324,6 +4360,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } } else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { + const bool is_motion = (event->type == MOUSEMOVE); const enum eSnapType snap = ui_event_to_snap(event); float fac; @@ -4335,8 +4372,9 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton fac = 1.0f; if (event->shift) fac /= 10.0f; - if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), snap, fac)) + if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), is_motion, snap, fac)) { ui_numedit_apply(C, block, but, data); + } #ifdef USE_DRAG_MULTINUM else if (data->multi_data.has_mbuts) { if (data->multi_data.init == BUTTON_MULTI_INIT_ENABLE) { @@ -4430,7 +4468,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton static bool ui_numedit_but_SLI( uiBut *but, uiHandleButtonData *data, - int mx, const bool is_horizontal, + int mx, const bool is_horizontal, const bool is_motion, const bool snap, const bool shift) { float deler, f, tempf, softmin, softmax, softrange; @@ -4440,8 +4478,9 @@ static bool ui_numedit_but_SLI( /* note, 'offs' is really from the widget drawing rounded corners see 'widget_numslider' */ float offs; - /* prevent unwanted drag adjustments */ + /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */ if ((but->type != UI_BTYPE_SCROLL) && + (is_motion || data->draglock) && (ui_but_dragedit_update_mval(data, mx) == false)) { return changed; @@ -4541,7 +4580,9 @@ static bool ui_numedit_but_SLI( return changed; } -static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_SLI( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my, click = 0; int retval = WM_UI_HANDLER_CONTINUE; @@ -4634,12 +4675,14 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } } else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { + const bool is_motion = (event->type == MOUSEMOVE); #ifdef USE_DRAG_MULTINUM data->multi_data.drag_dir[0] += abs(data->draglastx - mx); data->multi_data.drag_dir[1] += abs(data->draglasty - my); #endif - if (ui_numedit_but_SLI(but, data, mx, true, event->ctrl != 0, event->shift != 0)) + if (ui_numedit_but_SLI(but, data, mx, true, is_motion, event->ctrl != 0, event->shift != 0)) { ui_numedit_apply(C, block, but, data); + } #ifdef USE_DRAG_MULTINUM else if (data->multi_data.has_mbuts) { @@ -4722,7 +4765,9 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton return retval; } -static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_SCROLL( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my /*, click = 0 */; int retval = WM_UI_HANDLER_CONTINUE; @@ -4765,8 +4810,10 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut button_activate_state(C, but, BUTTON_STATE_EXIT); } else if (event->type == MOUSEMOVE) { - if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, false, false)) + const bool is_motion = (event->type == MOUSEMOVE); + if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, is_motion, false, false)) { ui_numedit_apply(C, block, but, data); + } } retval = WM_UI_HANDLER_BREAK; @@ -4775,7 +4822,9 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut return retval; } -static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_GRIP( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; int retval = WM_UI_HANDLER_CONTINUE; @@ -4826,7 +4875,9 @@ static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButto return retval; } -static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_LISTROW( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { /* hack to pass on ctrl+click and double click to overlapping text @@ -4846,7 +4897,9 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, return ui_do_but_EXIT(C, but, data, event); } -static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_BLOCK( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -5021,7 +5074,9 @@ static void ui_palette_set_active(uiBut *but) } } -static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_COLOR( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { /* first handle click on icondrag type button */ @@ -5154,7 +5209,9 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_UNITVEC(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_UNITVEC( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -5431,7 +5488,9 @@ static void ui_ndofedit_but_HSVCUBE( ui_but_v3_set(but, data->vec); } -static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HSVCUBE( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -5693,7 +5752,9 @@ static void ui_ndofedit_but_HSVCIRCLE( } -static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HSVCIRCLE( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { ColorPicker *cpicker = but->custom_data; float *hsv = cpicker->color_data; @@ -5821,7 +5882,9 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m return changed; } -static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_COLORBAND( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { ColorBand *coba; CBData *cbd; @@ -5997,7 +6060,9 @@ static bool ui_numedit_but_CURVE( return changed; } -static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_CURVE( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my, a; bool changed = false; @@ -6165,7 +6230,9 @@ static bool ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int m return changed; } -static int ui_do_but_HISTOGRAM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HISTOGRAM( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -6238,7 +6305,9 @@ static bool ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx return changed; } -static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_WAVEFORM( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -6292,7 +6361,9 @@ static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleB return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_LINK( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { VECCOPY2D(but->linkto, event->mval); @@ -6355,7 +6426,9 @@ static bool ui_numedit_but_TRACKPREVIEW( return changed; } -static int ui_do_but_TRACKPREVIEW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_TRACKPREVIEW( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -6851,7 +6924,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) WM_operator_properties_create(&ptr_props, "WM_OT_doc_view"); RNA_string_set(&ptr_props, "doc_id", buf); - uiItemFullO(layout, "WM_OT_doc_view", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"), + uiItemFullO(layout, "WM_OT_doc_view", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"), ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0); /* XXX inactive option, not for public! */ @@ -6860,7 +6934,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) RNA_string_set(&ptr_props, "doc_id", buf); RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop)); - uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0); + uiItemFullO(layout, "WM_OT_doc_edit", + "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0); #endif } } @@ -7440,7 +7515,8 @@ static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y) /** * Can we mouse over the button or is it hidden/disabled/layout. - * Note: ctrl is kind of a hack currently, so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed. + * \note ctrl is kind of a hack currently, + * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed. */ static bool ui_but_is_interactive(const uiBut *but, const bool labeledit) { @@ -7634,7 +7710,9 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s if (but->block->auto_open == true) { /* test for toolbox */ time = 1; } - else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) || but->block->auto_open == true) { + else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) || + (but->block->auto_open == true)) + { time = 5 * U.menuthreshold2; } else if (U.uiflag & USER_MENUOPENAUTO) { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index e00d8cf7c07..4107414a240 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1061,6 +1061,9 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size) } } +static void ui_id_preview_image_render_size( + const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job); + void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big) { Icon *icon = BKE_icon_get(icon_id); @@ -1076,22 +1079,20 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi } if (di) { - if (di->type == ICON_TYPE_PREVIEW) { - PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj; - - if (prv) { - const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; - - if (!prv->use_deferred || prv->rect[size] || (prv->flag[size] & PRV_USER_EDITED)) { - return; + switch (di->type) { + case ICON_TYPE_PREVIEW: + { + ID *id = (icon->type != 0) ? icon->obj : NULL; + PreviewImage *prv = id ? BKE_previewimg_id_ensure(id) : icon->obj; + + if (prv) { + const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; + + if (id || prv->use_deferred) { + ui_id_preview_image_render_size(C, NULL, id, prv, size, true); + } } - - icon_create_rect(prv, size); - - /* Always using job (background) version. */ - ED_preview_icon_job(C, prv, NULL, prv->rect[size], prv->w[size], prv->h[size]); - - prv->flag[size] &= ~PRV_CHANGED; + break; } } } diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 01b10b7b032..1af6d902b18 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -416,7 +416,7 @@ bool UI_context_copy_to_selected_list( if ((id_data == NULL) || (id_data->tag & LIB_TAG_DOIT) == 0 || - ID_IS_LINKED_DATABLOCK(id_data->lib) || + ID_IS_LINKED_DATABLOCK(id_data) || (GS(id_data->name) != id_code)) { BLI_remlink(&lb, link); diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 575b32e81e8..694794193da 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -110,7 +110,7 @@ bool ui_but_menu_step_poll(const uiBut *but) { BLI_assert(but->type == UI_BTYPE_MENU); - /* currenly only RNA buttons */ + /* currently only RNA buttons */ return ((but->menu_step_func != NULL) || (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM)); } @@ -459,6 +459,11 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) data->format[data->totline].color_id = UI_TIP_LC_NORMAL; data->totline++; } + else if (ID_IS_LINKED_DATAPATH(id)) { + BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Using file path as asset")); + data->format[data->totline].color_id = UI_TIP_LC_NORMAL; + data->totline++; + } } } else if (but->optype) { @@ -3331,6 +3336,11 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block) if (win) { UI_popup_handlers_remove(&win->modalhandlers, block->handle); ui_popup_block_free(C, block->handle); + + /* In the case we have nested popups, closing one may need to redraw anorher, see: T48874 */ + for (ARegion *ar = win->screen->regionbase.first; ar; ar = ar->next) { + ED_region_tag_refresh_ui(ar); + } } } } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index d91bd498225..aec4065adaf 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -302,7 +302,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_LOCAL: if (id) { - if (id_make_local(CTX_data_main(C), id, false)) { + if (id_make_local(CTX_data_main(C), id, false, false)) { /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template->ptr, template->prop); RNA_property_pointer_set(&template->ptr, template->prop, idptr); @@ -455,7 +455,7 @@ static void template_ID( else { but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Direct linked library datablock, click to make local")); - if (!id_make_local(CTX_data_main(C), id, true /* test */) || (idfrom && idfrom->lib)) + if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib)) UI_but_flag_enable(but, UI_BUT_DISABLED); } diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index b74c4b5f526..d62651cef81 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -175,7 +175,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) open_sim); if (export_count == 0) { - BKE_report(op->reports, RPT_WARNING, "Export file is empty"); + BKE_report(op->reports, RPT_WARNING, "No objects selected -- Created empty export file"); return OPERATOR_CANCELLED; } else if (export_count < 0) { diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index 69588928253..281a8b2a02d 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -563,7 +563,7 @@ static BMEdge *bm_face_split_edge_find( if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) || BM_edge_exists(v_pivot, l_iter->e->v2))) { - /* very unlikley but will cause complications splicing the verts together, + /* very unlikely but will cause complications splicing the verts together, * so just skip this case */ ok = false; } diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index e3e5863dc0e..e31e4096ded 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -395,7 +395,7 @@ static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs, * return an un-ordered array of loop pairs * use for rebuilding face-fill * - * \note the method currenly used fails for edges with 3+ face users and gives + * \note the method currently used fails for edges with 3+ face users and gives * nasty holes in the mesh, there isnt a good way of knowing ahead of time * which loops will be split apart (its possible to figure out but quite involved). * So for now this is a known limitation of current rip-fill option. @@ -748,10 +748,8 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve } if (do_fill) { - if (do_fill) { - /* match extrude vert-order */ - BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP); - } + /* match extrude vert-order */ + BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP); } MEM_freeN(vout); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 3a7a8fb883b..1a14fad8650 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -4032,7 +4032,7 @@ static int edbm_decimate_exec(bContext *C, wmOperator *op) const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset); weight = defvert_find_weight(dv, defbase_act); if (invert_vertex_group) { - weight = 1.0 - weight; + weight = 1.0f - weight; } } else { diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index bcdd170c53c..0fe43c44d7d 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -440,7 +440,7 @@ static int group_link_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; /* Early return check, if the object is already in group - * we could sckip all the dependency check and just consider + * we could skip all the dependency check and just consider * operator is finished. */ if (BKE_group_object_exists(group, ob)) { diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 6b16e19f790..b3edf1f5e0d 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2104,11 +2104,11 @@ static void make_local_makelocalmaterial(Material *ma) AnimData *adt; int b; - id_make_local(G.main, &ma->id, false); + id_make_local(G.main, &ma->id, false, false); for (b = 0; b < MAX_MTEX; b++) if (ma->mtex[b] && ma->mtex[b]->tex) - id_make_local(G.main, &ma->mtex[b]->tex->id, false); + id_make_local(G.main, &ma->mtex[b]->tex->id, false, false); adt = BKE_animdata_from_id(&ma->id); if (adt) BKE_animdata_make_local(adt); @@ -2237,7 +2237,7 @@ static int make_local_exec(bContext *C, wmOperator *op) } if (ob->id.lib) - id_make_local(bmain, &ob->id, false); + id_make_local(bmain, &ob->id, false, false); } CTX_DATA_END; @@ -2259,7 +2259,7 @@ static int make_local_exec(bContext *C, wmOperator *op) id = ob->data; if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) { - id_make_local(bmain, id, false); + id_make_local(bmain, id, false, false); adt = BKE_animdata_from_id(id); if (adt) BKE_animdata_make_local(adt); @@ -2275,7 +2275,7 @@ static int make_local_exec(bContext *C, wmOperator *op) } for (psys = ob->particlesystem.first; psys; psys = psys->next) - id_make_local(bmain, &psys->part->id, false); + id_make_local(bmain, &psys->part->id, false, false); adt = BKE_animdata_from_id(&ob->id); if (adt) BKE_animdata_make_local(adt); @@ -2294,7 +2294,7 @@ static int make_local_exec(bContext *C, wmOperator *op) for (b = 0; b < MAX_MTEX; b++) if (la->mtex[b] && la->mtex[b]->tex) - id_make_local(bmain, &la->mtex[b]->tex->id, false); + id_make_local(bmain, &la->mtex[b]->tex->id, false, false); } else { for (a = 0; a < ob->totcol; a++) { diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 0cbbe46f461..f1b7186f8a1 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -577,7 +577,6 @@ static bool select_grouped_parent(bContext *C) /* Makes parent active and de-sel /* can be NULL if parent in other scene */ if (baspar && BASE_SELECTABLE(v3d, baspar)) { - ED_base_object_select(basact, BA_DESELECT); ED_base_object_select(baspar, BA_SELECT); ED_base_object_activate(C, baspar); changed = true; diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 6e8aaebcccc..ad41fb23a69 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -3538,8 +3538,10 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr) return BLI_natstrcmp(def_a->name, def_b->name); } -/* Sorts the weight groups according to the bone hierarchy of the - associated armature (similar to how bones are ordered in the Outliner) */ +/** + * Sorts the weight groups according to the bone hierarchy of the + * associated armature (similar to how bones are ordered in the Outliner) + */ static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase) { if (bonebase == NULL) { diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 1203889cf0e..8c5d25ad44d 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -1482,7 +1482,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) void render_view3d_update(RenderEngine *engine, const bContext *C) { /* this shouldn't be needed and causes too many database rebuilds, but we - * aren't actually tracking updates for all relevent datablocks so this is + * aren't actually tracking updates for all relevant datablocks so this is * a catch-all for updates */ engine->update_flag |= RE_ENGINE_UPDATE_DATABASE; diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index c3f83138707..5a0c250c777 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -102,7 +102,7 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op)) if (!ob) return OPERATOR_CANCELLED; - object_add_material_slot(ob); + BKE_object_material_slot_add(ob); if (ob->mode & OB_MODE_TEXTURE_PAINT) { Scene *scene = CTX_data_scene(C); @@ -145,7 +145,7 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - object_remove_material_slot(ob); + BKE_object_material_slot_remove(ob); if (ob->mode & OB_MODE_TEXTURE_PAINT) { Scene *scene = CTX_data_scene(C); @@ -529,7 +529,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) if (prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer use also increases user, so this compensates it */ id_us_min(&tex->id); if (ptr.id.data && GS(((ID *)ptr.id.data)->name) == ID_MA && @@ -592,7 +592,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) if (prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer use also increases user, so this compensates it */ id_us_min(&wo->id); RNA_id_pointer_create(&wo->id, &idptr); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index ab8b7d4e138..8d058ed2081 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -580,15 +580,20 @@ void ED_region_tag_refresh_ui(ARegion *ar) void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct) { if (ar && !(ar->do_draw & RGN_DRAWING)) { - if (!(ar->do_draw & RGN_DRAW)) { + if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_PARTIAL))) { /* no redraw set yet, set partial region */ ar->do_draw |= RGN_DRAW_PARTIAL; ar->drawrct = *rct; } else if (ar->drawrct.xmin != ar->drawrct.xmax) { + BLI_assert((ar->do_draw & RGN_DRAW_PARTIAL) != 0); /* partial redraw already set, expand region */ BLI_rcti_union(&ar->drawrct, rct); } + else { + BLI_assert((ar->do_draw & RGN_DRAW) != 0); + /* Else, full redraw is already requested, nothing to do here. */ + } } } diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 6ed969cb270..d60c8e8dbd9 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -183,8 +183,8 @@ BLI_INLINE unsigned char f_to_char(const float val) /* to avoid locking in tile initialization */ #define TILE_PENDING SET_INT_IN_POINTER(-1) -/* This is mainly a convenience struct used so we can keep an array of images we use - * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread +/* This is mainly a convenience struct used so we can keep an array of images we use - + * their imbufs, etc, in 1 array, When using threads this array is copied for each thread * because 'partRedrawRect' and 'touch' values would not be thread safe */ typedef struct ProjPaintImage { Image *ima; @@ -202,7 +202,7 @@ typedef struct ProjPaintImage { */ typedef struct ProjStrokeHandle { /* Support for painting from multiple views at once, - * currently used to impliment symmetry painting, + * currently used to implement symmetry painting, * we can assume at least the first is set while painting. */ struct ProjPaintState *ps_views[8]; int ps_views_tot; @@ -2174,7 +2174,7 @@ static void project_bucket_clip_face( if ((*tot) < 3) { /* no intersections to speak of, but more probable is that all face is just outside the - * rectangle and culled due to float precision issues. Since above teste have failed, + * rectangle and culled due to float precision issues. Since above tests have failed, * just dump triangle as is for painting */ *tot = 0; copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++; diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index aa17cb02fe5..1431958501d 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -491,31 +491,30 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float } /* Returns zero if no sculpt changes should be made, non-zero otherwise */ -static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outpressure, - const PaintSample *sample, PaintMode mode) +static bool paint_smooth_stroke( + PaintStroke *stroke, const PaintSample *sample, PaintMode mode, + float r_mouse[2], float *r_pressure) { if (paint_supports_smooth_stroke(stroke->brush, mode)) { float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d; - float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u; - float dx = stroke->last_mouse_position[0] - sample->mouse[0]; - float dy = stroke->last_mouse_position[1] - sample->mouse[1]; + float u = stroke->brush->smooth_stroke_factor; /* If the mouse is moving within the radius of the last move, * don't update the mouse position. This allows sharp turns. */ - if (dx * dx + dy * dy < radius * radius) - return 0; + if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < SQUARE(radius)) { + return false; + } - output[0] = sample->mouse[0] * v + stroke->last_mouse_position[0] * u; - output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u; - *outpressure = sample->pressure * v + stroke->last_pressure * u; + interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u); + *r_pressure = interpf(sample->pressure, stroke->last_pressure, u); } else { - output[0] = sample->mouse[0]; - output[1] = sample->mouse[1]; - *outpressure = sample->pressure; + r_mouse[0] = sample->mouse[0]; + r_mouse[1] = sample->mouse[1]; + *r_pressure = sample->pressure; } - return 1; + return true; } static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure) @@ -1190,7 +1189,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) /* airbrush */ ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer)) { - if (paint_smooth_stroke(stroke, mouse, &pressure, &sample_average, mode)) { + if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) { if (stroke->stroke_started) { if (paint_space_stroke_enabled(br, mode)) { if (paint_space_stroke(C, op, mouse, pressure)) diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 3bcd610150c..991025a4d5d 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -257,9 +257,7 @@ static bool make_vertexcol(Object *ob) /* single ob */ /* copies from shadedisplist to mcol */ if (!me->mloopcol && me->totloop) { - if (!me->mloopcol) { - CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop); - } + CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop); BKE_mesh_update_customdata_pointers(me, true); } @@ -2380,9 +2378,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P swap_m4m4(vc->rv3d->persmat, mat); /* calculate pivot for rotation around seletion if needed */ - if (U.uiflag & USER_ORBIT_SELECTION) { - paint_last_stroke_update(scene, vc->ar, mval); - } + /* also needed for "View Selected" on last stroke */ + paint_last_stroke_update(scene, vc->ar, mval); DAG_id_tag_update(ob->data, 0); ED_region_tag_redraw(vc->ar); @@ -2858,9 +2855,8 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P } /* calculate pivot for rotation around seletion if needed */ - if (U.uiflag & USER_ORBIT_SELECTION) { - paint_last_stroke_update(scene, vc->ar, mval); - } + /* also needed for "View Selected" on last stroke */ + paint_last_stroke_update(scene, vc->ar, mval); ED_region_tag_redraw(vc->ar); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index cc7531b9783..1305b76b5ad 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1145,7 +1145,9 @@ static void calc_area_normal_and_center( /* Return modified brush strength. Includes the direction of the brush, positive * values pull vertices, negative values push. Uses tablet pressure and a * special multiplier found experimentally to scale the strength factor. */ -static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups) +static float brush_strength( + const Sculpt *sd, const StrokeCache *cache, + const float feather, const UnifiedPaintSettings *ups) { const Scene *scene = cache->vc->scene; const Brush *brush = BKE_paint_brush((Paint *)&sd->paint); @@ -3985,7 +3987,9 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) } /* Initialize the stroke cache invariants from operator properties */ -static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2]) +static void sculpt_update_cache_invariants( + bContext *C, Sculpt *sd, SculptSession *ss, + wmOperator *op, const float mouse[2]) { StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); Scene *scene = CTX_data_scene(C); @@ -4448,7 +4452,9 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin) } } -static float sculpt_raycast_init(ViewContext *vc, const float mouse[2], float ray_start[3], float ray_end[3], float ray_normal[3], bool original) +static float sculpt_raycast_init( + ViewContext *vc, const float mouse[2], + float ray_start[3], float ray_end[3], float ray_normal[3], bool original) { float obimat[4][4]; float dist; @@ -4956,8 +4962,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss) cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id); } - ss->cd_vert_node_offset = CustomData_get_n_offset(&ss->bm->vdata, CD_PROP_INT, - cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT)); + ss->cd_vert_node_offset = CustomData_get_n_offset( + &ss->bm->vdata, CD_PROP_INT, + cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT)); ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; @@ -4967,8 +4974,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss) cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id); } - ss->cd_face_node_offset = CustomData_get_n_offset(&ss->bm->pdata, CD_PROP_INT, - cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT)); + ss->cd_face_node_offset = CustomData_get_n_offset( + &ss->bm->pdata, CD_PROP_INT, + cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT)); ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; } @@ -5667,7 +5675,8 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, "Location", "Screen Coordinates of sampling", 0, SHRT_MAX); + RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, + "Location", "Screen Coordinates of sampling", 0, SHRT_MAX); } diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 4931426d62e..03f2e146b7d 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -136,7 +136,7 @@ static int sound_open_exec(bContext *C, wmOperator *op) if (pprop->prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer use also increases user, so this compensates it */ id_us_min(&sound->id); RNA_id_pointer_create(&sound->id, &idptr); diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 1ff656243d6..14d0f909d23 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -634,7 +634,7 @@ typedef struct PrefetchQueue { short render_size, render_flag; /* If true prefecthing goes forward in time, - * othwewise it goes backwards in time (starting from current frame). + * otherwise it goes backwards in time (starting from current frame). */ bool forward; diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 085fdd57309..83876ae2669 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -234,7 +234,7 @@ static int open_exec(bContext *C, wmOperator *op) if (pprop->prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer use also increases user, so this compensates it */ id_us_min(&clip->id); RNA_id_pointer_create(&clip->id, &idptr); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 6d1916cfae7..6fb55729802 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -40,7 +40,7 @@ #include "BLO_readfile.h" #include "BKE_appdir.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_context.h" #include "BKE_screen.h" #include "BKE_global.h" diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 8e2eed89de2..814eb846d37 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -65,7 +65,7 @@ #include "RNA_types.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_library.h" diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index cd008d4a54b..ee768ba6087 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -37,7 +37,7 @@ extern "C" { #endif -#include "BKE_asset.h" +#include "BKE_asset_engine.h" struct AssetEngineType; struct AssetEngine; diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 9f5fffc73c5..7e230b5befb 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -43,7 +43,7 @@ #include "RNA_types.h" #include "BKE_appdir.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_context.h" #include "BKE_screen.h" #include "BKE_global.h" diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index b837e516422..ae91a466495 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -826,7 +826,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu) //if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0) // return; - /* No curve to modify/visualise the result? + /* No curve to modify/visualize the result? * => We still want to show the 1-1 default... */ if ((fcu->totvert == 0) && BLI_listbase_is_empty(&fcu->modifiers)) { diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index a2db6827b0e..38a54ade367 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -345,6 +345,13 @@ struct ImageUI_Data { int rpass_index; }; +static struct ImageUI_Data *ui_imageuser_data_copy(const struct ImageUI_Data *rnd_pt_src) +{ + struct ImageUI_Data *rnd_pt_dst = MEM_mallocN(sizeof(*rnd_pt_src), __func__); + memcpy(rnd_pt_dst, rnd_pt_src, sizeof(*rnd_pt_src)); + return rnd_pt_dst; +} + static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt) { struct ImageUI_Data *rnd_data = rnd_pt; @@ -532,9 +539,10 @@ static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layo } /* 5 layer button callbacks... */ -static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v) +static void image_multi_cb(bContext *C, void *rnd_pt, void *rr_v) { - ImageUser *iuser = iuser_v; + struct ImageUI_Data *rnd_data = rnd_pt; + ImageUser *iuser = rnd_data->iuser; BKE_image_multilayer_index(rr_v, iuser); WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); @@ -575,6 +583,8 @@ static bool ui_imageuser_layer_menu_step(bContext *C, int direction, void *rnd_p BLI_assert(0); } + BKE_image_release_renderresult(scene, image); + if (changed) { BKE_image_multilayer_index(rr, iuser); WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); @@ -662,10 +672,11 @@ static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt } /* 5 view button callbacks... */ -static void image_multiview_cb(bContext *C, void *ima_v, void *iuser_v) +static void image_multiview_cb(bContext *C, void *rnd_pt, void *UNUSED(arg_v)) { - Image *ima = ima_v; - ImageUser *iuser = iuser_v; + struct ImageUI_Data *rnd_data = rnd_pt; + Image *ima = rnd_data->image; + ImageUser *iuser = rnd_data->iuser; BKE_image_multiview_index(ima, iuser); WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); @@ -692,7 +703,7 @@ static void uiblock_layer_pass_buttons( uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot) { - static struct ImageUI_Data rnd_pt; /* XXX, workaround */ + struct ImageUI_Data rnd_pt_local, *rnd_pt = NULL; uiBlock *block = uiLayoutGetBlock(layout); uiBut *but; RenderLayer *rl = NULL; @@ -708,10 +719,10 @@ static void uiblock_layer_pass_buttons( wmenu2 = (3 * w) / 5; wmenu3 = (3 * w) / 6; wmenu4 = (3 * w) / 6; - - rnd_pt.image = image; - rnd_pt.iuser = iuser; - rnd_pt.rpass_index = 0; + + rnd_pt_local.image = image; + rnd_pt_local.iuser = iuser; + rnd_pt_local.rpass_index = 0; /* menu buts */ if (render_slot) { @@ -723,10 +734,12 @@ static void uiblock_layer_pass_buttons( BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1); } + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); but = uiDefMenuBut(block, ui_imageuser_slot_menu, image, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot")); UI_but_func_menu_step_set(but, ui_imageuser_slot_menu_step); - UI_but_func_set(but, image_multi_cb, rr, iuser); + UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; } if (rr) { @@ -738,15 +751,18 @@ static void uiblock_layer_pass_buttons( fake_name = ui_imageuser_layer_fake_name(rr); rpass_index = iuser->layer - (fake_name ? 1 : 0); rl = BLI_findlink(&rr->layers, rpass_index); - rnd_pt.rpass_index = rpass_index; + rnd_pt_local.rpass_index = rpass_index; if (RE_layers_have_name(rr)) { display_name = rl ? rl->name : (fake_name ? fake_name : ""); - but = uiDefMenuBut(block, ui_imageuser_layer_menu, &rnd_pt, display_name, - 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer")); + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); + but = uiDefMenuBut( + block, ui_imageuser_layer_menu, rnd_pt, display_name, + 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer")); UI_but_func_menu_step_set(but, ui_imageuser_layer_menu_step); - UI_but_func_set(but, image_multi_cb, rr, iuser); + UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; } /* pass */ @@ -754,11 +770,14 @@ static void uiblock_layer_pass_buttons( rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL); display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : ""); - but = uiDefMenuBut(block, ui_imageuser_pass_menu, &rnd_pt, IFACE_(display_name), - 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass")); + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); + but = uiDefMenuBut( + block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name), + 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass")); UI_but_func_menu_step_set(but, ui_imageuser_pass_menu_step); - UI_but_func_set(but, image_multi_cb, rr, iuser); + UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; /* view */ if (BLI_listbase_count_ex(&rr->views, 2) > 1 && @@ -767,9 +786,13 @@ static void uiblock_layer_pass_buttons( rview = BLI_findlink(&rr->views, iuser->view); display_name = rview ? rview->name : ""; - but = uiDefMenuBut(block, ui_imageuser_view_menu_rr, &rnd_pt, display_name, 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View")); - UI_but_func_set(but, image_multi_cb, rr, iuser); + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); + but = uiDefMenuBut( + block, ui_imageuser_view_menu_rr, rnd_pt, display_name, + 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View")); + UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; } } @@ -787,9 +810,13 @@ static void uiblock_layer_pass_buttons( } } - but = uiDefMenuBut(block, ui_imageuser_view_menu_multiview, &rnd_pt, display_name, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View")); - UI_but_func_set(but, image_multiview_cb, image, iuser); + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); + but = uiDefMenuBut( + block, ui_imageuser_view_menu_multiview, rnd_pt, display_name, + 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View")); + UI_but_funcN_set(but, image_multiview_cb, rnd_pt, NULL); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; } } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 06caf930988..1158e692182 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1061,6 +1061,12 @@ typedef struct ImageOpenData { ImageFormatData im_format; } ImageOpenData; +typedef struct ImageFrameRange { + struct ImageFrameRange *next, *prev; + ListBase frames; + char filepath[FILE_MAX]; +} ImageFrameRange; + typedef struct ImageFrame { struct ImageFrame *next, *prev; int framenr; @@ -1086,10 +1092,10 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op) * \param frames [out] the list of frame numbers found in the files matching the first one by name * \param path [out] the full path of the first file in the list of image files */ -static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen) +static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all) { char dir[FILE_MAXDIR]; - bool is_first_entry = true; + ImageFrameRange *frame_range = NULL; RNA_string_get(ptr, "directory", dir); RNA_BEGIN (ptr, itemptr, "files") @@ -1101,29 +1107,26 @@ static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *p ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame"); /* use the first file in the list as base filename */ - if (is_first_entry) { - BLI_join_dirfile(path, maxlen, dir, filename); - frame->framenr = BLI_stringdec(filename, base_head, base_tail, &digits); - BLI_addtail(frames, frame); - is_first_entry = false; + frame->framenr = BLI_stringdec(filename, head, tail, &digits); + + /* still in the same sequence */ + if ((frame_range != NULL) && + (STREQLEN(base_head, head, FILE_MAX)) && + (STREQLEN(base_tail, tail, FILE_MAX))) + { + /* pass */ } else { - frame->framenr = BLI_stringdec(filename, head, tail, &digits); + /* start a new frame range */ + frame_range = MEM_callocN(sizeof(*frame_range), __func__); + BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename); + BLI_addtail(frames_all, frame_range); - /* still in the same sequence */ - if ((STREQLEN(base_head, head, FILE_MAX)) && - (STREQLEN(base_tail, tail, FILE_MAX))) - { - BLI_addtail(frames, frame); - } - else { - /* different file base name found, is ignored */ - MEM_freeN(filename); - MEM_freeN(frame); - break; - } + BLI_strncpy(base_head, head, sizeof(base_head)); + BLI_strncpy(base_tail, tail, sizeof(base_tail)); } + BLI_addtail(&frame_range->frames, frame); MEM_freeN(filename); } RNA_END @@ -1164,6 +1167,52 @@ static int image_sequence_get_len(ListBase *frames, int *ofs) return 0; } +static Image *image_open_single( + wmOperator *op, const char *filepath, const char *relbase, + bool is_relative_path, bool use_multiview, int frame_seq_len) +{ + bool exists = false; + Image *ima = NULL; + + errno = 0; + ima = BKE_image_load_exists_ex(filepath, &exists); + + if (!ima) { + if (op->customdata) MEM_freeN(op->customdata); + BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s", + filepath, errno ? strerror(errno) : TIP_("unsupported image format")); + return NULL; + } + + if (!exists) { + /* only image path after save, never ibuf */ + if (is_relative_path) { + BLI_path_rel(ima->name, relbase); + } + + /* handle multiview images */ + if (use_multiview) { + ImageOpenData *iod = op->customdata; + ImageFormatData *imf = &iod->im_format; + + ima->flag |= IMA_USE_VIEWS; + ima->views_format = imf->views_format; + *ima->stereo3d_format = imf->stereo3d_format; + } + else { + ima->flag &= ~IMA_USE_VIEWS; + BKE_image_free_views(ima); + } + + if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) { + ima->source = IMA_SRC_SEQUENCE; + } + } + + return ima; +} + + static int image_open_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -1174,70 +1223,60 @@ static int image_open_exec(bContext *C, wmOperator *op) ImageOpenData *iod = op->customdata; PointerRNA idptr; Image *ima = NULL; - char path[FILE_MAX]; + char filepath[FILE_MAX]; int frame_seq_len = 0; int frame_ofs = 1; - bool exists = false; const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path"); + const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview"); - RNA_string_get(op->ptr, "filepath", path); + if (!op->customdata) + image_open_init(C, op); + + RNA_string_get(op->ptr, "filepath", filepath); if (RNA_struct_property_is_set(op->ptr, "directory") && RNA_struct_property_is_set(op->ptr, "files")) { - /* only to pass to imbuf */ - char path_full[FILE_MAX]; - BLI_strncpy(path_full, path, sizeof(path_full)); - BLI_path_abs(path_full, G.main->name); + bool was_relative = BLI_path_is_rel(filepath); + ListBase frame_ranges_all; - if (!IMB_isanim(path_full)) { - bool was_relative = BLI_path_is_rel(path); - ListBase frames; + BLI_listbase_clear(&frame_ranges_all); + image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all); + for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range; frame_range = frame_range->next) { + int frame_range_ofs; + int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs); + BLI_freelistN(&frame_range->frames); - BLI_listbase_clear(&frames); - image_sequence_get_frames(op->ptr, &frames, path, sizeof(path)); - frame_seq_len = image_sequence_get_len(&frames, &frame_ofs); - BLI_freelistN(&frames); + char filepath_range[FILE_MAX]; + BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range)); if (was_relative) { - BLI_path_rel(path, G.main->name); + BLI_path_rel(filepath_range, bmain->name); } - } - } - - errno = 0; - ima = BKE_image_load_exists_ex(path, &exists); + Image *ima_range = image_open_single( + op, filepath_range, bmain->name, + is_relative_path, use_multiview, frame_range_seq_len); - if (!ima) { - if (op->customdata) MEM_freeN(op->customdata); - BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s", - path, errno ? strerror(errno) : TIP_("unsupported image format")); - return OPERATOR_CANCELLED; - } - - if (!op->customdata) - image_open_init(C, op); - - /* handle multiview images */ - if (RNA_boolean_get(op->ptr, "use_multiview")) { - ImageFormatData *imf = &iod->im_format; - - ima->flag |= IMA_USE_VIEWS; - ima->views_format = imf->views_format; - *ima->stereo3d_format = imf->stereo3d_format; + /* take the first image */ + if ((ima == NULL) && ima_range) { + ima = ima_range; + frame_seq_len = frame_range_seq_len; + frame_ofs = frame_range_ofs; + } + } + BLI_freelistN(&frame_ranges_all); } else { - ima->flag &= ~IMA_USE_VIEWS; - BKE_image_free_views(ima); + /* for drag & drop etc. */ + ima = image_open_single( + op, filepath, bmain->name, + is_relative_path, use_multiview, 1); } - /* only image path after save, never ibuf */ - if (is_relative_path) { - if (!exists) { - BLI_path_rel(ima->name, bmain->name); - } + if (ima == NULL) { + return OPERATOR_CANCELLED; } /* hook into UI */ @@ -1245,11 +1284,9 @@ static int image_open_exec(bContext *C, wmOperator *op) if (iod->pprop.prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer use also increases user, so this compensates it */ id_us_min(&ima->id); - if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) { - ima->source = IMA_SRC_SEQUENCE; - } + RNA_id_pointer_create(&ima->id, &idptr); RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr); RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop); @@ -2359,7 +2396,7 @@ static int image_new_exec(bContext *C, wmOperator *op) if (prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer use also increases user, so this compensates it */ id_us_min(&ima->id); RNA_id_pointer_create(&ima->id, &idptr); diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index d7249897723..ea3869ef387 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -1726,7 +1726,7 @@ static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const w float duration; bool redraw = false; - if (!snode || event->type != TIMER || iofsd->anim_timer != event->customdata) + if (!snode || event->type != TIMER || iofsd == NULL || iofsd->anim_timer != event->customdata) return OPERATOR_PASS_THROUGH; duration = (float)iofsd->anim_timer->duration; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 5173b18dc9b..b357e742d78 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1568,7 +1568,7 @@ static void outliner_draw_tree_element( else offsx += 2 * ufac; - if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) { + if (tselem->type == 0 && ID_IS_LINKED(tselem->id)) { glPixelTransferf(GL_ALPHA_SCALE, 0.5f); if (tselem->id->tag & LIB_TAG_MISSING) { UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN); @@ -1579,8 +1579,6 @@ static void outliner_draw_tree_element( else { UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT); } - /* TODO use proper icons or other UI feedback, for sake of simplicity for now using basic - * color code to show assets and their state. */ if (tselem->id->uuid) { offsx += UI_UNIT_X; UI_icon_draw((float)startx + offsx - 0.5f * ufac, (float)*starty + 1.5f * ufac, ICON_SOLO_ON); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index b0cd3aabbfd..3c47f542dae 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -417,9 +417,9 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) { + if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) { BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')", - old_id->name, new_id->name); + old_id ? old_id->name : "Invalid ID", new_id ? new_id->name : "Invalid ID"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index f3235d07757..a840a720b3d 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -435,11 +435,12 @@ static void id_local_cb( bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { - if (ID_IS_LINKED_DATABLOCK(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { + if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { Main *bmain = CTX_data_main(C); /* if the ID type has no special local function, - * just clear the lib */ - if (id_make_local(bmain, tselem->id, false) == false) { + * just clear the lib. */ + /* XXX This is very, very, **very** suspicious - should not be handled that way at all!!! */ + if (id_make_local(bmain, tselem->id, false, false) == false) { id_clear_lib_data(bmain, tselem->id); } } @@ -516,23 +517,16 @@ static void group_linkobs2scene_cb( Group *group = (Group *)tselem->id; GroupObject *gob; Base *base; - + for (gob = group->gobject.first; gob; gob = gob->next) { base = BKE_scene_base_find(scene, gob->ob); - if (base) { - base->object->flag |= SELECT; - base->flag |= SELECT; - } - else { + if (!base) { /* link to scene */ - base = MEM_callocN(sizeof(Base), "add_base"); - BLI_addhead(&scene->base, base); - base->lay = gob->ob->lay; - gob->ob->flag |= SELECT; - base->flag = gob->ob->flag; - base->object = gob->ob; + base = BKE_scene_base_add(scene, gob->ob); id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */ } + base->object->flag |= SELECT; + base->flag |= SELECT; } } @@ -1352,7 +1346,7 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); SpaceOops *soops = CTX_wm_space_outliner(C); int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutlinerIdOpTypes event; + eOutlinerLibOpTypes event; /* check for invalid states */ if (soops == NULL) diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index c11a4d2e5a3..ede6b7ce469 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -1071,7 +1071,7 @@ static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, const { bool is_type_set = RNA_struct_property_is_set(op->ptr, "type"); int type = -1; - int prop_flag = SEQPROP_ENDFRAME; + int prop_flag = SEQPROP_ENDFRAME | SEQPROP_NOPATHS; if (is_type_set) { type = RNA_enum_get(op->ptr, "type"); @@ -1106,9 +1106,6 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_filesel( - ot, 0, FILE_SPECIAL, FILE_OPENFILE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME); RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_TYPE_CROSS, "Type", "Sequencer effect type"); RNA_def_float_vector(ot->srna, "color", 3, NULL, 0.0f, 1.0f, "Color", diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index 791ece14cb9..f5289a0d245 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -237,7 +237,9 @@ static struct TextureDrawState { bool texpaint_material; /* use material slots for texture painting */ } Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, false, {0, 0, 0, 0}, false, false}; -static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material *ma, struct TextureDrawState gtexdraw) +static bool set_draw_settings_cached( + int clearcache, MTexPoly *texface, Material *ma, + const struct TextureDrawState *gtexdraw) { static Material *c_ma; static int c_textured; @@ -253,7 +255,7 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material int lit = 0; int has_texface = texface != NULL; bool need_set_tpage = false; - bool texpaint = ((gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) != 0); + bool texpaint = ((gtexdraw->ob->mode & OB_MODE_TEXTURE_PAINT) != 0); Image *ima = NULL; @@ -271,16 +273,18 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material c_ma = NULL; } else { - textured = gtexdraw.is_tex; + textured = gtexdraw->is_tex; } /* convert number of lights into boolean */ - if (gtexdraw.is_lit) lit = 1; + if (gtexdraw->is_lit) { + lit = 1; + } - backculled = gtexdraw.use_backface_culling; + backculled = gtexdraw->use_backface_culling; if (ma) { if (ma->mode & MA_SHLESS) lit = 0; - if (gtexdraw.use_game_mat) { + if (gtexdraw->use_game_mat) { backculled = backculled || (ma->game.flag & GEMAT_BACKCULL); alphablend = ma->game.alpha_blend; } @@ -294,10 +298,10 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material alphablend = GPU_BLEND_ALPHA; } else if (texpaint) { - if (gtexdraw.texpaint_material) + if (gtexdraw->texpaint_material) ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; else - ima = gtexdraw.canvas; + ima = gtexdraw->canvas; } else textured = 0; @@ -375,7 +379,7 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material if (c_textured && !c_badtex) { options |= GPU_SHADER_TEXTURE_2D; } - if (gtexdraw.two_sided_lighting) { + if (gtexdraw->two_sided_lighting) { options |= GPU_SHADER_TWO_SIDED; } @@ -495,7 +499,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O Gtexdraw.two_sided_lighting = (me->flag & ME_TWOSIDED); memcpy(Gtexdraw.obcol, obcol, sizeof(obcol)); - set_draw_settings_cached(1, NULL, NULL, Gtexdraw); + set_draw_settings_cached(1, NULL, NULL, &Gtexdraw); glCullFace(GL_BACK); } @@ -553,7 +557,7 @@ static DMDrawOption draw_tface__set_draw_legacy(MTexPoly *mtexpoly, const bool h if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return DM_DRAW_OPTION_SKIP; - invalidtexture = set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw); + invalidtexture = set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw); if (mtexpoly && invalidtexture) { glColor3ub(0xFF, 0x00, 0xFF); @@ -594,7 +598,7 @@ static DMDrawOption draw_tface__set_draw(MTexPoly *mtexpoly, const bool UNUSED(h if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return DM_DRAW_OPTION_SKIP; if (mtexpoly || Gtexdraw.is_texpaint) - set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw); + set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw); /* always use color from mcol, as set in update_tface_color_layer */ return DM_DRAW_OPTION_NORMAL; @@ -664,7 +668,7 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol) copy_mode = COPY_PREV; } } - else if (mtexpoly && set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw)) { + else if (mtexpoly && set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw)) { int loop_index = mp->loopstart; for (j = 0; j < mp->totloop; j++, loop_index++) { finalCol[loop_index].r = 255; @@ -830,7 +834,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl) } } else { - badtex = set_draw_settings_cached(0, mtpoly, mat, Gtexdraw); + badtex = set_draw_settings_cached(0, mtpoly, mat, &Gtexdraw); if (badtex) { continue; } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 90f79f0ff69..b117a5e68d8 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3079,7 +3079,9 @@ static int viewselected_exec(bContext *C, wmOperator *op) else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { ok = PE_minmax(scene, min, max); } - else if (ob && (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT))) { + else if (ob && + (ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) + { BKE_paint_stroke_get_average(scene, ob, min); copy_v3_v3(max, min); ok = true; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 6d831c667a8..bdd2702a6ce 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -274,6 +274,7 @@ bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]); void VIEW3D_OT_snap_selected_to_grid(struct wmOperatorType *ot); void VIEW3D_OT_snap_selected_to_cursor(struct wmOperatorType *ot); +void VIEW3D_OT_snap_selected_to_active(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_grid(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 1c84ce3c985..b273f46fca3 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -214,6 +214,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_snap_selected_to_grid); WM_operatortype_append(VIEW3D_OT_snap_selected_to_cursor); + WM_operatortype_append(VIEW3D_OT_snap_selected_to_active); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_grid); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_center); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index ac05853e6d0..7448d4c658e 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -312,25 +312,9 @@ static void view3d_win_to_ray_segment( if (!r_ray_co) r_ray_co = _ray_co; if (!r_ray_dir) r_ray_dir = _ray_dir; + ED_view3d_win_to_origin(ar, mval, r_ray_co); ED_view3d_win_to_vector(ar, mval, r_ray_dir); - if (rv3d->is_persp) { - copy_v3_v3(r_ray_co, rv3d->viewinv[3]); - } - else { - r_ray_co[0] = 2.0f * mval[0] / ar->winx - 1.0f; - r_ray_co[1] = 2.0f * mval[1] / ar->winy - 1.0f; - - if (rv3d->persp == RV3D_CAMOB) { - r_ray_co[2] = -1.0f; - } - else { - r_ray_co[2] = 0.0f; - } - - mul_project_m4_v3(rv3d->persinv, r_ray_co); - } - if ((rv3d->is_persp == false) && (rv3d->persp != RV3D_CAMOB)) { end_offset = v3d->far / 2.0f; start_offset = -end_offset; @@ -347,7 +331,7 @@ static void view3d_win_to_ray_segment( } } -BLI_INLINE bool view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3]) +bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3]) { if ((rv3d->rflag & RV3D_CLIPPING) && (clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6, @@ -384,7 +368,7 @@ bool ED_view3d_win_to_ray_ex( /* bounds clipping */ if (do_clip) { - return view3d_clip_segment(ar->regiondata, r_ray_start, ray_end); + return ED_view3d_clip_segment(ar->regiondata, r_ray_start, ray_end); } return true; @@ -549,6 +533,37 @@ void ED_view3d_win_to_delta(const ARegion *ar, const float mval[2], float out[3] } /** + * Calculate a 3d origin from 2d window coordinates. + * \note Orthographic views have a less obvious origin, + * Since far clip can be a very large value resulting in numeric precision issues, + * the origin in this case is close to zero coordinate. + * + * \param ar The region (used for the window width and height). + * \param mval The area relative 2d location (such as event->mval converted to floats). + * \param out The resulting normalized world-space direction vector. + */ +void ED_view3d_win_to_origin(const ARegion *ar, const float mval[2], float out[3]) +{ + RegionView3D *rv3d = ar->regiondata; + if (rv3d->is_persp) { + copy_v3_v3(out, rv3d->viewinv[3]); + } + else { + out[0] = 2.0f * mval[0] / ar->winx - 1.0f; + out[1] = 2.0f * mval[1] / ar->winy - 1.0f; + + if (rv3d->persp == RV3D_CAMOB) { + out[2] = -1.0f; + } + else { + out[2] = 0.0f; + } + + mul_project_m4_v3(rv3d->persinv, out); + } +} + +/** * Calculate a 3d direction vector from 2d window coordinates. * This direction vector starts and the view in the direction of the 2d window coordinates. * In orthographic view all window coordinates yield the same vector. @@ -599,7 +614,7 @@ bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2 /* bounds clipping */ if (do_clip) { - return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end); + return ED_view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end); } return true; diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index e8e7d3c62fb..5dd69cc66eb 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -44,6 +44,7 @@ #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_object.h" +#include "BKE_report.h" #include "BKE_tracking.h" #include "WM_api.h" @@ -204,7 +205,7 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot) /* *************************************************** */ -static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) +static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset) { Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); @@ -213,15 +214,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) TransVertStore tvs = {NULL}; TransVert *tv; float imat[3][3], bmat[3][3]; - const float *cursor_global; float center_global[3]; float offset_global[3]; int a; - const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); - - cursor_global = ED_view3d_cursor3d_get(scene, v3d); - if (use_offset) { if ((v3d && v3d->around == V3D_AROUND_ACTIVE) && snap_calc_active_center(C, true, center_global)) @@ -231,11 +227,11 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) else { snap_curs_to_sel_ex(C, center_global); } - sub_v3_v3v3(offset_global, cursor_global, center_global); + sub_v3_v3v3(offset_global, snap_target_global, center_global); } if (obedit) { - float cursor_local[3]; + float snap_target_local[3]; if (ED_transverts_check_obedit(obedit)) ED_transverts_create_from_obedit(&tvs, obedit, 0); @@ -246,8 +242,8 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) invert_m3_m3(imat, bmat); /* get the cursor in object space */ - sub_v3_v3v3(cursor_local, cursor_global, obedit->obmat[3]); - mul_m3_v3(imat, cursor_local); + sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]); + mul_m3_v3(imat, snap_target_local); if (use_offset) { float offset_local[3]; @@ -262,7 +258,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) else { tv = tvs.transverts; for (a = 0; a < tvs.transverts_tot; a++, tv++) { - copy_v3_v3(tv->loc, cursor_local); + copy_v3_v3(tv->loc, snap_target_local); } } @@ -274,10 +270,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) bPoseChannel *pchan; bArmature *arm = obact->data; - float cursor_local[3]; + float snap_target_local[3]; invert_m4_m4(obact->imat, obact->obmat); - mul_v3_m4v3(cursor_local, obact->imat, cursor_global); + mul_v3_m4v3(snap_target_local, obact->imat, snap_target_global); for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { if ((pchan->bone->flag & BONE_SELECTED) && @@ -311,7 +307,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose); } else { - BKE_armature_loc_pose_to_bone(pchan, cursor_local, cursor_pose); + BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose); } /* copy new position */ @@ -367,7 +363,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global); } else { - copy_v3_v3(cursor_parent, cursor_global); + copy_v3_v3(cursor_parent, snap_target_global); } sub_v3_v3(cursor_parent, ob->obmat[3]); @@ -401,6 +397,18 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op) +{ + const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); + + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + + const float *snap_target_global = ED_view3d_cursor3d_get(scene, v3d); + + return snap_selected_to_location(C, snap_target_global, use_offset); +} + void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) { /* identifiers */ @@ -409,7 +417,7 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) ot->idname = "VIEW3D_OT_snap_selected_to_cursor"; /* api callbacks */ - ot->exec = snap_sel_to_curs_exec; + ot->exec = snap_selected_to_cursor_exec; ot->poll = ED_operator_view3d_active; /* flags */ @@ -419,6 +427,34 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", ""); } +static int snap_selected_to_active_exec(bContext *C, wmOperator *op) +{ + float snap_target_global[3]; + + if (snap_calc_active_center(C, false, snap_target_global) == false) { + BKE_report(op->reports, RPT_ERROR, "No active element found!"); + return OPERATOR_CANCELLED; + } + + return snap_selected_to_location(C, snap_target_global, false); +} + +void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Snap Selection to Active"; + ot->description = "Snap selected item(s) to the active item"; + ot->idname = "VIEW3D_OT_snap_selected_to_active"; + + /* api callbacks */ + ot->exec = snap_selected_to_active_exec; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + /* *************************************************** */ static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index fc32613c1ab..b7456facbdf 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -5273,13 +5273,9 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) skip_invert = true; if (skip_invert == false && constinv == false) { - if (constinv == false) - ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */ - + ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */ BKE_object_where_is_calc(t->scene, ob); - - if (constinv == false) - ob->transflag &= ~OB_NO_CONSTRAINTS; + ob->transflag &= ~OB_NO_CONSTRAINTS; } else BKE_object_where_is_calc(t->scene, ob); diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 59dfe18139a..1d4872cca7a 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -110,6 +110,12 @@ struct SnapObjectContext { }; +enum eViewProj { + VIEW_PROJ_NONE = -1, + VIEW_PROJ_ORTHO = 0, + VIEW_PROJ_PERSP = -1, +}; + static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); @@ -137,10 +143,6 @@ struct RayCastAll_Data { Object *ob; unsigned int ob_uuid; - /* DerivedMesh only */ - DerivedMesh *dm; - const struct MLoopTri *dm_looptri; - /* output data */ ListBase *hit_list; bool retval; @@ -218,76 +220,177 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH /* -------------------------------------------------------------------- */ -/** \name Internal Object Snapping API +/** \Common utilities * \{ */ + +/** + * Struct that kepts basic information about a BVHTree build from a editmesh. + */ +typedef struct BVHTreeFromMeshType { + void *userdata; + char type; +} BVHTreeFromMeshType; + +typedef struct PreDefProject { + float pmat[4][4]; /* perspective matrix multiplied by object matrix */ + float win_half[2]; + float dist_px_sq; +} PreDefProject; + +static void precalc_project( + PreDefProject *projectdefs, const ARegion *ar, + const float dist_px, float obmat[4][4]) +{ + float (*pmat)[4] = ((RegionView3D *)ar->regiondata)->persmat; + if (obmat) { + mul_m4_m4m4(projectdefs->pmat, pmat, obmat); + } + else { + copy_m4_m4(projectdefs->pmat, pmat); + } + projectdefs->win_half[0] = ar->winx / 2; + projectdefs->win_half[1] = ar->winy / 2; + projectdefs->dist_px_sq = SQUARE(dist_px); +} + +/** + * From a threshold (maximum distance to snap in pixels) returns: + * + * - The *real* distance (3D) if you are in orthographic-view. + * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view. + */ +static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px) +{ + const RegionView3D *rv3d = ar->regiondata; + if (ar->winx >= ar->winy) + return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0]; + else + return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1]; +} + +static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int index) +{ + switch (meshdata->type) { + case SNAP_MESH: + { + BVHTreeFromMesh *data = meshdata->userdata; + const MVert *vert = data->vert; + return vert[index].co; + } + case SNAP_EDIT_MESH: + { + BVHTreeFromEditMesh *data = meshdata->userdata; + BMVert *eve = BM_vert_at_index(data->em->bm, index); + return eve->co; + } + } + return NULL; +} + +static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3]) +{ + switch (meshdata->type) { + case SNAP_MESH: + { + BVHTreeFromMesh *data = meshdata->userdata; + const MVert *vert = data->vert; + normal_short_to_float_v3(r_no, vert->no); + break; + } + case SNAP_EDIT_MESH: + { + BVHTreeFromEditMesh *data = meshdata->userdata; + BMVert *eve = BM_vert_at_index(data->em->bm, index); + copy_v3_v3(r_no, eve->no); + break; + } + } +} + +static void get_edge_verts( + const BVHTreeFromMeshType *meshdata, const int index, + const float *v_pair[2]) +{ + switch (meshdata->type) { + case SNAP_MESH: + { + BVHTreeFromMesh *data = meshdata->userdata; + + const MVert *vert = data->vert; + const MEdge *edge = data->edge + index; + + v_pair[0] = vert[edge->v1].co; + v_pair[1] = vert[edge->v2].co; + break; + } + case SNAP_EDIT_MESH: + { + BVHTreeFromEditMesh *data = meshdata->userdata; + BMEdge *eed = BM_edge_at_index(data->em->bm, index); + + v_pair[0] = eed->v1->co; + v_pair[1] = eed->v2->co; + break; + } + } +} + #define V3_MUL_ELEM(a, b) \ (a)[0] * (b)[0], \ (a)[1] * (b)[1], \ (a)[2] * (b)[2] -static bool test_vert( - const float vco[3], const float vno[3], const float ray_co[3], const float ray_dir[3], - const float ray_depth_range[2], const float scale[3], const bool is_persp, +static bool test_vert_dist( + const float vco[3], const float ray_co[3], const float ray_dir[3], + const float ray_depth_range[2], const float scale[3], /* read/write args */ float *ray_depth, float *dist_to_ray_sq, /* return args */ - float r_co[3], float r_no[3]) + float r_co[3]) { const float vco_sc[3] = {V3_MUL_ELEM(vco, scale)}; - const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; + const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)}; - float depth; - float dist_sq = dist_squared_to_ray_v3(co_sc, dir_sc, vco_sc, &depth); + float depth, dist_sq; + dist_sq = dist_squared_to_ray_v3(origin_sc, dir_sc, vco_sc, &depth); if (depth < ray_depth_range[0]) { return false; } - if (is_persp) { - dist_sq /= SQUARE(depth); - } - if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) { *dist_to_ray_sq = dist_sq; copy_v3_v3(r_co, vco); - if (vno) { - copy_v3_v3(r_no, vno); - } - *ray_depth = depth; return true; } return false; } -static bool test_edge( +static bool test_edge_dist( const float v1[3], const float v2[3], const float ray_co[3], const float ray_dir[3], - const float ray_depth_range[2], const float scale[3], const bool is_persp, + const float ray_depth_range[2], const float scale[3], /* read/write args */ float *ray_depth, float *dist_to_ray_sq, /* return args */ - float r_co[3], float r_no[3]) + float r_co[3]) { const float v1_sc[3] = {V3_MUL_ELEM(v1, scale)}; const float v2_sc[3] = {V3_MUL_ELEM(v2, scale)}; const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)}; - float tmp_co[3], depth; - float dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth); + float tmp_co[3], depth, dist_sq; + dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth); if (depth < ray_depth_range[0]) { return false; } - if (is_persp) { - dist_sq /= SQUARE(depth); - } - if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) { *dist_to_ray_sq = dist_sq; @@ -297,10 +400,6 @@ static bool test_edge( copy_v3_v3(r_co, tmp_co); - if (r_no) { - sub_v3_v3v3(r_no, v1, v2); - } - *ray_depth = depth; return true; } @@ -309,50 +408,369 @@ static bool test_edge( #undef V3_MUL_ELEM +static bool test_projected_vert_dist( + PreDefProject *projectdefs, + const float co[3], const enum eViewProj view_proj, + const float mval[2], const float depth_range[2], + float r_co[3]) +{ + float depth; + float(*pmat)[4] = projectdefs->pmat; + if (view_proj == VIEW_PROJ_PERSP) { + depth = mul_project_m4_v3_zfac(pmat, co); + if (depth < depth_range[0] || depth > depth_range[1]) { + return false; + } + } + + float co2d[2] = { + (dot_m4_v3_row_x(pmat, co) + pmat[3][0]), + (dot_m4_v3_row_y(pmat, co) + pmat[3][1]), + }; + + if (view_proj == VIEW_PROJ_PERSP) { + mul_v2_fl(co2d, 1 / depth); + } + + co2d[0] += 1.0f; + co2d[1] += 1.0f; + co2d[0] *= projectdefs->win_half[0]; + co2d[1] *= projectdefs->win_half[1]; + + const float dist_sq = len_squared_v2v2(mval, co2d); + if (dist_sq < projectdefs->dist_px_sq) { + copy_v3_v3(r_co, co); + projectdefs->dist_px_sq = dist_sq; + return true; + } + return false; +} + +static bool test_projected_edge_dist( + PreDefProject *projectdefs, + const float va[3], const float vb[3], const float ray_start[3], const float ray_normal[3], + const enum eViewProj view_proj, const float mval[2], const float depth_range[2], + float r_co[3]) +{ + + float tmp_co[3], depth; + dist_squared_ray_to_seg_v3(ray_start, ray_normal, va, vb, tmp_co, &depth); + return test_projected_vert_dist(projectdefs, tmp_co, view_proj, mval, depth_range, r_co); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \Walk DFS + * \{ */ +typedef struct Object_Nearest2dPrecalc { + float ray_origin_local[3]; + float ray_direction_local[3]; + float ray_inv_dir[3]; + + PreDefProject projectdefs; + float mval[2]; + bool sign[3]; + bool r_axis_closest[3]; + float depth_range[2]; + + void *userdata; + int index; + float co[3]; + float no[3]; +} Object_Nearest2dPrecalc; + + +static void nearest2d_precalc( + Object_Nearest2dPrecalc *neasrest_precalc, const ARegion *ar, + const float dist_px, float obmat[4][4], + const float ray_origin_local[3], const float ray_direction_local[3], + const float mval[2], const float depth_range[2]) +{ + precalc_project(&neasrest_precalc->projectdefs, ar, dist_px, obmat); + copy_v3_v3(neasrest_precalc->ray_origin_local, ray_origin_local); + copy_v3_v3(neasrest_precalc->ray_direction_local, ray_direction_local); + copy_v2_v2(neasrest_precalc->mval, mval); + copy_v2_v2(neasrest_precalc->depth_range, depth_range); + + for (int i = 0; i < 3; i++) { + neasrest_precalc->ray_inv_dir[i] = + (neasrest_precalc->ray_direction_local[i] != 0.0f) ? + (1.0f / neasrest_precalc->ray_direction_local[i]) : FLT_MAX; + neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f); + neasrest_precalc->r_axis_closest[i] = true; + } +} + +static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data) +{ + Object_Nearest2dPrecalc *data = user_data; + float local_bvmin[3], local_bvmax[3]; + if (data->sign[0]) { + local_bvmin[0] = bounds[0].max; + local_bvmax[0] = bounds[0].min; + } + else { + local_bvmin[0] = bounds[0].min; + local_bvmax[0] = bounds[0].max; + } + if (data->sign[1]) { + local_bvmin[1] = bounds[1].max; + local_bvmax[1] = bounds[1].min; + } + else { + local_bvmin[1] = bounds[1].min; + local_bvmax[1] = bounds[1].max; + } + if (data->sign[2]) { + local_bvmin[2] = bounds[2].max; + local_bvmax[2] = bounds[2].min; + } + else { + local_bvmin[2] = bounds[2].min; + local_bvmax[2] = bounds[2].max; + } + + const float tmin[3] = { + (local_bvmin[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0], + (local_bvmin[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1], + (local_bvmin[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2], + }; + const float tmax[3] = { + (local_bvmax[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0], + (local_bvmax[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1], + (local_bvmax[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2], + }; + float va[3], vb[3]; + float rtmin, rtmax; + int main_axis; + + if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) { + rtmax = tmax[0]; + va[0] = vb[0] = local_bvmax[0]; + main_axis = 3; + data->r_axis_closest[0] = data->sign[0]; + } + else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) { + rtmax = tmax[1]; + va[1] = vb[1] = local_bvmax[1]; + main_axis = 2; + data->r_axis_closest[1] = data->sign[1]; + } + else { + rtmax = tmax[2]; + va[2] = vb[2] = local_bvmax[2]; + main_axis = 1; + data->r_axis_closest[2] = data->sign[2]; + } + + if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) { + rtmin = tmin[0]; + va[0] = vb[0] = local_bvmin[0]; + main_axis -= 3; + data->r_axis_closest[0] = !data->sign[0]; + } + else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) { + rtmin = tmin[1]; + va[1] = vb[1] = local_bvmin[1]; + main_axis -= 1; + data->r_axis_closest[1] = !data->sign[1]; + } + else { + rtmin = tmin[2]; + va[2] = vb[2] = local_bvmin[2]; + main_axis -= 2; + data->r_axis_closest[2] = !data->sign[2]; + } + if (main_axis < 0) { + main_axis += 3; + } + + /* if rtmin < rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { +#ifdef IGNORE_BEHIND_RAY + /* `if rtmax < depth_min`, the whole `AABB` is behind us */ + if (rtmax < min_depth) { + return fallback; + } +#endif + const float proj = rtmin * data->ray_direction_local[main_axis]; + data->r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj); + return true; + } +#ifdef IGNORE_BEHIND_RAY + /* `if rtmin < depth_min`, the whole `AABB` is behing us */ + else if (rtmin < min_depth) { + return fallback; + } +#endif + if (data->sign[main_axis]) { + va[main_axis] = local_bvmax[main_axis]; + vb[main_axis] = local_bvmin[main_axis]; + } + else { + va[main_axis] = local_bvmin[main_axis]; + vb[main_axis] = local_bvmax[main_axis]; + } + float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]); + + float (*pmat)[4] = data->projectdefs.pmat; + float depth_a = mul_project_m4_v3_zfac(pmat, va); + float depth_b = depth_a + pmat[main_axis][3] * scale; + + float va2d[2] = { + (dot_m4_v3_row_x(pmat, va) + pmat[3][0]), + (dot_m4_v3_row_y(pmat, va) + pmat[3][1]), + }; + float vb2d[2] = { + (va2d[0] + pmat[main_axis][0] * scale) / depth_b, + (va2d[1] + pmat[main_axis][1] * scale) / depth_b, + }; + + va2d[0] /= depth_a; + va2d[1] /= depth_a; + + va2d[0] += 1.0f; + va2d[1] += 1.0f; + vb2d[0] += 1.0f; + vb2d[1] += 1.0f; + + va2d[0] *= data->projectdefs.win_half[0]; + va2d[1] *= data->projectdefs.win_half[1]; + vb2d[0] *= data->projectdefs.win_half[0]; + vb2d[1] *= data->projectdefs.win_half[1]; + + //float dvec[2], edge[2], rdist; + //sub_v2_v2v2(dvec, data->mval, va2d); + //sub_v2_v2v2(edge, vb2d, va2d); + float rdist; + short dvec[2] = {data->mval[0] - va2d[0], data->mval[1] - va2d[1]}; + short edge[2] = {vb2d[0] - va2d[0], vb2d[1] - va2d[1]}; + float lambda = dvec[0] * edge[0] + dvec[1] * edge[1]; + if (lambda != 0.0f) { + lambda /= edge[0] * edge[0] + edge[1] * edge[1]; + if (lambda <= 0.0f) { + rdist = len_squared_v2v2(data->mval, va2d); + data->r_axis_closest[main_axis] = true; + } + else if (lambda >= 1.0f) { + rdist = len_squared_v2v2(data->mval, vb2d); + data->r_axis_closest[main_axis] = false; + } + else { + va2d[0] += edge[0] * lambda; + va2d[1] += edge[1] * lambda; + rdist = len_squared_v2v2(data->mval, va2d); + data->r_axis_closest[main_axis] = lambda < 0.5f; + } + } + else { + rdist = len_squared_v2v2(data->mval, va2d); + } + return rdist < data->projectdefs.dist_px_sq; +} + +static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata) +{ + struct Object_Nearest2dPrecalc *neasrest_precalc = userdata; + const float co[3] = { + (bounds[0].min + bounds[0].max) / 2, + (bounds[1].min + bounds[1].max) / 2, + (bounds[2].min + bounds[2].max) / 2, + }; + + /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP) + * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO), + * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/ + if (test_projected_vert_dist( + &neasrest_precalc->projectdefs, co, VIEW_PROJ_PERSP, + neasrest_precalc->mval, neasrest_precalc->depth_range, + neasrest_precalc->co)) + { + copy_vert_no(neasrest_precalc->userdata, index, neasrest_precalc->no); + neasrest_precalc->index = index; + } + return true; +} + +static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata) +{ + struct Object_Nearest2dPrecalc *neasrest_precalc = userdata; + + const float *v_pair[2]; + get_edge_verts(neasrest_precalc->userdata, index, v_pair); + + /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP) + * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO), + * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/ + if (test_projected_edge_dist( + &neasrest_precalc->projectdefs, v_pair[0], v_pair[1], + neasrest_precalc->ray_origin_local, neasrest_precalc->ray_direction_local, + VIEW_PROJ_PERSP, neasrest_precalc->mval, neasrest_precalc->depth_range, + neasrest_precalc->co)) + { + sub_v3_v3v3(neasrest_precalc->no, v_pair[0], v_pair[1]); + neasrest_precalc->index = index; + } + return true; +} + +static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char axis, void *userdata) +{ + const bool *r_axis_closest = ((struct Object_Nearest2dPrecalc *)userdata)->r_axis_closest; + return r_axis_closest[axis]; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Internal Object Snapping API + * \{ */ + static bool snapArmature( - Object *ob, bArmature *arm, float obmat[4][4], - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2], + const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], + const short snap_to, const float origin[3], const float dir[3], + const float mval[2], const enum eViewProj view_proj, const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *dist_px, /* return args */ float r_loc[3], float *UNUSED(r_no)) { - float imat[4][4]; - float ray_origin_local[3], ray_normal_local[3]; bool retval = false; - invert_m4_m4(imat, obmat); + float ray_start_local[3], ray_normal_local[3]; + if (snap_to != SCE_SNAP_MODE_VERTEX) { + float imat[4][4]; + invert_m4_m4(imat, obmat); - mul_v3_m4v3(ray_origin_local, imat, ray_origin); - mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); + copy_v3_v3(ray_start_local, origin); + copy_v3_v3(ray_normal_local, dir); + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + } - float ob_scale[3]; - mat4_to_size(ob_scale, obmat); + PreDefProject projectdefs; + precalc_project(&projectdefs, ar, *dist_px, obmat); if (arm->edbo) { - EditBone *eBone; - - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { + for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) { if (eBone->layer & arm->layer) { /* skip hidden or moving (selected) bones */ if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) { switch (snap_to) { case SCE_SNAP_MODE_VERTEX: - retval |= test_vert( - eBone->head, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); - retval |= test_vert( - eBone->tail, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, eBone->head, view_proj, mval, depth_range, r_loc); + retval |= test_projected_vert_dist( + &projectdefs, eBone->tail, view_proj, mval, depth_range, r_loc); break; case SCE_SNAP_MODE_EDGE: - retval |= test_edge( - eBone->head, eBone->tail, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_edge_dist( + &projectdefs, eBone->head, eBone->tail, ray_start_local, ray_normal_local, + view_proj, mval, depth_range, r_loc); break; } } @@ -360,11 +778,8 @@ static bool snapArmature( } } else if (ob->pose && ob->pose->chanbase.first) { - bPoseChannel *pchan; - Bone *bone; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - bone = pchan->bone; + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + Bone *bone = pchan->bone; /* skip hidden bones */ if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { const float *head_vec = pchan->pose_head; @@ -372,26 +787,22 @@ static bool snapArmature( switch (snap_to) { case SCE_SNAP_MODE_VERTEX: - retval |= test_vert( - head_vec, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); - retval |= test_vert( - tail_vec, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, head_vec, view_proj, mval, depth_range, r_loc); + retval |= test_projected_vert_dist( + &projectdefs, tail_vec, view_proj, mval, depth_range, r_loc); break; case SCE_SNAP_MODE_EDGE: - retval |= test_edge( - head_vec, tail_vec, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_edge_dist( + &projectdefs, head_vec, tail_vec, ray_start_local, ray_normal_local, + view_proj, mval, depth_range, r_loc); break; } } } } if (retval) { + *dist_px = sqrtf(projectdefs.dist_px_sq); mul_m4_v3(obmat, r_loc); return true; } @@ -399,39 +810,26 @@ static bool snapArmature( } static bool snapCurve( - Object *ob, Curve *cu, float obmat[4][4], - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2], + const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *dist_px, /* return args */ float r_loc[3], float *UNUSED(r_no)) { - float imat[4][4]; - float ray_origin_local[3], ray_normal_local[3]; bool retval = false; - int u; - - Nurb *nu; /* only vertex snapping mode (eg control points and handles) supported for now) */ if (snap_to != SCE_SNAP_MODE_VERTEX) { return retval; } - invert_m4_m4(imat, obmat); - - copy_v3_v3(ray_origin_local, ray_origin); - copy_v3_v3(ray_normal_local, ray_normal); - - mul_m4_v3(imat, ray_origin_local); - mul_mat3_m4_v3(imat, ray_normal_local); - - float ob_scale[3]; - mat4_to_size(ob_scale, obmat); + PreDefProject projectdefs; + precalc_project(&projectdefs, ar, *dist_px, obmat); - for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { - for (u = 0; u < nu->pntsu; u++) { + for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { + for (int u = 0; u < nu->pntsu; u++) { switch (snap_to) { case SCE_SNAP_MODE_VERTEX: { @@ -441,26 +839,20 @@ static bool snapCurve( if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { break; } - retval |= test_vert( - nu->bezt[u].vec[1], NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc); /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */ if (!(nu->bezt[u].f1 & SELECT) && !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) { - retval |= test_vert( - nu->bezt[u].vec[0], NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[0], view_proj, mval, depth_range, r_loc); } if (!(nu->bezt[u].f3 & SELECT) && !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) { - retval |= test_vert( - nu->bezt[u].vec[2], NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[2], view_proj, mval, depth_range, r_loc); } } else { @@ -468,26 +860,20 @@ static bool snapCurve( if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) { break; } - retval |= test_vert( - nu->bp[u].vec, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc); } } else { /* curve is not visible outside editmode if nurb length less than two */ if (nu->pntsu > 1) { if (nu->bezt) { - retval |= test_vert( - nu->bezt[u].vec[1], NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc); } else { - retval |= test_vert( - nu->bp[u].vec, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc); } } } @@ -499,6 +885,7 @@ static bool snapCurve( } } if (retval) { + *dist_px = sqrtf(projectdefs.dist_px_sq); mul_m4_v3(obmat, r_loc); return true; } @@ -507,11 +894,11 @@ static bool snapCurve( /* may extend later (for now just snaps to empty center) */ static bool snapEmpty( - Object *ob, float obmat[4][4], - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2], + const ARegion *ar, Object *ob, float obmat[4][4], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *dist_px, /* return args */ float r_loc[3], float *UNUSED(r_no)) { @@ -520,17 +907,19 @@ static bool snapEmpty( if (ob->transflag & OB_DUPLI) { return retval; } + /* for now only vertex supported */ switch (snap_to) { case SCE_SNAP_MODE_VERTEX: { - float ob_loc[3], ob_scale[3] = {1.0, 1.0, 1.0}; - copy_v3_v3(ob_loc, obmat[3]); - - retval |= test_vert( - ob_loc, NULL, ray_origin, ray_normal, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); + PreDefProject projectdefs; + precalc_project(&projectdefs, ar, *dist_px, NULL); + float tmp_co[3]; + copy_v3_v3(tmp_co, obmat[3]); + if (test_projected_vert_dist(&projectdefs, tmp_co, view_proj, mval, depth_range, r_loc)) { + *dist_px = sqrtf(projectdefs.dist_px_sq); + retval = true; + } break; } default: @@ -541,19 +930,23 @@ static bool snapEmpty( } static bool snapCamera( - Scene *scene, Object *object, float obmat[4][4], - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2], + const SnapObjectContext *sctx, Object *object, float obmat[4][4], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *dist_px, /* return args */ float r_loc[3], float *UNUSED(r_no)) { + Scene *scene = sctx->scene; + + PreDefProject projectdefs; + precalc_project(&projectdefs, sctx->v3d_data.ar, *dist_px, NULL); + float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4]; bool retval = false; MovieClip *clip = BKE_object_movieclip_get(scene, object, false); MovieTracking *tracking; - float ray_origin_local[3], ray_normal_local[3]; if (clip == NULL) { return retval; @@ -584,9 +977,6 @@ static bool snapCamera( reconstructed_camera_imat[4][4]; float (*vertex_obmat)[4]; - copy_v3_v3(ray_origin_local, ray_origin); - copy_v3_v3(ray_normal_local, ray_normal); - if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, CFRA, reconstructed_camera_mat); @@ -603,26 +993,16 @@ static bool snapCamera( copy_v3_v3(bundle_pos, track->bundle_pos); if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { - mul_m4_v3(orig_camera_imat, ray_origin_local); - mul_mat3_m4_v3(orig_camera_imat, ray_normal_local); vertex_obmat = orig_camera_mat; } else { mul_m4_v3(reconstructed_camera_imat, bundle_pos); - mul_m4_v3(imat, ray_origin_local); - mul_mat3_m4_v3(imat, ray_normal_local); vertex_obmat = obmat; } - float ob_scale[3]; - mat4_to_size(ob_scale, vertex_obmat); - - retval |= test_vert( - bundle_pos, NULL, ray_origin_local, ray_normal_local, - ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq, - r_loc, NULL); - - mul_m4_v3(vertex_obmat, r_loc); + mul_m4_v3(vertex_obmat, bundle_pos); + retval |= test_projected_vert_dist( + &projectdefs, bundle_pos, view_proj, mval, depth_range, r_loc); } } @@ -632,7 +1012,11 @@ static bool snapCamera( break; } - return retval; + if (retval) { + *dist_px = sqrtf(projectdefs.dist_px_sq); + return true; + } + return false; } static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) @@ -643,44 +1027,45 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) struct NearestDM_Data { void *bvhdata; - bool is_persp; - const float *ray_depth_range; - + const float *depth_range; float *ray_depth; }; -static void test_vert_depth_cb( +static void test_vert_ray_dist_cb( void *userdata, const float origin[3], const float dir[3], const float scale[3], int index, BVHTreeNearest *nearest) { struct NearestDM_Data *ndata = userdata; - const BVHTreeFromMesh *data = ndata->bvhdata; - const MVert *vert = data->vert + index; + const struct BVHTreeFromMeshType *data = ndata->bvhdata; + + const float *co = get_vert_co(data, index); - if (test_vert( - vert->co, NULL, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, - ndata->ray_depth, &nearest->dist_sq, - nearest->co, NULL)) + if (test_vert_dist( + co, origin, dir, ndata->depth_range, + scale, ndata->ray_depth, &nearest->dist_sq, + nearest->co)) { - normal_short_to_float_v3(nearest->no, vert->no); + copy_vert_no(data, index, nearest->no); nearest->index = index; } } -static void test_edge_depth_cb( +static void test_edge_ray_dist_cb( void *userdata, const float origin[3], const float dir[3], const float scale[3], int index, BVHTreeNearest *nearest) { struct NearestDM_Data *ndata = userdata; - const BVHTreeFromMesh *data = ndata->bvhdata; - const MVert *vert = data->vert; - const MEdge *edge = data->edge + index; - - if (test_edge( - vert[edge->v1].co, vert[edge->v2].co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, - ndata->ray_depth, &nearest->dist_sq, - nearest->co, nearest->no)) + BVHTreeFromMeshType *data = ndata->bvhdata; + + const float *v_pair[2]; + get_edge_verts(data, index, v_pair); + + if (test_edge_dist( + v_pair[0], v_pair[1], origin, dir, ndata->depth_range, + scale, ndata->ray_depth, &nearest->dist_sq, + nearest->co)) { + sub_v3_v3v3(nearest->no, v_pair[0], v_pair[1]); nearest->index = index; } } @@ -688,10 +1073,11 @@ static void test_edge_depth_cb( static bool snapDerivedMesh( SnapObjectContext *sctx, Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index, - const short snap_to, const bool is_persp, bool do_bb, - const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2], + const short snap_to, const float mval[2], const enum eViewProj view_proj, bool do_bb, + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, ListBase *r_hit_list) @@ -703,7 +1089,7 @@ static bool snapDerivedMesh( return retval; } } - if (snap_to == SCE_SNAP_MODE_EDGE) { + else if (snap_to == SCE_SNAP_MODE_EDGE) { if (dm->getNumEdges(dm) == 0) { return retval; } @@ -715,7 +1101,7 @@ static bool snapDerivedMesh( } { - bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && sctx->use_v3d && !is_persp; + bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && (view_proj == VIEW_PROJ_ORTHO); float imat[4][4]; float timat[3][3]; /* transpose inverse matrix for normals */ @@ -823,28 +1209,30 @@ static bool snapDerivedMesh( } } + if (!treedata || !treedata->tree) { + return retval; + } + if (snap_to == SCE_SNAP_MODE_FACE) { /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already * been *inside* boundbox, leading to snap failures (see T38409). * Note also ar might be null (see T38435), in this case we assume ray_start is ok! */ - if (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */ + if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ if (need_ray_start_correction_init) { /* We *need* a reasonably valid len_diff in this case. * Use BHVTree to find the closest face from ray_start_local. */ - if (treedata && treedata->tree != NULL) { - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); - if (nearest.index != -1) { - float dvec[3]; - sub_v3_v3v3(dvec, nearest.co, ray_start_local); - len_diff = dot_v3v3(dvec, ray_normal_local); - } + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); + if (nearest.index != -1) { + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); } } float ray_org_local[3]; @@ -856,8 +1244,8 @@ static bool snapDerivedMesh( * away ray_start values (as returned in case of ortho view3d), see T38358. */ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, - len_diff + ray_depth_range[0]); + madd_v3_v3v3fl( + ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale); local_depth -= len_diff; } else { @@ -874,24 +1262,19 @@ static bool snapDerivedMesh( data.local_scale = local_scale; data.ob = ob; data.ob_uuid = ob_index; - data.dm = dm; data.hit_list = r_hit_list; data.retval = retval; BLI_bvhtree_ray_cast_all( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - *ray_depth, raycast_all_cb, &data); + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); retval = data.retval; } else { - BVHTreeRayHit hit; + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; - hit.index = -1; - hit.dist = local_depth; - - if (treedata->tree && - BLI_bvhtree_ray_cast( + if (BLI_bvhtree_ray_cast( treedata->tree, ray_start_local, ray_normal_local, 0.0f, &hit, treedata->raycast_callback, treedata) != -1) { @@ -900,12 +1283,15 @@ static bool snapDerivedMesh( if (hit.dist <= *ray_depth) { *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - copy_v3_v3(r_no, hit.no); /* back to worldspace */ mul_m4_v3(obmat, r_loc); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); + + if (r_no) { + copy_v3_v3(r_no, hit.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } retval = true; @@ -917,51 +1303,78 @@ static bool snapDerivedMesh( } } else { - /* Vert & edge use nearly identical logic. */ - BLI_assert(ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)); + const ARegion *ar = sctx->v3d_data.ar; float ray_org_local[3]; - copy_v3_v3(ray_org_local, ray_origin); mul_m4_v3(imat, ray_org_local); - BVHTreeNearest nearest; + BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_MESH}; - nearest.index = -1; - nearest.dist_sq = *dist_to_ray_sq; + if (view_proj == VIEW_PROJ_PERSP) { + Object_Nearest2dPrecalc neasrest_precalc; + neasrest_precalc.userdata = &treedata_type; + neasrest_precalc.index = -1; - struct NearestDM_Data userdata; - userdata.bvhdata = treedata; - userdata.is_persp = is_persp; - userdata.ray_depth_range = ray_depth_range; - userdata.ray_depth = ray_depth; + nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat, + ray_org_local, ray_normal_local, mval, depth_range); - float ob_scale[3]; - mat4_to_size(ob_scale, obmat); + BVHTree_WalkLeafCallback cb_walk_leaf = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - BVHTree_NearestToRayCallback callback = - (snap_to == SCE_SNAP_MODE_VERTEX) ? - test_vert_depth_cb : test_edge_depth_cb; + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc); - if (treedata->tree && - (is_persp ? - BLI_bvhtree_find_nearest_to_ray_angle( - treedata->tree, ray_org_local, ray_normal_local, - true, ob_scale, &nearest, callback, &userdata) : - BLI_bvhtree_find_nearest_to_ray( - treedata->tree, ray_org_local, ray_normal_local, - true, ob_scale, &nearest, callback, &userdata)) != -1) - { - copy_v3_v3(r_loc, nearest.co); - mul_m4_v3(obmat, r_loc); - if (r_no) { - copy_v3_v3(r_no, nearest.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); + if (neasrest_precalc.index != -1) { + copy_v3_v3(r_loc, neasrest_precalc.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest_precalc.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq); + + retval = true; } - *dist_to_ray_sq = nearest.dist_sq; + } + else { + BVHTreeNearest nearest; - retval = true; + nearest.index = -1; + float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px); + nearest.dist_sq = SQUARE(dist_3d); + + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + struct NearestDM_Data userdata; + userdata.bvhdata = &treedata_type; + userdata.depth_range = depth_range; + userdata.ray_depth = ray_depth; + + BVHTree_NearestToRayCallback cb_test_ray_dist = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + test_vert_ray_dist_cb : test_edge_ray_dist_cb; + + if (BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_org_local, ray_normal_local, + true, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1) + { + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px *= sqrtf(nearest.dist_sq) / dist_3d; + + retval = true; + } } } @@ -975,47 +1388,14 @@ static bool snapDerivedMesh( return retval; } -static void test_bmvert_depth_cb( - void *userdata, const float origin[3], const float dir[3], - const float scale[3], int index, BVHTreeNearest *nearest) -{ - struct NearestDM_Data *ndata = userdata; - const BMEditMesh *em = ndata->bvhdata; - BMVert *eve = BM_vert_at_index(em->bm, index); - - if (test_vert( - eve->co, eve->no, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, - ndata->ray_depth, &nearest->dist_sq, - nearest->co, nearest->no)) - { - nearest->index = index; - } -} - -static void test_bmedge_depth_cb( - void *userdata, const float origin[3], const float dir[3], - const float scale[3], int index, BVHTreeNearest *nearest) -{ - struct NearestDM_Data *ndata = userdata; - const BMEditMesh *em = ndata->bvhdata; - BMEdge *eed = BM_edge_at_index(em->bm, index); - - if (test_edge( - eed->v1->co, eed->v2->co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, - ndata->ray_depth, &nearest->dist_sq, - nearest->co, nearest->no)) - { - nearest->index = index; - } -} - static bool snapEditMesh( SnapObjectContext *sctx, Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index, - const short snap_to, const bool is_persp, - const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, ListBase *r_hit_list) @@ -1143,6 +1523,10 @@ static bool snapEditMesh( } } + if (!treedata || !treedata->tree) { + return retval; + } + if (snap_to == SCE_SNAP_MODE_FACE) { float ray_start_local[3]; copy_v3_v3(ray_start_local, ray_start); @@ -1160,35 +1544,33 @@ static bool snapEditMesh( * Note also ar might be null (see T38435), in this case we assume ray_start is ok! */ float len_diff = 0.0f; - if (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */ + if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ /* We *need* a reasonably valid len_diff in this case. * Use BHVTree to find the closest face from ray_start_local. */ - if (treedata && treedata->tree != NULL) { - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - if (BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1) - { - float dvec[3]; - sub_v3_v3v3(dvec, nearest.co, ray_start_local); - len_diff = dot_v3v3(dvec, ray_normal_local); - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, ray_origin); - mul_m4_v3(imat, ray_org_local); - - /* We pass a temp ray_start, set from object's boundbox, - * to avoid precision issues with very far away ray_start values - * (as returned in case of ortho view3d), see T38358. - */ - len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, - len_diff + ray_depth_range[0]); - local_depth -= len_diff; - } + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + if (BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1) + { + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + /* We pass a temp ray_start, set from object's boundbox, + * to avoid precision issues with very far away ray_start values + * (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3v3fl( + ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale); + local_depth -= len_diff; } } if (r_hit_list) { @@ -1202,7 +1584,6 @@ static bool snapEditMesh( data.local_scale = local_scale; data.ob = ob; data.ob_uuid = ob_index; - data.dm = NULL; data.hit_list = r_hit_list; data.retval = retval; @@ -1213,13 +1594,9 @@ static bool snapEditMesh( retval = data.retval; } else { - BVHTreeRayHit hit; + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; - hit.index = -1; - hit.dist = local_depth; - - if (treedata->tree && - BLI_bvhtree_ray_cast( + if (BLI_bvhtree_ray_cast( treedata->tree, ray_start_local, ray_normal_local, 0.0f, &hit, treedata->raycast_callback, treedata) != -1) { @@ -1228,12 +1605,15 @@ static bool snapEditMesh( if (hit.dist <= *ray_depth) { *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - copy_v3_v3(r_no, hit.no); /* back to worldspace */ mul_m4_v3(obmat, r_loc); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); + + if (r_no) { + copy_v3_v3(r_no, hit.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } retval = true; @@ -1245,51 +1625,78 @@ static bool snapEditMesh( } } else { - /* Vert & edge use nearly identical logic. */ - BLI_assert(ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)); + const ARegion *ar = sctx->v3d_data.ar; float ray_org_local[3]; - copy_v3_v3(ray_org_local, ray_origin); mul_m4_v3(imat, ray_org_local); - BVHTreeNearest nearest; + BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_EDIT_MESH}; - nearest.index = -1; - nearest.dist_sq = *dist_to_ray_sq; + if (view_proj == VIEW_PROJ_PERSP) { + Object_Nearest2dPrecalc neasrest_precalc; + neasrest_precalc.userdata = &treedata_type; + neasrest_precalc.index = -1; - struct NearestDM_Data userdata; - userdata.bvhdata = em; - userdata.is_persp = is_persp; - userdata.ray_depth_range = ray_depth_range; - userdata.ray_depth = ray_depth; + nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat, + ray_org_local, ray_normal_local, mval, depth_range); - float ob_scale[3]; - mat4_to_size(ob_scale, obmat); + BVHTree_WalkLeafCallback cb_walk_leaf = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - BVHTree_NearestToRayCallback callback = - (snap_to == SCE_SNAP_MODE_VERTEX) ? - test_bmvert_depth_cb : test_bmedge_depth_cb; + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc); - if (treedata->tree && - (is_persp ? - BLI_bvhtree_find_nearest_to_ray_angle( - treedata->tree, ray_org_local, ray_normal_local, - false, ob_scale, &nearest, callback, &userdata) : - BLI_bvhtree_find_nearest_to_ray( - treedata->tree, ray_org_local, ray_normal_local, - false, ob_scale, &nearest, callback, &userdata)) != -1) - { - copy_v3_v3(r_loc, nearest.co); - mul_m4_v3(obmat, r_loc); - if (r_no) { - copy_v3_v3(r_no, nearest.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); + if (neasrest_precalc.index != -1) { + copy_v3_v3(r_loc, neasrest_precalc.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest_precalc.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq); + + retval = true; } - *dist_to_ray_sq = nearest.dist_sq; + } + else { + BVHTreeNearest nearest; - retval = true; + nearest.index = -1; + float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px); + nearest.dist_sq = SQUARE(dist_3d); + + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + struct NearestDM_Data userdata; + userdata.bvhdata = &treedata_type; + userdata.depth_range = depth_range; + userdata.ray_depth = ray_depth; + + BVHTree_NearestToRayCallback cb_test_ray_dist = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + test_vert_ray_dist_cb : test_edge_ray_dist_cb; + + if (BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_org_local, ray_normal_local, + false, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1) + { + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px *= sqrtf(nearest.dist_sq) / dist_3d; + + retval = true; + } } } @@ -1305,26 +1712,28 @@ static bool snapEditMesh( /** * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; - * \param ray_depth_range: - * - 0: distance from the ray_origin to the clipping plane min (can be negative). - * - 1: maximum distance, elements outside this are ignored. - * \param ray_depth: maximum depth allowed for r_co. * * \note Duplicate args here are documented at #snapObjectsRay */ static bool snapObject( SnapObjectContext *sctx, Object *ob, float obmat[4][4], const unsigned int ob_index, - bool use_obedit, const short snap_to, - const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2], + bool use_obedit, const short snap_to, const float mval[2], + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4], ListBase *r_hit_list) { - const bool is_persp = sctx->use_v3d && ((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp; + const enum eViewProj view_proj = + ((sctx->use_v3d == false) || (mval == NULL)) ? VIEW_PROJ_NONE : + (((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO); + + const ARegion *ar = sctx->v3d_data.ar; + bool retval = false; if (ob->type == OB_MESH) { @@ -1334,9 +1743,9 @@ static bool snapObject( em = BKE_editmesh_from_object(ob); retval = snapEditMesh( sctx, ob, em, obmat, ob_index, - snap_to, is_persp, - ray_origin, ray_start, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, + snap_to, mval, view_proj, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_hit_list); } @@ -1353,42 +1762,43 @@ static bool snapObject( } retval = snapDerivedMesh( sctx, ob, dm, obmat, ob_index, - snap_to, is_persp, true, - ray_origin, ray_start, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, + snap_to, mval, view_proj, true, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_hit_list); dm->release(dm); } } - else if (ob->type == OB_ARMATURE) { - retval = snapArmature( - ob, ob->data, obmat, snap_to, is_persp, - ray_origin, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, - r_loc, r_no); - } - else if (ob->type == OB_CURVE) { - retval = snapCurve( - ob, ob->data, obmat, snap_to, is_persp, - ray_origin, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, - r_loc, r_no); - } - else if (ob->type == OB_EMPTY) { - retval = snapEmpty( - ob, obmat, snap_to, is_persp, - ray_origin, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, - r_loc, r_no); - } - else if (ob->type == OB_CAMERA) { - retval = snapCamera( - sctx->scene, ob, obmat, snap_to, is_persp, - ray_origin, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, - r_loc, r_no); + else if (snap_to != SCE_SNAP_MODE_FACE) { + if (ob->type == OB_ARMATURE) { + retval = snapArmature( + ar, ob, ob->data, obmat, snap_to, ray_origin, ray_normal, + mval, view_proj, depth_range, dist_px, + r_loc, r_no); + } + else if (ob->type == OB_CURVE) { + retval = snapCurve( + ar, ob, ob->data, obmat, snap_to, mval, view_proj, + depth_range, + dist_px, + r_loc, r_no); + } + else if (ob->type == OB_EMPTY) { + retval = snapEmpty( + ar, ob, obmat, snap_to, mval, view_proj, + depth_range, + dist_px, + r_loc, r_no); + } + else if (ob->type == OB_CAMERA) { + retval = snapCamera( + sctx, ob, obmat, snap_to, mval, view_proj, + depth_range, + dist_px, + r_loc, r_no); + } } if (retval) { @@ -1414,16 +1824,18 @@ static bool snapObject( * \param snap_select: from enum SnapSelect. * * \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping. + * \param mval: Mouse coords. + * When NULL, ray-casting is handled without any projection matrix correction. * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min. * \param ray_start: ray_origin moved for the start clipping plane (clip_min). * \param ray_normal: Unit length direction of the ray. + * \param depth_range: distances of clipe plane min and clip plane max; * * Read/Write Args * --------------- * * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored. - * \param dist_to_ray_sq: Real distance (3D) or Tangent (view cone radius at distance 1.0) squared. - * resulting of the function #dist_px_to_dist3d_or_tangent. + * \param dist_px: Maximum threshold distance (in pixels). * * Output Args * ----------- @@ -1440,10 +1852,11 @@ static bool snapObject( static bool snapObjectsRay( SnapObjectContext *sctx, const unsigned short snap_to, const SnapSelect snap_select, - const bool use_object_edit_cage, + const bool use_object_edit_cage, const float mval[2], const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], /* read/write args */ - float *ray_depth, float *dist_to_ray_sq, + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4], @@ -1451,14 +1864,6 @@ static bool snapObjectsRay( { bool retval = false; - float dvec[3]; - sub_v3_v3v3(dvec, ray_start, ray_origin); - - const float ray_depth_range[2] = { - dot_v3v3(dvec, ray_normal), - *ray_depth, - }; - unsigned int ob_index = 0; Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; @@ -1473,9 +1878,9 @@ static bool snapObjectsRay( retval |= snapObject( sctx, ob, ob->obmat, ob_index++, - false, snap_to, - ray_origin, ray_start, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, + false, snap_to, mval, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } @@ -1509,9 +1914,9 @@ static bool snapObjectsRay( retval |= snapObject( sctx, dupli_snap, dupli_ob->mat, ob_index++, - use_obedit_dupli, snap_to, - ray_origin, ray_start, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, + use_obedit_dupli, snap_to, mval, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } @@ -1523,9 +1928,9 @@ static bool snapObjectsRay( retval |= snapObject( sctx, ob_snap, ob->obmat, ob_index++, - use_obedit, snap_to, - ray_origin, ray_start, ray_normal, ray_depth_range, - ray_depth, dist_to_ray_sq, + use_obedit, snap_to, mval, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } } @@ -1632,13 +2037,12 @@ bool ED_transform_snap_object_project_ray_ex( float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { - float dist_to_ray_sq = 0.0f; - + const float depth_range[2] = {0.0f, FLT_MAX}; return snapObjectsRay( sctx, - snap_to, params->snap_select, params->use_object_edit_cage, - ray_start, ray_start, ray_normal, - ray_depth, &dist_to_ray_sq, + snap_to, params->snap_select, params->use_object_edit_cage, NULL, + ray_start, ray_start, ray_normal, depth_range, + ray_depth, NULL, r_loc, r_no, r_index, r_ob, r_obmat, NULL); } @@ -1657,8 +2061,7 @@ bool ED_transform_snap_object_project_ray_all( float ray_depth, bool sort, ListBase *r_hit_list) { - float dist_to_ray_sq = 0.0f; - + const float depth_range[2] = {0.0f, FLT_MAX}; if (ray_depth == -1.0f) { ray_depth = BVH_RAYCAST_DIST_MAX; } @@ -1669,9 +2072,9 @@ bool ED_transform_snap_object_project_ray_all( bool retval = snapObjectsRay( sctx, - snap_to, params->snap_select, params->use_object_edit_cage, - ray_start, ray_start, ray_normal, - &ray_depth, &dist_to_ray_sq, + snap_to, params->snap_select, params->use_object_edit_cage, NULL, + ray_start, ray_start, ray_normal, depth_range, + &ray_depth, NULL, NULL, NULL, NULL, NULL, NULL, r_hit_list); @@ -1726,11 +2129,6 @@ bool ED_transform_snap_object_project_ray( ray_depth = &ray_depth_fallback; } - float no_fallback[3]; - if (r_no == NULL) { - r_no = no_fallback; - } - return transform_snap_context_project_ray_impl( sctx, params, @@ -1749,11 +2147,6 @@ static bool transform_snap_context_project_view3d_mixed_impl( float ray_depth = BVH_RAYCAST_DIST_MAX; bool is_hit = false; - float r_no_dummy[3]; - if (r_no == NULL) { - r_no = r_no_dummy; - } - const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE}; BLI_assert(snap_to_flag != 0); @@ -1780,21 +2173,6 @@ static bool transform_snap_context_project_view3d_mixed_impl( } /** - * From a threshold (maximum distance to snap in pixels) returns: - * - * - The *real* distance (3D) if you are in orthographic-view. - * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view. - */ -static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px) -{ - const RegionView3D *rv3d = ar->regiondata; - if (ar->winx >= ar->winy) - return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0]; - else - return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1]; -} - -/** * Convenience function for performing snapping. * * Given a 2D region value, snap to vert/edge/face. @@ -1830,55 +2208,37 @@ bool ED_transform_snap_object_project_view3d_ex( float *ray_depth, float r_loc[3], float r_no[3], int *r_index) { - float ray_start[3], ray_normal[3], ray_origin[3]; + float ray_origin[3], ray_start[3], ray_normal[3], depth_range[2], ray_end[3]; - float ray_depth_fallback; - if (ray_depth == NULL) { - ray_depth_fallback = BVH_RAYCAST_DIST_MAX; - ray_depth = &ray_depth_fallback; - } + const ARegion *ar = sctx->v3d_data.ar; + const RegionView3D *rv3d = ar->regiondata; - if (!ED_view3d_win_to_ray_ex( - sctx->v3d_data.ar, sctx->v3d_data.v3d, - mval, ray_origin, ray_normal, ray_start, true)) - { + ED_view3d_win_to_origin(ar, mval, ray_origin); + ED_view3d_win_to_vector(ar, mval, ray_normal); + + ED_view3d_clip_range_get( + sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata, + &depth_range[0], &depth_range[1], false); + + madd_v3_v3v3fl(ray_start, ray_origin, ray_normal, depth_range[0]); + madd_v3_v3v3fl(ray_end, ray_origin, ray_normal, depth_range[1]); + + if (!ED_view3d_clip_segment(rv3d, ray_start, ray_end)) { return false; } - float radius, dist_to_ray_sq = 0.0f; - if (dist_px) { - radius = dist_px_to_dist3d_or_tangent(sctx->v3d_data.ar, *dist_px); - /** - * Workaround to use of cone (Instead of project the radius on view plane): - * In perspective view, the radius of the cone may decrease depending on the ray direction. - * This is more evident with small values of the `Viewport lens angle`. - * The threshold becomes distorted that way. - */ - RegionView3D *rv3d = sctx->v3d_data.ar->regiondata; - if (rv3d->is_persp) { - float view_dir[3]; - negate_v3_v3(view_dir, rv3d->viewinv[2]); - normalize_v3(view_dir); - radius *= dot_v3v3(ray_normal, view_dir); - } - - dist_to_ray_sq = SQUARE(radius); + float ray_depth_fallback; + if (ray_depth == NULL) { + ray_depth_fallback = BVH_RAYCAST_DIST_MAX; + ray_depth = &ray_depth_fallback; } - if (snapObjectsRay( + return snapObjectsRay( sctx, snap_to, params->snap_select, params->use_object_edit_cage, - ray_origin, ray_start, ray_normal, - ray_depth, &dist_to_ray_sq, - r_loc, r_no, r_index, NULL, NULL, NULL)) - { - if (dist_px) { - *dist_px *= sqrtf(dist_to_ray_sq) / radius; - } - return true; - } - - return false; + mval, ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, + r_loc, r_no, r_index, NULL, NULL, NULL); } bool ED_transform_snap_object_project_view3d( diff --git a/source/blender/freestyle/intern/stroke/Curve.cpp b/source/blender/freestyle/intern/stroke/Curve.cpp index 69c5dcdfe28..a8dbce84971 100644 --- a/source/blender/freestyle/intern/stroke/Curve.cpp +++ b/source/blender/freestyle/intern/stroke/Curve.cpp @@ -133,7 +133,7 @@ iA_B_eq_iB_A: //_t2d = t3; _t2d = t2 * t3; } - else if ((iA->getPoint2D() - iA->getPoint2D()).norm() < 1.0e-6) { + else if ((iA->getPoint2D() - iB->getPoint2D()).norm() < 1.0e-6) { __A = iB->A(); __B = iB->B(); //_t2d = t3; diff --git a/source/blender/freestyle/intern/view_map/Functions1D.cpp b/source/blender/freestyle/intern/view_map/Functions1D.cpp index 11e0cc37d4d..8f16f78cb10 100644 --- a/source/blender/freestyle/intern/view_map/Functions1D.cpp +++ b/source/blender/freestyle/intern/view_map/Functions1D.cpp @@ -104,7 +104,7 @@ int QuantitativeInvisibilityF1D::operator()(Interface1D& inter) } FEdge *fe = dynamic_cast<FEdge*>(&inter); if (fe) { - result = ve->qi(); + result = fe->qi(); return 0; } result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index c663af0ccbb..370841327aa 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -916,7 +916,7 @@ void GPU_buffer_unlock(GPUBuffer *UNUSED(buffer), GPUBindingType binding) { int bindtypegl = gpu_binding_type_gl[binding]; /* note: this operation can fail, could return - * an error code from this function? */ + * an error code from this function? */ glUnmapBuffer(bindtypegl); glBindBuffer(bindtypegl, 0); } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 3c028ff0805..aec94f9f2cb 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -853,11 +853,14 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { if (input->attribtype == CD_MTFACE) { + /* NOTE: For now we are using varying on purpose, + * otherwise we are not able to write to the varying. + */ BLI_dynstr_appendf(ds, "%s %s var%d%s;\n", - GLEW_VERSION_3_0 ? "in" : "varying", + "varying", GPU_DATATYPE_STR[input->type], input->attribid, - GLEW_VERSION_3_0 ? "[]" : ""); + ""); BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n", input->attribid); } @@ -868,22 +871,20 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl); /* Generate varying assignments. */ - /* TODO(sergey): Disabled for now, needs revisit. */ -#if 0 for (node = nodes->first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { if (input->attribtype == CD_MTFACE) { - BLI_dynstr_appendf(ds, - "\tINTERP_FACE_VARYING_2(var%d, " - "fvar%d_offset, st);\n", - input->attribid, - input->attribid); + BLI_dynstr_appendf( + ds, + "\tINTERP_FACE_VARYING_2(var%d, " + "int(texelFetch(FVarDataOffsetBuffer, fvar%d_offset).r), st);\n", + input->attribid, + input->attribid); } } } } -#endif BLI_dynstr_append(ds, "}\n"); code = BLI_dynstr_get_cstring(ds); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 064e91743e8..7936811ab4d 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -803,7 +803,7 @@ static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int * | | | | * | NegZ | PosZ | PosY | * |______|______|______| - */ + */ if (use_high_bit_depth) { float (*frectb)[4] = (float(*)[4])frect; float (**fsides)[4] = (float(**)[4])sides; diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index b8a39c81122..d41573b681b 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -77,9 +77,10 @@ static struct GPUGlobal { GPUDeviceType device; GPUOSType os; GPUDriverType driver; - float dfdyfactors[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers - calculate dfdy in shader differently when drawing to an offscreen buffer. First - number is factor on screen and second is off-screen */ + /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers + * calculate dfdy in shader differently when drawing to an offscreen buffer. First + * number is factor on screen and second is off-screen */ + float dfdyfactors[2]; float max_anisotropy; } GG = {1, 0}; diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 0f95107c018..4775d2ed30a 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -1745,8 +1745,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) (GPU_link_changed(shi->refl) || ma->ref != 0.0f)) { if (world->aocolor != WO_AOPLAIN) { - if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr))) - { + if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr))) { GPUNodeLink *fcol, *f; GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f); GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f); @@ -2887,8 +2886,7 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material, "fvar%d_offset", input->attribid); location = GPU_shader_get_uniform(shader, name); - /* Multiply by 2 because we're offseting U and V variables. */ - GPU_shader_uniform_int(shader, location, layer_index * 2); + GPU_shader_uniform_int(shader, location, layer_index); } } diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 5a1b38e6be7..df1213b01e2 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -437,6 +437,10 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, /* TODO(sergey): Find a better place for this. */ if (use_opensubdiv && GLEW_VERSION_4_1) { glProgramUniform1i(shader->program, + glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"), + 30); /* GL_TEXTURE30 */ + + glProgramUniform1i(shader->program, glGetUniformLocation(shader->program, "FVarDataBuffer"), 31); /* GL_TEXTURE31 */ } diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl index 1663915549c..6f063883e37 100644 --- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl +++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl @@ -32,6 +32,7 @@ uniform int osd_fvar_count; } uniform samplerBuffer FVarDataBuffer; +uniform isamplerBuffer FVarDataOffsetBuffer; out block { VertexData v; diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index f3bd817a7cc..845a78720ba 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1142,14 +1142,10 @@ void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) { - float facm; - - fact *= facg; - facm = 1.0 - fact; + vec4 col; - vec3 one = vec3(1.0); - vec3 scr = one - (one - texcol) * (one - outcol); - incol = facm * outcol + fact * ((one - texcol) * outcol * texcol + outcol * scr); + mix_soft(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); + incol.rgb = col.rgb; } void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c index 26ced49a333..1987c6d2a9a 100644 --- a/source/blender/imbuf/intern/filter.c +++ b/source/blender/imbuf/intern/filter.c @@ -206,7 +206,7 @@ void imb_filterx(struct ImBuf *ibuf) static void imb_filterN(ImBuf *out, ImBuf *in) { BLI_assert(out->channels == in->channels); - BLI_assert(out->x == in->x && out->y == out->y); + BLI_assert(out->x == in->x && out->y == in->y); const int channels = in->channels; const int rowlen = in->x; diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c index a55cef60943..a4418443790 100644 --- a/source/blender/imbuf/intern/stereoimbuf.c +++ b/source/blender/imbuf/intern/stereoimbuf.c @@ -117,7 +117,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp to[0] = from[r][0]; to[1] = from[g][1]; to[2] = from[b][2]; - to[3] = MAX2(from[0][3], from[0][3]); + to[3] = MAX2(from[0][3], from[1][3]); } } } @@ -154,7 +154,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp to[0] = from[r][0]; to[1] = from[g][1]; to[2] = from[b][2]; - to[3] = MAX2(from[0][3], from[0][3]); + to[3] = MAX2(from[0][3], from[1][3]); } } } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index d7feb3a3880..0936284e354 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -354,7 +354,10 @@ typedef struct PreviewImage { #define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0) -#define ID_IS_LINKED_DATABLOCK(_id) (((ID *)(_id))->lib != NULL) +#define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL) +#define LIB_IS_VIRTUAL(_lib) (((_lib)->flag & LIBRARY_FLAG_VIRTUAL) != 0) +#define ID_IS_LINKED_DATABLOCK(_id) (ID_IS_LINKED(_id) && !LIB_IS_VIRTUAL(((ID *)(_id))->lib)) +#define ID_IS_LINKED_DATAPATH(_id) (ID_IS_LINKED(_id) && LIB_IS_VIRTUAL(((ID *)(_id))->lib)) #ifdef GS # undef GS diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 3dca087c7fa..f4a1677efc4 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -4,7 +4,7 @@ * 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. + * 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 @@ -70,7 +70,6 @@ typedef struct Brush { float normal_weight; float rake_factor; /* rake actual data (not texture), used for sculpt */ - int pad; short blend; /* blend mode */ short ob_mode; /* & with ob->mode to see if the brush is compatible, use for display only. */ @@ -95,7 +94,6 @@ typedef struct Brush { float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */ - int flag2; int gradient_spacing; int gradient_stroke_mode; /* source for stroke color gradient application */ int gradient_fill_mode; /* source for fill tool color gradient application */ @@ -104,7 +102,7 @@ typedef struct Brush { char vertexpaint_tool; /* active vertex/weight paint blend mode (poorly named) */ char imagepaint_tool; /* active image paint tool */ char mask_tool; /* enum BrushMaskTool, only used if sculpt_tool is SCULPT_TOOL_MASK */ - + float autosmooth_factor; float crease_pinch_factor; @@ -333,5 +331,4 @@ typedef enum BlurKernelType { #define MAX_BRUSH_PIXEL_RADIUS 500 -#endif - +#endif /* __DNA_BRUSH_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h index 07bc2478837..d385e303a7c 100644 --- a/source/blender/makesdna/DNA_cloth_types.h +++ b/source/blender/makesdna/DNA_cloth_types.h @@ -42,7 +42,7 @@ * * I've tried to keep similar, if not exact names for the variables as * are presented in the paper. Where I've changed the concept slightly, - * as in stepsPerFrame comapred to the time step in the paper, I've used + * as in stepsPerFrame compared to the time step in the paper, I've used * variables with different names to minimize confusion. */ diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index c9a5e056e4a..1d88b01cf62 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -157,10 +157,11 @@ typedef struct Scopes { /* scopes->wavefrm_mode */ #define SCOPES_WAVEFRM_LUMA 0 -#define SCOPES_WAVEFRM_RGB 1 +#define SCOPES_WAVEFRM_RGB_PARADE 1 #define SCOPES_WAVEFRM_YCC_601 2 #define SCOPES_WAVEFRM_YCC_709 3 #define SCOPES_WAVEFRM_YCC_JPEG 4 +#define SCOPES_WAVEFRM_RGB 5 typedef struct ColorManagedViewSettings { int flag, pad; diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h index bc127ac2c82..a2981c0aa76 100644 --- a/source/blender/makesdna/DNA_genfile.h +++ b/source/blender/makesdna/DNA_genfile.h @@ -69,8 +69,11 @@ typedef enum eSDNA_Type { * For use with #DNA_struct_reconstruct & #DNA_struct_get_compareflags */ enum eSDNA_StructCompare { + /* Struct has disappeared (values of this struct type will not be loaded by the current Blender) */ SDNA_CMP_REMOVED = 0, + /* Struct is the same (can be loaded with straight memory copy after any necessary endian conversion) */ SDNA_CMP_EQUAL = 1, + /* Struct is different in some way (needs to be copied/converted field by field) */ SDNA_CMP_NOT_EQUAL = 2, }; @@ -89,15 +92,15 @@ void DNA_sdna_current_free(void); int DNA_struct_find_nr_ex(const struct SDNA *sdna, const char *str, unsigned int *index_last); int DNA_struct_find_nr(const struct SDNA *sdna, const char *str); void DNA_struct_switch_endian(const struct SDNA *oldsdna, int oldSDNAnr, char *data); -char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA*newsdna); +const char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA *newsdna); void *DNA_struct_reconstruct( const struct SDNA *newsdna, const struct SDNA *oldsdna, - char *compflags, int oldSDNAnr, int blocks, void *data); + const char *compflags, int oldSDNAnr, int blocks, const void *data); int DNA_elem_array_size(const char *str); int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name); -bool DNA_struct_elem_find(struct SDNA *sdna, const char *stype, const char *vartype, const char *name); +bool DNA_struct_elem_find(const struct SDNA *sdna, const char *stype, const char *vartype, const char *name); int DNA_elem_type_size(const eSDNA_Type elem_nr); diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index a58e995f1c6..bbc8edf4344 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -641,8 +641,9 @@ typedef struct BooleanModifierData { struct Object *object; char operation; - char bm_flag, pad[2]; - float threshold; + char solver; + char pad[2]; + float double_threshold; } BooleanModifierData; typedef enum { @@ -651,13 +652,10 @@ typedef enum { eBooleanModifierOp_Difference = 2, } BooleanModifierOp; -/* temp bm_flag (debugging only) */ -enum { - eBooleanModifierBMeshFlag_Enabled = (1 << 0), - eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 1), - eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 2), - eBooleanModifierBMeshFlag_BMesh_NoConnectRegions = (1 << 3), -}; +typedef enum { + eBooleanModifierSolver_Carve = 0, + eBooleanModifierSolver_BMesh = 1, +} BooleanSolver; typedef struct MDefInfluence { int vertex; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 58f4255068c..4c739203e77 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1273,7 +1273,9 @@ typedef struct CurvePaintSettings { char flag; char depth_mode; char surface_plane; - int error_threshold; + char fit_method; + char pad; + short error_threshold; float radius_min, radius_max; float radius_taper_start, radius_taper_end; float surface_offset; @@ -1288,6 +1290,12 @@ enum { CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS = (1 << 3), }; +/* CurvePaintSettings.fit_method */ +enum { + CURVE_PAINT_FIT_METHOD_REFIT = 0, + CURVE_PAINT_FIT_METHOD_SPLIT = 1, +}; + /* CurvePaintSettings.depth_mode */ enum { CURVE_PAINT_PROJECT_CURSOR = 0, diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h index 26ea5cd4e93..bd8f23f30c1 100644 --- a/source/blender/makesdna/DNA_sdna_types.h +++ b/source/blender/makesdna/DNA_sdna_types.h @@ -45,7 +45,7 @@ typedef struct SDNA { int pointerlen; /* size of a pointer in bytes */ int nr_types; /* number of basic types + struct types */ - char **types; /* type names */ + const char **types; /* type names */ short *typelens; /* type lengths */ int nr_structs; /* number of struct types */ diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 5b533d1ec48..4c243507e82 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -239,7 +239,7 @@ typedef struct View3D { float stereo3d_convergence_alpha; /* Previous viewport draw type. - * Runtime-only, set in the rendered viewport otggle operator. + * Runtime-only, set in the rendered viewport toggle operator. */ short prev_drawtype; short pad1; diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 0bb6e866bf4..8c758c33dc5 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -52,6 +52,8 @@ endif() # SRC_DNA_INC is defined in the parent dir +add_cc_flags_custom_test(makesdna) + add_executable(makesdna ${SRC} ${SRC_DNA_INC}) # Output dna.c diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index 1e3c91d5ddc..6a41591e051 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -134,39 +134,6 @@ * */ -/* ************************* ENDIAN STUFF ********************** */ - -/** - * converts a short between big/little endian. - */ -static short le_short(short temp) -{ - short new; - char *rt = (char *)&temp, *rtn = (char *)&new; - - rtn[0] = rt[1]; - rtn[1] = rt[0]; - - return new; -} - -/** - * converts an int between big/little endian. - */ -static int le_int(int temp) -{ - int new; - char *rt = (char *)&temp, *rtn = (char *)&new; - - rtn[0] = rt[3]; - rtn[1] = rt[2]; - rtn[2] = rt[1]; - rtn[3] = rt[0]; - - return new; -} - - /* ************************* MAKE DNA ********************** */ /* allowed duplicate code from makesdna.c */ @@ -338,6 +305,11 @@ int DNA_struct_find_nr(const SDNA *sdna, const char *str) /* ************************* READ DNA ********************** */ +BLI_INLINE const char *pad_up_4(const char *ptr) +{ + return (const char *)((((uintptr_t)ptr) + 3) & ~3); +} + /** * In sdna->data the data, now we convert that to something understandable */ @@ -366,8 +338,7 @@ static bool init_structDNA( return false; } else { - intptr_t nr; - char *cp; + const char *cp; data++; @@ -376,8 +347,10 @@ static bool init_structDNA( if (*data == *verg) { data++; - if (do_endian_swap) sdna->nr_names = le_int(*data); - else sdna->nr_names = *data; + sdna->nr_names = *data; + if (do_endian_swap) { + BLI_endian_switch_int32(&sdna->nr_names); + } data++; sdna->names = MEM_callocN(sizeof(void *) * sdna->nr_names, "sdnanames"); @@ -387,9 +360,8 @@ static bool init_structDNA( return false; } - nr = 0; cp = (char *)data; - while (nr < sdna->nr_names) { + for (int nr = 0; nr < sdna->nr_names; nr++) { sdna->names[nr] = cp; /* "float gravity [3]" was parsed wrong giving both "gravity" and @@ -404,20 +376,20 @@ static bool init_structDNA( while (*cp) cp++; cp++; - nr++; } - nr = (intptr_t)cp; /* prevent BUS error */ - nr = (nr + 3) & ~3; - cp = (char *)nr; + + cp = pad_up_4(cp); /* load type names array */ data = (int *)cp; strcpy(str, "TYPE"); if (*data == *verg) { data++; - - if (do_endian_swap) sdna->nr_types = le_int(*data); - else sdna->nr_types = *data; + + sdna->nr_types = *data; + if (do_endian_swap) { + BLI_endian_switch_int32(&sdna->nr_types); + } data++; sdna->types = MEM_callocN(sizeof(void *) * sdna->nr_types, "sdnatypes"); @@ -427,9 +399,8 @@ static bool init_structDNA( return false; } - nr = 0; cp = (char *)data; - while (nr < sdna->nr_types) { + for (int nr = 0; nr < sdna->nr_types; nr++) { sdna->types[nr] = cp; /* this is a patch, to change struct names without a conflict with SDNA */ @@ -442,11 +413,9 @@ static bool init_structDNA( while (*cp) cp++; cp++; - nr++; } - nr = (intptr_t)cp; /* prevent BUS error */ - nr = (nr + 3) & ~3; - cp = (char *)nr; + + cp = pad_up_4(cp); /* load typelen array */ data = (int *)cp; @@ -457,13 +426,7 @@ static bool init_structDNA( sdna->typelens = sp; if (do_endian_swap) { - short a, *spo = sp; - - a = sdna->nr_types; - while (a--) { - spo[0] = le_short(spo[0]); - spo++; - } + BLI_endian_switch_int16_array(sp, sdna->nr_types); } sp += sdna->nr_types; @@ -480,8 +443,10 @@ static bool init_structDNA( if (*data == *verg) { data++; - if (do_endian_swap) sdna->nr_structs = le_int(*data); - else sdna->nr_structs = *data; + sdna->nr_structs = *data; + if (do_endian_swap) { + BLI_endian_switch_int32(&sdna->nr_structs); + } data++; sdna->structs = MEM_callocN(sizeof(void *) * sdna->nr_structs, "sdnastrcs"); @@ -491,37 +456,34 @@ static bool init_structDNA( return false; } - nr = 0; sp = (short *)data; - while (nr < sdna->nr_structs) { + for (int nr = 0; nr < sdna->nr_structs; nr++) { sdna->structs[nr] = sp; if (do_endian_swap) { short a; - sp[0] = le_short(sp[0]); - sp[1] = le_short(sp[1]); + BLI_endian_switch_int16(&sp[0]); + BLI_endian_switch_int16(&sp[1]); a = sp[1]; sp += 2; while (a--) { - sp[0] = le_short(sp[0]); - sp[1] = le_short(sp[1]); + BLI_endian_switch_int16(&sp[0]); + BLI_endian_switch_int16(&sp[1]); sp += 2; } } else { sp += 2 * sp[1] + 2; } - - nr++; } } { /* second part of gravity problem, setting "gravity" type to void */ if (gravity_fix > -1) { - for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) { + for (int nr = 0; nr < sdna->nr_structs; nr++) { sp = sdna->structs[nr]; if (strcmp(sdna->types[sp[0]], "ClothSimSettings") == 0) sp[10] = SDNA_TYPE_VOID; @@ -536,7 +498,7 @@ static bool init_structDNA( for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) { sp = sdna->structs[nr]; - BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr)); + BLI_ghash_insert(sdna->structs_map, (void *)sdna->types[sp[0]], SET_INT_IN_POINTER(nr)); } } #endif @@ -670,13 +632,8 @@ static void recurs_test_compflags(const SDNA *sdna, char *compflags, int structn /** * Constructs and returns an array of byte flags with one element for each struct in oldsdna, * indicating how it compares to newsdna: - * - * flag value: - * - 0 Struct has disappeared (values of this struct type will not be loaded by the current Blender) - * - 1 Struct is the same (can be loaded with straight memory copy after any necessary endian conversion) - * - 2 Struct is different in some way (needs to be copied/converted field by field) */ -char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna) +const char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna) { int a, b; const short *sp_old, *sp_new; @@ -947,12 +904,12 @@ static int elem_strcmp(const char *name, const char *oname) * \param sppo Optional place to return pointer to field info in sdna * \return Data address. */ -static char *find_elem( +static const char *find_elem( const SDNA *sdna, const char *type, const char *name, const short *old, - char *olddata, + const char *olddata, const short **sppo) { int a, elemcount, len; @@ -1100,7 +1057,7 @@ static void reconstruct_struct( const char *compflags, int oldSDNAnr, - char *data, + const char *data, int curSDNAnr, char *cur) { @@ -1111,7 +1068,8 @@ static void reconstruct_struct( int a, elemcount, elen, eleno, mul, mulo, firststructtypenr; const short *spo, *spc, *sppo; const char *type; - char *cpo, *cpc; + const char *cpo; + char *cpc; const char *name, *nameo; unsigned int oldsdna_index_last = UINT_MAX; @@ -1149,7 +1107,7 @@ static void reconstruct_struct( if (spc[0] >= firststructtypenr && !ispointer(name)) { /* struct field type */ /* where does the old struct data start (and is there an old one?) */ - cpo = find_elem(oldsdna, type, name, spo, data, &sppo); + cpo = (char *)find_elem(oldsdna, type, name, spo, data, &sppo); if (cpo) { oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last); @@ -1226,7 +1184,7 @@ void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data) if (spc[0] >= firststructtypenr && !ispointer(name)) { /* struct field type */ /* where does the old data start (is there one?) */ - char *cpo = find_elem(oldsdna, type, name, spo, data, NULL); + char *cpo = (char *)find_elem(oldsdna, type, name, spo, data, NULL); if (cpo) { oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last); @@ -1288,11 +1246,12 @@ void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data) */ void *DNA_struct_reconstruct( const SDNA *newsdna, const SDNA *oldsdna, - char *compflags, int oldSDNAnr, int blocks, void *data) + const char *compflags, int oldSDNAnr, int blocks, const void *data) { int a, curSDNAnr, curlen = 0, oldlen; const short *spo, *spc; - char *cur, *cpc, *cpo; + char *cur, *cpc; + const char *cpo; const char *type; /* oldSDNAnr == structnr, we're looking for the corresponding 'cur' number */ @@ -1335,7 +1294,7 @@ int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const ch return (int)((intptr_t)cp); } -bool DNA_struct_elem_find(SDNA *sdna, const char *stype, const char *vartype, const char *name) +bool DNA_struct_elem_find(const SDNA *sdna, const char *stype, const char *vartype, const char *name) { const int SDNAnr = DNA_struct_find_nr(sdna, stype); diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index b1048f72022..7ae3d552916 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -52,6 +52,7 @@ extern EnumPropertyItem rna_enum_proportional_editing_items[]; extern EnumPropertyItem rna_enum_snap_target_items[]; extern EnumPropertyItem rna_enum_snap_element_items[]; extern EnumPropertyItem rna_enum_snap_node_element_items[]; +extern EnumPropertyItem rna_enum_curve_fit_method_items[]; extern EnumPropertyItem rna_enum_mesh_select_mode_items[]; extern EnumPropertyItem rna_enum_mesh_delimit_mode_items[]; extern EnumPropertyItem rna_enum_space_type_items[]; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 17b65a9d529..01db7b338b9 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -351,7 +351,10 @@ blender_include_dirs_sys( "${GLEW_INCLUDE_PATH}" ) +add_cc_flags_custom_test(makesrna) + add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC}) + target_link_libraries(makesrna bf_dna) target_link_libraries(makesrna bf_dna_blenlib) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 813c1062a02..8af9fa87865 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3299,7 +3299,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_animviz.c", NULL, RNA_def_animviz}, {"rna_actuator.c", "rna_actuator_api.c", RNA_def_actuator}, {"rna_armature.c", "rna_armature_api.c", RNA_def_armature}, - {"rna_asset.c", NULL, RNA_def_asset}, + {"rna_asset.c", NULL, RNA_def_asset}, {"rna_boid.c", NULL, RNA_def_boid}, {"rna_brush.c", NULL, RNA_def_brush}, {"rna_camera.c", "rna_camera_api.c", RNA_def_camera}, diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 533b1991ba5..528aabf33ee 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -698,7 +698,7 @@ static void rna_ImagePreview_icon_pixels_float_set(PointerRNA *ptr, const float static int rna_ImagePreview_icon_id_get(PointerRNA *ptr) { /* Using a callback here allows us to only generate icon matching that preview when icon_id is requested. */ - return BKE_icon_preview_ensure((PreviewImage *)(ptr->data)); + return BKE_icon_preview_ensure(ptr->id.data, (PreviewImage *)(ptr->data)); } static void rna_ImagePreview_icon_reload(PreviewImage *prv) { @@ -1061,6 +1061,7 @@ static void rna_def_ID(BlenderRNA *brna) static void rna_def_library(BlenderRNA *brna) { StructRNA *srna; + FunctionRNA *func; PropertyRNA *prop; srna = RNA_def_struct(brna, "Library", "ID"); @@ -1079,6 +1080,10 @@ static void rna_def_library(BlenderRNA *brna) prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "packedfile"); RNA_def_property_ui_text(prop, "Packed File", ""); + + func = RNA_def_function(srna, "reload", "WM_lib_reload"); + RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Reload this library and all its linked datablocks"); } void RNA_def_ID(BlenderRNA *brna) { diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 00b7df122ee..5a93e18a7dd 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -3127,8 +3127,11 @@ void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA RNA_parameter_list_free(¶ms); } } - /*else - printf("%s %s.%s: not implemented for this property.\n", __func__, ptr->type->identifier, prop->identifier);*/ +#if 0 + else { + printf("%s %s.%s: not implemented for this property.\n", __func__, ptr->type->identifier, prop->identifier); + } +#endif #endif if (r_ptr) { @@ -3187,8 +3190,11 @@ bool RNA_property_collection_remove(PointerRNA *ptr, PropertyRNA *prop, int key) return false; } - /*else - printf("%s %s.%s: only supported for id properties.\n", __func__, ptr->type->identifier, prop->identifier);*/ +#if 0 + else { + printf("%s %s.%s: only supported for id properties.\n", __func__, ptr->type->identifier, prop->identifier); + } +#endif #endif return false; } diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index c3d1070b8c2..7a1954036e3 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -116,6 +116,23 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value) } } +static void rna_AnimData_tweakmode_set(PointerRNA *ptr, const int value) +{ + AnimData *adt = (AnimData *)ptr->data; + + /* NOTE: technically we should also set/unset SCE_NLA_EDIT_ON flag on the + * scene which is used to make polling tests faster, but this flag is weak + * and can easily break e.g. by changing layer visibility. This needs to be + * dealt with at some point. */ + + if (value) { + BKE_nla_tweakmode_enter(adt); + } + else { + BKE_nla_tweakmode_exit(adt); + } +} + /* ****************************** */ /* wrapper for poll callback */ @@ -1041,6 +1058,12 @@ static void rna_def_animdata(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADT_NLA_EVAL_OFF); RNA_def_property_ui_text(prop, "NLA Evaluation Enabled", "NLA stack is evaluated when evaluating this block"); RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */ + + prop = RNA_def_property(srna, "use_tweak_mode", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ADT_NLA_EDIT_ON); + RNA_def_property_boolean_funcs(prop, NULL, "rna_AnimData_tweakmode_set"); + RNA_def_property_ui_text(prop, "Use NLA Tweak Mode", "Whether to enable or disable tweak mode in NLA"); + RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); } /* --- */ diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 842e220e8b5..5c7f51516cb 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -498,13 +498,13 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone) /* Roll In/Out */ prop = RNA_def_property(srna, "bbone_rollin", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "roll1"); - RNA_def_property_range(prop, -M_PI * 2.0f, M_PI * 2.0f); + RNA_def_property_range(prop, -M_PI * 2.0, M_PI * 2.0); RNA_def_property_ui_text(prop, "Roll In", "Roll offset for the start of the B-Bone, adjusts twist"); RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone); prop = RNA_def_property(srna, "bbone_rollout", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "roll2"); - RNA_def_property_range(prop, -M_PI * 2.0f, M_PI * 2.0f); + RNA_def_property_range(prop, -M_PI * 2.0, M_PI * 2.0); RNA_def_property_ui_text(prop, "Roll Out", "Roll offset for the end of the B-Bone, adjusts twist"); RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone); diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index 0d1279e96df..afd23e9fa0d 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -35,7 +35,7 @@ #include "rna_internal.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_idprop.h" #include "WM_types.h" @@ -46,7 +46,6 @@ #include "RNA_access.h" -#include "BKE_asset.h" #include "BKE_context.h" #include "BKE_report.h" diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 492430fbda6..078ba13d76d 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -159,13 +159,13 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "pole_merge_angle_from", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_range(prop, 0.0f, M_PI / 2.0f); + RNA_def_property_range(prop, 0.0f, M_PI / 2.0); RNA_def_property_ui_text(prop, "Pole Merge Start Angle", "Angle at which interocular distance starts to fade to 0"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "pole_merge_angle_to", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_range(prop, 0.0f, M_PI / 2.0f); + RNA_def_property_range(prop, 0.0f, M_PI / 2.0); RNA_def_property_ui_text(prop, "Pole Merge End Angle", "Angle at which interocular distance is 0"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 021bc608564..78e3bbe4176 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -1018,10 +1018,11 @@ static void rna_def_scopes(BlenderRNA *brna) static EnumPropertyItem prop_wavefrm_mode_items[] = { {SCOPES_WAVEFRM_LUMA, "LUMA", ICON_COLOR, "Luma", ""}, - {SCOPES_WAVEFRM_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""}, + {SCOPES_WAVEFRM_RGB_PARADE, "PARADE", ICON_COLOR, "Parade", ""}, {SCOPES_WAVEFRM_YCC_601, "YCBCR601", ICON_COLOR, "YCbCr (ITU 601)", ""}, {SCOPES_WAVEFRM_YCC_709, "YCBCR709", ICON_COLOR, "YCbCr (ITU 709)", ""}, {SCOPES_WAVEFRM_YCC_JPEG, "YCBCRJPG", ICON_COLOR, "YCbCr (Jpeg)", ""}, + {SCOPES_WAVEFRM_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index 16e0f17eac5..091950a8e66 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -204,18 +204,6 @@ static char *rna_FluidSettings_path(PointerRNA *ptr) return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc); } -static void rna_FluidMeshVertex_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) -{ - FluidsimSettings *fss = (FluidsimSettings *)ptr->data; - rna_iterator_array_begin(iter, fss->meshVelocities, sizeof(float) * 3, fss->totvert, 0, NULL); -} - -static int rna_FluidMeshVertex_data_length(PointerRNA *ptr) -{ - FluidsimSettings *fss = (FluidsimSettings *)ptr->data; - return fss->totvert; -} - #else static void rna_def_fluidsim_slip(StructRNA *srna) @@ -251,9 +239,8 @@ static void rna_def_fluid_mesh_vertices(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "FluidMeshVertex", NULL); - RNA_def_struct_sdna(srna, "FluidVertexVelocity"); - RNA_def_struct_ui_text(srna, "Fluid Mesh Vertex", "Vertex of a simulated fluid mesh"); + srna = RNA_def_struct(brna, "FluidVertexVelocity", NULL); + RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh"); RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL); prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY); @@ -442,11 +429,10 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna) /* simulated fluid mesh data */ prop = RNA_def_property(srna, "fluid_mesh_vertices", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "FluidMeshVertex"); + RNA_def_property_collection_sdna(prop, NULL, "meshVelocities", "totvert"); + RNA_def_property_struct_type(prop, "FluidVertexVelocity"); RNA_def_property_ui_text(prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation"); - RNA_def_property_collection_funcs(prop, "rna_FluidMeshVertex_data_begin", "rna_iterator_array_next", - "rna_iterator_array_end", "rna_iterator_array_get", - "rna_FluidMeshVertex_data_length", NULL, NULL, NULL); + rna_def_fluid_mesh_vertices(brna); } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index ef74f01f9be..a23ef6eaa82 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1895,6 +1895,12 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_solver_items[] = { + {eBooleanModifierSolver_BMesh, "BMESH", 0, "BMesh", "Use the BMesh boolean solver"}, + {eBooleanModifierSolver_Carve, "CARVE", 0, "Carve", "Use the Carve boolean solver"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "BooleanModifier", "Modifier"); RNA_def_struct_ui_text(srna, "Boolean Modifier", "Boolean operations modifier"); RNA_def_struct_sdna(srna, "BooleanModifierData"); @@ -1911,35 +1917,17 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Operation", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); -#if 0 /* WITH_MOD_BOOLEAN */ - /* BMesh intersection options */ - prop = RNA_def_property(srna, "use_bmesh", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_Enabled); - RNA_def_property_ui_text(prop, "Use BMesh", "Use BMesh boolean calculation"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); - - prop = RNA_def_property(srna, "use_bmesh_separate", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_Separate); - RNA_def_property_ui_text(prop, "Separate", "Keep edges separate"); + prop = RNA_def_property(srna, "solver", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_solver_items); + RNA_def_property_ui_text(prop, "Solver", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); - prop = RNA_def_property(srna, "use_bmesh_dissolve", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoDissolve); - RNA_def_property_ui_text(prop, "Dissolve", "Dissolve verts created from tessellated intersection"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); - - prop = RNA_def_property(srna, "use_bmesh_connect_regions", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoConnectRegions); - RNA_def_property_ui_text(prop, "Calculate Holes", "Connect regions (needed for hole filling)"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); - - prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_float_sdna(prop, NULL, "threshold"); + prop = RNA_def_property(srna, "double_threshold", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "double_threshold"); RNA_def_property_range(prop, 0, 1.0f); - RNA_def_property_ui_range(prop, 0, 1, 1, 7); - RNA_def_property_ui_text(prop, "Threshold", ""); + RNA_def_property_ui_range(prop, 0, 1, 0.0001, 7); + RNA_def_property_ui_text(prop, "Overlap Threshold", "Threshold for checking overlapping geometry"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); -#endif } static void rna_def_modifier_array(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index f15625259a9..9683495c54c 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1033,7 +1033,7 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value) ob->gameflag &= ~(OB_SENSOR | OB_OCCLUDER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR | OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH); /* When we switch to character physics and the collision bounds is set to triangle mesh - we have to change collision bounds because triangle mesh is not supported by Characters*/ + * we have to change collision bounds because triangle mesh is not supported by Characters */ if ((ob->gameflag & OB_BOUNDS) && ob->collision_boundtype == OB_BOUND_TRIANGLE_MESH) { ob->boundtype = ob->collision_boundtype = OB_BOUND_BOX; } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index d1f8c4e5bed..ed90f146f4d 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -178,6 +178,11 @@ EnumPropertyItem snap_uv_element_items[] = { {0, NULL, 0, NULL, NULL} }; +EnumPropertyItem rna_enum_curve_fit_method_items[] = { + {CURVE_PAINT_FIT_METHOD_REFIT, "REFIT", 0, "Refit", "Incrementally re-fit the curve (high quality)"}, + {CURVE_PAINT_FIT_METHOD_SPLIT, "SPLIT", 0, "Split", "Split the curve until the tolerance is met (fast)"}, + {0, NULL, 0, NULL, NULL}}; + /* workaround for duplicate enums, * have each enum line as a define then conditionally set it or not */ @@ -2638,6 +2643,11 @@ static void rna_def_curve_paint_settings(BlenderRNA *brna) RNA_def_property_range(prop, 1, 100); RNA_def_property_ui_text(prop, "Tolerance", "Allow deviation for a smoother, less precise line"); + prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_PIXEL); + RNA_def_property_enum_sdna(prop, NULL, "fit_method"); + RNA_def_property_enum_items(prop, rna_enum_curve_fit_method_items); + RNA_def_property_ui_text(prop, "Method", "Curve fitting method"); + prop = RNA_def_property(srna, "corner_angle", PROP_FLOAT, PROP_ANGLE); RNA_def_property_range(prop, 0, M_PI); RNA_def_property_ui_text(prop, "Corner Angle", "Angles above this are considered corners"); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 738554af9c0..4437c26f0be 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -35,7 +35,7 @@ #include "RNA_define.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_image.h" #include "BKE_key.h" #include "BKE_movieclip.h" @@ -253,7 +253,7 @@ EnumPropertyItem rna_enum_file_sort_items[] = { #include "BLI_math.h" #include "BKE_animsys.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_context.h" @@ -3661,7 +3661,7 @@ static void rna_def_space_nla(BlenderRNA *brna) prop = RNA_def_property(srna, "show_local_markers", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOLOCALMARKERS); RNA_def_property_ui_text(prop, "Show Local Markers", - "Show action-local markers on the strips, useful when synchronising timing across strips"); + "Show action-local markers on the strips, useful when synchronizing timing across strips"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL); /* editing */ diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 3f418fa16f3..da0f5aa3923 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -33,7 +33,7 @@ */ // #ifdef DEBUG_TIME -// #define USE_BMESH +#define USE_BMESH #ifdef WITH_MOD_BOOLEAN # define USE_CARVE WITH_MOD_BOOLEAN #endif @@ -71,6 +71,14 @@ #include "PIL_time_utildefines.h" #endif +static void initData(ModifierData *md) +{ + BooleanModifierData *bmd = (BooleanModifierData *)md; + + bmd->solver = eBooleanModifierSolver_BMesh; + bmd->double_threshold = 1e-6f; +} + static void copyData(ModifierData *md, ModifierData *target) { #if 0 @@ -222,7 +230,9 @@ static DerivedMesh *applyModifier_bmesh( #ifdef DEBUG_TIME TIMEIT_START(boolean_bmesh); #endif - bm = BM_mesh_create_ex(&allocsize, ); + bm = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = false,})); DM_to_bmesh_ex(dm_other, bm, true); DM_to_bmesh_ex(dm, bm, true); @@ -296,16 +306,21 @@ static DerivedMesh *applyModifier_bmesh( * currently this is ok for 'BM_mesh_intersect' */ // BM_mesh_normals_update(bm); + /* change for testing */ + bool use_separate = false; + bool use_dissolve = true; + bool use_island_connect = true; + BM_mesh_intersect( bm, looptris, tottri, bm_face_isect_pair, NULL, false, - (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0, - (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0, - (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0, + use_separate, + use_dissolve, + use_island_connect, bmd->operation, - bmd->threshold); + bmd->double_threshold); MEM_freeN(looptris); } @@ -409,15 +424,14 @@ static DerivedMesh *applyModifier( ModifierApplyFlag flag) { BooleanModifierData *bmd = (BooleanModifierData *)md; - const int method = (bmd->bm_flag & eBooleanModifierBMeshFlag_Enabled) ? 1 : 0; - switch (method) { + switch (bmd->solver) { #ifdef USE_CARVE - case 0: + case eBooleanModifierSolver_Carve: return applyModifier_carve(md, ob, derivedData, flag); #endif #ifdef USE_BMESH - case 1: + case eBooleanModifierSolver_BMesh: return applyModifier_bmesh(md, ob, derivedData, flag); #endif default: @@ -441,7 +455,7 @@ ModifierTypeInfo modifierType_Boolean = { /* deformMatricesEM */ NULL, /* applyModifier */ applyModifier, /* applyModifierEM */ NULL, - /* initData */ NULL, + /* initData */ initData, /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 2cfa746ab3c..ceb7dc02699 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -144,8 +144,9 @@ static void mix_normals( break; } - interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new, - (mix_limit < M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac); + interp_v3_v3v3_slerp_safe( + *no_new, *no_old, *no_new, + (mix_limit < (float)M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac); } MEM_SAFE_FREE(facs); @@ -390,7 +391,7 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) && (smd->mix_factor == 1.0f) && (smd->defgrp_name[0] == '\0') && - (smd->mix_limit == M_PI)); + (smd->mix_limit == (float)M_PI)); int defgrp_index; MDeformVert *dvert; diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c index eb1594688c7..d5973baeadb 100644 --- a/source/blender/python/bmesh/bmesh_py_api.c +++ b/source/blender/python/bmesh/bmesh_py_api.c @@ -207,20 +207,21 @@ PyObject *BPyInit_bmesh(void) /* bmesh.types */ PyModule_AddObject(mod, "types", (submodule = BPyInit_bmesh_types())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); + /* bmesh.ops (not a real module, exposes module like access). */ PyModule_AddObject(mod, "ops", (submodule = BPyInit_bmesh_ops())); - /* PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); */ + /* PyDict_SetItemString(sys_modules, PyModule_GetNameObject(submodule), submodule); */ PyDict_SetItemString(sys_modules, "bmesh.ops", submodule); /* fake module */ Py_INCREF(submodule); PyModule_AddObject(mod, "utils", (submodule = BPyInit_bmesh_utils())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); PyModule_AddObject(mod, "geometry", (submodule = BPyInit_bmesh_geometry())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); return mod; diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index db8ed072722..11646f3f3df 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -1560,7 +1560,7 @@ PyObject *BPyInit_idprop(void) /* idprop.types */ PyModule_AddObject(mod, "types", (submodule = BPyInit_idprop_types())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); return mod; diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 7f13a7a4d94..72dec55e50b 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -177,7 +177,7 @@ PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type, /** * Caller needs to ensure tuple is uninitialized. - * Handy for filling a typle with None for eg. + * Handy for filling a tuple with None for eg. */ void PyC_Tuple_Fill(PyObject *tuple, PyObject *value) { @@ -367,11 +367,12 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings) } -/* similar to PyErr_Format(), +/** + * Similar to #PyErr_Format(), * - * implementation - we cant actually preprend the existing exception, + * Implementation - we cant actually prepend the existing exception, * because it could have _any_ arguments given to it, so instead we get its - * __str__ output and raise our own exception including it. + * ``__str__`` output and raise our own exception including it. */ PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...) { @@ -748,6 +749,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...) /* set the value so we can access it */ PyDict_SetItemString(py_dict, "values", values); + Py_DECREF(values); py_result = PyRun_File(fp, filepath, Py_file_input, py_dict, py_dict); diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 9f83bc94760..538ff7ba257 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -236,7 +236,7 @@ static int bpy_app_debug_set(PyObject *UNUSED(self), PyObject *value, void *clos PyDoc_STRVAR(bpy_app_binary_path_python_doc, "String, the path to the python executable (read-only)" ); -static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UNUSED(closure)) +static PyObject *bpy_app_binary_path_python_get(PyObject *self, void *UNUSED(closure)) { /* refcount is held in BlenderAppType.tp_dict */ static PyObject *ret = NULL; @@ -248,7 +248,7 @@ static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UN fullpath, sizeof(fullpath), PY_MAJOR_VERSION, PY_MINOR_VERSION); ret = PyC_UnicodeFromByte(fullpath); - PyDict_SetItemString(BlenderAppType.tp_dict, "binary_path_python", ret); + PyDict_SetItem(BlenderAppType.tp_dict, PyDescr_NAME(self), ret); } else { Py_INCREF(ret); @@ -363,10 +363,10 @@ static PyGetSetDef bpy_app_getsets[] = { static void py_struct_seq_getset_init(void) { /* tricky dynamic members, not to py-spec! */ - PyGetSetDef *getset; - - for (getset = bpy_app_getsets; getset->name; getset++) { - PyDict_SetItemString(BlenderAppType.tp_dict, getset->name, PyDescr_NewGetSet(&BlenderAppType, getset)); + for (PyGetSetDef *getset = bpy_app_getsets; getset->name; getset++) { + PyObject *item = PyDescr_NewGetSet(&BlenderAppType, getset); + PyDict_SetItem(BlenderAppType.tp_dict, PyDescr_NAME(item), item); + Py_DECREF(item); } } /* end dynamic bpy.app */ diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index 9b477e384db..65b6bd501ce 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -110,9 +110,11 @@ static void bpy_pydriver_update_dict(const float evaltime) bpy_pydriver_InternStr__frame = PyUnicode_FromString("frame"); } + PyObject *item = PyFloat_FromDouble(evaltime); PyDict_SetItem(bpy_pydriver_Dict, bpy_pydriver_InternStr__frame, - PyFloat_FromDouble(evaltime)); + item); + Py_DECREF(item); bpy_pydriver_evaltime_prev = evaltime; } @@ -301,7 +303,10 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime) /* try to add to dictionary */ /* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */ - if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) < 0) { + if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) != -1) { + Py_DECREF(driver_arg); + } + else { /* this target failed - bad name */ if (targets_ok) { /* first one - print some extra info for easier identification */ diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index a120e4886e0..37a7e0e23dd 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -39,7 +39,6 @@ #include "BLO_readfile.h" -#include "BKE_global.h" #include "BKE_main.h" #include "BKE_library.h" #include "BKE_idcode.h" @@ -186,6 +185,7 @@ PyDoc_STRVAR(bpy_lib_load_doc, static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) { static const char *kwlist[] = {"filepath", "link", "relative", NULL}; + Main *bmain = CTX_data_main(BPy_GetContext()); BPy_Library *ret; const char *filename = NULL; bool is_rel = false, is_link = false; @@ -204,7 +204,7 @@ static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject * BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath)); BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath)); - BLI_path_abs(ret->abspath, G.main->name); + BLI_path_abs(ret->abspath, bmain->name); ret->blo_handle = NULL; ret->flag = ((is_link ? FILE_LINK : 0) | @@ -222,19 +222,16 @@ static PyObject *_bpy_names(BPy_Library *self, int blocktype) int totnames; names = BLO_blendhandle_get_datablock_names(self->blo_handle, blocktype, &totnames); + list = PyList_New(totnames); if (names) { int counter = 0; - list = PyList_New(totnames); for (l = names; l; l = l->next) { PyList_SET_ITEM(list, counter, PyUnicode_FromString((char *)l->link)); counter++; } BLI_linklist_free(names, free); /* free linklist *and* each node's data */ } - else { - list = PyList_New(0); - } return list; } @@ -264,8 +261,13 @@ static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args)) if (BKE_idcode_is_linkable(code)) { const char *name_plural = BKE_idcode_to_name_plural(code); PyObject *str = PyUnicode_FromString(name_plural); - PyDict_SetItem(self->dict, str, PyList_New(0)); - PyDict_SetItem(from_dict, str, _bpy_names(self, code)); + PyObject *item; + + PyDict_SetItem(self->dict, str, item = PyList_New(0)); + Py_DECREF(item); + PyDict_SetItem(from_dict, str, item = _bpy_names(self, code)); + Py_DECREF(item); + Py_DECREF(str); } } @@ -346,48 +348,44 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* loop */ Py_ssize_t size = PyList_GET_SIZE(ls); Py_ssize_t i; - PyObject *item; - const char *item_str; for (i = 0; i < size; i++) { - item = PyList_GET_ITEM(ls, i); - item_str = _PyUnicode_AsString(item); + PyObject *item_src = PyList_GET_ITEM(ls, i); + PyObject *item_dst; /* must be set below */ + const char *item_idname = _PyUnicode_AsString(item_src); - // printf(" %s\n", item_str); + // printf(" %s\n", item_idname); - if (item_str) { - ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_str); + if (item_idname) { + ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_idname); if (id) { #ifdef USE_RNA_DATABLOCKS /* swap name for pointer to the id */ - Py_DECREF(item); - item = PyCapsule_New((void *)id, NULL, NULL); + item_dst = PyCapsule_New((void *)id, NULL, NULL); +#else + /* leave as is */ + continue; #endif } else { - bpy_lib_exit_warn_idname(self, name_plural, item_str); + bpy_lib_exit_warn_idname(self, name_plural, item_idname); /* just warn for now */ /* err = -1; */ -#ifdef USE_RNA_DATABLOCKS - item = Py_INCREF_RET(Py_None); -#endif + item_dst = Py_INCREF_RET(Py_None); } /* ID or None */ } else { /* XXX, could complain about this */ - bpy_lib_exit_warn_type(self, item); + bpy_lib_exit_warn_type(self, item_src); PyErr_Clear(); - -#ifdef USE_RNA_DATABLOCKS - item = Py_INCREF_RET(Py_None); -#endif + item_dst = Py_INCREF_RET(Py_None); } -#ifdef USE_RNA_DATABLOCKS - PyList_SET_ITEM(ls, i, item); -#endif + /* item_dst must be new or already incref'd */ + Py_DECREF(item_src); + PyList_SET_ITEM(ls, i, item_dst); } } } @@ -410,7 +408,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* copied from wm_operator.c */ { /* mark all library linked objects to be updated */ - BKE_main_lib_objects_recalc_all(G.main); + BKE_main_lib_objects_recalc_all(bmain); /* append, rather than linking */ if ((self->flag & FILE_LINK) == 0) { @@ -422,6 +420,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* finally swap the capsules for real bpy objects * important since BLO_library_append_end initializes NodeTree types used by srna->refine */ +#ifdef USE_RNA_DATABLOCKS { int idcode_step = 0, idcode; while ((idcode = BKE_idcode_iter_step(&idcode_step))) { @@ -451,6 +450,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) } } } +#endif /* USE_RNA_DATABLOCKS */ Py_RETURN_NONE; } diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index eaa96e6243c..bd3e5736c6c 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -223,9 +223,9 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) WM_operator_properties_create_ptr(&ptr, ot); WM_operator_properties_sanitize(&ptr, 0); - if (kw && PyDict_Size(kw)) - error_val = pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); - + if (kw && PyDict_Size(kw)) { + error_val = pyrna_pydict_to_props(&ptr, kw, false, "Converting py args to operator properties: "); + } if (error_val == 0) { ReportList *reports; @@ -353,8 +353,9 @@ static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args) /* Save another lookup */ RNA_pointer_create(NULL, ot->srna, NULL, &ptr); - if (kw && PyDict_Size(kw)) - error_val = pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); + if (kw && PyDict_Size(kw)) { + error_val = pyrna_pydict_to_props(&ptr, kw, false, "Converting py args to operator properties: "); + } if (error_val == 0) buf = WM_operator_pystring_ex(C, NULL, all_args, macro_args, ot, &ptr); diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index bce1d923462..3baeae0384a 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -2627,17 +2627,29 @@ PyDoc_STRVAR(BPy_EnumProperty_doc, " Returns a new enumerator property definition.\n" "\n" " :arg items: sequence of enum items formatted:\n" -" [(identifier, name, description, icon, number), ...] where the identifier is used\n" -" for python access and other values are used for the interface.\n" -" The three first elements of the tuples are mandatory.\n" -" The fourth one is either the (unique!) number id of the item or, if followed by a fith element\n" -" (which must be the numid), an icon string identifier or integer icon value (e.g. returned by icon()...).\n" -" Note the item is optional.\n" +" ``[(identifier, name, description, icon, number), ...]``.\n" +"\n" +" The first three elements of the tuples are mandatory.\n" +"\n" +" :identifier: The identifier is used for Python access.\n" +" :name: Name for the interace.\n" +" :description: Used for documentation and tooltips.\n" +" :icon: An icon string identifier or integer icon value\n" +" (e.g. returned by :class:`bpy.types.UILayout.icon`)\n" +" :number: Unique value used as the identifier for this item (stored in file data).\n" +" Use when the identifier may need to change.\n" +"\n" +" When an item only contains 4 items they define ``(identifier, name, description, number)``.\n" +"\n" " For dynamic values a callback can be passed which returns a list in\n" " the same format as the static list.\n" -" This function must take 2 arguments (self, context), **context may be None**.\n" -" WARNING: There is a known bug with using a callback,\n" -" Python must keep a reference to the strings returned or Blender will crash.\n" +" This function must take 2 arguments ``(self, context)``, **context may be None**.\n" +"\n" +" .. warning::\n" +"\n" +" There is a known bug with using a callback,\n" +" Python must keep a reference to the strings returned or Blender will crash.\n" +"\n" " :type items: sequence of string tuples or a function\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC @@ -2986,7 +2998,7 @@ static struct PyModuleDef props_module = { "This module defines properties to extend Blender's internal data. The result of these functions" " is used to assign properties to classes registered with Blender and can't be used directly.\n" "\n" - ".. warning:: All parameters to these functions must be passed as keywords.\n", + ".. note:: All parameters to these functions must be passed as keywords.\n", -1, /* multiple "initialization" just copies the module dict. */ props_methods, NULL, NULL, NULL, NULL diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 4bd30ba4dff..05bd55d3781 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -136,7 +136,9 @@ static void id_release_gc(struct ID *id) PyGC_Head *g = gen->gc.gc_next; while ((g = g->gc.gc_next) != gen) { PyObject *ob = FROM_GC(g); - if (PyType_IsSubtype(Py_TYPE(ob), &pyrna_struct_Type) || PyType_IsSubtype(Py_TYPE(ob), &pyrna_prop_Type)) { + if (PyType_IsSubtype(Py_TYPE(ob), &pyrna_struct_Type) || + PyType_IsSubtype(Py_TYPE(ob), &pyrna_prop_Type)) + { BPy_DummyPointerRNA *ob_ptr = (BPy_DummyPointerRNA *)ob; if (ob_ptr->ptr.id.data == id) { pyrna_invalidate(ob_ptr); @@ -358,9 +360,12 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item #ifdef USE_MATHUTILS #include "../mathutils/mathutils.h" /* so we can have mathutils callbacks */ -static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, - Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length); -static short pyrna_rotation_euler_order_get(PointerRNA *ptr, PropertyRNA **prop_eul_order, const short order_fallback); +static PyObject *pyrna_prop_array_subscript_slice( + BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, + Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length); +static short pyrna_rotation_euler_order_get( + PointerRNA *ptr, const short order_fallback, + PropertyRNA **r_prop_eul_order); /* bpyrna vector/euler/quat callbacks */ static unsigned char mathutils_rna_array_cb_index = -1; /* index for our callbacks */ @@ -395,7 +400,7 @@ static int mathutils_rna_vector_get(BaseMathObject *bmo, int subtype) if (subtype == MATHUTILS_CB_SUBTYPE_EUL) { EulerObject *eul = (EulerObject *)bmo; PropertyRNA *prop_eul_order = NULL; - eul->order = pyrna_rotation_euler_order_get(&self->ptr, &prop_eul_order, eul->order); + eul->order = pyrna_rotation_euler_order_get(&self->ptr, eul->order, &prop_eul_order); } return 0; @@ -442,7 +447,7 @@ static int mathutils_rna_vector_set(BaseMathObject *bmo, int subtype) if (subtype == MATHUTILS_CB_SUBTYPE_EUL) { EulerObject *eul = (EulerObject *)bmo; PropertyRNA *prop_eul_order = NULL; - short order = pyrna_rotation_euler_order_get(&self->ptr, &prop_eul_order, eul->order); + short order = pyrna_rotation_euler_order_get(&self->ptr, eul->order, &prop_eul_order); if (order != eul->order) { RNA_property_enum_set(&self->ptr, prop_eul_order, eul->order); if (RNA_property_update_check(prop_eul_order)) { @@ -562,16 +567,21 @@ static Mathutils_Callback mathutils_rna_matrix_cb = { NULL }; -static short pyrna_rotation_euler_order_get(PointerRNA *ptr, PropertyRNA **prop_eul_order, const short order_fallback) +static short pyrna_rotation_euler_order_get( + PointerRNA *ptr, const short order_fallback, + PropertyRNA **r_prop_eul_order) { /* attempt to get order */ - if (*prop_eul_order == NULL) - *prop_eul_order = RNA_struct_find_property(ptr, "rotation_mode"); + if (*r_prop_eul_order == NULL) { + *r_prop_eul_order = RNA_struct_find_property(ptr, "rotation_mode"); + } - if (*prop_eul_order) { - short order = RNA_property_enum_get(ptr, *prop_eul_order); - if (order >= EULER_ORDER_XYZ && order <= EULER_ORDER_ZYX) /* could be quat or axisangle */ + if (*r_prop_eul_order) { + short order = RNA_property_enum_get(ptr, *r_prop_eul_order); + /* could be quat or axisangle */ + if (order >= EULER_ORDER_XYZ && order <= EULER_ORDER_ZYX) { return order; + } } return order_fallback; @@ -639,7 +649,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) RNA_property_float_get_array(ptr, prop, ((VectorObject *)ret)->vec); } else { - PyObject *vec_cb = Vector_CreatePyObject_cb(ret, len, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_VEC); + PyObject *vec_cb = Vector_CreatePyObject_cb( + ret, len, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_VEC); Py_DECREF(ret); /* the vector owns now */ ret = vec_cb; /* return the vector instead */ } @@ -652,7 +663,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) RNA_property_float_get_array(ptr, prop, ((MatrixObject *)ret)->matrix); } else { - PyObject *mat_cb = Matrix_CreatePyObject_cb(ret, 4, 4, mathutils_rna_matrix_cb_index, 0); + PyObject *mat_cb = Matrix_CreatePyObject_cb( + ret, 4, 4, mathutils_rna_matrix_cb_index, 0); Py_DECREF(ret); /* the matrix owns now */ ret = mat_cb; /* return the matrix instead */ } @@ -663,7 +675,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) RNA_property_float_get_array(ptr, prop, ((MatrixObject *)ret)->matrix); } else { - PyObject *mat_cb = Matrix_CreatePyObject_cb(ret, 3, 3, mathutils_rna_matrix_cb_index, 0); + PyObject *mat_cb = Matrix_CreatePyObject_cb( + ret, 3, 3, mathutils_rna_matrix_cb_index, 0); Py_DECREF(ret); /* the matrix owns now */ ret = mat_cb; /* return the matrix instead */ } @@ -675,14 +688,16 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) if (is_thick) { /* attempt to get order, only needed for thick types since wrapped with update via callbacks */ PropertyRNA *prop_eul_order = NULL; - short order = pyrna_rotation_euler_order_get(ptr, &prop_eul_order, EULER_ORDER_XYZ); + short order = pyrna_rotation_euler_order_get(ptr, EULER_ORDER_XYZ, &prop_eul_order); ret = Euler_CreatePyObject(NULL, order, NULL); /* TODO, get order from RNA */ RNA_property_float_get_array(ptr, prop, ((EulerObject *)ret)->eul); } else { /* order will be updated from callback on use */ - PyObject *eul_cb = Euler_CreatePyObject_cb(ret, EULER_ORDER_XYZ, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_EUL); // TODO, get order from RNA + // TODO, get order from RNA + PyObject *eul_cb = Euler_CreatePyObject_cb( + ret, EULER_ORDER_XYZ, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_EUL); Py_DECREF(ret); /* the euler owns now */ ret = eul_cb; /* return the euler instead */ } @@ -693,7 +708,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) RNA_property_float_get_array(ptr, prop, ((QuaternionObject *)ret)->quat); } else { - PyObject *quat_cb = Quaternion_CreatePyObject_cb(ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_QUAT); + PyObject *quat_cb = Quaternion_CreatePyObject_cb( + ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_QUAT); Py_DECREF(ret); /* the quat owns now */ ret = quat_cb; /* return the quat instead */ } @@ -707,7 +723,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) RNA_property_float_get_array(ptr, prop, ((ColorObject *)ret)->col); } else { - PyObject *col_cb = Color_CreatePyObject_cb(ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_COLOR); + PyObject *col_cb = Color_CreatePyObject_cb( + ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_COLOR); Py_DECREF(ret); /* the color owns now */ ret = col_cb; /* return the color instead */ } @@ -738,9 +755,11 @@ thick_wrap_slice: } /* same as RNA_enum_value_from_id but raises an exception */ -int pyrna_enum_value_from_id(EnumPropertyItem *item, const char *identifier, int *value, const char *error_prefix) +int pyrna_enum_value_from_id( + EnumPropertyItem *item, const char *identifier, int *r_value, + const char *error_prefix) { - if (RNA_enum_value_from_id(item, identifier, value) == 0) { + if (RNA_enum_value_from_id(item, identifier, r_value) == 0) { const char *enum_str = BPy_enum_as_string(item); PyErr_Format(PyExc_ValueError, "%s: '%.200s' not found in (%s)", @@ -1165,7 +1184,9 @@ static const char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop) } -static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *val, const char *error_prefix) +static int pyrna_string_to_enum( + PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *r_value, + const char *error_prefix) { const char *param = _PyUnicode_AsString(item); @@ -1176,7 +1197,7 @@ static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *pr return -1; } else { - if (!RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, val)) { + if (!RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, r_value)) { const char *enum_str = pyrna_enum_as_string(ptr, prop); PyErr_Format(PyExc_TypeError, "%.200s enum \"%.200s\" not found in (%.200s)", @@ -1253,7 +1274,9 @@ error: } /* 'value' _must_ be a set type, error check before calling */ -int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_value, const char *error_prefix) +int pyrna_set_to_enum_bitfield( + EnumPropertyItem *items, PyObject *value, int *r_value, + const char *error_prefix) { /* set of enum items, concatenate all values with OR */ int ret, flag = 0; @@ -1286,7 +1309,9 @@ int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_ return 0; } -static int pyrna_prop_to_enum_bitfield(PointerRNA *ptr, PropertyRNA *prop, PyObject *value, int *r_value, const char *error_prefix) +static int pyrna_prop_to_enum_bitfield( + PointerRNA *ptr, PropertyRNA *prop, PyObject *value, int *r_value, + const char *error_prefix) { EnumPropertyItem *item; int ret; @@ -1505,9 +1530,13 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) return ret; } -/* This function is used by operators and converting dicts into collections. - * Its takes keyword args and fills them with property values */ -int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const char *error_prefix) +/** + * This function is used by operators and converting dicts into collections. + * Its takes keyword args and fills them with property values + */ +int pyrna_pydict_to_props( + PointerRNA *ptr, PyObject *kw, const bool all_args, + const char *error_prefix) { int error_val = 0; int totkw; @@ -1582,7 +1611,9 @@ static PyObject *pyrna_func_to_py(const PointerRNA *ptr, FunctionRNA *func) } -static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value, const char *error_prefix) +static int pyrna_py_to_prop( + PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value, + const char *error_prefix) { /* XXX hard limits should be checked here */ const int type = RNA_property_type(prop); @@ -1713,7 +1744,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb } else { /* same as unicode */ - if (data) *((char **)data) = (char *)param; /*XXX, this is suspect but needed for function calls, need to see if theres a better way */ + /* XXX, this is suspect but needed for function calls, need to see if theres a better way */ + if (data) *((char **)data) = (char *)param; else RNA_property_string_set(ptr, prop, param); } } @@ -1753,7 +1785,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb } else { /* same as bytes */ - if (data) *((char **)data) = (char *)param; /*XXX, this is suspect but needed for function calls, need to see if theres a better way */ + /* XXX, this is suspect but needed for function calls, need to see if theres a better way */ + if (data) *((char **)data) = (char *)param; else RNA_property_string_set(ptr, prop, param); } #ifdef USE_STRING_COERCE @@ -1801,8 +1834,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb * if the prop is not an operator type and the pyobject is an operator, * use its properties in place of its self. * - * this is so bad that its almost a good reason to do away with fake 'self.properties -> self' class mixing - * if this causes problems in the future it should be removed. + * this is so bad that its almost a good reason to do away with fake 'self.properties -> self' + * class mixing if this causes problems in the future it should be removed. */ if ((ptr_type == &RNA_AnyType) && (BPy_StructRNA_Check(value)) && @@ -1817,7 +1850,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb * forward back to pyrna_pydict_to_props */ if (RNA_struct_is_a(ptr_type, &RNA_OperatorProperties) && PyDict_Check(value)) { PointerRNA opptr = RNA_property_pointer_get(ptr, prop); - return pyrna_pydict_to_props(&opptr, value, 0, error_prefix); + return pyrna_pydict_to_props(&opptr, value, false, error_prefix); } /* another exception, allow to pass a collection as an RNA property */ @@ -1983,7 +2016,10 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb else RNA_property_collection_add(ptr, prop, &itemptr); - if (pyrna_pydict_to_props(&itemptr, item, 1, "Converting a python list to an RNA collection") == -1) { + if (pyrna_pydict_to_props( + &itemptr, item, true, + "Converting a python list to an RNA collection") == -1) + { PyObject *msg = PyC_ExceptionBuffer(); const char *msg_char = _PyUnicode_AsString(msg); @@ -2245,19 +2281,21 @@ static PyObject *pyrna_prop_collection_subscript_str(BPy_PropertyRNA *self, cons } /* static PyObject *pyrna_prop_array_subscript_str(BPy_PropertyRNA *self, char *keyname) */ -/* special case: bpy.data.objects["some_id_name", "//some_lib_name.blend"] - * also for: bpy.data.objects.get(("some_id_name", "//some_lib_name.blend"), fallback) +/** + * Special case: `bpy.data.objects["some_id_name", "//some_lib_name.blend"]` + * also for: `bpy.data.objects.get(("some_id_name", "//some_lib_name.blend"), fallback)` * - * note: + * \note * error codes since this is not to be called directly from python, - * this matches pythons __contains__ values capi. - * -1: exception set - * 0: not found - * 1: found */ -static int pyrna_prop_collection_subscript_str_lib_pair_ptr(BPy_PropertyRNA *self, PyObject *key, - const char *err_prefix, const short err_not_found, - PointerRNA *r_ptr - ) + * this matches pythons `__contains__` values capi. + * - -1: exception set + * - 0: not found + * - 1: found + */ +static int pyrna_prop_collection_subscript_str_lib_pair_ptr( + BPy_PropertyRNA *self, PyObject *key, + const char *err_prefix, const short err_not_found, + PointerRNA *r_ptr) { const char *keyname; @@ -2342,8 +2380,9 @@ static int pyrna_prop_collection_subscript_str_lib_pair_ptr(BPy_PropertyRNA *sel } } -static PyObject *pyrna_prop_collection_subscript_str_lib_pair(BPy_PropertyRNA *self, PyObject *key, - const char *err_prefix, const bool err_not_found) +static PyObject *pyrna_prop_collection_subscript_str_lib_pair( + BPy_PropertyRNA *self, PyObject *key, + const char *err_prefix, const bool err_not_found) { PointerRNA ptr; const int contains = pyrna_prop_collection_subscript_str_lib_pair_ptr(self, key, err_prefix, err_not_found, &ptr); @@ -2395,8 +2434,9 @@ static PyObject *pyrna_prop_collection_subscript_slice(BPy_PropertyRNA *self, Py * note: could also use pyrna_prop_array_to_py_index(self, count) in a loop but its a lot slower * since at the moment it reads (and even allocates) the entire array for each index. */ -static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, - Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length) +static PyObject *pyrna_prop_array_subscript_slice( + BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, + Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length) { int count, totdim; PyObject *tuple; @@ -4588,9 +4628,10 @@ static PyObject *pyrna_prop_collection_find(BPy_PropertyRNA *self, PyObject *key return PyLong_FromLong(index); } -static bool foreach_attr_type(BPy_PropertyRNA *self, const char *attr, - /* values to assign */ - RawPropertyType *raw_type, int *attr_tot, bool *attr_signed) +static bool foreach_attr_type( + BPy_PropertyRNA *self, const char *attr, + /* values to assign */ + RawPropertyType *raw_type, int *attr_tot, bool *attr_signed) { PropertyRNA *prop; bool attr_ok = true; @@ -4618,12 +4659,12 @@ static bool foreach_attr_type(BPy_PropertyRNA *self, const char *attr, } /* pyrna_prop_collection_foreach_get/set both use this */ -static int foreach_parse_args(BPy_PropertyRNA *self, PyObject *args, +static int foreach_parse_args( + BPy_PropertyRNA *self, PyObject *args, - /* values to assign */ - const char **attr, PyObject **seq, int *tot, int *size, - RawPropertyType *raw_type, int *attr_tot, bool *attr_signed - ) + /* values to assign */ + const char **attr, PyObject **seq, int *tot, int *size, + RawPropertyType *raw_type, int *attr_tot, bool *attr_signed) { #if 0 int array_tot; @@ -7500,7 +7541,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param } } - if (err != -1 && (is_staticmethod || is_classmethod || py_class_instance)) { /* Initializing the class worked, now run its invoke function */ + /* Initializing the class worked, now run its invoke function */ + if (err != -1 && (is_staticmethod || is_classmethod || py_class_instance)) { PyObject *item = PyObject_GetAttrString((PyObject *)py_class, RNA_function_identifier(func)); if (item) { @@ -7913,7 +7955,9 @@ static PyObject *pyrna_register_class(PyObject *UNUSED(self), PyObject *py_class } -static int pyrna_srna_contains_pointer_prop_srna(StructRNA *srna_props, StructRNA *srna, const char **prop_identifier) +static int pyrna_srna_contains_pointer_prop_srna( + StructRNA *srna_props, StructRNA *srna, + const char **r_prop_identifier) { PropertyRNA *prop; LinkData *link; @@ -7928,7 +7972,7 @@ static int pyrna_srna_contains_pointer_prop_srna(StructRNA *srna_props, StructRN RNA_pointer_create(NULL, &RNA_Struct, srna_props, &tptr); if (RNA_property_pointer_type(&tptr, prop) == srna) { - *prop_identifier = RNA_property_identifier(prop); + *r_prop_identifier = RNA_property_identifier(prop); return 1; } } diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index c5d4a346f56..e38d4f095d6 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -181,7 +181,7 @@ PyObject *pyrna_id_CreatePyObject(struct ID *id); bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id); /* operators also need this to set args */ -int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const char *error_prefix); +int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const bool all_args, const char *error_prefix); PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop); unsigned int *pyrna_set_to_enum_bitmap( diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c index c3bb588f7eb..50dd4618166 100644 --- a/source/blender/python/intern/gpu.c +++ b/source/blender/python/intern/gpu.c @@ -330,10 +330,10 @@ PyObject *GPU_initPython(void) /* gpu.offscreen */ PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); - PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module); + PyDict_SetItem(PyImport_GetModuleDict(), PyModule_GetNameObject(module), module); return module; } diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 635090869ea..5c505247a97 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -638,30 +638,30 @@ PyMODINIT_FUNC PyInit_mathutils(void) /* XXX, python doesnt do imports with this usefully yet * 'from mathutils.geometry import PolyFill' * ...fails without this. */ - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); PyModule_AddObject(mod, "interpolate", (submodule = PyInit_mathutils_interpolate())); /* XXX, python doesnt do imports with this usefully yet * 'from mathutils.geometry import PolyFill' * ...fails without this. */ - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); #ifndef MATH_STANDALONE /* Noise submodule */ PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); /* BVHTree submodule */ PyModule_AddObject(mod, "bvhtree", (submodule = PyInit_mathutils_bvhtree())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); /* KDTree submodule */ PyModule_AddObject(mod, "kdtree", (submodule = PyInit_mathutils_kdtree())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); #endif diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m index d42d0ee8ebb..ba7ee0a8936 100644 --- a/source/blender/quicktime/apple/qtkit_import.m +++ b/source/blender/quicktime/apple/qtkit_import.m @@ -200,7 +200,7 @@ static ImBuf *nsImageToiBuf(NSImage *sourceImage, int width, int height) /* Convert the image in a RGBA 32bit format */ /* As Core Graphics does not support contextes with non premutliplied alpha, - we need to get alpha key values in a separate batch */ + * we need to get alpha key values in a separate batch */ /* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */ blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index ce0691b7632..39f62f9fc33 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -231,8 +231,9 @@ struct RenderStats *RE_GetStats(struct Render *re); void RE_ResultGet32(struct Render *re, unsigned int *rect); void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect, const int view_id); -void RE_render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd, - struct ImBuf *ibuf, const int view_id); +void RE_render_result_rect_from_ibuf( + struct RenderResult *rr, struct RenderData *rd, + struct ImBuf *ibuf, const int view_id); struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name); float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname); @@ -249,8 +250,8 @@ struct Object *RE_GetCamera(struct Render *re); /* return camera override if set void RE_SetOverrideCamera(struct Render *re, struct Object *camera); void RE_SetCamera(struct Render *re, struct Object *camera); void RE_SetEnvmapCamera(struct Render *re, struct Object *cam_ob, float viewscale, float clipsta, float clipend); -void RE_SetWindow(struct Render *re, rctf *viewplane, float clipsta, float clipend); -void RE_SetOrtho(struct Render *re, rctf *viewplane, float clipsta, float clipend); +void RE_SetWindow(struct Render *re, const rctf *viewplane, float clipsta, float clipend); +void RE_SetOrtho(struct Render *re, const rctf *viewplane, float clipsta, float clipend); void RE_SetPixelSize(struct Render *re, float pixsize); /* option to set viewmatrix before making dbase */ @@ -258,10 +259,12 @@ void RE_SetView(struct Render *re, float mat[4][4]); /* get current view and window transform */ void RE_GetView(struct Render *re, float mat[4][4]); -void RE_GetViewPlane(struct Render *re, rctf *viewplane, rcti *disprect); +void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect); /* make or free the dbase */ -void RE_Database_FromScene(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, int use_camera_view); +void RE_Database_FromScene( + struct Render *re, struct Main *bmain, struct Scene *scene, + unsigned int lay, int use_camera_view); void RE_Database_Preprocess(struct Render *re); void RE_Database_Free(struct Render *re); @@ -304,11 +307,16 @@ void RE_SetReports(struct Render *re, struct ReportList *reports); void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene); bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode); -bool RE_WriteRenderResult(struct ReportList *reports, RenderResult *rr, const char *filename, struct ImageFormatData *imf, const bool multiview, const char *view); -struct RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); +bool RE_WriteRenderResult( + struct ReportList *reports, RenderResult *rr, const char *filename, + struct ImageFormatData *imf, const bool multiview, const char *view); +struct RenderResult *RE_MultilayerConvert( + void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); extern const float default_envmap_layout[]; -bool RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]); +bool RE_WriteEnvmapResult( + struct ReportList *reports, struct Scene *scene, struct EnvMap *env, + const char *relpath, const char imtype, float layout[12]); /* do a full sample buffer compo */ void RE_MergeFullSample(struct Render *re, struct Main *bmain, struct Scene *sce, struct bNodeTree *ntree); @@ -326,7 +334,9 @@ void RE_current_scene_update_cb(struct Render *re, void *handle, void (*f)(void /* should move to kernel once... still unsure on how/where */ float RE_filter_value(int type, float x); /* vector blur zbuffer method */ -void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect); +void RE_zbuf_accumulate_vecblur( + struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, + const float *imgrect, float *vecbufrect, const float *zbufrect); int RE_seq_render_active(struct Scene *scene, struct RenderData *rd); @@ -351,7 +361,9 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int pas #define RE_BAKE_DERIVATIVE 13 #define RE_BAKE_VERTEX_COLORS 14 -void RE_Database_Baking(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, const int type, struct Object *actob); +void RE_Database_Baking( + struct Render *re, struct Main *bmain, struct Scene *scene, + unsigned int lay, const int type, struct Object *actob); void RE_DataBase_GetView(struct Render *re, float mat[4][4]); void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]); diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 6de5da3795a..b3a5ccdae17 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -180,6 +180,7 @@ struct Render { float jit[32][2]; float mblur_jit[32][2]; ListBase *qmcsamplers; + int num_qmc_samplers; /* shadow counter, detect shadow-reuse for shaders */ int shadowsamplenr[BLENDER_MAX_THREADS]; diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index 308903c6c6d..7254fd25ee6 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -90,7 +90,7 @@ extern void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]); extern void ray_trace(ShadeInput *shi, ShadeResult *); extern void ray_ao(ShadeInput *shi, float ao[3], float env[3]); extern void init_jitter_plane(LampRen *lar); -extern void init_ao_sphere(struct World *wrld); +extern void init_ao_sphere(Render *re, struct World *wrld); extern void init_render_qmcsampler(Render *re); extern void free_render_qmcsampler(Render *re); diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp index f511042749e..2104315dc00 100644 --- a/source/blender/render/intern/raytrace/rayobject.cpp +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -145,8 +145,8 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { /* check if intersection is within ray length */ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { - r_uv[0] = uv[0]; - r_uv[1] = uv[1]; + r_uv[0] = -uv[0]; + r_uv[1] = -uv[1]; *lambda = l; return 1; } @@ -157,8 +157,8 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { /* check if intersection is within ray length */ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { - r_uv[0] = uv[0]; - r_uv[1] = uv[1]; + r_uv[0] = -uv[0]; + r_uv[1] = -uv[1]; *lambda = l; return 2; } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 907974e20dc..86961cdd169 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -4192,7 +4192,7 @@ static void split_quads(ObjectRen *obr, int dir) vlr= RE_findOrAddVlak(obr, a); /* test if rendering as a quad or triangle, skip wire */ - if (vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) { + if ((vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) { if (vlr->v4) { @@ -5230,7 +5230,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT) - init_ao_sphere(&re->wrld); + init_ao_sphere(re, &re->wrld); } /* still bad... doing all */ @@ -5956,7 +5956,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT) - init_ao_sphere(&re->wrld); + init_ao_sphere(re, &re->wrld); } /* still bad... doing all */ diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index c5c3b6bbf94..b3d31e3b93a 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -115,6 +115,8 @@ typedef struct OcclusionTree { int doindirect; OcclusionCache *cache; + + int num_threads; } OcclusionTree; typedef struct OcclusionThread { @@ -641,6 +643,7 @@ static void occ_build_sh_normalize(OccNode *node) static OcclusionTree *occ_tree_build(Render *re) { + const int num_threads = re->r.threads; OcclusionTree *tree; ObjectInstanceRen *obi; ObjectRen *obr; @@ -679,7 +682,7 @@ static OcclusionTree *occ_tree_build(Render *re) BLI_memarena_use_calloc(tree->arena); if (re->wrld.aomode & WO_AOCACHE) - tree->cache = MEM_callocN(sizeof(OcclusionCache) * BLENDER_MAX_THREADS, "OcclusionCache"); + tree->cache = MEM_callocN(sizeof(OcclusionCache) * num_threads, "OcclusionCache"); tree->face = MEM_callocN(sizeof(OccFace) * totface, "OcclusionFace"); tree->co = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionCo"); @@ -730,9 +733,11 @@ static OcclusionTree *occ_tree_build(Render *re) if (!(re->test_break(re->tbh))) occ_build_sh_normalize(tree->root); - for (a = 0; a < BLENDER_MAX_THREADS; a++) + for (a = 0; a < num_threads; a++) tree->stack[a] = MEM_callocN(sizeof(OccNode) * TOTCHILD * (tree->maxdepth + 1), "OccStack"); + tree->num_threads = num_threads; + return tree; } @@ -742,7 +747,7 @@ static void occ_free_tree(OcclusionTree *tree) if (tree) { if (tree->arena) BLI_memarena_free(tree->arena); - for (a = 0; a < BLENDER_MAX_THREADS; a++) + for (a = 0; a < tree->num_threads; a++) if (tree->stack[a]) MEM_freeN(tree->stack[a]); if (tree->occlusion) MEM_freeN(tree->occlusion); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 6b910dc9fc4..1ee905c596c 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -355,7 +355,7 @@ Scene *RE_GetScene(Render *re) * Same as #RE_AcquireResultImage but creating the necessary views to store the result * fill provided result struct with a copy of thew views of what is done so far the * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews -*/ + */ void RE_AcquireResultImageViews(Render *re, RenderResult *rr) { memset(rr, 0, sizeof(RenderResult)); @@ -931,7 +931,7 @@ void render_update_anim_renderdata(Render *re, RenderData *rd) BLI_duplicatelist(&re->r.views, &rd->views); } -void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend) +void RE_SetWindow(Render *re, const rctf *viewplane, float clipsta, float clipend) { /* re->ok flag? */ @@ -946,7 +946,7 @@ void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend) } -void RE_SetOrtho(Render *re, rctf *viewplane, float clipsta, float clipend) +void RE_SetOrtho(Render *re, const rctf *viewplane, float clipsta, float clipend) { /* re->ok flag? */ @@ -967,15 +967,17 @@ void RE_SetView(Render *re, float mat[4][4]) invert_m4_m4(re->viewinv, re->viewmat); } -void RE_GetViewPlane(Render *re, rctf *viewplane, rcti *disprect) +void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect) { - *viewplane = re->viewplane; + *r_viewplane = re->viewplane; /* make disprect zero when no border render, is needed to detect changes in 3d view render */ - if (re->r.mode & R_BORDER) - *disprect = re->disprect; - else - BLI_rcti_init(disprect, 0, 0, 0, 0); + if (re->r.mode & R_BORDER) { + *r_disprect = re->disprect; + } + else { + BLI_rcti_init(r_disprect, 0, 0, 0, 0); + } } void RE_GetView(Render *re, float mat[4][4]) diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 9aac5ed1f1d..26a0b0c71b4 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -174,10 +174,11 @@ void freeraytree(Render *re) #ifdef RE_RAYCOUNTER { + const int num_threads = re->r.threads; RayCounter sum; memset(&sum, 0, sizeof(sum)); int i; - for (i=0; i<BLENDER_MAX_THREADS; i++) + for (i=0; i<num_threads; i++) RE_RC_MERGE(&sum, re_rc_counter+i); RE_RC_INFO(&sum); } @@ -1186,7 +1187,9 @@ static void QMC_sampleHemiCosine(float vec[3], QMCSampler *qsa, int thread, int /* called from convertBlenderScene.c */ void init_render_qmcsampler(Render *re) { - re->qmcsamplers= MEM_callocN(sizeof(ListBase)*BLENDER_MAX_THREADS, "QMCListBase"); + const int num_threads = re->r.threads; + re->qmcsamplers= MEM_callocN(sizeof(ListBase)*num_threads, "QMCListBase"); + re->num_qmc_samplers = num_threads; } static QMCSampler *get_thread_qmcsampler(Render *re, int thread, int type, int tot) @@ -1220,7 +1223,7 @@ void free_render_qmcsampler(Render *re) if (re->qmcsamplers) { QMCSampler *qsa, *next; int a; - for (a=0; a<BLENDER_MAX_THREADS; a++) { + for (a = 0; a < re->num_qmc_samplers; a++) { for (qsa=re->qmcsamplers[a].first; qsa; qsa=next) { next= qsa->next; QMC_freeSampler(qsa); @@ -1695,9 +1698,10 @@ static void DS_energy(float *sphere, int tot, float vec[3]) /* called from convertBlenderScene.c */ /* creates an equally distributed spherical sample pattern */ /* and allocates threadsafe memory */ -void init_ao_sphere(World *wrld) +void init_ao_sphere(Render *re, World *wrld) { /* fixed random */ + const int num_threads = re->r.threads; RNG *rng; float *fp; int a, tot, iter= 16; @@ -1721,7 +1725,7 @@ void init_ao_sphere(World *wrld) } /* tables */ - wrld->aotables= MEM_mallocN(BLENDER_MAX_THREADS*3*tot*sizeof(float), "AO tables"); + wrld->aotables= MEM_mallocN(num_threads*3*tot*sizeof(float), "AO tables"); BLI_rng_free(rng); } diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 513cfa6df7d..b4a14f5337d 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -3653,7 +3653,8 @@ void render_realtime_texture(ShadeInput *shi, Image *ima) if (firsttime) { BLI_lock_thread(LOCK_IMAGE); if (firsttime) { - for (a=0; a<BLENDER_MAX_THREADS; a++) { + const int num_threads = BLI_system_thread_count(); + for (a = 0; a < num_threads; a++) { memset(&imatex[a], 0, sizeof(Tex)); BKE_texture_default(&imatex[a]); imatex[a].type= TEX_IMAGE; diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index d3d26011a57..76e6ca8d467 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -1006,7 +1006,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]); yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]); - if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0f; + if (yn == 0.0f && xn >= 0.0f) zn = 0.0f; else zn = atan2f(yn, xn); har->sin = sinf(zn); @@ -1136,7 +1136,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]); yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]); - if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0; + if (yn == 0.0f && xn >= 0.0f) zn = 0.0f; else zn = atan2f(yn, xn); har->sin = sinf(zn); diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c index 553710b4367..26ca3ad50e0 100644 --- a/source/blender/render/intern/source/sss.c +++ b/source/blender/render/intern/source/sss.c @@ -279,13 +279,19 @@ static void build_Rd_table(ScatterSettings *ss) for (i= 0; i < size; i++) { r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE); - /*if (r < ss->invsigma_t_*ss->invsigma_t_) - r= ss->invsigma_t_*ss->invsigma_t_;*/ +#if 0 + if (r < ss->invsigma_t_*ss->invsigma_t_) { + r= ss->invsigma_t_*ss->invsigma_t_; + } +#endif ss->tableRd[i]= Rd(ss, sqrtf(r)); r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE); - /*if (r < ss->invsigma_t_) - r= ss->invsigma_t_;*/ +#if 0 + if (r < ss->invsigma_t_) { + r= ss->invsigma_t_; + } +#endif ss->tableRd2[i]= Rd(ss, r); } } diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index d3a1dcfd8ce..9f777631e52 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -2883,14 +2883,17 @@ static void set_quad_bezier_ipo(float fac, float *data) data[2]= fac*fac; } -void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect) +void RE_zbuf_accumulate_vecblur( + NodeBlurData *nbd, int xsize, int ysize, float *newrect, + const float *imgrect, float *vecbufrect, const float *zbufrect) { ZSpan zspan; DrawBufPixel *rectdraw, *dr; static float jit[256][2]; float v1[3], v2[3], v3[3], v4[3], fx, fy; - float *rectvz, *dvz, *dimg, *dvec1, *dvec2, *dz, *dz1, *dz2, *rectz; - float *minvecbufrect= NULL, *rectweight, *rw, *rectmax, *rm, *ro; + const float *dimg, *dz, *ro; + float *rectvz, *dvz, *dvec1, *dvec2, *dz1, *dz2, *rectz; + float *minvecbufrect= NULL, *rectweight, *rw, *rectmax, *rm; float maxspeedsq= (float)nbd->maxspeed*nbd->maxspeed; int y, x, step, maxspeed=nbd->maxspeed, samples= nbd->samples; int tsktsk= 0; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 3fbbea72046..127525bb857 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -114,6 +114,8 @@ void WM_autosave_init(struct wmWindowManager *wm); void WM_recover_last_session(struct bContext *C, struct ReportList *reports); void WM_file_tag_modified(const struct bContext *C); +void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports); + /* mouse cursors */ void WM_cursor_set(struct wmWindow *win, int curs); void WM_cursor_modal_set(struct wmWindow *win, int curs); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 4a48143b87b..51fbabac638 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -52,7 +52,7 @@ #include "RNA_access.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_context.h" #include "BKE_idprop.h" #include "BKE_global.h" diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 638d6fe96d2..a85e39ac65e 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -482,8 +482,6 @@ static void wm_file_read_post(bContext *C, bool is_startup_file) BPY_python_reset(C); addons_loaded = true; } -#else - UNUSED_VARS(is_startup_file); #endif /* WITH_PYTHON */ WM_operatortype_last_properties_clear_all(); @@ -492,8 +490,12 @@ static void wm_file_read_post(bContext *C, bool is_startup_file) BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); - /* would otherwise be handled by event loop */ - if (G.background) { + /* Would otherwise be handled by event loop. + * + * Disabled for startup file, since it causes problems when PyDrivers are used in the startup file. + * While its possible state of startup file may be wrong, + * in this case users nearly always load a file to replace the startup file. */ + if (G.background && (is_startup_file == false)) { Main *bmain = CTX_data_main(C); BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C)); } diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index f3792e0bac6..8195212f3c3 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -62,7 +62,7 @@ #include "BLO_readfile.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_library.h" @@ -691,9 +691,13 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN return OPERATOR_CANCELLED; } -/* Note that IDs listed in lapp_data items *must* have been removed from bmain by caller. */ +/** + * \param library if given, all IDs from that library will be removed and reloaded. Otherwise, IDs must have already + * been removed from \a bmain, and added to \a lapp_data. + */ static void lib_relocate_do( - Main *bmain, WMLinkAppendData *lapp_data, ReportList *reports, AssetEngineType *aet, const bool do_reload) + Main *bmain, Scene *scene, + Library *library, WMLinkAppendData *lapp_data, ReportList *reports, AssetEngineType *aet, const bool do_reload) { ListBase *lbarray[MAX_LIBARRAY]; int lba_idx; @@ -701,6 +705,36 @@ static void lib_relocate_do( LinkNode *itemlink; int item_idx; + /* Remove all IDs to be reloaded from Main. */ + if (library) { + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id = lbarray[lba_idx]->first; + const short idcode = id ? GS(id->name) : 0; + + if (!id || !BKE_idcode_is_linkable(idcode)) { + /* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */ + continue; + } + + for (; id; id = id->next) { + if (id->lib == library) { + WMLinkAppendDataItem *item; + + /* We remove it from current Main, and add it to items to link... */ + /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitely linked here... */ + BLI_remlink(lbarray[lba_idx], id); + item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, NULL, id); + BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries); + +#ifdef PRINT_DEBUG + printf("\tdatablock to seek for: %s\n", id->name); +#endif + } + } + } + } + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* We do not want any instanciation here! */ @@ -839,6 +873,43 @@ static void lib_relocate_do( } } } + + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* important we unset, otherwise these object wont + * link into other scenes from this blend file */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* recreate dependency graph to include new objects */ + DAG_scene_relations_rebuild(bmain, scene); + + /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */ + GPU_materials_free(); +} + +void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) +{ + if (!BLO_has_bfile_extension(lib->filepath)) { + BKE_reportf(reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->filepath); + return; + } + + if (!BLI_exists(lib->filepath)) { + BKE_reportf(reports, RPT_ERROR, + "Trying to reload library '%s' from invalid path '%s'", lib->id.name, lib->filepath); + return; + } + + WMLinkAppendData *lapp_data = wm_link_append_data_new(0); + + wm_link_append_data_library_add(lapp_data, lib->filepath); + + lib_relocate_do(CTX_data_main(C), CTX_data_scene(C), lib, lapp_data, reports, NULL, true); + + wm_link_append_data_free(lapp_data); + + WM_event_add_notifier(C, NC_WINDOW, NULL); } static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) @@ -855,9 +926,6 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) PropertyRNA *prop; WMLinkAppendData *lapp_data; - ListBase *lbarray[MAX_LIBARRAY]; - int lba_idx; - char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; short flag = 0; @@ -949,50 +1017,10 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } } - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id = lbarray[lba_idx]->first; - const short idcode = id ? GS(id->name) : 0; - - if (!id || !BKE_idcode_is_linkable(idcode)) { - /* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */ - continue; - } - - for (; id; id = id->next) { - if (id->lib == lib) { - WMLinkAppendDataItem *item; - - /* We remove it from current Main, and add it to items to link... */ - /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitely linked here... */ - BLI_remlink(lbarray[lba_idx], id); - item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, NULL, id); - BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries); - -#ifdef PRINT_DEBUG - printf("\tdatablock to seek for: %s\n", id->name); -#endif - } - } - } - - lib_relocate_do(bmain, lapp_data, op->reports, NULL, do_reload); + lib_relocate_do(bmain, scene, lib, lapp_data, op->reports, NULL, do_reload); wm_link_append_data_free(lapp_data); - BKE_main_lib_objects_recalc_all(bmain); - IMB_colormanagement_check_file_config(bmain); - - /* important we unset, otherwise these object wont - * link into other scenes from this blend file */ - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - - /* recreate dependency graph to include new objects */ - DAG_scene_relations_rebuild(bmain, scene); - - /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */ - GPU_materials_free(); - /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ BLI_strncpy(G.lib, root, FILE_MAX); @@ -1066,9 +1094,10 @@ typedef struct AssetUpdateCheckEngine { AssetEngine *ae; /* Note: We cannot store IDs themselves in non-locking async task... so we'll have to check again for - * UUID/IDs mapping on each update call... Not ideal, but don't think it will be that big of an override + * UUID/IDs mapping on each update call... Not ideal, but don't think it will be that big of a bottleneck * in practice. */ AssetUUIDList uuids; + int allocated_uuids; int ae_job_id; short status; } AssetUpdateCheckEngine; @@ -1170,13 +1199,16 @@ static void asset_update_engines_uuids_fetch( id->uuid->tag = (id->tag & LIB_TAG_MISSING) ? UUID_TAG_ASSET_MISSING : 0; } - /* XXX horrible, need to use some mempool, stack or something :) */ auce->uuids.nbr_uuids++; - if (auce->uuids.uuids) { - auce->uuids.uuids = MEM_reallocN_id(auce->uuids.uuids, sizeof(*auce->uuids.uuids) * (size_t)auce->uuids.nbr_uuids, __func__); - } - else { - auce->uuids.uuids = MEM_mallocN(sizeof(*auce->uuids.uuids) * (size_t)auce->uuids.nbr_uuids, __func__); + BKE_asset_uuid_print(id->uuid); + if (auce->uuids.nbr_uuids > auce->allocated_uuids) { + auce->allocated_uuids += 16; + BLI_assert(auce->uuids.nbr_uuids < auce->allocated_uuids); + + const size_t allocsize = sizeof(*auce->uuids.uuids) * (size_t)auce->allocated_uuids; + auce->uuids.uuids = auce->uuids.uuids ? + MEM_reallocN_id(auce->uuids.uuids, allocsize, __func__) : + MEM_mallocN(allocsize, __func__); } auce->uuids.uuids[auce->uuids.nbr_uuids - 1] = *id->uuid; } @@ -1381,6 +1413,7 @@ static int wm_assets_reload_exec(bContext *C, wmOperator *op) * - cleanup indirect dependencies IDs with zero users. */ Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); ListBase engines = {NULL}; @@ -1461,7 +1494,7 @@ static int wm_assets_reload_exec(bContext *C, wmOperator *op) } } - lib_relocate_do(bmain, lapp_data, op->reports, auce->ae->type, do_reload); + lib_relocate_do(bmain, scene, NULL, lapp_data, op->reports, auce->ae->type, do_reload); wm_link_append_data_free(lapp_data); BLI_ghash_free(libraries, MEM_freeN, NULL); @@ -1476,19 +1509,6 @@ static int wm_assets_reload_exec(bContext *C, wmOperator *op) } BLI_freelistN(&engines); - BKE_main_lib_objects_recalc_all(bmain); - IMB_colormanagement_check_file_config(bmain); - - /* important we unset, otherwise these object wont - * link into other scenes from this blend file */ - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - - /* recreate dependency graph to include new objects */ - DAG_scene_relations_rebuild(bmain, CTX_data_scene(C)); - - /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */ - GPU_materials_free(); - WM_event_add_notifier(C, NC_WINDOW, NULL); G.f &= ~G_ASSETS_NEED_RELOAD; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 1de92c09af1..c96d0199d24 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -57,7 +57,7 @@ #include "BLO_writefile.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_blender.h" #include "BKE_blender_undo.h" #include "BKE_context.h" diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 206007b8d8b..ca841954b16 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -63,6 +63,8 @@ if(WIN32 AND NOT UNIX) COMPONENT Blenderplayer DESTINATION ".") +add_cc_flags_custom_test(blenderplayer) + elseif(APPLE) add_executable(blenderplayer ${EXETYPE} bad_level_call_stubs/stubs.c) # setup Info.plist diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 4d3ad159231..644c84fa3fa 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -247,7 +247,7 @@ bool RE_HasFakeLayer(RenderResult *res) RET_ZERO /* zbuf.c stub */ void antialias_tagbuf(int xsize, int ysize, char *rectmove) RET_NONE -void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect) RET_NONE +void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, const float *imgrect, float *vecbufrect, const float *zbufrect) RET_NONE /* imagetexture.c stub */ void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result) RET_NONE @@ -309,6 +309,8 @@ void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot) void WM_autosave_init(wmWindowManager *wm) RET_NONE void WM_jobs_kill_all_except(struct wmWindowManager *wm, void *owner) RET_NONE +void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports) RET_NONE + char *WM_clipboard_text_get(bool selection, int *r_len) RET_NULL char *WM_clipboard_text_get_firstline(bool selection, int *r_len) RET_NULL void WM_clipboard_text_set(const char *buf, bool selection) RET_NONE diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 4e8dd6f9fd3..7acea43d1f5 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -222,6 +222,8 @@ if(WITH_BUILDINFO) add_dependencies(buildinfoobj buildinfo) endif() +add_cc_flags_custom_test(blender) + # message(STATUS "Configuring blender") if(WITH_PYTHON_MODULE) add_definitions(-DWITH_PYTHON_MODULE) @@ -244,7 +246,7 @@ if(WITH_PYTHON_MODULE) set_target_properties( blender PROPERTIES - MACOSX_BUNDLE + MACOSX_BUNDLE TRUE LINK_FLAGS_RELEASE "${PLATFORM_LINKFLAGS}" LINK_FLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG}" ) diff --git a/source/creator/creator.c b/source/creator/creator.c index 5596402b41b..741fcec6cfc 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -54,7 +54,7 @@ /* mostly init functions */ #include "BKE_appdir.h" -#include "BKE_asset.h" +#include "BKE_asset_engine.h" #include "BKE_blender.h" #include "BKE_brush.h" #include "BKE_context.h" @@ -172,9 +172,9 @@ static void callback_main_atexit(void *user_data) #ifdef WIN32 if (app_init_data->argv) { while (app_init_data->argv_num) { - free(app_init_data->argv[--app_init_data->argv_num]); + free((void *)app_init_data->argv[--app_init_data->argv_num]); } - free(app_init_data->argv); + free((void *)app_init_data->argv); app_init_data->argv = NULL; } #endif diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index c89cdea4e29..c3c76a0d1d3 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -739,8 +739,6 @@ static const char arg_handle_debug_mode_generic_set_doc_handlers[] = "\n\tEnable debug messages for event handling"; static const char arg_handle_debug_mode_generic_set_doc_wm[] = "\n\tEnable debug messages for the window manager, also prints every operator call"; -static const char arg_handle_debug_mode_generic_set_doc_all[] = -"\n\tEnable all debug messages (excludes libmv)"; static const char arg_handle_debug_mode_generic_set_doc_jobs[] = "\n\tEnable time profiling for background jobs."; static const char arg_handle_debug_mode_generic_set_doc_gpu[] = @@ -758,6 +756,20 @@ static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUS return 0; } +static const char arg_handle_debug_mode_all_doc[] = +"\n\tEnable all debug messages"; +static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) +{ + G.debug |= G_DEBUG_ALL; +#ifdef WITH_LIBMV + libmv_startDebugLogging(); +#endif +#ifdef WITH_CYCLES_LOGGING + CCL_start_debug_logging(); +#endif + return 0; +} + #ifdef WITH_LIBMV static const char arg_handle_debug_mode_libmv_doc[] = "\n\tEnable debug messages from libmv library" @@ -1791,8 +1803,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle) CB_EX(arg_handle_debug_mode_generic_set, handlers), (void *)G_DEBUG_HANDLERS); BLI_argsAdd(ba, 1, NULL, "--debug-wm", CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM); - BLI_argsAdd(ba, 1, NULL, "--debug-all", - CB_EX(arg_handle_debug_mode_generic_set, all), (void *)G_DEBUG_ALL); + BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL); BLI_argsAdd(ba, 1, NULL, "--debug-fpe", CB(arg_handle_debug_fpe_set), NULL); diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp index 25936b34fde..fd2e723741c 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.cpp +++ b/source/gameengine/GameLogic/SCA_PythonController.cpp @@ -163,7 +163,9 @@ void SCA_PythonController::SetNamespace(PyObject* pythondictionary) /* Without __file__ set the sys.argv[0] is used for the filename * which ends up with lines from the blender binary being printed in the console */ - PyDict_SetItemString(m_pythondictionary, "__file__", PyUnicode_From_STR_String(m_scriptName)); + PyObject *value = PyUnicode_From_STR_String(m_scriptName); + PyDict_SetItemString(m_pythondictionary, "__file__", value); + Py_DECREF(value); } #endif diff --git a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp index 19aae46f2a3..9a96a7b0334 100644 --- a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp +++ b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp @@ -113,11 +113,15 @@ PyObject *SCA_PythonKeyboard::pyattr_get_events(void *self_v, const KX_PYATTRIBU { SCA_PythonKeyboard* self = static_cast<SCA_PythonKeyboard*>(self_v); - for (int i=SCA_IInputDevice::KX_BEGINKEY; i<=SCA_IInputDevice::KX_ENDKEY; i++) - { + for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) { const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - - PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status)); + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(inevent.m_status); + + PyDict_SetItem(self->m_event_dict, key, value); + + Py_DECREF(key); + Py_DECREF(value); } Py_INCREF(self->m_event_dict); return self->m_event_dict; @@ -129,12 +133,18 @@ PyObject *SCA_PythonKeyboard::pyattr_get_active_events(void *self_v, const KX_PY PyDict_Clear(self->m_event_dict); - for (int i=SCA_IInputDevice::KX_BEGINKEY; i<=SCA_IInputDevice::KX_ENDKEY; i++) - { + for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) { const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) - PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status)); + if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) { + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(inevent.m_status); + + PyDict_SetItem(self->m_event_dict, key, value); + + Py_DECREF(key); + Py_DECREF(value); + } } Py_INCREF(self->m_event_dict); return self->m_event_dict; diff --git a/source/gameengine/GameLogic/SCA_PythonMouse.cpp b/source/gameengine/GameLogic/SCA_PythonMouse.cpp index 1617f714113..184b306a665 100644 --- a/source/gameengine/GameLogic/SCA_PythonMouse.cpp +++ b/source/gameengine/GameLogic/SCA_PythonMouse.cpp @@ -96,11 +96,15 @@ PyObject *SCA_PythonMouse::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_ { SCA_PythonMouse* self = static_cast<SCA_PythonMouse*>(self_v); - for (int i=SCA_IInputDevice::KX_BEGINMOUSE; i<=SCA_IInputDevice::KX_ENDMOUSE; i++) - { - const SCA_InputEvent & inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - - PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status)); + for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) { + const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(inevent.m_status); + + PyDict_SetItem(self->m_event_dict, key, value); + + Py_DECREF(key); + Py_DECREF(value); } Py_INCREF(self->m_event_dict); return self->m_event_dict; @@ -112,12 +116,19 @@ PyObject *SCA_PythonMouse::pyattr_get_active_events(void *self_v, const KX_PYATT PyDict_Clear(self->m_event_dict); - for (int i=SCA_IInputDevice::KX_BEGINMOUSE; i<=SCA_IInputDevice::KX_ENDMOUSE; i++) - { - const SCA_InputEvent & inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); + for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) { + const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) - PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status)); + if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) { + + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(inevent.m_status); + + PyDict_SetItem(self->m_event_dict, key, value); + + Py_DECREF(key); + Py_DECREF(value); + } } Py_INCREF(self->m_event_dict); return self->m_event_dict; diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 9c3f94f1918..d033afacc08 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -709,7 +709,7 @@ int main( { i++; if ( (i + 1) <= validArguments ) - parentWindow = atoi(argv[i++]); + parentWindow = (GHOST_TEmbedderWindowID)atoll(argv[i++]); else { error = true; printf("error: too few options for parent window argument.\n"); diff --git a/source/tools b/source/tools new file mode 160000 +Subproject 373945d0978b6601c55c9d5879e0f488b18515c |