diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2016-07-25 16:07:17 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2016-07-25 16:07:17 +0300 |
commit | b1532493c27b08444745cef348641f3a0e899ba8 (patch) | |
tree | 84db57081ef3e1d2a1bfbf3c4bbfe352854164f2 | |
parent | 9186b9ae4806f4bbc1a14417c408e844f8e8cc1a (diff) | |
parent | e7721f5ec8b859d14c982a8a34bc269ab7eed82b (diff) |
Merge branch 'master' into blender2.8
Conflicts:
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/particle.c
198 files changed, 4651 insertions, 1768 deletions
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/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 5ffd6c4e7f4..f57a6952164 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -1547,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 04feb979165..7dc0f46fa86 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -505,7 +505,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): ) cls.debug_use_hair_bvh = BoolProperty( name="Use Hair BVH", - description="Use special type BVH optimized for hair. Uses more ram but renders faster", + description="Use special type BVH optimized for hair (uses more ram but renders faster)", default=True, ) cls.tile_order = EnumProperty( diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 6faec5e013b..c2538f2edd9 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -459,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 890ae76f6cc..471afa70611 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); } @@ -682,12 +681,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.h b/intern/cycles/blender/blender_sync.h index e7361589436..8caa8070939 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 89a53a1deca..798fe36d4fe 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/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 720ee6a1f5c..caa6c9d9a5b 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -256,7 +256,7 @@ ccl_device_inline void triangle_intersect_subsurface( const float inv_det = 1.0f / det; const float t = T * inv_det; - for(int i = min(max_hits, ss_isect->num_hits); i >= 0; --i) { + for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { if(ss_isect->hits[i].t == t) { return; } 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_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/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/nodes.cpp b/intern/cycles/render/nodes.cpp index a8fd9da9ced..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,16 +1577,11 @@ RGBToBWNode::RGBToBWNode() { } -bool RGBToBWNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - 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) @@ -1663,40 +1659,35 @@ ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool auto special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; } -bool ConvertNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - 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) @@ -2366,15 +2357,15 @@ void EmissionNode::compile(OSLCompiler& compiler) compiler.add(this, "node_emission"); } -bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - ShaderInput * /*optimized*/) +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 */ @@ -2418,15 +2409,15 @@ void BackgroundNode::compile(OSLCompiler& compiler) compiler.add(this, "node_background"); } -bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - ShaderInput * /*optimized*/) +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 */ @@ -3388,12 +3379,9 @@ ValueNode::ValueNode() { } -bool ValueNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - ShaderInput *optimized) +void ValueNode::constant_fold(const ConstantFolder& folder) { - optimized->set(value); - return true; + folder.make_constant(value); } void ValueNode::compile(SVMCompiler& compiler) @@ -3426,12 +3414,9 @@ ColorNode::ColorNode() { } -bool ColorNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - ShaderInput *optimized) +void ColorNode::constant_fold(const ConstantFolder& folder) { - optimized->set(value); - return true; + folder.make_constant(value); } void ColorNode::compile(SVMCompiler& compiler) @@ -3480,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) @@ -3511,37 +3510,28 @@ void MixClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix_closure"); } -bool MixClosureNode::constant_fold(ShaderGraph *graph, - ShaderOutput * /*socket*/, - ShaderInput * /*optimized*/) +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 */ @@ -3603,28 +3593,21 @@ InvertNode::InvertNode() { } -bool InvertNode::constant_fold(ShaderGraph *graph, - ShaderOutput * /*socket*/, - 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) @@ -3713,63 +3696,47 @@ void MixNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix"); } -bool MixNode::constant_fold(ShaderGraph *graph, - ShaderOutput * /*socket*/, - 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 */ @@ -3792,16 +3759,11 @@ CombineRGBNode::CombineRGBNode() { } -bool CombineRGBNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - 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) @@ -3849,16 +3811,11 @@ CombineXYZNode::CombineXYZNode() { } -bool CombineXYZNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - 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) @@ -3906,16 +3863,11 @@ CombineHSVNode::CombineHSVNode() { } -bool CombineHSVNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - 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) @@ -3956,16 +3908,11 @@ GammaNode::GammaNode() { } -bool GammaNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - 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) @@ -4005,16 +3952,11 @@ BrightContrastNode::BrightContrastNode() { } -bool BrightContrastNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - 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) @@ -4057,20 +3999,16 @@ SeparateRGBNode::SeparateRGBNode() { } -bool SeparateRGBNode::constant_fold(ShaderGraph * /*graph*/, - 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) @@ -4118,20 +4056,16 @@ SeparateXYZNode::SeparateXYZNode() { } -bool SeparateXYZNode::constant_fold(ShaderGraph * /*graph*/, - 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) @@ -4179,22 +4113,18 @@ SeparateHSVNode::SeparateHSVNode() { } -bool SeparateHSVNode::constant_fold(ShaderGraph * /*graph*/, - 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) @@ -4580,16 +4510,11 @@ BlackbodyNode::BlackbodyNode() { } -bool BlackbodyNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - 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) @@ -4691,17 +4616,11 @@ MathNode::MathNode() { } -bool MathNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - 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) @@ -4755,31 +4674,25 @@ VectorMathNode::VectorMathNode() { } -bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, - 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) @@ -4913,9 +4826,7 @@ void BumpNode::compile(OSLCompiler& compiler) compiler.add(this, "node_bump"); } -bool BumpNode::constant_fold(ShaderGraph *graph, - ShaderOutput * /*socket*/, - ShaderInput * /*optimized*/) +void BumpNode::constant_fold(const ConstantFolder& folder) { ShaderInput *height_in = input("Height"); ShaderInput *normal_in = input("Normal"); @@ -4923,18 +4834,15 @@ bool BumpNode::constant_fold(ShaderGraph *graph, 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; } @@ -5154,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 */ @@ -5169,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/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 5abcbfcdaad..05e807ff60c 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -213,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/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_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/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/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/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..cc9e05a11c8 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 }; 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 0ad72c88a12..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); @@ -426,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); @@ -476,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 */ @@ -517,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(); } @@ -552,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(); } @@ -562,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(); } @@ -572,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(); } @@ -583,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(); } @@ -592,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(); @@ -606,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..752dce7744c 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,7 +94,7 @@ 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; @@ -87,102 +106,98 @@ 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 +211,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 +313,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 +367,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 +422,27 @@ 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 FLAT_SHADING\n"); + g_flat_fill_texture2d_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_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); @@ -436,8 +484,8 @@ void openSubdiv_osdGLDisplayDeinit(void) 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 +542,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,28 +557,42 @@ 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; } @@ -562,7 +624,7 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh, program = g_wireframe_program; } - bindProgram(mesh, program); + bindProgram(gl_mesh, program); return program; } @@ -623,7 +685,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 +731,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 +746,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/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 1e476b63b56..97ef37fa5e0 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -300,19 +300,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_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index f6cbd2c444a..949897159fd 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -1415,7 +1415,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 38f7675b070..9bae931880b 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2361,6 +2361,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 1879a35aa35..ba44983b649 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() 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 ac9b0b6fb10..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, const bool force_local); +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 bfd4a7e3dd8..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, const bool force_local); +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_brush.h b/source/blender/blenkernel/BKE_brush.h index 4be4d95490b..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, const bool force_local); +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 3ae0e0e1111..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, const bool force_local); +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 c2a0404e96e..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, const bool force_local); +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 7839b9e2154..efef8d4be78 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -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 db73b42d894..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, const bool force_local); +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_lamp.h b/source/blender/blenkernel/BKE_lamp.h index dc977eabbb1..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, const bool force_local); +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 4f72bbecff4..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, const bool force_local); +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 b6a91caee4e..3af0177c25b 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -80,6 +80,7 @@ void id_us_min(struct ID *id); void id_fake_user_set(struct ID *id); void id_fake_user_clear(struct ID *id); +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); @@ -88,7 +89,7 @@ void BKE_id_expand_local(struct ID *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 bbe104cd6ee..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, const bool force_local); +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 191e8721099..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, const bool force_local); +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 ef8d1c98318..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, const bool force_local); +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 647b96fb9ae..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, const bool force_local); +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 8811f358cd3..efffc90e96c 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -104,7 +104,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, const bool force_local); +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); 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 fb730d95b92..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, const bool force_local); +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 b853ebd4793..df1fd945eb4 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -71,7 +71,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, const bool force_local); +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 8b8dac4ab22..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, const bool force_local); +void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local); #endif 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/action.c b/source/blender/blenkernel/intern/action.c index fa49797126d..8f82610a8bb 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, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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); } /* .................................. */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 53e28177bdf..790272c4411 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, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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) @@ -1931,6 +1906,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 +1937,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/brush.c b/source/blender/blenkernel/intern/brush.c index 3d9cabdc15d..9027287a457 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -219,7 +219,7 @@ void BKE_brush_free(Brush *brush) BKE_previewimg_free(&(brush->preview)); } -void BKE_brush_make_local(Main *bmain, Brush *brush, const bool force_local) +void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local) { bool is_local = false, is_lib = false; @@ -239,7 +239,7 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool force_local) BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib); - if (force_local || 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 +252,9 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool force_local) 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 cd085816b4d..4229b2a727e 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) @@ -107,34 +107,9 @@ Camera *BKE_camera_copy(Main *bmain, Camera *cam) return camn; } -void BKE_camera_make_local(Main *bmain, Camera *cam, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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/curve.c b/source/blender/blenkernel/intern/curve.c index 693e7eb0c80..07f4e4f1610 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -215,34 +215,9 @@ Curve *BKE_curve_copy(Main *bmain, Curve *cu) return cun; } -void BKE_curve_make_local(Main *bmain, Curve *cu, const bool force_local) +void BKE_curve_make_local(Main *bmain, Curve *cu, const bool lib_local) { - bool is_local = false, is_lib = false; - - /* - only lib users: do nothing (unless force_local is set) - * - 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 (force_local || is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &cu->id); - 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 82ea710b5b6..419a1cd854b 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -4161,7 +4161,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; @@ -4312,7 +4312,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; } @@ -4329,7 +4329,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); @@ -4687,7 +4687,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; @@ -4697,13 +4698,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 5a51d4797bb..aae1ba241e7 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -104,6 +104,11 @@ Group *BKE_group_copy(Main *bmain, Group *group) 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 63055dc0646..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)) { diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ae3163d388e..017eb41cd49 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -456,10 +456,11 @@ 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); @@ -469,34 +470,9 @@ Image *BKE_image_copy(Main *bmain, Image *ima) return nima; } -void BKE_image_make_local(Main *bmain, Image *ima, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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,39 +1059,48 @@ 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) { @@ -1132,46 +1117,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/lamp.c b/source/blender/blenkernel/intern/lamp.c index c224b5ca0a7..35fcf211b05 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -135,8 +135,8 @@ Lamp *BKE_lamp_copy(Main *bmain, Lamp *la) if (la->nodetree) lan->nodetree = ntreeCopyTree(bmain, la->nodetree); - - lan->preview = BKE_previewimg_copy(la->preview); + + BKE_previewimg_id_copy(&lan->id, &la->id); if (ID_IS_LINKED_DATABLOCK(la)) { BKE_id_expand_local(&lan->id); @@ -172,34 +172,9 @@ Lamp *localize_lamp(Lamp *la) return lan; } -void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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 c2675fabe3b..82b179d4f1c 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -330,34 +330,9 @@ void BKE_lattice_free(Lattice *lt) } -void BKE_lattice_make_local(Main *bmain, Lattice *lt, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, <->id); - 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 9b9b80a2ecc..6718f1a13ce 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -96,6 +96,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" @@ -105,6 +106,7 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_packedFile.h" +#include "BKE_sound.h" #include "BKE_speaker.h" #include "BKE_scene.h" #include "BKE_text.h" @@ -268,86 +270,144 @@ 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, const bool test, const bool force_local) +/** + * 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_DATABLOCK(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, force_local); + 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, force_local); + 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, force_local); + 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, force_local); + 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, force_local); + 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, force_local); + 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, force_local); + 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, force_local); + 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, force_local); + 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, force_local); + 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, force_local); + if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local); return true; case ID_IP: return false; /* deprecated */ case ID_KE: return false; /* can't be linked */ case ID_WO: - if (!test) BKE_world_make_local(bmain, (World *)id, force_local); + 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, force_local); + 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, force_local); + if (!test) BKE_action_make_local(bmain, (bAction *)id, lib_local); return true; case ID_NT: - if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true, force_local); + if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true, lib_local); return true; case ID_BR: - if (!test) BKE_brush_make_local(bmain, (Brush *)id, force_local); + if (!test) BKE_brush_make_local(bmain, (Brush *)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; @@ -1451,7 +1511,7 @@ 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; @@ -1508,53 +1568,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. @@ -1562,19 +1575,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 @@ -1601,15 +1625,39 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged } } } + } + } - id = idn; + /* 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->newid) { + BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE); + } } } - a = set_listbasepointers(bmain, lbarray); - while (a--) { - for (id = lbarray[a]->first; id; id = id->next) - lib_indirect_test_id(id, lib); + /* 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; + } + } + } + } } } diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index b623cecb0ff..2ccdcbba86f 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -427,7 +427,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_DATABLOCK(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; @@ -787,9 +796,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 62a6541529a..92652fcc1eb 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -295,6 +295,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; @@ -640,6 +643,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). */ diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index c4a0d0074fb..1aff5d502f8 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -226,6 +226,11 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l 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..014461e0d22 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -861,6 +861,11 @@ Mask *BKE_mask_copy(Main *bmain, Mask *mask) 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 2ae369fdd1b..62aba1af694 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -243,7 +243,7 @@ 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); @@ -285,34 +285,9 @@ Material *localize_material(Material *ma) return man; } -void BKE_material_make_local(Main *bmain, Material *ma, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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 +544,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 +849,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 +866,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 +886,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 +1168,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 aeb38b3bd1d..7e363e5600f 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -127,34 +127,9 @@ MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb) return mbn; } -void BKE_mball_make_local(Main *bmain, MetaBall *mb, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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 b2f57328df3..2b35cdc9d64 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" @@ -555,34 +556,9 @@ BMesh *BKE_mesh_to_bmesh( return bm; } -void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || is_local) { - if (!is_lib) { - id_clear_lib_data(bmain, &me->id); - 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, @@ -2394,23 +2370,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) { @@ -2438,9 +2416,6 @@ Mesh *BKE_mesh_new_from_object( BKE_mesh_tessface_ensure(tmpmesh); } - /* make sure materials get updated in object */ - test_object_materials(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/node.c b/source/blender/blenkernel/intern/node.c index eec09973a82..8bae0484920 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1950,34 +1950,9 @@ bNodeTree *ntreeFromID(ID *id) } } -void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 5d654515fc8..980877fd541 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1023,13 +1023,14 @@ 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, const bool force_local) +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 (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)) { @@ -1038,7 +1039,7 @@ void BKE_object_make_local(Main *bmain, Object *ob, const bool force_local) BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib); - if (force_local || is_local) { + if (lib_local || is_local) { if (!is_lib) { id_clear_lib_data(bmain, &ob->id); BKE_id_expand_local(&ob->id); @@ -1049,7 +1050,9 @@ void BKE_object_make_local(Main *bmain, Object *ob, const bool force_local) 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); + } } } } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index d284548d6bc..a75522d5573 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -343,7 +343,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; } @@ -354,6 +354,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) { diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 2f497d807e4..6067a8b2d9b 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3558,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 c027f3b38ca..80ee6d50d7e 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -85,34 +85,9 @@ Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk) return spkn; } -void BKE_speaker_make_local(Main *bmain, Speaker *spk, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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 f73dbd8078f..10a0a39fcdd 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,78 @@ 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; + 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 + 1; + } + else { + mat_nr = 0; + } + + 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); + + if (!flush && compareDrawOptions) { + flush |= compareDrawOptions(userData, i, min_ii(i + 1, num_base_faces - 1)) == 0; + } + + current_patch += num_patches; + + if (flush) { + if (draw_option != DM_DRAW_OPTION_SKIP) { + num_draw_patches += num_patches; + } + if (num_draw_patches != 0) { + 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); @@ -3581,7 +3646,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 +3845,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 +5035,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 +5050,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 +5081,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 +5121,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 +5150,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..82c3132d73e 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -499,6 +499,11 @@ Text *BKE_text_copy(Main *bmain, Text *ta) 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 155c7f04e53..d2e0d9d9c83 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -862,7 +862,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) { @@ -870,8 +869,8 @@ Tex *BKE_texture_copy(Main *bmain, Tex *tex) } texn->nodetree = ntreeCopyTree(bmain, tex->nodetree); } - - texn->preview = BKE_previewimg_copy(tex->preview); + + BKE_previewimg_id_copy(&texn->id, &tex->id); if (ID_IS_LINKED_DATABLOCK(tex)) { BKE_id_expand_local(&texn->id); @@ -917,34 +916,9 @@ Tex *BKE_texture_localize(Tex *tex) /* ------------------------------------------------------------------------- */ -void BKE_texture_make_local(Main *bmain, Tex *tex, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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 277aeaa7e42..78342e9919a 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -138,7 +138,7 @@ 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); @@ -176,32 +176,7 @@ World *localize_world(World *wrld) return wrldn; } -void BKE_world_make_local(Main *bmain, World *wrld, const bool force_local) +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 (unless force_local is set) - * - 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 (force_local || 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/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c index d48e9fbddde..0a8dafc2dc1 100644 --- a/source/blender/blenlib/intern/BLI_heap.c +++ b/source/blender/blenlib/intern/BLI_heap.c @@ -167,8 +167,7 @@ static struct HeapNode *heap_node_alloc(Heap *heap) else { struct HeapNode_Chunk *chunk = heap->nodes.chunk; if (UNLIKELY(chunk->size == chunk->bufsize)) { - struct HeapNode_Chunk *chunk_next = heap_node_alloc_chunk(HEAP_CHUNK_DEFAULT_NUM, chunk); - chunk = chunk_next; + chunk = heap->nodes.chunk = heap_node_alloc_chunk(HEAP_CHUNK_DEFAULT_NUM, chunk); } node = &chunk->buf[chunk->size++]; } 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 a7c625b0842..6c28b8e4f89 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1278,7 +1278,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); 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 81b61f399c9..f67ce629a00 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1112,8 +1112,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); } } @@ -1143,5 +1143,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + 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 30734b7f828..5798b62b689 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -250,6 +250,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/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 241086fbf02..05322a570a7 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -124,7 +124,7 @@ 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_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/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/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_icons.c b/source/blender/editors/interface/interface_icons.c index 3660160a98c..73a7be16176 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1092,6 +1092,7 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi ui_id_preview_image_render_size(C, NULL, id, prv, size, true); } } + break; } } } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index d4205c50ddc..2caf52cf8dc 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -3331,6 +3331,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/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_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 2cdb00286aa..e31e4096ded 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -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/render/render_shading.c b/source/blender/editors/render/render_shading.c index bd5fd6b060a..39256bc8ca3 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -101,7 +101,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); @@ -144,7 +144,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); @@ -528,7 +528,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 && @@ -591,7 +591,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_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index f21f62cc141..ef99fedbec0 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -256,9 +256,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); } 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_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_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 1538842b139..1158e692182 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1284,8 +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 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); RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr); RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop); @@ -2395,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_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 111e60e5159..e38886abeac 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -1345,7 +1345,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_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/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index bb645562515..0b17f7075bc 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -5103,13 +5103,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 724eba160a0..1b0f5862a44 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -1244,7 +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 + 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 { @@ -1361,7 +1362,7 @@ static bool snapDerivedMesh( 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) + true, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1) { copy_v3_v3(r_loc, nearest.co); mul_m4_v3(obmat, r_loc); @@ -1567,7 +1568,8 @@ static bool snapEditMesh( * (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]); + madd_v3_v3v3fl( + ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale); local_depth -= len_diff; } } 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_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index a89efce3077..a69b64a25d7 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -845,11 +845,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); } @@ -860,22 +863,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_material.c b/source/blender/gpu/intern/gpu_material.c index 24228c8d087..00af1991eaf 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -2861,8 +2861,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_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_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 0e34792e624..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_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 87b6813712f..804c58e445c 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1240,7 +1240,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; @@ -1255,6 +1257,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_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/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index 4db98bda7dd..6a41591e051 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -632,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; @@ -909,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; @@ -1062,7 +1057,7 @@ static void reconstruct_struct( const char *compflags, int oldSDNAnr, - char *data, + const char *data, int curSDNAnr, char *cur) { @@ -1073,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; @@ -1111,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); @@ -1188,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); @@ -1250,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 */ @@ -1297,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 f76e50b4a00..cd709a42b38 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/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index af8fe78c0af..df114b0cc03 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -1012,6 +1012,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"); @@ -1030,6 +1031,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_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_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 e8986cd9813..30c966fdc3a 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -1010,10 +1010,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 95cb21e5858..06dec0998a5 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -158,18 +158,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) @@ -205,9 +193,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); @@ -396,11 +383,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_scene.c b/source/blender/makesrna/intern/rna_scene.c index 532f788619e..641e8ebc155 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -177,6 +177,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 */ @@ -2619,6 +2624,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 04557e15fee..ca5c0f2c6f0 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3606,7 +3606,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_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/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 1c6471c2cca..ab523e03f4d 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/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/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 468d66f6065..5f87f9b03d6 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3048,7 +3048,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) { diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 49d6e5a0d7f..8a2911464b1 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -930,7 +930,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? */ @@ -945,7 +945,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? */ @@ -966,15 +966,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/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index de08ea8d11c..2d6d7244a5f 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -1005,7 +1005,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); @@ -1135,7 +1135,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/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 7a247d9791b..26a1c7038d8 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_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 12ad8f91064..e2ccb6fbbd7 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -551,8 +551,9 @@ 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. */ -static void lib_relocate_do(Main *bmain, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload) +static void lib_relocate_do( + Main *bmain, Scene *scene, + Library *library, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload) { ListBase *lbarray[MAX_LIBARRAY]; int lba_idx; @@ -560,6 +561,34 @@ static void lib_relocate_do(Main *bmain, WMLinkAppendData *lapp_data, ReportList LinkNode *itemlink; int item_idx; + /* Remove all IDs to be reloaded from Main. */ + 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, 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! */ @@ -698,6 +727,43 @@ static void lib_relocate_do(Main *bmain, WMLinkAppendData *lapp_data, ReportList } } } + + 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, 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) @@ -714,9 +780,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; @@ -803,50 +866,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, 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, do_reload); + lib_relocate_do(bmain, scene, lib, lapp_data, op->reports, 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); diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 37e9c7eae7a..8e3aace7fff 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -245,7 +245,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 @@ -307,6 +307,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 d8435284096..7acea43d1f5 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -246,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 85c4e5b0681..ccb3e02e0a9 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -170,9 +170,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/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"); |