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:
authorSergey Sharybin <sergey.vfx@gmail.com>2015-06-08 15:20:07 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2015-06-08 15:20:07 +0300
commitf1cd1e650354dd9096cd35914234441047cc393b (patch)
tree0c0ec8c9d269a8485eba3e8e46c5116c9a0f17d9 /source/blender/blenkernel/intern
parent8b9d1818a57f538ec1c629ce94871351601ffa4c (diff)
parent303c91209311cade10edf1678900e2d1ba812ffb (diff)
Merge branch 'master' into cycles_memory_experiments
Conflicts: intern/cycles/blender/blender_object.cpp intern/cycles/blender/blender_sync.h intern/cycles/render/graph.h intern/cycles/render/mesh.cpp
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c57
-rw-r--r--source/blender/blenkernel/intern/action.c11
-rw-r--r--source/blender/blenkernel/intern/addon.c6
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c67
-rw-r--r--source/blender/blenkernel/intern/appdir.c172
-rw-r--r--source/blender/blenkernel/intern/armature.c538
-rw-r--r--source/blender/blenkernel/intern/armature_update.c697
-rw-r--r--source/blender/blenkernel/intern/blender.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c17
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c2
-rw-r--r--source/blender/blenkernel/intern/colortools.c6
-rw-r--r--source/blender/blenkernel/intern/curve.c109
-rw-r--r--source/blender/blenkernel/intern/customdata.c4
-rw-r--r--source/blender/blenkernel/intern/deform.c8
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c405
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c15
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c48
-rw-r--r--source/blender/blenkernel/intern/effect.c2
-rw-r--r--source/blender/blenkernel/intern/fcurve.c7
-rw-r--r--source/blender/blenkernel/intern/icons.c343
-rw-r--r--source/blender/blenkernel/intern/image.c205
-rw-r--r--source/blender/blenkernel/intern/key.c28
-rw-r--r--source/blender/blenkernel/intern/lamp.c2
-rw-r--r--source/blender/blenkernel/intern/lattice.c8
-rw-r--r--source/blender/blenkernel/intern/library.c41
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c3
-rw-r--r--source/blender/blenkernel/intern/material.c38
-rw-r--r--source/blender/blenkernel/intern/mball.c6
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c9
-rw-r--r--source/blender/blenkernel/intern/mesh.c66
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c15
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c45
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c97
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c5
-rw-r--r--source/blender/blenkernel/intern/movieclip.c8
-rw-r--r--source/blender/blenkernel/intern/multires.c48
-rw-r--r--source/blender/blenkernel/intern/node.c20
-rw-r--r--source/blender/blenkernel/intern/object.c424
-rw-r--r--source/blender/blenkernel/intern/object_deform.c4
-rw-r--r--source/blender/blenkernel/intern/object_update.c348
-rw-r--r--source/blender/blenkernel/intern/ocean.c4
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c22
-rw-r--r--source/blender/blenkernel/intern/packedFile.c22
-rw-r--r--source/blender/blenkernel/intern/paint.c11
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c22
-rw-r--r--source/blender/blenkernel/intern/particle_system.c37
-rw-r--r--source/blender/blenkernel/intern/pbvh.c16
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c401
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h8
-rw-r--r--source/blender/blenkernel/intern/pointcache.c4
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c50
-rw-r--r--source/blender/blenkernel/intern/scene.c222
-rw-r--r--source/blender/blenkernel/intern/screen.c47
-rw-r--r--source/blender/blenkernel/intern/sequencer.c20
-rw-r--r--source/blender/blenkernel/intern/smoke.c2
-rw-r--r--source/blender/blenkernel/intern/softbody.c46
-rw-r--r--source/blender/blenkernel/intern/sound.c75
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c79
-rw-r--r--source/blender/blenkernel/intern/text.c172
-rw-r--r--source/blender/blenkernel/intern/texture.c6
-rw-r--r--source/blender/blenkernel/intern/tracking.c95
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c16
-rw-r--r--source/blender/blenkernel/intern/unit.c7
-rw-r--r--source/blender/blenkernel/intern/world.c2
64 files changed, 3796 insertions, 1526 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 38ae0461c84..d850dd3ee26 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -295,11 +295,11 @@ void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
dm->dirty = 0;
/* don't use CustomData_reset(...); because we dont want to touch customdata */
- fill_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
}
void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
@@ -1276,7 +1276,7 @@ static void calc_weightpaint_vert_array(Object *ob, DerivedMesh *dm, int const d
else {
weightpaint_color(col, dm_wcinfo, 0.0f);
}
- fill_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
+ copy_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
}
}
@@ -2292,13 +2292,8 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
}
static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
- int build_shapekey_layers)
+ int build_shapekey_layers, int needMapping)
{
- Object *obact = scene->basact ? scene->basact->object : NULL;
- bool editing = BKE_paint_select_face_test(ob);
- /* weight paint and face select need original indices because of selection buffer drawing */
- int needMapping = (ob == obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)));
-
BLI_assert(ob->type == OB_MESH);
BKE_object_free_derived_caches(ob);
@@ -2313,6 +2308,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
ob->derivedFinal->needsFree = 0;
ob->derivedDeform->needsFree = 0;
ob->lastDataMask = dataMask;
+ ob->lastNeedMapping = needMapping;
if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) {
/* create PBVH immediately (would be created on the fly too,
@@ -2341,14 +2337,23 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C
BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS));
}
-static CustomDataMask object_get_datamask(const Scene *scene, Object *ob)
+static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, int *r_needmapping)
{
Object *actob = scene->basact ? scene->basact->object : NULL;
CustomDataMask mask = ob->customdata_mask;
+ bool editing = BKE_paint_select_face_test(ob);
+
+ if (r_needmapping)
+ *r_needmapping = 0;
if (ob == actob) {
+
+ /* weight paint and face select need original indices because of selection buffer drawing */
+ if (r_needmapping)
+ *r_needmapping = (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT)));
+
/* check if we need tfaces & mcols due to face select or texture paint */
- if ((ob->mode & OB_MODE_TEXTURE_PAINT) || BKE_paint_select_face_test(ob)) {
+ if ((ob->mode & OB_MODE_TEXTURE_PAINT) || editing) {
mask |= CD_MASK_MTFACE | CD_MASK_MCOL;
}
@@ -2371,13 +2376,14 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob)
void makeDerivedMesh(Scene *scene, Object *ob, BMEditMesh *em,
CustomDataMask dataMask, int build_shapekey_layers)
{
- dataMask |= object_get_datamask(scene, ob);
+ int needMapping;
+ dataMask |= object_get_datamask(scene, ob, &needMapping);
if (em) {
editbmesh_build_data(scene, ob, em, dataMask);
}
else {
- mesh_build_data(scene, ob, dataMask, build_shapekey_layers);
+ mesh_build_data(scene, ob, dataMask, build_shapekey_layers, needMapping);
}
}
@@ -2388,10 +2394,11 @@ DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dat
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, ob);
+ int needMapping;
+ dataMask |= object_get_datamask(scene, ob, &needMapping);
- if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask)
- mesh_build_data(scene, ob, dataMask, 0);
+ if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask || (needMapping != ob->lastNeedMapping))
+ mesh_build_data(scene, ob, dataMask, 0, needMapping);
if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); }
return ob->derivedFinal;
@@ -2402,10 +2409,12 @@ DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask da
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, ob);
+ int needmapping;
+
+ dataMask |= object_get_datamask(scene, ob, &needmapping);
- if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask)
- mesh_build_data(scene, ob, dataMask, 0);
+ if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask || (needmapping != ob->lastNeedMapping))
+ mesh_build_data(scene, ob, dataMask, 0, needmapping);
return ob->derivedDeform;
}
@@ -2494,7 +2503,7 @@ DerivedMesh *editbmesh_get_derived_cage_and_final(Scene *scene, Object *obedit,
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit);
+ dataMask |= object_get_datamask(scene, obedit, NULL);
if (!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
@@ -2512,7 +2521,7 @@ DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit);
+ dataMask |= object_get_datamask(scene, obedit, NULL);
if (!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 9ce198bd687..7e09ad355a7 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -54,6 +54,7 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -1317,6 +1318,16 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
return true;
}
+/* Tag pose for recalc. Also tag all related data to be recalc. */
+void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
+{
+ pose->flag |= POSE_RECALC;
+ /* Depsgraph components depends on actual pose state,
+ * if pose was changed depsgraph is to be updated as well.
+ */
+ DAG_relations_tag_update(bmain);
+}
+
/* For the calculation of the effects of an Action at the given frame on an object
* This is currently only used for the Action Constraint
*/
diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c
index 28667d458b8..811461b84c1 100644
--- a/source/blender/blenkernel/intern/addon.c
+++ b/source/blender/blenkernel/intern/addon.c
@@ -62,12 +62,12 @@ bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet)
void BKE_addon_pref_type_add(bAddonPrefType *apt)
{
- BLI_ghash_insert(global_addonpreftype_hash, (void *)apt->idname, apt);
+ BLI_ghash_insert(global_addonpreftype_hash, apt->idname, apt);
}
-void BKE_addon_pref_type_remove(bAddonPrefType *apt)
+void BKE_addon_pref_type_remove(const bAddonPrefType *apt)
{
- BLI_ghash_remove(global_addonpreftype_hash, (void *)apt->idname, NULL, MEM_freeN);
+ BLI_ghash_remove(global_addonpreftype_hash, apt->idname, NULL, MEM_freeN);
}
void BKE_addon_pref_type_init(void)
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 3c98d11dbdb..d5a8b8f857c 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1620,7 +1620,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind
}
/* Simple replacement based data-setting of the FCurve using RNA */
-static bool animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
+bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
{
char *path = NULL;
bool free_path = false;
@@ -1655,7 +1655,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
calculate_fcurve(fcu, ctime);
- animsys_execute_fcurve(ptr, remap, fcu);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu);
}
}
}
@@ -1685,7 +1685,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
calculate_fcurve(fcu, ctime);
- ok = animsys_execute_fcurve(ptr, NULL, fcu);
+ ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu);
/* clear recalc flag */
driver->flag &= ~DRIVER_FLAG_RECALC;
@@ -1754,7 +1754,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
calculate_fcurve(fcu, ctime);
- animsys_execute_fcurve(ptr, remap, fcu);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu);
}
}
}
@@ -2846,3 +2846,62 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
}
/* ***************************************** */
+
+/* ************** */
+/* Evaluation API */
+
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+
+void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates,
+ * which should get handled as part of the graph instead...
+ */
+ DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime);
+ BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM);
+}
+
+void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
+ ID *id,
+ FCurve *fcu)
+{
+ /* TODO(sergey): De-duplicate with BKE animsys. */
+ ChannelDriver *driver = fcu->driver;
+ PointerRNA id_ptr;
+ bool ok = false;
+
+ DEBUG_PRINT("%s on %s (%s[%d])\n",
+ __func__,
+ id->name,
+ fcu->rna_path,
+ fcu->array_index);
+
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* check if this driver's curve should be skipped */
+ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
+ /* check if driver itself is tagged for recalculation */
+ /* XXX driver recalc flag is not set yet by depsgraph! */
+ if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID) /*&& (driver->flag & DRIVER_FLAG_RECALC)*/) {
+ /* evaluate this using values set already in other places
+ * NOTE: for 'layering' option later on, we should check if we should remove old value before adding
+ * new to only be done when drivers only changed */
+ //printf("\told val = %f\n", fcu->curval);
+ calculate_fcurve(fcu, eval_ctx->ctime);
+ ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu);
+ //printf("\tnew val = %f\n", fcu->curval);
+
+ /* clear recalc flag */
+ driver->flag &= ~DRIVER_FLAG_RECALC;
+
+ /* set error-flag if evaluation failed */
+ if (ok == 0) {
+ printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index);
+ driver->flag |= DRIVER_FLAG_INVALID;
+ }
+ }
+ }
+}
+
+#undef DEBUG_PRINT
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 60e81003c40..b1b32e75f59 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -501,54 +501,6 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
/* Preset paths */
/**
- * Tries appending each of the semicolon-separated extensions in the PATHEXT
- * environment variable (Windows-only) onto *name in turn until such a file is found.
- * Returns success/failure.
- */
-static int add_win32_extension(char *name)
-{
- int retval = 0;
- int type;
-
- type = BLI_exists(name);
- if ((type == 0) || S_ISDIR(type)) {
-#ifdef _WIN32
- char filename[FILE_MAX];
- char ext[FILE_MAX];
- const char *extensions = getenv("PATHEXT");
- if (extensions) {
- char *temp;
- do {
- strcpy(filename, name);
- temp = strstr(extensions, ";");
- if (temp) {
- strncpy(ext, extensions, temp - extensions);
- ext[temp - extensions] = 0;
- extensions = temp + 1;
- strcat(filename, ext);
- }
- else {
- strcat(filename, extensions);
- }
-
- type = BLI_exists(filename);
- if (type && (!S_ISDIR(type))) {
- retval = 1;
- strcpy(name, filename);
- break;
- }
- } while (temp);
- }
-#endif
- }
- else {
- retval = 1;
- }
-
- return (retval);
-}
-
-/**
* Checks if name is a fully qualified filename to an executable.
* If not it searches $PATH for the file. On Windows it also
* adds the correct extension (.com .exe etc) from
@@ -562,39 +514,34 @@ static int add_win32_extension(char *name)
*/
static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name)
{
- char filename[FILE_MAX];
- const char *path = NULL, *temp;
-
-#ifdef _WIN32
- const char *separator = ";";
-#else
- const char *separator = ":";
-#endif
-
-
#ifdef WITH_BINRELOC
/* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
- path = br_find_exe(NULL);
- if (path) {
- BLI_strncpy(fullname, path, maxlen);
- free((void *)path);
- return;
+ {
+ const char *path = NULL;
+ path = br_find_exe(NULL);
+ if (path) {
+ BLI_strncpy(fullname, path, maxlen);
+ free((void *)path);
+ return;
+ }
}
#endif
#ifdef _WIN32
- wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
- if (GetModuleFileNameW(0, fullname_16, maxlen)) {
- conv_utf_16_to_8(fullname_16, fullname, maxlen);
- if (!BLI_exists(fullname)) {
- printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname);
- MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
+ {
+ wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
+ if (GetModuleFileNameW(0, fullname_16, maxlen)) {
+ conv_utf_16_to_8(fullname_16, fullname, maxlen);
+ if (!BLI_exists(fullname)) {
+ printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname);
+ MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
+ }
+ MEM_freeN(fullname_16);
+ return;
}
+
MEM_freeN(fullname_16);
- return;
}
-
- MEM_freeN(fullname_16);
#endif
/* unix and non linux */
@@ -611,34 +558,19 @@ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name
else
BLI_join_dirfile(fullname, maxlen, wdir, name);
- add_win32_extension(fullname); /* XXX, doesnt respect length */
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
+#endif
}
else if (BLI_last_slash(name)) {
// full path
BLI_strncpy(fullname, name, maxlen);
- add_win32_extension(fullname);
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
+#endif
}
else {
- // search for binary in $PATH
- path = getenv("PATH");
- if (path) {
- do {
- temp = strstr(path, separator);
- if (temp) {
- strncpy(filename, path, temp - path);
- filename[temp - path] = 0;
- path = temp + 1;
- }
- else {
- strncpy(filename, path, sizeof(filename));
- }
- BLI_path_append(fullname, maxlen, name);
- if (add_win32_extension(filename)) {
- BLI_strncpy(fullname, filename, maxlen);
- break;
- }
- } while (temp);
- }
+ BLI_path_program_search(fullname, maxlen, name);
}
#if defined(DEBUG)
if (!STREQ(name, fullname)) {
@@ -670,6 +602,58 @@ const char *BKE_appdir_program_dir(void)
return bprogdir;
}
+bool BKE_appdir_program_python_search(
+ char *fullpath, const size_t fullpath_len,
+ const int version_major, const int version_minor)
+{
+ const char *basename = "python";
+ char python_ver[16];
+ /* check both possible names */
+ const char *python_names[] = {basename, python_ver};
+ int i;
+
+ bool is_found = false;
+
+ BLI_snprintf(python_ver, sizeof(python_ver), "%s%d.%d", basename, version_major, version_minor);
+
+ {
+ const char *python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, "bin");
+ if (python_bin_dir) {
+
+ for (i = 0; i < ARRAY_SIZE(python_names); i++) {
+ BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]);
+
+ if (
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullpath, fullpath_len)
+#else
+ BLI_exists(fullpath)
+#endif
+ )
+ {
+ is_found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (is_found == false) {
+ for (i = 0; i < ARRAY_SIZE(python_names); i++) {
+ if (BLI_path_program_search(fullpath, fullpath_len, python_names[i])) {
+ is_found = true;
+ break;
+ }
+ }
+ }
+
+ if (is_found == false) {
+ *fullpath = '\0';
+ }
+
+ return is_found;
+}
+
/**
* Gets the temp directory when blender first runs.
* If the default path is not found, use try $TEMP
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index dc11bcb00aa..27d3d1c50fb 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1825,9 +1825,12 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */
+#ifdef WITH_LEGACY_DEPSGRAPH
/* the sorting */
+ /* Sorting for new dependnecy graph is done on the scene graph level. */
if (counter > 1)
DAG_pose_sort(ob);
+#endif
ob->pose->flag &= ~POSE_RECALC;
ob->pose->flag |= POSE_WAS_REBUILT;
@@ -1835,494 +1838,6 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
BKE_pose_channels_hash_make(ob->pose);
}
-
-/* ********************** SPLINE IK SOLVER ******************* */
-
-/* Temporary evaluation tree data used for Spline IK */
-typedef struct tSplineIK_Tree {
- struct tSplineIK_Tree *next, *prev;
-
- int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */
-
- bool free_points; /* free the point positions array */
- short chainlen; /* number of bones in the chain */
-
- float *points; /* parametric positions for the joints along the curve */
- bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */
-
- bPoseChannel *root; /* bone that is the root node of the chain */
-
- bConstraint *con; /* constraint for this chain */
- bSplineIKConstraint *ikData; /* constraint settings for this chain */
-} tSplineIK_Tree;
-
-/* ----------- */
-
-/* Tag the bones in the chain formed by the given bone for IK */
-static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip)
-{
- bPoseChannel *pchan, *pchanRoot = NULL;
- bPoseChannel *pchanChain[255];
- bConstraint *con = NULL;
- bSplineIKConstraint *ikData = NULL;
- float boneLengths[255], *jointPoints;
- float totLength = 0.0f;
- bool free_joints = 0;
- int segcount = 0;
-
- /* find the SplineIK constraint */
- for (con = pchan_tip->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
- ikData = con->data;
-
- /* target can only be curve */
- if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE))
- continue;
- /* skip if disabled */
- if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)))
- continue;
-
- /* otherwise, constraint is ok... */
- break;
- }
- }
- if (con == NULL)
- return;
-
- /* make sure that the constraint targets are ok
- * - this is a workaround for a depsgraph bug...
- */
- if (ikData->tar) {
- /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
- * currently for paths to work it needs to go through the bevlist/displist system (ton)
- */
-
- /* only happens on reload file, but violates depsgraph still... fix! */
- if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
- BKE_displist_make_curveTypes(scene, ikData->tar, 0);
-
- /* path building may fail in EditMode after removing verts [#33268]*/
- if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
- /* BLI_assert(cu->path != NULL); */
- return;
- }
- }
- }
-
- /* find the root bone and the chain of bones from the root to the tip
- * NOTE: this assumes that the bones are connected, but that may not be true... */
- for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) {
- /* store this segment in the chain */
- pchanChain[segcount] = pchan;
-
- /* if performing rebinding, calculate the length of the bone */
- boneLengths[segcount] = pchan->bone->length;
- totLength += boneLengths[segcount];
- }
-
- if (segcount == 0)
- return;
- else
- pchanRoot = pchanChain[segcount - 1];
-
- /* perform binding step if required */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
- float segmentLen = (1.0f / (float)segcount);
- int i;
-
- /* setup new empty array for the points list */
- if (ikData->points)
- MEM_freeN(ikData->points);
- ikData->numpoints = ikData->chainlen + 1;
- ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding");
-
- /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
- ikData->points[0] = 1.0f;
-
- /* perform binding of the joints to parametric positions along the curve based
- * proportion of the total length that each bone occupies
- */
- for (i = 0; i < segcount; i++) {
- /* 'head' joints, traveling towards the root of the chain
- * - 2 methods; the one chosen depends on whether we've got usable lengths
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
- /* 1) equi-spaced joints */
- ikData->points[i + 1] = ikData->points[i] - segmentLen;
- }
- else {
- /* 2) to find this point on the curve, we take a step from the previous joint
- * a distance given by the proportion that this bone takes
- */
- ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength);
- }
- }
-
- /* spline has now been bound */
- ikData->flag |= CONSTRAINT_SPLINEIK_BOUND;
- }
-
- /* disallow negative values (happens with float precision) */
- CLAMP_MIN(ikData->points[segcount], 0.0f);
-
- /* apply corrections for sensitivity to scaling on a copy of the bind points,
- * since it's easier to determine the positions of all the joints beforehand this way
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) {
- float splineLen, maxScale;
- int i;
-
- /* make a copy of the points array, that we'll store in the tree
- * - although we could just multiply the points on the fly, this approach means that
- * we can introduce per-segment stretchiness later if it is necessary
- */
- jointPoints = MEM_dupallocN(ikData->points);
- free_joints = 1;
-
- /* get the current length of the curve */
- /* NOTE: this is assumed to be correct even after the curve was resized */
- splineLen = ikData->tar->curve_cache->path->totdist;
-
- /* calculate the scale factor to multiply all the path values by so that the
- * bone chain retains its current length, such that
- * maxScale * splineLen = totLength
- */
- maxScale = totLength / splineLen;
-
- /* apply scaling correction to all of the temporary points */
- /* TODO: this is really not adequate enough on really short chains */
- for (i = 0; i < segcount; i++)
- jointPoints[i] *= maxScale;
- }
- else {
- /* just use the existing points array */
- jointPoints = ikData->points;
- free_joints = 0;
- }
-
- /* make a new Spline-IK chain, and store it in the IK chains */
- /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */
- {
- /* make new tree */
- tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
- tree->type = CONSTRAINT_TYPE_SPLINEIK;
-
- tree->chainlen = segcount;
-
- /* copy over the array of links to bones in the chain (from tip to root) */
- tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain");
- memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount);
-
- /* store reference to joint position array */
- tree->points = jointPoints;
- tree->free_points = free_joints;
-
- /* store references to different parts of the chain */
- tree->root = pchanRoot;
- tree->con = con;
- tree->ikData = ikData;
-
- /* AND! link the tree to the root */
- BLI_addtail(&pchanRoot->siktree, tree);
- }
-
- /* mark root channel having an IK tree */
- pchanRoot->flag |= POSE_IKSPLINE;
-}
-
-/* Tag which bones are members of Spline IK chains */
-static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
-{
- bPoseChannel *pchan;
-
- /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->constflag & PCHAN_HAS_SPLINEIK)
- splineik_init_tree_from_pchan(scene, ob, pchan);
- }
-}
-
-/* ----------- */
-
-/* Evaluate spline IK for a given bone */
-static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
- int index, float ctime)
-{
- bSplineIKConstraint *ikData = tree->ikData;
- float poseHead[3], poseTail[3], poseMat[4][4];
- float splineVec[3], scaleFac, radius = 1.0f;
-
- /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
-
- copy_v3_v3(poseHead, pchan->pose_head);
- copy_v3_v3(poseTail, pchan->pose_tail);
-
- /* step 1: determine the positions for the endpoints of the bone */
- {
- float vec[4], dir[3], rad;
- float tailBlendFac = 1.0f;
-
- /* determine if the bone should still be affected by SplineIK */
- if (tree->points[index + 1] >= 1.0f) {
- /* spline doesn't affect the bone anymore, so done... */
- pchan->flag |= POSE_DONE;
- return;
- }
- else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) {
- /* blending factor depends on the amount of the bone still left on the chain */
- tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]);
- }
-
- /* tail endpoint */
- if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) {
- /* apply curve's object-mode transforms to the position
- * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
- mul_m4_v3(ikData->tar->obmat, vec);
-
- /* convert the position to pose-space, then store it */
- mul_m4_v3(ob->imat, vec);
- interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac);
-
- /* set the new radius */
- radius = rad;
- }
-
- /* head endpoint */
- if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) {
- /* apply curve's object-mode transforms to the position
- * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
- mul_m4_v3(ikData->tar->obmat, vec);
-
- /* store the position, and convert it to pose space */
- mul_m4_v3(ob->imat, vec);
- copy_v3_v3(poseHead, vec);
-
- /* set the new radius (it should be the average value) */
- radius = (radius + rad) / 2;
- }
- }
-
- /* step 2: determine the implied transform from these endpoints
- * - splineVec: the vector direction that the spline applies on the bone
- * - scaleFac: the factor that the bone length is scaled by to get the desired amount
- */
- sub_v3_v3v3(splineVec, poseTail, poseHead);
- scaleFac = len_v3(splineVec) / pchan->bone->length;
-
- /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis
- * - this uses the same method as is used for the Damped Track Constraint (see the code there for details)
- */
- {
- float dmat[3][3], rmat[3][3], tmat[3][3];
- float raxis[3], rangle;
-
- /* compute the raw rotation matrix from the bone's current matrix by extracting only the
- * orientation-relevant axes, and normalizing them
- */
- copy_v3_v3(rmat[0], pchan->pose_mat[0]);
- copy_v3_v3(rmat[1], pchan->pose_mat[1]);
- copy_v3_v3(rmat[2], pchan->pose_mat[2]);
- normalize_m3(rmat);
-
- /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */
- normalize_v3(splineVec);
-
- /* calculate smallest axis-angle rotation necessary for getting from the
- * current orientation of the bone, to the spline-imposed direction
- */
- cross_v3_v3v3(raxis, rmat[1], splineVec);
-
- rangle = dot_v3v3(rmat[1], splineVec);
- CLAMP(rangle, -1.0f, 1.0f);
- rangle = acosf(rangle);
-
- /* multiply the magnitude of the angle by the influence of the constraint to
- * control the influence of the SplineIK effect
- */
- rangle *= tree->con->enforce;
-
- /* construct rotation matrix from the axis-angle rotation found above
- * - this call takes care to make sure that the axis provided is a unit vector first
- */
- axis_angle_to_mat3(dmat, raxis, rangle);
-
- /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates,
- * while still maintaining roll control from the existing bone animation
- */
- mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */
- normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */
- copy_m4_m3(poseMat, tmat);
- }
-
- /* step 4: set the scaling factors for the axes */
- {
- /* only multiply the y-axis by the scaling factor to get nice volume-preservation */
- mul_v3_fl(poseMat[1], scaleFac);
-
- /* set the scaling factors of the x and z axes from... */
- switch (ikData->xzScaleMode) {
- case CONSTRAINT_SPLINEIK_XZS_ORIGINAL:
- {
- /* original scales get used */
- float scale;
-
- /* x-axis scale */
- scale = len_v3(pchan->pose_mat[0]);
- mul_v3_fl(poseMat[0], scale);
- /* z-axis scale */
- scale = len_v3(pchan->pose_mat[2]);
- mul_v3_fl(poseMat[2], scale);
- break;
- }
- case CONSTRAINT_SPLINEIK_XZS_INVERSE:
- {
- /* old 'volume preservation' method using the inverse scale */
- float scale;
-
- /* calculate volume preservation factor which is
- * basically the inverse of the y-scaling factor
- */
- if (fabsf(scaleFac) != 0.0f) {
- scale = 1.0f / fabsf(scaleFac);
-
- /* we need to clamp this within sensible values */
- /* NOTE: these should be fine for now, but should get sanitised in future */
- CLAMP(scale, 0.0001f, 100000.0f);
- }
- else
- scale = 1.0f;
-
- /* apply the scaling */
- mul_v3_fl(poseMat[0], scale);
- mul_v3_fl(poseMat[2], scale);
- break;
- }
- case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC:
- {
- /* improved volume preservation based on the Stretch To constraint */
- float final_scale;
-
- /* as the basis for volume preservation, we use the inverse scale factor... */
- if (fabsf(scaleFac) != 0.0f) {
- /* NOTE: The method here is taken wholesale from the Stretch To constraint */
- float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge);
-
- if (bulge > 1.0f) {
- if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) {
- float bulge_max = max_ff(ikData->bulge_max, 1.0f);
- float hard = min_ff(bulge, bulge_max);
-
- float range = bulge_max - 1.0f;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, ikData->bulge_smooth);
- }
- }
- if (bulge < 1.0f) {
- if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) {
- float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f);
- float hard = max_ff(bulge, bulge_min);
-
- float range = 1.0f - bulge_min;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, ikData->bulge_smooth);
- }
- }
-
- /* compute scale factor for xz axes from this value */
- final_scale = sqrtf(bulge);
- }
- else {
- /* no scaling, so scale factor is simple */
- final_scale = 1.0f;
- }
-
- /* apply the scaling (assuming normalised scale) */
- mul_v3_fl(poseMat[0], final_scale);
- mul_v3_fl(poseMat[2], final_scale);
- break;
- }
- }
-
- /* finally, multiply the x and z scaling by the radius of the curve too,
- * to allow automatic scales to get tweaked still
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) {
- mul_v3_fl(poseMat[0], radius);
- mul_v3_fl(poseMat[2], radius);
- }
- }
-
- /* step 5: set the location of the bone in the matrix */
- if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) {
- /* when the 'no-root' option is affected, the chain can retain
- * the shape but be moved elsewhere
- */
- copy_v3_v3(poseHead, pchan->pose_head);
- }
- else if (tree->con->enforce < 1.0f) {
- /* when the influence is too low
- * - blend the positions for the 'root' bone
- * - stick to the parent for any other
- */
- if (pchan->parent) {
- copy_v3_v3(poseHead, pchan->pose_head);
- }
- else {
- /* FIXME: this introduces popping artifacts when we reach 0.0 */
- interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce);
- }
- }
- copy_v3_v3(poseMat[3], poseHead);
-
- /* finally, store the new transform */
- copy_m4_m4(pchan->pose_mat, poseMat);
- copy_v3_v3(pchan->pose_head, poseHead);
-
- /* recalculate tail, as it's now outdated after the head gets adjusted above! */
- BKE_pose_where_is_bone_tail(pchan);
-
- /* done! */
- pchan->flag |= POSE_DONE;
-}
-
-/* Evaluate the chain starting from the nominated bone */
-static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
-{
- tSplineIK_Tree *tree;
-
- /* for each pose-tree, execute it if it is spline, otherwise just free it */
- while ((tree = pchan_root->siktree.first) != NULL) {
- int i;
-
- /* walk over each bone in the chain, calculating the effects of spline IK
- * - the chain is traversed in the opposite order to storage order (i.e. parent to children)
- * so that dependencies are correct
- */
- for (i = tree->chainlen - 1; i >= 0; i--) {
- bPoseChannel *pchan = tree->chain[i];
- splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime);
- }
-
- /* free the tree info specific to SplineIK trees now */
- if (tree->chain)
- MEM_freeN(tree->chain);
- if (tree->free_points)
- MEM_freeN(tree->points);
-
- /* free this tree */
- BLI_freelinkN(&pchan_root->siktree, tree);
- }
-}
-
/* ********************** THE POSE SOLVER ******************* */
/* loc/rot/size to given mat4 */
@@ -2623,7 +2138,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
* - this is not integrated as an IK plugin, since it should be able
* to function in conjunction with standard IK
*/
- splineik_init_tree(scene, ob, ctime);
+ BKE_pose_splineik_init_tree(scene, ob, ctime);
/* 3. the main loop, channels are already hierarchical sorted from root to children */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -2633,7 +2148,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
}
/* 4b. if we find a Spline IK root, we handle it separated too */
else if (pchan->flag & POSE_IKSPLINE) {
- splineik_execute_tree(scene, ob, pchan, ctime);
+ BKE_splineik_execute_tree(scene, ob, pchan, ctime);
}
/* 5. otherwise just call the normal solver */
else if (!(pchan->flag & POSE_DONE)) {
@@ -2703,3 +2218,46 @@ BoundBox *BKE_armature_boundbox_get(Object *ob)
return ob->bb;
}
+
+/************** Graph evaluation ********************/
+
+bPoseChannel *BKE_armature_ik_solver_find_root(
+ bPoseChannel *pchan,
+ bKinematicConstraint *data)
+{
+ bPoseChannel *rootchan = pchan;
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ /* Exclude tip from chain. */
+ rootchan = rootchan->parent;
+ }
+ if (rootchan != NULL) {
+ int segcount = 0;
+ while (rootchan->parent) {
+ /* Continue up chain, until we reach target number of items. */
+ segcount++;
+ if (segcount == data->rootbone) {
+ break;
+ }
+ rootchan = rootchan->parent;
+ }
+ }
+ return rootchan;
+}
+
+bPoseChannel *BKE_armature_splineik_solver_find_root(
+ bPoseChannel *pchan,
+ bSplineIKConstraint *data)
+{
+ bPoseChannel *rootchan = pchan;
+ int segcount = 0;
+ BLI_assert(rootchan != NULL);
+ while (rootchan->parent) {
+ /* Continue up chain, until we reach target number of items. */
+ segcount++;
+ if (segcount == data->chainlen) {
+ break;
+ }
+ rootchan = rootchan->parent;
+ }
+ return rootchan;
+}
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
new file mode 100644
index 00000000000..ceda9f056bb
--- /dev/null
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -0,0 +1,697 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Defines and code for core node types
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_fcurve.h"
+#include "BKE_scene.h"
+
+#include "BIK_api.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
+#else
+# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+#endif
+
+/* ********************** SPLINE IK SOLVER ******************* */
+
+/* Temporary evaluation tree data used for Spline IK */
+typedef struct tSplineIK_Tree {
+ struct tSplineIK_Tree *next, *prev;
+
+ int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */
+
+ bool free_points; /* free the point positions array */
+ short chainlen; /* number of bones in the chain */
+
+ float *points; /* parametric positions for the joints along the curve */
+ bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */
+
+ bPoseChannel *root; /* bone that is the root node of the chain */
+
+ bConstraint *con; /* constraint for this chain */
+ bSplineIKConstraint *ikData; /* constraint settings for this chain */
+} tSplineIK_Tree;
+
+/* ----------- */
+
+/* Tag the bones in the chain formed by the given bone for IK */
+static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip)
+{
+ bPoseChannel *pchan, *pchanRoot = NULL;
+ bPoseChannel *pchanChain[255];
+ bConstraint *con = NULL;
+ bSplineIKConstraint *ikData = NULL;
+ float boneLengths[255], *jointPoints;
+ float totLength = 0.0f;
+ bool free_joints = 0;
+ int segcount = 0;
+
+ /* find the SplineIK constraint */
+ for (con = pchan_tip->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
+ ikData = con->data;
+
+ /* target can only be curve */
+ if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE))
+ continue;
+ /* skip if disabled */
+ if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)))
+ continue;
+
+ /* otherwise, constraint is ok... */
+ break;
+ }
+ }
+ if (con == NULL)
+ return;
+
+ /* make sure that the constraint targets are ok
+ * - this is a workaround for a depsgraph bug...
+ */
+ if (ikData->tar) {
+ /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
+ * currently for paths to work it needs to go through the bevlist/displist system (ton)
+ */
+
+ /* only happens on reload file, but violates depsgraph still... fix! */
+ if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
+ BKE_displist_make_curveTypes(scene, ikData->tar, 0);
+
+ /* path building may fail in EditMode after removing verts [#33268]*/
+ if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
+ /* BLI_assert(cu->path != NULL); */
+ return;
+ }
+ }
+ }
+
+ /* find the root bone and the chain of bones from the root to the tip
+ * NOTE: this assumes that the bones are connected, but that may not be true... */
+ for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) {
+ /* store this segment in the chain */
+ pchanChain[segcount] = pchan;
+
+ /* if performing rebinding, calculate the length of the bone */
+ boneLengths[segcount] = pchan->bone->length;
+ totLength += boneLengths[segcount];
+ }
+
+ if (segcount == 0)
+ return;
+ else
+ pchanRoot = pchanChain[segcount - 1];
+
+ /* perform binding step if required */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
+ float segmentLen = (1.0f / (float)segcount);
+ int i;
+
+ /* setup new empty array for the points list */
+ if (ikData->points)
+ MEM_freeN(ikData->points);
+ ikData->numpoints = ikData->chainlen + 1;
+ ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding");
+
+ /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
+ ikData->points[0] = 1.0f;
+
+ /* perform binding of the joints to parametric positions along the curve based
+ * proportion of the total length that each bone occupies
+ */
+ for (i = 0; i < segcount; i++) {
+ /* 'head' joints, traveling towards the root of the chain
+ * - 2 methods; the one chosen depends on whether we've got usable lengths
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
+ /* 1) equi-spaced joints */
+ ikData->points[i + 1] = ikData->points[i] - segmentLen;
+ }
+ else {
+ /* 2) to find this point on the curve, we take a step from the previous joint
+ * a distance given by the proportion that this bone takes
+ */
+ ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength);
+ }
+ }
+
+ /* spline has now been bound */
+ ikData->flag |= CONSTRAINT_SPLINEIK_BOUND;
+ }
+
+ /* disallow negative values (happens with float precision) */
+ CLAMP_MIN(ikData->points[segcount], 0.0f);
+
+ /* apply corrections for sensitivity to scaling on a copy of the bind points,
+ * since it's easier to determine the positions of all the joints beforehand this way
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) {
+ float splineLen, maxScale;
+ int i;
+
+ /* make a copy of the points array, that we'll store in the tree
+ * - although we could just multiply the points on the fly, this approach means that
+ * we can introduce per-segment stretchiness later if it is necessary
+ */
+ jointPoints = MEM_dupallocN(ikData->points);
+ free_joints = 1;
+
+ /* get the current length of the curve */
+ /* NOTE: this is assumed to be correct even after the curve was resized */
+ splineLen = ikData->tar->curve_cache->path->totdist;
+
+ /* calculate the scale factor to multiply all the path values by so that the
+ * bone chain retains its current length, such that
+ * maxScale * splineLen = totLength
+ */
+ maxScale = totLength / splineLen;
+
+ /* apply scaling correction to all of the temporary points */
+ /* TODO: this is really not adequate enough on really short chains */
+ for (i = 0; i < segcount; i++)
+ jointPoints[i] *= maxScale;
+ }
+ else {
+ /* just use the existing points array */
+ jointPoints = ikData->points;
+ free_joints = 0;
+ }
+
+ /* make a new Spline-IK chain, and store it in the IK chains */
+ /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */
+ {
+ /* make new tree */
+ tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
+ tree->type = CONSTRAINT_TYPE_SPLINEIK;
+
+ tree->chainlen = segcount;
+
+ /* copy over the array of links to bones in the chain (from tip to root) */
+ tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain");
+ memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount);
+
+ /* store reference to joint position array */
+ tree->points = jointPoints;
+ tree->free_points = free_joints;
+
+ /* store references to different parts of the chain */
+ tree->root = pchanRoot;
+ tree->con = con;
+ tree->ikData = ikData;
+
+ /* AND! link the tree to the root */
+ BLI_addtail(&pchanRoot->siktree, tree);
+ }
+
+ /* mark root channel having an IK tree */
+ pchanRoot->flag |= POSE_IKSPLINE;
+}
+
+/* Tag which bones are members of Spline IK chains */
+static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
+{
+ bPoseChannel *pchan;
+
+ /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->constflag & PCHAN_HAS_SPLINEIK)
+ splineik_init_tree_from_pchan(scene, ob, pchan);
+ }
+}
+
+/* ----------- */
+
+/* Evaluate spline IK for a given bone */
+static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
+ int index, float ctime)
+{
+ bSplineIKConstraint *ikData = tree->ikData;
+ float poseHead[3], poseTail[3], poseMat[4][4];
+ float splineVec[3], scaleFac, radius = 1.0f;
+
+ /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+
+ copy_v3_v3(poseHead, pchan->pose_head);
+ copy_v3_v3(poseTail, pchan->pose_tail);
+
+ /* step 1: determine the positions for the endpoints of the bone */
+ {
+ float vec[4], dir[3], rad;
+ float tailBlendFac = 1.0f;
+
+ /* determine if the bone should still be affected by SplineIK */
+ if (tree->points[index + 1] >= 1.0f) {
+ /* spline doesn't affect the bone anymore, so done... */
+ pchan->flag |= POSE_DONE;
+ return;
+ }
+ else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) {
+ /* blending factor depends on the amount of the bone still left on the chain */
+ tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]);
+ }
+
+ /* tail endpoint */
+ if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) {
+ /* apply curve's object-mode transforms to the position
+ * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
+ mul_m4_v3(ikData->tar->obmat, vec);
+
+ /* convert the position to pose-space, then store it */
+ mul_m4_v3(ob->imat, vec);
+ interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac);
+
+ /* set the new radius */
+ radius = rad;
+ }
+
+ /* head endpoint */
+ if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) {
+ /* apply curve's object-mode transforms to the position
+ * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
+ mul_m4_v3(ikData->tar->obmat, vec);
+
+ /* store the position, and convert it to pose space */
+ mul_m4_v3(ob->imat, vec);
+ copy_v3_v3(poseHead, vec);
+
+ /* set the new radius (it should be the average value) */
+ radius = (radius + rad) / 2;
+ }
+ }
+
+ /* step 2: determine the implied transform from these endpoints
+ * - splineVec: the vector direction that the spline applies on the bone
+ * - scaleFac: the factor that the bone length is scaled by to get the desired amount
+ */
+ sub_v3_v3v3(splineVec, poseTail, poseHead);
+ scaleFac = len_v3(splineVec) / pchan->bone->length;
+
+ /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis
+ * - this uses the same method as is used for the Damped Track Constraint (see the code there for details)
+ */
+ {
+ float dmat[3][3], rmat[3][3], tmat[3][3];
+ float raxis[3], rangle;
+
+ /* compute the raw rotation matrix from the bone's current matrix by extracting only the
+ * orientation-relevant axes, and normalizing them
+ */
+ copy_v3_v3(rmat[0], pchan->pose_mat[0]);
+ copy_v3_v3(rmat[1], pchan->pose_mat[1]);
+ copy_v3_v3(rmat[2], pchan->pose_mat[2]);
+ normalize_m3(rmat);
+
+ /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */
+ normalize_v3(splineVec);
+
+ /* calculate smallest axis-angle rotation necessary for getting from the
+ * current orientation of the bone, to the spline-imposed direction
+ */
+ cross_v3_v3v3(raxis, rmat[1], splineVec);
+
+ rangle = dot_v3v3(rmat[1], splineVec);
+ CLAMP(rangle, -1.0f, 1.0f);
+ rangle = acosf(rangle);
+
+ /* multiply the magnitude of the angle by the influence of the constraint to
+ * control the influence of the SplineIK effect
+ */
+ rangle *= tree->con->enforce;
+
+ /* construct rotation matrix from the axis-angle rotation found above
+ * - this call takes care to make sure that the axis provided is a unit vector first
+ */
+ axis_angle_to_mat3(dmat, raxis, rangle);
+
+ /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates,
+ * while still maintaining roll control from the existing bone animation
+ */
+ mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */
+ normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */
+ copy_m4_m3(poseMat, tmat);
+ }
+
+ /* step 4: set the scaling factors for the axes */
+ {
+ /* only multiply the y-axis by the scaling factor to get nice volume-preservation */
+ mul_v3_fl(poseMat[1], scaleFac);
+
+ /* set the scaling factors of the x and z axes from... */
+ switch (ikData->xzScaleMode) {
+ case CONSTRAINT_SPLINEIK_XZS_ORIGINAL:
+ {
+ /* original scales get used */
+ float scale;
+
+ /* x-axis scale */
+ scale = len_v3(pchan->pose_mat[0]);
+ mul_v3_fl(poseMat[0], scale);
+ /* z-axis scale */
+ scale = len_v3(pchan->pose_mat[2]);
+ mul_v3_fl(poseMat[2], scale);
+ break;
+ }
+ case CONSTRAINT_SPLINEIK_XZS_INVERSE:
+ {
+ /* old 'volume preservation' method using the inverse scale */
+ float scale;
+
+ /* calculate volume preservation factor which is
+ * basically the inverse of the y-scaling factor
+ */
+ if (fabsf(scaleFac) != 0.0f) {
+ scale = 1.0f / fabsf(scaleFac);
+
+ /* we need to clamp this within sensible values */
+ /* NOTE: these should be fine for now, but should get sanitised in future */
+ CLAMP(scale, 0.0001f, 100000.0f);
+ }
+ else
+ scale = 1.0f;
+
+ /* apply the scaling */
+ mul_v3_fl(poseMat[0], scale);
+ mul_v3_fl(poseMat[2], scale);
+ break;
+ }
+ case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC:
+ {
+ /* improved volume preservation based on the Stretch To constraint */
+ float final_scale;
+
+ /* as the basis for volume preservation, we use the inverse scale factor... */
+ if (fabsf(scaleFac) != 0.0f) {
+ /* NOTE: The method here is taken wholesale from the Stretch To constraint */
+ float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge);
+
+ if (bulge > 1.0f) {
+ if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) {
+ float bulge_max = max_ff(ikData->bulge_max, 1.0f);
+ float hard = min_ff(bulge, bulge_max);
+
+ float range = bulge_max - 1.0f;
+ float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, ikData->bulge_smooth);
+ }
+ }
+ if (bulge < 1.0f) {
+ if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) {
+ float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f);
+ float hard = max_ff(bulge, bulge_min);
+
+ float range = 1.0f - bulge_min;
+ float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, ikData->bulge_smooth);
+ }
+ }
+
+ /* compute scale factor for xz axes from this value */
+ final_scale = sqrtf(bulge);
+ }
+ else {
+ /* no scaling, so scale factor is simple */
+ final_scale = 1.0f;
+ }
+
+ /* apply the scaling (assuming normalised scale) */
+ mul_v3_fl(poseMat[0], final_scale);
+ mul_v3_fl(poseMat[2], final_scale);
+ break;
+ }
+ }
+
+ /* finally, multiply the x and z scaling by the radius of the curve too,
+ * to allow automatic scales to get tweaked still
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) {
+ mul_v3_fl(poseMat[0], radius);
+ mul_v3_fl(poseMat[2], radius);
+ }
+ }
+
+ /* step 5: set the location of the bone in the matrix */
+ if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) {
+ /* when the 'no-root' option is affected, the chain can retain
+ * the shape but be moved elsewhere
+ */
+ copy_v3_v3(poseHead, pchan->pose_head);
+ }
+ else if (tree->con->enforce < 1.0f) {
+ /* when the influence is too low
+ * - blend the positions for the 'root' bone
+ * - stick to the parent for any other
+ */
+ if (pchan->parent) {
+ copy_v3_v3(poseHead, pchan->pose_head);
+ }
+ else {
+ /* FIXME: this introduces popping artifacts when we reach 0.0 */
+ interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce);
+ }
+ }
+ copy_v3_v3(poseMat[3], poseHead);
+
+ /* finally, store the new transform */
+ copy_m4_m4(pchan->pose_mat, poseMat);
+ copy_v3_v3(pchan->pose_head, poseHead);
+
+ /* recalculate tail, as it's now outdated after the head gets adjusted above! */
+ BKE_pose_where_is_bone_tail(pchan);
+
+ /* done! */
+ pchan->flag |= POSE_DONE;
+}
+
+/* Evaluate the chain starting from the nominated bone */
+static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+{
+ tSplineIK_Tree *tree;
+
+ /* for each pose-tree, execute it if it is spline, otherwise just free it */
+ while ((tree = pchan_root->siktree.first) != NULL) {
+ int i;
+
+ /* walk over each bone in the chain, calculating the effects of spline IK
+ * - the chain is traversed in the opposite order to storage order (i.e. parent to children)
+ * so that dependencies are correct
+ */
+ for (i = tree->chainlen - 1; i >= 0; i--) {
+ bPoseChannel *pchan = tree->chain[i];
+ splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime);
+ }
+
+ /* free the tree info specific to SplineIK trees now */
+ if (tree->chain)
+ MEM_freeN(tree->chain);
+ if (tree->free_points)
+ MEM_freeN(tree->points);
+
+ /* free this tree */
+ BLI_freelinkN(&pchan_root->siktree, tree);
+ }
+}
+
+void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime)
+{
+ splineik_init_tree(scene, ob, ctime);
+}
+
+void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+{
+ splineik_execute_tree(scene, ob, pchan_root, ctime);
+}
+
+/* *************** Depsgraph evaluation callbacks ************ */
+
+void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPose *pose)
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ bPoseChannel *pchan;
+
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ BLI_assert(ob->type == OB_ARMATURE);
+
+ /* We demand having proper pose. */
+ BLI_assert(ob->pose != NULL);
+ BLI_assert((ob->pose->flag & POSE_RECALC) == 0);
+
+ /* imat is needed for solvers. */
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ /* 1. clear flags */
+ for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
+ }
+
+ /* 2a. construct the IK tree (standard IK) */
+ BIK_initialize_tree(scene, ob, ctime);
+
+ /* 2b. construct the Spline IK trees
+ * - this is not integrated as an IK plugin, since it should be able
+ * to function in conjunction with standard IK
+ */
+ BKE_pose_splineik_init_tree(scene, ob, ctime);
+}
+
+void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan)
+{
+ bArmature *arm = (bArmature *)ob->data;
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+ BLI_assert(ob->type == OB_ARMATURE);
+ if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
+ Bone *bone = pchan->bone;
+ if (bone) {
+ copy_m4_m4(pchan->pose_mat, bone->arm_mat);
+ copy_v3_v3(pchan->pose_head, bone->arm_head);
+ copy_v3_v3(pchan->pose_tail, bone->arm_tail);
+ }
+ }
+ else {
+ /* TODO(sergey): Currently if there are constraints full transform is being
+ * evaluated in BKE_pose_constraints_evaluate.
+ */
+ if (pchan->constraints.first == NULL) {
+ if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ /* pass */
+ }
+ else {
+ /* TODO(sergey): Use time source node for time. */
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
+ }
+ }
+}
+
+void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Object *ob,
+ bPoseChannel *pchan)
+{
+ Scene *scene = G.main->scene.first;
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+ if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ /* IK are being solved separately/ */
+ }
+ else {
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
+}
+
+void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
+ bPoseChannel *pchan)
+{
+ float imat[4][4];
+ DEBUG_PRINT("%s on pchan %s\n", __func__, pchan->name);
+ if (pchan->bone) {
+ invert_m4_m4(imat, pchan->bone->arm_mat);
+ mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
+ }
+}
+
+void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *rootchan)
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+ BIK_execute_tree(scene, ob, rootchan, ctime);
+}
+
+void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *rootchan)
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+ BKE_splineik_execute_tree(scene, ob, rootchan, ctime);
+}
+
+void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPose *UNUSED(pose))
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ BLI_assert(ob->type == OB_ARMATURE);
+
+ /* 6. release the IK tree */
+ BIK_release_tree(scene, ob, ctime);
+
+ ob->recalc &= ~OB_RECALC_ALL;
+}
+
+void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+{
+ BLI_assert(ob->id.lib != NULL && ob->proxy_from != NULL);
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
+ printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
+ ob->id.name + 2, ob->proxy_from->id.name + 2);
+ }
+}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 2085fefdb93..37bd9c5db5c 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -623,7 +623,7 @@ int BKE_write_file_userdef(const char *filepath, ReportList *reports)
static void (*blender_test_break_cb)(void) = NULL;
-void set_blender_test_break_cb(void (*func)(void))
+void BKE_blender_callback_test_break_set(void (*func)(void))
{
blender_test_break_cb = func;
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 7c2b0a8a840..76544e5ed42 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -322,13 +322,14 @@ void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportLis
const bool find_all)
{
struct BPathFind_Data data = {NULL};
+ const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED;
data.basedir = bmain->name;
data.reports = reports;
data.searchdir = searchpath;
data.find_all = find_all;
- BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, BKE_BPATH_TRAVERSE_ABS, (void *)&data);
+ BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data);
}
/* Run a visitor on a string, replacing the contents of the string as needed. */
@@ -370,6 +371,9 @@ static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR],
BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ /* so functions can check old value */
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
+
if (absbase) {
BLI_path_abs(path_src, absbase);
}
@@ -432,9 +436,14 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
- if (!BKE_image_has_packedfile(ima)) {
- BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
- BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb);
+ if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
+ if (!BKE_image_has_packedfile(ima) &&
+ /* image may have been painted onto (and not saved, T44543) */
+ !BKE_image_is_dirty(ima))
+ {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb);
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index e4a5dbb9d24..3feea12f017 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -793,7 +793,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
else {
/* we need to check if the next material changes */
int next_actualFace = dm->drawObject->triangle_to_mface[0];
- int prev_mat_nr = -1;
+ short prev_mat_nr = -1;
for (i = 0; i < tottri; i++) {
//int actualFace = dm->drawObject->triangle_to_mface[i];
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 616e8a0486b..c5f7e12c9d0 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -1303,3 +1303,9 @@ void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings *
{
BLI_strncpy(colorspace_settings->name, settings->name, sizeof(colorspace_settings->name));
}
+
+bool BKE_color_managed_colorspace_settings_equals(const ColorManagedColorspaceSettings *settings1,
+ const ColorManagedColorspaceSettings *settings2)
+{
+ return STREQ(settings1->name, settings2->name);
+}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 5fcdc9c2e78..6322570d562 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -1384,6 +1384,30 @@ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float
}
}
+/* forward differencing method for first derivative of cubic bezier curve */
+void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
+{
+ float rt0, rt1, rt2, f;
+ int a;
+
+ f = 1.0f / (float)it;
+
+ rt0 = 3.0f * (q1 - q0);
+ rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2));
+ rt2 = 6.0f * (q0 + q2) - 12.0f * q1;
+
+ q0 = rt0;
+ q1 = f * (rt1 + rt2);
+ q2 = 2.0f * f * rt1;
+
+ for (a = 0; a <= it; a++) {
+ *p = q0;
+ p = (float *)(((char *)p) + stride);
+ q0 += q1;
+ q1 += q2;
+ }
+}
+
static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3],
float p[3], int it, int stride)
{
@@ -4344,8 +4368,10 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons
}
else {
i = nu->pntsu * nu->pntsv;
- for (bp = nu->bp; i--; bp++)
+ for (bp = nu->bp; i--; bp++) {
mul_m4_v3(mat, bp->vec);
+ bp->radius *= unit_scale;
+ }
}
}
@@ -4422,9 +4448,6 @@ void BKE_curve_material_index_remove(Curve *cu, int index)
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->mat_nr && nu->mat_nr >= index) {
nu->mat_nr--;
- if (curvetype == OB_CURVE) {
- nu->charidx--;
- }
}
}
}
@@ -4446,9 +4469,6 @@ void BKE_curve_material_index_clear(Curve *cu)
for (nu = cu->nurb.first; nu; nu = nu->next) {
nu->mat_nr = 0;
- if (curvetype == OB_CURVE) {
- nu->charidx = 0;
- }
}
}
}
@@ -4475,9 +4495,6 @@ int BKE_curve_material_index_validate(Curve *cu)
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->mat_nr > max_idx) {
nu->mat_nr = 0;
- if (curvetype == OB_CURVE) {
- nu->charidx = 0;
- }
is_valid = false;
}
}
@@ -4492,6 +4509,54 @@ int BKE_curve_material_index_validate(Curve *cu)
}
}
+void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len)
+{
+ const int curvetype = BKE_curve_type_get(cu);
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((void)0)
+
+ if (curvetype == OB_FONT) {
+ struct CharInfo *strinfo;
+ int charinfo_len, i;
+
+ if (cu->editfont) {
+ EditFont *ef = cu->editfont;
+ strinfo = ef->textbufinfo;
+ charinfo_len = ef->len;
+ }
+ else {
+ strinfo = cu->strinfo;
+ charinfo_len = cu->len_wchar;
+ }
+
+ for (i = 0; i <= charinfo_len; i++) {
+ if (strinfo[i].mat_nr > 0) {
+ strinfo[i].mat_nr -= 1;
+ MAT_NR_REMAP(strinfo[i].mat_nr);
+ strinfo[i].mat_nr += 1;
+ }
+ }
+ }
+ else {
+ Nurb *nu;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+
+ if (nurbs) {
+ for (nu = nurbs->first; nu; nu = nu->next) {
+ MAT_NR_REMAP(nu->mat_nr);
+ }
+ }
+ }
+
+#undef MAT_NR_REMAP
+
+}
+
void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect)
{
r_rect->xmin = cu->xof + tb->x;
@@ -4500,3 +4565,27 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t
r_rect->xmax = r_rect->xmin + tb->w;
r_rect->ymin = r_rect->ymax - tb->h;
}
+
+/* **** Depsgraph evaluation **** */
+
+void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ Curve *curve)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, curve->id.name);
+ }
+ if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(curve);
+ }
+}
+
+void BKE_curve_eval_path(EvaluationContext *UNUSED(eval_ctx),
+ Curve *curve)
+{
+ /* TODO(sergey): This will probably need to be a part of
+ * the modifier stack still.
+ */
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, curve->id.name);
+ }
+}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index add6bb0fd0b..eced263d493 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1091,7 +1091,7 @@ static void layerDefault_mcol(void *data, int count)
static void layerDefault_origindex(void *data, int count)
{
- fill_vn_i((int *)data, count, ORIGINDEX_NONE);
+ copy_vn_i((int *)data, count, ORIGINDEX_NONE);
}
static void layerInterp_bweight(
@@ -1542,7 +1542,7 @@ static void CustomData_external_free(CustomData *data)
void CustomData_reset(CustomData *data)
{
memset(data, 0, sizeof(*data));
- fill_vn_i(data->typemap, CD_NUMTYPES, -1);
+ copy_vn_i(data->typemap, CD_NUMTYPES, -1);
}
void CustomData_free(CustomData *data, int totelem)
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 72133cf6460..88885da474b 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -982,7 +982,7 @@ void BKE_defvert_extract_vgroup_to_vertweights(
}
}
else {
- fill_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f);
+ copy_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f);
}
}
@@ -1008,7 +1008,7 @@ void BKE_defvert_extract_vgroup_to_edgeweights(
MEM_freeN(tmp_weights);
}
else {
- fill_vn_fl(r_weights, num_edges, 0.0f);
+ copy_vn_fl(r_weights, num_edges, 0.0f);
}
}
@@ -1031,7 +1031,7 @@ void BKE_defvert_extract_vgroup_to_loopweights(
MEM_freeN(tmp_weights);
}
else {
- fill_vn_fl(r_weights, num_loops, 0.0f);
+ copy_vn_fl(r_weights, num_loops, 0.0f);
}
}
@@ -1060,7 +1060,7 @@ void BKE_defvert_extract_vgroup_to_polyweights(
MEM_freeN(tmp_weights);
}
else {
- fill_vn_fl(r_weights, num_polys, 0.0f);
+ copy_vn_fl(r_weights, num_polys, 0.0f);
}
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 869404ae4a6..2fd53045e29 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -88,16 +88,25 @@
#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+
static SpinLock threaded_update_lock;
void DAG_init(void)
{
BLI_spin_init(&threaded_update_lock);
+ DEG_register_node_types();
}
void DAG_exit(void)
{
BLI_spin_end(&threaded_update_lock);
+ DEG_free_node_types();
}
/* Queue and stack operations for dag traversal
@@ -1329,8 +1338,14 @@ static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NU
void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), void (*scene_func)(Main *bmain, Scene *scene, int updated))
{
- EditorsUpdateIDCb = id_func;
- EditorsUpdateSceneCb = scene_func;
+ if (DEG_depsgraph_use_legacy()) {
+ EditorsUpdateIDCb = id_func;
+ EditorsUpdateSceneCb = scene_func;
+ }
+ else {
+ /* New dependency graph. */
+ DEG_editors_set_update_cb(id_func, scene_func);
+ }
}
static void dag_editors_id_update(Main *bmain, ID *id)
@@ -1529,7 +1544,7 @@ static void dag_scene_build(Main *bmain, Scene *sce)
Base *base;
BLI_listbase_clear(&tempbase);
-
+
build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA);
dag_check_cycle(sce->theDag);
@@ -1621,32 +1636,65 @@ static void dag_scene_build(Main *bmain, Scene *sce)
/* clear all dependency graphs */
void DAG_relations_tag_update(Main *bmain)
{
- Scene *sce;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next)
- dag_scene_free(sce);
+ if (DEG_depsgraph_use_legacy()) {
+ Scene *sce;
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ dag_scene_free(sce);
+ }
+ }
+ else {
+ /* New dependency graph. */
+ DEG_relations_tag_update(bmain);
+ }
}
/* rebuild dependency graph only for a given scene */
void DAG_scene_relations_rebuild(Main *bmain, Scene *sce)
{
- dag_scene_free(sce);
- DAG_scene_relations_update(bmain, sce);
+ if (DEG_depsgraph_use_legacy()) {
+ dag_scene_free(sce);
+ DAG_scene_relations_update(bmain, sce);
+ }
+ else {
+ /* New dependency graph. */
+ DEG_scene_relations_rebuild(bmain, sce);
+ }
}
/* create dependency graph if it was cleared or didn't exist yet */
void DAG_scene_relations_update(Main *bmain, Scene *sce)
{
- if (!sce->theDag)
- dag_scene_build(bmain, sce);
+ if (DEG_depsgraph_use_legacy()) {
+ if (!sce->theDag)
+ dag_scene_build(bmain, sce);
+ }
+ else {
+ /* New dependency graph. */
+ DEG_scene_relations_update(bmain, sce);
+ }
+}
+
+void DAG_scene_relations_validate(Main *bmain, Scene *sce)
+{
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_debug_scene_relations_validate(bmain, sce);
+ }
}
void DAG_scene_free(Scene *sce)
{
- if (sce->theDag) {
- free_forest(sce->theDag);
- MEM_freeN(sce->theDag);
- sce->theDag = NULL;
+ if (DEG_depsgraph_use_legacy()) {
+ if (sce->theDag) {
+ free_forest(sce->theDag);
+ MEM_freeN(sce->theDag);
+ sce->theDag = NULL;
+ }
+ }
+ else {
+ if (sce->depsgraph) {
+ DEG_graph_free(sce->depsgraph);
+ sce->depsgraph = NULL;
+ }
}
}
@@ -1889,7 +1937,11 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho
DagAdjList *itA;
Object *ob;
int lasttime;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ return;
+ }
+
if (sce->theDag == NULL) {
printf("DAG zero... not allowed to happen!\n");
DAG_scene_relations_update(bmain, sce);
@@ -2300,7 +2352,7 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb)
}
}
-static void dag_group_on_visible_update(Group *group)
+static void dag_group_on_visible_update(Scene *scene, Group *group)
{
GroupObject *go;
@@ -2322,7 +2374,7 @@ static void dag_group_on_visible_update(Group *group)
}
if (go->ob->dup_group)
- dag_group_on_visible_update(go->ob->dup_group);
+ dag_group_on_visible_update(scene, go->ob->dup_group);
}
}
@@ -2330,7 +2382,13 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
{
ListBase listbase;
DagSceneLayer *dsl;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ /* Inform new dependnecy graphs about visibility changes. */
+ DEG_on_visible_update(bmain, do_time);
+ return;
+ }
+
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@@ -2357,7 +2415,8 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
oblay = (node) ? node->lay : ob->lay;
if ((oblay & lay) & ~scene->lay_updated) {
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
+ /* TODO(sergey): Why do we need armature here now but didn't need before? */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) {
ob->recalc |= OB_RECALC_DATA;
lib_id_recalc_tag(bmain, &ob->id);
}
@@ -2375,7 +2434,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
lib_id_recalc_tag(bmain, &ob->id);
}
if (ob->dup_group)
- dag_group_on_visible_update(ob->dup_group);
+ dag_group_on_visible_update(scene, ob->dup_group);
}
}
@@ -2609,7 +2668,12 @@ void DAG_ids_flush_tagged(Main *bmain)
ListBase *lbarray[MAX_LIBARRAY];
int a;
bool do_flush = false;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_ids_flush_tagged(bmain);
+ return;
+ }
+
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@@ -2653,6 +2717,11 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
int a;
bool updated = false;
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_ids_check_recalc(bmain, scene, time);
+ return;
+ }
+
/* loop over all ID types */
a = set_listbasepointers(bmain, lbarray);
@@ -2769,6 +2838,11 @@ void DAG_ids_clear_recalc(Main *bmain)
void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
{
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_id_tag_update_ex(bmain, id, flag);
+ return;
+ }
+
if (id == NULL) return;
if (G.debug & G_DEBUG_DEPSGRAPH) {
@@ -3160,6 +3234,10 @@ short DAG_get_eval_flags_for_object(Scene *scene, void *object)
{
DagNode *node;
+ if (!DEG_depsgraph_use_legacy()) {
+ return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object);
+ }
+
if (scene->theDag == NULL) {
/* Happens when converting objects to mesh from a python script
* after modifying scene graph.
@@ -3198,3 +3276,286 @@ bool DAG_is_acyclic(Scene *scene)
{
return scene->theDag->is_acyclic;
}
+
+#else
+
+/* *********************************************************************
+ * Stubs to avoid linking issues and make sure legacy crap is not used *
+ * *********************************************************************
+ */
+
+DagNodeQueue *queue_create(int UNUSED(slots))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void queue_raz(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void queue_delete(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+DagNode *pop_queue(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagForest *dag_init(void)
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagForest *build_dag(Main *UNUSED(bmain),
+ Scene *UNUSED(sce),
+ short UNUSED(mask))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void free_forest(DagForest *UNUSED(Dag))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void dag_add_relation(DagForest *UNUSED(forest),
+ DagNode *UNUSED(fob1),
+ DagNode *UNUSED(fob2),
+ short UNUSED(rel),
+ const char *UNUSED(name))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* debug test functions */
+
+void graph_print_queue(DagNodeQueue *UNUSED(nqueue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void graph_print_adj_list(DagForest *UNUSED(dag))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void DAG_scene_flush_update(Main *UNUSED(bmain),
+ Scene *UNUSED(sce),
+ unsigned int UNUSED(lay),
+ const short UNUSED(time))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void DAG_scene_update_flags(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ unsigned int UNUSED(lay),
+ const bool UNUSED(do_time),
+ const bool UNUSED(do_invisible_flush))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* ******************* DAG FOR ARMATURE POSE ***************** */
+
+void DAG_pose_sort(Object *UNUSED(ob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* ************************ DAG FOR THREADED UPDATE ********************* */
+
+void DAG_threaded_update_begin(Scene *UNUSED(scene),
+ void (*func)(void *node, void *user_data),
+ void *UNUSED(user_data))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ (void)func;
+}
+
+void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v),
+ void (*func)(void *node, void *user_data),
+ void *UNUSED(user_data))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ (void)func;
+}
+
+/* ************************ DAG querying ********************* */
+
+Object *DAG_get_node_object(void *UNUSED(node_v))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return "INVALID";
+}
+
+bool DAG_is_acyclic(Scene *UNUSED(scene))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return false;
+}
+
+/* ************************************
+ * This functions are to be supported *
+ * ************************************
+ */
+
+void DAG_init(void)
+{
+ DEG_register_node_types();
+}
+
+void DAG_exit(void)
+{
+ DEG_free_node_types();
+}
+
+/* ************************ API *********************** */
+
+void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func)
+{
+ DEG_editors_set_update_cb(id_func, scene_func);
+}
+
+/* Tag all relations for update. */
+void DAG_relations_tag_update(Main *bmain)
+{
+ DEG_relations_tag_update(bmain);
+}
+
+/* Rebuild dependency graph only for a given scene. */
+void DAG_scene_relations_rebuild(Main *bmain, Scene *scene)
+{
+ DEG_scene_relations_rebuild(bmain, scene);
+}
+
+/* Create dependency graph if it was cleared or didn't exist yet. */
+void DAG_scene_relations_update(Main *bmain, Scene *scene)
+{
+ DEG_scene_relations_update(bmain, scene);
+}
+
+void DAG_scene_relations_validate(Main *bmain, Scene *scene)
+{
+ DEG_debug_scene_relations_validate(bmain, scene);
+}
+
+void DAG_scene_free(Scene *scene)
+{
+ DEG_scene_graph_free(scene);
+}
+
+void DAG_on_visible_update(Main *bmain, const bool do_time)
+{
+ DEG_on_visible_update(bmain, do_time);
+}
+
+void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
+{
+ DEG_ids_check_recalc(bmain, scene, time);
+}
+
+void DAG_id_tag_update(ID *id, short flag)
+{
+ DEG_id_tag_update_ex(G.main, id, flag);
+}
+
+void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
+{
+ DEG_id_tag_update_ex(bmain, id, flag);
+}
+
+void DAG_id_type_tag(Main *bmain, short idtype)
+{
+ DEG_id_type_tag(bmain, idtype);
+}
+
+int DAG_id_type_tagged(Main *bmain, short idtype)
+{
+ return DEG_id_type_tagged(bmain, idtype);
+}
+
+void DAG_ids_clear_recalc(Main *bmain)
+{
+ DEG_ids_clear_recalc(bmain);
+}
+
+short DAG_get_eval_flags_for_object(Scene *scene, void *object)
+{
+ return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object);
+}
+
+void DAG_ids_flush_tagged(Main *bmain)
+{
+ DEG_ids_flush_tagged(bmain);
+}
+
+/* ************************ DAG DEBUGGING ********************* */
+
+void DAG_print_dependencies(Main *UNUSED(bmain),
+ Scene *scene,
+ Object *UNUSED(ob))
+{
+ DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 5c9e516aee9..8dac578ac0a 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -2964,15 +2964,16 @@ static void mesh_faces_nearest_point_dp(void *userdata, int index, const float c
/**
* Mix color values to canvas point.
*
- * \param surface canvas surface
- * \param index surface point index
- * \param paintFlags paint object flags
- * \param paintColor,Alpha,Wetness to be mixed paint values
- * \param timescale value used to adjust time dependent
+ * \param surface: Canvas surface
+ * \param index: Surface point index
+ * \param paintFlags: paint object flags
+ * \param paintColor,paintAlpha,paintWetness: To be mixed paint values
+ * \param timescale: Value used to adjust time dependent
* operations when using substeps
*/
-static void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags,
- const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
+static void dynamicPaint_mixPaintColors(
+ DynamicPaintSurface *surface, int index, int paintFlags,
+ const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
{
PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 40f3022c192..fbce501f57f 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -521,8 +521,6 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
GLenum poly_prev = GL_ZERO;
GLenum shade_prev = GL_ZERO;
- (void)setMaterial; /* UNUSED */
-
/* currently unused -- each original face is handled separately */
(void)compareDrawOptions;
@@ -539,6 +537,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
}
if (bmdm->vertexCos) {
+ short prev_mat_nr = -1;
+
/* add direct access */
const float (*vertexCos)[3] = bmdm->vertexCos;
const float (*vertexNos)[3];
@@ -569,8 +569,14 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
setDrawOptions(userData, BM_elem_index_get(efa)));
if (draw_option != DM_DRAW_OPTION_SKIP) {
const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
- if (setMaterial)
- setMaterial(efa->mat_nr + 1, NULL);
+
+ if (efa->mat_nr != prev_mat_nr) {
+ if (setMaterial) {
+ setMaterial(efa->mat_nr + 1, NULL);
+ }
+ prev_mat_nr = efa->mat_nr;
+ }
+
if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
if (poly_prev != GL_ZERO) glEnd();
@@ -645,6 +651,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
}
}
else {
+ short prev_mat_nr = -1;
+
BM_mesh_elem_index_ensure(bm, lnors ? BM_FACE | BM_LOOP : BM_FACE);
for (i = 0; i < tottri; i++) {
@@ -661,8 +669,12 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
if (draw_option != DM_DRAW_OPTION_SKIP) {
const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
- if (setMaterial)
- setMaterial(efa->mat_nr + 1, NULL);
+ if (efa->mat_nr != prev_mat_nr) {
+ if (setMaterial) {
+ setMaterial(efa->mat_nr + 1, NULL);
+ }
+ prev_mat_nr = efa->mat_nr;
+ }
if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
@@ -985,7 +997,7 @@ static void emDM_drawMappedFacesTex(DerivedMesh *dm,
* ... because the material may use layer names to select different UV's
* see: [#34378]
*/
-static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face)
+static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face, const int face_index)
{
BMVert *eve = loop->v;
int i;
@@ -1028,7 +1040,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
glVertexAttrib4ubvARB(attribs->mcol[i].gl_index, col);
}
if (attribs->tottang) {
- int index = i * 4 + index_in_face;
+ int index = face_index * 4 + index_in_face;
const float *tang = (attribs->tang.array) ? attribs->tang.array[index] : zero;
glVertexAttrib4fvARB(attribs->tang.gl_index, tang);
}
@@ -1100,14 +1112,14 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
if (vertexCos) {
glNormal3fv(polyNos[BM_elem_index_get(efa)]);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
}
}
else {
glNormal3fv(efa->no);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(ltri[fi]->v->co);
}
}
@@ -1116,7 +1128,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
if (vertexCos) {
for (fi = 0; fi < 3; fi++) {
const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(vertexNos[j]);
glVertex3fv(vertexCos[j]);
@@ -1124,7 +1136,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
}
else {
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(ltri[fi]->v->no);
glVertex3fv(ltri[fi]->v->co);
@@ -1204,14 +1216,14 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm,
if (vertexCos) {
glNormal3fv(polyNos[BM_elem_index_get(efa)]);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
}
}
else {
glNormal3fv(efa->no);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(ltri[fi]->v->co);
}
}
@@ -1220,7 +1232,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm,
if (vertexCos) {
for (fi = 0; fi < 3; fi++) {
const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(vertexNos[j]);
glVertex3fv(vertexCos[j]);
@@ -1228,7 +1240,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm,
}
else {
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(ltri[fi]->v->no);
glVertex3fv(ltri[fi]->v->co);
@@ -1968,7 +1980,7 @@ static void statvis_calc_thickness(
BLI_assert(min <= max);
- fill_vn_fl(face_dists, em->bm->totface, max);
+ copy_vn_fl(face_dists, em->bm->totface, max);
if (use_jit) {
int j;
@@ -2223,7 +2235,7 @@ static void statvis_calc_sharp(
(void)vertexCos; /* TODO */
- fill_vn_fl(vert_angles, em->bm->totvert, -M_PI);
+ copy_vn_fl(vert_angles, em->bm->totvert, -M_PI);
/* first assign float values to verts */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 296a56ada5d..785561d8239 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -1176,7 +1176,7 @@ void BKE_sim_debug_data_clear_category(const char *category)
GHashIterator iter;
BLI_ghashIterator_init(&iter, _sim_debug_data->gh);
while (!BLI_ghashIterator_done(&iter)) {
- SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ const SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
BLI_ghashIterator_step(&iter); /* removing invalidates the current iterator, so step before removing */
if (elem->category_hash == category_hash)
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 413e34e72a8..6e58513e38e 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -46,6 +46,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_easing.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLF_translation.h"
@@ -69,6 +70,10 @@
#define SMALL -1.0e-10
#define SELECT 1
+#ifdef WITH_PYTHON
+static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER;
+#endif
+
/* ************************** Data-Level Functions ************************* */
/* ---------------------- Freeing --------------------------- */
@@ -1807,7 +1812,9 @@ static float evaluate_driver(ChannelDriver *driver, const float evaltime)
/* this evaluates the expression using Python, and returns its result:
* - on errors it reports, then returns 0.0f
*/
+ BLI_mutex_lock(&python_driver_lock);
driver->curval = BPY_driver_exec(driver, evaltime);
+ BLI_mutex_unlock(&python_driver_lock);
}
#else /* WITH_PYTHON*/
(void)evaltime;
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index d3225f3fa35..daf39116d76 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -45,6 +45,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLI_string.h"
#include "BKE_icons.h"
#include "BKE_global.h" /* only for G.background test */
@@ -53,6 +54,10 @@
#include "GPU_extensions.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
+
/* GLOBALS */
static GHash *gIcons = NULL;
@@ -61,6 +66,7 @@ static int gNextIconId = 1;
static int gFirstIconId = 1;
+static GHash *gCachedPreviews = NULL;
static void icon_free(void *val)
{
@@ -105,30 +111,50 @@ void BKE_icons_init(int first_dyn_id)
gFirstIconId = first_dyn_id;
if (!gIcons)
- gIcons = BLI_ghash_int_new("icons_init gh");
+ gIcons = BLI_ghash_int_new(__func__);
+
+ if (!gCachedPreviews) {
+ gCachedPreviews = BLI_ghash_str_new(__func__);
+ }
}
void BKE_icons_free(void)
{
- if (gIcons)
+ if (gIcons) {
BLI_ghash_free(gIcons, NULL, icon_free);
- gIcons = NULL;
+ gIcons = NULL;
+ }
+
+ if (gCachedPreviews) {
+ BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
+ gCachedPreviews = NULL;
+ }
}
-PreviewImage *BKE_previewimg_create(void)
+static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
{
PreviewImage *prv_img = NULL;
int i;
- prv_img = MEM_callocN(sizeof(PreviewImage), "img_prv");
+ prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv");
+ memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
+
+ if (deferred_data_size) {
+ prv_img->use_deferred = true;
+ }
for (i = 0; i < NUM_ICON_SIZES; ++i) {
- prv_img->changed[i] = 1;
+ prv_img->flag[i] |= PRV_CHANGED;
prv_img->changed_timestamp[i] = 0;
}
return prv_img;
}
+PreviewImage *BKE_previewimg_create(void)
+{
+ return previewimg_create_ex(0);
+}
+
void BKE_previewimg_freefunc(void *link)
{
PreviewImage *prv = (PreviewImage *)link;
@@ -138,7 +164,6 @@ void BKE_previewimg_freefunc(void *link)
for (i = 0; i < NUM_ICON_SIZES; ++i) {
if (prv->rect[i]) {
MEM_freeN(prv->rect[i]);
- prv->rect[i] = NULL;
}
if (prv->gputexture[i])
GPU_texture_free(prv->gputexture[i]);
@@ -156,6 +181,26 @@ void BKE_previewimg_free(PreviewImage **prv)
}
}
+void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
+{
+ MEM_SAFE_FREE(prv->rect[size]);
+ if (prv->gputexture[size]) {
+ GPU_texture_free(prv->gputexture[size]);
+ }
+ prv->h[size] = prv->w[size] = 0;
+ prv->flag[size] |= PRV_CHANGED;
+ prv->flag[size] &= ~PRV_USER_EDITED;
+ prv->changed_timestamp[size] = 0;
+}
+
+void BKE_previewimg_clear(struct PreviewImage *prv)
+{
+ int i;
+ for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ BKE_previewimg_clear_single(prv, i);
+ }
+}
+
PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
{
PreviewImage *prv_img = NULL;
@@ -167,79 +212,186 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
if (prv->rect[i]) {
prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
}
- else {
- prv_img->rect[i] = NULL;
- }
prv_img->gputexture[i] = NULL;
}
}
return prv_img;
}
-void BKE_previewimg_free_id(ID *id)
+PreviewImage **BKE_previewimg_id_get_p(ID *id)
{
- if (GS(id->name) == ID_MA) {
- Material *mat = (Material *)id;
- BKE_previewimg_free(&mat->preview);
- }
- else if (GS(id->name) == ID_TE) {
- Tex *tex = (Tex *)id;
- BKE_previewimg_free(&tex->preview);
- }
- else if (GS(id->name) == ID_WO) {
- World *wo = (World *)id;
- BKE_previewimg_free(&wo->preview);
+ switch (GS(id->name)) {
+#define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; }
+ ID_PRV_CASE(ID_MA, Material);
+ ID_PRV_CASE(ID_TE, Tex);
+ ID_PRV_CASE(ID_WO, World);
+ ID_PRV_CASE(ID_LA, Lamp);
+ ID_PRV_CASE(ID_IM, Image);
+ ID_PRV_CASE(ID_BR, Brush);
+#undef ID_PRV_CASE
}
- else if (GS(id->name) == ID_LA) {
- Lamp *la = (Lamp *)id;
- BKE_previewimg_free(&la->preview);
- }
- else if (GS(id->name) == ID_IM) {
- Image *img = (Image *)id;
- BKE_previewimg_free(&img->preview);
+
+ return NULL;
+}
+
+void BKE_previewimg_id_free(ID *id)
+{
+ PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
+ if (prv_p) {
+ BKE_previewimg_free(prv_p);
}
- else if (GS(id->name) == ID_BR) {
- Brush *br = (Brush *)id;
- BKE_previewimg_free(&br->preview);
+}
+
+PreviewImage *BKE_previewimg_id_ensure(ID *id)
+{
+ PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
+
+ if (prv_p) {
+ if (*prv_p == NULL) {
+ *prv_p = BKE_previewimg_create();
+ }
+ return *prv_p;
}
+
+ return NULL;
}
-PreviewImage *BKE_previewimg_get(ID *id)
+PreviewImage *BKE_previewimg_cached_get(const char *name)
{
- PreviewImage *prv_img = NULL;
+ return BLI_ghash_lookup(gCachedPreviews, name);
+}
- if (GS(id->name) == ID_MA) {
- Material *mat = (Material *)id;
- if (!mat->preview) mat->preview = BKE_previewimg_create();
- prv_img = mat->preview;
+/**
+ * Generate an empty PreviewImage, if not yet existing.
+ */
+PreviewImage *BKE_previewimg_cached_ensure(const char *name)
+{
+ PreviewImage *prv = NULL;
+ void **prv_p;
+
+ if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &prv_p, (GHashKeyCopyFP)BLI_strdup)) {
+ *prv_p = BKE_previewimg_create();
}
- else if (GS(id->name) == ID_TE) {
- Tex *tex = (Tex *)id;
- if (!tex->preview) tex->preview = BKE_previewimg_create();
- prv_img = tex->preview;
+ prv = *prv_p;
+ BLI_assert(prv);
+
+ return prv;
+}
+
+/**
+ * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
+ */
+PreviewImage *BKE_previewimg_cached_thumbnail_read(
+ const char *name, const char *path, const int source, bool force_update)
+{
+ PreviewImage *prv = NULL;
+ void **prv_p;
+
+ prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
+
+ if (prv_p) {
+ prv = *prv_p;
+ BLI_assert(prv);
}
- else if (GS(id->name) == ID_WO) {
- World *wo = (World *)id;
- if (!wo->preview) wo->preview = BKE_previewimg_create();
- prv_img = wo->preview;
+
+ if (prv && force_update) {
+ const char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
+ /* If same path, no need to re-allocate preview, just clear it up. */
+ BKE_previewimg_clear(prv);
+ }
+ else {
+ BKE_previewimg_free(&prv);
+ }
}
- else if (GS(id->name) == ID_LA) {
- Lamp *la = (Lamp *)id;
- if (!la->preview) la->preview = BKE_previewimg_create();
- prv_img = la->preview;
+
+ if (!prv) {
+ /* We pack needed data for lazy loading (source type, in a single char, and path). */
+ const size_t deferred_data_size = strlen(path) + 2;
+ char *deferred_data;
+
+ prv = previewimg_create_ex(deferred_data_size);
+ deferred_data = PRV_DEFERRED_DATA(prv);
+ deferred_data[0] = source;
+ memcpy(&deferred_data[1], path, deferred_data_size - 1);
+
+ force_update = true;
}
- else if (GS(id->name) == ID_IM) {
- Image *img = (Image *)id;
- if (!img->preview) img->preview = BKE_previewimg_create();
- prv_img = img->preview;
+
+ if (force_update) {
+ if (prv_p) {
+ *prv_p = prv;
+ }
+ else {
+ BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv);
+ }
}
- else if (GS(id->name) == ID_BR) {
- Brush *br = (Brush *)id;
- if (!br->preview) br->preview = BKE_previewimg_create();
- prv_img = br->preview;
+
+ return prv;
+}
+
+void BKE_previewimg_cached_release(const char *name)
+{
+ PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
+
+ if (prv) {
+ if (prv->icon_id) {
+ BKE_icon_delete(prv->icon_id);
+ }
+ BKE_previewimg_freefunc(prv);
}
+}
- return prv_img;
+/** 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) {
+ 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]);
+
+ if (do_icon || do_preview) {
+ ImBuf *thumb;
+ char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ int source = prv_deferred_data[0];
+ char *path = &prv_deferred_data[1];
+ int icon_w, icon_h;
+
+ thumb = IMB_thumb_manage(path, THB_LARGE, source);
+
+ if (thumb) {
+ /* PreviewImage assumes premultiplied alhpa... */
+ IMB_premultiply_alpha(thumb);
+
+ if (do_preview) {
+ prv->w[ICON_SIZE_PREVIEW] = thumb->x;
+ prv->h[ICON_SIZE_PREVIEW] = thumb->y;
+ prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ }
+ if (do_icon) {
+ if (thumb->x > thumb->y) {
+ icon_w = ICON_RENDER_DEFAULT_HEIGHT;
+ icon_h = (thumb->y * icon_w) / thumb->x + 1;
+ }
+ else if (thumb->x < thumb->y) {
+ icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+ icon_w = (thumb->x * icon_h) / thumb->y + 1;
+ }
+ else {
+ icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+ }
+
+ IMB_scaleImBuf(thumb, icon_w, icon_h);
+ prv->w[ICON_SIZE_ICON] = icon_w;
+ prv->h[ICON_SIZE_ICON] = icon_h;
+ prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ }
+ IMB_freeImBuf(thumb);
+ }
+ }
+ }
}
void BKE_icon_changed(int id)
@@ -251,20 +403,20 @@ void BKE_icon_changed(int id)
icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id));
if (icon) {
- PreviewImage *prv = BKE_previewimg_get((ID *)icon->obj);
+ PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj);
/* all previews changed */
if (prv) {
int i;
for (i = 0; i < NUM_ICON_SIZES; ++i) {
- prv->changed[i] = 1;
+ prv->flag[i] |= PRV_CHANGED;
prv->changed_timestamp[i]++;
}
}
}
}
-int BKE_icon_getid(struct ID *id)
+int BKE_icon_id_ensure(struct ID *id)
{
Icon *new_icon = NULL;
@@ -277,11 +429,11 @@ int BKE_icon_getid(struct ID *id)
id->icon_id = get_next_free_id();
if (!id->icon_id) {
- printf("BKE_icon_getid: Internal error - not enough IDs\n");
+ printf("%s: Internal error - not enough IDs\n", __func__);
return 0;
}
- new_icon = MEM_callocN(sizeof(Icon), "texicon");
+ new_icon = MEM_mallocN(sizeof(Icon), __func__);
new_icon->obj = id;
new_icon->type = GS(id->name);
@@ -295,6 +447,40 @@ int BKE_icon_getid(struct ID *id)
return id->icon_id;
}
+/**
+ * Return icon id of given preview, or create new icon if not found.
+ */
+int BKE_icon_preview_ensure(PreviewImage *preview)
+{
+ Icon *new_icon = NULL;
+
+ if (!preview || G.background)
+ return 0;
+
+ if (preview->icon_id)
+ return preview->icon_id;
+
+ preview->icon_id = get_next_free_id();
+
+ if (!preview->icon_id) {
+ printf("%s: Internal error - not enough IDs\n", __func__);
+ return 0;
+ }
+
+ new_icon = MEM_mallocN(sizeof(Icon), __func__);
+
+ new_icon->obj = preview;
+ new_icon->type = 0; /* Special, tags as non-ID icon/preview. */
+
+ /* next two lines make sure image gets created */
+ new_icon->drawinfo = NULL;
+ new_icon->drawinfo_free = NULL;
+
+ BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(preview->icon_id), new_icon);
+
+ return preview->icon_id;
+}
+
Icon *BKE_icon_get(int icon_id)
{
Icon *icon = NULL;
@@ -302,7 +488,7 @@ Icon *BKE_icon_get(int icon_id)
icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
if (!icon) {
- printf("BKE_icon_get: Internal error, no icon for icon ID: %d\n", icon_id);
+ printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id);
return NULL;
}
@@ -314,18 +500,39 @@ void BKE_icon_set(int icon_id, struct Icon *icon)
void **val_p;
if (BLI_ghash_ensure_p(gIcons, SET_INT_IN_POINTER(icon_id), &val_p)) {
- printf("BKE_icon_set: Internal error, icon already set: %d\n", icon_id);
+ printf("%s: Internal error, icon already set: %d\n", __func__, icon_id);
return;
}
*val_p = icon;
}
-void BKE_icon_delete(struct ID *id)
+void BKE_icon_id_delete(struct ID *id)
{
-
if (!id->icon_id) return; /* no icon defined for library object */
BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(id->icon_id), NULL, icon_free);
id->icon_id = 0;
}
+
+/**
+ * Remove icon and free data.
+ */
+void BKE_icon_delete(int icon_id)
+{
+ Icon *icon;
+
+ if (!icon_id) return; /* no icon defined for library object */
+
+ icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL);
+
+ if (icon) {
+ if (icon->type) {
+ ((ID *)(icon->obj))->icon_id = 0;
+ }
+ else {
+ ((PreviewImage *)(icon->obj))->icon_id = 0;
+ }
+ icon_free(icon);
+ }
+}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index a09c42e9178..09934c872f7 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -75,6 +75,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
+#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_sequencer.h" /* seq_foreground_frame_get() */
@@ -101,7 +102,7 @@ static SpinLock image_spin;
/* prototypes */
static size_t image_num_files(struct Image *ima);
-static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r);
+static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock);
static void image_update_views_format(Image *ima, ImageUser *iuser);
static void image_add_view(Image *ima, const char *viewname, const char *filepath);
@@ -338,7 +339,7 @@ void BKE_image_free(Image *ima)
image_free_packedfiles(ima);
- BKE_icon_delete(&ima->id);
+ BKE_icon_id_delete(&ima->id);
ima->id.icon_id = 0;
BKE_previewimg_free(&ima->preview);
@@ -883,12 +884,16 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
/* Create an image image from ibuf. The refcount of ibuf is increased,
* caller should take care to drop its reference by calling
* IMB_freeImBuf if needed. */
-Image *BKE_image_add_from_imbuf(ImBuf *ibuf)
+Image *BKE_image_add_from_imbuf(ImBuf *ibuf, const char *name)
{
/* on save, type is changed to FILE in editsima.c */
Image *ima;
- ima = image_alloc(G.main, BLI_path_basename(ibuf->name), IMA_SRC_FILE, IMA_TYPE_IMAGE);
+ if (name == NULL) {
+ name = BLI_path_basename(ibuf->name);
+ }
+
+ ima = image_alloc(G.main, name, IMA_SRC_FILE, IMA_TYPE_IMAGE);
if (ima) {
BLI_strncpy(ima->name, ibuf->name, FILE_MAX);
@@ -1012,7 +1017,12 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = newPackedFile(reports, ima->name, basepath);
- BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ if (imapf->packedfile) {
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ }
+ else {
+ BLI_freelinkN(&ima->packedfiles, imapf);
+ }
}
else {
ImageView *iv;
@@ -1021,11 +1031,31 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = newPackedFile(reports, iv->filepath, basepath);
- BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ if (imapf->packedfile) {
+ BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ }
+ else {
+ BLI_freelinkN(&ima->packedfiles, imapf);
+ }
}
}
}
+void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, const size_t data_len)
+{
+ const size_t totfiles = image_num_files(ima);
+
+ if (totfiles != 1) {
+ BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently...");
+ }
+ else {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__);
+ BLI_addtail(&ima->packedfiles, imapf);
+ imapf->packedfile = newPackedFileMemory(data, data_len);
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ }
+}
+
void BKE_image_tag_time(Image *ima)
{
ima->lastused = PIL_check_seconds_timer_i();
@@ -2028,28 +2058,65 @@ void BKE_image_stamp_buf(
#undef BUFF_MARGIN_Y
}
-void BKE_imbuf_stamp_info(Scene *scene, Object *camera, struct ImBuf *ibuf)
+void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderResult *rr)
{
- struct StampData stamp_data;
+ struct StampData *stamp_data;
- if (!ibuf) return;
+ if (!(scene && scene->r.stamp & R_STAMP_ALL))
+ return;
- /* fill all the data values, no prefix */
- stampdata(scene, camera, &stamp_data, 0);
+ if (!rr->stamp_data) {
+ stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data");
+ }
+ else {
+ stamp_data = rr->stamp_data;
+ }
+
+ stampdata(scene, camera, stamp_data, 0);
- if (stamp_data.file[0]) IMB_metadata_change_field(ibuf, "File", stamp_data.file);
- if (stamp_data.note[0]) IMB_metadata_change_field(ibuf, "Note", stamp_data.note);
- if (stamp_data.date[0]) IMB_metadata_change_field(ibuf, "Date", stamp_data.date);
- if (stamp_data.marker[0]) IMB_metadata_change_field(ibuf, "Marker", stamp_data.marker);
- if (stamp_data.time[0]) IMB_metadata_change_field(ibuf, "Time", stamp_data.time);
- if (stamp_data.frame[0]) IMB_metadata_change_field(ibuf, "Frame", stamp_data.frame);
- if (stamp_data.camera[0]) IMB_metadata_change_field(ibuf, "Camera", stamp_data.camera);
- if (stamp_data.cameralens[0]) IMB_metadata_change_field(ibuf, "Lens", stamp_data.cameralens);
- if (stamp_data.scene[0]) IMB_metadata_change_field(ibuf, "Scene", stamp_data.scene);
- if (stamp_data.strip[0]) IMB_metadata_change_field(ibuf, "Strip", stamp_data.strip);
- if (stamp_data.rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data.rendertime);
+ if (!rr->stamp_data) {
+ rr->stamp_data = stamp_data;
+ }
}
+
+void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf)
+{
+ struct StampData *stamp_data = rr->stamp_data;
+
+ if (!ibuf || !stamp_data) return;
+
+ if (stamp_data->file[0]) IMB_metadata_change_field(ibuf, "File", stamp_data->file);
+ if (stamp_data->note[0]) IMB_metadata_change_field(ibuf, "Note", stamp_data->note);
+ if (stamp_data->date[0]) IMB_metadata_change_field(ibuf, "Date", stamp_data->date);
+ if (stamp_data->marker[0]) IMB_metadata_change_field(ibuf, "Marker", stamp_data->marker);
+ if (stamp_data->time[0]) IMB_metadata_change_field(ibuf, "Time", stamp_data->time);
+ if (stamp_data->frame[0]) IMB_metadata_change_field(ibuf, "Frame", stamp_data->frame);
+ if (stamp_data->camera[0]) IMB_metadata_change_field(ibuf, "Camera", stamp_data->camera);
+ if (stamp_data->cameralens[0]) IMB_metadata_change_field(ibuf, "Lens", stamp_data->cameralens);
+ if (stamp_data->scene[0]) IMB_metadata_change_field(ibuf, "Scene", stamp_data->scene);
+ if (stamp_data->strip[0]) IMB_metadata_change_field(ibuf, "Strip", stamp_data->strip);
+ if (stamp_data->rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data->rendertime);
+}
+
+void BKE_stamp_info_callback(void *data, const struct StampData *stamp_data, StampCallback callback)
+{
+ if (!callback || !stamp_data) return;
+
+ if (stamp_data->file[0]) callback(data, "File", stamp_data->file);
+ if (stamp_data->note[0]) callback(data, "Note", stamp_data->note);
+ if (stamp_data->date[0]) callback(data, "Date", stamp_data->date);
+ if (stamp_data->marker[0]) callback(data, "Marker", stamp_data->marker);
+ if (stamp_data->time[0]) callback(data, "Time", stamp_data->time);
+ if (stamp_data->frame[0]) callback(data, "Frame", stamp_data->frame);
+ if (stamp_data->camera[0]) callback(data, "Camera", stamp_data->camera);
+ if (stamp_data->cameralens[0]) callback(data, "Lens", stamp_data->cameralens);
+ if (stamp_data->scene[0]) callback(data, "Scene", stamp_data->scene);
+ if (stamp_data->strip[0]) callback(data, "Strip", stamp_data->strip);
+ if (stamp_data->rendertime[0]) callback(data, "RenderTime", stamp_data->rendertime);
+}
+
+
bool BKE_imbuf_alpha_test(ImBuf *ibuf)
{
int tot;
@@ -2242,15 +2309,14 @@ int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf,
return ok;
}
-int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, const char *name, struct ImageFormatData *imf)
+int BKE_imbuf_write_stamp(Scene *scene, struct RenderResult *rr, ImBuf *ibuf, const char *name, struct ImageFormatData *imf)
{
if (scene && scene->r.stamp & R_STAMP_ALL)
- BKE_imbuf_stamp_info(scene, camera, ibuf);
+ BKE_imbuf_stamp_info(rr, ibuf);
return BKE_imbuf_write(ibuf, name, imf);
}
-
static void do_makepicstring(
char *string, const char *base, const char *relbase, int frame, const char imtype,
const ImageFormatData *im_format, const short use_ext, const short use_frames,
@@ -2376,6 +2442,7 @@ static void image_viewer_create_views(const RenderData *rd, Image *ima)
void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
{
bool do_reset;
+ const bool is_multiview = (rd->scemode & R_MULTIVIEW) != 0;
BLI_lock_thread(LOCK_DRAW_IMAGE);
@@ -2391,7 +2458,9 @@ void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *
/* see if all scene render views are in the image view list */
do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views));
- if (!do_reset) {
+
+ /* multiview also needs to be sure all the views are synced */
+ if (is_multiview && !do_reset) {
SceneRenderView *srv;
ImageView *iv;
@@ -2405,11 +2474,15 @@ void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *
}
if (do_reset) {
+ BLI_spin_lock(&image_spin);
+
image_free_cached_frames(ima);
BKE_image_free_views(ima);
/* add new views */
image_viewer_create_views(rd, ima);
+
+ BLI_spin_unlock(&image_spin);
}
BLI_unlock_thread(LOCK_DRAW_IMAGE);
@@ -2975,7 +3048,7 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
{
/* preview is NULL when it has never been used as an icon before */
if (G.background == 0 && ima->preview == NULL)
- BKE_icon_changed(BKE_icon_getid(&ima->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* fields */
if (ima->flag & IMA_FIELDS) {
@@ -3321,9 +3394,11 @@ static ImBuf *load_image_single(
flag |= imbuf_alpha_flags_for_image(ima);
imapf = BLI_findlink(&ima->packedfiles, view_id);
- ibuf = IMB_ibImageFromMemory(
- (unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag,
- ima->colorspace_settings.name, "<packed data>");
+ if (imapf->packedfile) {
+ ibuf = IMB_ibImageFromMemory(
+ (unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag,
+ ima->colorspace_settings.name, "<packed data>");
+ }
}
else {
ImageUser iuser_t;
@@ -3500,10 +3575,11 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
/* showing RGBA result itself (from compo/sequence) or
* like exr, using layers etc */
/* always returns a single ibuf, also during render progress */
-static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_r)
+static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock)
{
Render *re;
RenderResult rres;
+ RenderView *rv;
float *rectf, *rectz;
unsigned int *rect;
float dither;
@@ -3517,7 +3593,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
return NULL;
/* if we the caller is not going to release the lock, don't give the image */
- if (!lock_r)
+ if (!r_lock)
return NULL;
re = RE_GetRender(iuser->scene->id.name);
@@ -3535,7 +3611,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
}
else if (ima->renders[ima->render_slot]) {
rres = *(ima->renders[ima->render_slot]);
- rres.have_combined = RE_RenderViewGetRectf(&rres, actview) != NULL;
+ rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL;
}
else
memset(&rres, 0, sizeof(RenderResult));
@@ -3546,16 +3622,30 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
return NULL;
}
- /* release is done in BKE_image_release_ibuf using lock_r */
+ /* release is done in BKE_image_release_ibuf using r_lock */
if (from_render) {
BLI_lock_thread(LOCK_VIEWER);
- *lock_r = re;
+ *r_lock = re;
+ rv = NULL;
+ }
+ else {
+ rv = BLI_findlink(&rres.views, actview);
+ if (rv == NULL)
+ rv = rres.views.first;
}
/* this gives active layer, composite or sequence result */
- rect = (unsigned int *)rres.rect32;
- rectf = rres.rectf;
- rectz = rres.rectz;
+ if (rv == NULL) {
+ rect = (unsigned int *)rres.rect32;
+ rectf = rres.rectf;
+ rectz = rres.rectz;
+ }
+ else {
+ rect = (unsigned int *)rv->rect32;
+ rectf = rv->rectf;
+ rectz = rv->rectz;
+ }
+
dither = iuser->scene->r.dither_intensity;
/* combined layer gets added as first layer */
@@ -3586,6 +3676,15 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
if (rpass) {
channels = rpass->channels;
rectf = rpass->rect;
+
+ if (!rectf) {
+ /* Happens when Save Buffers is enabled.
+ * Use display buffer stored in the render layer.
+ */
+ rect = (unsigned int *) rl->display_buffer;
+ byte_buffer_in_display_space = true;
+ }
+
dither = 0.0f; /* don't dither passes */
}
@@ -3679,9 +3778,10 @@ static size_t image_get_multiview_index(Image *ima, ImageUser *iuser)
{
const bool is_multilayer = BKE_image_is_multilayer(ima);
const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) && (iuser == NULL);
+ int index = BKE_image_is_animated(ima) ? 0 : IMA_NO_INDEX;
if (is_multilayer) {
- return iuser ? iuser->multi_index : IMA_NO_INDEX;
+ return iuser ? iuser->multi_index : index;
}
else if (is_backdrop) {
if ((ima->flag & IMA_IS_STEREO)) {
@@ -3690,16 +3790,15 @@ static size_t image_get_multiview_index(Image *ima, ImageUser *iuser)
}
}
else if ((ima->flag & IMA_IS_MULTIVIEW)) {
- return iuser ? iuser->multi_index : 0;
+ return iuser ? iuser->multi_index : index;
}
- return IMA_NO_INDEX;
+ return index;
}
static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
{
- int frame = 0, index = 0;
- index = image_get_multiview_index(ima, iuser);
+ int frame = 0, index = image_get_multiview_index(ima, iuser);
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
@@ -3727,9 +3826,7 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
{
ImBuf *ibuf = NULL;
- int frame = 0, index = 0;
-
- index = image_get_multiview_index(ima, iuser);
+ int frame = 0, index = image_get_multiview_index(ima, iuser);
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
@@ -3809,13 +3906,13 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
*
* not thread-safe, so callee should worry about thread locks
*/
-static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
+static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
ImBuf *ibuf = NULL;
int frame = 0, index = 0;
- if (lock_r)
- *lock_r = NULL;
+ if (r_lock)
+ *r_lock = NULL;
/* quick reject tests */
if (!image_quick_test(ima, iuser))
@@ -3864,14 +3961,14 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
if (ima->type == IMA_TYPE_R_RESULT) {
/* always verify entirely, and potentially
* returns pointer to release later */
- ibuf = image_get_render_result(ima, iuser, lock_r);
+ ibuf = image_get_render_result(ima, iuser, r_lock);
}
else if (ima->type == IMA_TYPE_COMPOSITE) {
/* requires lock/unlock, otherwise don't return image */
- if (lock_r) {
+ if (r_lock) {
/* unlock in BKE_image_release_ibuf */
BLI_lock_thread(LOCK_VIEWER);
- *lock_r = ima;
+ *r_lock = ima;
/* XXX anim play for viewer nodes not yet supported */
frame = 0; // XXX iuser ? iuser->framenr : 0;
@@ -3905,13 +4002,13 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
*
* references the result, BKE_image_release_ibuf should be used to de-reference
*/
-ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
+ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
ImBuf *ibuf;
BLI_spin_lock(&image_spin);
- ibuf = image_acquire_ibuf(ima, iuser, lock_r);
+ ibuf = image_acquire_ibuf(ima, iuser, r_lock);
BLI_spin_unlock(&image_spin);
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 3aea343ec5a..8427b17c01a 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -1002,7 +1002,9 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
k1 += elemsize;
}
}
- else k1 += elemsize;
+ else {
+ k1 += elemsize;
+ }
}
if (flagdo & 2) {
if (flagflo & 2) {
@@ -1390,25 +1392,37 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
-Key *BKE_key_from_object(Object *ob)
+Key **BKE_key_from_object_p(Object *ob)
{
- if (ob == NULL) return NULL;
-
+ if (ob == NULL)
+ return NULL;
+
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- return me->key;
+ return &me->key;
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
- return cu->key;
+ return &cu->key;
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
- return lt->key;
+ return &lt->key;
}
return NULL;
}
+Key *BKE_key_from_object(Object *ob)
+{
+ Key **key_p;
+ key_p = BKE_key_from_object_p(ob);
+ if (key_p) {
+ return *key_p;
+ }
+
+ return NULL;
+}
+
KeyBlock *BKE_keyblock_add(Key *key, const char *name)
{
KeyBlock *kb;
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 96b0b95adf3..44e35c645de 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -232,7 +232,7 @@ void BKE_lamp_free(Lamp *la)
}
BKE_previewimg_free(&la->preview);
- BKE_icon_delete(&la->id);
+ BKE_icon_id_delete(&la->id);
la->id.icon_id = 0;
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 73dca9436ef..86927609ff6 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -53,6 +53,7 @@
#include "BKE_anim.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_key.h"
@@ -1206,3 +1207,10 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
}
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ Lattice *UNUSED(latt))
+{
+}
+
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 2cee08a821b..bf6f7a5f22c 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -115,6 +115,8 @@
#include "BKE_texture.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#ifdef WITH_PYTHON
@@ -291,7 +293,7 @@ bool id_make_local(ID *id, bool test)
/**
* Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true iff the block can be copied.
+ * newid, unless test. Returns true if the block can be copied.
*/
bool id_copy(ID *id, ID **newid, bool test)
{
@@ -865,18 +867,24 @@ static void BKE_library_free(Library *lib)
static void (*free_windowmanager_cb)(bContext *, wmWindowManager *) = NULL;
-void set_free_windowmanager_cb(void (*func)(bContext *C, wmWindowManager *) )
+void BKE_library_callback_free_window_manager_set(void (*func)(bContext *C, wmWindowManager *) )
{
free_windowmanager_cb = func;
}
static void (*free_notifier_reference_cb)(const void *) = NULL;
-void set_free_notifier_reference_cb(void (*func)(const void *) )
+void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *) )
{
free_notifier_reference_cb = func;
}
+static void (*free_editor_id_reference_cb)(const ID *) = NULL;
+
+void BKE_library_callback_free_editor_id_reference_set(void (*func)(const ID *))
+{
+ free_editor_id_reference_cb = func;
+}
static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
{
@@ -1034,8 +1042,13 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
/* avoid notifying on removed data */
BKE_main_lock(bmain);
- if (free_notifier_reference_cb)
+ if (free_notifier_reference_cb) {
free_notifier_reference_cb(id);
+ }
+
+ if (free_editor_id_reference_cb) {
+ free_editor_id_reference_cb(id);
+ }
BLI_remlink(lb, id);
@@ -1070,8 +1083,7 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
Main *BKE_main_new(void)
{
Main *bmain = MEM_callocN(sizeof(Main), "new main");
- bmain->eval_ctx = MEM_callocN(sizeof(EvaluationContext),
- "EvaluationContext");
+ bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT);
bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
BLI_spin_init((SpinLock *)bmain->lock);
return bmain;
@@ -1138,7 +1150,7 @@ void BKE_main_free(Main *mainvar)
BLI_spin_end((SpinLock *)mainvar->lock);
MEM_freeN(mainvar->lock);
- MEM_freeN(mainvar->eval_ctx);
+ DEG_evaluation_context_free(mainvar->eval_ctx);
MEM_freeN(mainvar);
}
@@ -1404,16 +1416,11 @@ void id_clear_lib_data(Main *bmain, ID *id)
/* internal bNodeTree blocks inside ID types below
* also stores id->lib, make sure this stays in sync.
*/
- switch (GS(id->name)) {
- case ID_SCE: ntree = ((Scene *)id)->nodetree; break;
- case ID_MA: ntree = ((Material *)id)->nodetree; break;
- case ID_LA: ntree = ((Lamp *)id)->nodetree; break;
- case ID_WO: ntree = ((World *)id)->nodetree; break;
- case ID_TE: ntree = ((Tex *)id)->nodetree; break;
- case ID_LS: ntree = ((FreestyleLineStyle *)id)->nodetree; break;
- }
- if (ntree)
+ ntree = ntreeFromID(id);
+
+ if (ntree) {
ntree->id.lib = NULL;
+ }
}
/* next to indirect usage in read/writefile also in editobject.c scene.c */
@@ -1603,7 +1610,7 @@ void rename_id(ID *id, const char *name)
void name_uiprefix_id(char *name, const ID *id)
{
name[0] = id->lib ? 'L' : ' ';
- name[1] = id->flag & LIB_FAKEUSER ? 'F' : (id->us == 0) ? '0' : ' ';
+ name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
name[2] = ' ';
strcpy(name + 3, id->name + 2);
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 387d093051e..13ec970c65c 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -1360,6 +1360,9 @@ float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float x
case PROP_SHARP:
value_layer = value_layer * value_layer;
break;
+ case PROP_INVSQUARE:
+ value_layer = value_layer * (2.0f - value_layer);
+ break;
case PROP_LIN:
default:
/* nothing */
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index b5b7f3d06aa..283c7a6fc88 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -53,6 +53,7 @@
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BLI_array_utils.h"
#include "BKE_animsys.h"
#include "BKE_displist.h"
@@ -66,6 +67,8 @@
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_curve.h"
+#include "BKE_editmesh.h"
+#include "BKE_font.h"
#include "GPU_material.h"
@@ -103,7 +106,7 @@ void BKE_material_free_ex(Material *ma, bool do_id_user)
if (ma->preview)
BKE_previewimg_free(&ma->preview);
- BKE_icon_delete((struct ID *)ma);
+ BKE_icon_id_delete((struct ID *)ma);
ma->id.icon_id = 0;
/* is no lib link block, but material extension */
@@ -806,9 +809,13 @@ void assign_material_id(ID *id, Material *ma, short act)
if (act > MAXMAT) return;
if (act < 1) act = 1;
+ /* this is needed for Python overrides,
+ * we just have to take care that the UI can't do this */
+#if 0
/* prevent crashing when using accidentally */
BLI_assert(id->lib == NULL);
if (id->lib) return;
+#endif
/* test arraylens */
@@ -918,6 +925,35 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type)
test_object_materials(G.main, ob->data);
}
+
+void BKE_material_remap_object(Object *ob, const unsigned int *remap)
+{
+ Material ***matar = give_matarar(ob);
+ const short *totcol_p = give_totcolp(ob);
+
+ BLI_array_permute(ob->mat, ob->totcol, remap);
+
+ if (ob->matbits) {
+ BLI_array_permute(ob->matbits, ob->totcol, remap);
+ }
+
+ if (matar) {
+ BLI_array_permute(*matar, *totcol_p, remap);
+ }
+
+ if (ob->type == OB_MESH) {
+ BKE_mesh_material_remap(ob->data, remap, ob->totcol);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ BKE_curve_material_remap(ob->data, remap, ob->totcol);
+ }
+ else {
+ /* add support for this object data! */
+ BLI_assert(matar == NULL);
+ }
+}
+
+
/* XXX - this calls many more update calls per object then are needed, could be optimized */
void assign_matarar(struct Object *ob, struct Material ***matar, short totcol)
{
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 8728e6f98d5..c09cd1aabdc 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -586,3 +586,9 @@ void BKE_mball_select_swap(struct MetaBall *mb)
}
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ MetaBall *UNUSED(mball))
+{
+}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 080a8cead7b..e8418e876bb 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -1233,14 +1233,9 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen
copy_v3_v3(new_ml->bb->vec[6], tempmax);
/* add new_ml to mainb[] */
- if (process->totelem == process->mem) {
- MetaElem **newelem;
+ if (UNLIKELY(process->totelem == process->mem)) {
process->mem = process->mem * 2 + 10;
- newelem = MEM_mallocN(sizeof(MetaElem *) * process->mem, "metaballs");
-
- memcpy(newelem, process->mainb, sizeof(MetaElem *) * process->totelem);
- if (process->mainb) MEM_freeN(process->mainb);
- process->mainb = newelem;
+ process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem);
}
process->mainb[process->totelem++] = new_ml;
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index eec2b108ca3..37a98eae58b 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -61,6 +61,7 @@
#include "BKE_object.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
enum {
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
@@ -1265,7 +1266,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase,
dl = dispbase->first;
while (dl) {
- int smooth = dl->rt & CU_SMOOTH ? 1 : 0;
+ const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;
if (dl->type == DL_SEGM) {
startvert = vertcount;
@@ -1344,7 +1345,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase,
}
}
- if (smooth) mpoly->flag |= ME_SMOOTH;
+ if (is_smooth) mpoly->flag |= ME_SMOOTH;
mpoly++;
mloop += 3;
index += 3;
@@ -1423,7 +1424,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase,
}
}
- if (smooth) mpoly->flag |= ME_SMOOTH;
+ if (is_smooth) mpoly->flag |= ME_SMOOTH;
mpoly++;
mloop += 4;
@@ -1773,6 +1774,36 @@ void BKE_mesh_material_index_clear(Mesh *me)
}
}
+void BKE_mesh_material_remap(Mesh *me, const unsigned int *remap, unsigned int remap_len)
+{
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((void)0)
+
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ MAT_NR_REMAP(efa->mat_nr);
+ }
+ }
+ else {
+ int i;
+ for (i = 0; i < me->totpoly; i++) {
+ MAT_NR_REMAP(me->mpoly[i].mat_nr);
+ }
+ }
+
+#undef MAT_NR_REMAP
+
+}
+
void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
{
Mesh *me = meshOb->data;
@@ -1890,6 +1921,7 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys)
{
int i;
MVert *mvert = me->mvert;
+ float (*lnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL);
for (i = 0; i < me->totvert; i++, mvert++)
mul_m4_v3(mat, mvert->co);
@@ -1904,7 +1936,17 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys)
}
}
- /* don't update normals, caller can do this explicitly */
+ /* don't update normals, caller can do this explicitly.
+ * We do update loop normals though, those may not be auto-generated (see e.g. STL import script)! */
+ if (lnors) {
+ float m3[3][3];
+
+ copy_m3_m4(m3, mat);
+ normalize_m3(m3);
+ for (i = 0; i < me->totloop; i++, lnors++) {
+ mul_m3_v3(m3, *lnors);
+ }
+ }
}
void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
@@ -2356,8 +2398,8 @@ Mesh *BKE_mesh_new_from_object(
* only contains for_render flag. As soon as CoW is
* implemented, this is to be rethinked.
*/
- EvaluationContext eval_ctx = {0};
- eval_ctx.mode = DAG_EVAL_RENDER;
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER);
BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
@@ -2482,3 +2524,15 @@ Mesh *BKE_mesh_new_from_object(
return tmpmesh;
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ Mesh *mesh)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, mesh->id.name);
+ }
+ if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(mesh);
+ }
+}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index bbc175fefcd..d17ca751c5e 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -372,6 +372,10 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3],
/* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
* tag it as invalid and abort. */
lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
+
+ if (edge_vectors) {
+ BLI_stack_clear(edge_vectors);
+ }
return;
}
@@ -2253,12 +2257,15 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData
/**
* Recreate tessellation.
*
- * \param do_face_nor_copy controls whether the normals from the poly are copied to the tessellated faces.
+ * \param do_face_nor_copy: Controls whether the normals from the poly are copied to the tessellated faces.
*
* \return number of tessellation faces.
*/
-int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomData *pdata,
- MVert *mvert, int totface, int totloop, int totpoly, const bool do_face_nor_cpy)
+int BKE_mesh_recalc_tessellation(
+ CustomData *fdata, CustomData *ldata, CustomData *pdata,
+ MVert *mvert,
+ int totface, int totloop, int totpoly,
+ const bool do_face_nor_copy)
{
/* use this to avoid locking pthread for _every_ polygon
* and calling the fill function */
@@ -2468,7 +2475,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat
CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
- if (do_face_nor_cpy) {
+ if (do_face_nor_copy) {
/* If polys have a normals layer, copying that to faces can help
* avoid the need to recalculate normals later */
if (CustomData_has_layer(pdata, CD_NORMAL)) {
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index ebdbd3aac8a..8b41aded3d9 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -54,8 +54,10 @@
/* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could
* but for now this replaces it because its unused. */
-UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv,
- unsigned int totpoly, unsigned int totvert, int selected, float *limit)
+UvVertMap *BKE_mesh_uv_vert_map_create(
+ struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv,
+ unsigned int totpoly, unsigned int totvert,
+ const float limit[2], const bool selected, const bool use_winding)
{
UvVertMap *vmap;
UvMapVert *buf;
@@ -109,7 +111,10 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
buf++;
}
- winding[a] = cross_poly_v2((const float (*)[2])tf_uv, (unsigned int)nverts) > 0;
+ if (use_winding)
+ winding[a] = cross_poly_v2((const float (*)[2])tf_uv, (unsigned int)nverts) > 0;
+ else
+ winding[a] = 0;
}
}
@@ -177,8 +182,6 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
}
/**
-
-
* Generates a map where the key is the vertex and the value is a list
* of polys or loops that use that vertex as a corner. The lists are allocated
* from one memory pool.
@@ -251,9 +254,10 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem,
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
}
-/* Generates a map where the key is the vertex and the value is a list
- * of edges that use that vertex as an endpoint. The lists are allocated
- * from one memory pool. */
+/**
+ * Generates a map where the key is the vertex and the value is a list of edges that use that vertex as an endpoint.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem,
const MEdge *medge, int totvert, int totedge)
{
@@ -293,6 +297,10 @@ void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem,
*r_mem = indices;
}
+/**
+ * Generates a map where the key is the edge and the value is a list of polygons that use that edge.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem,
const MEdge *UNUSED(medge), const int totedge,
const MPoly *mpoly, const int totpoly,
@@ -400,7 +408,8 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map, int **r_mem,
* Used currently for UVs and 'smooth groups'.
* \{ */
-/** Callback deciding whether the given poly/loop/edge define an island boundary or not.
+/**
+ * Callback deciding whether the given poly/loop/edge define an island boundary or not.
*/
typedef bool (*MeshRemap_CheckIslandBoundary)(
const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge,
@@ -583,8 +592,7 @@ static void poly_edge_loop_islands_calc(
}
static bool poly_is_island_boundary_smooth_cb(
- const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me,
- const int nbr_egde_users)
+ const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users)
{
/* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */
return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2));
@@ -681,7 +689,6 @@ void BKE_mesh_loop_islands_add(
const size_t curr_num_islands = (size_t)island_store->islands_num;
int i = item_num;
- island_store->items_to_islands_num = item_num;
while (i--) {
island_store->items_to_islands[items_indices[i]] = curr_island_idx;
}
@@ -716,17 +723,21 @@ void BKE_mesh_loop_islands_add(
* not sure we want that at all!
*/
static bool mesh_check_island_boundary_uv(
- const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me,
- const int UNUSED(nbr_egde_users))
+ const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, const int UNUSED(nbr_egde_users))
{
/* Edge is UV boundary if tagged as seam. */
return (me->flag & ME_SEAM) != 0;
}
/**
- * \note all this could be optimized...
- * Not sure it would be worth the more complex code, though, those loops
- * are supposed to be really quick to do...
+ * Calculate UV islands.
+ *
+ * \note Currently we only consider edges tagges as seams as UV boundaries. This has the advantages of simplicity,
+ * and being valid/common to all UV maps. However, it means actual UV islands whithout matching UV seams
+ * will not be handled correctly...
+ *
+ * \note All this could be optimized...
+ * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do...
*/
bool BKE_mesh_calc_islands_loop_poly_uv(
MVert *UNUSED(verts), const int UNUSED(totvert),
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index aca72614094..0ed10687fae 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -707,7 +707,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
BLI_space_transform_apply_normal(space_transform, v2_no);
}
- fill_vn_fl(weights, (int)numedges_src, 0.0f);
+ copy_vn_fl(weights, (int)numedges_src, 0.0f);
/* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
* with lower/upper bounds. */
@@ -977,6 +977,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
float (*poly_nors_dst)[3] = NULL;
float (*loop_nors_dst)[3] = NULL;
+ float (*poly_cents_src)[3] = NULL;
+
MeshElemMap *vert_to_loop_map_src = NULL;
int *vert_to_loop_map_src_buff = NULL;
MeshElemMap *vert_to_poly_map_src = NULL;
@@ -1012,6 +1014,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
int *indices_interp = NULL;
float *weights_interp = NULL;
+ MLoop *ml_src, *ml_dst;
+ MPoly *mp_src, *mp_dst;
int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src;
IslandResult **islands_res;
@@ -1089,11 +1093,13 @@ void BKE_mesh_remap_calc_loops_from_dm(
edges_src, num_edges_src, polys_src, num_polys_src, loops_src, num_loops_src);
if (use_from_vert) {
loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, __func__);
- for (pidx_src = 0; pidx_src < num_polys_src; pidx_src++) {
- MPoly *mp = &polys_src[pidx_src];
- for (plidx_src = 0, lidx_src = mp->loopstart; plidx_src < mp->totloop; plidx_src++, lidx_src++) {
+ poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__);
+ for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) {
+ ml_src = &loops_src[mp_src->loopstart];
+ for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop; plidx_src++, lidx_src++) {
loop_to_poly_map_src[lidx_src] = pidx_src;
}
+ BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]);
}
}
@@ -1155,10 +1161,13 @@ void BKE_mesh_remap_calc_loops_from_dm(
int num_verts_active = 0;
BLI_BITMAP_SET_ALL(verts_active, false, (size_t)num_verts_src);
for (i = 0; i < isld->count; i++) {
- MPoly *mp_src = &polys_src[isld->indices[i]];
+ mp_src = &polys_src[isld->indices[i]];
for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; lidx_src++) {
- BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
- num_verts_active++;
+ const unsigned int vidx_src = loops_src[lidx_src].v;
+ if (!BLI_BITMAP_TEST(verts_active, vidx_src)) {
+ BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
+ num_verts_active++;
+ }
}
}
/* verts 'ownership' is transfered to treedata here, which will handle its freeing. */
@@ -1199,13 +1208,13 @@ void BKE_mesh_remap_calc_loops_from_dm(
int num_faces_active = 0;
BLI_BITMAP_SET_ALL(faces_active, false, (size_t)num_faces_src);
for (i = 0; i < num_faces_src; i++) {
- MPoly *mp_src = &polys_src[tessface_to_poly_map_src[i]];
+ mp_src = &polys_src[tessface_to_poly_map_src[i]];
if (island_store.items_to_islands[mp_src->loopstart] == tindex) {
BLI_BITMAP_ENABLE(faces_active, i);
num_faces_active++;
}
}
- /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */
+ /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */
bvhtree_from_mesh_faces_ex(
&treedata[tindex], verts_src, verts_allocated_src,
faces_src, num_faces_src, faces_allocated_src,
@@ -1233,10 +1242,14 @@ void BKE_mesh_remap_calc_loops_from_dm(
islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__);
}
- for (pidx_dst = 0; pidx_dst < numpolys_dst; pidx_dst++) {
- MPoly *mp_dst = &polys_dst[pidx_dst];
+ for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) {
float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst];
+ /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which
+ * corner to use from normals only. */
+ float pcent_dst[3];
+ bool pcent_dst_valid = false;
+
if ((size_t)mp_dst->totloop > islands_res_buff_size) {
islands_res_buff_size = (size_t)mp_dst->totloop;
for (tindex = 0; tindex < num_trees; tindex++) {
@@ -1246,8 +1259,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
for (tindex = 0; tindex < num_trees; tindex++) {
BVHTreeFromMesh *tdata = &treedata[tindex];
- MLoop *ml_dst = &loops_dst[mp_dst->loopstart];
+ ml_dst = &loops_dst[mp_dst->loopstart];
for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) {
if (use_from_vert) {
float tmp_co[3];
@@ -1263,6 +1276,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
float (*nor_dst)[3];
float (*nors_src)[3];
float best_nor_dot = -2.0f;
+ float best_sqdist_fallback = FLT_MAX;
int best_index_src = -1;
if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) {
@@ -1279,16 +1293,50 @@ void BKE_mesh_remap_calc_loops_from_dm(
for (i = vert_to_refelem_map_src[nearest.index].count; i--;) {
const int index_src = vert_to_refelem_map_src[nearest.index].indices[i];
const float dot = dot_v3v3(nors_src[index_src], *nor_dst);
- if (dot > best_nor_dot) {
- best_nor_dot = dot;
- best_index_src = index_src;
+
+ pidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
+ loop_to_poly_map_src[index_src] : index_src;
+ /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it
+ * to check we stay on current island (all loops from a given poly are
+ * on same island!). */
+ lidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
+ index_src : polys_src[pidx_src].loopstart;
+
+ /* A same vert may be at the boundary of several islands! Hence, we have to ensure
+ * poly/loop we are currently considering *belongs* to current island! */
+ if (use_islands && island_store.items_to_islands[lidx_src] != tindex) {
+ continue;
+ }
+
+ if (dot > best_nor_dot - 1e-6f) {
+ /* We need something as fallback decision in case dest normal matches several
+ * source normals (see T44522), using distance between polys' centers here. */
+ float *pcent_src;
+ float sqdist;
+
+ mp_src = &polys_src[pidx_src];
+ ml_src = &loops_src[mp_src->loopstart];
+
+ if (!pcent_dst_valid) {
+ BKE_mesh_calc_poly_center(
+ mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst);
+ pcent_dst_valid = true;
+ }
+ pcent_src = poly_cents_src[pidx_src];
+ sqdist = len_squared_v3v3(pcent_dst, pcent_src);
+
+ if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) {
+ best_nor_dot = dot;
+ best_sqdist_fallback = sqdist;
+ best_index_src = index_src;
+ }
}
}
if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
/* Our best_index_src is a poly one for now!
* Have to find its loop matching our closest vertex. */
- MPoly *mp_src = &polys_src[best_index_src];
- MLoop *ml_src = &loops_src[mp_src->loopstart];
+ mp_src = &polys_src[best_index_src];
+ ml_src = &loops_src[mp_src->loopstart];
for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) {
if ((int)ml_src->v == nearest.index) {
best_index_src = plidx_src + mp_src->loopstart;
@@ -1296,7 +1344,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
}
- islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / (hit_dist * best_nor_dot)) : 1e18f;
+ best_nor_dot = (best_nor_dot + 1.0f) * 0.5f;
+ islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist * best_nor_dot) : 1e18f;
islands_res[tindex][plidx_dst].hit_dist = hit_dist;
islands_res[tindex][plidx_dst].index_src = best_index_src;
}
@@ -1488,12 +1537,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (last_valid_pidx_isld_src != -1) {
/* Find a new valid loop in that new poly (nearest one for now).
* Note we could be much more subtle here, again that's for later... */
- MPoly *mp_src;
- MLoop *ml_src, *ml_dst = &loops_dst[lidx_dst];
int j;
float best_dist_sq = FLT_MAX;
float tmp_co[3];
+ ml_dst = &loops_dst[lidx_dst];
copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
/* We do our transform here, since we may do several raycast/nearest queries. */
@@ -1532,10 +1580,10 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Else, we use source poly, indices stored in islands_res are those of polygons. */
pidx_src = isld_res->index_src;
if (pidx_src >= 0) {
- MPoly *mp_src = &polys_src[pidx_src];
float *hit_co = isld_res->hit_point;
int best_loop_index_src;
+ mp_src = &polys_src[pidx_src];
/* If prev and curr poly are the same, no need to do anything more!!! */
if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
int pidx_isld_src, pidx_isld_src_prev;
@@ -1575,11 +1623,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (last_valid_pidx_isld_src != -1) {
/* Find a new valid loop in that new poly (nearest point on poly for now).
* Note we could be much more subtle here, again that's for later... */
- MLoop *ml_dst = &loops_dst[lidx_dst];
float best_dist_sq = FLT_MAX;
float tmp_co[3];
int j;
+ ml_dst = &loops_dst[lidx_dst];
copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
/* We do our transform here, since we may do several raycast/nearest queries. */
@@ -1710,6 +1758,9 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (loop_to_poly_map_src) {
MEM_freeN(loop_to_poly_map_src);
}
+ if (poly_cents_src) {
+ MEM_freeN(poly_cents_src);
+ }
if (vcos_interp) {
MEM_freeN(vcos_interp);
}
@@ -1865,7 +1916,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
BLI_space_transform_apply_normal(space_transform, tmp_no);
}
- fill_vn_fl(weights, (int)numpolys_src, 0.0f);
+ copy_vn_fl(weights, (int)numpolys_src, 0.0f);
if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) {
tmp_poly_size = (size_t)mp->totloop;
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
index 645567eea67..18f3db6bd15 100644
--- a/source/blender/blenkernel/intern/modifiers_bmesh.c
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -37,8 +37,9 @@
#include "BKE_editmesh.h"
/* Static function for alloc */
-static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml,
- BMesh *bm, BMVert **vtable, BMEdge **etable)
+static BMFace *bm_face_create_from_mpoly(
+ MPoly *mp, MLoop *ml,
+ BMesh *bm, BMVert **vtable, BMEdge **etable)
{
BMVert **verts = BLI_array_alloca(verts, mp->totloop);
BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 1aeb7bed86c..f063933f3f9 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1129,15 +1129,15 @@ void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy)
}
/* get segments of cached frames. useful for debugging cache policies */
-void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *totseg_r, int **points_r)
+void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *r_totseg, int **r_points)
{
- *totseg_r = 0;
- *points_r = NULL;
+ *r_totseg = 0;
+ *r_points = NULL;
if (clip->cache) {
int proxy = rendersize_to_proxy(user, clip->flag);
- IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, totseg_r, points_r);
+ IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, r_totseg, r_points);
}
}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 4ac96405fbf..0c984c38b8e 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -340,13 +340,13 @@ static int multires_get_level(Object *ob, MultiresModifierData *mmd,
bool render, bool ignore_simplify)
{
if (render)
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl) : mmd->renderlvl;
+ return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl, true) : mmd->renderlvl;
else if (ob->mode == OB_MODE_SCULPT)
return mmd->sculptlvl;
else if (ignore_simplify)
return mmd->lvl;
else
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl) : mmd->lvl;
+ return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl, false) : mmd->lvl;
}
void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl)
@@ -882,18 +882,20 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
{
Mesh *me = ob->data;
MDisps *mdisps;
- int lvl = mmd->totlvl;
+ const int lvl = mmd->totlvl;
if ((totlvl > multires_max_levels) || (me->totpoly == 0))
return;
+ BLI_assert(totlvl > lvl);
+
multires_force_update(ob);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if (!mdisps)
mdisps = multires_mdisps_initialize_hidden(me, totlvl);
- if (mdisps->disps && !updateblock && totlvl > 1) {
+ if (mdisps->disps && !updateblock && lvl != 0) {
/* upsample */
DerivedMesh *lowdm, *cddm, *highdm;
CCGElem **highGridData, **lowGridData, **subGridData;
@@ -910,6 +912,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
/* create multires DM from original mesh at low level */
lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask);
+ BLI_assert(lowdm != cddm);
cddm->release(cddm);
/* copy subsurf grids and replace them with low displaced grids */
@@ -2137,27 +2140,38 @@ void multires_load_old(Object *ob, Mesh *me)
me->mr = NULL;
}
-/* If 'ob' and 'to_ob' both have multires modifiers, synchronize them
- * such that 'ob' has the same total number of levels as 'to_ob'. */
-static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob)
+/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
+ * such that 'ob_dst' has the same total number of levels as 'ob_src'. */
+void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
{
- MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1);
- MultiresModifierData *to_mmd = get_multires_modifier(scene, to_ob, 1);
+ if (mmd_src->totlvl == mmd_dst->totlvl) {
+ return;
+ }
+
+ if (mmd_src->totlvl > mmd_dst->totlvl) {
+ multires_subdivide(mmd_dst, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
+ }
+ else {
+ multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
+ }
+}
- if (!mmd) {
+static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
+{
+ MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true);
+ MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true);
+
+ if (!mmd_src) {
/* object could have MDISP even when there is no multires modifier
* this could lead to troubles due to i've got no idea how mdisp could be
* upsampled correct without modifier data.
* just remove mdisps if no multires present (nazgul) */
- multires_customdata_delete(ob->data);
+ multires_customdata_delete(ob_src->data);
}
- if (mmd && to_mmd) {
- if (mmd->totlvl > to_mmd->totlvl)
- multires_del_higher(mmd, ob, to_mmd->totlvl);
- else
- multires_subdivide(mmd, ob, to_mmd->totlvl, 0, mmd->simple);
+ if (mmd_src && mmd_dst) {
+ multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst);
}
}
@@ -2276,7 +2290,7 @@ void multiresModifier_scale_disp(Scene *scene, Object *ob)
void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
{
float smat[3][3], tmat[3][3], mat[3][3];
- multires_sync_levels(scene, ob, to_ob);
+ multires_sync_levels(scene, to_ob, ob);
/* construct scale matrix for displacement */
BKE_object_scale_to_mat3(to_ob, tmat);
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 0d375b0dbeb..c1fa6c55d59 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -303,7 +303,7 @@ bNodeTreeType *ntreeTypeFind(const char *idname)
void ntreeTypeAdd(bNodeTreeType *nt)
{
- BLI_ghash_insert(nodetreetypes_hash, (void *)nt->idname, nt);
+ BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt);
/* XXX pass Main to register function? */
update_typeinfo(G.main, NULL, nt, NULL, NULL, false);
}
@@ -317,7 +317,7 @@ static void ntree_free_type(void *treetype_v)
MEM_freeN(treetype);
}
-void ntreeTypeFreeLink(bNodeTreeType *nt)
+void ntreeTypeFreeLink(const bNodeTreeType *nt)
{
BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type);
}
@@ -378,7 +378,7 @@ void nodeRegisterType(bNodeType *nt)
BLI_assert(nt->idname[0] != '\0');
BLI_assert(nt->poll != NULL);
- BLI_ghash_insert(nodetypes_hash, (void *)nt->idname, nt);
+ BLI_ghash_insert(nodetypes_hash, nt->idname, nt);
/* XXX pass Main to register function? */
update_typeinfo(G.main, NULL, NULL, nt, NULL, false);
}
@@ -1109,7 +1109,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
* copying for internal use (threads for eg), where you wont want it to modify the
* scene data.
*/
-static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_id_user, bool do_make_extern, bool copy_previews)
+static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews)
{
bNodeTree *newtree;
bNode *node /*, *nnode */ /* UNUSED */, *last;
@@ -1119,7 +1119,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_
if (ntree == NULL) return NULL;
/* is ntree part of library? */
- if (bmain && BLI_findindex(&bmain->nodetree, ntree) >= 0) {
+ if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) {
newtree = BKE_libblock_copy(&ntree->id);
}
else {
@@ -1211,7 +1211,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_
bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user)
{
- return ntreeCopyTree_internal(ntree, bmain, do_id_user, true, true);
+ return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true);
}
bNodeTree *ntreeCopyTree(bNodeTree *ntree)
{
@@ -1980,7 +1980,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
/* Make full copy.
* Note: previews are not copied here.
*/
- ltree = ntreeCopyTree_internal(ntree, NULL, false, false, false);
+ ltree = ntreeCopyTree_internal(ntree, G.main, true, false, false, false);
ltree->flag |= NTREE_IS_LOCALIZED;
for (node = ltree->nodes.first; node; node = node->next) {
@@ -3082,10 +3082,14 @@ void nodeSynchronizeID(bNode *node, bool copy_to_id)
bNodeSocket *sock;
Material *ma = (Material *)node->id;
int a;
+ short check_flags = SOCK_UNAVAIL;
+
+ if (!copy_to_id)
+ check_flags |= SOCK_HIDDEN;
/* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */
for (a = 0, sock = node->inputs.first; sock; sock = sock->next, a++) {
- if (!nodeSocketIsHidden(sock)) {
+ if (!(sock->flag & check_flags)) {
if (copy_to_id) {
switch (a) {
case MAT_IN_COLOR:
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index f14f72614f4..f8fe53063bc 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -96,6 +96,7 @@
#include "BKE_editmesh.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
+#include "BKE_multires.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -247,7 +248,7 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
return true;
}
-void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
+void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
{
ModifierData *md;
BKE_object_free_modifiers(ob_dst);
@@ -263,8 +264,6 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
if (ELEM(md->type,
eModifierType_Hook,
- eModifierType_Softbody,
- eModifierType_ParticleInstance,
eModifierType_Collision))
{
continue;
@@ -272,21 +271,31 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
if (!BKE_object_support_modifier_type_check(ob_dst, md->type))
continue;
-
- if (md->type == eModifierType_Skin) {
- /* ensure skin-node customdata exists */
- BKE_mesh_ensure_skin_customdata(ob_dst->data);
+
+ switch (md->type) {
+ case eModifierType_Softbody:
+ BKE_object_copy_softbody(ob_dst, ob_src);
+ break;
+ case eModifierType_Skin:
+ /* ensure skin-node customdata exists */
+ BKE_mesh_ensure_skin_customdata(ob_dst->data);
+ break;
}
nmd = modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+
+ if (md->type == eModifierType_Multires) {
+ /* Has to be done after mod creation, but *before* we actually copy its settings! */
+ multiresModifier_sync_levels_ex(ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ }
+
modifier_copyData(md, nmd);
BLI_addtail(&ob_dst->modifiers, nmd);
modifier_unique_name(&ob_dst->modifiers, nmd);
}
BKE_object_copy_particlesystems(ob_dst, ob_src);
- BKE_object_copy_softbody(ob_dst, ob_src);
/* TODO: smoke?, cloth? */
}
@@ -808,34 +817,11 @@ void BKE_object_unlink(Object *ob)
}
}
}
- else if (sl->spacetype == SPACE_OUTLINER) {
- SpaceOops *so = (SpaceOops *)sl;
-
- if (so->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == (ID *)ob) tselem->id = NULL;
- }
- }
- }
- else if (sl->spacetype == SPACE_BUTS) {
- SpaceButs *sbuts = (SpaceButs *)sl;
-
- if (sbuts->pinid == (ID *)ob) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
- sbuts->pinid = NULL;
- }
- }
- else if (sl->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)sl;
-
- if (snode->from == (ID *)ob) {
- snode->flag &= ~SNODE_PIN;
- snode->from = NULL;
- }
+#if 0
+ else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) {
+ /* now handled by WM_main_remove_editor_id_reference */
}
+#endif
}
sa = sa->next;
@@ -938,26 +924,6 @@ bool BKE_object_exists_check(Object *obtest)
/* *************************************************** */
-void *BKE_object_obdata_add_from_type(Main *bmain, int type)
-{
- switch (type) {
- case OB_MESH: return BKE_mesh_add(bmain, "Mesh");
- case OB_CURVE: return BKE_curve_add(bmain, "Curve", OB_CURVE);
- case OB_SURF: return BKE_curve_add(bmain, "Surf", OB_SURF);
- case OB_FONT: return BKE_curve_add(bmain, "Text", OB_FONT);
- case OB_MBALL: return BKE_mball_add(bmain, "Meta");
- case OB_CAMERA: return BKE_camera_add(bmain, "Camera");
- case OB_LAMP: return BKE_lamp_add(bmain, "Lamp");
- case OB_LATTICE: return BKE_lattice_add(bmain, "Lattice");
- case OB_ARMATURE: return BKE_armature_add(bmain, "Armature");
- case OB_SPEAKER: return BKE_speaker_add(bmain, "Speaker");
- case OB_EMPTY: return NULL;
- default:
- printf("BKE_object_obdata_add_from_type: Internal error, bad type: %d\n", type);
- return NULL;
- }
-}
-
static const char *get_obdata_defname(int type)
{
switch (type) {
@@ -978,6 +944,30 @@ static const char *get_obdata_defname(int type)
}
}
+void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
+{
+ if (name == NULL) {
+ name = get_obdata_defname(type);
+ }
+
+ switch (type) {
+ case OB_MESH: return BKE_mesh_add(bmain, name);
+ case OB_CURVE: return BKE_curve_add(bmain, name, OB_CURVE);
+ case OB_SURF: return BKE_curve_add(bmain, name, OB_SURF);
+ case OB_FONT: return BKE_curve_add(bmain, name, OB_FONT);
+ case OB_MBALL: return BKE_mball_add(bmain, name);
+ case OB_CAMERA: return BKE_camera_add(bmain, name);
+ case OB_LAMP: return BKE_lamp_add(bmain, name);
+ case OB_LATTICE: return BKE_lattice_add(bmain, name);
+ case OB_ARMATURE: return BKE_armature_add(bmain, name);
+ case OB_SPEAKER: return BKE_speaker_add(bmain, name);
+ case OB_EMPTY: return NULL;
+ default:
+ printf("%s: Internal error, bad type: %d\n", __func__, type);
+ return NULL;
+ }
+}
+
/* more general add: creates minimum required data, but without vertices etc. */
Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
{
@@ -1063,16 +1053,16 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
/* general add: to scene, with layer from area and default name */
/* creates minimum required data, but without vertices etc. */
-Object *BKE_object_add(Main *bmain, Scene *scene, int type)
+Object *BKE_object_add(
+ Main *bmain, Scene *scene,
+ int type, const char *name)
{
Object *ob;
Base *base;
- char name[MAX_ID_NAME];
- BLI_strncpy(name, get_obdata_defname(type), sizeof(name));
ob = BKE_object_add_only_object(bmain, type, name);
- ob->data = BKE_object_obdata_add_from_type(bmain, type);
+ ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
ob->lay = scene->lay;
@@ -1219,7 +1209,7 @@ struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
#endif /* WITH_GAMEENGINE */
-SoftBody *copy_softbody(SoftBody *sb, bool copy_caches)
+SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches)
{
SoftBody *sbn;
@@ -1343,24 +1333,24 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
return psysn;
}
-void BKE_object_copy_particlesystems(Object *obn, Object *ob)
+void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src)
{
ParticleSystem *psys, *npsys;
ModifierData *md;
- if (obn->type != OB_MESH) {
+ if (ob_dst->type != OB_MESH) {
/* currently only mesh objects can have soft body */
return;
}
- BLI_listbase_clear(&obn->particlesystem);
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ BLI_listbase_clear(&ob_dst->particlesystem);
+ for (psys = ob_src->particlesystem.first; psys; psys = psys->next) {
npsys = BKE_object_copy_particlesystem(psys);
- BLI_addtail(&obn->particlesystem, npsys);
+ BLI_addtail(&ob_dst->particlesystem, npsys);
/* need to update particle modifiers too */
- for (md = obn->modifiers.first; md; md = md->next) {
+ for (md = ob_dst->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
if (psmd->psys == psys)
@@ -1388,10 +1378,12 @@ void BKE_object_copy_particlesystems(Object *obn, Object *ob)
}
}
-void BKE_object_copy_softbody(Object *obn, Object *ob)
+void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src)
{
- if (ob->soft)
- obn->soft = copy_softbody(ob->soft, false);
+ if (ob_src->soft) {
+ ob_dst->softflag = ob_src->softflag;
+ ob_dst->soft = copy_softbody(ob_src->soft, false);
+ }
}
static void copy_object_pose(Object *obn, Object *ob)
@@ -1769,8 +1761,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat);
if (gob->dup_group) { /* should always be true */
float tvec[3];
- copy_v3_v3(tvec, gob->dup_group->dupli_ofs);
- mul_mat3_m4_v3(ob->obmat, tvec);
+ mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs);
sub_v3_v3(ob->obmat[3], tvec);
}
BKE_object_apply_mat4(ob, ob->obmat, false, true);
@@ -2065,14 +2056,12 @@ void BKE_object_to_mat4(Object *ob, float mat[4][4])
add_v3_v3v3(mat[3], ob->loc, ob->dloc);
}
-static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]);
-
void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
{
if (ob->parent) {
float par_imat[4][4];
- ob_get_parent_matrix(NULL, ob, ob->parent, par_imat);
+ BKE_object_get_parent_matrix(NULL, ob, ob->parent, par_imat);
invert_m4(par_imat);
mul_m4_m4m4(mat, par_imat, ob->obmat);
}
@@ -2092,7 +2081,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
unit_m4(mat);
cu = par->data;
- if (ELEM(NULL, par->curve_cache, par->curve_cache->path, par->curve_cache->path->data)) /* only happens on reload file, but violates depsgraph still... fix! */
+ if (par->curve_cache == NULL) /* only happens on reload file, but violates depsgraph still... fix! */
BKE_displist_make_curveTypes(scene, par, 0);
if (par->curve_cache->path == NULL) return;
@@ -2127,7 +2116,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
}
/* vec: 4 items! */
- if (where_on_path(par, ctime, vec, dir, cu->flag & CU_FOLLOW ? quat : NULL, &radius, NULL)) {
+ if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
if (cu->flag & CU_FOLLOW) {
#if 0
@@ -2364,7 +2353,8 @@ static void ob_parvert3(Object *ob, Object *par, float mat[4][4])
}
}
-static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4])
+
+void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4])
{
float tmat[4][4];
float vec[3];
@@ -2421,7 +2411,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4
if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat);
- ob_get_parent_matrix(scene, ob, par, totmat);
+ BKE_object_get_parent_matrix(scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
@@ -2579,7 +2569,7 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c
if (use_parent && ob->parent) {
float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
- ob_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
+ BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv);
invert_m4_m4(imat, diff_mat);
@@ -3045,8 +3035,9 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
// printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
if (ob->proxy_from->proxy_group) { /* transform proxy into group space */
Object *obg = ob->proxy_from->proxy_group;
- invert_m4_m4(obg->imat, obg->obmat);
- mul_m4_m4m4(ob->obmat, obg->imat, ob->proxy_from->obmat);
+ float imat[4][4];
+ invert_m4_m4(imat, obg->obmat);
+ mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat);
if (obg->dup_group) { /* should always be true */
add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs);
}
@@ -3059,147 +3050,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
}
if (ob->recalc & OB_RECALC_DATA) {
- ID *data_id = (ID *)ob->data;
- AnimData *adt = BKE_animdata_from_id(data_id);
- Key *key;
- float ctime = BKE_scene_frame_get(scene);
-
- if (G.debug & G_DEBUG_DEPSGRAPH)
- printf("recalcdata %s\n", ob->id.name + 2);
-
- if (adt) {
- /* evaluate drivers - datalevel */
- /* XXX: for mesh types, should we push this to derivedmesh instead? */
- BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- key = BKE_key_from_object(ob);
- if (key && key->block.first) {
- if (!(ob->shapeflag & OB_SHAPE_LOCK))
- BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* includes all keys and modifiers */
- switch (ob->type) {
- case OB_MESH:
- {
- BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL;
- uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
-#ifdef WITH_FREESTYLE
- /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
- if (eval_ctx->mode != DAG_EVAL_VIEWPORT) {
- data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
- }
-#endif
- if (em) {
- makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */
- }
- else {
- makeDerivedMesh(scene, ob, NULL, data_mask, 0);
- }
- break;
- }
- case OB_ARMATURE:
- if (ob->id.lib && ob->proxy_from) {
- if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
- printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
- ob->id.name + 2, ob->proxy_from->id.name + 2);
- }
- }
- else {
- BKE_pose_where_is(scene, ob);
- }
- break;
-
- case OB_MBALL:
- BKE_displist_make_mball(eval_ctx, scene, ob);
- break;
-
- case OB_CURVE:
- case OB_SURF:
- case OB_FONT:
- BKE_displist_make_curveTypes(scene, ob, 0);
- break;
-
- case OB_LATTICE:
- BKE_lattice_modifiers_calc(scene, ob);
- break;
-
- case OB_EMPTY:
- if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
- if (BKE_image_is_animated(ob->data))
- BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0);
- break;
- }
-
- /* related materials */
- /* XXX: without depsgraph tagging, this will always need to be run, which will be slow!
- * However, not doing anything (or trying to hack around this lack) is not an option
- * anymore, especially due to Cycles [#31834]
- */
- if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
- Material *ma = give_current_material(ob, a);
-
- if (ma) {
- /* recursively update drivers for this material */
- material_drivers_update(scene, ma, ctime);
- }
- }
- }
- else if (ob->type == OB_LAMP)
- lamp_drivers_update(scene, ob->data, ctime);
-
- /* particles */
- if (ob != scene->obedit && ob->particlesystem.first) {
- ParticleSystem *tpsys, *psys;
- DerivedMesh *dm;
- ob->transflag &= ~OB_DUPLIPARTS;
-
- psys = ob->particlesystem.first;
- while (psys) {
- /* ensure this update always happens even if psys is disabled */
- if (psys->recalc & PSYS_RECALC_TYPE) {
- psys_changed_type(ob, psys);
- }
-
- if (psys_check_enabled(ob, psys)) {
- /* check use of dupli objects here */
- if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
- ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
- (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
- {
- ob->transflag |= OB_DUPLIPARTS;
- }
-
- particle_system_update(scene, ob, psys);
- psys = psys->next;
- }
- else if (psys->flag & PSYS_DELETE) {
- tpsys = psys->next;
- BLI_remlink(&ob->particlesystem, psys);
- psys_free(ob, psys);
- psys = tpsys;
- }
- else
- psys = psys->next;
- }
-
- if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
- /* this is to make sure we get render level duplis in groups:
- * the derivedmesh must be created before init_render_mesh,
- * since object_duplilist does dupliparticles before that */
- dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
- dm->release(dm);
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
- }
- }
-
- /* quick cache removed */
+ BKE_object_handle_data_update(eval_ctx, scene, ob);
}
ob->recalc &= ~OB_RECALC_ALL;
@@ -3507,7 +3358,7 @@ static KeyBlock *insert_curvekey(Object *ob, const char *name, const bool from_m
return kb;
}
-KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool from_mix)
+KeyBlock *BKE_object_shapekey_insert(Object *ob, const char *name, const bool from_mix)
{
switch (ob->type) {
case OB_MESH:
@@ -3523,6 +3374,85 @@ KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool f
}
+bool BKE_object_shapekey_free(Main *bmain, Object *ob)
+{
+ Key **key_p, *key;
+
+ key_p = BKE_key_from_object_p(ob);
+ if (ELEM(NULL, key_p, *key_p)) {
+ return false;
+ }
+
+ key = *key_p;
+ *key_p = NULL;
+
+ BKE_libblock_free_us(bmain, key);
+
+ return false;
+}
+
+bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
+{
+ KeyBlock *rkb;
+ Key *key = BKE_key_from_object(ob);
+ short kb_index;
+
+ if (key == NULL) {
+ return false;
+ }
+
+ kb_index = BLI_findindex(&key->block, kb);
+ BLI_assert(kb_index != -1);
+
+ for (rkb = key->block.first; rkb; rkb = rkb->next) {
+ if (rkb->relative == kb_index) {
+ /* remap to the 'Basis' */
+ rkb->relative = 0;
+ }
+ else if (rkb->relative >= kb_index) {
+ /* Fix positional shift of the keys when kb is deleted from the list */
+ rkb->relative -= 1;
+ }
+ }
+
+ BLI_remlink(&key->block, kb);
+ key->totkey--;
+ if (key->refkey == kb) {
+ key->refkey = key->block.first;
+
+ if (key->refkey) {
+ /* apply new basis key on original data */
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_keyblock_convert_to_mesh(key->refkey, ob->data);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data));
+ break;
+ case OB_LATTICE:
+ BKE_keyblock_convert_to_lattice(key->refkey, ob->data);
+ break;
+ }
+ }
+ }
+
+ if (kb->data) {
+ MEM_freeN(kb->data);
+ }
+ MEM_freeN(kb);
+
+ if (ob->shapenr > 1) {
+ ob->shapenr--;
+ }
+
+ if (key->totkey == 0) {
+ BKE_object_shapekey_free(bmain, ob);
+ }
+
+ return true;
+}
+
bool BKE_object_flag_test_recursive(const Object *ob, short flag)
{
if (ob->flag & flag) {
@@ -4044,3 +3974,51 @@ KDTree *BKE_object_as_kdtree(Object *ob, int *r_tot)
*r_tot = tot;
return tree;
}
+
+bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
+{
+ if (modifier_dependsOnTime(md)) {
+ return true;
+ }
+
+ /* Check whether modifier is animated. */
+ /* TODO: this should be handled as part of build_animdata() -- Aligorith */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 10];
+ /* TODO(sergey): Escape modifier name. */
+ BLI_snprintf(pattern, sizeof(pattern), "modifiers[%s", md->name);
+
+ /* action - check for F-Curves with paths containing 'modifiers[' */
+ if (adt->action) {
+ for (fcu = (FCurve *)adt->action->curves.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ /* This here allows modifier properties to get driven and still update properly
+ *
+ * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven)
+ * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused
+ * by the RNA updates cache introduced in r.38649
+ */
+ for (fcu = (FCurve *)adt->drivers.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+
+ /* XXX: also, should check NLA strips, though for now assume that nobody uses
+ * that and we can omit that for performance reasons... */
+ }
+
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index e46929dde4a..f6e939a103e 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -163,7 +163,7 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id)
/**
* Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
*
- * \param allverts If true, remove all vertices, else only selected ones.
+ * \param use_selection: Only operate on selection.
* \return True if any vertex was removed, false otherwise.
*/
bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection)
@@ -241,7 +241,7 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele
/**
* Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
*
- * \param allverts If true, remove all vertices, else only selected ones.
+ * \param use_selection: Only operate on selection.
* \return True if any vertex was removed, false otherwise.
*/
bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
new file mode 100644
index 00000000000..483968c6bd9
--- /dev/null
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -0,0 +1,348 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 20014 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/object_update.c
+ * \ingroup bke
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_threads.h"
+
+#include "BKE_global.h"
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_animsys.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_key.h"
+#include "BKE_lamp.h"
+#include "BKE_lattice.h"
+#include "BKE_editmesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+#include "BKE_material.h"
+#include "BKE_image.h"
+
+#include "DEG_depsgraph.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
+#else
+# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+#endif
+
+static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER;
+
+void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
+ Scene *UNUSED(scene),
+ Object *ob)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* calculate local matrix */
+ BKE_object_to_mat4(ob, ob->obmat);
+}
+
+/* Evaluate parent */
+/* NOTE: based on solve_parenting(), but with the cruft stripped out */
+void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
+{
+ Object *par = ob->parent;
+
+ float totmat[4][4];
+ float tmat[4][4];
+ float locmat[4][4];
+
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* get local matrix (but don't calculate it, as that was done already!) */
+ // XXX: redundant?
+ copy_m4_m4(locmat, ob->obmat);
+
+ /* get parent effect matrix */
+ BKE_object_get_parent_matrix(scene, ob, par, totmat);
+
+ /* total */
+ mul_m4_m4m4(tmat, totmat, ob->parentinv);
+ mul_m4_m4m4(ob->obmat, tmat, locmat);
+
+ /* origin, for help line */
+ if ((ob->partype & PARTYPE) == PARSKEL) {
+ copy_v3_v3(ob->orig, par->obmat[3]);
+ }
+ else {
+ copy_v3_v3(ob->orig, totmat[3]);
+ }
+}
+
+void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
+{
+ bConstraintOb *cob;
+ float ctime = BKE_scene_frame_get(scene);
+
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* evaluate constraints stack */
+ /* TODO: split this into:
+ * - pre (i.e. BKE_constraints_make_evalob, per-constraint (i.e.
+ * - inner body of BKE_constraints_solve),
+ * - post (i.e. BKE_constraints_clear_evalob)
+ *
+ * Not sure why, this is from Joshua - sergey
+ *
+ */
+ cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(&ob->constraints, cob, ctime);
+ BKE_constraints_clear_evalob(cob);
+}
+
+void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* Set negative scale flag in object. */
+ if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
+ else ob->transflag &= ~OB_NEG_SCALE;
+}
+
+void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct ModifierData *md)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ (void) eval_ctx; /* Ignored. */
+ (void) scene; /* Ignored. */
+ (void) ob; /* Ignored. */
+ (void) md; /* Ignored. */
+}
+
+void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
+ Scene *scene,
+ Object *ob)
+{
+ ID *data_id = (ID *)ob->data;
+ AnimData *adt = BKE_animdata_from_id(data_id);
+ Key *key;
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH)
+ printf("recalcdata %s\n", ob->id.name + 2);
+
+ /* TODO(sergey): Only used by legacy depsgraph. */
+ if (adt) {
+ /* evaluate drivers - datalevel */
+ /* XXX: for mesh types, should we push this to derivedmesh instead? */
+ BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
+ }
+
+ /* TODO(sergey): Only used by legacy depsgraph. */
+ key = BKE_key_from_object(ob);
+ if (key && key->block.first) {
+ if (!(ob->shapeflag & OB_SHAPE_LOCK))
+ BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
+ }
+
+ /* includes all keys and modifiers */
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL;
+ uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
+#ifdef WITH_FREESTYLE
+ /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
+ if (eval_ctx->mode != DAG_EVAL_VIEWPORT) {
+ data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
+ }
+#endif
+ if (em) {
+ makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */
+ }
+ else {
+ makeDerivedMesh(scene, ob, NULL, data_mask, 0);
+ }
+ break;
+ }
+ case OB_ARMATURE:
+ if (ob->id.lib && ob->proxy_from) {
+ if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
+ printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
+ ob->id.name + 2, ob->proxy_from->id.name + 2);
+ }
+ }
+ else {
+ BKE_pose_where_is(scene, ob);
+ }
+ break;
+
+ case OB_MBALL:
+ BKE_displist_make_mball(eval_ctx, scene, ob);
+ break;
+
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ BKE_displist_make_curveTypes(scene, ob, 0);
+ break;
+
+ case OB_LATTICE:
+ BKE_lattice_modifiers_calc(scene, ob);
+ break;
+
+ case OB_EMPTY:
+ if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
+ if (BKE_image_is_animated(ob->data))
+ BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0);
+ break;
+ }
+
+ /* related materials */
+ /* XXX: without depsgraph tagging, this will always need to be run, which will be slow!
+ * However, not doing anything (or trying to hack around this lack) is not an option
+ * anymore, especially due to Cycles [#31834]
+ */
+ if (ob->totcol) {
+ int a;
+ if (ob->totcol != 0) {
+ BLI_mutex_lock(&material_lock);
+ for (a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+ if (ma) {
+ /* recursively update drivers for this material */
+ material_drivers_update(scene, ma, ctime);
+ }
+ }
+ BLI_mutex_unlock(&material_lock);
+ }
+ }
+ else if (ob->type == OB_LAMP)
+ lamp_drivers_update(scene, ob->data, ctime);
+
+ /* particles */
+ if (ob != scene->obedit && ob->particlesystem.first) {
+ ParticleSystem *tpsys, *psys;
+ DerivedMesh *dm;
+ ob->transflag &= ~OB_DUPLIPARTS;
+ psys = ob->particlesystem.first;
+ while (psys) {
+ /* ensure this update always happens even if psys is disabled */
+ if (psys->recalc & PSYS_RECALC_TYPE) {
+ psys_changed_type(ob, psys);
+ }
+
+ if (psys_check_enabled(ob, psys)) {
+ /* check use of dupli objects here */
+ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
+ ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
+ (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
+ {
+ ob->transflag |= OB_DUPLIPARTS;
+ }
+
+ particle_system_update(scene, ob, psys);
+ psys = psys->next;
+ }
+ else if (psys->flag & PSYS_DELETE) {
+ tpsys = psys->next;
+ BLI_remlink(&ob->particlesystem, psys);
+ psys_free(ob, psys);
+ psys = tpsys;
+ }
+ else
+ psys = psys->next;
+ }
+
+ if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
+ /* this is to make sure we get render level duplis in groups:
+ * the derivedmesh must be created before init_render_mesh,
+ * since object_duplilist does dupliparticles before that */
+ dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+ dm->release(dm);
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next)
+ psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
+ }
+ }
+
+ /* quick cache removed */
+}
+
+void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx),
+ Scene *UNUSED(scene),
+ Object *ob)
+{
+ /* TODO(sergey): Currently it's a duplicate of logic in BKE_object_handle_update_ex(). */
+ // XXX: it's almost redundant now...
+
+ /* Handle proxy copy for target, */
+ if (ob->id.lib && ob->proxy_from) {
+ if (ob->proxy_from->proxy_group) {
+ /* Transform proxy into group space. */
+ Object *obg = ob->proxy_from->proxy_group;
+ float imat[4][4];
+ invert_m4_m4(imat, obg->obmat);
+ mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat);
+ /* Should always be true. */
+ if (obg->dup_group) {
+ add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs);
+ }
+ }
+ else
+ copy_m4_m4(ob->obmat, ob->proxy_from->obmat);
+ }
+
+ ob->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME);
+ if (ob->data == NULL) {
+ ob->recalc &= ~OB_RECALC_DATA;
+ }
+}
+
+void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
+ Scene *scene,
+ Object *ob)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ BLI_assert(ob->type != OB_ARMATURE);
+ BKE_object_handle_data_update(eval_ctx, scene, ob);
+
+ ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
+}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index b89b5ab4bbc..1a178fb2bdf 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -738,8 +738,8 @@ static void set_height_normalize_factor(struct Ocean *oc)
for (i = 0; i < oc->_M; ++i) {
for (j = 0; j < oc->_N; ++j) {
- if (max_h < fabsf(oc->_disp_y[i * oc->_N + j])) {
- max_h = fabsf(oc->_disp_y[i * oc->_N + j]);
+ if (max_h < fabs(oc->_disp_y[i * oc->_N + j])) {
+ max_h = fabs(oc->_disp_y[i * oc->_N + j]);
}
}
}
diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index 21664bfd285..f31ba34a984 100644
--- a/source/blender/blenkernel/intern/outliner_treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -102,6 +102,9 @@ static void fill_treehash(void *treehash, BLI_mempool *treestore)
TreeStoreElem *tselem;
BLI_mempool_iter iter;
BLI_mempool_iternew(treestore, &iter);
+
+ BLI_assert(treehash);
+
while ((tselem = BLI_mempool_iterstep(&iter))) {
BKE_outliner_treehash_add_element(treehash, tselem);
}
@@ -121,6 +124,8 @@ static void free_treehash_group(void *key)
void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
{
+ BLI_assert(treehash);
+
BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_count(treestore));
fill_treehash(treehash, treestore);
return treehash;
@@ -144,12 +149,19 @@ static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short
tse_template.type = type;
tse_template.nr = type ? nr : 0; // we're picky! :)
tse_template.id = id;
+
+ BLI_assert(th);
+
return BLI_ghash_lookup(th, &tse_template);
}
TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id)
{
- TseGroup *group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
+ TseGroup *group;
+
+ BLI_assert(treehash);
+
+ group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
if (group) {
int i;
for (i = 0; i < group->size; i++) {
@@ -163,11 +175,17 @@ TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, s
TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id)
{
- TseGroup *group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
+ TseGroup *group;
+
+ BLI_assert(treehash);
+
+ group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
return group ? group->elems[0] : NULL;
}
void BKE_outliner_treehash_free(void *treehash)
{
+ BLI_assert(treehash);
+
BLI_ghash_free(treehash, NULL, free_treehash_group);
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 61e39d0ad47..800df252c69 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -224,7 +224,7 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char
}
/* no libraries for now */
-void packAll(Main *bmain, ReportList *reports)
+void packAll(Main *bmain, ReportList *reports, bool verbose)
{
Image *ima;
VFont *vfont;
@@ -237,7 +237,7 @@ void packAll(Main *bmain, ReportList *reports)
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot ++;
}
- else if (BKE_image_is_animated(ima)) {
+ else if (BKE_image_is_animated(ima) && verbose) {
BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported",
ima->id.name + 2);
}
@@ -258,10 +258,10 @@ void packAll(Main *bmain, ReportList *reports)
}
}
- if (tot == 0)
- BKE_report(reports, RPT_INFO, "No new files have been packed");
- else
+ if (tot > 0)
BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
+ else if (verbose)
+ BKE_report(reports, RPT_INFO, "No new files have been packed");
}
@@ -478,7 +478,7 @@ char *unpackFile(ReportList *reports, const char *abs_name, const char *local_na
}
static void unpack_generate_paths(
- const char *name, ID *id, char *abspath_r, char *relpath_r, size_t abspathlen, size_t relpathlen)
+ const char *name, ID *id, char *r_abspath, char *r_relpath, size_t abspathlen, size_t relpathlen)
{
char tempname[FILE_MAX];
char tempdir[FILE_MAXDIR];
@@ -500,19 +500,19 @@ static void unpack_generate_paths(
switch (GS(id->name)) {
case ID_VF:
- BLI_snprintf(relpath_r, relpathlen, "//fonts/%s", tempname);
+ BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname);
break;
case ID_SO:
- BLI_snprintf(relpath_r, relpathlen, "//sounds/%s", tempname);
+ BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname);
break;
case ID_IM:
- BLI_snprintf(relpath_r, relpathlen, "//textures/%s", tempname);
+ BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
break;
}
{
- size_t len = BLI_strncpy_rlen(abspath_r, tempdir, abspathlen);
- BLI_strncpy(abspath_r + len, tempname, abspathlen - len);
+ size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen);
+ BLI_strncpy(r_abspath + len, tempname, abspathlen - len);
}
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 3900ba8b5ea..0bda740af53 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -519,7 +519,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level,
/* threshold to move before updating the brush rotation */
#define RAKE_THRESHHOLD 20
-static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
+void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
{
if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
ups->brush_rotation = rotation;
@@ -527,7 +527,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush,
ups->brush_rotation = 0.0f;
if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
- /* here, translation contains the mouse coordinates. */
ups->brush_rotation_sec = rotation;
else
ups->brush_rotation_sec = 0.0f;
@@ -536,7 +535,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush,
void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2])
{
if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
- const float u = 0.5f;
const float r = RAKE_THRESHHOLD;
float rotation;
@@ -546,17 +544,16 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons
if (len_squared_v2(dpos) >= r * r) {
rotation = atan2f(dpos[0], dpos[1]);
- interp_v2_v2v2(ups->last_rake, ups->last_rake,
- mouse_pos, u);
+ copy_v2_v2(ups->last_rake, mouse_pos);
ups->last_rake_angle = rotation;
- update_brush_rake_rotation(ups, brush, rotation);
+ paint_update_brush_rake_rotation(ups, brush, rotation);
}
/* make sure we reset here to the last rotation to avoid accumulating
* values in case a random rotation is also added */
else {
- update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
+ paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
}
}
else {
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 1429d3b1cdc..50634460028 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -332,7 +332,7 @@ static void init_mv_jit(float *jit, int num, int seed2, float amount)
rng = BLI_rng_new(31415926 + num + seed2);
x= 0;
- num2 = 2 * num;
+ num2 = 2 * num;
for (i=0; i<num2; i+=2) {
jit[i] = x + amount*rad1*(0.5f - BLI_rng_get_float(rng));
@@ -490,7 +490,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
ParticleThreadContext *ctx= thread->ctx;
DerivedMesh *dm= ctx->dm;
- float *v1, *v2, *v3, *v4, nor[3], co1[3], co2[3];
+ float *v1, *v2, *v3, *v4, nor[3], co[3];
float cur_d, min_d, randu, randv;
int distr= ctx->distr;
int i, intersect, tot;
@@ -530,14 +530,12 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
/* experimental */
tot=dm->getNumTessFaces(dm);
- psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0);
+ psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0);
normalize_v3(nor);
- mul_v3_fl(nor,-100.0);
+ negate_v3(nor);
- add_v3_v3v3(co2,co1,nor);
-
- min_d=2.0;
+ min_d=FLT_MAX;
intersect=0;
for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
@@ -547,20 +545,20 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
v2=mvert[mface->v2].co;
v3=mvert[mface->v3].co;
- if (isect_line_tri_v3(co1, co2, v2, v3, v1, &cur_d, 0)) {
+ if (isect_ray_tri_v3(co, nor, v2, v3, v1, &cur_d, 0)) {
if (cur_d<min_d) {
min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ pa->foffset=cur_d*0.5f; /* to the middle of volume */
intersect=1;
}
}
if (mface->v4) {
v4=mvert[mface->v4].co;
- if (isect_line_tri_v3(co1, co2, v4, v1, v3, &cur_d, 0)) {
+ if (isect_ray_tri_v3(co, nor, v4, v1, v3, &cur_d, 0)) {
if (cur_d<min_d) {
min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ pa->foffset=cur_d*0.5f; /* to the middle of volume */
intersect=1;
}
}
@@ -668,6 +666,8 @@ static void exec_distribute_parent(TaskPool *UNUSED(pool), void *taskdata, int U
ParticleSystem *psys= task->ctx->sim.psys;
ParticleData *pa;
int p;
+
+ BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->begin);
pa= psys->particles + task->begin;
switch (psys->part->from) {
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 5a263e24fc4..3a19ca7304c 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -90,6 +90,7 @@
#include "BKE_modifier.h"
#include "BKE_scene.h"
#include "BKE_bvhutils.h"
+#include "BKE_depsgraph.h"
#include "PIL_time.h"
@@ -297,7 +298,7 @@ int psys_get_child_number(Scene *scene, ParticleSystem *psys)
else
nbr= psys->part->child_nbr;
- return get_render_child_particle_number(&scene->r, nbr);
+ return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL);
}
int psys_get_tot_child(Scene *scene, ParticleSystem *psys)
@@ -559,17 +560,24 @@ static void initialize_all_particles(ParticleSimulationData *sim)
ParticleSystem *psys = sim->psys;
PARTICLE_P;
+ LOOP_PARTICLES {
+ initialize_particle(sim, pa);
+ }
+}
+
+static void free_unexisting_particles(ParticleSimulationData *sim)
+{
+ ParticleSystem *psys = sim->psys;
+ PARTICLE_P;
+
psys->totunexist = 0;
LOOP_PARTICLES {
- if ((pa->flag & PARS_UNEXIST)==0)
- initialize_particle(sim, pa);
-
- if (pa->flag & PARS_UNEXIST)
+ if (pa->flag & PARS_UNEXIST) {
psys->totunexist++;
+ }
}
- /* Free unexisting particles. */
if (psys->totpart && psys->totunexist == psys->totpart) {
if (psys->particles->boid)
MEM_freeN(psys->particles->boid);
@@ -3790,6 +3798,7 @@ static void system_step(ParticleSimulationData *sim, float cfra)
initialize_all_particles(sim);
/* reset only just created particles (on startframe all particles are recreated) */
reset_all_particles(sim, 0.0, cfra, oldtotpart);
+ free_unexisting_particles(sim);
if (psys->fluid_springs) {
MEM_freeN(psys->fluid_springs);
@@ -4136,6 +4145,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
{
PARTICLE_P;
float disp = psys_get_current_display_percentage(psys);
+ bool free_unexisting = false;
/* Particles without dynamics haven't been reset yet because they don't use pointcache */
if (psys->recalc & PSYS_RECALC_RESET)
@@ -4145,6 +4155,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
free_keyed_keys(psys);
distribute_particles(&sim, part->from);
initialize_all_particles(&sim);
+ free_unexisting = true;
/* flag for possible explode modifiers after this system */
sim.psmd->flag |= eParticleSystemFlag_Pars;
@@ -4163,6 +4174,10 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
pa->flag &= ~PARS_NO_DISP;
}
+ /* free unexisting after reseting particles */
+ if (free_unexisting)
+ free_unexisting_particles(&sim);
+
if (part->phystype == PART_PHYS_KEYED) {
psys_count_keyed_targets(&sim);
set_keyed_keys(&sim);
@@ -4195,3 +4210,13 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
invert_m4_m4(psys->imat, ob->obmat);
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx),
+ Object *ob,
+ ParticleSystem *psys)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s:%s\n", __func__, ob->id.name, psys->name);
+ }
+}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index fdda72e4f7d..95d8e37d1c7 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -570,7 +570,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int
}
/* Do a full rebuild with on Grids data structure */
-void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj,
+void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids,
int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
BBC *prim_bbc = NULL;
@@ -580,7 +580,6 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj,
bvh->type = PBVH_GRIDS;
bvh->grids = grids;
- bvh->gridadj = gridadj;
bvh->gridfaces = gridfaces;
bvh->grid_flag_mats = flagmats;
bvh->totgrid = totgrid;
@@ -1383,7 +1382,7 @@ void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to
}
}
-void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj)
+void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata)
{
switch (bvh->type) {
case PBVH_GRIDS:
@@ -1392,7 +1391,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if (maxgrid) *maxgrid = bvh->totgrid;
if (gridsize) *gridsize = bvh->gridkey.grid_size;
if (griddata) *griddata = bvh->grids;
- if (gridadj) *gridadj = bvh->gridadj;
break;
case PBVH_FACES:
case PBVH_BMESH:
@@ -1401,7 +1399,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if (maxgrid) *maxgrid = 0;
if (gridsize) *gridsize = 0;
if (griddata) *griddata = NULL;
- if (gridadj) *gridadj = NULL;
break;
}
}
@@ -1612,7 +1609,9 @@ bool BKE_pbvh_node_raycast(
return hit;
}
-void BKE_pbvh_raycast_project_ray_root (PBVH *bvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
+void BKE_pbvh_raycast_project_ray_root(
+ PBVH *bvh, bool original,
+ float ray_start[3], float ray_end[3], float ray_normal[3])
{
if (bvh->nodes) {
float rootmin_start, rootmin_end;
@@ -1785,13 +1784,12 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
pbvh_draw_BB(bvh);
}
-void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces,
+void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
int a;
bvh->grids = grids;
- bvh->gridadj = gridadj;
bvh->gridfaces = gridfaces;
if (flagmats != bvh->grid_flag_mats || bvh->grid_hidden != grid_hidden) {
@@ -1970,7 +1968,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
vi->fno = NULL;
vi->mvert = NULL;
- BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL);
+ BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
vi->key = &bvh->gridkey;
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 5977243a21c..9f092bd651f 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -29,6 +29,7 @@
#include "BLI_ghash.h"
#include "BLI_heap.h"
#include "BLI_math.h"
+#include "BLI_memarena.h"
#include "BKE_ccg.h"
#include "BKE_DerivedMesh.h"
@@ -47,6 +48,9 @@
# include "BKE_global.h"
#endif
+/* Support for only operating on front-faces */
+#define USE_EDGEQUEUE_FRONTFACE
+
/* don't add edges into the queue multiple times */
#define USE_EDGEQUEUE_TAG
/**
@@ -597,6 +601,12 @@ typedef struct {
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
float limit_len;
#endif
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ const float *view_normal;
+ unsigned int use_view_normal : 1;
+#endif
+
} EdgeQueue;
typedef struct {
@@ -667,8 +677,9 @@ static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
return (BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f);
}
-static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e,
- float priority)
+static void edge_queue_insert(
+ EdgeQueueContext *eq_ctx, BMEdge *e,
+ float priority)
{
BMVert **pair;
@@ -694,8 +705,9 @@ static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e,
}
}
-static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
- BMEdge *e)
+static void long_edge_queue_edge_add(
+ EdgeQueueContext *eq_ctx,
+ BMEdge *e)
{
#ifdef USE_EDGEQUEUE_TAG
if (EDGE_QUEUE_TEST(e) == false)
@@ -716,6 +728,14 @@ static void long_edge_queue_edge_add_recursive(
{
BLI_assert(len_sq > SQUARE(limit_len));
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(l_edge->f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
#ifdef USE_EDGEQUEUE_TAG
if (EDGE_QUEUE_TEST(l_edge->e) == false)
#endif
@@ -765,8 +785,9 @@ static void long_edge_queue_edge_add_recursive(
}
#endif /* USE_EDGEQUEUE_EVEN_SUBDIV */
-static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
- BMEdge *e)
+static void short_edge_queue_edge_add(
+ EdgeQueueContext *eq_ctx,
+ BMEdge *e)
{
#ifdef USE_EDGEQUEUE_TAG
if (EDGE_QUEUE_TEST(e) == false)
@@ -779,9 +800,18 @@ static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
}
}
-static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
- BMFace *f)
+static void long_edge_queue_face_add(
+ EdgeQueueContext *eq_ctx,
+ BMFace *f)
{
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
BMLoop *l_iter;
BMLoop *l_first;
@@ -795,7 +825,7 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
if (len_sq > eq_ctx->q->limit_len_squared) {
long_edge_queue_edge_add_recursive(
eq_ctx, l_iter->radial_next, l_iter,
- len_sq, eq_ctx->q->limit_len_squared);
+ len_sq, eq_ctx->q->limit_len);
}
#else
long_edge_queue_edge_add(eq_ctx, l_iter->e);
@@ -805,9 +835,18 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
}
}
-static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx,
- BMFace *f)
+static void short_edge_queue_face_add(
+ EdgeQueueContext *eq_ctx,
+ BMFace *f)
{
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
BMLoop *l_iter;
BMLoop *l_first;
@@ -829,9 +868,10 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx,
*
* The highest priority (lowest number) is given to the longest edge.
*/
-static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh, const float center[3],
- float radius)
+static void long_edge_queue_create(
+ EdgeQueueContext *eq_ctx,
+ PBVH *bvh, const float center[3], const float view_normal[3],
+ float radius)
{
int n;
@@ -843,6 +883,13 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->limit_len = bvh->bm_max_edge_len;
#endif
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ eq_ctx->q->view_normal = view_normal;
+ eq_ctx->q->use_view_normal = (view_normal != NULL);
+#else
+ UNUSED_VARS(view_normal);
+#endif
+
#ifdef USE_EDGEQUEUE_TAG_VERIFY
pbvh_bmesh_edge_tag_verify(bvh);
#endif
@@ -877,9 +924,10 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
*
* The highest priority (lowest number) is given to the shortest edge.
*/
-static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh, const float center[3],
- float radius)
+static void short_edge_queue_create(
+ EdgeQueueContext *eq_ctx,
+ PBVH *bvh, const float center[3], const float view_normal[3],
+ float radius)
{
int n;
@@ -891,6 +939,13 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->limit_len = bvh->bm_min_edge_len;
#endif
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ eq_ctx->q->view_normal = view_normal;
+ eq_ctx->q->use_view_normal = (view_normal != NULL);
+#else
+ UNUSED_VARS(view_normal);
+#endif
+
for (n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
@@ -920,8 +975,9 @@ static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
}
-static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
- BMEdge *e, BLI_Buffer *edge_loops)
+static void pbvh_bmesh_split_edge(
+ EdgeQueueContext *eq_ctx, PBVH *bvh,
+ BMEdge *e, BLI_Buffer *edge_loops)
{
BMVert *v_new;
float co_mid[3], no_mid[3];
@@ -1037,16 +1093,12 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
BM_edge_kill(bvh->bm, e);
}
-static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh,
- BLI_Buffer *edge_loops)
+static bool pbvh_bmesh_subdivide_long_edges(
+ EdgeQueueContext *eq_ctx, PBVH *bvh,
+ BLI_Buffer *edge_loops)
{
bool any_subdivided = false;
-#ifdef USE_EDGEQUEUE_TAG_VERIFY
- pbvh_bmesh_edge_tag_verify(bvh);
-#endif
-
-
while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap);
BMVert *v1 = pair[0], *v2 = pair[1];
@@ -1295,9 +1347,10 @@ static bool pbvh_bmesh_collapse_short_edges(
/************************* Called from pbvh.c *************************/
-bool pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3],
- const float ray_normal[3], float *dist,
- bool use_original)
+bool pbvh_bmesh_node_raycast(
+ PBVHNode *node, const float ray_start[3],
+ const float ray_normal[3], float *dist,
+ bool use_original)
{
bool hit = false;
@@ -1410,36 +1463,225 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
}
}
-/***************************** Public API *****************************/
+typedef struct FastNodeBuildInfo {
+ int totface; /* number of faces */
+ int start; /* start of faces in array */
+ struct FastNodeBuildInfo *child1;
+ struct FastNodeBuildInfo *child2;
+} FastNodeBuildInfo;
-static void pbvh_bmesh_node_layers_reset(PBVH *bvh)
+/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies
+ * to a sub part of the arrays */
+static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena)
{
BMFace *f;
- BMVert *v;
- BMIter iter;
- BMesh *bm = bvh->bm;
- int cd_vert_node_offset = bvh->cd_vert_node_offset;
- int cd_face_node_offset = bvh->cd_face_node_offset;
+ BB cb;
+ BBC *bbc;
+ float mid;
+ int axis, i;
+ int end;
+ FastNodeBuildInfo *child1, *child2;
+ int num_child1, num_child2;
+ BMFace *tmp;
- /* clear the elements of the node information */
- BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ if (node->totface <= bvh->leaf_limit) {
+ return;
}
- BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) {
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ /* Calculate bounding box around primitive centroids */
+ BB_reset(&cb);
+ for (i = 0; i < node->totface; i++) {
+ f = nodeinfo[i + node->start];
+ bbc = &bbc_array[BM_elem_index_get(f)];
+
+ BB_expand(&cb, bbc->bcentroid);
+ }
+
+ /* initialize the children */
+
+ /* Find widest axis and its midpoint */
+ axis = BB_widest_axis(&cb);
+ mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
+
+ num_child1 = 0, num_child2 = 0;
+
+ /* split vertices along the middle line */
+ end = node->start + node->totface;
+ for (i = node->start; i < end - num_child2; i++) {
+ f = nodeinfo[i];
+ bbc = &bbc_array[BM_elem_index_get(f)];
+
+ if (bbc->bcentroid[axis] > mid) {
+ int i_iter = end - num_child2 - 1;
+ int candidate = -1;
+ /* found a face that should be part of another node, look for a face to substitute with */
+
+ for (;i_iter > i; i_iter--) {
+ BMFace *f_iter = nodeinfo[i_iter];
+ const BBC *bbc_iter = &bbc_array[BM_elem_index_get(f_iter)];
+ if (bbc_iter->bcentroid[axis] <= mid) {
+ candidate = i_iter;
+ break;
+ }
+ else {
+ num_child2++;
+ }
+ }
+
+ if (candidate != -1) {
+ tmp = nodeinfo[i];
+ nodeinfo[i] = nodeinfo[candidate];
+ nodeinfo[candidate] = tmp;
+ /* increase both counts */
+ num_child1++;
+ num_child2++;
+ }
+ else {
+ /* not finding candidate means second half of array part is full of
+ * second node parts, just increase the number of child nodes for it */
+ num_child2++;
+ }
+ }
+ else {
+ num_child1++;
+ }
+ }
+
+ /* ensure at least one child in each node */
+ if (num_child2 == 0) {
+ num_child2++;
+ num_child1--;
+ }
+ else if (num_child1 == 0) {
+ num_child1++;
+ num_child2--;
+ }
+
+ /* at this point, faces should have been split along the array range sequentially,
+ * each sequential part belonging to one node only */
+ BLI_assert((num_child1 + num_child2) == node->totface);
+
+ node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
+ node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
+
+ child1->totface = num_child1;
+ child1->start = node->start;
+ child2->totface = num_child2;
+ child2->start = node->start + num_child1;
+ child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL;
+
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena);
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
+
+ return;
+}
+
+static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index)
+{
+ PBVHNode *n = bvh->nodes + node_index;
+ /* two cases, node does not have children or does have children */
+ if (node->child1) {
+ int children_offset = bvh->totnode;
+
+ n->children_offset = children_offset;
+ pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child1, children_offset);
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
+
+ n = &bvh->nodes[node_index];
+
+ /* Update bounding box */
+ BB_reset(&n->vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
+ n->orig_vb = n->vb;
+ }
+ else {
+ /* node does not have children so it's a leaf node, populate with faces and tag accordingly
+ * this is an expensive part but it's not so easily threadable due to vertex node indices */
+ const int cd_vert_node_offset = bvh->cd_vert_node_offset;
+ const int cd_face_node_offset = bvh->cd_face_node_offset;
+
+ bool has_visible = false;
+ int i, end;
+ BMFace *f;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMVert *v;
+ BBC *bbc;
+
+ n->flag = PBVH_Leaf;
+ n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface);
+
+ /* Create vert hash sets */
+ n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
+ n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
+
+ BB_reset(&n->vb);
+
+ end = node->start + node->totface;
+
+ for (i = node->start; i < end; i++) {
+ f = nodeinfo[i];
+ bbc = &bbc_array[BM_elem_index_get(f)];
+
+ /* Update ownership of faces */
+ BLI_gset_insert(n->bm_faces, f);
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
+
+ /* Update vertices */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ v = l_iter->v;
+ if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
+ if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_add(n->bm_other_verts, v);
+ }
+ else {
+ BLI_gset_insert(n->bm_unique_verts, v);
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
+ }
+ }
+ /* Update node bounding box */
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+ has_visible = true;
+
+ BB_expand_with_bb(&n->vb, (BB *)bbc);
+ }
+
+ BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] &&
+ n->vb.bmin[1] <= n->vb.bmax[1] &&
+ n->vb.bmin[2] <= n->vb.bmax[2]);
+
+ n->orig_vb = n->vb;
+
+ /* Build GPU buffers for new node and update vertex normals */
+ BKE_pbvh_node_mark_rebuild_draw(n);
+
+ BKE_pbvh_node_fully_hidden_set(n, !has_visible);
+ n->flag |= PBVH_UpdateNormals;
}
}
+/***************************** Public API *****************************/
+
/* Build a PBVH from a BMesh */
-void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
- const int cd_vert_node_offset, const int cd_face_node_offset)
+void BKE_pbvh_build_bmesh(
+ PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
+ const int cd_vert_node_offset, const int cd_face_node_offset)
{
BMIter iter;
BMFace *f;
- PBVHNode *n;
- int node_index = 0;
+ BMVert *v;
+ int i;
+ /* bounding box array of all faces, no need to recalculate every time */
+ BBC *bbc_array;
+ BMFace **nodeinfo;
+ FastNodeBuildInfo rootnode = {0};
+ MemArena *arena;
bvh->cd_vert_node_offset = cd_vert_node_offset;
bvh->cd_face_node_offset = cd_face_node_offset;
@@ -1456,26 +1698,61 @@ void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
if (smooth_shading)
bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
- pbvh_bmesh_node_layers_reset(bvh);
+ /* calculate all bounding boxes once for all faces */
+ bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC");
+ nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
+ arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
+
+ BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) {
+ BBC *bbc = &bbc_array[i];
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ BB_reset((BB *)bbc);
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BB_expand((BB *)bbc, l_iter->v->co);
+ } while ((l_iter = l_iter->next) != l_first);
+ BBC_update_centroid(bbc);
+
+ /* so we can do direct lookups on 'bbc_array' */
+ BM_elem_index_set(f, i); /* set_dirty! */
+ nodeinfo[i] = f;
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ }
+
+ BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ }
+
+ /* likely this is already dirty */
+ bm->elem_index_dirty |= BM_FACE;
+
+ /* setup root node */
+ rootnode.totface = bm->totface;
+
+ /* start recursion, assign faces to nodes accordingly */
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena);
+
+ /* we now have all faces assigned to a node, next we need to assign those to the gsets of the nodes */
/* Start with all faces in the root node */
- n = bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
+ bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
bvh->totnode = 1;
- n->flag = PBVH_Leaf;
- n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", bvh->bm->totface);
- BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BLI_gset_insert(n->bm_faces, f);
- }
- /* Recursively split the node until it is under the limit; if no
- * splitting occurs then finalize the existing leaf node */
- if (!pbvh_bmesh_node_limit_ensure(bvh, node_index))
- pbvh_bmesh_node_finalize(bvh, 0, cd_vert_node_offset, cd_face_node_offset);
+ /* take root node and visit and populate children recursively */
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0);
+
+ BLI_memarena_free(arena);
+ MEM_freeN(bbc_array);
+ MEM_freeN(nodeinfo);
}
/* Collapse short edges, subdivide long edges */
-bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
- const float center[3], float radius)
+bool BKE_pbvh_bmesh_update_topology(
+ PBVH *bvh, PBVHTopologyUpdateMode mode,
+ const float center[3], const float view_normal[3],
+ float radius)
{
/* 2 is enough for edge faces - manifold edge */
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
@@ -1487,12 +1764,16 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
bool modified = false;
int n;
+ if (view_normal) {
+ BLI_assert(len_squared_v3(view_normal) != 0.0f);
+ }
+
if (mode & PBVH_Collapse) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
- short_edge_queue_create(&eq_ctx, bvh, center, radius);
+ short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
modified |= !BLI_heap_is_empty(q.heap);
pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh,
&deleted_faces);
@@ -1505,7 +1786,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
- long_edge_queue_create(&eq_ctx, bvh, center, radius);
+ long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
modified |= !BLI_heap_is_empty(q.heap);
pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops);
BLI_heap_free(q.heap, NULL);
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 6b3ef8eb5da..7daccb47c92 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -139,7 +139,6 @@ struct PBVH {
/* Grid Data */
CCGKey gridkey;
CCGElem **grids;
- DMGridAdjacency *gridadj;
void **gridfaces;
const DMFlagMat *grid_flag_mats;
int totgrid;
@@ -175,9 +174,10 @@ void BB_expand_with_bb(BB *bb, BB *bb2);
void BBC_update_centroid(BBC *bbc);
int BB_widest_axis(const BB *bb);
void pbvh_grow_nodes(PBVH *bvh, int totnode);
-bool ray_face_intersection(const float ray_start[3], const float ray_normal[3],
- const float *t0, const float *t1, const float *t2,
- const float *t3, float *fdist);
+bool ray_face_intersection(
+ const float ray_start[3], const float ray_normal[3],
+ const float *t0, const float *t1, const float *t2,
+ const float *t3, float *fdist);
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index c477aabbb71..2f4a45828ea 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -3093,7 +3093,7 @@ static PointCache *ptcache_copy(PointCache *cache, bool copy_data)
}
/* returns first point cache */
-PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, ListBase *ptcaches_old, bool copy_data)
+PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, bool copy_data)
{
PointCache *cache = ptcaches_old->first;
@@ -3354,7 +3354,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
- BLI_end_threads(&threads);
+ BLI_end_threads(&threads);
}
/* clear baking flag */
if (pid) {
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index aaf54b82f32..ff9e1a2b831 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -54,6 +54,7 @@
#include "DNA_scene_types.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_library.h"
@@ -61,6 +62,7 @@
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
#ifdef WITH_BULLET
@@ -1610,3 +1612,51 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
#endif
#endif /* WITH_BULLET */
+
+/* -------------------- */
+/* Depsgraph evaluation */
+
+void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene)
+{
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s at %f\n", __func__, ctime);
+ }
+
+ /* rebuild sim data (i.e. after resetting to start of timeline) */
+ if (BKE_scene_check_rigidbody_active(scene)) {
+ BKE_rigidbody_rebuild_world(scene, ctime);
+ }
+}
+
+void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene)
+{
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s at %f\n", __func__, ctime);
+ }
+
+ /* evaluate rigidbody sim */
+ if (BKE_scene_check_rigidbody_active(scene)) {
+ BKE_rigidbody_do_simulation(scene, ctime);
+ }
+}
+
+void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
+{
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, ob->id.name);
+ }
+
+ /* read values pushed into RBO from sim/cache... */
+ BKE_rigidbody_sync_transforms(rbw, ob, ctime);
+}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 07e2a186444..bd03706c5b8 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -75,6 +75,7 @@
#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_node.h"
@@ -82,11 +83,14 @@
#include "BKE_paint.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
#include "BKE_unit.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "RE_engine.h"
#include "PIL_time.h"
@@ -154,6 +158,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
{
Scene *scen;
SceneRenderLayer *srl, *new_srl;
+ FreestyleLineSet *lineset;
ToolSettings *ts;
Base *base, *obase;
@@ -190,6 +195,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
scen->ed = NULL;
scen->theDag = NULL;
+ scen->depsgraph = NULL;
scen->obedit = NULL;
scen->stats = NULL;
scen->fps_info = NULL;
@@ -237,6 +243,14 @@ Scene *BKE_scene_copy(Scene *sce, int type)
new_srl = scen->r.layers.first;
for (srl = sce->r.layers.first; srl; srl = srl->next) {
BKE_freestyle_config_copy(&new_srl->freestyleConfig, &srl->freestyleConfig);
+ if (type == SCE_COPY_FULL) {
+ for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ if (lineset->linestyle) {
+ id_us_plus((ID *)lineset->linestyle);
+ lineset->linestyle = BKE_linestyle_copy(G.main, lineset->linestyle);
+ }
+ }
+ }
new_srl = new_srl->next;
}
}
@@ -420,6 +434,8 @@ void BKE_scene_free(Scene *sce)
}
DAG_scene_free(sce);
+ if (sce->depsgraph)
+ DEG_graph_free(sce->depsgraph);
if (sce->nodetree) {
ntreeFreeTree(sce->nodetree);
@@ -680,7 +696,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->gm.recastData.cellsize = 0.3f;
sce->gm.recastData.cellheight = 0.2f;
- sce->gm.recastData.agentmaxslope = M_PI / 2;
+ sce->gm.recastData.agentmaxslope = M_PI_4;
sce->gm.recastData.agentmaxclimb = 0.9f;
sce->gm.recastData.agentheight = 2.0f;
sce->gm.recastData.agentradius = 0.6f;
@@ -798,33 +814,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
return NULL;
}
-static void scene_unlink_space_node(SpaceNode *snode, Scene *sce)
-{
- if (snode->id == &sce->id) {
- /* nasty DNA logic for SpaceNode:
- * ideally should be handled by editor code, but would be bad level call
- */
- bNodeTreePath *path, *path_next;
- for (path = snode->treepath.first; path; path = path_next) {
- path_next = path->next;
- MEM_freeN(path);
- }
- BLI_listbase_clear(&snode->treepath);
-
- snode->id = NULL;
- snode->from = NULL;
- snode->nodetree = NULL;
- snode->edittree = NULL;
- }
-}
-
-static void scene_unlink_space_buts(SpaceButs *sbuts, Scene *sce)
-{
- if (sbuts->pinid == &sce->id) {
- sbuts->pinid = NULL;
- }
-}
-
void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
{
Scene *sce1;
@@ -849,24 +838,11 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
/* all screens */
for (screen = bmain->screen.first; screen; screen = screen->id.next) {
- ScrArea *area;
-
- if (screen->scene == sce)
+ if (screen->scene == sce) {
screen->scene = newsce;
-
- for (area = screen->areabase.first; area; area = area->next) {
- SpaceLink *space_link;
- for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
- switch (space_link->spacetype) {
- case SPACE_NODE:
- scene_unlink_space_node((SpaceNode *)space_link, sce);
- break;
- case SPACE_BUTS:
- scene_unlink_space_buts((SpaceButs *)space_link, sce);
- break;
- }
- }
}
+
+ /* editors are handled by WM_main_remove_editor_id_reference */
}
BKE_libblock_free(bmain, sce);
@@ -1196,6 +1172,7 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra)
scene->r.cfra = (int)intpart;
}
+#ifdef WITH_LEGACY_DEPSGRAPH
/* drivers support/hacks
* - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render
* - these are always run since the depsgraph can't handle non-object data
@@ -1296,6 +1273,7 @@ static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scen
}
}
}
+#endif /* WITH_LEGACY_DEPSGRAPH */
/* That's like really a bummer, because currently animation data for armatures
* might want to use pose, and pose might be missing on the object.
@@ -1325,6 +1303,7 @@ static void scene_armature_depsgraph_workaround(Main *bmain)
}
#endif
+#ifdef WITH_LEGACY_DEPSGRAPH
static void scene_rebuild_rbw_recursive(Scene *scene, float ctime)
{
if (scene->set)
@@ -1342,12 +1321,18 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
if (BKE_scene_check_rigidbody_active(scene))
BKE_rigidbody_do_simulation(scene, ctime);
}
+#endif
/* Used to visualize CPU threads activity during threaded object update,
* would pollute STDERR with whole bunch of timing information which then
* could be parsed and nicely visualized.
*/
-#undef DETAILED_ANALYSIS_OUTPUT
+#ifdef WITH_LEGACY_DEPSGRAPH
+# undef DETAILED_ANALYSIS_OUTPUT
+#else
+/* ALWAYS KEEY DISABLED! */
+# undef DETAILED_ANALYSIS_OUTPUT
+#endif
/* Mballs evaluation uses BKE_scene_base_iter_next which calls
* duplilist for all objects in the scene. This leads to conflict
@@ -1359,6 +1344,7 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
*/
#define MBALL_SINGLETHREAD_HACK
+#ifdef WITH_LEGACY_DEPSGRAPH
typedef struct StatisicsEntry {
struct StatisicsEntry *next, *prev;
Object *object;
@@ -1595,6 +1581,9 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
#endif
task_pool = BLI_task_pool_create(task_scheduler, &state);
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ BLI_pool_set_num_threads(task_pool, 1);
+ }
DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool);
BLI_task_pool_work_and_wait(task_pool);
@@ -1648,6 +1637,7 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma
BKE_mask_update_scene(bmain, scene);
}
+#endif /* WITH_LEGACY_DEPSGRAPH */
static bool check_rendered_viewport_visible(Main *bmain)
{
@@ -1699,13 +1689,26 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
{
Scene *sce_iter;
-
+#ifdef WITH_LEGACY_DEPSGRAPH
+ bool use_new_eval = !DEG_depsgraph_use_legacy();
+#endif
+
/* keep this first */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
/* (re-)build dependency graph if needed */
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
+ for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) {
DAG_scene_relations_update(bmain, sce_iter);
+ /* Uncomment this to check if graph was properly tagged for update. */
+#if 0
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval)
+#endif
+ {
+ DAG_scene_relations_validate(bmain, sce_iter);
+ }
+#endif
+ }
/* flush editing data if needed */
prepare_mesh_for_viewport_render(bmain, scene);
@@ -1726,7 +1729,17 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
*
* in the future this should handle updates for all datablocks, not
* only objects and scenes. - brecht */
- scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval) {
+ DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
+ }
+ else {
+ scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
+ }
+#else
+ DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
+#endif
+
/* update sound system animation (TODO, move to depsgraph) */
BKE_sound_update_scene(bmain, scene);
@@ -1744,7 +1757,8 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
* Need to do this so changing material settings from the graph/dopesheet
* will update stuff in the viewport.
*/
- if (DAG_id_type_tagged(bmain, ID_MA)) {
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) {
Material *material;
float ctime = BKE_scene_frame_get(scene);
@@ -1759,7 +1773,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
/* Also do the same for node trees. */
- if (DAG_id_type_tagged(bmain, ID_NT)) {
+ if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) {
float ctime = BKE_scene_frame_get(scene);
FOREACH_NODETREE(bmain, ntree, id)
@@ -1770,9 +1784,12 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
FOREACH_NODETREE_END
}
+#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST);
+
+ /* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, scene, false);
/* clear recalc flags */
@@ -1792,6 +1809,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
#ifdef DETAILED_ANALYSIS_OUTPUT
double start_time = PIL_check_seconds_timer();
#endif
+#ifdef WITH_LEGACY_DEPSGRAPH
+ bool use_new_eval = !DEG_depsgraph_use_legacy();
+#else
+ /* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */
+ (void) do_invisible_flush;
+#endif
/* keep this first */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
@@ -1801,12 +1824,16 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* call this at the start so modifiers with textures don't lag 1 frame */
BKE_image_update_frame(bmain, sce->r.cfra);
+#ifdef WITH_LEGACY_DEPSGRAPH
/* rebuild rigid body worlds before doing the actual frame update
* this needs to be done on start frame but animation playback usually starts one frame later
* we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
*/
- scene_rebuild_rbw_recursive(sce, ctime);
-
+ if (!use_new_eval) {
+ scene_rebuild_rbw_recursive(sce, ctime);
+ }
+#endif
+
BKE_sound_set_cfra(sce->r.cfra);
/* clear animation overrides */
@@ -1815,14 +1842,18 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
DAG_scene_relations_update(bmain, sce_iter);
- /* flush recalc flags to dependencies, if we were only changing a frame
- * this would not be necessary, but if a user or a script has modified
- * some datablock before BKE_scene_update_tagged was called, we need the flush */
- DAG_ids_flush_tagged(bmain);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ /* flush recalc flags to dependencies, if we were only changing a frame
+ * this would not be necessary, but if a user or a script has modified
+ * some datablock before BKE_scene_update_tagged was called, we need the flush */
+ DAG_ids_flush_tagged(bmain);
- /* Following 2 functions are recursive
- * so don't call within 'scene_update_tagged_recursive' */
- DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
+ /* Following 2 functions are recursive
+ * so don't call within 'scene_update_tagged_recursive' */
+ DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
+ }
+#endif
BKE_mask_evaluate_all_masks(bmain, ctime, true);
@@ -1836,8 +1867,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* can be overridden by settings from Scene, which owns the Texture through a hierarchy
* such as Scene->World->MTex/Texture) can still get correctly overridden.
*/
- BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
- /*...done with recursive funcs */
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
+ /*...done with recursive funcs */
+ }
+#endif
/* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later
* when trying to find materials with drivers that need evaluating [#32017]
@@ -1847,19 +1882,38 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
/* run rigidbody sim */
/* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
- scene_do_rb_simulation_recursive(sce, ctime);
-
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ scene_do_rb_simulation_recursive(sce, ctime);
+ }
+#endif
+
/* BKE_object_handle_update() on all objects, groups and sets */
- scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval) {
+ DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
+ }
+ else {
+ scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
+ }
+#else
+ DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
+#endif
+
/* update sound system animation (TODO, move to depsgraph) */
BKE_sound_update_scene(bmain, sce);
- scene_depsgraph_hack(eval_ctx, sce, sce);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ scene_depsgraph_hack(eval_ctx, sce, sce);
+ }
+#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST);
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST);
+ /* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, sce, true);
/* clear recalc flags */
@@ -1968,20 +2022,30 @@ bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv)
/* render simplification */
-int get_render_subsurf_level(const RenderData *r, int lvl)
+int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render)
{
- if (r->mode & R_SIMPLIFY)
- return min_ii(r->simplify_subsurf, lvl);
- else
+ if (r->mode & R_SIMPLIFY) {
+ if (for_render)
+ return min_ii(r->simplify_subsurf_render, lvl);
+ else
+ return min_ii(r->simplify_subsurf, lvl);
+ }
+ else {
return lvl;
+ }
}
-int get_render_child_particle_number(const RenderData *r, int num)
+int get_render_child_particle_number(const RenderData *r, int num, bool for_render)
{
- if (r->mode & R_SIMPLIFY)
- return (int)(r->simplify_particles * num);
- else
+ if (r->mode & R_SIMPLIFY) {
+ if (for_render)
+ return (int)(r->simplify_particles_render * num);
+ else
+ return (int)(r->simplify_particles * num);
+ }
+ else {
return num;
+ }
}
int get_render_shadow_samples(const RenderData *r, int samples)
@@ -2030,6 +2094,12 @@ bool BKE_scene_use_new_shading_nodes(const Scene *scene)
return (type && type->flag & RE_USE_SHADING_NODES);
}
+bool BKE_scene_use_shading_nodes_custom(Scene *scene)
+{
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
+}
+
bool BKE_scene_uses_blender_internal(const Scene *scene)
{
return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER);
@@ -2148,11 +2218,13 @@ size_t BKE_scene_multiview_num_views_get(const RenderData *rd)
return 1;
if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
- if (BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name))) {
+ srv = BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
+ if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
totviews++;
}
- if (BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name))) {
+ srv = BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
+ if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
totviews++;
}
}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 3c43bfa2920..4125a35cb33 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -272,6 +272,19 @@ void BKE_spacedata_draw_locks(int set)
}
}
+static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL;
+
+void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *))
+{
+ spacedata_id_unref_cb = func;
+}
+
+void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id)
+{
+ if (spacedata_id_unref_cb) {
+ spacedata_id_unref_cb(sl, id);
+ }
+}
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
@@ -405,6 +418,23 @@ ARegion *BKE_area_find_region_active_win(ScrArea *sa)
return NULL;
}
+ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y)
+{
+ ARegion *ar_found = NULL;
+ if (sa) {
+ ARegion *ar;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) {
+ if (BLI_rcti_isect_pt(&ar->winrct, x, y)) {
+ ar_found = ar;
+ break;
+ }
+ }
+ }
+ }
+ return ar_found;
+}
+
/**
* \note, ideally we can get the area from the context,
* there are a few places however where this isn't practical.
@@ -488,6 +518,23 @@ unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const stru
return BKE_screen_view3d_layer_active_ex(v3d, scene, true);
}
+/**
+ * Accumulate all visible layers on this screen.
+ */
+unsigned int BKE_screen_view3d_layer_all(const bScreen *sc)
+{
+ const ScrArea *sa;
+ unsigned int lay = 0;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = sa->spacedata.first;
+ lay |= v3d->lay;
+ }
+ }
+
+ return lay;
+}
+
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
{
int bit;
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 535dcd6ba4d..d4d64af6c94 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -254,15 +254,15 @@ void BKE_sequence_free_anim(Sequence *seq)
{
while (seq->anims.last) {
StripAnim *sanim = seq->anims.last;
- BLI_remlink(&seq->anims, sanim);
if (sanim->anim) {
IMB_free_anim(sanim->anim);
sanim->anim = NULL;
}
- MEM_freeN(sanim);
+ BLI_freelinkN(&seq->anims, sanim);
}
+ BLI_listbase_clear(&seq->anims);
}
/* cache must be freed before calling this function
@@ -1737,6 +1737,7 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) {
ibuf = IMB_dupImBuf(ibuf_tmp);
+ IMB_metadata_copy(ibuf, ibuf_tmp);
IMB_freeImBuf(ibuf_tmp);
IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
}
@@ -2423,6 +2424,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa
IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy);
sequencer_imbuf_assign_spaces(scene, i);
+ IMB_metadata_copy(i, ibuf);
IMB_freeImBuf(ibuf);
ibuf = i;
@@ -2474,6 +2476,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa
ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, ibuf, cfra);
if (ibuf_new != ibuf) {
+ IMB_metadata_copy(ibuf_new, ibuf);
IMB_freeImBuf(ibuf);
ibuf = ibuf_new;
}
@@ -2496,6 +2499,7 @@ static ImBuf *copy_from_ibuf_still(const SeqRenderData *context, Sequence *seq,
if (ibuf) {
rval = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(rval, ibuf);
IMB_freeImBuf(ibuf);
}
@@ -2509,9 +2513,11 @@ static void copy_to_ibuf_still(const SeqRenderData *context, Sequence *seq, floa
/* we have to store a copy, since the passed ibuf
* could be preprocessed afterwards (thereby silently
* changing the cached image... */
- ibuf = IMB_dupImBuf(ibuf);
+ ImBuf *oibuf = ibuf;
+ ibuf = IMB_dupImBuf(oibuf);
if (ibuf) {
+ IMB_metadata_copy(ibuf, oibuf);
sequencer_imbuf_assign_spaces(context->scene, ibuf);
}
@@ -2721,7 +2727,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq
BLI_path_abs(name, G.main->name);
}
- flag = IB_rect;
+ flag = IB_rect | IB_metadata;
if (seq->alpha_mode == SEQ_ALPHA_PREMUL)
flag |= IB_alphamode_premul;
@@ -3583,6 +3589,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+ IMB_metadata_copy(out, ibuf2);
+
IMB_freeImBuf(ibuf1);
IMB_freeImBuf(ibuf2);
}
@@ -4640,7 +4648,7 @@ static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char
char name_esc[SEQ_NAME_MAXSTR * 2];
BLI_strescape(name_esc, name, sizeof(name_esc));
- return BLI_snprintf(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
+ return BLI_snprintf_rlen(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
}
/* XXX - hackish function needed for transforming strips! TODO - have some better solution */
@@ -4974,7 +4982,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
- if (sound == NULL || sound->playback_handle == NULL) {
+ if (sound->playback_handle == NULL) {
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 069f9136a1f..fdff858eeb0 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -269,7 +269,7 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *
}
/* apply object scale */
for (i = 0; i < 3; i++) {
- size[i] = fabs(size[i] * ob->size[i]);
+ size[i] = fabsf(size[i] * ob->size[i]);
}
copy_v3_v3(sds->global_size, size);
copy_v3_v3(sds->dp0, min);
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 3cc2337d4f1..607f89699a4 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1035,6 +1035,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
#if 0 /* UNUSED */
@@ -1076,6 +1077,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U
}
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1114,6 +1116,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MVert *mvert= NULL;
@@ -1177,6 +1180,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float
} /* if (mvert) */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1206,6 +1210,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MFace *mface= NULL;
@@ -1315,6 +1320,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl
}/* while a */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1434,6 +1440,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MFace *mface= NULL;
@@ -1555,6 +1562,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
}/* while a */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1762,6 +1770,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MFace *mface= NULL;
@@ -1799,7 +1808,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
else {
/*aye that should be cached*/
printf("missing cache error\n");
- BLI_ghashIterator_step(ihash);
+ BLI_ghashIterator_step(ihash);
continue;
}
@@ -1917,16 +1926,16 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
if (facedist > outerfacethickness*ff)
force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness);
*damp=ob->pd->pdef_sbdamp;
- if (facedist > 0.0f) {
- *damp *= (1.0f - facedist/outerfacethickness);
- Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect);
- deflected = 3;
+ if (facedist > 0.0f) {
+ *damp *= (1.0f - facedist/outerfacethickness);
+ Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect);
+ deflected = 3;
- }
- else {
- Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect);
- if (deflected < 2) deflected = 2;
- }
+ }
+ else {
+ Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect);
+ if (deflected < 2) deflected = 2;
+ }
if ((mprevvert) && (*damp > 0.0f)) {
choose_winner(ve, opco, nv1, nv3, nv4, vv1, vv3, vv4);
@@ -1997,6 +2006,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
}/* while a */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
if (deflected == 1) { // no face but 'outer' edge cylinder sees vert
@@ -2335,14 +2345,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
float kd = 1.0f;
if (sb_deflect_face(ob, bp->pos, facenormal, defforce, &cf, timenow, vel, &intrusion)) {
- if (intrusion < 0.0f) {
- sb->scratch->flag |= SBF_DOFUZZY;
- bp->loc_flag |= SBF_DOFUZZY;
- bp->choke = sb->choke*0.01f;
- }
+ if (intrusion < 0.0f) {
+ sb->scratch->flag |= SBF_DOFUZZY;
+ bp->loc_flag |= SBF_DOFUZZY;
+ bp->choke = sb->choke*0.01f;
+ }
- sub_v3_v3v3(cfforce, bp->vec, vel);
- Vec3PlusStVec(bp->force, -cf*50.0f, cfforce);
+ sub_v3_v3v3(cfforce, bp->vec, vel);
+ Vec3PlusStVec(bp->force, -cf*50.0f, cfforce);
Vec3PlusStVec(bp->force, kd, defforce);
}
@@ -3484,7 +3494,7 @@ static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff, Object
bs->v1 = bpc;
bs->v2 = bpc+dw+dv-1;
bs->springtype=SB_BEND;
- bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob);
+ bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob);
bs++;
}
}
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 6a831d23aea..46a50917427 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -66,7 +66,7 @@ static int sound_cfra;
bSound *BKE_sound_new_file(struct Main *bmain, const char *filename)
{
- bSound *sound = NULL;
+ bSound *sound;
char str[FILE_MAX];
const char *path;
@@ -89,11 +89,6 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filename)
BKE_sound_load(bmain, sound);
- if (!sound->playback_handle) {
- BKE_libblock_free(bmain, sound);
- sound = NULL;
- }
-
return sound;
}
@@ -144,8 +139,8 @@ static void sound_sync_callback(void *data, int mode, float time)
BKE_sound_play_scene(scene);
else
BKE_sound_stop_scene(scene);
- if (scene->sound_scene_handle)
- AUD_seek(scene->sound_scene_handle, time);
+ if (scene->playback_handle)
+ AUD_seek(scene->playback_handle, time);
}
scene = scene->id.next;
}
@@ -246,12 +241,6 @@ bSound *BKE_sound_new_buffer(struct Main *bmain, bSound *source)
sound_load(bmain, sound);
- if (!sound->playback_handle)
- {
- BKE_libblock_free(bmain, sound);
- sound = NULL;
- }
-
return sound;
}
@@ -272,12 +261,6 @@ bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, f
sound_load(bmain, sound);
- if (!sound->playback_handle)
- {
- BKE_libblock_free(bmain, sound);
- sound = NULL;
- }
-
return sound;
}
#endif
@@ -400,15 +383,15 @@ void BKE_sound_create_scene(struct Scene *scene)
scene->sound_scene = AUD_createSequencer(FPS, scene->audio.flag & AUDIO_MUTE);
AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound,
scene->audio.doppler_factor, scene->audio.distance_model);
- scene->sound_scene_handle = NULL;
+ scene->playback_handle = NULL;
scene->sound_scrub_handle = NULL;
scene->speaker_handles = NULL;
}
void BKE_sound_destroy_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle)
- AUD_stop(scene->sound_scene_handle);
+ if (scene->playback_handle)
+ AUD_stop(scene->playback_handle);
if (scene->sound_scrub_handle)
AUD_stop(scene->sound_scrub_handle);
if (scene->sound_scene)
@@ -541,13 +524,13 @@ void BKE_sound_update_sequencer(struct Main *main, bSound *sound)
static void sound_start_play_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle)
- AUD_stop(scene->sound_scene_handle);
+ if (scene->playback_handle)
+ AUD_stop(scene->playback_handle);
AUD_setSequencerDeviceSpecs(scene->sound_scene);
- if ((scene->sound_scene_handle = AUD_play(scene->sound_scene, 1)))
- AUD_setLoop(scene->sound_scene_handle, -1);
+ if ((scene->playback_handle = AUD_play(scene->sound_scene, 1)))
+ AUD_setLoop(scene->playback_handle, -1);
}
void BKE_sound_play_scene(struct Scene *scene)
@@ -557,20 +540,20 @@ void BKE_sound_play_scene(struct Scene *scene)
AUD_lock();
- status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID;
+ status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID;
if (status == AUD_STATUS_INVALID) {
sound_start_play_scene(scene);
- if (!scene->sound_scene_handle) {
+ if (!scene->playback_handle) {
AUD_unlock();
return;
}
}
if (status != AUD_STATUS_PLAYING) {
- AUD_seek(scene->sound_scene_handle, cur_time);
- AUD_resume(scene->sound_scene_handle);
+ AUD_seek(scene->playback_handle, cur_time);
+ AUD_resume(scene->playback_handle);
}
if (scene->audio.flag & AUDIO_SYNC)
@@ -581,8 +564,8 @@ void BKE_sound_play_scene(struct Scene *scene)
void BKE_sound_stop_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle) {
- AUD_pause(scene->sound_scene_handle);
+ if (scene->playback_handle) {
+ AUD_pause(scene->playback_handle);
if (scene->audio.flag & AUDIO_SYNC)
AUD_stopPlayback();
@@ -600,17 +583,17 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
AUD_lock();
- status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID;
+ status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID;
if (status == AUD_STATUS_INVALID) {
sound_start_play_scene(scene);
- if (!scene->sound_scene_handle) {
+ if (!scene->playback_handle) {
AUD_unlock();
return;
}
- AUD_pause(scene->sound_scene_handle);
+ AUD_pause(scene->playback_handle);
}
animation_playing = 0;
@@ -623,13 +606,13 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
if (scene->audio.flag & AUDIO_SCRUB && !animation_playing) {
if (scene->audio.flag & AUDIO_SYNC) {
- AUD_seek(scene->sound_scene_handle, cur_time);
- AUD_seekSequencer(scene->sound_scene_handle, cur_time);
+ AUD_seek(scene->playback_handle, cur_time);
+ AUD_seekSequencer(scene->playback_handle, cur_time);
}
else {
- AUD_seek(scene->sound_scene_handle, cur_time);
+ AUD_seek(scene->playback_handle, cur_time);
}
- AUD_resume(scene->sound_scene_handle);
+ AUD_resume(scene->playback_handle);
if (scene->sound_scrub_handle && AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) {
AUD_seek(scene->sound_scrub_handle, 0);
}
@@ -637,16 +620,16 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
if (scene->sound_scrub_handle) {
AUD_stop(scene->sound_scrub_handle);
}
- scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, one_frame);
+ scene->sound_scrub_handle = AUD_pauseAfter(scene->playback_handle, one_frame);
}
}
else {
if (scene->audio.flag & AUDIO_SYNC) {
- AUD_seekSequencer(scene->sound_scene_handle, cur_time);
+ AUD_seekSequencer(scene->playback_handle, cur_time);
}
else {
if (status == AUD_STATUS_PLAYING) {
- AUD_seek(scene->sound_scene_handle, cur_time);
+ AUD_seek(scene->playback_handle, cur_time);
}
}
}
@@ -656,11 +639,11 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
float BKE_sound_sync_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle) {
+ if (scene->playback_handle) {
if (scene->audio.flag & AUDIO_SYNC)
- return AUD_getSequencerPosition(scene->sound_scene_handle);
+ return AUD_getSequencerPosition(scene->playback_handle);
else
- return AUD_getPosition(scene->sound_scene_handle);
+ return AUD_getPosition(scene->playback_handle);
}
return NAN_FLT;
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index a4e0eaaa324..e8bca50c3d7 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -300,7 +300,11 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */
limit[0] = limit[1] = STD_UV_CONNECT_LIMIT;
- vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, 0, limit);
+ /* previous behavior here is without accounting for winding, however this causes stretching in
+ * UV map in really simple cases with mirror + subsurf, see second part of T44530. Also, initially
+ * intention is to treat merged vertices from mirror modifier as seams, see code below with ME_VERT_MERGED
+ * This fixes a very old regression (2.49 was correct here) */
+ vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, limit, false, true);
if (!vmap)
return 0;
@@ -2796,7 +2800,6 @@ static void ccgDM_release(DerivedMesh *dm)
if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap);
if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces);
if (ccgdm->gridData) MEM_freeN(ccgdm->gridData);
- if (ccgdm->gridAdjacency) MEM_freeN(ccgdm->gridAdjacency);
if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset);
if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats);
if (ccgdm->gridHidden) {
@@ -3107,46 +3110,11 @@ static int ccgDM_getGridSize(DerivedMesh *dm)
return ccgSubSurf_getGridSize(ccgdm->ss);
}
-static int ccgdm_adjacent_grid(int *gridOffset, CCGFace *f, int S, int offset)
-{
- CCGFace *adjf;
- CCGEdge *e;
- int i, j = 0, numFaces, fIndex, numEdges = 0;
-
- e = ccgSubSurf_getFaceEdge(f, S);
- numFaces = ccgSubSurf_getEdgeNumFaces(e);
-
- if (numFaces != 2)
- return -1;
-
- for (i = 0; i < numFaces; i++) {
- adjf = ccgSubSurf_getEdgeFace(e, i);
-
- if (adjf != f) {
- numEdges = ccgSubSurf_getFaceNumVerts(adjf);
- for (j = 0; j < numEdges; j++)
- if (ccgSubSurf_getFaceEdge(adjf, j) == e)
- break;
-
- if (j != numEdges)
- break;
- }
- }
-
- if (numEdges == 0)
- return -1;
-
- fIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(adjf));
-
- return gridOffset[fIndex] + (j + offset) % numEdges;
-}
-
static void ccgdm_create_grids(DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
CCGSubSurf *ss = ccgdm->ss;
CCGElem **gridData;
- DMGridAdjacency *gridAdjacency, *adj;
DMFlagMat *gridFlagMats;
CCGFace **gridFaces;
int *gridOffset;
@@ -3172,7 +3140,6 @@ static void ccgdm_create_grids(DerivedMesh *dm)
/* compute grid data */
gridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "ccgdm.gridData");
- gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency) * numGrids, "ccgdm.gridAdjacency");
gridFaces = MEM_mallocN(sizeof(CCGFace *) * numGrids, "ccgdm.gridFaces");
gridFlagMats = MEM_mallocN(sizeof(DMFlagMat) * numGrids, "ccgdm.gridFlagMats");
@@ -3183,29 +3150,14 @@ static void ccgdm_create_grids(DerivedMesh *dm)
int numVerts = ccgSubSurf_getFaceNumVerts(f);
for (S = 0; S < numVerts; S++, gIndex++) {
- int prevS = (S - 1 + numVerts) % numVerts;
- int nextS = (S + 1 + numVerts) % numVerts;
-
gridData[gIndex] = ccgSubSurf_getFaceGridDataArray(ss, f, S);
gridFaces[gIndex] = f;
gridFlagMats[gIndex] = ccgdm->faceFlags[index];
-
- adj = &gridAdjacency[gIndex];
-
- adj->index[0] = gIndex - S + nextS;
- adj->rotation[0] = 3;
- adj->index[1] = ccgdm_adjacent_grid(gridOffset, f, prevS, 0);
- adj->rotation[1] = 1;
- adj->index[2] = ccgdm_adjacent_grid(gridOffset, f, S, 1);
- adj->rotation[2] = 3;
- adj->index[3] = gIndex - S + prevS;
- adj->rotation[3] = 1;
}
}
ccgdm->gridData = gridData;
ccgdm->gridFaces = gridFaces;
- ccgdm->gridAdjacency = gridAdjacency;
ccgdm->gridOffset = gridOffset;
ccgdm->gridFlagMats = gridFlagMats;
}
@@ -3218,14 +3170,6 @@ static CCGElem **ccgDM_getGridData(DerivedMesh *dm)
return ccgdm->gridData;
}
-static DMGridAdjacency *ccgDM_getGridAdjacency(DerivedMesh *dm)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
-
- ccgdm_create_grids(dm);
- return ccgdm->gridAdjacency;
-}
-
static int *ccgDM_getGridOffset(DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
@@ -3308,7 +3252,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
* when the ccgdm gets remade, the assumption is that the topology
* does not change. */
ccgdm_create_grids(dm);
- BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces,
+ BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces,
ccgdm->gridFlagMats, ccgdm->gridHidden);
}
@@ -3327,7 +3271,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
numGrids = ccgDM_getNumGrids(dm);
ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new();
- BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency,
+ BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData,
numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden);
}
else if (ob->type == OB_MESH) {
@@ -3455,7 +3399,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
ccgdm->dm.getGridSize = ccgDM_getGridSize;
ccgdm->dm.getGridData = ccgDM_getGridData;
- ccgdm->dm.getGridAdjacency = ccgDM_getGridAdjacency;
ccgdm->dm.getGridOffset = ccgDM_getGridOffset;
ccgdm->dm.getGridKey = ccgDM_getGridKey;
ccgdm->dm.getGridFlagMats = ccgDM_getGridFlagMats;
@@ -3820,7 +3763,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
SubsurfFlags flags)
{
int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
- CCGFlags useAging = smd->flags & eSubsurfModifierFlag_DebugIncr ? CCG_USE_AGING : 0;
+ CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
CCGDerivedMesh *result;
@@ -3828,7 +3771,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
/* note: editmode calculation can only run once per
* modifier stack evaluation (uses freed cache) [#36299] */
if (flags & SUBSURF_FOR_EDIT_MODE) {
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels;
+ int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple);
@@ -3840,7 +3783,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
else if (flags & SUBSURF_USE_RENDER_PARAMS) {
/* Do not use cache in render mode. */
CCGSubSurf *ss;
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels) : smd->renderLevels;
+ int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels;
if (levels == 0)
return dm;
@@ -3856,7 +3799,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
}
else {
int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels;
+ int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
CCGSubSurf *ss;
/* It is quite possible there is a much better place to do this. It
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 9f441b45db9..89456763b95 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -330,7 +330,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len
text->curc = text->selc = 0;
}
-int BKE_text_reload(Text *text)
+bool BKE_text_reload(Text *text)
{
FILE *fp;
int len;
@@ -339,13 +339,24 @@ int BKE_text_reload(Text *text)
char str[FILE_MAX];
BLI_stat_t st;
- if (!text->name) return 0;
-
+ if (!text->name) {
+ return false;
+ }
+
BLI_strncpy(str, text->name, FILE_MAX);
BLI_path_abs(str, G.main->name);
fp = BLI_fopen(str, "r");
- if (fp == NULL) return 0;
+ if (fp == NULL) {
+ return false;
+ }
+ fseek(fp, 0L, SEEK_END);
+ len = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+ if (UNLIKELY(len == -1)) {
+ fclose(fp);
+ return false;
+ }
/* free memory: */
@@ -363,11 +374,6 @@ int BKE_text_reload(Text *text)
MEM_freeN(text->undo_buf);
init_undo_text(text);
- fseek(fp, 0L, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
-
-
buffer = MEM_mallocN(len, "text_buffer");
/* under windows fread can return less than len bytes because
* of CR stripping */
@@ -385,7 +391,7 @@ int BKE_text_reload(Text *text)
text_from_buf(text, buffer, len);
MEM_freeN(buffer);
- return 1;
+ return true;
}
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
@@ -402,8 +408,18 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
BLI_path_abs(str, relpath);
fp = BLI_fopen(str, "r");
- if (fp == NULL) return NULL;
-
+ if (fp == NULL) {
+ return NULL;
+ }
+
+ fseek(fp, 0L, SEEK_END);
+ len = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+ if (UNLIKELY(len == -1)) {
+ fclose(fp);
+ return NULL;
+ }
+
ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(str));
ta->id.us = 1;
@@ -423,10 +439,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
/* clear undo buffer */
init_undo_text(ta);
-
- fseek(fp, 0L, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
buffer = MEM_mallocN(len, "text_buffer");
/* under windows fread can return less than len bytes because
@@ -473,6 +485,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
BLI_listbase_clear(&tan->lines);
tan->curl = tan->sell = NULL;
+ tan->compiled = NULL;
tan->nlines = ta->nlines;
@@ -651,7 +664,7 @@ void BKE_text_unlink(Main *bmain, Text *text)
}
}
- /* Freestyle (while looping oer the scene) */
+ /* Freestyle (while looping over the scene) */
for (srl = sce->r.layers.first; srl; srl = srl->next) {
for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
if (module->script == text)
@@ -1895,6 +1908,47 @@ static void txt_undo_add_charop(Text *text, int op_start, unsigned int c)
text->undo_buf[text->undo_pos + 1] = 0;
}
+/* extends Link */
+struct LinkInt {
+ struct LinkInt *next, *prev;
+ int value;
+};
+
+/* unindentLines points to a ListBase composed of LinkInt elements, listing the numbers
+ * of the lines that should not be indented back. */
+static void txt_undo_add_unindent_op(Text *text, const ListBase *line_index_mask, const int line_index_mask_len)
+{
+ struct LinkInt *idata;
+
+ BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len);
+
+ /* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */
+ if (!max_undo_test(text, 1 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) {
+ return;
+ }
+
+ /* Opening buffer sequence with OP */
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos] = UNDO_UNINDENT;
+ text->undo_pos++;
+ /* Adding number of line numbers to read */
+ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
+
+ /* Adding linenumbers of lines that shall not be indented if undoing */
+ for (idata = line_index_mask->first; idata; idata = idata->next) {
+ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, idata->value);
+ }
+
+ /* Adding number of line numbers to read again */
+ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
+ /* Adding current selection */
+ txt_undo_store_cursors(text);
+ /* Closing with OP (same as above) */
+ text->undo_buf[text->undo_pos] = UNDO_UNINDENT;
+ /* Marking as last undo operation */
+ text->undo_buf[text->undo_pos + 1] = 0;
+}
+
static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos)
{
unsigned short val;
@@ -2189,7 +2243,6 @@ void txt_do_undo(Text *text)
text->undo_pos--;
break;
case UNDO_INDENT:
- case UNDO_UNINDENT:
case UNDO_COMMENT:
case UNDO_UNCOMMENT:
case UNDO_DUPLICATE:
@@ -2203,9 +2256,6 @@ void txt_do_undo(Text *text)
if (op == UNDO_INDENT) {
txt_unindent(text);
}
- else if (op == UNDO_UNINDENT) {
- txt_indent(text);
- }
else if (op == UNDO_COMMENT) {
txt_uncomment(text);
}
@@ -2224,6 +2274,37 @@ void txt_do_undo(Text *text)
text->undo_pos--;
break;
+ case UNDO_UNINDENT:
+ {
+ int count;
+ int i;
+ /* Get and restore the cursors */
+ txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ /* Un-unindent */
+ txt_indent(text);
+
+ /* Get the count */
+ count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ /* Iterate! */
+ txt_pop_sel(text);
+
+ for (i = 0; i < count; i++) {
+ txt_move_to(text, txt_undo_read_uint32(text->undo_buf, &text->undo_pos), 0, 0);
+ /* Un-un-unindent */
+ txt_unindent(text);
+ }
+ /* Restore selection */
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+ /* Jumo over count */
+ txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ /* Jump over closing OP byte */
+ text->undo_pos--;
+ break;
+ }
default:
//XXX error("Undo buffer error - resetting");
text->undo_pos = -1;
@@ -2353,7 +2434,6 @@ void txt_do_redo(Text *text)
break;
case UNDO_INDENT:
- case UNDO_UNINDENT:
case UNDO_COMMENT:
case UNDO_UNCOMMENT:
case UNDO_DUPLICATE:
@@ -2369,9 +2449,6 @@ void txt_do_redo(Text *text)
if (op == UNDO_INDENT) {
txt_indent(text);
}
- else if (op == UNDO_UNINDENT) {
- txt_unindent(text);
- }
else if (op == UNDO_COMMENT) {
txt_comment(text);
}
@@ -2401,6 +2478,26 @@ void txt_do_redo(Text *text)
txt_move_to(text, selln, selc, 1);
break;
+ case UNDO_UNINDENT:
+ {
+ int count;
+ int i;
+
+ text->undo_pos++;
+ /* Scan all the stuff described in txt_undo_add_unindent_op */
+ count = txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ for (i = 0; i < count; i++) {
+ txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ }
+ /* Count again */
+ txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ /* Get the selection and re-unindent */
+ txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+ txt_unindent(text);
+ break;
+ }
default:
//XXX error("Undo buffer error - resetting");
text->undo_pos = -1;
@@ -2801,6 +2898,12 @@ void txt_unindent(Text *text)
int indentlen = 1;
bool unindented_first = false;
+ /* List of lines that are already at indent level 0, to store them later into the undo buffer */
+ ListBase line_index_mask = {NULL, NULL};
+ int line_index_mask_len = 0;
+ int curl_span_init = 0;
+
+
/* hardcoded: TXT_TABSIZE = 4 spaces: */
int spaceslen = TXT_TABSIZE;
@@ -2814,6 +2917,10 @@ void txt_unindent(Text *text)
indentlen = spaceslen;
}
+ if (!undoing) {
+ curl_span_init = txt_get_span(text->lines.first, text->curl);
+ }
+
while (true) {
bool changed = false;
if (STREQLEN(text->curl->line, remove, indentlen)) {
@@ -2823,6 +2930,16 @@ void txt_unindent(Text *text)
memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1);
changed = true;
}
+ else {
+ if (!undoing) {
+ /* Create list element for 0 indent line */
+ struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__);
+ idata->value = curl_span_init + num;
+ BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl));
+ BLI_addtail(&line_index_mask, idata);
+ line_index_mask_len += 1;
+ }
+ }
txt_make_dirty(text);
txt_clean_text(text);
@@ -2835,6 +2952,7 @@ void txt_unindent(Text *text)
else {
text->curl = text->curl->next;
num++;
+
}
}
@@ -2848,8 +2966,10 @@ void txt_unindent(Text *text)
}
if (!undoing) {
- txt_undo_add_op(text, UNDO_UNINDENT);
+ txt_undo_add_unindent_op(text, &line_index_mask, line_index_mask_len);
}
+
+ BLI_freelistN(&line_index_mask);
}
void txt_comment(Text *text)
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 8e4fcc5d1cc..2ea903247b2 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -567,7 +567,7 @@ void BKE_texture_free(Tex *tex)
BKE_animdata_free((struct ID *)tex);
BKE_previewimg_free(&tex->preview);
- BKE_icon_delete((struct ID *)tex);
+ BKE_icon_id_delete((struct ID *)tex);
tex->id.icon_id = 0;
if (tex->nodetree) {
@@ -629,7 +629,7 @@ void BKE_texture_default(Tex *tex)
tex->env->stype = ENV_ANIM;
tex->env->clipsta = 0.1;
tex->env->clipend = 100;
- tex->env->cuberes = 600;
+ tex->env->cuberes = 512;
tex->env->depth = 0;
}
@@ -1423,7 +1423,7 @@ EnvMap *BKE_texture_envmap_add(void)
env->stype = ENV_ANIM;
env->clipsta = 0.1;
env->clipend = 100.0;
- env->cuberes = 600;
+ env->cuberes = 512;
env->viewscale = 0.5;
return env;
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 83db0639468..f9ae987db70 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -730,7 +730,7 @@ MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking, MovieT
return NULL;
}
-MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **tracksbase_r)
+MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **r_tracksbase)
{
MovieTrackingObject *object;
int cur = 1;
@@ -743,7 +743,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int
while (track) {
if (track->flag & TRACK_HAS_BUNDLE) {
if (cur == tracknr) {
- *tracksbase_r = tracksbase;
+ *r_tracksbase = tracksbase;
return track;
}
@@ -756,7 +756,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int
object = object->next;
}
- *tracksbase_r = NULL;
+ *r_tracksbase = NULL;
return NULL;
}
@@ -1302,6 +1302,95 @@ void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base)
}
}
+bool BKE_tracking_plane_track_has_point_track(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingTrack *track)
+{
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] == track) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_tracking_plane_track_remove_point_track(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingTrack *track)
+{
+ int i, track_index;
+ MovieTrackingTrack **new_point_tracks;
+
+ if (plane_track->point_tracksnr <= 4) {
+ return false;
+ }
+
+ new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * (plane_track->point_tracksnr - 1),
+ "new point tracks array");
+
+ for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] != track) {
+ new_point_tracks[track_index++] = plane_track->point_tracks[i];
+ }
+ }
+
+ MEM_freeN(plane_track->point_tracks);
+ plane_track->point_tracks = new_point_tracks;
+ plane_track->point_tracksnr--;
+
+ return true;
+}
+
+void BKE_tracking_plane_tracks_remove_point_track(MovieTracking *tracking,
+ MovieTrackingTrack *track)
+{
+ MovieTrackingPlaneTrack *plane_track, *next_plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = next_plane_track)
+ {
+ next_plane_track = plane_track->next;
+ if (BKE_tracking_plane_track_has_point_track(plane_track, track)) {
+ if (!BKE_tracking_plane_track_remove_point_track(plane_track, track)) {
+ /* Delete planes with less than 3 point tracks in it. */
+ BKE_tracking_plane_track_free(plane_track);
+ BLI_freelinkN(plane_tracks_base, plane_track);
+ }
+ }
+ }
+}
+
+void BKE_tracking_plane_track_replace_point_track(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingTrack *old_track,
+ MovieTrackingTrack *new_track)
+{
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] == old_track) {
+ plane_track->point_tracks[i] = new_track;
+ break;
+ }
+ }
+}
+
+void BKE_tracking_plane_tracks_replace_point_track(MovieTracking *tracking,
+ MovieTrackingTrack *old_track,
+ MovieTrackingTrack *new_track)
+{
+ MovieTrackingPlaneTrack *plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if (BKE_tracking_plane_track_has_point_track(plane_track, old_track)) {
+ BKE_tracking_plane_track_replace_point_track(plane_track,
+ old_track,
+ new_track);
+ }
+ }
+}
+
/*********************** Plane Marker *************************/
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track,
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 4cb3f2ca493..76261bddfbc 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -534,19 +534,9 @@ void BKE_autotrack_context_finish(AutoTrackContext *context)
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
int track;
for (track = 0; track < context->num_tracks; ++track) {
- MovieTrackingTrack *old_track;
- bool do_update = false;
- int j;
-
- old_track = context->options[track].track;
- for (j = 0; j < plane_track->point_tracksnr; j++) {
- if (plane_track->point_tracks[j] == old_track) {
- do_update = true;
- break;
- }
- }
-
- if (do_update) {
+ if (BKE_tracking_plane_track_has_point_track(plane_track,
+ context->options[track].track))
+ {
BKE_tracking_track_plane_from_existing_motion(
plane_track,
context->first_frame);
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 5a2c77b5619..0d83695d2f1 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -370,12 +370,7 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, bUn
value_conv = value / unit->scalar;
/* Convert to a string */
- {
- len = BLI_snprintf(str, len_max, "%.*f", prec, value_conv);
-
- if (len >= len_max)
- len = len_max;
- }
+ len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv);
/* Add unit prefix and strip zeros */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index f26cbf7880a..e4736b1f54c 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -74,7 +74,7 @@ void BKE_world_free_ex(World *wrld, bool do_id_user)
if (wrld->gpumaterial.first)
GPU_material_free(&wrld->gpumaterial);
- BKE_icon_delete((struct ID *)wrld);
+ BKE_icon_id_delete((struct ID *)wrld);
wrld->id.icon_id = 0;
}