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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2016-07-25 10:35:03 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2016-07-25 10:35:03 +0300
commit49c63d46db8c055152d9e431e89405f9b51a4bbe (patch)
tree77d59518d74d0f88b2b596951d4e7b9afef9fcc9
parentbe12e7a42e43d532b88387f1091e4b23fa551306 (diff)
parentf4cb6d45d50d5fa45bcb78236725924219c9b038 (diff)
Merge branch 'master' into object_nodes
-rw-r--r--extern/curve_fit_nd/CMakeLists.txt6
-rw-r--r--extern/curve_fit_nd/curve_fit_nd.h35
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic.c33
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic_refit.c1424
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_inline.h2
-rw-r--r--extern/curve_fit_nd/intern/generic_alloc_impl.h220
-rw-r--r--extern/curve_fit_nd/intern/generic_heap.c278
-rw-r--r--extern/curve_fit_nd/intern/generic_heap.h54
-rw-r--r--intern/atomic/intern/atomic_ops_utils.h4
-rw-r--r--intern/audaspace/Python/AUD_PyAPI.cpp2
-rw-r--r--intern/cycles/blender/addon/properties.py2
-rw-r--r--intern/cycles/blender/addon/ui.py4
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h2
-rw-r--r--intern/cycles/render/graph.cpp20
-rw-r--r--intern/cycles/render/nodes.cpp18
-rw-r--r--intern/cycles/render/nodes.h2
-rw-r--r--intern/libmv/intern/autotrack.cc8
-rw-r--r--intern/libmv/libmv/numeric/numeric.cc2
-rw-r--r--intern/opensubdiv/CMakeLists.txt2
-rw-r--r--intern/opensubdiv/gpu_shader_opensubd_display.glsl2
-rw-r--r--intern/opensubdiv/opensubdiv_capi.cc89
-rw-r--r--intern/opensubdiv/opensubdiv_capi.h11
-rw-r--r--intern/opensubdiv/opensubdiv_converter.cc107
-rw-r--r--intern/opensubdiv/opensubdiv_converter_capi.h16
-rw-r--r--intern/opensubdiv/opensubdiv_gpu_capi.cc332
-rw-r--r--intern/opensubdiv/opensubdiv_topology_refiner.h41
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py6
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py2
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py5
-rw-r--r--release/scripts/startup/bl_ui/space_info.py33
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py1
-rw-r--r--source/blender/blenfont/intern/blf_font.c8
-rw-r--r--source/blender/blenkernel/BKE_action.h2
-rw-r--r--source/blender/blenkernel/BKE_armature.h3
-rw-r--r--source/blender/blenkernel/BKE_brush.h2
-rw-r--r--source/blender/blenkernel/BKE_camera.h2
-rw-r--r--source/blender/blenkernel/BKE_curve.h2
-rw-r--r--source/blender/blenkernel/BKE_font.h2
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h2
-rw-r--r--source/blender/blenkernel/BKE_group.h1
-rw-r--r--source/blender/blenkernel/BKE_icons.h2
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_lamp.h2
-rw-r--r--source/blender/blenkernel/BKE_lattice.h2
-rw-r--r--source/blender/blenkernel/BKE_library.h3
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h2
-rw-r--r--source/blender/blenkernel/BKE_mask.h2
-rw-r--r--source/blender/blenkernel/BKE_material.h10
-rw-r--r--source/blender/blenkernel/BKE_mball.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h15
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/BKE_object.h2
-rw-r--r--source/blender/blenkernel/BKE_particle.h2
-rw-r--r--source/blender/blenkernel/BKE_scene.h2
-rw-r--r--source/blender/blenkernel/BKE_sound.h2
-rw-r--r--source/blender/blenkernel/BKE_speaker.h2
-rw-r--r--source/blender/blenkernel/BKE_text.h1
-rw-r--r--source/blender/blenkernel/BKE_texture.h2
-rw-r--r--source/blender/blenkernel/BKE_world.h2
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h5
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c15
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c244
-rw-r--r--source/blender/blenkernel/intern/action.c29
-rw-r--r--source/blender/blenkernel/intern/armature.c45
-rw-r--r--source/blender/blenkernel/intern/brush.c8
-rw-r--r--source/blender/blenkernel/intern/camera.c33
-rw-r--r--source/blender/blenkernel/intern/curve.c29
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c16
-rw-r--r--source/blender/blenkernel/intern/font.c5
-rw-r--r--source/blender/blenkernel/intern/gpencil.c5
-rw-r--r--source/blender/blenkernel/intern/group.c5
-rw-r--r--source/blender/blenkernel/intern/icons.c18
-rw-r--r--source/blender/blenkernel/intern/image.c34
-rw-r--r--source/blender/blenkernel/intern/lamp.c33
-rw-r--r--source/blender/blenkernel/intern/lattice.c29
-rw-r--r--source/blender/blenkernel/intern/library.c222
-rw-r--r--source/blender/blenkernel/intern/library_query.c9
-rw-r--r--source/blender/blenkernel/intern/library_remap.c3
-rw-r--r--source/blender/blenkernel/intern/linestyle.c5
-rw-r--r--source/blender/blenkernel/intern/mask.c5
-rw-r--r--source/blender/blenkernel/intern/material.c55
-rw-r--r--source/blender/blenkernel/intern/mball.c29
-rw-r--r--source/blender/blenkernel/intern/mesh.c47
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c184
-rw-r--r--source/blender/blenkernel/intern/node.c29
-rw-r--r--source/blender/blenkernel/intern/object.c9
-rw-r--r--source/blender/blenkernel/intern/particle.c29
-rw-r--r--source/blender/blenkernel/intern/scene.c9
-rw-r--r--source/blender/blenkernel/intern/sequencer.c2
-rw-r--r--source/blender/blenkernel/intern/sound.c5
-rw-r--r--source/blender/blenkernel/intern/speaker.c29
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c115
-rw-r--r--source/blender/blenkernel/intern/text.c5
-rw-r--r--source/blender/blenkernel/intern/texture.c34
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c32
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c6
-rw-r--r--source/blender/blenkernel/intern/world.c31
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c3
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c3
-rw-r--r--source/blender/blenloader/intern/readfile.c2
-rw-r--r--source/blender/blenloader/intern/readfile.h2
-rw-r--r--source/blender/blenloader/intern/versioning_270.c10
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c5
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c222
-rw-r--r--source/blender/bmesh/operators/bmo_connect_nonplanar.c18
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c3
-rw-r--r--source/blender/editors/curve/editcurve.c2
-rw-r--r--source/blender/editors/curve/editcurve_paint.c93
-rw-r--r--source/blender/editors/curve/editcurve_select.c19
-rw-r--r--source/blender/editors/curve/editfont.c2
-rw-r--r--source/blender/editors/io/io_collada.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/render/render_shading.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c4
-rw-r--r--source/blender/editors/sound/sound_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c5
-rw-r--r--source/blender/editors/space_node/node_relationships.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c2
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c32
-rw-r--r--source/blender/editors/transform/transform_conversions.c8
-rw-r--r--source/blender/editors/transform/transform_snap_object.c8
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.cpp2
-rw-r--r--source/blender/freestyle/intern/view_map/Functions1D.cpp2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c21
-rw-r--r--source/blender/gpu/intern/gpu_material.c3
-rw-r--r--source/blender/gpu/intern/gpu_shader.c4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl10
-rw-r--r--source/blender/imbuf/intern/filter.c2
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c4
-rw-r--r--source/blender/makesdna/DNA_brush_types.h9
-rw-r--r--source/blender/makesdna/DNA_genfile.h9
-rw-r--r--source/blender/makesdna/DNA_scene_types.h10
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c27
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_ID.c5
-rw-r--r--source/blender/makesrna/intern/rna_animation.c23
-rw-r--r--source/blender/makesrna/intern/rna_armature.c4
-rw-r--r--source/blender/makesrna/intern/rna_camera.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c10
-rw-r--r--source/blender/makesrna/intern/rna_space.c2
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c7
-rw-r--r--source/blender/python/intern/bpy_operator.c11
-rw-r--r--source/blender/python/intern/bpy_rna.c166
-rw-r--r--source/blender/python/intern/bpy_rna.h2
-rw-r--r--source/blender/render/intern/source/convertblender.c2
-rw-r--r--source/blender/render/intern/source/renderdatabase.c4
-rw-r--r--source/blender/windowmanager/WM_api.h2
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c115
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c2
-rw-r--r--source/creator/creator.c4
160 files changed, 3921 insertions, 1326 deletions
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..c701f28f131
--- /dev/null
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
@@ -0,0 +1,1424 @@
+/*
+ * 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>
+
+
+#include <stdio.h>
+
+#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
+
+
+typedef unsigned int uint;
+
+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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(
+ &params,
+ 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..74327c761e4
--- /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_IMPL_H__
+#define __GENERIC_HEAP_IMPL_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 193ef0cf505..0b3dd552f62 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 10c8959172d..6656beb4478 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/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/render/graph.cpp b/intern/cycles/render/graph.cpp
index ac78238dfee..66601fa3502 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -374,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 */
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 66c92bda54b..e26084c690b 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -5062,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 */
@@ -5077,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 c98ff6f278d..caad11af0f8 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -921,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/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_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 5e4e102cbc9..1512f4f4600 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -1416,7 +1416,7 @@ class USERPREF_PT_addons(Panel):
split.operator("wm.url_open", text="Documentation", icon='HELP').url = info["wiki_url"]
split.operator("wm.url_open", text="Report a Bug", icon='URL').url = info.get(
"tracker_url",
- "http://developer.blender.org/maniphest/task/create/?project=3&type=Bug")
+ "https://developer.blender.org/maniphest/task/edit/form/2")
if user_addon:
split.operator("wm.addon_remove", text="Remove", icon='CANCEL').module = mod.__name__
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 5e8eaf55d0b..fdf0996ac1e 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2472,6 +2472,7 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.operator("mesh.edge_face_add")
layout.operator("mesh.subdivide")
+ layout.operator("mesh.subdivide_edgering")
layout.operator("mesh.unsubdivide")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index b0cc2c63b18..e9f4d715ec2 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -570,6 +570,7 @@ class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
if cps.curve_type == 'BEZIER':
col.label("Bezier Options:")
col.prop(cps, "error_threshold")
+ col.prop(cps, "fit_method")
col.prop(cps, "use_corners_detect")
col = layout.column()
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 3e8ede638ca..2ac7e3c97fb 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 db46ec2497f..b1d51c599ce 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -349,7 +349,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 509524a7ce0..1b3e05d11ae 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -107,7 +107,7 @@ struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene);
struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches);
struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob);
-void BKE_object_make_local(struct Main *bmain, struct Object *ob, 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_particle.h b/source/blender/blenkernel/BKE_particle.h
index dd7068c6d37..ace30b38b3d 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -325,7 +325,7 @@ struct ModifierData *object_add_particle_system(struct Scene *scene, struct Obje
void object_remove_particle_system(struct Scene *scene, struct Object *ob);
struct ParticleSettings *psys_new_settings(const char *name, struct Main *main);
struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, struct ParticleSettings *part);
-void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool force_local);
+void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool lib_local);
void psys_reset(struct ParticleSystem *psys, int mode);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 03af0b7d6c9..d2152950bff 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -101,6 +101,8 @@ struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type);
void BKE_scene_groups_relink(struct Scene *sce);
+void BKE_scene_make_local(struct Main *bmain, struct Scene *sce, const bool lib_local);
+
struct Object *BKE_scene_camera_find(struct Scene *sc);
#ifdef DURIAN_CAMERA_SWITCH
struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 18d9fe061a8..28b15b2a310 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -80,6 +80,8 @@ void BKE_sound_load(struct Main *main, struct bSound *sound);
void BKE_sound_free(struct bSound *sound);
+void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool lib_local);
+
#if defined(__AUD_C_API_H__) || defined(WITH_SYSTEM_AUDASPACE)
AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
#endif
diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h
index 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 2fef79f3897..d992757ed6e 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -74,7 +74,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 0cdf3acf075..9df1c9021ef 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -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/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 7f54c81542b..88df2cfa59d 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -4483,7 +4483,7 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
CLAMP_MIN(max_velocity, vel);
}
- steps = (int)ceil(max_velocity / bData->average_dist * timescale);
+ steps = (int)ceil((double)max_velocity / bData->average_dist * (double)timescale);
CLAMP(steps, 0, 12);
eff_scale = brush->smudge_strength / (float)steps * timescale;
@@ -4633,7 +4633,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;
}
@@ -4650,7 +4650,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);
@@ -5008,7 +5008,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;
@@ -5018,13 +5019,14 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
int numOfNeighs = sData->adj_data->n_num[index];
for (i = 0; i < numOfNeighs; i++) {
- average_dist += bNeighs[sData->adj_data->n_index[index] + i].dist;
+ average_dist += (double)bNeighs[sData->adj_data->n_index[index] + i].dist;
}
}
- average_dist *= wave_scale / sData->adj_data->total_targets;
+ average_dist *= (double)wave_scale / sData->adj_data->total_targets;
/* determine number of required steps */
- steps = (int)ceil((WAVE_TIME_FAC * timescale * surface->wave_timescale) / (average_dist / wave_speed / 3));
+ steps = (int)ceil((double)(WAVE_TIME_FAC * timescale * surface->wave_timescale) /
+ (average_dist / (double)wave_speed / 3));
CLAMP(steps, 1, 20);
timescale /= steps;
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 5e1f8814ed6..580842fe176 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -309,6 +309,11 @@ VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath)
return BKE_vfont_load_exists_ex(bmain, filepath, NULL);
}
+void BKE_vfont_make_local(Main *bmain, VFont *vfont, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &vfont->id, true, lib_local);
+}
+
static VFont *which_vfont(Curve *cu, CharInfo *info)
{
switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) {
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index ac4f566dc62..8621da0d42e 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -390,6 +390,11 @@ bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *src, bool internal_copy)
return dst;
}
+void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local);
+}
+
/* -------- GP-Stroke API --------- */
/* ensure selection status of stroke is in sync with its points */
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 11bbd91e9c9..f58d26f47dc 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -105,6 +105,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 50ab365563a..b1fc9e0fbe0 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)
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, &lt->id);
- BKE_id_expand_local(&lt->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, &lt->id, true, lib_local);
}
typedef struct LatticeDeformData {
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 2e066528f56..c31df685136 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"
@@ -106,6 +107,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
+#include "BKE_sound.h"
#include "BKE_speaker.h"
#include "BKE_scene.h"
#include "BKE_text.h"
@@ -269,89 +271,147 @@ 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_PA:
- if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id, force_local);
+ if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id, lib_local);
return true;
case ID_WM:
return false; /* can't be linked */
case ID_GD:
- return false; /* not implemented */
+ if (!test) BKE_gpencil_make_local(bmain, (bGPdata *)id, lib_local);
+ return true;
+ case ID_MSK:
+ if (!test) BKE_mask_make_local(bmain, (Mask *)id, lib_local);
+ return true;
case ID_LS:
- return false; /* not implemented */
+ if (!test) BKE_linestyle_make_local(bmain, (FreestyleLineStyle *)id, lib_local);
+ return true;
}
return false;
@@ -1467,7 +1527,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;
@@ -1524,53 +1584,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.
@@ -1578,19 +1591,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
@@ -1617,15 +1641,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 04132114d2e..1ded6f6679f 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -442,7 +442,16 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
/* object->proxy is refcounted, but not object->proxy_group... *sigh* */
CALLBACK_INVOKE(object->proxy, IDWALK_USER);
CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
+
+ /* Special case!
+ * Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage
+ * if proxy object is linked... Twisted. */
+ if (object->proxy_from) {
+ data.cd_flag = ID_IS_LINKED_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;
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index f3e6ec1ec51..74b3b1b6c18 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -296,6 +296,9 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
if (ob->pose && (!old_id || ob->data == old_id)) {
BLI_assert(ob->type == OB_ARMATURE);
ob->pose->flag |= POSE_RECALC;
+ /* We need to clear pose bone pointers immediately, things like undo writefile may be called
+ * before pose is actually recomputed, can lead to segfault... */
+ BKE_pose_clear_pointers(ob->pose);
}
}
break;
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..1a20300457f 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,59 @@ 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);
+ 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 +964,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 +989,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 +1057,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 +1077,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 2f7744684e2..d360356aa3d 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1960,34 +1960,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 4bdcec51360..9c48fdfbf08 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1186,13 +1186,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)) {
@@ -1201,7 +1202,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);
@@ -1212,7 +1213,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/particle.c b/source/blender/blenkernel/intern/particle.c
index f88dfdb0306..2c0f183d78f 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -3343,34 +3343,9 @@ ParticleSettings *BKE_particlesettings_copy(Main *bmain, ParticleSettings *part)
return partn;
}
-void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool force_local)
+void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(part)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, part, &is_local, &is_lib);
-
- if (force_local || is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &part->id);
- BKE_id_expand_local(&part->id);
- }
- else {
- ParticleSettings *part_new = BKE_particlesettings_copy(bmain, part);
-
- part_new->id.us = 0;
-
- BKE_libblock_remap(bmain, part, part_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &part->id, true, lib_local);
}
/************************************************/
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 11b60e1301d..3e37ee83cea 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -344,7 +344,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
}
}
- scen->preview = BKE_previewimg_copy(sce->preview);
+ BKE_previewimg_id_copy(&scen->id, &sce->id);
return scen;
}
@@ -355,6 +355,13 @@ void BKE_scene_groups_relink(Scene *sce)
BKE_rigidbody_world_groups_relink(sce->rigidbody_world);
}
+void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local)
+{
+ /* For now should work, may need more work though to support all possible corner cases
+ * (also scene_copy probably needs some love). */
+ BKE_id_make_local_generic(bmain, &sce->id, true, lib_local);
+}
+
/** Free (or release) any data used by this scene (does not free the scene itself). */
void BKE_scene_free(Scene *sce)
{
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 684ed7d3ab4..8ef950294b8 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -866,7 +866,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) {
@@ -874,8 +873,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);
@@ -921,34 +920,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/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 35903961b72..c7dec460b3c 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1280,7 +1280,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 ac2811aeb06..a254a854c66 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1194,8 +1194,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (camera->stereo.pole_merge_angle_from == 0.0f &&
camera->stereo.pole_merge_angle_to == 0.0f)
{
- camera->stereo.pole_merge_angle_from = DEG2RAD(60.0f);
- camera->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
+ camera->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
+ camera->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
}
}
@@ -1225,5 +1225,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 ad7a3c5b9c4..0ed7a397e0b 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -256,6 +256,11 @@ void BLO_update_defaults_startup_blend(Main *bmain)
if (br) {
br->alpha = 1.0f;
}
+
+ br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Flatten/Contrast");
+ if (br) {
+ br->flag |= BRUSH_ACCUMULATE;
+ }
}
}
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 08e97046f68..c500d7b9ec2 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -48,30 +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 */
- const float 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.
@@ -602,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
@@ -909,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
*
@@ -1267,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++;
- }
-#else
- if (line_crosses_v2f(p1, p2, 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++;
}
-#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_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/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/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 c3f83138707..5a0c250c777 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -102,7 +102,7 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
if (!ob)
return OPERATOR_CANCELLED;
- object_add_material_slot(ob);
+ BKE_object_material_slot_add(ob);
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
@@ -145,7 +145,7 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- object_remove_material_slot(ob);
+ BKE_object_material_slot_remove(ob);
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
@@ -529,7 +529,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&tex->id);
if (ptr.id.data && GS(((ID *)ptr.id.data)->name) == ID_MA &&
@@ -592,7 +592,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&wo->id);
RNA_id_pointer_create(&wo->id, &idptr);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 7b296473f31..991025a4d5d 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -257,9 +257,7 @@ static bool make_vertexcol(Object *ob) /* single ob */
/* copies from shadedisplist to mcol */
if (!me->mloopcol && me->totloop) {
- if (!me->mloopcol) {
- CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
- }
+ CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
BKE_mesh_update_customdata_pointers(me, true);
}
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_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 6e0b2e6d9c6..a7945de437a 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -1624,7 +1624,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 fc32613c1ab..b7456facbdf 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -5273,13 +5273,9 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
skip_invert = true;
if (skip_invert == false && constinv == false) {
- if (constinv == false)
- ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
-
+ ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
BKE_object_where_is_calc(t->scene, ob);
-
- if (constinv == false)
- ob->transflag &= ~OB_NO_CONSTRAINTS;
+ ob->transflag &= ~OB_NO_CONSTRAINTS;
}
else
BKE_object_where_is_calc(t->scene, ob);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index c3adebec9d8..1d4872cca7a 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 3c028ff0805..aec94f9f2cb 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -853,11 +853,14 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_MTFACE) {
+ /* NOTE: For now we are using varying on purpose,
+ * otherwise we are not able to write to the varying.
+ */
BLI_dynstr_appendf(ds, "%s %s var%d%s;\n",
- GLEW_VERSION_3_0 ? "in" : "varying",
+ "varying",
GPU_DATATYPE_STR[input->type],
input->attribid,
- GLEW_VERSION_3_0 ? "[]" : "");
+ "");
BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n",
input->attribid);
}
@@ -868,22 +871,20 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl);
/* Generate varying assignments. */
- /* TODO(sergey): Disabled for now, needs revisit. */
-#if 0
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_MTFACE) {
- BLI_dynstr_appendf(ds,
- "\tINTERP_FACE_VARYING_2(var%d, "
- "fvar%d_offset, st);\n",
- input->attribid,
- input->attribid);
+ BLI_dynstr_appendf(
+ ds,
+ "\tINTERP_FACE_VARYING_2(var%d, "
+ "int(texelFetch(FVarDataOffsetBuffer, fvar%d_offset).r), st);\n",
+ input->attribid,
+ input->attribid);
}
}
}
}
-#endif
BLI_dynstr_append(ds, "}\n");
code = BLI_dynstr_get_cstring(ds);
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 98a2ceb472e..4775d2ed30a 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -2886,8 +2886,7 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
"fvar%d_offset",
input->attribid);
location = GPU_shader_get_uniform(shader, name);
- /* Multiply by 2 because we're offseting U and V variables. */
- GPU_shader_uniform_int(shader, location, layer_index * 2);
+ GPU_shader_uniform_int(shader, location, layer_index);
}
}
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 5a1b38e6be7..df1213b01e2 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -437,6 +437,10 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
/* TODO(sergey): Find a better place for this. */
if (use_opensubdiv && GLEW_VERSION_4_1) {
glProgramUniform1i(shader->program,
+ glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"),
+ 30); /* GL_TEXTURE30 */
+
+ glProgramUniform1i(shader->program,
glGetUniformLocation(shader->program, "FVarDataBuffer"),
31); /* GL_TEXTURE31 */
}
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index 1663915549c..6f063883e37 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -32,6 +32,7 @@ uniform int osd_fvar_count;
}
uniform samplerBuffer FVarDataBuffer;
+uniform isamplerBuffer FVarDataOffsetBuffer;
out block {
VertexData v;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index f3bd817a7cc..845a78720ba 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1142,14 +1142,10 @@ void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
- float facm;
-
- fact *= facg;
- facm = 1.0 - fact;
+ vec4 col;
- vec3 one = vec3(1.0);
- vec3 scr = one - (one - texcol) * (one - outcol);
- incol = facm * outcol + fact * ((one - texcol) * outcol * texcol + outcol * scr);
+ mix_soft(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ incol.rgb = col.rgb;
}
void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 26ced49a333..1987c6d2a9a 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -206,7 +206,7 @@ void imb_filterx(struct ImBuf *ibuf)
static void imb_filterN(ImBuf *out, ImBuf *in)
{
BLI_assert(out->channels == in->channels);
- BLI_assert(out->x == in->x && out->y == out->y);
+ BLI_assert(out->x == in->x && out->y == in->y);
const int channels = in->channels;
const int rowlen = in->x;
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index a55cef60943..a4418443790 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -117,7 +117,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp
to[0] = from[r][0];
to[1] = from[g][1];
to[2] = from[b][2];
- to[3] = MAX2(from[0][3], from[0][3]);
+ to[3] = MAX2(from[0][3], from[1][3]);
}
}
}
@@ -154,7 +154,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp
to[0] = from[r][0];
to[1] = from[g][1];
to[2] = from[b][2];
- to[3] = MAX2(from[0][3], from[0][3]);
+ to[3] = MAX2(from[0][3], from[1][3]);
}
}
}
diff --git a/source/blender/makesdna/DNA_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_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 60bd37799fb..c7578a19e0c 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1273,7 +1273,9 @@ typedef struct CurvePaintSettings {
char flag;
char depth_mode;
char surface_plane;
- int error_threshold;
+ char fit_method;
+ char pad;
+ short error_threshold;
float radius_min, radius_max;
float radius_taper_start, radius_taper_end;
float surface_offset;
@@ -1288,6 +1290,12 @@ enum {
CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS = (1 << 3),
};
+/* CurvePaintSettings.fit_method */
+enum {
+ CURVE_PAINT_FIT_METHOD_REFIT = 0,
+ CURVE_PAINT_FIT_METHOD_SPLIT = 1,
+};
+
/* CurvePaintSettings.depth_mode */
enum {
CURVE_PAINT_PROJECT_CURSOR = 0,
diff --git a/source/blender/makesdna/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 b1048f72022..7ae3d552916 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -52,6 +52,7 @@ extern EnumPropertyItem rna_enum_proportional_editing_items[];
extern EnumPropertyItem rna_enum_snap_target_items[];
extern EnumPropertyItem rna_enum_snap_element_items[];
extern EnumPropertyItem rna_enum_snap_node_element_items[];
+extern EnumPropertyItem rna_enum_curve_fit_method_items[];
extern EnumPropertyItem rna_enum_mesh_select_mode_items[];
extern EnumPropertyItem rna_enum_mesh_delimit_mode_items[];
extern EnumPropertyItem rna_enum_space_type_items[];
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 332ca190a08..b6e9844d97a 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -1024,6 +1024,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");
@@ -1042,6 +1043,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_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d1f8c4e5bed..ed90f146f4d 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -178,6 +178,11 @@ EnumPropertyItem snap_uv_element_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem rna_enum_curve_fit_method_items[] = {
+ {CURVE_PAINT_FIT_METHOD_REFIT, "REFIT", 0, "Refit", "Incrementally re-fit the curve (high quality)"},
+ {CURVE_PAINT_FIT_METHOD_SPLIT, "SPLIT", 0, "Split", "Split the curve until the tolerance is met (fast)"},
+ {0, NULL, 0, NULL, NULL}};
+
/* workaround for duplicate enums,
* have each enum line as a define then conditionally set it or not
*/
@@ -2638,6 +2643,11 @@ static void rna_def_curve_paint_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Tolerance", "Allow deviation for a smoother, less precise line");
+ prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_PIXEL);
+ RNA_def_property_enum_sdna(prop, NULL, "fit_method");
+ RNA_def_property_enum_items(prop, rna_enum_curve_fit_method_items);
+ RNA_def_property_ui_text(prop, "Method", "Curve fitting method");
+
prop = RNA_def_property(srna, "corner_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, 0, M_PI);
RNA_def_property_ui_text(prop, "Corner Angle", "Angles above this are considered corners");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index df589bb1bf1..4818fe0cd35 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -3616,7 +3616,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 b8f06f69260..ffa6dd9414c 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_rna.c b/source/blender/python/intern/bpy_rna.c
index e59b01b8f1d..7680897989f 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;
@@ -7501,7 +7542,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) {
@@ -7914,7 +7956,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;
@@ -7929,7 +7973,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/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index ab828a0c04e..86961cdd169 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -4192,7 +4192,7 @@ static void split_quads(ObjectRen *obr, int dir)
vlr= RE_findOrAddVlak(obr, a);
/* test if rendering as a quad or triangle, skip wire */
- if (vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
+ if ((vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
if (vlr->v4) {
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index d3d26011a57..76e6ca8d467 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -1006,7 +1006,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0f;
+ if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
else zn = atan2f(yn, xn);
har->sin = sinf(zn);
@@ -1136,7 +1136,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0;
+ if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
else zn = atan2f(yn, xn);
har->sin = sinf(zn);
diff --git a/source/blender/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 5c5f0909edb..8de70d87f00 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -308,6 +308,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/creator.c b/source/creator/creator.c
index 066b0b0ddb3..a5c7b02b3d9 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -173,9 +173,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