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:
authorPascal Schoen <pascal_schoen@gmx.net>2017-01-24 11:59:58 +0300
committerPascal Schoen <pascal_schoen@gmx.net>2017-01-24 11:59:58 +0300
commit17724e9d2dbffb1aaa61401224ecbf2349c1dac3 (patch)
treebd985509daa781786ac71af0698e610bb6e57557 /source/blender/blenkernel/intern
parent379ba346b0acd1ea779365b940fcd01f5ba1165f (diff)
parent520afa2962f1fc97a04f81a5f6a423dd71cf30f3 (diff)
Merge branch 'master' into cycles_disney_brdf
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c4
-rw-r--r--source/blender/blenkernel/intern/action.c7
-rw-r--r--source/blender/blenkernel/intern/anim.c10
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c11
-rw-r--r--source/blender/blenkernel/intern/armature.c12
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c4
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c7
-rw-r--r--source/blender/blenkernel/intern/blendfile.c4
-rw-r--r--source/blender/blenkernel/intern/brush.c3
-rw-r--r--source/blender/blenkernel/intern/cachefile.c45
-rw-r--r--source/blender/blenkernel/intern/camera.c4
-rw-r--r--source/blender/blenkernel/intern/collision.c6
-rw-r--r--source/blender/blenkernel/intern/constraint.c40
-rw-r--r--source/blender/blenkernel/intern/context.c2
-rw-r--r--source/blender/blenkernel/intern/customdata.c3
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c34
-rw-r--r--source/blender/blenkernel/intern/deform.c187
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c16
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c567
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c56
-rw-r--r--source/blender/blenkernel/intern/effect.c21
-rw-r--r--source/blender/blenkernel/intern/fcurve.c1
-rw-r--r--source/blender/blenkernel/intern/freestyle.c1
-rw-r--r--source/blender/blenkernel/intern/gpencil.c16
-rw-r--r--source/blender/blenkernel/intern/icons.c20
-rw-r--r--source/blender/blenkernel/intern/image.c21
-rw-r--r--source/blender/blenkernel/intern/ipo.c1
-rw-r--r--source/blender/blenkernel/intern/key.c1
-rw-r--r--source/blender/blenkernel/intern/library.c320
-rw-r--r--source/blender/blenkernel/intern/library_query.c40
-rw-r--r--source/blender/blenkernel/intern/library_remap.c92
-rw-r--r--source/blender/blenkernel/intern/linestyle.c1
-rw-r--r--source/blender/blenkernel/intern/mask.c2
-rw-r--r--source/blender/blenkernel/intern/mball.c1
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c7
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c29
-rw-r--r--source/blender/blenkernel/intern/modifier.c3
-rw-r--r--source/blender/blenkernel/intern/nla.c2
-rw-r--r--source/blender/blenkernel/intern/node.c35
-rw-r--r--source/blender/blenkernel/intern/object.c12
-rw-r--r--source/blender/blenkernel/intern/object_deform.c25
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c3
-rw-r--r--source/blender/blenkernel/intern/particle_child.c2
-rw-r--r--source/blender/blenkernel/intern/particle_system.c2
-rw-r--r--source/blender/blenkernel/intern/pbvh.c2
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c17
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c54
-rw-r--r--source/blender/blenkernel/intern/sca.c22
-rw-r--r--source/blender/blenkernel/intern/scene.c28
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c51
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c2
-rw-r--r--source/blender/blenkernel/intern/sequencer.c3
-rw-r--r--source/blender/blenkernel/intern/smoke.c20
-rw-r--r--source/blender/blenkernel/intern/sound.c33
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c60
-rw-r--r--source/blender/blenkernel/intern/text.c8
-rw-r--r--source/blender/blenkernel/intern/tracking.c10
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c4
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c24
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c48
61 files changed, 1242 insertions, 826 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index ae18f5289d4..1f937d837b4 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -230,7 +230,9 @@ static MPoly *dm_dupPolyArray(DerivedMesh *dm)
static int dm_getNumLoopTri(DerivedMesh *dm)
{
- return dm->looptris.num;
+ const int numlooptris = poly_to_tri_count(dm->getNumPolys(dm), dm->getNumLoops(dm));
+ BLI_assert(ELEM(dm->looptris.num, 0, numlooptris));
+ return numlooptris;
}
static CustomData *dm_getVertCData(DerivedMesh *dm)
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 470098f8c7c..1e33fe4ab46 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -44,6 +44,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -433,8 +434,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
chan->scaleIn = chan->scaleOut = 1.0f;
- chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f;
- chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f;
+ chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI;
+ chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI;
chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
chan->ikrotweight = chan->iklinweight = 0.0f;
unit_m4(chan->constinv);
@@ -494,7 +495,7 @@ bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name)
{
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, name, false);
+ BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
if (!STREQ(name_flip, name)) {
return BKE_pose_channel_find_name(pose, name_flip);
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index 7d3d12ac112..2f65e71c6d2 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -201,7 +201,15 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec
mpath->flag |= MOTIONPATH_FLAG_BHEAD;
else
mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
-
+
+ /* set default custom values */
+ mpath->color[0] = 1.0; /* Red */
+ mpath->color[1] = 0.0;
+ mpath->color[2] = 0.0;
+
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
+
/* allocate a cache */
mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index e3764adb969..0b637355ecf 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -43,6 +43,7 @@
#include "BLI_alloca.h"
#include "BLI_dynstr.h"
#include "BLI_listbase.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -308,17 +309,19 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
return true;
}
-void BKE_animdata_copy_id_action(ID *id)
+void BKE_animdata_copy_id_action(ID *id, const bool set_newid)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
if (adt->action) {
id_us_min((ID *)adt->action);
- adt->action = BKE_action_copy(G.main, adt->action);
+ adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(G.main, adt->action)) :
+ BKE_action_copy(G.main, adt->action);
}
if (adt->tmpact) {
id_us_min((ID *)adt->tmpact);
- adt->tmpact = BKE_action_copy(G.main, adt->tmpact);
+ adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(G.main, adt->tmpact)) :
+ BKE_action_copy(G.main, adt->tmpact);
}
}
}
@@ -1657,7 +1660,7 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
/* for cases like duplifarmes it's only a temporary so don't
* notify anyone of updates */
if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
- id->tag |= LIB_TAG_ID_RECALC;
+ BKE_id_tag_set_atomic(id, LIB_TAG_ID_RECALC);
DAG_id_type_tag(G.main, GS(id->name));
}
}
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index c644fe09364..0287d6ae9ca 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -87,6 +87,7 @@ bArmature *BKE_armature_add(Main *bmain, const char *name)
arm->deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE;
arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */
arm->layer = 1;
+ arm->ghostsize = 1;
return arm;
}
@@ -1794,6 +1795,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
/* copy posechannel to temp, but restore important pointers */
pchanw = *pchanp;
+ pchanw.bone = pchan->bone;
pchanw.prev = pchan->prev;
pchanw.next = pchan->next;
pchanw.parent = pchan->parent;
@@ -1916,7 +1918,7 @@ void BKE_pose_clear_pointers(bPose *pose)
/* 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)
+void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones)
{
Bone *bone;
bPose *pose;
@@ -1963,8 +1965,9 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
#ifdef WITH_LEGACY_DEPSGRAPH
/* the sorting */
/* Sorting for new dependnecy graph is done on the scene graph level. */
- if (counter > 1)
+ if (counter > 1 && sort_bones) {
DAG_pose_sort(ob);
+ }
#endif
ob->pose->flag &= ~POSE_RECALC;
@@ -1973,6 +1976,11 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
BKE_pose_channels_hash_make(ob->pose);
}
+void BKE_pose_rebuild(Object *ob, bArmature *arm)
+{
+ BKE_pose_rebuild_ex(ob, arm, true);
+}
+
/* ********************** THE POSE SOLVER ******************* */
/* loc/rot/size to given mat4 */
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index a4c28121040..e57524af546 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -101,7 +101,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor
IMB_colormanagement_check_file_config(bmain_dst);
/* Append, rather than linking. */
Library *lib = BLI_findstring(&bmain_dst->library, libname, offsetof(Library, filepath));
- BKE_library_make_local(bmain_dst, lib, true, false);
+ BKE_library_make_local(bmain_dst, lib, NULL, true, false);
/* Important we unset, otherwise these object wont
* link into other scenes from this blend file.
*/
@@ -150,7 +150,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
/* append, rather than linking */
lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath));
- BKE_library_make_local(bmain, lib, true, false);
+ BKE_library_make_local(bmain, lib, NULL, true, false);
/* important we unset, otherwise these object wont
* link into other scenes from this blend file */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index d64bf7ecf43..bc98d6f6805 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -319,6 +319,13 @@ const char *BKE_undo_get_name(int nr, bool *r_active)
return NULL;
}
+/* return the name of the last item */
+const char *BKE_undo_get_name_last(void)
+{
+ UndoElem *uel = undobase.last;
+ return (uel ? uel->name : NULL);
+}
+
/**
* Saves .blend using undo buffer.
*
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6da68470ecc..54f709a1e5b 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -407,9 +407,9 @@ bool BKE_blendfile_read_from_memfile(
if (bfd) {
/* remove the unused screens and wm */
while (bfd->main->wm.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true);
+ BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true, true);
while (bfd->main->screen.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true);
+ BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true, true);
setup_app_data(C, bfd, "<memory1>", reports);
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 8ef1fae1155..0d509ecea06 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -249,6 +249,9 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
brush_new->id.us = 0;
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(brush, brush_new);
+
if (!lib_local) {
BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index e62e652b4a6..deeb35bd880 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -29,6 +29,8 @@
#include "DNA_anim_types.h"
#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_fileops.h"
@@ -43,6 +45,7 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_modifier.h"
#include "BKE_scene.h"
#ifdef WITH_ALEMBIC
@@ -90,7 +93,9 @@ void BKE_cachefile_free(CacheFile *cache_file)
ABC_free_handle(cache_file->handle);
#endif
- BLI_mutex_free(cache_file->handle_mutex);
+ if (cache_file->handle_mutex) {
+ BLI_mutex_free(cache_file->handle_mutex);
+ }
BLI_freelistN(&cache_file->object_paths);
}
@@ -196,3 +201,41 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f
const float frame = (cache_file->override_frame ? cache_file->frame : time);
return cache_file->is_sequence ? frame : frame / fps;
}
+
+/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
+void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
+{
+ for (Base *base = scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
+
+ if (md) {
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+ if (cache_file == mcmd->cache_file) {
+#ifdef WITH_ALEMBIC
+ CacheReader_free(mcmd->reader);
+#endif
+ mcmd->reader = NULL;
+ mcmd->object_path[0] = '\0';
+ }
+ }
+
+ for (bConstraint *con = ob->constraints.first; con; con = con->next) {
+ if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ continue;
+ }
+
+ bTransformCacheConstraint *data = con->data;
+
+ if (cache_file == data->cache_file) {
+#ifdef WITH_ALEMBIC
+ CacheReader_free(data->reader);
+#endif
+ data->reader = NULL;
+ data->object_path[0] = '\0';
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 85ce399b770..9cb553aa27b 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -252,7 +252,7 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons
}
else if (rv3d->persp == RV3D_ORTHO) {
/* orthographic view */
- int sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
+ float sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
params->clipend *= 0.5f; // otherwise too extreme low zbuffer quality
params->clipsta = -params->clipend;
@@ -337,6 +337,8 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
viewplane.ymin *= pixsize;
viewplane.ymax *= pixsize;
+ /* Used for rendering (offset by near-clip with perspective views), passed to RE_SetPixelSize.
+ * For viewport drawing 'RegionView3D.pixsize'. */
params->viewdx = pixsize;
params->viewdy = params->ycor * pixsize;
params->viewplane = viewplane;
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 18ca1407ba0..ee25be36855 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -1014,7 +1014,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll
}
BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3],
- float r_nor[3], float *r_lambda, float r_w[4])
+ float r_nor[3], float *r_lambda, float r_w[3])
{
float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3];
float nor_v0p2, nor_p1p2;
@@ -1026,7 +1026,7 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float
nor_v0p2 = dot_v3v3(v0p2, r_nor);
madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
- interp_weights_face_v3(r_w, v0, v1, v2, NULL, p2face);
+ interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
sub_v3_v3v3(p1p2, p2, p1);
sub_v3_v3v3(v0p2, p2, v0);
@@ -1085,7 +1085,7 @@ static CollPair *cloth_point_collpair(
const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
float lambda /*, distance1 */, distance2;
float facenor[3], v1p1[3], v1p2[3];
- float w[4];
+ float w[3];
if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w))
return collpair;
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index c4afa58b7d3..58ad171ee20 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_kdopbvh.h"
#include "BLI_utildefines.h"
-
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
#include "DNA_armature_types.h"
@@ -4364,8 +4364,14 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
BKE_cachefile_ensure_handle(G.main, cache_file);
- ABC_get_transform(cache_file->handle, cob->ob, data->object_path,
- cob->matrix, time, cache_file->scale);
+ if (!data->reader) {
+ data->reader = CacheReader_open_alembic_object(cache_file->handle,
+ data->reader,
+ cob->ob,
+ data->object_path);
+ }
+
+ ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
#else
UNUSED_VARS(con, cob);
#endif
@@ -4393,6 +4399,13 @@ static void transformcache_free(bConstraint *con)
if (data->cache_file) {
id_us_min(&data->cache_file->id);
}
+
+ if (data->reader) {
+#ifdef WITH_ALEMBIC
+ CacheReader_free(data->reader);
+#endif
+ data->reader = NULL;
+ }
}
static void transformcache_new_data(void *cdata)
@@ -4693,27 +4706,6 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t
/* ......... */
-/* helper for BKE_constraints_relink() - call ID_NEW() on every ID reference the constraint has */
-static void con_relink_id_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userdata))
-{
- /* ID_NEW() expects a struct with inline "id" member as first
- * since we've got the actual ID block, let's just inline this
- * code.
- *
- * See ID_NEW(a) in DNA_ID.h
- */
- if ((*idpoin) && (*idpoin)->newid)
- (*idpoin) = (void *)(*idpoin)->newid;
-}
-
-/* Reassign links that constraints have to other data (called during file loading?) */
-void BKE_constraints_relink(ListBase *conlist)
-{
- /* just a wrapper around ID-loop for just calling ID_NEW() on all ID refs */
- BKE_constraints_id_loop(conlist, con_relink_id_cb, NULL);
-}
-
-
/* Run the given callback on all ID-blocks in list of constraints */
void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata)
{
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 926ca8da192..4c01bfd35f2 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -49,6 +49,7 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_sound.h"
#include "RNA_access.h"
@@ -882,6 +883,7 @@ Main *CTX_data_main(const bContext *C)
void CTX_data_main_set(bContext *C, Main *bmain)
{
C->data.main = bmain;
+ BKE_sound_init_main(bmain);
}
Scene *CTX_data_scene(const bContext *C)
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 612f1f477e1..98d37fb07bf 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -45,8 +45,9 @@
#include "DNA_ID.h"
#include "BLI_utildefines.h"
-#include "BLI_string.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_mempool.h"
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 839673c192b..3bc09c0173b 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -1205,6 +1205,18 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
+ if ((map_vert_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any edges, "
+ "None of the 'Edge' mappings can be used in this case");
+ continue;
+ }
+ if ((map_vert_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any faces, "
+ "None of the 'Face' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_verts_dst, num_verts_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any vertices, cannot transfer vertex data");
@@ -1253,6 +1265,12 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
+ if ((map_edge_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any faces, "
+ "None of the 'Face' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_edges_dst, num_edges_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any edges, cannot transfer edge data");
@@ -1312,9 +1330,15 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
+ if ((map_loop_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any edges, "
+ "None of the 'Edge' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_loops_dst, num_loops_src)) {
BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any polygons, cannot transfer loop data");
+ "Source or destination meshes do not have any faces, cannot transfer corner data");
continue;
}
@@ -1370,9 +1394,15 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
+ if ((map_poly_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any edges, "
+ "None of the 'Edge' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_polys_dst, num_polys_src)) {
BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any polygons, cannot transfer poly data");
+ "Source or destination meshes do not have any faces, cannot transfer face data");
continue;
}
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 7052e0a7d25..13b1aab5e1c 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -45,8 +45,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -509,7 +509,7 @@ int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default)
if (use_default)
map[i] = i;
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_num = defgroup_name_index(ob, name_flip);
@@ -545,7 +545,7 @@ int *defgroup_flip_map_single(Object *ob, int *flip_map_len, const bool use_defa
dg = BLI_findlink(&ob->defbase, defgroup);
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_num = defgroup_name_index(ob, name_flip);
@@ -566,7 +566,7 @@ int defgroup_flip_index(Object *ob, int index, const bool use_default)
if (dg) {
char name_flip[sizeof(dg->name)];
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_index = defgroup_name_index(ob, name_flip);
@@ -606,185 +606,6 @@ void defgroup_unique_name(bDeformGroup *dg, Object *ob)
BLI_uniquename_cb(defgroup_unique_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name));
}
-static bool is_char_sep(const char c)
-{
- return ELEM(c, '.', ' ', '-', '_');
-}
-
-/**
- * based on `BLI_split_dirfile()` / `os.path.splitext()`,
- * `"a.b.c"` -> (`"a.b"`, `".c"`).
- */
-void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME], char suf[MAX_VGROUP_NAME])
-{
- size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
- size_t i;
-
- body[0] = suf[0] = '\0';
-
- for (i = len; i > 0; i--) {
- if (is_char_sep(string[i])) {
- BLI_strncpy(body, string, i + 1);
- BLI_strncpy(suf, string + i, (len + 1) - i);
- return;
- }
- }
-
- memcpy(body, string, len + 1);
-}
-
-/**
- * `"a.b.c"` -> (`"a."`, `"b.c"`)
- */
-void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char pre[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME])
-{
- size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
- size_t i;
-
- body[0] = pre[0] = '\0';
-
- for (i = 1; i < len; i++) {
- if (is_char_sep(string[i])) {
- i++;
- BLI_strncpy(pre, string, i + 1);
- BLI_strncpy(body, string + i, (len + 1) - i);
- return;
- }
- }
-
- BLI_strncpy(body, string, len);
-}
-
-/**
- * Finds the best possible flipped name. For renaming; check for unique names afterwards.
- *
- * if strip_number: removes number extensions
- *
- * \note don't use sizeof() for 'name' or 'from_name'.
- */
-void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME],
- const bool strip_number)
-{
- int len;
- char prefix[MAX_VGROUP_NAME] = ""; /* The part before the facing */
- char suffix[MAX_VGROUP_NAME] = ""; /* The part after the facing */
- char replace[MAX_VGROUP_NAME] = ""; /* The replacement string */
- char number[MAX_VGROUP_NAME] = ""; /* The number extension string */
- char *index = NULL;
- bool is_set = false;
-
- /* always copy the name, since this can be called with an uninitialized string */
- BLI_strncpy(name, from_name, MAX_VGROUP_NAME);
-
- len = BLI_strnlen(from_name, MAX_VGROUP_NAME);
- if (len < 3) {
- /* we don't do names like .R or .L */
- return;
- }
-
- /* We first check the case with a .### extension, let's find the last period */
- if (isdigit(name[len - 1])) {
- index = strrchr(name, '.'); // last occurrence
- if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever!
- if (strip_number == false) {
- BLI_strncpy(number, index, sizeof(number));
- }
- *index = 0;
- len = BLI_strnlen(name, MAX_VGROUP_NAME);
- }
- }
-
- BLI_strncpy(prefix, name, sizeof(prefix));
-
- /* first case; separator . - _ with extensions r R l L */
- if ((len > 1) && is_char_sep(name[len - 2])) {
- is_set = true;
- switch (name[len - 1]) {
- case 'l':
- prefix[len - 1] = 0;
- strcpy(replace, "r");
- break;
- case 'r':
- prefix[len - 1] = 0;
- strcpy(replace, "l");
- break;
- case 'L':
- prefix[len - 1] = 0;
- strcpy(replace, "R");
- break;
- case 'R':
- prefix[len - 1] = 0;
- strcpy(replace, "L");
- break;
- default:
- is_set = false;
- }
- }
-
- /* case; beginning with r R l L, with separator after it */
- if (!is_set && is_char_sep(name[1])) {
- is_set = true;
- switch (name[0]) {
- case 'l':
- strcpy(replace, "r");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'r':
- strcpy(replace, "l");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'L':
- strcpy(replace, "R");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'R':
- strcpy(replace, "L");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- default:
- is_set = false;
- }
- }
-
- if (!is_set && len > 5) {
- /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
- if (((index = BLI_strcasestr(prefix, "right")) == prefix) ||
- (index == prefix + len - 5))
- {
- is_set = true;
- if (index[0] == 'r') {
- strcpy(replace, "left");
- }
- else {
- strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
- }
- *index = 0;
- BLI_strncpy(suffix, index + 5, sizeof(suffix));
- }
- else if (((index = BLI_strcasestr(prefix, "left")) == prefix) ||
- (index == prefix + len - 4))
- {
- is_set = true;
- if (index[0] == 'l') {
- strcpy(replace, "right");
- }
- else {
- strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
- }
- *index = 0;
- BLI_strncpy(suffix, index + 4, sizeof(suffix));
- }
- }
-
- (void)is_set; /* quiet warning */
-
- BLI_snprintf(name, MAX_VGROUP_NAME, "%s%s%s%s", prefix, replace, suffix, number);
-}
-
float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
{
MDeformWeight *dw = defvert_find_index(dvert, defgroup);
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 5f8332dcf0c..a8341939692 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -800,6 +800,10 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
/* Actual code uses get_collider_cache */
dag_add_collision_relations(dag, scene, ob, node, part->collision_group, ob->lay, eModifierType_Collision, NULL, true, "Particle Collision");
}
+ else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) {
+ /* Hair uses cloth simulation, i.e. get_collision_objects */
+ dag_add_collision_relations(dag, scene, ob, node, psys->clmd->coll_parms->group, ob->lay | scene->lay, eModifierType_Collision, NULL, true, "Hair Collision");
+ }
dag_add_forcefield_relations(dag, scene, ob, node, part->effector_weights, part->type == PART_HAIR, 0, "Particle Force Field");
@@ -1428,7 +1432,6 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
/* test; are group objects all in this scene? */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
ob->id.tag &= ~LIB_TAG_DOIT;
- ob->id.newid = NULL; /* newid abuse for GroupObject */
}
for (base = sce->base.first; base; base = base->next)
base->object->id.tag |= LIB_TAG_DOIT;
@@ -1459,6 +1462,11 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
group->gobject = listb;
}
}
+
+ /* newid abused for GroupObject, cleanup. */
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
+ ob->id.newid = NULL;
+ }
}
static void dag_scene_tag_rebuild(Scene *sce)
@@ -2997,7 +3005,7 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
if (mcmd->cache_file && (&mcmd->cache_file->id == id)) {
- ob->recalc |= OB_RECALC_DATA;
+ ob->recalc |= OB_RECALC_ALL;
continue;
}
}
@@ -3010,7 +3018,7 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
bTransformCacheConstraint *data = con->data;
if (data->cache_file && (&data->cache_file->id == id)) {
- ob->recalc |= OB_RECALC_DATA;
+ ob->recalc |= OB_RECALC_ALL;
break;
}
}
@@ -3284,7 +3292,7 @@ void DAG_threaded_update_handle_node_updated(void *node_v,
for (itA = node->child; itA; itA = itA->next) {
DagNode *child_node = itA->node;
if (child_node != node) {
- atomic_sub_uint32(&child_node->num_pending_parents, 1);
+ atomic_sub_and_fetch_uint32(&child_node->num_pending_parents, 1);
if (child_node->num_pending_parents == 0) {
bool need_schedule;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index c7399047ed5..dc9f3b57f1f 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -32,6 +32,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_kdtree.h"
+#include "BLI_string_utils.h"
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -215,6 +216,7 @@ typedef struct ImgSeqFormatData {
/* adjacency data flags */
#define ADJ_ON_MESH_EDGE (1 << 0)
+#define ADJ_BORDER_PIXEL (1 << 1)
typedef struct PaintAdjData {
int *n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
@@ -222,6 +224,8 @@ typedef struct PaintAdjData {
int *n_num; /* num of neighs for each point */
int *flags; /* vertex adjacency flags */
int total_targets; /* size of n_target */
+ int *border; /* indices of border pixels (only for texture paint) */
+ int total_border; /* size of border */
} PaintAdjData;
/***************************** General Utils ******************************/
@@ -822,6 +826,8 @@ static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
MEM_freeN(data->adj_data->n_target);
if (data->adj_data->flags)
MEM_freeN(data->adj_data->flags);
+ if (data->adj_data->border)
+ MEM_freeN(data->adj_data->border);
MEM_freeN(data->adj_data);
data->adj_data = NULL;
}
@@ -1298,6 +1304,8 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
ad->total_targets = neigh_points;
+ ad->border = NULL;
+ ad->total_border = 0;
/* in case of allocation error, free memory */
if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
@@ -2264,7 +2272,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
* to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
*/
tPoint->neighbour_pixel = ind - 1;
- atomic_add_uint32(&tPoint->neighbour_pixel, 1);
+ atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1);
tPoint->tri_index = i;
/* Now calculate pixel data for this pixel as it was on polygon surface */
@@ -2289,12 +2297,42 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
/* Increase the final number of active surface points if relevant. */
if (tPoint->tri_index != -1)
- atomic_add_uint32(active_points, 1);
+ atomic_add_and_fetch_uint32(active_points, 1);
}
}
#undef JITTER_SAMPLES
+static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri, const MLoopUV *mloopuv, int tri_index, const float point[2])
+{
+ float min_distance = FLT_MAX;
+
+ for (int i = 0; i < 3; i++) {
+ const float dist_squared = dist_squared_to_line_segment_v2(
+ point,
+ mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv,
+ mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv
+ );
+
+ if (dist_squared < min_distance)
+ min_distance = dist_squared;
+ }
+
+ return min_distance;
+}
+
+typedef struct DynamicPaintFindIslandBorderData {
+ const MeshElemMap *vert_to_looptri_map;
+ int w, h, px, py;
+
+ int best_index;
+ float best_weight;
+} DynamicPaintFindIslandBorderData;
+
+static void dynamic_paint_find_island_border(
+ const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
+ int tri_index, const float pixel[2], int in_edge, int depth);
+
/* Tries to find the neighboring pixel in given (uv space) direction.
* Result is used by effect system to move paint on the surface.
*
@@ -2345,167 +2383,162 @@ static int dynamic_paint_find_neighbour_pixel(
* TODO: Implement something more accurate / optimized?
*/
{
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
-
- /* Get closest edge to that subpixel on UV map */
+ DynamicPaintFindIslandBorderData bdata = {
+ .vert_to_looptri_map = vert_to_looptri_map,
+ .w = w, .h = h, .px = px, .py = py,
+ .best_index = NOT_FOUND, .best_weight = 1.0f
+ };
float pixel[2];
- /* distances only used for comparison */
- float dist_squared, t_dist_squared;
-
- int edge1_index, edge2_index;
- int e1_index, e2_index, target_tri;
- float closest_point[2], lambda, dir_vec[2];
- int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
-
- const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
- /*
- * Find closest edge to that pixel
- */
+ /* Do a small recursive search for the best island edge. */
+ dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
- /* Dist to first edge */
- e1_index = cPoint->v1;
- e2_index = cPoint->v2;
- edge1_index = 0;
- edge2_index = 1;
- dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
-
- /* Dist to second edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v2;
- e2_index = cPoint->v3;
- edge1_index = 1;
- edge2_index = 2;
- dist_squared = t_dist_squared;
- }
-
- /* Dist to third edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v3;
- e2_index = cPoint->v1;
- edge1_index = 2;
- edge2_index = 0;
- dist_squared = t_dist_squared;
- }
+ return bdata.best_index;
+ }
+}
- /*
- * Now find another face that is linked to that edge
- */
- target_tri = -1;
+static void dynamic_paint_find_island_border(
+ const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
+ int tri_index, const float pixel[2], int in_edge, int depth)
+{
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
- /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
- for (int i = 0; i < vert_to_looptri_map[e1_index].count; i++) {
- const int lt_index = vert_to_looptri_map[e1_index].indices[i];
- const int v0 = mloop[mlooptri[lt_index].tri[0]].v;
- const int v1 = mloop[mlooptri[lt_index].tri[1]].v;
- const int v2 = mloop[mlooptri[lt_index].tri[2]].v;
+ const unsigned int *loop_idx = mlooptri[tri_index].tri;
- BLI_assert(ELEM(e1_index, v0, v1, v2));
+ /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
+ for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
+ /* but not the edge we have just recursed through */
+ if (edge_idx == in_edge)
+ continue;
- if (ELEM(e2_index, v0, v1, v2)) {
- if (lt_index == cPoint->tri_index)
- continue;
+ float uv0[2], uv1[2], uv2[2];
- target_tri = lt_index;
+ copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv);
+ copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv);
+ copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv);
- /* Get edge UV index */
- target_uv1 = (e1_index == v0) ? 0 : ((e1_index == v1) ? 1 : 2);
- target_uv2 = (e2_index == v0) ? 0 : ((e2_index == v1) ? 1 : 2);
- break;
- }
- }
+ /* Verify the target point is on the opposite side of the edge from the third triangle
+ * vertex, to ensure that we always move closer to the goal point. */
+ const float sidep = line_point_side_v2(uv0, uv1, pixel);
+ const float side2 = line_point_side_v2(uv0, uv1, uv2);
- /* If none found pixel is on mesh edge */
- if (target_tri == -1)
- return ON_MESH_EDGE;
+ if (side2 == 0.0f)
+ continue;
- /*
- * If target face is connected in UV space as well, just use original index
- */
- s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
- s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
- t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
- t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+ /* Hack: allow all edges of the original triangle */
+ const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) || (sidep > 0 && side2 < 0);
- //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
+ /* Allow exactly on edge for the non-recursive case */
+ if (!correct_side && sidep != 0.0f)
+ continue;
- if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
- (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) ||
- ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
- (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1])))
- {
- final_index = x + w * y;
+ /* Now find another face that is linked to that edge. */
+ const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v;
+ const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
+
+ /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
+ const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
+
+ bool found_other = false;
+ int target_tri = -1;
+ int target_edge = -1;
+
+ float ouv0[2], ouv1[2];
+
+ for (int i = 0; i < map->count && !found_other; i++) {
+ const int lt_index = map->indices[i];
+
+ if (lt_index == tri_index)
+ continue;
+
+ const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
+
+ /* Check edges for match, looping in the same order as the outer loop. */
+ for (int j = 0; j < 3; j++)
+ {
+ const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
+ const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
+
+ /* Allow for swapped vertex order */
+ if (overt0 == vert0 && overt1 == vert1) {
+ found_other = true;
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+ else if (overt0 == vert1 && overt1 == vert0) {
+ found_other = true;
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+
+ if (found_other) {
+ target_tri = lt_index;
+ target_edge = j;
+ break;
+ }
+ }
+ }
- /* If not an active pixel, bail out */
- if (tempPoints[final_index].tri_index == -1)
- return NOT_FOUND;
+ if (!found_other) {
+ if (bdata->best_index < 0)
+ bdata->best_index = ON_MESH_EDGE;
- /* If final point is an "edge pixel", use it's "real" neighbor instead */
- if (tempPoints[final_index].neighbour_pixel != -1) {
- final_index = tempPoints[final_index].neighbour_pixel;
+ continue;
+ }
- /* If we ended up to our origin point */
- if (final_index == (px + w * py))
- return NOT_FOUND;
+ /* If this edge is connected in UV space too, recurse */
+ if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
+ if (depth > 0 && correct_side) {
+ dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
}
- return final_index;
+ continue;
}
+ /* Otherwise try to map to the other side of the edge.
+ * First check if there already is a better solution. */
+ const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
+
+ if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight)
+ continue;
+
/*
* Find a point that is relatively at same edge position
* on this other face UV
*/
- lambda = closest_to_line_v2(
- closest_point, pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
- CLAMP(lambda, 0.0f, 1.0f);
+ float closest_point[2], dir_vec[2], tgt_pixel[2];
- sub_v2_v2v2(
- dir_vec,
- mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
- mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+ float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
+ CLAMP(lambda, 0.0f, 1.0f);
- mul_v2_fl(dir_vec, lambda);
+ sub_v2_v2v2(dir_vec, ouv1, ouv0);
+ madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda);
- copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
- add_v2_v2(pixel, dir_vec);
- pixel[0] = (pixel[0] * (float)w);
- pixel[1] = (pixel[1] * (float)h);
+ int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
- final_pixel[0] = (int)floorf(pixel[0]);
- final_pixel[1] = (int)floorf(pixel[1]);
+ int final_pixel[2] = { (int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h) };
/* If current pixel uv is outside of texture */
if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h)
- return OUT_OF_TEXTURE;
+ {
+ if (bdata->best_index == NOT_FOUND)
+ bdata->best_index = OUT_OF_TEXTURE;
+
+ continue;
+ }
- final_index = final_pixel[0] + w * final_pixel[1];
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ int final_index = final_pixel[0] + w * final_pixel[1];
/* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
if (final_index == (px + w * py))
- return NOT_FOUND;
- /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri)
- return NOT_FOUND;
+ continue;
/* If final point is an "edge pixel", use it's "real" neighbor instead */
if (tempPoints[final_index].neighbour_pixel != -1) {
@@ -2513,11 +2546,125 @@ static int dynamic_paint_find_neighbour_pixel(
/* If we ended up to our origin point */
if (final_index == (px + w * py))
- return NOT_FOUND;
+ continue;
+ }
+
+ /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ if (tempPoints[final_index].tri_index != target_tri) {
+ /* Check if it's close enough to likely touch the intended triangle. Any triangle
+ * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
+ const float final_pt[2] = { ((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h };
+ const float threshold = SQUARE(0.7f) / (w * h);
+
+ if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold)
+ continue;
+ }
+
+ bdata->best_index = final_index;
+ bdata->best_weight = dist_squared;
+ }
+}
+
+static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
+{
+ const int idx = ed->n_index[index];
+
+ for (int i = 0; i < ed->n_num[index]; i++) {
+ if (ed->n_target[idx + i] == neighbor) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Makes the adjacency data symmetric, except for border pixels. I.e. if A is neighbor of B, B is neighbor of A. */
+static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
+{
+ int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index");
+ int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts");
+
+ if (new_n_num && new_n_index) {
+ /* Count symmetrized neigbors */
+ int total_targets = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ total_targets += ed->n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ new_n_num[target]++;
+ total_targets++;
+ }
+ }
}
- return final_index;
+ /* Allocate a new target map */
+ int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets");
+
+ if (new_n_target) {
+ /* Copy existing neighbors to the new map */
+ int n_pos = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ new_n_index[index] = n_pos;
+ memcpy(&new_n_target[n_pos], &ed->n_target[ed->n_index[index]], sizeof(int) * ed->n_num[index]);
+
+ /* Reset count to old, but advance position by new, leaving a gap to fill below. */
+ n_pos += new_n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ assert(n_pos == total_targets);
+
+ /* Add symmetrized - this loop behavior must exactly match the count pass above */
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ const int num = new_n_num[target]++;
+ new_n_target[new_n_index[target] + num] = index;
+ }
+ }
+ }
+
+ /* Swap maps */
+ MEM_freeN(ed->n_target);
+ ed->n_target = new_n_target;
+
+ MEM_freeN(ed->n_index);
+ ed->n_index = new_n_index;
+
+ MEM_freeN(ed->n_num);
+ ed->n_num = new_n_num;
+
+ ed->total_targets = total_targets;
+ return true;
+ }
}
+
+ if (new_n_index)
+ MEM_freeN(new_n_index);
+ if (new_n_num)
+ MEM_freeN(new_n_num);
+
+ return false;
}
int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
@@ -2668,30 +2815,28 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
&vert_to_looptri_map, &vert_to_looptri_map_mem,
dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+ int total_border = 0;
+
for (int ty = 0; ty < h; ty++) {
for (int tx = 0; tx < w; tx++) {
const int index = tx + w * ty;
if (tempPoints[index].tri_index != -1) {
- int start_pos = n_pos;
ed->n_index[final_index[index]] = n_pos;
ed->n_num[final_index[index]] = 0;
+ if (tempPoints[index].neighbour_pixel != -1) {
+ ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
+ total_border++;
+ }
+
for (int i = 0; i < 8; i++) {
/* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
const int n_target = dynamic_paint_find_neighbour_pixel(
&data, vert_to_looptri_map, w, h, tx, ty, i);
if (n_target >= 0 && n_target != index) {
- bool duplicate = false;
- for (int j = start_pos; j < n_pos; j++) {
- if (ed->n_target[j] == final_index[n_target]) {
- duplicate = true;
- break;
- }
- }
-
- if (!duplicate) {
+ if (!dynamicPaint_pointHasNeighbor(ed, final_index[index], final_index[n_target])) {
ed->n_target[n_pos] = final_index[n_target];
ed->n_num[final_index[index]]++;
n_pos++;
@@ -2707,6 +2852,57 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
MEM_freeN(vert_to_looptri_map);
MEM_freeN(vert_to_looptri_map_mem);
+
+ /* Make neighbors symmetric */
+ if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
+ error = true;
+ }
+
+ /* Create a list of border pixels */
+ ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index");
+
+ if (ed->border) {
+ ed->total_border = total_border;
+
+ for (int i = 0, next = 0; i < active_points; i++) {
+ if (ed->flags[i] & ADJ_BORDER_PIXEL) {
+ ed->border[next++] = i;
+ }
+ }
+ }
+
+#if 0
+ /* -----------------------------------------------------------------
+ * For debug, write a dump of adjacency data to a file.
+ * -----------------------------------------------------------------*/
+ FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
+ int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ if (tempPoints[index].tri_index != -1)
+ tmp[final_index[index]] = index;
+ }
+ }
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ const int fidx = final_index[index];
+
+ if (tempPoints[index].tri_index != -1) {
+ int nidx = tempPoints[index].neighbour_pixel;
+ fprintf(dump_file, "%d\t%d,%d\t%u\t%d,%d\t%d\t", fidx, tx, h-1-ty, tempPoints[index].tri_index, nidx<0?-1:(nidx%w), nidx<0?-1:h-1-(nidx/w), ed->flags[fidx]);
+ for (int i = 0; i < ed->n_num[fidx]; i++) {
+ int tgt = tmp[ed->n_target[ed->n_index[fidx]+i]];
+ fprintf(dump_file, "%s%d,%d", i?" ":"", tgt%w, h-1-tgt/w);
+ }
+ fprintf(dump_file, "\n");
+ }
+ }
+ }
+ MEM_freeN(tmp);
+ fclose(dump_file);
+#endif
}
}
@@ -3739,7 +3935,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
/* velocity brush, only do on main sample */
if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
- float weights[4];
+ float weights[3];
float brushPointVelocity[3];
float velocity[3];
@@ -3748,7 +3944,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
/* calculate barycentric weights for hit point */
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord);
/* simple check based on brush surface velocity,
* todo: perhaps implement something that handles volume movement as well */
@@ -4529,6 +4725,10 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
for (step = 0; step < steps; step++) {
for (index = 0; index < sData->total_points; index++) {
int i;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ continue;
+
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
float smudge_str = bData->brush_velocity[index * 4 + 3];
@@ -4708,6 +4908,9 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4737,7 +4940,7 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
CLAMP(w_factor, 0.0f, 1.0f);
/* mix new wetness and color */
- pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * pPoint_prev->wetness;
+ pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness);
pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3],
pPoint_prev->e_color, pPoint_prev->e_color[3], w_factor);
}
@@ -4750,6 +4953,9 @@ static void dynamic_paint_effect_shrink_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4796,6 +5002,10 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
const PaintPoint *prevPoint = data->prevPoint;
@@ -4964,6 +5174,80 @@ static void dynamicPaint_doEffectStep(
}
}
+static void dynamic_paint_border_cb(void *userdata, const int b_index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int index = sData->adj_data->border[b_index];
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Average neighboring points. Intermediaries use premultiplied alpha. */
+ float mix_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float mix_e_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float mix_wetness = 0.0f;
+
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const int target = n_target[n_idx];
+
+ PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
+
+ assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
+
+ madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
+ mix_color[3] += pPoint2->color[3];
+
+ madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
+ mix_e_color[3] += pPoint2->e_color[3];
+
+ mix_wetness += pPoint2->wetness;
+ }
+
+ const float divisor = 1.0f / numOfNeighs;
+
+ if (mix_color[3]) {
+ pPoint->color[3] = mix_color[3] * divisor;
+ mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
+ }
+ else {
+ pPoint->color[3] = 0.0f;
+ }
+
+ if (mix_e_color[3]) {
+ pPoint->e_color[3] = mix_e_color[3] * divisor;
+ mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
+ }
+ else {
+ pPoint->e_color[3] = 0.0f;
+ }
+
+ pPoint->wetness = mix_wetness / numOfNeighs;
+}
+
+static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface)
+{
+ PaintSurfaceData *sData = surface->data;
+
+ if (!sData->adj_data || !sData->adj_data->border)
+ return;
+
+ /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
+ DynamicPaintEffectData data = {
+ .surface = surface
+ };
+
+ BLI_task_parallel_range(
+ 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, sData->adj_data->total_border > 1000);
+}
+
static void dynamic_paint_wave_step_cb(void *userdata, const int index)
{
const DynamicPaintEffectData *data = userdata;
@@ -5636,6 +5920,11 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (force)
MEM_freeN(force);
}
+
+ /* paint island border pixels */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ dynamicPaint_doBorderStep(surface);
+ }
}
return ret;
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 05cf5f6d7bd..e7c0e69b1cb 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -621,10 +621,33 @@ static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))
/* do nothing */
}
-static void emDM_recalcLoopTri(DerivedMesh *UNUSED(dm))
+static void emDM_recalcLoopTri(DerivedMesh *dm)
{
- /* Nothing to do: emDM tessellation is known,
- * allocate and fill in with emDM_getLoopTriArray */
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMLoop *(*looptris)[3] = bmdm->em->looptris;
+ MLoopTri *mlooptri;
+ const int tottri = bmdm->em->tottri;
+ int i;
+
+ DM_ensure_looptri_data(dm);
+ mlooptri = dm->looptris.array;
+
+ BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
+ BLI_assert(tottri == dm->looptris.num);
+
+ BM_mesh_elem_index_ensure(bmdm->em->bm, BM_FACE | BM_LOOP);
+
+ for (i = 0; i < tottri; i++) {
+ BMLoop **ltri = looptris[i];
+ MLoopTri *lt = &mlooptri[i];
+
+ ARRAY_SET_ITEMS(
+ lt->tri,
+ BM_elem_index_get(ltri[0]),
+ BM_elem_index_get(ltri[1]),
+ BM_elem_index_get(ltri[2]));
+ lt->poly = BM_elem_index_get(ltri[0]->f);
+ }
}
static const MLoopTri *emDM_getLoopTriArray(DerivedMesh *dm)
@@ -633,32 +656,9 @@ static const MLoopTri *emDM_getLoopTriArray(DerivedMesh *dm)
BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
}
else {
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMLoop *(*looptris)[3] = bmdm->em->looptris;
- MLoopTri *mlooptri;
- const int tottri = bmdm->em->tottri;
- int i;
-
- DM_ensure_looptri_data(dm);
- mlooptri = dm->looptris.array;
-
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- BLI_assert(tottri == dm->looptris.num);
-
- BM_mesh_elem_index_ensure(bmdm->em->bm, BM_FACE | BM_LOOP);
-
- for (i = 0; i < tottri; i++) {
- BMLoop **ltri = looptris[i];
- MLoopTri *lt = &mlooptri[i];
-
- ARRAY_SET_ITEMS(
- lt->tri,
- BM_elem_index_get(ltri[0]),
- BM_elem_index_get(ltri[1]),
- BM_elem_index_get(ltri[2]));
- lt->poly = BM_elem_index_get(ltri[0]->f);
- }
+ dm->recalcLoopTri(dm);
}
+
return dm->looptris.array;
}
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 7e6897a2858..fe8f5ebdca6 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -770,7 +770,7 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
force[1] = (0.5f - result->tg) * strength;
force[2] = (0.5f - result->tb) * strength;
}
- else {
+ else if (nabla != 0) {
strength/=nabla;
tex_co[0] += nabla;
@@ -810,6 +810,9 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
force[2] = (dgdx - drdy) * strength;
}
}
+ else {
+ zero_v3(force);
+ }
if (eff->pd->flag & PFIELD_TEX_2D) {
float fac = -dot_v3v3(force, efd->nor);
@@ -1127,7 +1130,7 @@ static void debug_data_insert(SimDebugData *debug_data, SimDebugElement *elem)
BLI_ghash_insert(debug_data->gh, elem, elem);
}
-void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], float r, float g, float b, const char *category, unsigned int hash)
+void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], const char *str, float r, float g, float b, const char *category, unsigned int hash)
{
unsigned int category_hash = BLI_ghashutil_strhash_p(category);
SimDebugElement *elem;
@@ -1146,8 +1149,18 @@ void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[
elem->color[0] = r;
elem->color[1] = g;
elem->color[2] = b;
- copy_v3_v3(elem->v1, v1);
- copy_v3_v3(elem->v2, v2);
+ if (v1)
+ copy_v3_v3(elem->v1, v1);
+ else
+ zero_v3(elem->v1);
+ if (v2)
+ copy_v3_v3(elem->v2, v2);
+ else
+ zero_v3(elem->v2);
+ if (str)
+ BLI_strncpy(elem->str, str, sizeof(elem->str));
+ else
+ elem->str[0] = '\0';
debug_data_insert(_sim_debug_data, elem);
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index a89d423e7a6..c67a61a5aad 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -47,6 +47,7 @@
#include "BLI_math.h"
#include "BLI_easing.h"
#include "BLI_threads.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 21fc1674dc5..0a0b023df82 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -40,6 +40,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
// function declarations
static FreestyleLineSet *alloc_lineset(void);
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 2242113b79b..30fc8915d46 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -382,7 +383,8 @@ bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool set
sizeof(palette->info));
/* make this one the active one */
- if (setactive) {
+ /* NOTE: Always make this active if there's nothing else yet (T50123) */
+ if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) {
BKE_gpencil_palette_setactive(gpd, palette);
}
@@ -1263,7 +1265,11 @@ void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
-
+
+ /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
+ if (ELEM(NULL, gpd, oldname, newname))
+ return;
+
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (gps = gpf->strokes.first; gps; gps = gps->next) {
@@ -1282,7 +1288,11 @@ void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps, *gpsn;
-
+
+ /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
+ if (ELEM(NULL, gpd, name))
+ return;
+
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (gps = gpf->strokes.first; gps; gps = gpsn) {
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 2d5b15c8f9d..7669c4ba112 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -143,7 +143,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
if (deferred_data_size) {
- prv_img->use_deferred = true;
+ prv_img->tag |= PRV_TAG_DEFFERED;
}
for (i = 0; i < NUM_ICON_SIZES; ++i) {
@@ -355,11 +355,14 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(
return prv;
}
-void BKE_previewimg_cached_release(const char *name)
+void BKE_previewimg_cached_release_pointer(PreviewImage *prv)
{
- PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
-
if (prv) {
+ if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
+ /* We cannot delete the preview while it is being loaded in another thread... */
+ prv->tag |= PRV_TAG_DEFFERED_DELETE;
+ return;
+ }
if (prv->icon_id) {
BKE_icon_delete(prv->icon_id);
}
@@ -367,11 +370,18 @@ void BKE_previewimg_cached_release(const char *name)
}
}
+void BKE_previewimg_cached_release(const char *name)
+{
+ PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
+
+ BKE_previewimg_cached_release_pointer(prv);
+}
+
/** Handle deferred (lazy) loading/generation of preview image, if needed.
* For now, only used with file thumbnails. */
void BKE_previewimg_ensure(PreviewImage *prv, const int size)
{
- if (prv->use_deferred) {
+ if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index a4eef2f9230..a2d94ccc478 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -436,7 +436,6 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
Image *BKE_image_copy(Main *bmain, Image *ima)
{
Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type);
- ima->id.newid = &nima->id;
BLI_strncpy(nima->name, ima->name, sizeof(ima->name));
@@ -1244,7 +1243,6 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file)
case R_IMF_IMTYPE_RAWTGA:
case R_IMF_IMTYPE_IRIS:
case R_IMF_IMTYPE_PNG:
- case R_IMF_IMTYPE_RADHDR:
case R_IMF_IMTYPE_TIFF:
case R_IMF_IMTYPE_OPENEXR:
case R_IMF_IMTYPE_MULTILAYER:
@@ -1580,24 +1578,7 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i
}
/* planes */
- /* TODO(sergey): Channels doesn't correspond actual planes used for image buffer
- * For example byte buffer will have 4 channels but it might easily
- * be BW or RGB image.
- *
- * Need to use im_format->planes = imbuf->planes instead?
- */
- switch (imbuf->channels) {
- case 0:
- case 4: im_format->planes = R_IMF_PLANES_RGBA;
- break;
- case 3: im_format->planes = R_IMF_PLANES_RGB;
- break;
- case 1: im_format->planes = R_IMF_PLANES_BW;
- break;
- default: im_format->planes = R_IMF_PLANES_RGB;
- break;
- }
-
+ im_format->planes = imbuf->planes;
}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 730d5a93758..f3a85dcee2b 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -62,6 +62,7 @@
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 6cdeaf5e59b..8a7c1dd2833 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -38,6 +38,7 @@
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 14612151a8e..77013a55d18 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -73,8 +73,10 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_memarena.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -128,6 +130,8 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "atomic_ops.h"
+
/* GS reads the memory pointed at in a specific ordering.
* only use this definition, makes little and big endian systems
* work fine, in conjunction with MAKE_ID */
@@ -260,10 +264,21 @@ void id_fake_user_clear(ID *id)
}
}
+void BKE_id_clear_newpoin(ID *id)
+{
+ if (id->newid) {
+ id->newid->tag &= ~LIB_TAG_NEW;
+ }
+ id->newid = NULL;
+}
+
static int id_expand_local_callback(
- void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag))
+ void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag))
{
- if (*id_pointer) {
+ /* Can hapen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)...
+ * Just skip it, shape key can only be either indirectly linked, or fully local, period.
+ * And let's curse one more time that stupid useless shapekey ID type! */
+ if (*id_pointer && *id_pointer != id_self && BKE_idcode_is_linkable(GS((*id_pointer)->name))) {
id_lib_extern(*id_pointer);
}
@@ -320,6 +335,17 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
if (id_copy(bmain, id, &id_new, false)) {
id_new->us = 0;
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(id, id_new);
+ Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id);
+ if (key && key_new) {
+ ID_NEW_SET(key, key_new);
+ }
+ bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new);
+ if (ntree && ntree_new) {
+ ID_NEW_SET(ntree, ntree_new);
+ }
+
if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
@@ -331,6 +357,8 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
/**
* Calls the appropriate make_local method for the block, unless test is set.
*
+ * \note Always set ID->newid pointer in case it gets duplicated...
+ *
* \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.
@@ -555,6 +583,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
return false;
}
+/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@@ -565,11 +594,11 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (RNA_property_editable(ptr, prop)) {
if (id_copy(CTX_data_main(C), id, &newid, false) && newid) {
/* copy animation actions too */
- BKE_animdata_copy_id_action(id);
+ BKE_animdata_copy_id_action(id, false);
/* us is 1 by convention, but RNA_property_pointer_set
* will also increment it, so set it to zero */
newid->us = 0;
-
+
/* assign copy */
RNA_id_pointer_create(newid, &idptr);
RNA_property_pointer_set(ptr, prop, idptr);
@@ -1114,9 +1143,6 @@ void *BKE_libblock_copy(Main *bmain, ID *id)
memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
}
-
- id->newid = idn;
- idn->tag |= LIB_TAG_NEW;
BKE_libblock_copy_data(idn, id, false);
@@ -1141,8 +1167,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
}
- id->newid = idn;
- idn->tag |= LIB_TAG_NEW;
idn->us = 1;
BKE_libblock_copy_data(idn, id, do_action);
@@ -1150,31 +1174,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
return idn;
}
-static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
-{
- ID *id = *id_pointer;
- if (id) {
- /* See: NEW_ID macro */
- if (id->newid) {
- BKE_library_update_ID_link_user(id->newid, id, cd_flag);
- *id_pointer = id->newid;
- }
- else if (id->tag & LIB_TAG_NEW) {
- id->tag &= ~LIB_TAG_NEW;
- BKE_libblock_relink(id);
- }
- }
- return IDWALK_RET_NOP;
-}
-
-void BKE_libblock_relink(ID *id)
-{
- if (ID_IS_LINKED_DATABLOCK(id))
- return;
-
- BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
-}
-
void BKE_library_free(Library *lib)
{
if (lib->packedfile)
@@ -1205,46 +1204,46 @@ void BKE_main_free(Main *mainvar)
while ( (id = lb->first) ) {
#if 1
- BKE_libblock_free_ex(mainvar, id, false);
+ BKE_libblock_free_ex(mainvar, id, false, false);
#else
/* errors freeing ID's can be hard to track down,
* enable this so valgrind will give the line number in its error log */
switch (a) {
- case 0: BKE_libblock_free_ex(mainvar, id, false); break;
- case 1: BKE_libblock_free_ex(mainvar, id, false); break;
- case 2: BKE_libblock_free_ex(mainvar, id, false); break;
- case 3: BKE_libblock_free_ex(mainvar, id, false); break;
- case 4: BKE_libblock_free_ex(mainvar, id, false); break;
- case 5: BKE_libblock_free_ex(mainvar, id, false); break;
- case 6: BKE_libblock_free_ex(mainvar, id, false); break;
- case 7: BKE_libblock_free_ex(mainvar, id, false); break;
- case 8: BKE_libblock_free_ex(mainvar, id, false); break;
- case 9: BKE_libblock_free_ex(mainvar, id, false); break;
- case 10: BKE_libblock_free_ex(mainvar, id, false); break;
- case 11: BKE_libblock_free_ex(mainvar, id, false); break;
- case 12: BKE_libblock_free_ex(mainvar, id, false); break;
- case 13: BKE_libblock_free_ex(mainvar, id, false); break;
- case 14: BKE_libblock_free_ex(mainvar, id, false); break;
- case 15: BKE_libblock_free_ex(mainvar, id, false); break;
- case 16: BKE_libblock_free_ex(mainvar, id, false); break;
- case 17: BKE_libblock_free_ex(mainvar, id, false); break;
- case 18: BKE_libblock_free_ex(mainvar, id, false); break;
- case 19: BKE_libblock_free_ex(mainvar, id, false); break;
- case 20: BKE_libblock_free_ex(mainvar, id, false); break;
- case 21: BKE_libblock_free_ex(mainvar, id, false); break;
- case 22: BKE_libblock_free_ex(mainvar, id, false); break;
- case 23: BKE_libblock_free_ex(mainvar, id, false); break;
- case 24: BKE_libblock_free_ex(mainvar, id, false); break;
- case 25: BKE_libblock_free_ex(mainvar, id, false); break;
- case 26: BKE_libblock_free_ex(mainvar, id, false); break;
- case 27: BKE_libblock_free_ex(mainvar, id, false); break;
- case 28: BKE_libblock_free_ex(mainvar, id, false); break;
- case 29: BKE_libblock_free_ex(mainvar, id, false); break;
- case 30: BKE_libblock_free_ex(mainvar, id, false); break;
- case 31: BKE_libblock_free_ex(mainvar, id, false); break;
- case 32: BKE_libblock_free_ex(mainvar, id, false); break;
- case 33: BKE_libblock_free_ex(mainvar, id, false); break;
- case 34: BKE_libblock_free_ex(mainvar, id, false); break;
+ case 0: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 1: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 2: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 3: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 4: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 5: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 6: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 7: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 8: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 9: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 10: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 11: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 12: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 13: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 14: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 15: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 16: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 17: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 18: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 19: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 20: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 21: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 22: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 23: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 24: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 25: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 26: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 27: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 28: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 29: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 30: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 31: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 32: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 33: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 34: BKE_libblock_free_ex(mainvar, id, false, false); break;
default:
BLI_assert(0);
break;
@@ -1409,7 +1408,8 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
static bool check_for_dupid(ListBase *lb, ID *id, char *name)
{
ID *idtest;
- int nr = 0, a, left_len;
+ int nr = 0, a;
+ size_t left_len;
#define MAX_IN_USE 64
bool in_use[MAX_IN_USE];
/* to speed up finding unused numbers within [1 .. MAX_IN_USE - 1] */
@@ -1433,14 +1433,18 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
/* if new name will be too long, truncate it */
if (nr > 999 && left_len > (MAX_ID_NAME - 8)) { /* assumption: won't go beyond 9999 */
- left[MAX_ID_NAME - 8] = 0;
+ left[MAX_ID_NAME - 8] = '\0';
left_len = MAX_ID_NAME - 8;
}
else if (left_len > (MAX_ID_NAME - 7)) {
- left[MAX_ID_NAME - 7] = 0;
+ left[MAX_ID_NAME - 7] = '\0';
left_len = MAX_ID_NAME - 7;
}
+ /* Code above may have generated invalid utf-8 string, due to raw truncation.
+ * Ensure we get a valid one now! */
+ left_len -= (size_t)BLI_utf8_invalid_strip(left, left_len);
+
for (idtest = lb->first; idtest; idtest = idtest->next) {
int nrtest;
if ( (id != idtest) &&
@@ -1481,7 +1485,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
* shave off the end chars until we have a unique name.
* Check the null terminators match as well so we don't get Cube.000 -> Cube.00 */
if (nr == 0 && name[left_len] == '\0') {
- int len;
+ size_t len;
/* FIXME: this code will never be executed, because either nr will be
* at least 1, or name will not end at left_len! */
BLI_assert(0);
@@ -1626,30 +1630,28 @@ void BKE_main_id_clear_newpoins(Main *bmain)
* \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
+/* Note: 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
+ * Current version uses regular id_make_local callback, which 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).
+ * However, we now have a first check that allows us to use 'direct localization' of a lot of IDs, so performances
+ * are now *reasonably* OK.
*/
-void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake)
+void BKE_library_make_local(
+ Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
- ID *id, *id_next;
+ ID *id;
int a;
+ LinkNode *todo_ids = NULL;
LinkNode *copied_ids = NULL;
LinkNode *linked_loop_candidates = NULL;
- MemArena *linklist_mem = BLI_memarena_new(256 * sizeof(copied_ids), __func__);
+ MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__);
+ /* Step 1: Detect datablocks to make local. */
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
id = lbarray[a]->first;
@@ -1657,54 +1659,79 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
* by real datablocks responsible of them. */
const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
- for (; id; id = id_next) {
- id->newid = NULL;
+ for (; id; id = id->next) {
id->tag &= ~LIB_TAG_DOIT;
- id_next = id->next; /* id is possibly being inserted again */
- /* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
+ if (id->lib == NULL) {
+ id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+ }
+ /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its
* possible to tag data you don't want to be made local, used for
* appending data, so any libdata already linked wont become local
- * (very nasty to discover all your links are lost after appending)
- * */
- if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
- ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
+ * (very nasty to discover all your links are lost after appending).
+ * Also, never ever make proxified objects local, would not make any sense. */
+ else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
+ ELEM(lib, NULL, id->lib) &&
+ !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) &&
+ ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
{
- if (lib == NULL || id->lib == lib) {
- if (id->lib) {
- /* In this specific case, we do want to make ID local even if it has no local usage yet... */
- if (GS(id->name) == ID_OB) {
- /* Special case for objects because we don't want proxy pointers to be
- * cleared yet. This will happen down the road in this function.
- */
- BKE_object_make_local_ex(bmain, (Object*)id, true, false);
- }
- else {
- id_make_local(bmain, id, false, true);
- }
-
- if (id->newid) {
- BLI_linklist_prepend_arena(&copied_ids, id, linklist_mem);
- }
- }
- else {
- id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
- }
- }
+ BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
+ id->tag |= LIB_TAG_DOIT;
+ }
+ }
+ }
- if (set_fake) {
- if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
- /* do not set fake user on objects, groups (instancing) */
- id_fake_user_set(id);
- }
- }
+ /* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future,
+ * local data), others will need to be duplicated and further processed later. */
+ BKE_library_indirectly_used_data_tag_clear(bmain);
+
+ /* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
+ * which involves more complex checks and might instead create a local copy of original linked ID. */
+ for (LinkNode *it = todo_ids, *it_next; it; it = it_next) {
+ it_next = it->next;
+ id = it->link;
+
+ if (id->tag & LIB_TAG_DOIT) {
+ /* We know all users of this object are local or will be made fully local, even if currently there are
+ * some indirect usages. So instead of making a copy that se'll likely get rid of later, directly make
+ * that data block local. Saves a tremendous amount of time with complex scenes... */
+ id_clear_lib_data_ex(bmain, id, true);
+ BKE_id_expand_local(id);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ /* In this specific case, we do want to make ID local even if it has no local usage yet... */
+ if (GS(id->name) == ID_OB) {
+ /* Special case for objects because we don't want proxy pointers to be
+ * cleared yet. This will happen down the road in this function.
+ */
+ BKE_object_make_local_ex(bmain, (Object*)id, true, false);
+ }
+ else {
+ id_make_local(bmain, id, false, true);
+ }
+
+ if (id->newid) {
+ /* Reuse already allocated LinkNode (transferring it from todo_ids to copied_ids). */
+ BLI_linklist_prepend_nlink(&copied_ids, id, it);
+ }
+ }
+
+ if (set_fake) {
+ if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
+ /* do not set fake user on objects, groups (instancing) */
+ id_fake_user_set(id);
}
}
}
- /* 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. */
+ /* At this point, we are done with directly made local IDs. Now we have to handle duplicated ones, since their
+ * remaining linked original counterpart may not be needed anymore... */
+ todo_ids = NULL;
+
+ /* Step 4: We have to remap local usages of old (linked) ID to new (local) id in a separated 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 (LinkNode *it = copied_ids; it; it = it->next) {
id = it->link;
@@ -1712,9 +1739,18 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
BLI_assert(id->lib != NULL);
BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
+ if (old_to_new_ids) {
+ BLI_ghash_insert(old_to_new_ids, id, id->newid);
+ }
+
+ /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
+ * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
+ if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id_us_ensure_real(id->newid);
+ }
}
- /* Third step: remove datablocks that have been copied to be localized and are no more used in the end...
+ /* Step 5: 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) {
@@ -1761,11 +1797,6 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
}
}
- /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
- * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
- else if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
- id_us_ensure_real(id->newid);
- }
if (!is_local) {
if (!is_lib) { /* Not used at all, we can free it! */
@@ -1773,7 +1804,8 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
it->link = NULL;
do_loop = true;
}
- else { /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */
+ /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */
+ else if ((id->tag & LIB_TAG_DOIT) == 0) { /* Check TAG_DOIT to avoid adding same ID several times... */
/* Note that we store the node, not directly ID pointer, that way if it->link is set to NULL
* later we can skip it in lib-dependency cycles search later. */
BLI_linklist_prepend_arena(&linked_loop_candidates, it, linklist_mem);
@@ -1791,9 +1823,9 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
}
}
- /* Fourth step: Try to find circle dependencies between indirectly-linked-only datablocks.
+ /* Step 6: Try to find circle dependencies between indirectly-linked-only datablocks.
* Those are fake 'usages' that prevent their deletion. See T49775 for nice ugly case. */
- BKE_library_tag_unused_linked_data(bmain, false);
+ BKE_library_unused_linked_data_set_tag(bmain, false);
for (LinkNode *it = linked_loop_candidates; it; it = it->next) {
if (it->link == NULL) {
continue;
@@ -1806,20 +1838,28 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
/* Note: in theory here we are only handling datablocks forming exclusive linked dependency-cycles-based
* archipelagos, so no need to check again after we have deleted one, as done in previous step. */
if (id->tag & LIB_TAG_DOIT) {
+ /* Object's deletion rely on valid ob->data, but ob->data may have already been freed here...
+ * Setting it to NULL may not be 100% correct, but should be safe and do the work. */
+ if (GS(id->name) == ID_OB) {
+ ((Object *)id)->data = NULL;
+ }
+
/* Note: *in theory* IDs tagged here are fully *outside* of file scope, totally unused, so we can
* directly wipe them out without caring about clearing their usages.
* However, this is a highly-risky presumption, and nice crasher in case something goes wrong here.
* So for 2.78a will keep the safe option, and switch to more efficient one in master later. */
-#if 0
- BKE_libblock_free_ex(bmain, id, false);
+#if 1
+ BKE_libblock_free_ex(bmain, id, false, true);
#else
BKE_libblock_unlink(bmain, id, false, false);
BKE_libblock_free(bmain, id);
#endif
+ ((LinkNode *)it->link)->link = NULL; /* Not strictly necessary, but safer (see T49903)... */
it->link = NULL;
}
}
+ BKE_main_id_clear_newpoins(bmain);
BLI_memarena_free(linklist_mem);
}
@@ -1888,3 +1928,13 @@ void BKE_library_filepath_set(Library *lib, const char *filepath)
BLI_path_abs(lib->filepath, basepath);
}
}
+
+void BKE_id_tag_set_atomic(ID *id, int tag)
+{
+ atomic_fetch_and_or_uint32((uint32_t *)&id->tag, tag);
+}
+
+void BKE_id_tag_clear_atomic(ID *id, int tag)
+{
+ atomic_fetch_and_and_uint32((uint32_t *)&id->tag, ~tag);
+}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index cec7fbacd80..fa75c906fb1 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -1170,8 +1170,9 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
*is_used_linked = (iter.count_indirect != 0);
}
-
-static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
+/* ***** IDs usages.checking/tagging. ***** */
+static int foreach_libblock_used_linked_data_tag_clear_cb(
+ void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
{
bool *is_changed = user_data;
@@ -1206,7 +1207,7 @@ static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID
* \param do_init_tag if \a true, all linked data are checked, if \a false, only linked datablocks already tagged with
* LIB_TAG_DOIT are checked.
*/
-void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag)
+void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
{
ListBase *lb_array[MAX_LIBARRAY];
@@ -1232,7 +1233,38 @@ void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag)
while (i--) {
for (ID *id = lb_array[i]->first; id; id = id->next) {
- BKE_library_foreach_ID_link(id, foreach_libblock_tag_unused_linked_data_callback, &do_loop, IDWALK_NOP);
+ if (id->tag & LIB_TAG_DOIT) {
+ /* Unused ID (so far), no need to check it further. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
+ }
+ }
+ }
+}
+
+/**
+ * Untag linked data blocks used by other untagged linked datablocks.
+ * Used to detect datablocks that we can forcefully make local (instead of copying them to later get rid of original):
+ * All datablocks we want to make local are tagged by caller, after this function has ran caller knows datablocks still
+ * tagged can directly be made local, since they are only used by other datablocks that will also be made fully local.
+ */
+void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
+{
+ ListBase *lb_array[MAX_LIBARRAY];
+
+ bool do_loop = true;
+ while (do_loop) {
+ int i = set_listbasepointers(bmain, lb_array);
+ do_loop = false;
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ if (id->lib == NULL || id->tag & LIB_TAG_DOIT) {
+ /* Local or non-indirectly-used ID (so far), no need to check it further. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP);
}
}
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index b468e6436c8..d7d566a9ec0 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -378,6 +378,18 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), O
}
}
+static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
+{
+ /* Verify all nodetree user nodes. */
+ ntreeVerifyNodes(bmain, new_id);
+
+ /* Update node trees as necessary. */
+ FOREACH_NODETREE(bmain, ntree, id) {
+ /* make an update call for the tree */
+ ntreeUpdateTree(bmain, ntree);
+ } FOREACH_NODETREE_END
+}
+
/**
* Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
*
@@ -510,8 +522,7 @@ void BKE_libblock_remap_locked(
* been incremented for that, we have to decrease once more its user count... unless we had to skip
* some 'user_one' cases. */
if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
- id_us_min(old_id);
- old_id->tag &= ~LIB_TAG_EXTRAUSER_SET;
+ id_us_clear_real(old_id);
}
BLI_assert(old_id->us - skipped_refcounted >= 0);
@@ -552,6 +563,14 @@ void BKE_libblock_remap_locked(
break;
}
+ /* Node trees may virtually use any kind of data-block... */
+ /* XXX Yuck!!!! nodetree update can do pretty much any thing when talking about py nodes,
+ * including creating new data-blocks (see T50385), so we need to unlock main here. :(
+ * Why can't we have re-entrent locks? */
+ BKE_main_unlock(bmain);
+ libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
+ BKE_main_lock(bmain);
+
/* Full rebuild of DAG! */
DAG_relations_tag_update(bmain);
}
@@ -666,46 +685,52 @@ void BKE_libblock_relink_ex(
}
}
-static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
+static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
{
- ChannelDriver *driver;
- FCurve *fcu;
-
- /* find the driver this belongs to and update it */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- driver = fcu->driver;
-
- if (driver) {
- DriverVar *dvar;
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id == userdata)
- dtar->id = NULL;
- }
- DRIVER_TARGETS_LOOPER_END
- }
+ ID *id = *id_pointer;
+ if (id) {
+ /* See: NEW_ID macro */
+ if (id->newid) {
+ BKE_library_update_ID_link_user(id->newid, id, cd_flag);
+ *id_pointer = id->newid;
+ }
+ else if (id->tag & LIB_TAG_NEW) {
+ id->tag &= ~LIB_TAG_NEW;
+ BKE_libblock_relink_to_newid(id);
}
}
+ return IDWALK_RET_NOP;
}
-void BKE_libblock_free_data(Main *bmain, ID *id)
+/** Similar to libblock_relink_ex, but is remapping IDs to their newid value if non-NULL, in given \a id.
+ *
+ * Very specific usage, not sure we'll keep it on the long run, currently only used in Object duplication code...
+ */
+void BKE_libblock_relink_to_newid(ID *id)
+{
+ if (ID_IS_LINKED_DATABLOCK(id))
+ return;
+
+ BKE_library_foreach_ID_link(id, id_relink_to_newid_looper, NULL, 0);
+}
+
+void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id)
{
if (id->properties) {
IDP_FreeProperty(id->properties);
MEM_freeN(id->properties);
}
-
- /* this ID may be a driver target! */
- BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
}
/**
* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
*
* \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
+ * (only applies to main database)
+ * \param do_ui_user: similar to do_id_user but makes sure UI does not hold references to
+ * \a id.
*/
-void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
+void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user)
{
ID *id = idv;
short type = GS(id->name);
@@ -830,12 +855,14 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
/* avoid notifying on removed data */
BKE_main_lock(bmain);
- if (free_notifier_reference_cb) {
- free_notifier_reference_cb(id);
- }
+ if (do_ui_user) {
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(id);
+ }
- if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(id, NULL);
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(id, NULL);
+ }
}
BLI_remlink(lb, id);
@@ -848,7 +875,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
void BKE_libblock_free(Main *bmain, void *idv)
{
- BKE_libblock_free_ex(bmain, idv, true);
+ BKE_libblock_free_ex(bmain, idv, true, true);
}
void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
@@ -861,9 +888,10 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
* Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
* removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
* fully unlinked.
+ * But only for local objects, not linked ones!
* Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
*/
- if ((GS(id->name) == ID_OB) && (id->us == 1)) {
+ if ((GS(id->name) == ID_OB) && (id->us == 1) && (id->lib == NULL)) {
id_us_clear_real(id);
}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index bd21215f91e..1eb909bd9f9 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -41,6 +41,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 21023d9f53c..6f23b82c6df 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -36,8 +36,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 8d024ea9aa5..97033a9555d 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -49,6 +49,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 2068854421f..5c0b09f0ff0 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -41,8 +41,8 @@
#include "DNA_scene_types.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_memarena.h"
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 446aef9be65..af02e02b017 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -2346,6 +2346,11 @@ Mesh *BKE_mesh_new_from_object(
tmpmesh = BKE_mesh_add(bmain, "Mesh");
DM_to_mesh(dm, tmpmesh, ob, mask, true);
+
+ /* Copy autosmooth settings from original mesh. */
+ Mesh *me = (Mesh *)ob->data;
+ tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
+ tmpmesh->smoothresh = me->smoothresh;
}
/* BKE_mesh_add/copy gives us a user count we don't need */
@@ -2389,7 +2394,7 @@ Mesh *BKE_mesh_new_from_object(
/* are we an object material or data based? */
tmpmesh->mat[i] = give_current_material(ob, i + 1);
- if (((ob->matbits[i] && ob->matbits) || do_mat_id_data_us) && tmpmesh->mat[i]) {
+ if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
id_us_plus(&tmpmesh->mat[i]->id);
}
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index fa113ef5eef..f9eba118383 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -58,6 +58,7 @@
#include "BLI_strict_flags.h"
+#include "atomic_ops.h"
#include "mikktspace.h"
// #define DEBUG_TIME
@@ -236,7 +237,9 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx)
const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
/* accumulate */
- madd_v3_v3fl(vnors[ml[i].v], pnor, fac);
+ for (int k = 3; k--; ) {
+ atomic_add_and_fetch_fl(&vnors[ml[i].v][k], pnor[k] * fac);
+ }
prev_edge = cur_edge;
}
}
@@ -1906,19 +1909,19 @@ void BKE_mesh_calc_poly_center(
const MVert *mvarray, float r_cent[3])
{
if (mpoly->totloop == 3) {
- cent_tri_v3(r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co
- );
+ mid_v3_v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co
+ );
}
else if (mpoly->totloop == 4) {
- cent_quad_v3(r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co,
- mvarray[loopstart[3].v].co
- );
+ mid_v3_v3v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co
+ );
}
else {
mesh_calc_ngon_center(mpoly, loopstart, mvarray, r_cent);
@@ -1975,7 +1978,7 @@ static float mesh_calc_poly_planar_area_centroid(
tri_area = area_tri_signed_v3(v1, v2, v3, normal);
total_area += tri_area;
- cent_tri_v3(tri_cent, v1, v2, v3);
+ mid_v3_v3v3v3(tri_cent, v1, v2, v3);
madd_v3_v3fl(r_cent, tri_cent, tri_area);
copy_v3_v3(v2, v3);
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 41e4c21d814..2276d56b9c6 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -49,10 +49,11 @@
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
+#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index c321bc92a71..148fc3827e0 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -40,9 +40,9 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_ghash.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index e34e2c29089..772c8b629c0 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -46,10 +46,11 @@
#include "DNA_world_types.h"
#include "DNA_linestyle_types.h"
-#include "BLI_string.h"
-#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -736,11 +737,14 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
node_socket_free(ntree, sock, node);
MEM_freeN(sock);
}
+ BLI_listbase_clear(&node->inputs);
+
for (sock = node->outputs.first; sock; sock = sock_next) {
sock_next = sock->next;
node_socket_free(ntree, sock, node);
MEM_freeN(sock);
}
+ BLI_listbase_clear(&node->outputs);
node->update |= NODE_UPDATE;
}
@@ -1304,33 +1308,6 @@ bNodeTree *ntreeCopyTree(Main *bmain, bNodeTree *ntree)
return ntreeCopyTree_ex(ntree, bmain, true);
}
-/* use when duplicating scenes */
-void ntreeSwitchID_ex(bNodeTree *ntree, ID *id_from, ID *id_to, const bool do_id_user)
-{
- bNode *node;
-
- if (id_from == id_to) {
- /* should never happen but may as well skip if it does */
- return;
- }
-
- /* for scene duplication only */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id == id_from) {
- if (do_id_user) {
- id_us_min(id_from);
- id_us_plus(id_to);
- }
-
- node->id = id_to;
- }
- }
-}
-void ntreeSwitchID(bNodeTree *ntree, ID *id_from, ID *id_to)
-{
- ntreeSwitchID_ex(ntree, id_from, id_to, true);
-}
-
void ntreeUserIncrefID(bNodeTree *ntree)
{
bNode *node;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 5bcf31ba45b..e93bfcdda83 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -246,6 +246,10 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
mti = modifierType_getInfo(modifier_type);
+ /* only geometry objects should be able to get modifiers [#25291] */
+ if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ return false;
+ }
if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
return false;
@@ -1215,6 +1219,9 @@ void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, con
ob_new->id.us = 0;
ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(ob, ob_new);
+
if (!lib_local) {
BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
@@ -1347,7 +1354,10 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
ob->type = target->type;
ob->data = target->data;
id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */
-
+
+ /* copy vertex groups */
+ defgroup_copy_list(&ob->defbase, &target->defbase);
+
/* copy material and index information */
ob->actcol = ob->totcol = 0;
if (ob->mat) MEM_freeN(ob->mat);
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index b5f63588423..ccf2aec5c7a 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_string_utils.h"
#include "DNA_armature_types.h"
#include "DNA_cloth_types.h"
@@ -408,8 +409,9 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
/**
* Remove all vgroups from object. Work in Object and Edit modes.
+ * When only_unlocked=true, locked vertex groups are not removed.
*/
-void BKE_object_defgroup_remove_all(Object *ob)
+void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
{
bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
@@ -418,10 +420,12 @@ void BKE_object_defgroup_remove_all(Object *ob)
while (dg) {
bDeformGroup *next_dg = dg->next;
- if (edit_mode)
- object_defgroup_remove_edit_mode(ob, dg);
- else
- object_defgroup_remove_object_mode(ob, dg);
+ if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) {
+ if (edit_mode)
+ object_defgroup_remove_edit_mode(ob, dg);
+ else
+ object_defgroup_remove_object_mode(ob, dg);
+ }
dg = next_dg;
}
@@ -446,6 +450,15 @@ void BKE_object_defgroup_remove_all(Object *ob)
}
/**
+ * Remove all vgroups from object. Work in Object and Edit modes.
+ */
+void BKE_object_defgroup_remove_all(struct Object *ob)
+{
+ BKE_object_defgroup_remove_all_ex(ob, false);
+}
+
+
+/**
* Get MDeformVert vgroup data from given object. Should only be used in Object mode.
*
* \return True if the id type supports weights.
@@ -611,7 +624,7 @@ void BKE_object_defgroup_mirror_selection(
if (dg_selection[i]) {
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, defgroup->name, false);
+ BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
i_mirr = STREQ(name_flip, defgroup->name) ? i : defgroup_name_index(ob, name_flip);
if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) {
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 14cc5ec0849..e3b801b3193 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -642,8 +642,7 @@ static void make_duplis_font(const DupliContext *ctx)
float rmat[4][4];
zero_v3(obmat[3]);
- unit_m4(rmat);
- rotate_m4(rmat, 'Z', -ct->rot);
+ axis_angle_to_mat4_single(rmat, 'Z', -ct->rot);
mul_m4_m4m4(obmat, obmat, rmat);
}
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index ec5f73f87ce..842de869291 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -136,7 +136,7 @@ static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const
*
* The "density" parameter b is defined by the shape parameter
* and goes up to the Golden Spiral for 1.0
- * http://en.wikipedia.org/wiki/Golden_spiral
+ * https://en.wikipedia.org/wiki/Golden_spiral
*/
const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f;
/* angle of the spiral against the curve (rotated opposite to make a smooth transition) */
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index efaf1f9df2b..ee435051151 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -2180,7 +2180,7 @@ static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, f
* The algorithm is roughly:
* 1. Use a BVH tree to search for faces that a particle may collide with.
* 2. Use Newton's method to find the exact time at which the collision occurs.
- * http://en.wikipedia.org/wiki/Newton's_method
+ * https://en.wikipedia.org/wiki/Newton's_method
*
************************************************/
#define COLLISION_MIN_RADIUS 0.001f
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index ff69f381b06..4fe4d6e75a6 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -977,7 +977,7 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n)
* Not exact equivalent though, since atomicity is only ensured for one component
* of the vector at a time, but here it shall not make any sensible difference. */
for (int k = 3; k--; ) {
- atomic_add_fl(&vnors[v][k], fn[k]);
+ atomic_add_and_fetch_fl(&vnors[v][k], fn[k]);
}
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 55f9f384081..a821578db1a 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -148,8 +148,7 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
*
* Its assumed that \a l_radial_first is never forming the target face.
*/
-static bool bm_face_exists_tri_from_loop_vert(
- BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing)
+static BMFace *bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert *v_opposite)
{
BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
if (l_radial_first->radial_next != l_radial_first) {
@@ -157,12 +156,11 @@ static bool bm_face_exists_tri_from_loop_vert(
do {
BLI_assert(l_radial_iter->f->len == 3);
if (l_radial_iter->prev->v == v_opposite) {
- *r_face_existing = l_radial_iter->f;
- return true;
+ return l_radial_iter->f;
}
} while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
}
- return false;
+ return NULL;
}
/**
@@ -519,7 +517,7 @@ static BMFace *pbvh_bmesh_face_create(
PBVHNode *node = &bvh->nodes[node_index];
/* ensure we never add existing face */
- BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
+ BLI_assert(!BM_face_exists(v_tri, 3));
BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
@@ -1313,18 +1311,17 @@ static void pbvh_bmesh_collapse_edge(
* deletion as well. Prevents extraneous "flaps" from being
* created. */
#if 0
- if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face)))
+ if (UNLIKELY(existing_face = BM_face_exists(v_tri, 3)))
#else
- if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face)))
+ if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn)))
#endif
{
- BLI_assert(existing_face);
BLI_buffer_append(deleted_faces, BMFace *, existing_face);
}
else {
BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v};
- BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
+ BLI_assert(!BM_face_exists(v_tri, 3));
BMEdge *e_tri[3];
PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
int ni = n - bvh->nodes;
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index c3ae5736aa9..b5f34a29ebb 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -46,6 +46,7 @@
# include "RBI_api.h"
#endif
+#include "DNA_ID.h"
#include "DNA_group_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -65,13 +66,22 @@
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
-#ifdef WITH_BULLET
-
/* ************************************** */
/* Memory Management */
/* Freeing Methods --------------------- */
+#ifndef WITH_BULLET
+
+static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) {}
+static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) {}
+static void RB_dworld_delete(void *UNUSED(world)) {}
+static void RB_body_delete(void *UNUSED(body)) {}
+static void RB_shape_delete(void *UNUSED(shape)) {}
+static void RB_constraint_delete(void *UNUSED(con)) {}
+
+#endif
+
/* Free rigidbody world */
void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
{
@@ -165,6 +175,8 @@ void BKE_rigidbody_free_constraint(Object *ob)
ob->rigidbody_constraint = NULL;
}
+#ifdef WITH_BULLET
+
/* Copying Methods --------------------- */
/* These just copy the data, clearing out references to physics objects.
@@ -211,13 +223,6 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob)
return rbcN;
}
-/* preserve relationships between constraints and rigid bodies after duplication */
-void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc)
-{
- ID_NEW(rbc->ob1);
- ID_NEW(rbc->ob2);
-}
-
/* ************************************** */
/* Setup Utilities - Validate Sim Instances */
@@ -804,6 +809,18 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z);
RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z);
+ RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X);
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x);
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x);
+
+ RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y);
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y);
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y);
+
+ RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z);
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z);
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
+
RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint);
/* fall-through */
case RBC_TYPE_6DOF:
@@ -950,12 +967,9 @@ RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw)
void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw)
{
- if (rbw->group && rbw->group->id.newid)
- rbw->group = (Group *)rbw->group->id.newid;
- if (rbw->constraints && rbw->constraints->id.newid)
- rbw->constraints = (Group *)rbw->constraints->id.newid;
- if (rbw->effector_weights->group && rbw->effector_weights->group->id.newid)
- rbw->effector_weights->group = (Group *)rbw->effector_weights->group->id.newid;
+ ID_NEW_REMAP(rbw->group);
+ ID_NEW_REMAP(rbw->constraints);
+ ID_NEW_REMAP(rbw->effector_weights->group);
}
void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata)
@@ -1072,9 +1086,15 @@ RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short ty
rbc->spring_damping_x = 0.5f;
rbc->spring_damping_y = 0.5f;
rbc->spring_damping_z = 0.5f;
+ rbc->spring_damping_ang_x = 0.5f;
+ rbc->spring_damping_ang_y = 0.5f;
+ rbc->spring_damping_ang_z = 0.5f;
rbc->spring_stiffness_x = 10.0f;
rbc->spring_stiffness_y = 10.0f;
rbc->spring_stiffness_z = 10.0f;
+ rbc->spring_stiffness_ang_x = 10.0f;
+ rbc->spring_stiffness_ang_y = 10.0f;
+ rbc->spring_stiffness_ang_z = 10.0f;
rbc->motor_lin_max_impulse = 1.0f;
rbc->motor_lin_target_velocity = 1.0f;
@@ -1602,12 +1622,8 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
-void BKE_rigidbody_free_world(RigidBodyWorld *rbw) {}
-void BKE_rigidbody_free_object(Object *ob) {}
-void BKE_rigidbody_free_constraint(Object *ob) {}
struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; }
struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; }
-void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {}
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {}
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; }
void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3(r_center); }
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index c7f406089d9..fa221348932 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -602,41 +602,41 @@ void set_sca_new_poins_ob(Object *ob)
if (act->flag & ACT_NEW) {
if (act->type==ACT_EDIT_OBJECT) {
bEditObjectActuator *eoa= act->data;
- ID_NEW(eoa->ob);
+ ID_NEW_REMAP(eoa->ob);
}
else if (act->type==ACT_SCENE) {
bSceneActuator *sca= act->data;
- ID_NEW(sca->camera);
+ ID_NEW_REMAP(sca->camera);
}
else if (act->type==ACT_CAMERA) {
bCameraActuator *ca= act->data;
- ID_NEW(ca->ob);
+ ID_NEW_REMAP(ca->ob);
}
else if (act->type==ACT_OBJECT) {
bObjectActuator *oa= act->data;
- ID_NEW(oa->reference);
+ ID_NEW_REMAP(oa->reference);
}
else if (act->type==ACT_MESSAGE) {
bMessageActuator *ma= act->data;
- ID_NEW(ma->toObject);
+ ID_NEW_REMAP(ma->toObject);
}
else if (act->type==ACT_PARENT) {
bParentActuator *para = act->data;
- ID_NEW(para->ob);
+ ID_NEW_REMAP(para->ob);
}
else if (act->type==ACT_ARMATURE) {
bArmatureActuator *aa = act->data;
- ID_NEW(aa->target);
- ID_NEW(aa->subtarget);
+ ID_NEW_REMAP(aa->target);
+ ID_NEW_REMAP(aa->subtarget);
}
else if (act->type==ACT_PROPERTY) {
bPropertyActuator *pa= act->data;
- ID_NEW(pa->ob);
+ ID_NEW_REMAP(pa->ob);
}
else if (act->type==ACT_STEERING) {
bSteeringActuator *sta = act->data;
- ID_NEW(sta->navmesh);
- ID_NEW(sta->target);
+ ID_NEW_REMAP(sta->navmesh);
+ ID_NEW_REMAP(sta->target);
}
}
act= act->next;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 6e1f11cb526..69d3b4db54c 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -56,6 +56,7 @@
#include "BLI_utildefines.h"
#include "BLI_callbacks.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLI_task.h"
@@ -78,6 +79,7 @@
#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_mask.h"
@@ -186,8 +188,6 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
scen = BKE_libblock_copy(bmain, &sce->id);
BLI_duplicatelist(&(scen->base), &(sce->base));
- BKE_main_id_clear_newpoins(bmain);
-
id_us_plus((ID *)scen->world);
id_us_plus((ID *)scen->set);
/* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */
@@ -211,7 +211,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (sce->nodetree) {
/* ID's are managed on both copy and switch */
scen->nodetree = ntreeCopyTree(bmain, sce->nodetree);
- ntreeSwitchID(scen->nodetree, &sce->id, &scen->id);
+ BKE_libblock_relink_ex(bmain, scen->nodetree, &sce->id, &scen->id, false);
}
obase = sce->base.first;
@@ -225,7 +225,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
}
/* copy action and remove animation used by sequencer */
- BKE_animdata_copy_id_action(&scen->id);
+ BKE_animdata_copy_id_action(&scen->id, false);
if (type != SCE_COPY_FULL)
remove_sequencer_fcurves(scen);
@@ -287,13 +287,16 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
ts->imapaint.paintcursor = NULL;
id_us_plus((ID *)ts->imapaint.stencil);
ts->particle.paintcursor = NULL;
+
/* duplicate Grease Pencil Drawing Brushes */
BLI_listbase_clear(&ts->gp_brushes);
for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
BLI_addtail(&ts->gp_brushes, newbrush);
}
-
+
+ /* duplicate Grease Pencil interpolation curve */
+ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
}
/* make a private copy of the avicodecdata */
@@ -318,7 +321,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* camera */
if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) {
- ID_NEW(scen->camera);
+ ID_NEW_REMAP(scen->camera);
}
/* before scene copy */
@@ -329,7 +332,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (scen->world) {
id_us_plus((ID *)scen->world);
scen->world = BKE_world_copy(bmain, scen->world);
- BKE_animdata_copy_id_action((ID *)scen->world);
+ BKE_animdata_copy_id_action((ID *)scen->world, false);
}
if (sce->ed) {
@@ -440,12 +443,17 @@ void BKE_scene_free(Scene *sce)
BKE_paint_free(&sce->toolsettings->uvsculpt->paint);
MEM_freeN(sce->toolsettings->uvsculpt);
}
+ BKE_paint_free(&sce->toolsettings->imapaint.paint);
+
/* free Grease Pencil Drawing Brushes */
BKE_gpencil_free_brushes(&sce->toolsettings->gp_brushes);
BLI_freelistN(&sce->toolsettings->gp_brushes);
-
- BKE_paint_free(&sce->toolsettings->imapaint.paint);
-
+
+ /* free Grease Pencil interpolation curve */
+ if (sce->toolsettings->gp_interpolate.custom_ipo) {
+ curvemapping_free(sce->toolsettings->gp_interpolate.custom_ipo);
+ }
+
MEM_freeN(sce->toolsettings);
sce->toolsettings = NULL;
}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index ce7c520438a..298671beedb 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -1074,29 +1074,31 @@ static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f
static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi)
{
- int height, width, temp, fac, fac1, fac2;
+ int temp, fac, fac1, fac2;
unsigned char *rt1, *rt2, *out;
int field = 1;
- width = x;
- height = y;
+ const int width = x;
+ const int height = y;
+ const int xoff = min_ii(XOFF, width);
+ const int yoff = min_ii(YOFF, height);
fac1 = (int) (70.0f * facf0);
fac2 = (int) (70.0f * facf1);
- rt2 = (unsigned char *) (rect2i + YOFF * width);
- rt1 = (unsigned char *) rect1i;
- out = (unsigned char *) outi;
- for (y = 0; y < height - YOFF; y++) {
+ rt2 = rect2i + yoff * 4 * width;
+ rt1 = rect1i;
+ out = outi;
+ for (y = 0; y < height - yoff; y++) {
if (field) fac = fac1;
else fac = fac2;
field = !field;
- memcpy(out, rt1, sizeof(int) * XOFF);
- rt1 += XOFF * 4;
- out += XOFF * 4;
+ memcpy(out, rt1, sizeof(*out) * xoff * 4);
+ rt1 += xoff * 4;
+ out += xoff * 4;
- for (x = XOFF; x < width; x++) {
+ for (x = xoff; x < width; x++) {
temp = ((fac * rt2[3]) >> 8);
*(out++) = MAX2(0, *rt1 - temp); rt1++;
@@ -1105,37 +1107,38 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned
*(out++) = MAX2(0, *rt1 - temp); rt1++;
rt2 += 4;
}
- rt2 += XOFF * 4;
+ rt2 += xoff * 4;
}
- memcpy(out, rt1, sizeof(int) * YOFF * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
}
static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi)
{
- int height, width;
float temp, fac, fac1, fac2;
float *rt1, *rt2, *out;
int field = 1;
- width = x;
- height = y;
+ const int width = x;
+ const int height = y;
+ const int xoff = min_ii(XOFF, width);
+ const int yoff = min_ii(YOFF, height);
fac1 = 70.0f * facf0;
fac2 = 70.0f * facf1;
- rt2 = (rect2i + YOFF * width);
+ rt2 = rect2i + yoff * 4 * width;
rt1 = rect1i;
out = outi;
- for (y = 0; y < height - YOFF; y++) {
+ for (y = 0; y < height - yoff; y++) {
if (field) fac = fac1;
else fac = fac2;
field = !field;
- memcpy(out, rt1, 4 * sizeof(float) * XOFF);
- rt1 += XOFF * 4;
- out += XOFF * 4;
+ memcpy(out, rt1, sizeof(*out) * xoff * 4);
+ rt1 += xoff * 4;
+ out += xoff * 4;
- for (x = XOFF; x < width; x++) {
+ for (x = xoff; x < width; x++) {
temp = fac * rt2[3];
*(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
@@ -1144,9 +1147,9 @@ static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *
*(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
rt2 += 4;
}
- rt2 += XOFF * 4;
+ rt2 += xoff * 4;
}
- memcpy(out, rt1, 4 * sizeof(float) * YOFF * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
}
/*********************** Mul *************************/
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index 95c6b7736e1..89c2f76c661 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -34,8 +34,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 65d751a8a72..1d2f5aee440 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -320,7 +320,8 @@ void BKE_sequencer_free_clipboard(void)
/* Manage pointers in the clipboard.
* note that these pointers should _never_ be access in the sequencer,
* they are only for storage while in the clipboard
- * notice 'newid' is used for temp pointer storage here, validate on access.
+ * notice 'newid' is used for temp pointer storage here, validate on access (this is safe usage,
+ * since those datablocks are fully out of Main lists).
*/
#define ID_PT (*id_pt)
static void seqclipboard_ptr_free(ID **id_pt)
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 05540f51588..d0ef5cfc092 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -360,6 +360,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
smd->domain->point_cache[0] = NULL;
+ if (smd->domain->coba) {
+ MEM_freeN(smd->domain->coba);
+ }
+
MEM_freeN(smd->domain);
smd->domain = NULL;
}
@@ -544,6 +548,9 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->slice_depth = 0.5f;
smd->domain->slice_axis = 0;
smd->domain->vector_scale = 1.0f;
+
+ smd->domain->coba = NULL;
+ smd->domain->coba_field = FLUID_FIELD_DENSITY;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@@ -646,6 +653,10 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
tsmd->domain->draw_velocity = smd->domain->draw_velocity;
tsmd->domain->vector_draw_type = smd->domain->vector_draw_type;
tsmd->domain->vector_scale = smd->domain->vector_scale;
+
+ if (smd->domain->coba) {
+ tsmd->domain->coba = MEM_dupallocN(smd->domain->coba);
+ }
}
else if (tsmd->flow) {
tsmd->flow->psys = smd->flow->psys;
@@ -747,15 +758,14 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
/* find the nearest point on the mesh */
if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) {
const MLoopTri *lt = &data->looptri[nearest.index];
- float weights[4];
+ float weights[3];
int v1, v2, v3;
/* calculate barycentric weights for nearest point */
v1 = data->mloop[lt->tri[0]].v;
v2 = data->mloop[lt->tri[1]].v;
v3 = data->mloop[lt->tri[2]].v;
- interp_weights_face_v3(
- weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, NULL, nearest.co);
+ interp_weights_tri_v3(weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
// DG TODO
if (data->has_velocity)
@@ -1443,7 +1453,7 @@ static void sample_derivedmesh(
/* find the nearest point on the mesh */
if (BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
- float weights[4];
+ float weights[3];
int v1, v2, v3, f_index = nearest.index;
float n1[3], n2[3], n3[3], hit_normal[3];
@@ -1460,7 +1470,7 @@ static void sample_derivedmesh(
v1 = mloop[mlooptri[f_index].tri[0]].v;
v2 = mloop[mlooptri[f_index].tri[1]].v;
v3 = mloop[mlooptri[f_index].tri[2]].v;
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co);
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
/* apply normal directional velocity */
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 3132a8e27e7..22288127119 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -167,6 +167,10 @@ static const char *force_device = NULL;
#ifdef WITH_JACK
static void sound_sync_callback(void *data, int mode, float time)
{
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return;
+
struct Main *bmain = (struct Main *)data;
struct Scene *scene;
@@ -251,7 +255,8 @@ void BKE_sound_init(struct Main *bmain)
void BKE_sound_init_main(struct Main *bmain)
{
#ifdef WITH_JACK
- AUD_setSynchronizerCallback(sound_sync_callback, bmain);
+ if (sound_device)
+ AUD_setSynchronizerCallback(sound_sync_callback, bmain);
#else
(void)bmain; /* unused */
#endif
@@ -449,6 +454,16 @@ void BKE_sound_destroy_scene(struct Scene *scene)
AUD_destroySet(scene->speaker_handles);
}
+void BKE_sound_reset_scene_specs(struct Scene *scene)
+{
+ AUD_Specs specs;
+
+ specs.channels = AUD_Device_getChannels(sound_device);
+ specs.rate = AUD_Device_getRate(sound_device);
+
+ AUD_Sequence_setSpecs(scene->sound_scene, specs);
+}
+
void BKE_sound_mute_scene(struct Scene *scene, int muted)
{
if (scene->sound_scene)
@@ -575,15 +590,10 @@ void BKE_sound_update_sequencer(struct Main *main, bSound *sound)
static void sound_start_play_scene(struct Scene *scene)
{
- AUD_Specs specs;
-
if (scene->playback_handle)
AUD_Handle_stop(scene->playback_handle);
- specs.channels = AUD_Device_getChannels(sound_device);
- specs.rate = AUD_Device_getRate(sound_device);
-
- AUD_Sequence_setSpecs(scene->sound_scene, specs);
+ BKE_sound_reset_scene_specs(scene);
if ((scene->playback_handle = AUD_Device_play(sound_device, scene->sound_scene, 1)))
AUD_Handle_setLoopCount(scene->playback_handle, -1);
@@ -692,6 +702,10 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
float BKE_sound_sync_scene(struct Scene *scene)
{
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return NAN_FLT;
+
if (scene->playback_handle) {
if (scene->audio.flag & AUDIO_SYNC)
return AUD_getSynchronizerPosition(scene->playback_handle);
@@ -703,6 +717,10 @@ float BKE_sound_sync_scene(struct Scene *scene)
int BKE_sound_scene_playing(struct Scene *scene)
{
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return -1;
+
if (scene->audio.flag & AUDIO_SYNC)
return AUD_isSynchronizerPlaying();
else
@@ -897,6 +915,7 @@ void BKE_sound_delete_cache(struct bSound *UNUSED(sound)) {}
void BKE_sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {}
void BKE_sound_create_scene(struct Scene *UNUSED(scene)) {}
void BKE_sound_destroy_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_reset_scene_specs(struct Scene *UNUSED(scene)) {}
void BKE_sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {}
void *BKE_sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence),
int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 6d57c5f09e8..c4665c40ec4 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -4474,46 +4474,46 @@ static void ccgDM_recalcTessellation(DerivedMesh *UNUSED(dm))
/* Nothing to do: CCG handles creating its own tessfaces */
}
-static void ccgDM_recalcLoopTri(DerivedMesh *UNUSED(dm))
+static void ccgDM_recalcLoopTri(DerivedMesh *dm)
{
- /* Nothing to do: CCG tessellation is known,
- * allocate and fill in with ccgDM_getLoopTriArray */
+ BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE);
+ MLoopTri *mlooptri;
+ const int tottri = dm->numPolyData * 2;
+ int i, poly_index;
+
+ DM_ensure_looptri_data(dm);
+ mlooptri = dm->looptris.array;
+
+ BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
+ BLI_assert(tottri == dm->looptris.num);
+
+ for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) {
+ MLoopTri *lt;
+ lt = &mlooptri[i];
+ /* quad is (0, 3, 2, 1) */
+ lt->tri[0] = (poly_index * 4) + 0;
+ lt->tri[1] = (poly_index * 4) + 2;
+ lt->tri[2] = (poly_index * 4) + 3;
+ lt->poly = poly_index;
+
+ lt = &mlooptri[i + 1];
+ lt->tri[0] = (poly_index * 4) + 0;
+ lt->tri[1] = (poly_index * 4) + 1;
+ lt->tri[2] = (poly_index * 4) + 2;
+ lt->poly = poly_index;
+ }
+ BLI_rw_mutex_unlock(&loops_cache_rwlock);
}
static const MLoopTri *ccgDM_getLoopTriArray(DerivedMesh *dm)
{
- BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE);
if (dm->looptris.array) {
BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
}
else {
- MLoopTri *mlooptri;
- const int tottri = dm->numPolyData * 2;
- int i, poly_index;
-
- DM_ensure_looptri_data(dm);
- mlooptri = dm->looptris.array;
-
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- BLI_assert(tottri == dm->looptris.num);
-
- for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) {
- MLoopTri *lt;
- lt = &mlooptri[i];
- /* quad is (0, 3, 2, 1) */
- lt->tri[0] = (poly_index * 4) + 0;
- lt->tri[1] = (poly_index * 4) + 2;
- lt->tri[2] = (poly_index * 4) + 3;
- lt->poly = poly_index;
-
- lt = &mlooptri[i + 1];
- lt->tri[0] = (poly_index * 4) + 0;
- lt->tri[1] = (poly_index * 4) + 1;
- lt->tri[2] = (poly_index * 4) + 2;
- lt->poly = poly_index;
- }
+ dm->recalcLoopTri(dm);
}
- BLI_rw_mutex_unlock(&loops_cache_rwlock);
+
return dm->looptris.array;
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 1636042f479..88575c7d3be 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -235,8 +235,9 @@ Text *BKE_text_add(Main *bmain, const char *name)
/* to a valid utf-8 sequences */
int txt_extended_ascii_as_utf8(char **str)
{
- int bad_char, added = 0, i = 0;
- int length = strlen(*str);
+ ptrdiff_t bad_char, i = 0;
+ const ptrdiff_t length = (ptrdiff_t)strlen(*str);
+ int added = 0;
while ((*str)[i]) {
if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1)
@@ -248,7 +249,7 @@ int txt_extended_ascii_as_utf8(char **str)
if (added != 0) {
char *newstr = MEM_mallocN(length + added + 1, "text_line");
- int mi = 0;
+ ptrdiff_t mi = 0;
i = 0;
while ((*str)[i]) {
@@ -410,6 +411,7 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
}
ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs));
+ ta->id.us = 0;
BLI_listbase_clear(&ta->lines);
ta->curl = ta->sell = NULL;
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index a86606f1099..990d250b854 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -44,12 +44,13 @@
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
+#include "BLI_bitmap_draw_2d.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_math_base.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -997,9 +998,10 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height
point[1] = (stroke_points[i].y - marker->search_min[1]) * frame_height;
}
/* TODO: add an option to control whether AA is enabled or not */
- fill_poly_v2i_n(0, 0, mask_width, mask_height,
- (const int (*)[2])mask_points, stroke->totpoints,
- track_mask_set_pixel_cb, &data);
+ BLI_bitmap_draw_2d_poly_v2i_n(
+ 0, 0, mask_width, mask_height,
+ (const int (*)[2])mask_points, stroke->totpoints,
+ track_mask_set_pixel_cb, &data);
MEM_freeN(mask_points);
}
stroke = stroke->next;
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index b8949f9a0de..36b24fbb2dc 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -587,7 +587,7 @@ static void compensate_rotation_center(const int size, float aspect,
copy_v2_v2(intended_pivot, pivot);
copy_v2_v2(rotated_pivot, pivot);
- rotate_m2(rotation_mat, +angle);
+ angle_to_mat2(rotation_mat, +angle);
sub_v2_v2(rotated_pivot, origin);
mul_m2v2(rotation_mat, rotated_pivot);
mul_v2_fl(rotated_pivot, scale);
@@ -967,7 +967,7 @@ static void initialize_track_for_stabilization(StabContext *ctx,
pos[0] *= aspect;
angle = average_angle - atan2f(pos[1],pos[0]);
- rotate_m2(local_data->stabilization_rotation_base, angle);
+ angle_to_mat2(local_data->stabilization_rotation_base, angle);
/* Per track baseline value for zoom. */
len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS;
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index a90b1dee927..1c056cda68d 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -42,8 +42,8 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_ghash.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -625,17 +625,17 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
*/
size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float);
grayscale->channels = 1;
- if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) {
+ if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
grayscale->mall |= IB_rectfloat;
grayscale->flags |= IB_rectfloat;
- }
- for (i = 0; i < grayscale->x * grayscale->y; ++i) {
- const float *pixel = ibuf->rect_float + ibuf->channels * i;
+ for (i = 0; i < grayscale->x * grayscale->y; ++i) {
+ const float *pixel = ibuf->rect_float + ibuf->channels * i;
- grayscale->rect_float[i] = 0.2126f * pixel[0] +
- 0.7152f * pixel[1] +
- 0.0722f * pixel[2];
+ grayscale->rect_float[i] = 0.2126f * pixel[0] +
+ 0.7152f * pixel[1] +
+ 0.0722f * pixel[2];
+ }
}
return grayscale;
@@ -653,14 +653,14 @@ static void ibuf_to_float_image(const ImBuf *ibuf, libmv_FloatImage *float_image
static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image)
{
ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
- size_t size = (size_t)ibuf->x * (size_t)ibuf->y *
- float_image->channels * sizeof(float);
+ size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float);
ibuf->channels = float_image->channels;
- if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) {
+ if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
ibuf->mall |= IB_rectfloat;
ibuf->flags |= IB_rectfloat;
+
+ memcpy(ibuf->rect_float, float_image->buffer, size);
}
- memcpy(ibuf->rect_float, float_image->buffer, size);
return ibuf;
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index b0ab6f707fa..9994d479ce7 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -444,7 +444,7 @@ static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDi
param = strchr(name, ':');
if (param) {
- *param++ = 0;
+ *param++ = '\0';
}
switch (prop->type) {
@@ -1114,7 +1114,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData
BLI_make_existing_file(string);
- autosplit[0] = 0;
+ autosplit[0] = '\0';
if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
if (context) {
@@ -1137,7 +1137,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData
strcat(string, *exts);
}
else {
- *(string + strlen(string) - strlen(*fe)) = 0;
+ *(string + strlen(string) - strlen(*fe)) = '\0';
strcat(string, autosplit);
strcat(string, *fe);
}
@@ -1267,7 +1267,7 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
if (is_autosplit == false) {
if (context->audio_mixdown_device) {
AUD_Device_free(context->audio_mixdown_device);
- context->audio_mixdown_device = 0;
+ context->audio_mixdown_device = NULL;
}
}
#endif
@@ -1283,50 +1283,50 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
/* Close the video codec */
- if (context->video_stream && context->video_stream->codec) {
+ if (context->video_stream != NULL && context->video_stream->codec != NULL) {
avcodec_close(context->video_stream->codec);
PRINT("zero video stream %p\n", context->video_stream);
- context->video_stream = 0;
+ context->video_stream = NULL;
}
- if (context->audio_stream && context->audio_stream->codec) {
+ if (context->audio_stream != NULL && context->audio_stream->codec != NULL) {
avcodec_close(context->audio_stream->codec);
- context->audio_stream = 0;
+ context->audio_stream = NULL;
}
/* free the temp buffer */
- if (context->current_frame) {
+ if (context->current_frame != NULL) {
delete_picture(context->current_frame);
- context->current_frame = 0;
+ context->current_frame = NULL;
}
- if (context->outfile && context->outfile->oformat) {
+ if (context->outfile != NULL && context->outfile->oformat) {
if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) {
avio_close(context->outfile->pb);
}
}
- if (context->outfile) {
+ if (context->outfile != NULL) {
avformat_free_context(context->outfile);
- context->outfile = 0;
+ context->outfile = NULL;
}
- if (context->audio_input_buffer) {
+ if (context->audio_input_buffer != NULL) {
av_free(context->audio_input_buffer);
- context->audio_input_buffer = 0;
+ context->audio_input_buffer = NULL;
}
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (context->audio_output_buffer) {
+ if (context->audio_output_buffer != NULL) {
av_free(context->audio_output_buffer);
- context->audio_output_buffer = 0;
+ context->audio_output_buffer = NULL;
}
#endif
- if (context->audio_deinterleave_buffer) {
+ if (context->audio_deinterleave_buffer != NULL) {
av_free(context->audio_deinterleave_buffer);
- context->audio_deinterleave_buffer = 0;
+ context->audio_deinterleave_buffer = NULL;
}
- if (context->img_convert_ctx) {
+ if (context->img_convert_ctx != NULL) {
sws_freeContext(context->img_convert_ctx);
- context->img_convert_ctx = 0;
+ context->img_convert_ctx = NULL;
}
}
@@ -1425,8 +1425,8 @@ static IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, con
int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char *str)
{
AVCodecContext c;
- const AVOption *o = 0;
- const AVOption *p = 0;
+ const AVOption *o = NULL;
+ const AVOption *p = NULL;
char name_[128];
char *name;
char *param;
@@ -1445,7 +1445,7 @@ int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char
param = strchr(name, ' ');
}
if (param) {
- *param++ = 0;
+ *param++ = '\0';
while (*param == ' ') param++;
}