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:
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c2
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c11
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c2055
-rw-r--r--source/blender/blenkernel/intern/action.c74
-rw-r--r--source/blender/blenkernel/intern/anim.c223
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c376
-rw-r--r--source/blender/blenkernel/intern/appdir.c4
-rw-r--r--source/blender/blenkernel/intern/armature.c79
-rw-r--r--source/blender/blenkernel/intern/armature_update.c84
-rw-r--r--source/blender/blenkernel/intern/blender.c23
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c19
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c5
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c114
-rw-r--r--source/blender/blenkernel/intern/blendfile.c113
-rw-r--r--source/blender/blenkernel/intern/boids.c3
-rw-r--r--source/blender/blenkernel/intern/bpath.c8
-rw-r--r--source/blender/blenkernel/intern/bullet.c99
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c446
-rw-r--r--source/blender/blenkernel/intern/cachefile.c37
-rw-r--r--source/blender/blenkernel/intern/camera.c122
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c1515
-rw-r--r--source/blender/blenkernel/intern/cloth.c115
-rw-r--r--source/blender/blenkernel/intern/collection.c1171
-rw-r--r--source/blender/blenkernel/intern/collision.c74
-rw-r--r--source/blender/blenkernel/intern/constraint.c246
-rw-r--r--source/blender/blenkernel/intern/context.c160
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c36
-rw-r--r--source/blender/blenkernel/intern/curve.c42
-rw-r--r--source/blender/blenkernel/intern/customdata.c144
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c407
-rw-r--r--source/blender/blenkernel/intern/deform.c3
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c3745
-rw-r--r--source/blender/blenkernel/intern/displist.c219
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c290
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c1433
-rw-r--r--source/blender/blenkernel/intern/editmesh.c22
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c431
-rw-r--r--source/blender/blenkernel/intern/effect.c283
-rw-r--r--source/blender/blenkernel/intern/fcurve.c17
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c4
-rw-r--r--source/blender/blenkernel/intern/font.c4
-rw-r--r--source/blender/blenkernel/intern/freestyle.c12
-rw-r--r--source/blender/blenkernel/intern/group.c379
-rw-r--r--source/blender/blenkernel/intern/icons.c214
-rw-r--r--source/blender/blenkernel/intern/icons_rasterize.c146
-rw-r--r--source/blender/blenkernel/intern/idcode.c11
-rw-r--r--source/blender/blenkernel/intern/idprop.c46
-rw-r--r--source/blender/blenkernel/intern/image.c208
-rw-r--r--source/blender/blenkernel/intern/ipo.c32
-rw-r--r--source/blender/blenkernel/intern/key.c8
-rw-r--r--source/blender/blenkernel/intern/lamp.c100
-rw-r--r--source/blender/blenkernel/intern/lattice.c114
-rw-r--r--source/blender/blenkernel/intern/layer.c1426
-rw-r--r--source/blender/blenkernel/intern/layer_utils.c125
-rw-r--r--source/blender/blenkernel/intern/library.c184
-rw-r--r--source/blender/blenkernel/intern/library_override.c771
-rw-r--r--source/blender/blenkernel/intern/library_query.c245
-rw-r--r--source/blender/blenkernel/intern/library_remap.c191
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c101
-rw-r--r--source/blender/blenkernel/intern/linestyle.c15
-rw-r--r--source/blender/blenkernel/intern/mask.c18
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c17
-rw-r--r--source/blender/blenkernel/intern/material.c1116
-rw-r--r--source/blender/blenkernel/intern/mball.c83
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c21
-rw-r--r--source/blender/blenkernel/intern/mesh.c405
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c498
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c228
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c154
-rw-r--r--source/blender/blenkernel/intern/mesh_merge.c684
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c197
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c376
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c691
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c104
-rw-r--r--source/blender/blenkernel/intern/modifier.c444
-rw-r--r--source/blender/blenkernel/intern/movieclip.c4
-rw-r--r--source/blender/blenkernel/intern/multires.c228
-rw-r--r--source/blender/blenkernel/intern/navmesh_conversion.c502
-rw-r--r--source/blender/blenkernel/intern/nla.c2
-rw-r--r--source/blender/blenkernel/intern/node.c162
-rw-r--r--source/blender/blenkernel/intern/object.c932
-rw-r--r--source/blender/blenkernel/intern/object_deform.c3
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c346
-rw-r--r--source/blender/blenkernel/intern/object_facemap.c257
-rw-r--r--source/blender/blenkernel/intern/object_update.c242
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c69
-rw-r--r--source/blender/blenkernel/intern/paint.c203
-rw-r--r--source/blender/blenkernel/intern/particle.c1074
-rw-r--r--source/blender/blenkernel/intern/particle_child.c42
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c472
-rw-r--r--source/blender/blenkernel/intern/particle_system.c279
-rw-r--r--source/blender/blenkernel/intern/pbvh.c133
-rw-r--r--source/blender/blenkernel/intern/pointcache.c71
-rw-r--r--source/blender/blenkernel/intern/property.c267
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c374
-rw-r--r--source/blender/blenkernel/intern/sca.c1179
-rw-r--r--source/blender/blenkernel/intern/scene.c1521
-rw-r--r--source/blender/blenkernel/intern/screen.c392
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c11
-rw-r--r--source/blender/blenkernel/intern/sequencer.c61
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c110
-rw-r--r--source/blender/blenkernel/intern/sketch.c555
-rw-r--r--source/blender/blenkernel/intern/smoke.c48
-rw-r--r--source/blender/blenkernel/intern/softbody.c185
-rw-r--r--source/blender/blenkernel/intern/sound.c168
-rw-r--r--source/blender/blenkernel/intern/studiolight.c1200
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2255
-rw-r--r--source/blender/blenkernel/intern/text.c3
-rw-r--r--source/blender/blenkernel/intern/texture.c439
-rw-r--r--source/blender/blenkernel/intern/tracking.c7
-rw-r--r--source/blender/blenkernel/intern/undo_system.c8
-rw-r--r--source/blender/blenkernel/intern/workspace.c536
-rw-r--r--source/blender/blenkernel/intern/world.c46
-rw-r--r--source/blender/blenkernel/intern/writeavi.c14
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c15
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c419
116 files changed, 16712 insertions, 21744 deletions
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index c6224da2fe0..81b1afa3621 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -42,7 +42,7 @@
# include "opensubdiv_converter_capi.h"
#endif
-#include "GL/glew.h"
+#include "GPU_glew.h"
/***/
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index f568bb94ac5..fc4220277eb 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -43,7 +43,7 @@
#include "opensubdiv_capi.h"
#include "opensubdiv_converter_capi.h"
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "GPU_extensions.h"
#define OSD_LOG if (false) printf
@@ -232,6 +232,9 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
CHECK_COMPUTE_TYPE(CUDA)
CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK)
CHECK_COMPUTE_TYPE(GLSL_COMPUTE)
+ default:
+ compute_type = OPENSUBDIV_EVALUATOR_CPU;
+ break;
#undef CHECK_COMPUTE_TYPE
}
@@ -540,7 +543,7 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
for (S = 0; S < face->numVerts; S++) {
int x, y, k;
CCGEdge *edge = NULL;
- bool inverse_edge;
+ bool inverse_edge = false;
for (x = 0; x < gridSize; x++) {
for (y = 0; y < gridSize; y++) {
@@ -739,7 +742,7 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
/* Evaluate edges. */
for (S = 0; S < face->numVerts; S++) {
CCGEdge *edge = FACE_getEdges(face)[S];
- int x, S0, S1;
+ int x, S0 = 0, S1 = 0;
bool flip;
for (x = 0; x < face->numVerts; ++x) {
@@ -995,7 +998,7 @@ void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs)
void BKE_subsurf_osd_init(void)
{
- openSubdiv_init(GPU_legacy_support());
+ openSubdiv_init();
BLI_spin_init(&delete_spin);
}
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 9c0fc79a358..19886738b00 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -55,11 +55,14 @@
#include "BKE_colorband.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_tangent.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
@@ -68,19 +71,12 @@
#include "BKE_deform.h"
#include "BKE_global.h" /* For debug flag, DM_update_tessface_data() func. */
-#ifdef WITH_GAMEENGINE
-#include "BKE_navmesh_conversion.h"
-static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
-#endif
-
#include "BLI_sys_types.h" /* for intptr_t support */
-#include "GPU_buffers.h"
-#include "GPU_glew.h"
-#include "GPU_shader.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#ifdef WITH_OPENSUBDIV
-# include "BKE_depsgraph.h"
# include "DNA_userdef_types.h"
#endif
@@ -89,17 +85,20 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#ifdef USE_MODIFIER_VALIDATE
# define ASSERT_IS_VALID_DM(dm) (BLI_assert((dm == NULL) || (DM_is_valid(dm) == true)))
+# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
#else
# define ASSERT_IS_VALID_DM(dm)
+# define ASSERT_IS_VALID_MESH(mesh)
#endif
static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
-static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob);
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
+static void mesh_init_origspace(Mesh *mesh);
+
/* -------------------------------------------------------------------- */
@@ -327,7 +326,7 @@ void DM_init_funcs(DerivedMesh *dm)
dm->getPolyDataArray = DM_get_poly_data_layer;
dm->getLoopDataArray = DM_get_loop_data_layer;
- bvhcache_init(&dm->bvhCache);
+ dm->bvhCache = NULL;
}
/**
@@ -349,7 +348,6 @@ void DM_init(
DM_init_funcs(dm);
dm->needsFree = 1;
- dm->auto_bump_scale = -1.0f;
dm->dirty = 0;
/* don't use CustomData_reset(...); because we dont want to touch customdata */
@@ -406,7 +404,6 @@ int DM_release(DerivedMesh *dm)
{
if (dm->needsFree) {
bvhcache_free(&dm->bvhCache);
- GPU_drawobject_free(dm);
CustomData_free(&dm->vertData, dm->numVertData);
CustomData_free(&dm->edgeData, dm->numEdgeData);
CustomData_free(&dm->faceData, dm->numTessFaceData);
@@ -552,7 +549,6 @@ void DM_update_tessface_data(DerivedMesh *dm)
MLoop *ml = dm->getLoopArray(dm);
CustomData *fdata = dm->getTessFaceDataLayout(dm);
- CustomData *pdata = dm->getPolyDataLayout(dm);
CustomData *ldata = dm->getLoopDataLayout(dm);
const int totface = dm->getNumTessFaces(dm);
@@ -565,7 +561,7 @@ void DM_update_tessface_data(DerivedMesh *dm)
if (!polyindex)
return;
- CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
if (CustomData_has_layer(fdata, CD_MTFACE) ||
CustomData_has_layer(fdata, CD_MCOL) ||
@@ -597,7 +593,7 @@ void DM_update_tessface_data(DerivedMesh *dm)
* 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
* So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
*/
- BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, mface, polyindex, loopindex, totface);
+ BKE_mesh_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface);
MEM_freeN(loopindex);
}
@@ -615,7 +611,6 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
MLoop *ml = dm->getLoopArray(dm);
CustomData *fdata = dm->getTessFaceDataLayout(dm);
- CustomData *pdata = dm->getPolyDataLayout(dm);
CustomData *ldata = dm->getLoopDataLayout(dm);
const int totface = dm->getNumTessFaces(dm);
@@ -632,7 +627,7 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
for (int j = 0; j < ldata->totlayer; j++) {
if (ldata->layers[j].type == CD_TANGENT) {
CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[j].name);
- CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
+ CustomData_bmesh_update_active_layers(fdata, ldata);
if (!loopindex) {
loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__);
@@ -662,7 +657,7 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
}
if (loopindex)
MEM_freeN(loopindex);
- BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
+ BLI_assert(CustomData_from_bmeshpoly_test(fdata, ldata, true));
}
if (G.debug & G_DEBUG)
@@ -721,7 +716,7 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
Mesh tmp = *me;
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
int did_shapekeys = 0;
- int alloctype = CD_DUPLICATE;
+ eCDAllocType alloctype = CD_DUPLICATE;
if (take_ownership && dm->type == DM_TYPE_CDDM && dm->needsFree) {
bool has_any_referenced_layers =
@@ -754,6 +749,7 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
CustomData_copy(&dm->loopData, &tmp.ldata, mask, alloctype, totloop);
CustomData_copy(&dm->polyData, &tmp.pdata, mask, alloctype, totpoly);
tmp.cd_flag = dm->cd_flag;
+ tmp.runtime.deformed_only = dm->deformedOnly;
if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) {
KeyBlock *kb;
@@ -831,8 +827,9 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
* stack */
if (tmp.totvert != me->totvert && !did_shapekeys && me->key) {
printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name);
- if (tmp.key)
+ if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
id_us_min(&tmp.key->id);
+ }
tmp.key = NULL;
}
@@ -859,26 +856,18 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
}
}
-void DM_to_meshkey(DerivedMesh *dm, Mesh *me, KeyBlock *kb)
+/** Utility function to convert an (evaluated) Mesh to a shape key block. */
+/* Just a shallow wrapper around BKE_keyblock_convert_from_mesh,
+ * that ensures both evaluated mesh and original one has same number of vertices. */
+void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
{
- int a, totvert = dm->getNumVerts(dm);
- float *fp;
- MVert *mvert;
+ const int totvert = me_deformed->totvert;
if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) {
return;
}
- if (kb->data) MEM_freeN(kb->data);
- kb->data = MEM_malloc_arrayN(me->key->elemsize, me->totvert, "kb->data");
- kb->totelem = totvert;
-
- fp = kb->data;
- mvert = dm->getVertDataArray(dm, CD_MVERT);
-
- for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) {
- copy_v3_v3(fp, mvert->co);
- }
+ BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb);
}
/**
@@ -900,27 +889,41 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask)
#endif
}
-void DM_add_vert_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+static void mesh_set_only_copy(Mesh *mesh, CustomDataMask mask)
+{
+ CustomData_set_only_copy(&mesh->vdata, mask);
+ CustomData_set_only_copy(&mesh->edata, mask);
+ CustomData_set_only_copy(&mesh->fdata, mask);
+ /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
+ * weight paint mode when there are modifiers applied, needs further investigation,
+ * see replies to r50969, Campbell */
+#if 0
+ CustomData_set_only_copy(&mesh->ldata, mask);
+ CustomData_set_only_copy(&mesh->pdata, mask);
+#endif
+}
+
+void DM_add_vert_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->vertData, type, alloctype, layer, dm->numVertData);
}
-void DM_add_edge_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_edge_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
}
-void DM_add_tessface_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_tessface_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numTessFaceData);
}
-void DM_add_loop_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData);
}
-void DM_add_poly_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_poly_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData);
}
@@ -1146,14 +1149,17 @@ DerivedMesh *mesh_create_derived(Mesh *me, float (*vertCos)[3])
return dm;
}
+/* XXX2.8(Sybren): can be removed once DerivedMesh port is done */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
DerivedMesh *mesh_create_derived_for_modifier(
- Scene *scene, Object *ob,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
ModifierData *md, int build_shapekey_layers)
{
Mesh *me = ob->data;
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
DerivedMesh *dm;
KeyBlock *kb;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
md->scene = scene;
@@ -1173,7 +1179,7 @@ DerivedMesh *mesh_create_derived_for_modifier(
int numVerts;
float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts);
- modwrap_deformVerts(md, ob, NULL, deformedVerts, numVerts, 0);
+ modwrap_deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
dm = mesh_create_derived(me, deformedVerts);
if (build_shapekey_layers)
@@ -1187,7 +1193,7 @@ DerivedMesh *mesh_create_derived_for_modifier(
if (build_shapekey_layers)
add_shapekey_layers(tdm, me, ob);
- dm = modwrap_applyModifier(md, ob, tdm, 0);
+ dm = modwrap_applyModifier(md, &mectx, tdm);
ASSERT_IS_VALID_DM(dm);
if (tdm != dm) tdm->release(tdm);
@@ -1195,6 +1201,7 @@ DerivedMesh *mesh_create_derived_for_modifier(
return dm;
}
+#endif
static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
{
@@ -1270,6 +1277,35 @@ static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, BMEditMesh *em, int lay
return dm;
}
+static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
+{
+ Mesh *mesh;
+ float (*orco)[3];
+ int free;
+
+ if (em) {
+ mesh = BKE_bmesh_to_mesh_nomain(em->bm, &(struct BMeshToMeshParams){0});
+ }
+ else {
+ BKE_id_copy_ex(
+ NULL, &me->id, (ID **)&mesh,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_CD_REFERENCE),
+ false);
+ }
+
+ orco = get_orco_coords_dm(ob, em, layer, &free);
+
+ if (orco) {
+ BKE_mesh_apply_vert_coords(mesh, orco);
+ if (free) MEM_freeN(orco);
+ }
+
+ return mesh;
+}
+
static void add_orco_dm(
Object *ob, BMEditMesh *em, DerivedMesh *dm,
DerivedMesh *orcodm, int layer)
@@ -1288,8 +1324,11 @@ static void add_orco_dm(
else
dm->getVertCos(dm, orco);
}
- else
+ else {
+ /* TODO(sybren): totvert should potentially change here, as ob->data
+ * or em may have a different number of vertices than dm. */
orco = get_orco_coords_dm(ob, em, layer, &free);
+ }
if (orco) {
if (layer == CD_ORCO)
@@ -1305,6 +1344,48 @@ static void add_orco_dm(
}
}
+static void add_orco_mesh(
+ Object *ob, BMEditMesh *em, Mesh *mesh,
+ Mesh *orco_mesh, int layer)
+{
+ float (*orco)[3], (*layerorco)[3];
+ int totvert, free;
+
+ totvert = mesh->totvert;
+
+ if (orco_mesh) {
+ free = 1;
+
+ if (orco_mesh->totvert == totvert) {
+ orco = BKE_mesh_vertexCos_get(orco_mesh, NULL);
+ }
+ else {
+ orco = BKE_mesh_vertexCos_get(mesh, NULL);
+ }
+ }
+ else {
+ /* TODO(sybren): totvert should potentially change here, as ob->data
+ * or em may have a different number of vertices than dm. */
+ orco = get_orco_coords_dm(ob, em, layer, &free);
+ }
+
+ if (orco) {
+ if (layer == CD_ORCO) {
+ BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0);
+ }
+
+ if (!(layerorco = CustomData_get_layer(&mesh->vdata, layer))) {
+ CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, NULL, mesh->totvert);
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ layerorco = CustomData_get_layer(&mesh->vdata, layer);
+ }
+
+ memcpy(layerorco, orco, sizeof(float) * 3 * totvert);
+ if (free) MEM_freeN(orco);
+ }
+}
+
/* weight paint colors */
/* Something of a hack, at the moment deal with weightpaint
@@ -1530,6 +1611,81 @@ static void calc_weightpaint_vert_array(
}
}
+static void calc_weightpaint_vert_array_mesh(
+ Object *ob, Mesh *mesh, int const draw_flag, DMWeightColorInfo *dm_wcinfo,
+ unsigned char (*r_wtcol_v)[4])
+{
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ const int numVerts = mesh->totvert;
+
+ if ((ob->actdef != 0) &&
+ (CustomData_has_layer(em ? &em->bm->vdata : &mesh->vdata, CD_MDEFORMVERT)))
+ {
+ unsigned char (*wc)[4] = r_wtcol_v;
+ unsigned int i;
+
+ /* variables for multipaint */
+ const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ const int defbase_act = ob->actdef - 1;
+
+ int defbase_sel_tot = 0;
+ bool *defbase_sel = NULL;
+
+ if (draw_flag & CALC_WP_MULTIPAINT) {
+ defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_sel_tot);
+
+ if (defbase_sel_tot > 1 && (draw_flag & CALC_WP_MIRROR_X)) {
+ BKE_object_defgroup_mirror_selection(ob, defbase_tot, defbase_sel, defbase_sel, &defbase_sel_tot);
+ }
+ }
+
+ /* editmesh won't have deform verts unless modifiers require it,
+ * avoid having to create an array of deform-verts only for drawing
+ * by reading from the bmesh directly. */
+ if (em) {
+ BMIter iter;
+ BMVert *eve;
+ const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+ BLI_assert(cd_dvert_offset != -1);
+
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ calc_weightpaint_vert_color(
+ (unsigned char *)wc, dv, dm_wcinfo,
+ defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
+ wc++;
+ }
+ }
+ else {
+ const MDeformVert *dv = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ for (i = numVerts; i != 0; i--, wc++, dv++) {
+ calc_weightpaint_vert_color(
+ (unsigned char *)wc, dv, dm_wcinfo,
+ defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
+ }
+ }
+
+ if (defbase_sel) {
+ MEM_freeN(defbase_sel);
+ }
+ }
+ else {
+ unsigned char col[4];
+ if ((ob->actdef == 0) && !BLI_listbase_is_empty(&ob->defbase)) {
+ /* color-code for missing data (full brightness isn't easy on the eye). */
+ ARRAY_SET_ITEMS(col, 0xa0, 0, 0xa0, 0xff);
+ }
+ else if (draw_flag & (CALC_WP_GROUP_USER_ACTIVE | CALC_WP_GROUP_USER_ALL)) {
+ copy_v3_v3_char((char *)col, dm_wcinfo->alert_color);
+ col[3] = 255;
+ }
+ else {
+ weightpaint_color(col, dm_wcinfo, 0.0f);
+ }
+ copy_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
+ }
+}
+
/** return an array of vertex weight colors from given weights, caller must free.
*
* \note that we could save some memory and allocate RGB only but then we'd need to
@@ -1622,6 +1778,80 @@ void DM_update_weight_mcol(
}
}
+static void mesh_update_weight_mcol(
+ Object *ob, Mesh *mesh, int const draw_flag,
+ float *weights, int num, const int *indices)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ unsigned char (*wtcol_v)[4];
+ int numVerts = mesh->totvert;
+ int i;
+
+ if (em) {
+ BKE_editmesh_color_ensure(em, BM_VERT);
+ wtcol_v = em->derivedVertColor;
+ }
+ else {
+ wtcol_v = MEM_malloc_arrayN(numVerts, sizeof(*wtcol_v), __func__);
+ }
+
+ /* Weights are given by caller. */
+ if (weights) {
+ float *w = weights;
+ /* If indices is not NULL, it means we do not have weights for all vertices,
+ * so we must create them (and set them to zero)... */
+ if (indices) {
+ w = MEM_calloc_arrayN(numVerts, sizeof(float), "Temp weight array DM_update_weight_mcol");
+ i = num;
+ while (i--)
+ w[indices[i]] = weights[i];
+ }
+
+ /* Convert float weights to colors. */
+ calc_colors_from_weights_array(numVerts, w, wtcol_v);
+
+ if (indices)
+ MEM_freeN(w);
+ }
+ else {
+ /* No weights given, take them from active vgroup(s). */
+ calc_weightpaint_vert_array_mesh(ob, mesh, draw_flag, &G_dm_wcinfo, wtcol_v);
+ }
+
+ if (em) {
+ /* editmesh draw function checks specifically for this */
+ }
+ else {
+ const int totpoly = mesh->totpoly;
+ const int totloop = mesh->totloop;
+ unsigned char(*wtcol_l)[4] = CustomData_get_layer(&mesh->ldata, CD_PREVIEW_MLOOPCOL);
+ MLoop *mloop = mesh->mloop, *ml;
+ MPoly *mp = mesh->mpoly;
+ int l_index;
+ int j;
+
+ /* now add to loops, so the data can be passed through the modifier stack
+ * If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
+ if (!wtcol_l) {
+ wtcol_l = MEM_malloc_arrayN(totloop, sizeof(*wtcol_l), __func__);
+ CustomData_add_layer(&mesh->ldata, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, totloop);
+ }
+
+ l_index = 0;
+ for (i = 0; i < totpoly; i++, mp++) {
+ ml = mloop + mp->loopstart;
+
+ for (j = 0; j < mp->totloop; j++, ml++, l_index++) {
+ copy_v4_v4_uchar(&wtcol_l[l_index][0],
+ &wtcol_v[ml->v][0]);
+ }
+ }
+ MEM_freeN(wtcol_v);
+
+ BKE_mesh_tessface_clear(mesh);
+ }
+}
+
static void DM_update_statvis_color(const Scene *scene, Object *ob, DerivedMesh *dm)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
@@ -1685,7 +1915,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape
}
}
-static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
+static void UNUSED_FUNCTION(add_shapekey_layers)(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
{
KeyBlock *kb;
Key *key = me->key;
@@ -1744,21 +1974,40 @@ static void dm_ensure_display_normals(DerivedMesh *dm)
}
}
-/**
- * new value for useDeform -1 (hack for the gameengine):
- *
- * - apply only the modifier stack of the object, skipping the virtual modifiers,
- * - don't apply the key
- * - apply deform modifiers and input vertexco
- */
+static void mesh_ensure_display_normals(Mesh *mesh)
+{
+ /* Note: mesh *may* have a poly CD_NORMAL layer (generated by a modifier needing poly normals e.g.).
+ * We do not use it here, though. And it should be tagged as temp!
+ */
+ /* BLI_assert((CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false)); */
+
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL || !CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
+ float (*face_nors)[3] = NULL;
+ face_nors = MEM_malloc_arrayN(mesh->totpoly, sizeof(*face_nors), "face_nors");
+
+ /* if normals are dirty we want to calculate vertex normals too */
+ bool only_face_normals = !(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL);
+
+ /* calculate face normals */
+ BKE_mesh_calc_normals_poly(
+ mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly,
+ mesh->totloop, mesh->totpoly, face_nors,
+ only_face_normals);
+
+ CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, face_nors, mesh->totpoly);
+
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ }
+}
+
static void mesh_calc_modifiers(
- Scene *scene, Object *ob, float (*inputVertexCos)[3],
- const bool useRenderParams, int useDeform,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (*inputVertexCos)[3],
+ int useDeform,
const bool need_mapping, CustomDataMask dataMask,
const int index, const bool useCache, const bool build_shapekey_layers,
const bool allow_gpu,
/* return args */
- DerivedMesh **r_deform, DerivedMesh **r_final)
+ Mesh **r_deform_mesh, Mesh **r_final_mesh)
{
Mesh *me = ob->data;
ModifierData *firstmd, *md, *previewmd = NULL;
@@ -1766,11 +2015,10 @@ static void mesh_calc_modifiers(
/* XXX Always copying POLYINDEX, else tessellated data are no more valid! */
CustomDataMask mask, nextmask, previewmask = 0, append_mask = CD_MASK_ORIGINDEX;
float (*deformedVerts)[3] = NULL;
- DerivedMesh *dm = NULL, *orcodm, *clothorcodm, *finaldm;
int numVerts = me->totvert;
+ const bool useRenderParams = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int required_mode = useRenderParams ? eModifierMode_Render : eModifierMode_Realtime;
bool isPrevDeform = false;
- const bool skipVirtualArmature = (useDeform < 0);
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
const bool has_multires = (mmd && mmd->sculptlvl != 0);
bool multires_applied = false;
@@ -1789,13 +2037,13 @@ static void mesh_calc_modifiers(
const bool do_mod_wmcol = do_init_wmcol;
const bool do_loop_normals = (me->flag & ME_AUTOSMOOTH) != 0;
- const float loop_normals_split_angle = me->smoothresh;
VirtualModifierData virtualModifierData;
ModifierApplyFlag app_flags = useRenderParams ? MOD_APPLY_RENDER : 0;
ModifierApplyFlag deform_app_flags = app_flags;
+ BLI_assert((me->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
if (useCache)
app_flags |= MOD_APPLY_USECACHE;
@@ -1804,17 +2052,13 @@ static void mesh_calc_modifiers(
if (useDeform)
deform_app_flags |= MOD_APPLY_USECACHE;
- if (!skipVirtualArmature) {
- firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- }
- else {
- /* game engine exception */
- firstmd = ob->modifiers.first;
- if (firstmd && firstmd->type == eModifierType_Armature)
- firstmd = firstmd->next;
- }
+ /* TODO(sybren): do we really need three context objects? Or do we modify
+ * them on the fly to change the flags where needed? */
+ const ModifierEvalContext mectx_deform = {depsgraph, ob, deform_app_flags};
+ const ModifierEvalContext mectx_apply = {depsgraph, ob, app_flags};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO};
- md = firstmd;
+ md = firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
modifiers_clearErrors(ob);
@@ -1836,10 +2080,10 @@ static void mesh_calc_modifiers(
datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, previewmask);
curr = datamasks;
- if (r_deform) {
- *r_deform = NULL;
+ if (r_deform_mesh) {
+ *r_deform_mesh = NULL;
}
- *r_final = NULL;
+ *r_final_mesh = NULL;
if (useDeform) {
if (inputVertexCos)
@@ -1849,8 +2093,6 @@ static void mesh_calc_modifiers(
for (; md; md = md->next, curr = curr->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!modifier_isEnabled(scene, md, required_mode)) {
continue;
}
@@ -1863,7 +2105,7 @@ static void mesh_calc_modifiers(
if (!deformedVerts)
deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
- modwrap_deformVerts(md, ob, NULL, deformedVerts, numVerts, deform_app_flags);
+ modifier_deformVerts_ensure_normals(md, &mectx_deform, NULL, deformedVerts, numVerts);
}
else {
break;
@@ -1878,14 +2120,22 @@ static void mesh_calc_modifiers(
* places that wish to use the original mesh but with deformed
* coordinates (vpaint, etc.)
*/
- if (r_deform) {
- *r_deform = CDDM_from_mesh(me);
-
- if (build_shapekey_layers)
- add_shapekey_layers(dm, me, ob);
+ if (r_deform_mesh) {
+ BKE_id_copy_ex(
+ NULL, &me->id, (ID **)r_deform_mesh,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_CD_REFERENCE),
+ false);
+
+ /* XXX: Is build_shapekey_layers ever even true? This should have crashed long ago... */
+ BLI_assert(!build_shapekey_layers);
+ //if (build_shapekey_layers)
+ // add_shapekey_layers(*r_deform_mesh, me, ob);
if (deformedVerts) {
- CDDM_apply_vert_coords(*r_deform, deformedVerts);
+ BKE_mesh_apply_vert_coords(*r_deform_mesh, deformedVerts);
}
}
}
@@ -1901,15 +2151,13 @@ static void mesh_calc_modifiers(
/* Now apply all remaining modifiers. If useDeform is off then skip
* OnlyDeform ones.
*/
- dm = NULL;
- orcodm = NULL;
- clothorcodm = NULL;
+ Mesh *mesh = NULL;
+ Mesh *orco_mesh = NULL;
+ Mesh *cloth_orco_mesh = NULL;
for (; md; md = md->next, curr = curr->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!modifier_isEnabled(scene, md, required_mode)) {
continue;
}
@@ -1918,7 +2166,7 @@ static void mesh_calc_modifiers(
continue;
}
- if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+ if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && mesh) {
modifier_setError(md, "Modifier requires original data, bad stack position");
continue;
}
@@ -1969,26 +2217,24 @@ static void mesh_calc_modifiers(
else
mask = 0;
- if (dm && (mask & CD_MASK_ORCO))
- add_orco_dm(ob, NULL, dm, orcodm, CD_ORCO);
+ if (mesh && (mask & CD_MASK_ORCO)) {
+ add_orco_mesh(ob, NULL, mesh, orco_mesh, CD_ORCO);
+ }
/* How to apply modifier depends on (a) what we already have as
- * a result of previous modifiers (could be a DerivedMesh or just
+ * a result of previous modifiers (could be a Mesh or just
* deformed vertices) and (b) what type the modifier is.
*/
if (mti->type == eModifierTypeType_OnlyDeform) {
/* No existing verts to deform, need to build them. */
if (!deformedVerts) {
- if (dm) {
- /* Deforming a derived mesh, read the vertex locations
+ if (mesh) {
+ /* Deforming a mesh, read the vertex locations
* out of the mesh and deform them. Once done with this
* run of deformers verts will be written back.
*/
- numVerts = dm->getNumVerts(dm);
- deformedVerts =
- MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv");
- dm->getVertCos(dm, deformedVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(mesh, &numVerts);
}
else {
deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
@@ -1999,45 +2245,46 @@ static void mesh_calc_modifiers(
* to avoid giving bogus normals to the next modifier see: [#23673] */
if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
/* XXX, this covers bug #23673, but we may need normal calc for other types */
- if (dm && dm->type == DM_TYPE_CDDM) {
- CDDM_apply_vert_coords(dm, deformedVerts);
+ if (mesh) {
+ BKE_mesh_apply_vert_coords(mesh, deformedVerts);
}
}
- modwrap_deformVerts(md, ob, dm, deformedVerts, numVerts, deform_app_flags);
+ modifier_deformVerts_ensure_normals(md, &mectx_deform, mesh, deformedVerts, numVerts);
}
else {
- DerivedMesh *ndm;
-
/* determine which data layers are needed by following modifiers */
if (curr->next)
nextmask = curr->next->mask;
else
nextmask = dataMask;
- /* apply vertex coordinates or build a DerivedMesh as necessary */
- if (dm) {
+ /* apply vertex coordinates or build a Mesh as necessary */
+ if (mesh) {
if (deformedVerts) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
-
- CDDM_apply_vert_coords(dm, deformedVerts);
+ BKE_mesh_apply_vert_coords(mesh, deformedVerts);
}
}
else {
- dm = CDDM_from_mesh(me);
- ASSERT_IS_VALID_DM(dm);
-
- if (build_shapekey_layers)
- add_shapekey_layers(dm, me, ob);
+ BKE_id_copy_ex(
+ NULL, &me->id, (ID **)&mesh,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_CD_REFERENCE),
+ false);
+ ASSERT_IS_VALID_MESH(mesh);
+
+ // XXX: port to Mesh if build_shapekey_layers can ever be true
+ //if (build_shapekey_layers)
+ // add_shapekey_layers(mesh, me, ob);
if (deformedVerts) {
- CDDM_apply_vert_coords(dm, deformedVerts);
+ BKE_mesh_apply_vert_coords(mesh, deformedVerts);
}
if (do_init_wmcol)
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
+ mesh_update_weight_mcol(ob, mesh, draw_flag, NULL, 0, NULL);
/* Constructive modifiers need to have an origindex
* otherwise they wont have anywhere to copy the data from.
@@ -2048,45 +2295,48 @@ static void mesh_calc_modifiers(
*/
if (need_mapping || (nextmask & CD_MASK_ORIGINDEX)) {
/* calc */
- DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+ CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
+ CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
+ CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly);
/* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */
- range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
- range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
- range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0);
+ range_vn_i(CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX), mesh->totvert, 0);
+ range_vn_i(CustomData_get_layer(&mesh->edata, CD_ORIGINDEX), mesh->totedge, 0);
+ range_vn_i(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX), mesh->totpoly, 0);
}
}
- /* set the DerivedMesh to only copy needed data */
+ /* set the Mesh to only copy needed data */
mask = curr->mask;
/* needMapping check here fixes bug [#28112], otherwise it's
* possible that it won't be copied */
mask |= append_mask;
- DM_set_only_copy(dm, mask | (need_mapping ? CD_MASK_ORIGINDEX : 0));
+ mesh_set_only_copy(mesh, mask | (need_mapping ? CD_MASK_ORIGINDEX : 0));
/* add cloth rest shape key if needed */
if (mask & CD_MASK_CLOTH_ORCO)
- add_orco_dm(ob, NULL, dm, clothorcodm, CD_CLOTH_ORCO);
+ add_orco_mesh(ob, NULL, mesh, orco_mesh, CD_CLOTH_ORCO);
/* add an origspace layer if needed */
if ((curr->mask) & CD_MASK_ORIGSPACE_MLOOP) {
- if (!CustomData_has_layer(&dm->loopData, CD_ORIGSPACE_MLOOP)) {
- DM_add_loop_layer(dm, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL);
- DM_init_origspace(dm);
+ if (!CustomData_has_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP)) {
+ CustomData_add_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh->totloop);
+ mesh_init_origspace(mesh);
}
}
- ndm = modwrap_applyModifier(md, ob, dm, app_flags);
- ASSERT_IS_VALID_DM(ndm);
+ Mesh *new_mesh = modifier_applyModifier_ensure_normals(md, &mectx_apply, mesh);
+ ASSERT_IS_VALID_MESH(new_mesh);
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (dm && dm != ndm) dm->release(dm);
+ if (new_mesh) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (mesh && mesh != new_mesh) {
+ BLI_assert(mesh != me);
+ BKE_id_free(NULL, mesh);
+ }
- dm = ndm;
+ mesh = new_mesh;
if (deformedVerts) {
if (deformedVerts != inputVertexCos)
@@ -2096,43 +2346,51 @@ static void mesh_calc_modifiers(
}
}
- /* create an orco derivedmesh in parallel */
+ /* create an orco mesh in parallel */
if (nextmask & CD_MASK_ORCO) {
- if (!orcodm)
- orcodm = create_orco_dm(ob, me, NULL, CD_ORCO);
+ if (!orco_mesh) {
+ orco_mesh = create_orco_mesh(ob, me, NULL, CD_ORCO);
+ }
nextmask &= ~CD_MASK_ORCO;
- DM_set_only_copy(orcodm, nextmask | CD_MASK_ORIGINDEX |
+ mesh_set_only_copy(orco_mesh, nextmask | CD_MASK_ORIGINDEX |
(mti->requiredDataMask ?
mti->requiredDataMask(ob, md) : 0));
- ndm = modwrap_applyModifier(md, ob, orcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO);
- ASSERT_IS_VALID_DM(ndm);
+ new_mesh = modifier_applyModifier_ensure_normals(md, &mectx_orco, orco_mesh);
+ ASSERT_IS_VALID_MESH(new_mesh);
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (orcodm && orcodm != ndm) orcodm->release(orcodm);
- orcodm = ndm;
+ if (new_mesh) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (orco_mesh && orco_mesh != new_mesh) {
+ BLI_assert(orco_mesh != me);
+ BKE_id_free(NULL, orco_mesh);
+ }
+
+ orco_mesh = new_mesh;
}
}
- /* create cloth orco derivedmesh in parallel */
+ /* create cloth orco mesh in parallel */
if (nextmask & CD_MASK_CLOTH_ORCO) {
- if (!clothorcodm)
- clothorcodm = create_orco_dm(ob, me, NULL, CD_CLOTH_ORCO);
+ if (!cloth_orco_mesh) {
+ cloth_orco_mesh = create_orco_mesh(ob, me, NULL, CD_CLOTH_ORCO);
+ }
nextmask &= ~CD_MASK_CLOTH_ORCO;
- DM_set_only_copy(clothorcodm, nextmask | CD_MASK_ORIGINDEX);
+ mesh_set_only_copy(cloth_orco_mesh, nextmask | CD_MASK_ORIGINDEX);
- ndm = modwrap_applyModifier(md, ob, clothorcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO);
- ASSERT_IS_VALID_DM(ndm);
+ new_mesh = modifier_applyModifier_ensure_normals(md, &mectx_orco, cloth_orco_mesh);
+ ASSERT_IS_VALID_DM(new_mesh);
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (clothorcodm && clothorcodm != ndm) {
- clothorcodm->release(clothorcodm);
+ if (new_mesh) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (cloth_orco_mesh && cloth_orco_mesh != new_mesh) {
+ BLI_assert(orco_mesh != me);
+ BKE_id_free(NULL, cloth_orco_mesh);
}
- clothorcodm = ndm;
+
+ cloth_orco_mesh = new_mesh;
}
}
@@ -2142,11 +2400,11 @@ static void mesh_calc_modifiers(
append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
/* In case of active preview modifier, make sure preview mask remains for following modifiers. */
else if ((md == previewmd) && (do_mod_wmcol)) {
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
+ mesh_update_weight_mcol(ob, mesh, draw_flag, NULL, 0, NULL);
append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
}
- dm->deformedOnly = false;
+ mesh->runtime.deformed_only = false;
}
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
@@ -2163,65 +2421,65 @@ static void mesh_calc_modifiers(
for (md = firstmd; md; md = md->next)
modifier_freeTemporaryData(md);
- /* Yay, we are done. If we have a DerivedMesh and deformed vertices
- * need to apply these back onto the DerivedMesh. If we have no
- * DerivedMesh then we need to build one.
+ /* Yay, we are done. If we have a Mesh and deformed vertices
+ * need to apply these back onto the Mesh. If we have no
+ * Mesh then we need to build one.
*/
- if (dm && deformedVerts) {
- finaldm = CDDM_copy(dm);
+ Mesh *final_mesh;
- dm->release(dm);
-
- CDDM_apply_vert_coords(finaldm, deformedVerts);
+ if (mesh) {
+ final_mesh = mesh;
-#if 0 /* For later nice mod preview! */
- /* In case we need modified weights in CD_PREVIEW_MCOL, we have to re-compute it. */
- if (do_final_wmcol)
- DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
-#endif
- }
- else if (dm) {
- finaldm = dm;
+ if (deformedVerts) {
+ BKE_mesh_apply_vert_coords(final_mesh, deformedVerts);
+ }
#if 0 /* For later nice mod preview! */
/* In case we need modified weights in CD_PREVIEW_MCOL, we have to re-compute it. */
if (do_final_wmcol)
- DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
+ mesh_update_weight_mcol(ob, final_mesh, draw_flag, NULL, 0, NULL);
#endif
}
else {
- finaldm = CDDM_from_mesh(me);
-
- if (build_shapekey_layers) {
- add_shapekey_layers(finaldm, me, ob);
- }
+ BKE_id_copy_ex(
+ NULL, &me->id, (ID **)&final_mesh,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_CD_REFERENCE),
+ false);
+
+ //if (build_shapekey_layers) {
+ // add_shapekey_layers(final_mesh, me, ob);
+ //}
if (deformedVerts) {
- CDDM_apply_vert_coords(finaldm, deformedVerts);
+ BKE_mesh_apply_vert_coords(final_mesh, deformedVerts);
}
/* In this case, we should never have weight-modifying modifiers in stack... */
if (do_init_wmcol)
- DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
+ mesh_update_weight_mcol(ob, final_mesh, draw_flag, NULL, 0, NULL);
}
/* add an orco layer if needed */
if (dataMask & CD_MASK_ORCO) {
- add_orco_dm(ob, NULL, finaldm, orcodm, CD_ORCO);
+ add_orco_mesh(ob, NULL, final_mesh, orco_mesh, CD_ORCO);
- if (r_deform && *r_deform)
- add_orco_dm(ob, NULL, *r_deform, NULL, CD_ORCO);
+ if (r_deform_mesh && *r_deform_mesh)
+ add_orco_mesh(ob, NULL, *r_deform_mesh, NULL, CD_ORCO);
}
if (do_loop_normals) {
/* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */
- DM_calc_loop_normals(finaldm, do_loop_normals, loop_normals_split_angle);
+ BKE_mesh_calc_normals_split(final_mesh);
+ BKE_mesh_tessface_clear(final_mesh);
}
if (sculpt_dyntopo == false) {
/* watch this! after 2.75a we move to from tessface to looptri (by default) */
if (dataMask & CD_MASK_MFACE) {
- DM_ensure_tessface(finaldm);
+ BKE_mesh_tessface_ensure(final_mesh);
}
/* without this, drawing ngon tri's faces will show ugly tessellated face
@@ -2234,36 +2492,24 @@ static void mesh_calc_modifiers(
* If using loop normals, poly nors have already been computed.
*/
if (!do_loop_normals) {
- dm_ensure_display_normals(finaldm);
+ mesh_ensure_display_normals(final_mesh);
}
}
/* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them,
* as they are used by display code when available (i.e. even if autosmooth is disabled). */
- if (!do_loop_normals && CustomData_has_layer(&finaldm->loopData, CD_NORMAL)) {
- CustomData_free_layers(&finaldm->loopData, CD_NORMAL, finaldm->numLoopData);
- }
-
-#ifdef WITH_GAMEENGINE
- /* NavMesh - this is a hack but saves having a NavMesh modifier */
- if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) {
- DerivedMesh *tdm;
- tdm = navmesh_dm_createNavMeshForVisualization(finaldm);
- if (finaldm != tdm) {
- finaldm->release(finaldm);
- finaldm = tdm;
- }
-
- DM_ensure_tessface(finaldm);
+ if (!do_loop_normals && CustomData_has_layer(&final_mesh->ldata, CD_NORMAL)) {
+ CustomData_free_layers(&final_mesh->ldata, CD_NORMAL, final_mesh->totloop);
}
-#endif /* WITH_GAMEENGINE */
- *r_final = finaldm;
+ *r_final_mesh = final_mesh;
- if (orcodm)
- orcodm->release(orcodm);
- if (clothorcodm)
- clothorcodm->release(clothorcodm);
+ if (orco_mesh) {
+ BKE_id_free(NULL, orco_mesh);
+ }
+ if (cloth_orco_mesh) {
+ BKE_id_free(NULL, cloth_orco_mesh);
+ }
if (deformedVerts && deformedVerts != inputVertexCos)
MEM_freeN(deformedVerts);
@@ -2271,6 +2517,31 @@ static void mesh_calc_modifiers(
BLI_linklist_free((LinkNode *)datamasks, NULL);
}
+static void mesh_calc_modifiers_dm(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (*inputVertexCos)[3],
+ int useDeform,
+ const bool need_mapping, CustomDataMask dataMask,
+ const int index, const bool useCache, const bool build_shapekey_layers,
+ const bool allow_gpu,
+ /* return args */
+ DerivedMesh **r_deformdm, DerivedMesh **r_finaldm)
+{
+ Mesh *deform_mesh = NULL, *final_mesh = NULL;
+
+ mesh_calc_modifiers(
+ depsgraph, scene, ob, inputVertexCos, useDeform,
+ need_mapping, dataMask, index, useCache, build_shapekey_layers, allow_gpu,
+ (r_deformdm ? &deform_mesh : NULL), &final_mesh);
+
+ if (deform_mesh) {
+ *r_deformdm = CDDM_from_mesh_ex(deform_mesh, CD_DUPLICATE, CD_MASK_MESH);
+ BKE_id_free(NULL, deform_mesh);
+ }
+
+ *r_finaldm = CDDM_from_mesh_ex(final_mesh, CD_DUPLICATE, CD_MASK_MESH);
+ BKE_id_free(NULL, final_mesh);
+}
+
float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3]
{
BMIter iter;
@@ -2307,8 +2578,8 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *
}
static void editbmesh_calc_modifiers(
- Scene *scene, Object *ob, BMEditMesh *em,
- CustomDataMask dataMask,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ BMEditMesh *em, CustomDataMask dataMask,
/* return args */
DerivedMesh **r_cage, DerivedMesh **r_final)
{
@@ -2332,6 +2603,11 @@ static void editbmesh_calc_modifiers(
const bool do_mod_wmcol = do_init_wmcol;
VirtualModifierData virtualModifierData;
+ /* TODO(sybren): do we really need multiple objects, or shall we change the flags where needed? */
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO};
+ const ModifierEvalContext mectx_cache_gpu = {depsgraph, ob, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU};
+
const bool do_loop_normals = (((Mesh *)(ob->data))->flag & ME_AUTOSMOOTH) != 0;
const float loop_normals_split_angle = ((Mesh *)(ob->data))->smoothresh;
@@ -2358,8 +2634,6 @@ static void editbmesh_calc_modifiers(
for (i = 0; md; i++, md = md->next, curr = curr->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!editbmesh_modifier_is_enabled(scene, md, dm)) {
continue;
}
@@ -2394,10 +2668,10 @@ static void editbmesh_calc_modifiers(
}
}
- if (mti->deformVertsEM)
- modwrap_deformVertsEM(md, ob, em, dm, deformedVerts, numVerts);
+ if (mti->deformVertsEM || mti->deformVertsEM_DM)
+ modwrap_deformVertsEM(md, &mectx, em, dm, deformedVerts, numVerts);
else
- modwrap_deformVerts(md, ob, dm, deformedVerts, numVerts, 0);
+ modwrap_deformVerts(md, &mectx, dm, deformedVerts, numVerts);
}
else {
DerivedMesh *ndm;
@@ -2441,11 +2715,11 @@ static void editbmesh_calc_modifiers(
mask &= ~CD_MASK_ORCO;
DM_set_only_copy(orcodm, mask | CD_MASK_ORIGINDEX);
- if (mti->applyModifierEM) {
- ndm = modwrap_applyModifierEM(md, ob, em, orcodm, MOD_APPLY_ORCO);
+ if (mti->applyModifierEM || mti->applyModifierEM_DM) {
+ ndm = modwrap_applyModifierEM(md, &mectx_orco, em, orcodm);
}
else {
- ndm = modwrap_applyModifier(md, ob, orcodm, MOD_APPLY_ORCO);
+ ndm = modwrap_applyModifier(md, &mectx_orco, orcodm);
}
ASSERT_IS_VALID_DM(ndm);
@@ -2469,10 +2743,10 @@ static void editbmesh_calc_modifiers(
}
}
- if (mti->applyModifierEM)
- ndm = modwrap_applyModifierEM(md, ob, em, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU);
+ if (mti->applyModifierEM || mti->applyModifierEM_DM)
+ ndm = modwrap_applyModifierEM(md, &mectx_cache_gpu, em, dm);
else
- ndm = modwrap_applyModifier(md, ob, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU);
+ ndm = modwrap_applyModifier(md, &mectx_cache_gpu, dm);
ASSERT_IS_VALID_DM(ndm);
if (ndm) {
@@ -2505,6 +2779,11 @@ static void editbmesh_calc_modifiers(
*r_cage = dm;
}
else {
+ struct Mesh *mesh = ob->data;
+ if (mesh->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ BKE_mesh_runtime_ensure_edit_data(mesh);
+ mesh->runtime.edit_data->vertexCos = MEM_dupallocN(deformedVerts);
+ }
*r_cage = getEditDerivedBMesh(
em, ob, mask,
deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
@@ -2542,6 +2821,13 @@ static void editbmesh_calc_modifiers(
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
+ struct Mesh *mesh = ob->data;
+ if (mesh->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ BKE_mesh_runtime_ensure_edit_data(mesh);
+ if (mesh->runtime.edit_data->vertexCos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->vertexCos);
+ mesh->runtime.edit_data->vertexCos = MEM_dupallocN(deformedVerts);
+ }
*r_final = getEditDerivedBMesh(em, ob, dataMask, deformedVerts);
deformedVerts = NULL;
@@ -2608,7 +2894,8 @@ static void editbmesh_calc_modifiers(
* we'll be using GPU backend of OpenSubdiv. This is so
* playback performance is kept as high as possible.
*/
-static bool calc_modifiers_skip_orco(Scene *scene,
+static bool calc_modifiers_skip_orco(Depsgraph *depsgraph,
+ Scene *scene,
Object *ob,
bool use_render_params)
{
@@ -2624,7 +2911,7 @@ static bool calc_modifiers_skip_orco(Scene *scene,
else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) {
return false;
}
- else if ((DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CPU) != 0) {
+ else if ((DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CPU) != 0) {
return false;
}
SubsurfModifierData *smd = (SubsurfModifierData *)last_md;
@@ -2635,8 +2922,50 @@ static bool calc_modifiers_skip_orco(Scene *scene,
}
#endif
+static void mesh_finalize_eval(Object *object)
+{
+ Mesh *mesh = (Mesh *)object->data;
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ /* Special Tweaks for cases when evaluated mesh came from
+ * BKE_mesh_new_nomain_from_template().
+ */
+ BLI_strncpy(mesh_eval->id.name, mesh->id.name, sizeof(mesh_eval->id.name));
+ if (mesh_eval->mat != NULL) {
+ MEM_freeN(mesh_eval->mat);
+ }
+ /* Set flag which makes it easier to see what's going on in a debugger. */
+ mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT;
+ mesh_eval->mat = MEM_dupallocN(mesh->mat);
+ mesh_eval->totcol = mesh->totcol;
+ /* Make evaluated mesh to share same edit mesh pointer as original
+ * and copied meshes.
+ */
+ mesh_eval->edit_btmesh = mesh->edit_btmesh;
+ /* Copy autosmooth settings from original mesh.
+ * This is not done by BKE_mesh_new_nomain_from_template(), so need to take
+ * extra care here.
+ */
+ mesh_eval->flag |= (mesh->flag & ME_AUTOSMOOTH);
+ mesh_eval->smoothresh = mesh->smoothresh;
+ /* Replace evaluated object's data with fully evaluated mesh. */
+ /* TODO(sergey): There was statement done by Sybren and Mai that this
+ * caused modifiers to be applied twice. which is weirtd and shouldn't
+ * really happen. But since there is no reference to the report, can not
+ * do much about this.
+ */
+
+ /* Object is sometimes not evaluated!
+ * TODO(sergey): BAD TEMPORARY HACK FOR UNTIL WE ARE SMARTER */
+ if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ object->data = mesh_eval;
+ }
+ else {
+ /* evaluated will be available via: 'object->runtime.mesh_eval' */
+ }
+}
+
static void mesh_build_data(
- Scene *scene, Object *ob, CustomDataMask dataMask,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask,
const bool build_shapekey_layers, const bool need_mapping)
{
BLI_assert(ob->type == OB_MESH);
@@ -2645,17 +2974,26 @@ static void mesh_build_data(
BKE_object_sculpt_modifiers_changed(ob);
#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(scene, ob, false)) {
+ if (calc_modifiers_skip_orco(depsgraph, scene, ob, false)) {
dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
}
#endif
mesh_calc_modifiers(
- scene, ob, NULL, false, 1, need_mapping, dataMask, -1, true, build_shapekey_layers,
+ depsgraph, scene, ob, NULL, 1, need_mapping, dataMask, -1, true, build_shapekey_layers,
true,
- &ob->derivedDeform, &ob->derivedFinal);
+ &ob->runtime.mesh_deform_eval, &ob->runtime.mesh_eval);
+
+ mesh_finalize_eval(ob);
+
+ ob->derivedDeform = CDDM_from_mesh_ex(ob->runtime.mesh_deform_eval, CD_REFERENCE, CD_MASK_MESH);
+ ob->derivedFinal = CDDM_from_mesh_ex(ob->runtime.mesh_eval, CD_REFERENCE, CD_MASK_MESH);
DM_set_object_boundbox(ob, ob->derivedFinal);
+ /* TODO(sergey): Convert bounding box calculation to use mesh, then
+ * we can skip this copy.
+ */
+ BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
ob->derivedFinal->needsFree = 0;
ob->derivedDeform->needsFree = 0;
@@ -2665,14 +3003,17 @@ static void mesh_build_data(
if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
/* create PBVH immediately (would be created on the fly too,
* but this avoids waiting on first stroke) */
-
- BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, false, false);
+ /* XXX Disabled for now.
+ * This can create horrible nasty bugs by generating re-entrant call of mesh_get_eval_final! */
+// BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS));
}
-static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
+static void editbmesh_build_data(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
{
BKE_object_free_derived_caches(obedit);
BKE_object_sculpt_modifiers_changed(obedit);
@@ -2680,13 +3021,13 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C
BKE_editmesh_free_derivedmesh(em);
#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(scene, obedit, false)) {
+ if (calc_modifiers_skip_orco(depsgraph, scene, obedit, false)) {
dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
}
#endif
editbmesh_calc_modifiers(
- scene, obedit, em, dataMask,
+ depsgraph, scene, obedit, em, dataMask,
&em->derivedCage, &em->derivedFinal);
DM_set_object_boundbox(obedit, em->derivedFinal);
@@ -2698,16 +3039,17 @@ 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, bool *r_need_mapping)
+static CustomDataMask object_get_datamask(const Depsgraph *depsgraph, Object *ob, bool *r_need_mapping)
{
- Object *actob = scene->basact ? scene->basact->object : NULL;
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) : NULL;
CustomDataMask mask = ob->customdata_mask;
if (r_need_mapping) {
*r_need_mapping = false;
}
- if (ob == actob) {
+ if (DEG_get_original_object(ob) == actob) {
bool editing = BKE_paint_select_face_test(ob);
/* weight paint and face select need original indices because of selection buffer drawing */
@@ -2737,85 +3079,130 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *
}
void makeDerivedMesh(
- Scene *scene, Object *ob, BMEditMesh *em,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em,
CustomDataMask dataMask, const bool build_shapekey_layers)
{
bool need_mapping;
- dataMask |= object_get_datamask(scene, ob, &need_mapping);
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
if (em) {
- editbmesh_build_data(scene, ob, em, dataMask);
+ editbmesh_build_data(depsgraph, scene, ob, em, dataMask);
}
else {
- mesh_build_data(scene, ob, dataMask, build_shapekey_layers, need_mapping);
+ mesh_build_data(depsgraph, scene, ob, dataMask, build_shapekey_layers, need_mapping);
}
}
/***/
-DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dataMask)
+#ifdef USE_DERIVEDMESH
+/* Deprecated DM, use: 'mesh_get_eval_final'. */
+DerivedMesh *mesh_get_derived_final(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
bool need_mapping;
- dataMask |= object_get_datamask(scene, ob, &need_mapping);
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
if (!ob->derivedFinal ||
((dataMask & ob->lastDataMask) != dataMask) ||
(need_mapping != ob->lastNeedMapping))
{
- mesh_build_data(scene, ob, dataMask, false, need_mapping);
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
}
if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); }
return ob->derivedFinal;
}
+#endif
+Mesh *mesh_get_eval_final(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
+{
+ /* if there's no evaluated mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ bool need_mapping;
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
-DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask dataMask)
+ if (!ob->runtime.mesh_eval ||
+ ((dataMask & ob->lastDataMask) != dataMask) ||
+ (need_mapping != ob->lastNeedMapping))
+ {
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
+ }
+
+ if (ob->runtime.mesh_eval) { BLI_assert(!(ob->runtime.mesh_eval->runtime.cd_dirty_vert & CD_MASK_NORMAL)); }
+ return ob->runtime.mesh_eval;
+}
+
+#ifdef USE_DERIVEDMESH
+/* Deprecated DM, use: 'mesh_get_eval_deform' instead. */
+DerivedMesh *mesh_get_derived_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
bool need_mapping;
- dataMask |= object_get_datamask(scene, ob, &need_mapping);
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
if (!ob->derivedDeform ||
((dataMask & ob->lastDataMask) != dataMask) ||
(need_mapping != ob->lastNeedMapping))
{
- mesh_build_data(scene, ob, dataMask, false, need_mapping);
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
}
return ob->derivedDeform;
}
+#endif
+Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
+{
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ bool need_mapping;
+
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
+
+ if (!ob->runtime.mesh_deform_eval ||
+ ((dataMask & ob->lastDataMask) != dataMask) ||
+ (need_mapping != ob->lastNeedMapping))
+ {
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
+ }
+
+ return ob->runtime.mesh_deform_eval;
+}
-DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask dataMask)
+
+DerivedMesh *mesh_create_derived_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
DerivedMesh *final;
- mesh_calc_modifiers(
- scene, ob, NULL, true, 1, false, dataMask, -1, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false, false,
NULL, &final);
return final;
}
-DerivedMesh *mesh_create_derived_index_render(Scene *scene, Object *ob, CustomDataMask dataMask, int index)
+DerivedMesh *mesh_create_derived_index_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask, int index)
{
DerivedMesh *final;
- mesh_calc_modifiers(
- scene, ob, NULL, true, 1, false, dataMask, index, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, NULL, 1, false, dataMask, index, false, false, false,
NULL, &final);
return final;
}
DerivedMesh *mesh_create_derived_view(
- Scene *scene, Object *ob,
- CustomDataMask dataMask)
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, CustomDataMask dataMask)
{
DerivedMesh *final;
@@ -2825,8 +3212,8 @@ DerivedMesh *mesh_create_derived_view(
*/
ob->transflag |= OB_NO_PSYS_UPDATE;
- mesh_calc_modifiers(
- scene, ob, NULL, false, 1, false, dataMask, -1, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false, false,
NULL, &final);
ob->transflag &= ~OB_NO_PSYS_UPDATE;
@@ -2835,53 +3222,13 @@ DerivedMesh *mesh_create_derived_view(
}
DerivedMesh *mesh_create_derived_no_deform(
- Scene *scene, Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask)
-{
- DerivedMesh *final;
-
- mesh_calc_modifiers(
- scene, ob, vertCos, false, 0, false, dataMask, -1, false, false, false,
- NULL, &final);
-
- return final;
-}
-
-DerivedMesh *mesh_create_derived_no_virtual(
- Scene *scene, Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask)
-{
- DerivedMesh *final;
-
- mesh_calc_modifiers(
- scene, ob, vertCos, false, -1, false, dataMask, -1, false, false, false,
- NULL, &final);
-
- return final;
-}
-
-DerivedMesh *mesh_create_derived_physics(
- Scene *scene, Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask)
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ float (*vertCos)[3], CustomDataMask dataMask)
{
DerivedMesh *final;
- mesh_calc_modifiers(
- scene, ob, vertCos, false, -1, true, dataMask, -1, false, false, false,
- NULL, &final);
-
- return final;
-}
-
-DerivedMesh *mesh_create_derived_no_deform_render(
- Scene *scene, Object *ob,
- float (*vertCos)[3],
- CustomDataMask dataMask)
-{
- DerivedMesh *final;
-
- mesh_calc_modifiers(
- scene, ob, vertCos, true, 0, false, dataMask, -1, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, vertCos, 0, false, dataMask, -1, false, false, false,
NULL, &final);
return final;
@@ -2890,7 +3237,7 @@ DerivedMesh *mesh_create_derived_no_deform_render(
/***/
DerivedMesh *editbmesh_get_derived_cage_and_final(
- Scene *scene, Object *obedit, BMEditMesh *em,
+ struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em,
CustomDataMask dataMask,
/* return args */
DerivedMesh **r_final)
@@ -2898,12 +3245,12 @@ DerivedMesh *editbmesh_get_derived_cage_and_final(
/* 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, NULL);
+ dataMask |= object_get_datamask(depsgraph, obedit, NULL);
if (!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
{
- editbmesh_build_data(scene, obedit, em, dataMask);
+ editbmesh_build_data(depsgraph, scene, obedit, em, dataMask);
}
*r_final = em->derivedFinal;
@@ -2911,17 +3258,19 @@ DerivedMesh *editbmesh_get_derived_cage_and_final(
return em->derivedCage;
}
-DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
+DerivedMesh *editbmesh_get_derived_cage(
+ struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em,
+ CustomDataMask dataMask)
{
/* 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, NULL);
+ dataMask |= object_get_datamask(depsgraph, obedit, NULL);
if (!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
{
- editbmesh_build_data(scene, obedit, em, dataMask);
+ editbmesh_build_data(depsgraph, scene, obedit, em, dataMask);
}
return em->derivedCage;
@@ -3056,271 +3405,6 @@ void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int
}
}
-/* ******************* GLSL ******************** */
-
-/** \name Tangent Space Calculation
- * \{ */
-
-/* Necessary complexity to handle looptri's as quads for correct tangents */
-#define USE_LOOPTRI_DETECT_QUADS
-
-typedef struct {
- float (*precomputedFaceNormals)[3];
- float (*precomputedLoopNormals)[3];
- const MLoopTri *looptri;
- MLoopUV *mloopuv; /* texture coordinates */
- MPoly *mpoly; /* indices */
- MLoop *mloop; /* indices */
- MVert *mvert; /* vertices & normals */
- float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
-#endif
-
-} SGLSLMeshToTangent;
-
-/* interface */
-#include "mikktspace.h"
-
-static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
-#else
- return pMesh->numTessFaces;
-#endif
-}
-
-static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
-#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- if (pMesh->face_as_quad_map) {
- const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- return 4;
- }
- }
- return 3;
-#else
- UNUSED_VARS(pContext, face_num);
- return 3;
-#endif
-}
-
-static void dm_ts_GetPosition(
- const SMikkTSpaceContext *pContext, float r_co[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
- const float *co;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
- copy_v3_v3(r_co, co);
-}
-
-static void dm_ts_GetTextureCoordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- if (pMesh->mloopuv != NULL) {
- const float *uv = pMesh->mloopuv[loop_index].uv;
- copy_v2_v2(r_uv, uv);
- }
- else {
- const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
- }
-}
-
-static void dm_ts_GetNormal(
- const SMikkTSpaceContext *pContext, float r_no[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
- }
- else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
- }
- else {
-#ifdef USE_LOOPTRI_DETECT_QUADS
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- normal_quad_v3(
- r_no,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
- }
- else
-#endif
- {
- normal_tri_v3(
- r_no,
- pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
- }
- }
- }
- else {
- const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
- normal_short_to_float_v3(r_no, no);
- }
-}
-
-static void dm_ts_SetTSpace(
- const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
- float *pRes;
-
-finally:
- pRes = pMesh->tangent[loop_index];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
-}
-
-void DM_calc_tangents_names_from_gpu(
- const GPUVertexAttribs *gattribs,
- char (*tangent_names)[MAX_NAME], int *r_tangent_names_count)
-{
- int count = 0;
- for (int b = 0; b < gattribs->totlayer; b++) {
- if (gattribs->layer[b].type == CD_TANGENT) {
- strcpy(tangent_names[count++], gattribs->layer[b].name);
- }
- }
- *r_tangent_names_count = count;
-}
-
-static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- struct SGLSLMeshToTangent *mesh2tangent = taskdata;
- /* new computation method */
- {
- SMikkTSpaceContext sContext = {NULL};
- SMikkTSpaceInterface sInterface = {NULL};
-
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = dm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = dm_ts_GetPosition;
- sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = dm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
-
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
-}
-
void DM_add_named_tangent_layer_for_uv(
CustomData *uv_data, CustomData *tan_data, int numLoopData,
const char *layer_name)
@@ -3334,602 +3418,24 @@ void DM_add_named_tangent_layer_for_uv(
}
}
-/**
- * Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
- * Also, we calculate tangent_mask that works as a descriptor of tangents state.
- * If tangent_mask has changed, then recalculate tangents.
- */
-void DM_calc_loop_tangents_step_0(
- const CustomData *loopData, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count,
- bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
- char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
-{
- /* Active uv in viewport */
- int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
- *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
- ract_uv_name[0] = 0;
- if (*ract_uv_n != -1) {
- strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
- }
-
- /* Active tangent in render */
- *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
- rren_uv_name[0] = 0;
- if (*rren_uv_n != -1) {
- strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
- }
-
- /* If active tangent not in tangent_names we take it into account */
- *rcalc_act = false;
- *rcalc_ren = false;
- for (int i = 0; i < tangent_names_count; i++) {
- if (tangent_names[i][0] == 0) {
- calc_active_tangent = true;
- }
- }
- if (calc_active_tangent) {
- *rcalc_act = true;
- *rcalc_ren = true;
- for (int i = 0; i < tangent_names_count; i++) {
- if (STREQ(ract_uv_name, tangent_names[i]))
- *rcalc_act = false;
- if (STREQ(rren_uv_name, tangent_names[i]))
- *rcalc_ren = false;
- }
- }
- *rtangent_mask = 0;
-
- const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
- for (int n = 0; n < uv_layer_num; n++) {
- const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
- bool add = false;
- for (int i = 0; i < tangent_names_count; i++) {
- if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
- add = true;
- break;
- }
- }
- if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
- (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
- {
- add = true;
- }
- if (add)
- *rtangent_mask |= 1 << n;
- }
-
- if (uv_layer_num == 0)
- *rtangent_mask |= DM_TANGENT_MASK_ORCO;
-}
-
void DM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count)
-{
- int act_uv_n = -1;
- int ren_uv_n = -1;
- bool calc_act = false;
- bool calc_ren = false;
- char act_uv_name[MAX_NAME];
- char ren_uv_name[MAX_NAME];
- short tangent_mask = 0;
- DM_calc_loop_tangents_step_0(
- &dm->loopData, calc_active_tangent, tangent_names, tangent_names_count,
- &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
- if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
- /* Check we have all the needed layers */
- MPoly *mpoly = dm->getPolyArray(dm);
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- int totface = dm->getNumLoopTri(dm);
- /* Allocate needed tangent layers */
- for (int i = 0; i < tangent_names_count; i++)
- if (tangent_names[i][0])
- DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]);
- if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1)
- CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, "");
- if (calc_act && act_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name);
- if (calc_ren && ren_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, ren_uv_name);
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (totface != dm->getNumPolys(dm)) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_malloc_arrayN(totface, sizeof(int), __func__);
- int k, j;
- for (k = 0, j = 0; j < totface; k++, j++) {
- face_as_quad_map[k] = j;
- /* step over all quads */
- if (mpoly[looptri[j].poly].totloop == 4) {
- j++; /* skips the nest looptri */
- }
- }
- num_face_as_quad_map = k;
- }
- else {
- num_face_as_quad_map = totface;
- }
-#endif
-
- /* Calculation */
- {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
-
- dm->tangent_mask = 0;
- /* Calculate tangent layers */
- SGLSLMeshToTangent data_array[MAX_MTFACE];
- const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
- for (int n = 0; n < tangent_layer_num; n++) {
- int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
- BLI_assert(n < MAX_MTFACE);
- SGLSLMeshToTangent *mesh2tangent = &data_array[n];
- mesh2tangent->numTessFaces = totface;
-#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent->face_as_quad_map = face_as_quad_map;
- mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
-#endif
- mesh2tangent->mvert = dm->getVertArray(dm);
- mesh2tangent->mpoly = dm->getPolyArray(dm);
- mesh2tangent->mloop = dm->getLoopArray(dm);
- mesh2tangent->looptri = dm->getLoopTriArray(dm);
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- mesh2tangent->precomputedLoopNormals = dm->getLoopDataArray(dm, CD_NORMAL);
- mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
- mesh2tangent->orco = NULL;
- mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
-
- /* Fill the resulting tangent_mask */
- if (!mesh2tangent->mloopuv) {
- mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
- if (!mesh2tangent->orco)
- continue;
-
- dm->tangent_mask |= DM_TANGENT_MASK_ORCO;
- }
- else {
- int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
- int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- dm->tangent_mask |= 1 << (uv_ind - uv_start);
- }
-
- mesh2tangent->tangent = dm->loopData.layers[index].data;
- BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
- }
-
- BLI_assert(dm->tangent_mask == tangent_mask);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- }
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (face_as_quad_map) {
- MEM_freeN(face_as_quad_map);
- }
-#undef USE_LOOPTRI_DETECT_QUADS
-
-#endif
-
- /* Update active layer index */
- int act_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
- if (act_uv_index != -1) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[act_uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
-
- /* Update render layer index */
- int ren_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
- if (ren_uv_index != -1) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[ren_uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
- }
-}
-
-/** \} */
-
-
-void DM_calc_auto_bump_scale(DerivedMesh *dm)
-{
- /* int totvert = dm->getNumVerts(dm); */ /* UNUSED */
- int totface = dm->getNumTessFaces(dm);
-
- MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getTessFaceArray(dm);
- MTFace *mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
-
- if (mtface) {
- double dsum = 0.0;
- int nr_accumulated = 0;
- int f;
-
- for (f = 0; f < totface; f++) {
- {
- float *verts[4], *tex_coords[4];
- const int nr_verts = mface[f].v4 != 0 ? 4 : 3;
- bool is_degenerate;
- int i;
-
- verts[0] = mvert[mface[f].v1].co; verts[1] = mvert[mface[f].v2].co; verts[2] = mvert[mface[f].v3].co;
- tex_coords[0] = mtface[f].uv[0]; tex_coords[1] = mtface[f].uv[1]; tex_coords[2] = mtface[f].uv[2];
- if (nr_verts == 4) {
- verts[3] = mvert[mface[f].v4].co;
- tex_coords[3] = mtface[f].uv[3];
- }
-
- /* discard degenerate faces */
- is_degenerate = 0;
- if (equals_v3v3(verts[0], verts[1]) ||
- equals_v3v3(verts[0], verts[2]) ||
- equals_v3v3(verts[1], verts[2]) ||
- equals_v2v2(tex_coords[0], tex_coords[1]) ||
- equals_v2v2(tex_coords[0], tex_coords[2]) ||
- equals_v2v2(tex_coords[1], tex_coords[2]))
- {
- is_degenerate = 1;
- }
-
- /* verify last vertex as well if this is a quad */
- if (is_degenerate == 0 && nr_verts == 4) {
- if (equals_v3v3(verts[3], verts[0]) ||
- equals_v3v3(verts[3], verts[1]) ||
- equals_v3v3(verts[3], verts[2]) ||
- equals_v2v2(tex_coords[3], tex_coords[0]) ||
- equals_v2v2(tex_coords[3], tex_coords[1]) ||
- equals_v2v2(tex_coords[3], tex_coords[2]))
- {
- is_degenerate = 1;
- }
-
- /* verify the winding is consistent */
- if (is_degenerate == 0) {
- float prev_edge[2];
- bool is_signed = 0;
- sub_v2_v2v2(prev_edge, tex_coords[0], tex_coords[3]);
-
- i = 0;
- while (is_degenerate == 0 && i < 4) {
- float cur_edge[2], signed_area;
- sub_v2_v2v2(cur_edge, tex_coords[(i + 1) & 0x3], tex_coords[i]);
- signed_area = cross_v2v2(prev_edge, cur_edge);
-
- if (i == 0) {
- is_signed = (signed_area < 0.0f) ? 1 : 0;
- }
- else if ((is_signed != 0) != (signed_area < 0.0f)) {
- is_degenerate = 1;
- }
-
- if (is_degenerate == 0) {
- copy_v2_v2(prev_edge, cur_edge);
- i++;
- }
- }
- }
- }
-
- /* proceed if not a degenerate face */
- if (is_degenerate == 0) {
- int nr_tris_to_pile = 0;
- /* quads split at shortest diagonal */
- int offs = 0; /* initial triangulation is 0,1,2 and 0, 2, 3 */
- if (nr_verts == 4) {
- float pos_len_diag0, pos_len_diag1;
-
- pos_len_diag0 = len_squared_v3v3(verts[2], verts[0]);
- pos_len_diag1 = len_squared_v3v3(verts[3], verts[1]);
-
- if (pos_len_diag1 < pos_len_diag0) {
- offs = 1; // alter split
- }
- else if (pos_len_diag0 == pos_len_diag1) { /* do UV check instead */
- float tex_len_diag0, tex_len_diag1;
-
- tex_len_diag0 = len_squared_v2v2(tex_coords[2], tex_coords[0]);
- tex_len_diag1 = len_squared_v2v2(tex_coords[3], tex_coords[1]);
-
- if (tex_len_diag1 < tex_len_diag0) {
- offs = 1; /* alter split */
- }
- }
- }
- nr_tris_to_pile = nr_verts - 2;
- if (nr_tris_to_pile == 1 || nr_tris_to_pile == 2) {
- const int indices[6] = {offs + 0, offs + 1, offs + 2, offs + 0, offs + 2, (offs + 3) & 0x3 };
- int t;
- for (t = 0; t < nr_tris_to_pile; t++) {
- float f2x_area_uv;
- const float *p0 = verts[indices[t * 3 + 0]];
- const float *p1 = verts[indices[t * 3 + 1]];
- const float *p2 = verts[indices[t * 3 + 2]];
-
- float edge_t0[2], edge_t1[2];
- sub_v2_v2v2(edge_t0, tex_coords[indices[t * 3 + 1]], tex_coords[indices[t * 3 + 0]]);
- sub_v2_v2v2(edge_t1, tex_coords[indices[t * 3 + 2]], tex_coords[indices[t * 3 + 0]]);
-
- f2x_area_uv = fabsf(cross_v2v2(edge_t0, edge_t1));
- if (f2x_area_uv > FLT_EPSILON) {
- float norm[3], v0[3], v1[3], f2x_surf_area, fsurf_ratio;
- sub_v3_v3v3(v0, p1, p0);
- sub_v3_v3v3(v1, p2, p0);
- cross_v3_v3v3(norm, v0, v1);
-
- f2x_surf_area = len_v3(norm);
- fsurf_ratio = f2x_surf_area / f2x_area_uv; /* tri area divided by texture area */
-
- nr_accumulated++;
- dsum += (double)(fsurf_ratio);
- }
- }
- }
- }
- }
- }
-
- /* finalize */
- {
- const float avg_area_ratio = (nr_accumulated > 0) ? ((float)(dsum / nr_accumulated)) : 1.0f;
- const float use_as_render_bump_scale = sqrtf(avg_area_ratio); // use width of average surface ratio as your bump scale
- dm->auto_bump_scale = use_as_render_bump_scale;
- }
- }
- else {
- dm->auto_bump_scale = 1.0f;
- }
-}
-
-void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, DMVertexAttribs *attribs)
-{
- CustomData *vdata, *ldata;
- int a, b, layer;
- const bool is_editmesh = (dm->type == DM_TYPE_EDITBMESH);
-
- /* From the layers requested by the GLSL shader, figure out which ones are
- * actually available for this derivedmesh, and retrieve the pointers */
-
- memset(attribs, 0, sizeof(DMVertexAttribs));
-
- vdata = &dm->vertData;
- ldata = dm->getLoopDataLayout(dm);
-
- /* calc auto bump scale if necessary */
- if (dm->auto_bump_scale <= 0.0f)
- DM_calc_auto_bump_scale(dm);
-
- char tangent_names[MAX_MTFACE][MAX_NAME];
- int tangent_names_count;
- /* Add a tangent layer/layers. */
- DM_calc_tangents_names_from_gpu(gattribs, tangent_names, &tangent_names_count);
-
- if (tangent_names_count)
- dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
-
- for (b = 0; b < gattribs->totlayer; b++) {
- int type = gattribs->layer[b].type;
- layer = -1;
- if (type == CD_AUTO_FROM_NAME) {
- /* We need to deduct what exact layer is used.
- *
- * We do it based on the specified name.
- */
- if (gattribs->layer[b].name[0]) {
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- type = CD_MTFACE;
- if (layer == -1) {
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- type = CD_MCOL;
- }
- if (layer == -1) {
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- type = CD_TANGENT;
- }
- if (layer == -1) {
- continue;
- }
- }
- else {
- /* Fall back to the UV layer, which matches old behavior. */
- type = CD_MTFACE;
- }
- }
- if (type == CD_MTFACE) {
- /* uv coordinates */
- if (layer == -1) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
- }
-
- a = attribs->tottface++;
-
- if (layer != -1) {
- attribs->tface[a].array = is_editmesh ? NULL : ldata->layers[layer].data;
- attribs->tface[a].em_offset = ldata->layers[layer].offset;
- }
- else {
- attribs->tface[a].array = NULL;
- attribs->tface[a].em_offset = -1;
- }
-
- attribs->tface[a].gl_index = gattribs->layer[b].glindex;
- attribs->tface[a].gl_info_index = gattribs->layer[b].glinfoindoex;
- attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
- }
- else if (type == CD_MCOL) {
- if (layer == -1) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
- }
-
- a = attribs->totmcol++;
-
- if (layer != -1) {
- attribs->mcol[a].array = is_editmesh ? NULL : ldata->layers[layer].data;
- /* odd, store the offset for a different layer type here, but editmode draw code expects it */
- attribs->mcol[a].em_offset = ldata->layers[layer].offset;
- }
- else {
- attribs->mcol[a].array = NULL;
- attribs->mcol[a].em_offset = -1;
- }
-
- attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
- attribs->mcol[a].gl_info_index = gattribs->layer[b].glinfoindoex;
- }
- else if (type == CD_TANGENT) {
- /* note, even with 'is_editmesh' this uses the derived-meshes loop data */
- if (layer == -1) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
- }
-
- a = attribs->tottang++;
-
- if (layer != -1) {
- attribs->tang[a].array = dm->loopData.layers[layer].data;
- attribs->tang[a].em_offset = dm->loopData.layers[layer].offset;
- }
- else {
- attribs->tang[a].array = NULL;
- attribs->tang[a].em_offset = -1;
- }
-
- attribs->tang[a].gl_index = gattribs->layer[b].glindex;
- attribs->tang[a].gl_info_index = gattribs->layer[b].glinfoindoex;
- }
- else if (type == CD_ORCO) {
- /* original coordinates */
- if (layer == -1) {
- layer = CustomData_get_layer_index(vdata, CD_ORCO);
- }
- attribs->totorco = 1;
-
- if (layer != -1) {
- attribs->orco.array = vdata->layers[layer].data;
- attribs->orco.em_offset = vdata->layers[layer].offset;
- }
- else {
- attribs->orco.array = NULL;
- attribs->orco.em_offset = -1;
- }
-
- attribs->orco.gl_index = gattribs->layer[b].glindex;
- attribs->orco.gl_texco = gattribs->layer[b].gltexco;
- attribs->orco.gl_info_index = gattribs->layer[b].glinfoindoex;
- }
- }
-}
-
-/**
- * Set vertex shader attribute inputs for a particular tessface vert
- *
- * \param a: tessface index
- * \param index: vertex index
- * \param vert: corner index (0, 1, 2, 3)
- * \param loop: absolute loop corner index
- */
-void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop)
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len)
{
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- int b;
-
- UNUSED_VARS(a, vert);
-
- /* orco texture coordinates */
- if (attribs->totorco) {
- /*const*/ float (*array)[3] = attribs->orco.array;
- const float *orco = (array) ? array[index] : zero;
-
- if (attribs->orco.gl_texco)
- glTexCoord3fv(orco);
- else
- glVertexAttrib3fv(attribs->orco.gl_index, orco);
- }
-
- /* uv texture coordinates */
- for (b = 0; b < attribs->tottface; b++) {
- const float *uv;
-
- if (attribs->tface[b].array) {
- const MLoopUV *mloopuv = &attribs->tface[b].array[loop];
- uv = mloopuv->uv;
- }
- else {
- uv = zero;
- }
-
- if (attribs->tface[b].gl_texco)
- glTexCoord2fv(uv);
- else
- glVertexAttrib2fv(attribs->tface[b].gl_index, uv);
- }
-
- /* vertex colors */
- for (b = 0; b < attribs->totmcol; b++) {
- GLfloat col[4];
-
- if (attribs->mcol[b].array) {
- const MLoopCol *cp = &attribs->mcol[b].array[loop];
- rgba_uchar_to_float(col, &cp->r);
- }
- else {
- zero_v4(col);
- }
-
- glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
- }
-
- /* tangent for normal mapping */
- for (b = 0; b < attribs->tottang; b++) {
- if (attribs->tang[b].array) {
- /*const*/ float (*array)[4] = attribs->tang[b].array;
- const float *tang = (array) ? array[loop] : zero;
- glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
- }
- }
-}
-
-void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs)
-{
- int i;
- if (attribs->totorco) {
- if (attribs->orco.gl_info_index != -1) {
- glUniform1i(attribs->orco.gl_info_index, 0);
- }
- }
- for (i = 0; i < attribs->tottface; i++) {
- if (attribs->tface[i].gl_info_index != -1) {
- glUniform1i(attribs->tface[i].gl_info_index, 0);
- }
- }
- for (i = 0; i < attribs->totmcol; i++) {
- if (attribs->mcol[i].gl_info_index != -1) {
- glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
- }
- }
-
- for (i = 0; i < attribs->tottang; i++) {
- if (attribs->tang[i].gl_info_index != -1) {
- glUniform1i(attribs->tang[i].gl_info_index, 0);
- }
- }
+ BKE_mesh_calc_loop_tangent_ex(
+ dm->getVertArray(dm),
+ dm->getPolyArray(dm), dm->getNumPolys(dm),
+ dm->getLoopArray(dm),
+ dm->getLoopTriArray(dm), dm->getNumLoopTri(dm),
+ &dm->loopData,
+ calc_active_tangent,
+ tangent_names, tangent_names_len,
+ CustomData_get_layer(&dm->polyData, CD_NORMAL),
+ dm->getLoopDataArray(dm, CD_NORMAL),
+ dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */
+ /* result */
+ &dm->loopData, dm->getNumLoops(dm),
+ &dm->tangent_mask);
}
/* Set object's bounding box based on DerivedMesh min/max data */
@@ -3948,191 +3454,87 @@ void DM_set_object_boundbox(Object *ob, DerivedMesh *dm)
ob->bb->flag &= ~BOUNDBOX_DIRTY;
}
-/* --- NAVMESH (begin) --- */
-#ifdef WITH_GAMEENGINE
-
-/* BMESH_TODO, navmesh is not working right currently
- * All tools set this as MPoly data, but derived mesh currently draws from MFace (tessface)
- *
- * Proposed solution, rather then copy CD_RECAST into the MFace array,
- * use ORIGINDEX to get the original poly index and then get the CD_RECAST
- * data from the original me->mpoly layer. - campbell
- */
-
-
-BLI_INLINE int navmesh_bit(int a, int b)
-{
- return (a & (1 << b)) >> b;
-}
-
-BLI_INLINE void navmesh_intToCol(int i, float col[3])
-{
- int r = navmesh_bit(i, 0) + navmesh_bit(i, 3) * 2 + 1;
- int g = navmesh_bit(i, 1) + navmesh_bit(i, 4) * 2 + 1;
- int b = navmesh_bit(i, 2) + navmesh_bit(i, 5) * 2 + 1;
- col[0] = 1 - r * 63.0f / 255.0f;
- col[1] = 1 - g * 63.0f / 255.0f;
- col[2] = 1 - b * 63.0f / 255.0f;
-}
-
-static void navmesh_drawColored(DerivedMesh *dm)
+void DM_init_origspace(DerivedMesh *dm)
{
- int a, glmode;
- MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT);
- MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE);
- int *polygonIdx = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
- float col[3];
+ const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
- if (!polygonIdx)
- return;
+ OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP);
+ const int numpoly = dm->getNumPolys(dm);
+ // const int numloop = dm->getNumLoops(dm);
+ MVert *mv = dm->getVertArray(dm);
+ MLoop *ml = dm->getLoopArray(dm);
+ MPoly *mp = dm->getPolyArray(dm);
+ int i, j, k;
-#if 0
- //UI_ThemeColor(TH_WIRE);
- glLineWidth(2.0);
- dm->drawEdges(dm, 0, 1);
-#endif
+ float (*vcos_2d)[2] = NULL;
+ BLI_array_staticdeclare(vcos_2d, 64);
- /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */
- {
- DEBUG_VBO("Using legacy code. drawNavMeshColored\n");
- glBegin(glmode = GL_QUADS);
- for (a = 0; a < dm->numTessFaceData; a++, mface++) {
- int new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES;
- int pi = polygonIdx[a];
- if (pi <= 0) {
- zero_v3(col);
- }
- else {
- navmesh_intToCol(pi, col);
- }
+ for (i = 0; i < numpoly; i++, mp++) {
+ OrigSpaceLoop *lof = lof_array + mp->loopstart;
- if (new_glmode != glmode) {
- glEnd();
- glBegin(glmode = new_glmode);
- }
- glColor3fv(col);
- glVertex3fv(mvert[mface->v1].co);
- glVertex3fv(mvert[mface->v2].co);
- glVertex3fv(mvert[mface->v3].co);
- if (mface->v4) {
- glVertex3fv(mvert[mface->v4].co);
+ if (mp->totloop == 3 || mp->totloop == 4) {
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ copy_v2_v2(lof->uv, default_osf[j]);
}
}
- glEnd();
- }
-}
-
-static void navmesh_DM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex UNUSED(setDrawOptions),
- DMCompareDrawOptions UNUSED(compareDrawOptions),
- void *UNUSED(userData), DMDrawFlag UNUSED(flag))
-{
- navmesh_drawColored(dm);
-}
+ else {
+ MLoop *l = &ml[mp->loopstart];
+ float p_nor[3], co[3];
+ float mat[3][3];
-static void navmesh_DM_drawFacesSolid(
- DerivedMesh *dm,
- float (*partial_redraw_planes)[4],
- bool UNUSED(fast), DMSetMaterial UNUSED(setMaterial))
-{
- UNUSED_VARS(partial_redraw_planes);
+ float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX};
+ float translate[2], scale[2];
- //drawFacesSolid_original(dm, partial_redraw_planes, fast, setMaterial);
- navmesh_drawColored(dm);
-}
+ BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
+ axis_dominant_v3_to_m3(mat, p_nor);
-static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
-{
- DerivedMesh *result;
- int maxFaces = dm->getNumPolys(dm);
- int *recastData;
- int vertsPerPoly = 0, nverts = 0, ndtris = 0, npolys = 0;
- float *verts = NULL;
- unsigned short *dtris = NULL, *dmeshes = NULL, *polys = NULL;
- int *dtrisToPolysMap = NULL, *dtrisToTrisMap = NULL, *trisToFacesMap = NULL;
- int res;
+ BLI_array_clear(vcos_2d);
+ BLI_array_reserve(vcos_2d, mp->totloop);
+ for (j = 0; j < mp->totloop; j++, l++) {
+ mul_v3_m3v3(co, mat, mv[l->v].co);
+ copy_v2_v2(vcos_2d[j], co);
- result = CDDM_copy(dm);
- if (!CustomData_has_layer(&result->polyData, CD_RECAST)) {
- int *sourceRecastData = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
- if (sourceRecastData) {
- CustomData_add_layer_named(&result->polyData, CD_RECAST, CD_DUPLICATE,
- sourceRecastData, maxFaces, "recastData");
- }
- }
- recastData = (int *)CustomData_get_layer(&result->polyData, CD_RECAST);
-
- /* note: This is not good design! - really should not be doing this */
- result->drawFacesTex = navmesh_DM_drawFacesTex;
- result->drawFacesSolid = navmesh_DM_drawFacesSolid;
-
-
- /* process mesh */
- res = buildNavMeshDataByDerivedMesh(dm, &vertsPerPoly, &nverts, &verts, &ndtris, &dtris,
- &npolys, &dmeshes, &polys, &dtrisToPolysMap, &dtrisToTrisMap,
- &trisToFacesMap);
- if (res) {
- size_t polyIdx;
-
- /* invalidate concave polygon */
- for (polyIdx = 0; polyIdx < (size_t)npolys; polyIdx++) {
- unsigned short *poly = &polys[polyIdx * 2 * vertsPerPoly];
- if (!polyIsConvex(poly, vertsPerPoly, verts)) {
- /* set negative polygon idx to all faces */
- unsigned short *dmesh = &dmeshes[4 * polyIdx];
- unsigned short tbase = dmesh[2];
- unsigned short tnum = dmesh[3];
- unsigned short ti;
-
- for (ti = 0; ti < tnum; ti++) {
- unsigned short triidx = dtrisToTrisMap[tbase + ti];
- unsigned short faceidx = trisToFacesMap[triidx];
- if (recastData[faceidx] > 0) {
- recastData[faceidx] = -recastData[faceidx];
- }
+ for (k = 0; k < 2; k++) {
+ if (co[k] > max[k])
+ max[k] = co[k];
+ else if (co[k] < min[k])
+ min[k] = co[k];
}
}
- }
- }
- else {
- printf("Navmesh: Unable to generate valid Navmesh");
- }
-
- /* clean up */
- if (verts != NULL)
- MEM_freeN(verts);
- if (dtris != NULL)
- MEM_freeN(dtris);
- if (dmeshes != NULL)
- MEM_freeN(dmeshes);
- if (polys != NULL)
- MEM_freeN(polys);
- if (dtrisToPolysMap != NULL)
- MEM_freeN(dtrisToPolysMap);
- if (dtrisToTrisMap != NULL)
- MEM_freeN(dtrisToTrisMap);
- if (trisToFacesMap != NULL)
- MEM_freeN(trisToFacesMap);
- return result;
-}
+ /* Brings min to (0, 0). */
+ negate_v2_v2(translate, min);
-#endif /* WITH_GAMEENGINE */
+ /* Scale will bring max to (1, 1). */
+ sub_v2_v2v2(scale, max, min);
+ if (scale[0] == 0.0f)
+ scale[0] = 1e-9f;
+ if (scale[1] == 0.0f)
+ scale[1] = 1e-9f;
+ invert_v2(scale);
-/* --- NAVMESH (end) --- */
+ /* Finally, transform all vcos_2d into ((0, 0), (1, 1)) square and assing them as origspace. */
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ add_v2_v2v2(lof->uv, vcos_2d[j], translate);
+ mul_v2_v2(lof->uv, scale);
+ }
+ }
+ }
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ BLI_array_free(vcos_2d);
+}
-void DM_init_origspace(DerivedMesh *dm)
+static void mesh_init_origspace(Mesh *mesh)
{
const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
- OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP);
- const int numpoly = dm->getNumPolys(dm);
- // const int numloop = dm->getNumLoops(dm);
- MVert *mv = dm->getVertArray(dm);
- MLoop *ml = dm->getLoopArray(dm);
- MPoly *mp = dm->getPolyArray(dm);
+ OrigSpaceLoop *lof_array = CustomData_get_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP);
+ const int numpoly = mesh->totpoly;
+ // const int numloop = mesh->totloop;
+ MVert *mv = mesh->mvert;
+ MLoop *ml = mesh->mloop;
+ MPoly *mp = mesh->mpoly;
int i, j, k;
float (*vcos_2d)[2] = NULL;
@@ -4190,12 +3592,11 @@ void DM_init_origspace(DerivedMesh *dm)
}
}
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ BKE_mesh_tessface_clear(mesh);
BLI_array_free(vcos_2d);
}
-
/* derivedmesh info printing function,
* to help track down differences DM output */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index eb7fefd423b..9f5b81a8915 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -55,7 +55,6 @@
#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"
@@ -65,6 +64,8 @@
#include "BKE_main.h"
#include "BKE_object.h"
+#include "DEG_depsgraph_build.h"
+
#include "BIK_api.h"
#include "RNA_access.h"
@@ -425,7 +426,7 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
return NULL;
/* See if this channel exists */
- chan = BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name));
+ chan = BKE_pose_channel_find_name(pose, name);
if (chan) {
return chan;
}
@@ -453,7 +454,9 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
chan->protectflag = OB_LOCK_ROT4D; /* lock by components by default */
BLI_addtail(&pose->chanbase, chan);
- BKE_pose_channels_hash_free(pose);
+ if (pose->chanhash) {
+ BLI_ghash_insert(pose->chanhash, chan->name, chan);
+ }
return chan;
}
@@ -581,12 +584,16 @@ void BKE_pose_copy_data_ex(bPose **dst, const bPose *src, const int flag, const
if (copy_constraints) {
BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true); // BKE_constraints_copy NULLs listb
pchan->constraints = listb;
- pchan->mpath = NULL; /* motion paths should not get copied yet... */
+
+ /* XXX: This is needed for motionpath drawing to work. Dunno why it was setting to null before... */
+ pchan->mpath = animviz_copy_motionpath(pchan->mpath);
}
if (pchan->prop) {
pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag);
}
+
+ pchan->draw_data = NULL; /* Drawing cache, no need to copy. */
}
/* for now, duplicate Bone Groups too when doing this */
@@ -780,6 +787,9 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
IDP_FreeProperty(pchan->prop);
MEM_freeN(pchan->prop);
}
+
+ /* Cached data, for new draw manager rendering code. */
+ MEM_SAFE_FREE(pchan->draw_data);
}
void BKE_pose_channel_free(bPoseChannel *pchan)
@@ -849,39 +859,6 @@ void BKE_pose_free(bPose *pose)
BKE_pose_free_ex(pose, true);
}
-static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan)
-{
- bConstraint *pcon, *con;
-
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- copy_v3_v3(pchan->eul, chan->eul);
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- copy_qt_qt(pchan->quat, chan->quat);
- pchan->rotmode = chan->rotmode;
- copy_m4_m4(pchan->chan_mat, (float(*)[4])chan->chan_mat);
- copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
- pchan->flag = chan->flag;
-
- pchan->roll1 = chan->roll1;
- pchan->roll2 = chan->roll2;
- pchan->curveInX = chan->curveInX;
- pchan->curveInY = chan->curveInY;
- pchan->curveOutX = chan->curveOutX;
- pchan->curveOutY = chan->curveOutY;
- pchan->ease1 = chan->ease1;
- pchan->ease2 = chan->ease2;
- pchan->scaleIn = chan->scaleIn;
- pchan->scaleOut = chan->scaleOut;
-
- con = chan->constraints.first;
- for (pcon = pchan->constraints.first; pcon && con; pcon = pcon->next, con = con->next) {
- pcon->enforce = con->enforce;
- pcon->headtail = con->headtail;
- }
-}
-
/**
* Copy the internal members of each pose channel including constraints
* and ID-Props, used when duplicating bones in editmode.
@@ -1323,25 +1300,6 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
/* ************** Pose Management Tools ****************** */
-/* Copy the data from the action-pose (src) into the pose */
-/* both args are assumed to be valid */
-/* exported to game engine */
-/* Note! this assumes both poses are aligned, this isn't always true when dealing with user poses */
-void extract_pose_from_pose(bPose *pose, const bPose *src)
-{
- const bPoseChannel *schan;
- bPoseChannel *pchan = pose->chanbase.first;
-
- if (pose == src) {
- printf("extract_pose_from_pose source and target are the same\n");
- return;
- }
-
- for (schan = src->chanbase.first; (schan && pchan); schan = schan->next, pchan = pchan->next) {
- copy_pose_channel_data(pchan, schan);
- }
-}
-
/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */
void BKE_pose_rest(bPose *pose)
{
@@ -1428,7 +1386,7 @@ void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
/* Depsgraph components depends on actual pose state,
* if pose was changed depsgraph is to be updated as well.
*/
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
/* For the calculation of the effects of an Action at the given frame on an object
@@ -1498,7 +1456,7 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c
adt.action = act;
/* execute effects of Action on to workob (or it's PoseChannels) */
- BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(NULL, NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
}
}
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index b3c6fb4f3a9..07b8b69bc70 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -35,6 +35,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_dlrbTree.h"
#include "BLT_translation.h"
@@ -43,18 +44,29 @@
#include "DNA_key_types.h"
#include "DNA_scene_types.h"
+#include "BKE_anim.h"
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
-#include "BKE_anim.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+#include "DEG_depsgraph_build.h"
+
+#include "GPU_batch.h"
+
// XXX bad level call...
+extern short compare_ak_cfraPtr(void *node, void *data);
+extern void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+extern void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* --------------------- */
/* forward declarations */
@@ -102,6 +114,10 @@ void animviz_free_motionpath_cache(bMotionPath *mpath)
if (mpath->points)
MEM_freeN(mpath->points);
+ GWN_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
+ GWN_BATCH_DISCARD_SAFE(mpath->batch_line);
+ GWN_BATCH_DISCARD_SAFE(mpath->batch_points);
+
/* reset the relevant parameters */
mpath->points = NULL;
mpath->length = 0;
@@ -125,6 +141,27 @@ void animviz_free_motionpath(bMotionPath *mpath)
/* ------------------- */
+/* Make a copy of motionpath data, so that viewing with copy on write works */
+bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
+{
+ bMotionPath *mpath_dst;
+
+ if (mpath_src == NULL)
+ return NULL;
+
+ mpath_dst = MEM_dupallocN(mpath_src);
+ mpath_dst->points = MEM_dupallocN(mpath_src->points);
+
+ /* should get recreated on draw... */
+ mpath_dst->points_vbo = NULL;
+ mpath_dst->batch_line = NULL;
+ mpath_dst->batch_points = NULL;
+
+ return mpath_dst;
+}
+
+/* ------------------- */
+
/**
* Setup motion paths for the given data.
* \note Only used when explicitly calculating paths on bones which may/may not be consider already
@@ -207,7 +244,7 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec
mpath->color[1] = 0.0;
mpath->color[2] = 0.0;
- mpath->line_thickness = 1;
+ mpath->line_thickness = 2;
mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
/* allocate a cache */
@@ -228,8 +265,16 @@ typedef struct MPathTarget {
bMotionPath *mpath; /* motion path in question */
+ DLRBT_Tree keys; /* temp, to know where the keyframes are */
+
+ /* Original (Source Objects) */
Object *ob; /* source object */
bPoseChannel *pchan; /* source posechannel (if applicable) */
+
+ /* "Evaluated" Copies (these come from the background COW copie
+ * that provide all the coordinates we want to save off)
+ */
+ Object *ob_eval; /* evaluated object */
} MPathTarget;
/* ........ */
@@ -273,88 +318,21 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
/* ........ */
-/* Note on evaluation optimizations:
- * Optimization's currently used here play tricks with the depsgraph in order to try and
- * evaluate as few objects as strictly necessary to get nicer performance under standard
- * production conditions. For those people who really need the accurate version,
- * disable the ifdef (i.e. 1 -> 0) and comment out the call to motionpaths_calc_optimise_depsgraph()
- */
-
-/* tweak the object ordering to trick depsgraph into making MotionPath calculations run faster */
-static void motionpaths_calc_optimise_depsgraph(Main *bmain, Scene *scene, ListBase *targets)
-{
- Base *base, *baseNext;
- MPathTarget *mpt;
-
- /* make sure our temp-tag isn't already in use */
- for (base = scene->base.first; base; base = base->next)
- base->object->flag &= ~BA_TEMP_TAG;
-
- /* for each target, dump its object to the start of the list if it wasn't moved already */
- for (mpt = targets->first; mpt; mpt = mpt->next) {
- for (base = scene->base.first; base; base = baseNext) {
- baseNext = base->next;
-
- if ((base->object == mpt->ob) && !(mpt->ob->flag & BA_TEMP_TAG)) {
- BLI_remlink(&scene->base, base);
- BLI_addhead(&scene->base, base);
-
- mpt->ob->flag |= BA_TEMP_TAG;
-
- /* we really don't need to continue anymore once this happens, but this line might really 'break' */
- break;
- }
- }
- }
-
- /* "brew me a list that's sorted a bit faster now depsy" */
- DAG_scene_relations_rebuild(bmain, scene);
-}
-
/* update scene for current frame */
-static void motionpaths_calc_update_scene(Main *bmain, Scene *scene)
+static void motionpaths_calc_update_scene(Main *bmain,
+ struct Depsgraph *depsgraph)
{
-#if 1 // 'production' optimizations always on
- /* rigid body simulation needs complete update to work correctly for now */
- /* RB_TODO investigate if we could avoid updating everything */
- if (BKE_scene_check_rigidbody_active(scene)) {
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
- }
- else { /* otherwise we can optimize by restricting updates */
- Base *base, *last = NULL;
-
- /* only stuff that moves or needs display still */
- DAG_scene_update_flags(bmain, scene, scene->lay, true, false);
-
- /* find the last object with the tag
- * - all those afterwards are assumed to not be relevant for our calculations
- */
- /* optimize further by moving out... */
- for (base = scene->base.first; base; base = base->next) {
- if (base->object->flag & BA_TEMP_TAG)
- last = base;
- }
-
- /* perform updates for tagged objects */
- /* XXX: this will break if rigs depend on scene or other data that
- * is animated but not attached to/updatable from objects */
- for (base = scene->base.first; base; base = base->next) {
- /* update this object */
- BKE_object_handle_update(bmain, bmain->eval_ctx, scene, base->object);
-
- /* if this is the last one we need to update, let's stop to save some time */
- if (base == last)
- break;
- }
- }
-#else // original, 'always correct' version
- /* do all updates
+ /* Do all updates
* - if this is too slow, resort to using a more efficient way
* that doesn't force complete update, but for now, this is the
* most accurate way!
+ *
+ * TODO(segey): Bring back partial updates, which became impossible
+ * with the new depsgraph due to unsorted nature of bases.
+ *
+ * TODO(sergey): Use evaluation context dedicated to motion paths.
*/
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); /* XXX this is the best way we can get anything moving */
-#endif
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
/* ........ */
@@ -372,28 +350,45 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets)
/* current frame must be within the range the cache works for
* - is inclusive of the first frame, but not the last otherwise we get buffer overruns
*/
- if ((CFRA < mpath->start_frame) || (CFRA >= mpath->end_frame))
+ if ((CFRA < mpath->start_frame) || (CFRA >= mpath->end_frame)) {
continue;
+ }
/* get the relevant cache vert to write to */
mpv = mpath->points + (CFRA - mpath->start_frame);
- /* pose-channel or object path baking? */
+ Object *ob_eval = mpt->ob_eval;
+
+ /* Lookup evaluated pose channel, here because the depsgraph
+ * evaluation can change them so they are not cached in mpt. */
+ bPoseChannel *pchan_eval = NULL;
if (mpt->pchan) {
+ pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, mpt->pchan->name);
+ }
+
+ /* pose-channel or object path baking? */
+ if (pchan_eval) {
/* heads or tails */
if (mpath->flag & MOTIONPATH_FLAG_BHEAD) {
- copy_v3_v3(mpv->co, mpt->pchan->pose_head);
+ copy_v3_v3(mpv->co, pchan_eval->pose_head);
}
else {
- copy_v3_v3(mpv->co, mpt->pchan->pose_tail);
+ copy_v3_v3(mpv->co, pchan_eval->pose_tail);
}
/* result must be in worldspace */
- mul_m4_v3(mpt->ob->obmat, mpv->co);
+ mul_m4_v3(ob_eval->obmat, mpv->co);
}
else {
/* worldspace object location */
- copy_v3_v3(mpv->co, mpt->ob->obmat[3]);
+ copy_v3_v3(mpv->co, ob_eval->obmat[3]);
+ }
+
+ float mframe = (float)(CFRA);
+
+ /* Tag if it's a keyframe */
+ if (BLI_dlrbTree_search_exact(&mpt->keys, compare_ak_cfraPtr, &mframe)) {
+ mpv->flag |= MOTIONPATH_VERT_KEY;
}
}
}
@@ -404,7 +399,7 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets)
* - recalc: whether we need to
*/
/* TODO: include reports pointer? */
-void animviz_calc_motionpaths(Main *bmain, Scene *scene, ListBase *targets)
+ void animviz_calc_motionpaths(Depsgraph *depsgraph, Main *bmain, Scene *scene, ListBase *targets)
{
MPathTarget *mpt;
int sfra, efra;
@@ -428,26 +423,64 @@ void animviz_calc_motionpaths(Main *bmain, Scene *scene, ListBase *targets)
}
if (efra <= sfra) return;
- /* optimize the depsgraph for faster updates */
- /* TODO: whether this is used should depend on some setting for the level of optimizations used */
- motionpaths_calc_optimise_depsgraph(bmain, scene, targets);
+
+ /* get copies of objects/bones to get the calculated results from
+ * (for copy-on-write evaluation), so that we actually get some results
+ */
+ // TODO: Create a copy of background depsgraph that only contain these entities, and only evaluates them..
+ for (mpt = targets->first; mpt; mpt = mpt->next) {
+ mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob);
+
+ AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id);
+
+ /* build list of all keyframes in active action for object or pchan */
+ BLI_dlrbTree_init(&mpt->keys);
+
+ if (adt) {
+ bAnimVizSettings *avs;
+
+ /* get pointer to animviz settings for each target */
+ if (mpt->pchan)
+ avs = &mpt->ob->pose->avs;
+ else
+ avs = &mpt->ob->avs;
+
+ /* it is assumed that keyframes for bones are all grouped in a single group
+ * unless an option is set to always use the whole action
+ */
+ if ((mpt->pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) {
+ bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
+
+ if (agrp) {
+ agroup_to_keylist(adt, agrp, &mpt->keys, NULL);
+ BLI_dlrbTree_linkedlist_sync(&mpt->keys);
+ }
+ }
+ else {
+ action_to_keylist(adt, adt->action, &mpt->keys, NULL);
+ BLI_dlrbTree_linkedlist_sync(&mpt->keys);
+ }
+ }
+ }
/* calculate path over requested range */
for (CFRA = sfra; CFRA <= efra; CFRA++) {
/* update relevant data for new frame */
- motionpaths_calc_update_scene(bmain, scene);
+ motionpaths_calc_update_scene(bmain, depsgraph);
/* perform baking for targets */
motionpaths_calc_bake_targets(scene, targets);
}
/* reset original environment */
+ // XXX: Soon to be obsolete
CFRA = cfra;
- motionpaths_calc_update_scene(bmain, scene);
+ motionpaths_calc_update_scene(bmain, depsgraph);
/* clear recalc flags from targets */
for (mpt = targets->first; mpt; mpt = mpt->next) {
bAnimVizSettings *avs;
+ bMotionPath *mpath = mpt->mpath;
/* get pointer to animviz settings for each target */
if (mpt->pchan)
@@ -457,6 +490,14 @@ void animviz_calc_motionpaths(Main *bmain, Scene *scene, ListBase *targets)
/* clear the flag requesting recalculation of targets */
avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
+
+ /* Clean temp data */
+ BLI_dlrbTree_free(&mpt->keys);
+
+ /* Free previous batches to force update. */
+ GWN_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
+ GWN_BATCH_DISCARD_SAFE(mpath->batch_line);
+ GWN_BATCH_DISCARD_SAFE(mpath->batch_points);
}
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 05cb10ab7a4..fd7497f9ba1 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -60,7 +60,6 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
#include "BKE_global.h"
@@ -70,14 +69,15 @@
#include "BKE_report.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#include "nla_private.h"
#include "atomic_ops.h"
-#include "DEG_depsgraph.h"
-
/* ***************************************** */
/* AnimData API */
@@ -97,6 +97,7 @@ bool id_type_can_have_animdata(const short id_type)
case ID_MA: case ID_TE: case ID_NT:
case ID_LA: case ID_CA: case ID_WO:
case ID_LS:
+ case ID_LP:
case ID_SPK:
case ID_SCE:
case ID_MC:
@@ -250,6 +251,9 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
/* free drivers - stored as a list of F-Curves */
free_fcurves(&adt->drivers);
+ /* free driver array cache */
+ MEM_SAFE_FREE(adt->driver_array);
+
/* free overrides */
/* TODO... */
@@ -263,7 +267,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
/* Copying -------------------------------------------- */
/* Make a copy of the given AnimData - to be used when copying datablocks */
-AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
+AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action, const bool do_id_user)
{
AnimData *dadt;
@@ -278,7 +282,7 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, 0, false);
BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, 0, false);
}
- else {
+ else if (do_id_user) {
id_us_plus((ID *)dadt->action);
id_us_plus((ID *)dadt->tmpact);
}
@@ -288,6 +292,7 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
/* duplicate drivers (F-Curves) */
copy_fcurves(&dadt->drivers, &adt->drivers);
+ dadt->driver_array = NULL;
/* don't copy overrides */
BLI_listbase_clear(&dadt->overrides);
@@ -296,19 +301,19 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
return dadt;
}
-bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const bool do_action)
+bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const bool do_action, const bool do_id_user)
{
AnimData *adt;
if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
return false;
- BKE_animdata_free(id_to, true);
+ BKE_animdata_free(id_to, do_id_user);
adt = BKE_animdata_from_id(id_from);
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
- iat->adt = BKE_animdata_copy(bmain, adt, do_action);
+ iat->adt = BKE_animdata_copy(bmain, adt, do_action, do_id_user);
}
return true;
@@ -604,36 +609,8 @@ char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *p
Object *ob = CTX_data_active_object(C);
if (ob && id) {
- /* only id-types which can be remapped to go through objects should be considered */
- switch (GS(id->name)) {
- case ID_TE: /* textures */
- {
- Material *ma = give_current_material(ob, ob->actcol);
- Tex *tex = give_current_material_texture(ma);
-
- /* assumes: texture will only be shown if it is active material's active texture it's ok */
- if ((ID *)tex == id) {
- char name_esc_ma[(sizeof(ma->id.name) - 2) * 2];
- char name_esc_tex[(sizeof(tex->id.name) - 2) * 2];
-
- BLI_strescape(name_esc_ma, ma->id.name + 2, sizeof(name_esc_ma));
- BLI_strescape(name_esc_tex, tex->id.name + 2, sizeof(name_esc_tex));
-
- /* create new path */
- // TODO: use RNA path functions to construct step by step instead?
- // FIXME: maybe this isn't even needed anymore...
- path = BLI_sprintfN("material_slots[\"%s\"].material.texture_slots[\"%s\"].texture.%s",
- name_esc_ma, name_esc_tex, basepath);
-
- /* free old one */
- if (basepath != base_path)
- MEM_freeN(basepath);
- }
- break;
- }
- default:
- break;
- }
+ /* TODO: after material textures were removed, this function serves
+ * no purpose anymore, but could be used again so was not removed. */
/* fix RNA pointer, as we've now changed the ID root by changing the paths */
if (basepath != path) {
@@ -1558,6 +1535,72 @@ static bool animsys_store_rna_setting(
/* less than 1.0 evaluates to false, use epsilon to avoid float error */
#define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON)))
+static bool animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value)
+{
+ PropertyRNA *prop = anim_rna->prop;
+ PointerRNA *ptr = &anim_rna->ptr;
+ int array_index = anim_rna->prop_index;
+ float orig_value;
+
+ /* caller must ensure this is animatable */
+ BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ {
+ if (array_index != -1) {
+ const int orig_value_coerce = RNA_property_boolean_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const int orig_value_coerce = RNA_property_boolean_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_INT:
+ {
+ if (array_index != -1) {
+ const int orig_value_coerce = RNA_property_int_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const int orig_value_coerce = RNA_property_int_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_FLOAT:
+ {
+ if (array_index != -1) {
+ const float orig_value_coerce = RNA_property_float_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const float orig_value_coerce = RNA_property_float_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_ENUM:
+ {
+ const int orig_value_coerce = RNA_property_enum_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ break;
+ }
+ default:
+ /* nothing can be done here... so it is unsuccessful? */
+ return false;
+ }
+
+ if (r_value != NULL) {
+ *r_value = orig_value;
+ }
+
+ /* successful */
+ return true;
+}
+
/* Write the given value to a setting using RNA, and return success */
static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value)
{
@@ -1568,27 +1611,24 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
/* caller must ensure this is animatable */
BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
- /* set value for animatable numerical values only
- * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated
- * without an ID provided, which causes the animateable test to fail!
- */
- bool written = false;
+ /* Check whether value is new. Otherwise we skip all the updates. */
+ float old_value;
+ if (!animsys_read_rna_setting(anim_rna, &old_value)) {
+ return false;
+ }
+ if (old_value == value) {
+ return true;
+ }
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
{
const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value);
if (array_index != -1) {
- if (RNA_property_boolean_get_index(ptr, prop, array_index) != value_coerce) {
- RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
- written = true;
- }
+ RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
}
else {
- if (RNA_property_boolean_get(ptr, prop) != value_coerce) {
- RNA_property_boolean_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_boolean_set(ptr, prop, value_coerce);
}
break;
}
@@ -1597,16 +1637,10 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
int value_coerce = (int)value;
RNA_property_int_clamp(ptr, prop, &value_coerce);
if (array_index != -1) {
- if (RNA_property_int_get_index(ptr, prop, array_index) != value_coerce) {
- RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
- written = true;
- }
+ RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
}
else {
- if (RNA_property_int_get(ptr, prop) != value_coerce) {
- RNA_property_int_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_int_set(ptr, prop, value_coerce);
}
break;
}
@@ -1615,26 +1649,17 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
float value_coerce = value;
RNA_property_float_clamp(ptr, prop, &value_coerce);
if (array_index != -1) {
- if (RNA_property_float_get_index(ptr, prop, array_index) != value_coerce) {
- RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
- written = true;
- }
+ RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
}
else {
- if (RNA_property_float_get(ptr, prop) != value_coerce) {
- RNA_property_float_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_float_set(ptr, prop, value_coerce);
}
break;
}
case PROP_ENUM:
{
const int value_coerce = (int)value;
- if (RNA_property_enum_get(ptr, prop) != value_coerce) {
- RNA_property_enum_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_enum_set(ptr, prop, value_coerce);
break;
}
default:
@@ -1662,23 +1687,6 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
}
#endif
- /* as long as we don't do property update, we still tag datablock
- * as having been updated. this flag does not cause any updates to
- * be run, it's for e.g. render engines to synchronize data */
- if (written && ptr->id.data) {
- ID *id = ptr->id.data;
-
- /* for cases like duplifarmes it's only a temporary so don't
- * notify anyone of updates */
- if (!(id->recalc & ID_RECALC_SKIP_ANIM_TAG)) {
- /* NOTE: This is a bit annoying to use atomic API here, but this
- * code is at it's EOL and removed already in 2.8 branch.
- */
- atomic_fetch_and_or_int32(&id->recalc, ID_RECALC);
- DAG_id_type_tag(G.main, GS(id->name));
- }
- }
-
/* successful */
return true;
}
@@ -1697,24 +1705,46 @@ bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu,
return ok;
}
+static void animsys_write_orig_anim_rna(
+ PointerRNA *ptr,
+ AnimMapper *remap,
+ FCurve *fcu,
+ float value)
+{
+ /* Pointer is expected to be an ID pointer, if it's not -- we are doomed. */
+ PointerRNA orig_ptr = *ptr;
+ orig_ptr.id.data = ((ID *)orig_ptr.id.data)->orig_id;
+ orig_ptr.data = orig_ptr.id.data;
+ PathResolvedRNA orig_anim_rna;
+ /* TODO(sergey): Is there a faster way to get anim_rna of original ID? */
+ if (animsys_store_rna_setting(&orig_ptr, remap, fcu->rna_path, fcu->array_index, &orig_anim_rna)) {
+ animsys_write_rna_setting(&orig_anim_rna, value);
+ }
+}
+
/* Evaluate all the F-Curves in the given list
* This performs a set of standard checks. If extra checks are required, separate code should be used
*/
-static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper *remap, float ctime)
-{
- FCurve *fcu;
-
- /* calculate then execute each curve */
- for (fcu = list->first; fcu; fcu = fcu->next) {
- /* check if this F-Curve doesn't belong to a muted group */
- if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED) == 0) {
- /* check if this curve should be skipped */
- if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
- const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
- animsys_write_rna_setting(&anim_rna, curval);
- }
+static void animsys_evaluate_fcurves(
+ Depsgraph *depsgraph, PointerRNA *ptr, ListBase *list, AnimMapper *remap, float ctime)
+{
+ const bool is_active_depsgraph = DEG_is_active(depsgraph);
+ /* Calculate then execute each curve. */
+ for (FCurve *fcu = list->first; fcu; fcu = fcu->next) {
+ /* Check if this F-Curve doesn't belong to a muted group. */
+ if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) {
+ continue;
+ }
+ /* Check if this curve should be skipped. */
+ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) {
+ continue;
+ }
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ animsys_write_rna_setting(&anim_rna, curval);
+ if (is_active_depsgraph) {
+ animsys_write_orig_anim_rna(ptr, remap, fcu, curval);
}
}
}
@@ -1826,7 +1856,8 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
}
/* Evaluate Action (F-Curve Bag) */
-void animsys_evaluate_action(PointerRNA *ptr, bAction *act, AnimMapper *remap, float ctime)
+static void animsys_evaluate_action_ex(
+ Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, AnimMapper *remap, float ctime)
{
/* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
if (act == NULL) return;
@@ -1835,7 +1866,12 @@ void animsys_evaluate_action(PointerRNA *ptr, bAction *act, AnimMapper *remap, f
action_idcode_patch_check(ptr->id.data, act);
/* calculate then execute each curve */
- animsys_evaluate_fcurves(ptr, &act->curves, remap, ctime);
+ animsys_evaluate_fcurves(depsgraph, ptr, &act->curves, remap, ctime);
+}
+
+void animsys_evaluate_action(Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, AnimMapper *remap, float ctime)
+{
+ animsys_evaluate_action_ex(depsgraph, ptr, act, remap, ctime);
}
/* ***************************************** */
@@ -1864,7 +1900,7 @@ static float nlastrip_get_influence(NlaStrip *strip, float cframe)
}
/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
-static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
+static void nlastrip_evaluate_controls(Depsgraph *depsgraph, NlaStrip *strip, float ctime)
{
/* now strip's evaluate F-Curves for these settings (if applicable) */
if (strip->fcurves.first) {
@@ -1874,7 +1910,7 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
/* execute these settings as per normal */
- animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime);
+ animsys_evaluate_fcurves(depsgraph, &strip_ptr, &strip->fcurves, NULL, ctime);
}
/* analytically generate values for influence and time (if applicable)
@@ -1896,7 +1932,7 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
}
/* gets the strip active at the current time for a list of strips for evaluation purposes */
-NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime)
+NlaEvalStrip *nlastrips_ctime_get_strip(Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime)
{
NlaStrip *strip, *estrip = NULL;
NlaEvalStrip *nes;
@@ -1973,7 +2009,7 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short
* - negative influence is not supported yet... how would that be defined?
*/
/* TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... */
- nlastrip_evaluate_controls(estrip, ctime);
+ nlastrip_evaluate_controls(depsgraph, estrip, ctime);
if (estrip->influence <= 0.0f)
return NULL;
@@ -1992,8 +2028,8 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short
return NULL;
/* evaluate controls for the relevant extents of the bordering strips... */
- nlastrip_evaluate_controls(estrip->prev, estrip->start);
- nlastrip_evaluate_controls(estrip->next, estrip->end);
+ nlastrip_evaluate_controls(depsgraph, estrip->prev, estrip->start);
+ nlastrip_evaluate_controls(depsgraph, estrip->next, estrip->end);
break;
}
@@ -2339,7 +2375,8 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, ListBase *channels, Li
}
/* evaluate transition strip */
-static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+static void nlastrip_evaluate_transition(
+ Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
ListBase tmp_channels = {NULL, NULL};
ListBase tmp_modifiers = {NULL, NULL};
@@ -2379,12 +2416,12 @@ static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, Li
/* first strip */
tmp_nes.strip_mode = NES_TIME_TRANSITION_START;
tmp_nes.strip = s1;
- nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
+ nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
/* second strip */
tmp_nes.strip_mode = NES_TIME_TRANSITION_END;
tmp_nes.strip = s2;
- nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
+ nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
/* accumulate temp-buffer and full-buffer, using the 'real' strip */
@@ -2395,7 +2432,8 @@ static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, Li
}
/* evaluate meta-strip */
-static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+static void nlastrip_evaluate_meta(
+ Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
ListBase tmp_modifiers = {NULL, NULL};
NlaStrip *strip = nes->strip;
@@ -2415,13 +2453,13 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase
/* find the child-strip to evaluate */
evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start;
- tmp_nes = nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime);
+ tmp_nes = nlastrips_ctime_get_strip(depsgraph, NULL, &strip->strips, -1, evaltime);
/* directly evaluate child strip into accumulation buffer...
* - there's no need to use a temporary buffer (as it causes issues [T40082])
*/
if (tmp_nes) {
- nlastrip_evaluate(ptr, channels, &tmp_modifiers, tmp_nes);
+ nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, tmp_nes);
/* free temp eval-strip */
MEM_freeN(tmp_nes);
@@ -2432,7 +2470,7 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase
}
/* evaluates the given evaluation strip */
-void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+void nlastrip_evaluate(Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
NlaStrip *strip = nes->strip;
@@ -2450,10 +2488,10 @@ void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers,
nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes);
break;
case NLASTRIP_TYPE_TRANSITION: /* transition */
- nlastrip_evaluate_transition(ptr, channels, modifiers, nes);
+ nlastrip_evaluate_transition(depsgraph, ptr, channels, modifiers, nes);
break;
case NLASTRIP_TYPE_META: /* meta */
- nlastrip_evaluate_meta(ptr, channels, modifiers, nes);
+ nlastrip_evaluate_meta(depsgraph, ptr, channels, modifiers, nes);
break;
default: /* do nothing */
@@ -2519,7 +2557,7 @@ void nladata_flush_channels(ListBase *channels)
*
* \param[out] echannels Evaluation channels with calculated values
*/
-static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime)
+static void animsys_evaluate_nla(Depsgraph *depsgraph, ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime)
{
NlaTrack *nlt;
short track_index = 0;
@@ -2557,7 +2595,7 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
has_strips = true;
/* otherwise, get strip to evaluate for this channel */
- nes = nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime);
+ nes = nlastrips_ctime_get_strip(depsgraph, &estrips, &nlt->strips, track_index, ctime);
if (nes) nes->track = nlt;
}
@@ -2598,14 +2636,14 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
}
/* add this to our list of evaluation strips */
- nlastrips_ctime_get_strip(&estrips, &dummy_trackslist, -1, ctime);
+ nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime);
}
else {
/* special case - evaluate as if there isn't any NLA data */
/* TODO: this is really just a stop-gap measure... */
if (G.debug & G_DEBUG) printf("NLA Eval: Stopgap for active action on NLA Stack - no strips case\n");
- animsys_evaluate_action(ptr, adt->action, adt->remap, ctime);
+ animsys_evaluate_action(depsgraph, ptr, adt->action, adt->remap, ctime);
BLI_freelistN(&estrips);
return;
}
@@ -2618,28 +2656,17 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
/* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
for (nes = estrips.first; nes; nes = nes->next)
- nlastrip_evaluate(ptr, echannels, NULL, nes);
+ nlastrip_evaluate(depsgraph, ptr, echannels, NULL, nes);
/* 3. free temporary evaluation data that's not used elsewhere */
BLI_freelistN(&estrips);
-
- /* Tag ID as updated so render engines will recognize changes in data
- * which is animated but doesn't have actions.
- */
- if (ptr->id.data != NULL) {
- ID *id = ptr->id.data;
- if (!(id->recalc & ID_RECALC_SKIP_ANIM_TAG)) {
- id->recalc |= ID_RECALC;
- DAG_id_type_tag(G.main, GS(id->name));
- }
- }
}
/* NLA Evaluation function (mostly for use through do_animdata)
* - All channels that will be affected are not cleared anymore. Instead, we just evaluate into
* some temp channels, where values can be accumulated in one go.
*/
-static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime)
+static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimData *adt, float ctime)
{
ListBase echannels = {NULL, NULL};
@@ -2647,7 +2674,7 @@ static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime)
* and also when the user jumps between different times instead of moving sequentially... */
/* evaluate the NLA stack, obtaining a set of values to flush */
- animsys_evaluate_nla(&echannels, ptr, adt, ctime);
+ animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime);
/* flush effects of accumulating channels in NLA to the actual data they affect */
nladata_flush_channels(&echannels);
@@ -2726,7 +2753,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* and that the flags for which parts of the anim-data settings need to be recalculated
* have been set already by the depsgraph. Now, we use the recalc
*/
-void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
+void BKE_animsys_evaluate_animdata(Depsgraph *depsgraph, Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
{
PointerRNA id_ptr;
@@ -2748,11 +2775,11 @@ void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ct
/* evaluate NLA-stack
* - active action is evaluated as part of the NLA stack as the last item
*/
- animsys_calculate_nla(&id_ptr, adt, ctime);
+ animsys_calculate_nla(depsgraph, &id_ptr, adt, ctime);
}
/* evaluate Active Action only */
else if (adt->action)
- animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime);
+ animsys_evaluate_action_ex(depsgraph, &id_ptr, adt->action, adt->remap, ctime);
/* reset tag */
adt->recalc &= ~ADT_RECALC_ANIM;
@@ -2796,7 +2823,7 @@ void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ct
* 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
* standard 'root') block are overridden by a larger 'user'
*/
-void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
+void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene *scene, float ctime)
{
ID *id;
@@ -2812,7 +2839,7 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
for (id = first; id; id = id->next) { \
if (ID_REAL_USERS(id) > 0) { \
AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
} \
} (void)0
@@ -2829,9 +2856,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
NtId_Type *ntp = (NtId_Type *)id; \
if (ntp->nodetree) { \
AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- BKE_animsys_evaluate_animdata(scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
} \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
} \
} (void)0
@@ -2923,27 +2950,60 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* ************** */
/* Evaluation API */
-void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id)
+void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id)
{
+ float ctime = DEG_get_ctime(depsgraph);
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 dependency graph instead...
*/
- DEG_debug_print_eval_time(__func__, id->name, id, eval_ctx->ctime);
- BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM);
+ DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime);
+ short recalc = ADT_RECALC_ANIM;
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, recalc);
+}
+
+void BKE_animsys_update_driver_array(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver.
+ * Ideally the depsgraph could pass a pointer to the COW driver directly,
+ * but this is difficult in the current design. */
+ if (adt && adt->drivers.first) {
+ BLI_assert(!adt->driver_array);
+
+ int num_drivers = BLI_listbase_count(&adt->drivers);
+ adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array");
+
+ int driver_index = 0;
+ for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ adt->driver_array[driver_index++] = fcu;
+ }
+ }
}
-void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
+void BKE_animsys_eval_driver(Depsgraph *depsgraph,
ID *id,
- FCurve *fcu)
+ int driver_index,
+ ChannelDriver *driver_orig)
{
/* TODO(sergey): De-duplicate with BKE animsys. */
- ChannelDriver *driver = fcu->driver;
PointerRNA id_ptr;
bool ok = false;
+ /* Lookup driver, accelerated with driver array map. */
+ const AnimData *adt = BKE_animdata_from_id(id);
+ FCurve *fcu;
+
+ if (adt->driver_array) {
+ fcu = adt->driver_array[driver_index];
+ }
+ else {
+ fcu = BLI_findlink(&adt->drivers, driver_index);
+ }
+
DEG_debug_print_eval_subdata_index(
- __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
+ depsgraph, __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
RNA_id_pointer_create(id, &id_ptr);
@@ -2951,7 +3011,7 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
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)*/) {
+ if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID) /*&& (driver_orig->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 */
@@ -2959,19 +3019,23 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
PathResolvedRNA anim_rna;
if (animsys_store_rna_setting(&id_ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) {
- const float curval = calculate_fcurve(&anim_rna, fcu, eval_ctx->ctime);
+ const float ctime = DEG_get_ctime(depsgraph);
+ const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime);
ok = animsys_write_rna_setting(&anim_rna, curval);
+ if (ok && DEG_is_active(depsgraph)) {
+ animsys_write_orig_anim_rna(&id_ptr, NULL, fcu, curval);
+ }
}
//printf("\tnew val = %f\n", fcu->curval);
/* clear recalc flag */
- driver->flag &= ~DRIVER_FLAG_RECALC;
+ driver_orig->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;
+ driver_orig->flag |= DRIVER_FLAG_INVALID;
}
}
}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 317994d4ed9..ccff6216cb3 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -790,7 +790,9 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
BLI_dir_create_recursive(tmp_name);
}
#else
- mkdtemp(tmp_name);
+ if (mkdtemp(tmp_name) == NULL) {
+ BLI_dir_create_recursive(tmp_name);
+ }
#endif
}
if (BLI_is_dir(tmp_name)) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index b7a811b7574..bd9ee7c9e5f 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -60,8 +60,6 @@
#include "BKE_anim.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_idprop.h"
@@ -74,7 +72,6 @@
#include "BKE_scene.h"
#include "BIK_api.h"
-#include "BKE_sketch.h"
/* **************** Generic Functions, data level *************** */
@@ -136,12 +133,6 @@ void BKE_armature_free(bArmature *arm)
MEM_freeN(arm->edbo);
arm->edbo = NULL;
}
-
- /* free sketch */
- if (arm->sketch) {
- freeSketch(arm->sketch);
- arm->sketch = NULL;
- }
}
void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local)
@@ -205,7 +196,6 @@ void BKE_armature_copy_data(Main *UNUSED(bmain), bArmature *arm_dst, const bArma
arm_dst->edbo = NULL;
arm_dst->act_edbone = NULL;
- arm_dst->sketch = NULL;
}
bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm)
@@ -972,7 +962,7 @@ static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index)
}
}
-void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
+void armature_deform_verts(Object *armOb, Object *target, const Mesh * mesh, float (*vertexCos)[3],
float (*defMats)[3][3], int numVerts, int deformflag,
float (*prevCos)[3], const char *defgrp_name)
{
@@ -1048,9 +1038,9 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
/* get a vertex-deform-index to posechannel array */
if (deformflag & ARM_DEF_VGROUP) {
if (ELEM(target->type, OB_MESH, OB_LATTICE)) {
- /* if we have a DerivedMesh, only use dverts if it has them */
- if (dm) {
- use_dverts = (dm->getVertDataArray(dm, CD_MDEFORMVERT) != NULL);
+ /* if we have a Mesh, only use dverts if it has them */
+ if (mesh) {
+ use_dverts = (mesh->dvert != NULL);
}
else if (dverts) {
use_dverts = true;
@@ -1112,8 +1102,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
}
if (use_dverts || armature_def_nr != -1) {
- if (dm)
- dvert = dm->getVertData(dm, i, CD_MDEFORMVERT);
+ if (mesh) {
+ BLI_assert(i < mesh->totvert);
+ dvert = mesh->dvert + i;
+ }
else if (dverts && i < target_totvert)
dvert = dverts + i;
else
@@ -1463,13 +1455,13 @@ void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], fl
copy_v3_v3(outloc, nLocMat[3]);
}
-void BKE_armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
+void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
{
bPoseChannel work_pchan = *pchan;
/* recalculate pose matrix with only parent transformations,
* bone loc/sca/rot is ignored, scene and frame are not used. */
- BKE_pose_where_is_bone(NULL, ob, &work_pchan, 0.0f, false);
+ BKE_pose_where_is_bone(depsgraph, NULL, ob, &work_pchan, 0.0f, false);
/* find the matrix, need to remove the bone transforms first so this is
* calculated as a matrix to set rather then a difference ontop of whats
@@ -1950,9 +1942,18 @@ void BKE_pose_clear_pointers(bPose *pose)
}
}
+void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose)
+{
+ GHash *bone_hash = BKE_armature_bone_from_name_map(armature);
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name);
+ }
+ BLI_ghash_free(bone_hash, NULL, NULL);
+}
+
/* only after leave editmode, duplicating, validating older files, library syncing */
/* NOTE: pose->flag is set for it */
-void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones)
+void BKE_pose_rebuild(Object *ob, bArmature *arm)
{
Bone *bone;
bPose *pose;
@@ -1989,34 +1990,22 @@ void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones)
/* printf("rebuild pose %s, %d bones\n", ob->id.name, counter); */
/* synchronize protected layers with proxy */
- if (ob->proxy) {
+ /* HACK! To preserve 2.7x behavior that you always can pose even locked bones,
+ * do not do any restauration if this is a COW temp copy! */
+ /* Switched back to just NO_MAIN tag, for some reasons (c) using COW tag was working this morning, but not anymore... */
+ if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
BKE_object_copy_proxy_drivers(ob, ob->proxy);
pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected);
}
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 && sort_bones) {
- DAG_pose_sort(ob);
- }
-#else
- UNUSED_VARS(sort_bones);
-#endif
-
ob->pose->flag &= ~POSE_RECALC;
ob->pose->flag |= POSE_WAS_REBUILT;
BKE_pose_channels_hash_make(ob->pose);
}
-void BKE_pose_rebuild(Object *ob, bArmature *arm)
-{
- BKE_pose_rebuild_ex(ob, arm, true);
-}
-
/* ********************** THE POSE SOLVER ******************* */
/* loc/rot/size to given mat4 */
@@ -2127,7 +2116,7 @@ static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseCha
if (STREQ(pchan->name, amod->channel)) {
float mat4[4][4], mat3[3][3];
- curve_deform_vector(scene, amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
+ curve_deform_vector(amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
copy_m4_m4(mat4, pchan->pose_mat);
mul_m4_m3m4(pchan->pose_mat, mat3, mat4);
@@ -2211,7 +2200,9 @@ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
/* pchan is validated, as having bone and parent pointer
* 'do_extra': when zero skips loc/size/rot, constraints and strip modifiers.
*/
-void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime, bool do_extra)
+void BKE_pose_where_is_bone(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, bPoseChannel *pchan, float ctime, bool do_extra)
{
/* This gives a chan_mat with actions (ipos) results. */
if (do_extra)
@@ -2247,10 +2238,10 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float
/* prepare PoseChannel for Constraint solving
* - makes a copy of matrix, and creates temporary struct to use
*/
- cob = BKE_constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
/* Solve PoseChannel's Constraints */
- BKE_constraints_solve(&pchan->constraints, cob, ctime); /* ctime doesnt alter objects */
+ BKE_constraints_solve(depsgraph, &pchan->constraints, cob, ctime); /* ctime doesnt alter objects */
/* cleanup after Constraint Solving
* - applies matrix back to pchan, and frees temporary struct used
@@ -2272,7 +2263,7 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float
/* This only reads anim data from channels, and writes to channels */
/* This is the only function adding poses */
-void BKE_pose_where_is(Scene *scene, Object *ob)
+void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bArmature *arm;
Bone *bone;
@@ -2311,7 +2302,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
}
/* 2a. construct the IK tree (standard IK) */
- BIK_initialize_tree(scene, ob, ctime);
+ BIK_initialize_tree(depsgraph, scene, ob, ctime);
/* 2b. construct the Spline IK trees
* - this is not integrated as an IK plugin, since it should be able
@@ -2323,15 +2314,15 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* 4a. if we find an IK root, we handle it separated */
if (pchan->flag & POSE_IKTREE) {
- BIK_execute_tree(scene, ob, pchan, ctime);
+ BIK_execute_tree(depsgraph, scene, ob, pchan, ctime);
}
/* 4b. if we find a Spline IK root, we handle it separated too */
else if (pchan->flag & POSE_IKSPLINE) {
- BKE_splineik_execute_tree(scene, ob, pchan, ctime);
+ BKE_splineik_execute_tree(depsgraph, scene, ob, pchan, ctime);
}
/* 5. otherwise just call the normal solver */
else if (!(pchan->flag & POSE_DONE)) {
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
}
/* 6. release the IK tree */
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index cb4237f51b4..628f92c7803 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -41,7 +41,6 @@
#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"
@@ -113,9 +112,11 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
* currently for paths to work it needs to go through the bevlist/displist system (ton)
*/
+ /* TODO: Make sure this doesn't crash. */
+#if 0
/* 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);
+ BKE_displist_make_curveTypes(depsgraph, 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)) {
@@ -123,6 +124,9 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
return;
}
}
+#else
+ (void) scene;
+#endif
}
/* find the root bone and the chain of bones from the root to the tip
@@ -261,15 +265,16 @@ static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
/* ----------- */
/* 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)
+static void splineik_evaluate_bone(
+ struct Depsgraph *depsgraph, 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);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
copy_v3_v3(poseHead, pchan->pose_head);
copy_v3_v3(poseTail, pchan->pose_tail);
@@ -511,7 +516,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
}
/* Evaluate the chain starting from the nominated bone */
-static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+static void splineik_execute_tree(struct Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
tSplineIK_Tree *tree;
@@ -525,7 +530,7 @@ static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_
*/
for (i = tree->chainlen - 1; i >= 0; i--) {
bPoseChannel *pchan = tree->chain[i];
- splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime);
+ splineik_evaluate_bone(depsgraph, tree, scene, ob, pchan, i, ctime);
}
/* free the tree info specific to SplineIK trees now */
@@ -544,9 +549,11 @@ 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)
+void BKE_splineik_execute_tree(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, bPoseChannel *pchan_root, float ctime)
{
- splineik_execute_tree(scene, ob, pchan_root, ctime);
+ splineik_execute_tree(depsgraph, scene, ob, pchan_root, ctime);
}
/* *************** Depsgraph evaluation callbacks ************ */
@@ -560,14 +567,14 @@ BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index)
return pose->chan_array[pchan_index];
}
-void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_init(struct Depsgraph *depsgraph,
Scene *UNUSED(scene),
Object *ob)
{
bPose *pose = ob->pose;
BLI_assert(pose != NULL);
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
@@ -590,11 +597,11 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
}
}
-void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
@@ -602,7 +609,7 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
return;
}
/* construct the IK tree (standard IK) */
- BIK_initialize_tree(scene, ob, ctime);
+ BIK_initialize_tree(depsgraph, scene, ob, ctime);
/* 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
@@ -610,14 +617,14 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
BKE_pose_splineik_init_tree(scene, ob, ctime);
}
-void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_bone(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int pchan_index)
{
bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
+ depsgraph, __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
BLI_assert(ob->type == OB_ARMATURE);
bArmature *arm = (bArmature *)ob->data;
if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
@@ -640,21 +647,21 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
if ((pchan->flag & POSE_DONE) == 0) {
/* 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);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
}
}
}
}
-void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int pchan_index)
{
bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
+ depsgraph, __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
@@ -665,42 +672,49 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
else {
if ((pchan->flag & POSE_DONE) == 0) {
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
}
}
-void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_bone_done(struct Depsgraph *depsgraph,
struct Object *ob,
int pchan_index)
{
bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
float imat[4][4];
- DEG_debug_print_eval(__func__, pchan->name, pchan);
+ DEG_debug_print_eval(depsgraph, __func__, pchan->name, pchan);
if (pchan->bone) {
invert_m4_m4(imat, pchan->bone->arm_mat);
mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
}
+ if (DEG_is_active(depsgraph)) {
+ bPoseChannel *pchan_orig = pchan->orig_pchan;
+ copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat);
+ copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat);
+ copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]);
+ BKE_pose_where_is_bone_tail(pchan_orig);
+ }
}
-void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_iktree_evaluate(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int rootchan_index)
{
bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
+ depsgraph, __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
}
- BIK_execute_tree(scene, ob, rootchan, ctime);
+ BIK_execute_tree(depsgraph, scene, ob, rootchan, ctime);
}
-void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_splineik_evaluate(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int rootchan_index)
@@ -708,17 +722,17 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
{
bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
+ depsgraph, __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
}
- BKE_splineik_execute_tree(scene, ob, rootchan, ctime);
+ BKE_splineik_execute_tree(depsgraph, scene, ob, rootchan, ctime);
}
-void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_flush(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
@@ -726,29 +740,23 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
BLI_assert(pose != NULL);
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
/* release the IK tree */
BIK_release_tree(scene, ob, ctime);
- ob->recalc &= ~OB_RECALC_ALL;
-
BLI_assert(pose->chan_array != NULL);
MEM_freeN(pose->chan_array);
pose->chan_array = NULL;
}
-void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+void BKE_pose_eval_proxy_copy(struct Depsgraph *depsgraph, Object *ob)
{
BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL);
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
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);
}
- /* Rest of operations are NO-OP in depsgraph, so can clear
- * flag now.
- */
- ob->recalc &= ~OB_RECALC_ALL;
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index ba20dbaddb0..23c2147ff7e 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -48,20 +48,24 @@
#include "BKE_addon.h"
#include "BKE_blender.h" /* own include */
#include "BKE_blender_version.h" /* own include */
+#include "BKE_blender_user_menu.h"
#include "BKE_blendfile.h"
#include "BKE_brush.h"
#include "BKE_cachefile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
+#include "BKE_studiolight.h"
+
+#include "DEG_depsgraph.h"
#include "RE_pipeline.h"
#include "RE_render_ext.h"
@@ -80,6 +84,8 @@ char versionstr[48] = "";
void BKE_blender_free(void)
{
/* samples are in a global list..., also sets G_MAIN->sound->sample NULL */
+
+ BKE_studiolight_free(); /* needs to run before main free as wm is still referenced for icons preview jobs */
BKE_main_free(G_MAIN);
G_MAIN = NULL;
@@ -92,7 +98,7 @@ void BKE_blender_free(void)
IMB_exit();
BKE_cachefiles_exit();
BKE_images_exit();
- DAG_exit();
+ DEG_free_node_types();
BKE_brush_system_exit();
RE_texture_rng_exit();
@@ -201,6 +207,15 @@ static void userdef_free_keymaps(UserDef *userdef)
BLI_listbase_clear(&userdef->user_keymaps);
}
+static void userdef_free_user_menus(UserDef *userdef)
+{
+ for (bUserMenu *um = userdef->user_menus.first, *um_next; um; um = um_next) {
+ um_next = um->next;
+ BKE_blender_user_menu_item_free_list(&um->items);
+ MEM_freeN(um);
+ }
+}
+
static void userdef_free_addons(UserDef *userdef)
{
for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) {
@@ -221,6 +236,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
#endif
userdef_free_keymaps(userdef);
+ userdef_free_user_menus(userdef);
userdef_free_addons(userdef);
if (clear_fonts) {
@@ -236,6 +252,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
BLI_freelistN(&userdef->uifonts);
BLI_freelistN(&userdef->themes);
+
#undef U
}
@@ -283,11 +300,13 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use
DATA_SWAP(font_path_ui_mono);
DATA_SWAP(keyconfigstr);
+ DATA_SWAP(manipulator_flag);
DATA_SWAP(app_flag);
/* We could add others. */
FLAG_SWAP(uiflag, int, USER_QUIT_PROMPT);
+#undef SWAP_TYPELESS
#undef DATA_SWAP
#undef LIST_SWAP
#undef FLAG_SWAP
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index e57524af546..7b149761952 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -44,12 +44,15 @@
#include "BKE_blender_copybuffer.h" /* own include */
#include "BKE_blendfile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -95,7 +98,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor
/* Here appending/linking starts. */
Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname);
BLO_library_link_copypaste(mainl, bh);
- BLO_library_link_end(mainl, &bh, 0, NULL, NULL);
+ BLO_library_link_end(mainl, &bh, 0, NULL, NULL, NULL);
/* Mark all library linked objects to be updated. */
BKE_main_lib_objects_recalc_all(bmain_dst);
IMB_colormanagement_check_file_config(bmain_dst);
@@ -117,7 +120,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Main *mainl = NULL;
Library *lib;
BlendHandle *bh;
@@ -129,7 +132,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
return false;
}
- BKE_scene_base_deselect_all(scene);
+ BKE_view_layer_base_deselect_all(view_layer);
/* tag everything, all untagged data can be made local
* its also generally useful to know what is new
@@ -142,7 +145,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
BLO_library_link_copypaste(mainl, bh);
- BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+ BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer);
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
@@ -157,7 +160,11 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
/* recreate dependency graph to include new objects */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
+
+ /* Tag update the scene to flush base collection settings, since the new object is added to a
+ * new (active) collection, not its original collection, thus need recalculation. */
+ DEG_id_tag_update(&scene->id, 0);
BLO_blendhandle_close(bh);
/* remove library... */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index df2caba0208..857fc72672c 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -50,13 +50,14 @@
#include "BKE_blendfile.h"
#include "BKE_appdir.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BLO_undofile.h"
#include "BLO_writefile.h"
+#include "DEG_depsgraph.h"
+
/* -------------------------------------------------------------------- */
/** \name Global Undo
@@ -89,7 +90,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C)
if (success) {
/* important not to update time here, else non keyed tranforms are lost */
- DAG_on_visible_update(bmain, false);
+ DEG_on_visible_update(bmain, false);
}
return success;
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
new file mode 100644
index 00000000000..3bb150b8fac
--- /dev/null
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -0,0 +1,114 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/blender_user_menu.c
+ * \ingroup bke
+ *
+ * User defined menu API.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "DNA_userdef_types.h"
+
+#include "BKE_blender_user_menu.h"
+#include "BKE_idprop.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Type
+ * \{ */
+
+bUserMenu *BKE_blender_user_menu_find(
+ ListBase *lb, char space_type, const char *context)
+{
+ for (bUserMenu *um = lb->first; um; um = um->next) {
+ if ((space_type == um->space_type) &&
+ (STREQ(context, um->context)))
+ {
+ return um;
+ }
+ }
+ return NULL;
+}
+
+bUserMenu *BKE_blender_user_menu_ensure(
+ ListBase *lb, char space_type, const char *context)
+{
+ bUserMenu *um = BKE_blender_user_menu_find(lb, space_type, context);
+ if (um == NULL) {
+ um = MEM_callocN(sizeof(bUserMenu), __func__);
+ um->space_type = space_type;
+ STRNCPY(um->context, context);
+ BLI_addhead(lb, um);
+ }
+ return um;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Item
+ * \{ */
+
+bUserMenuItem *BKE_blender_user_menu_item_add(ListBase *lb, int type)
+{
+ uint size;
+
+ if (type == USER_MENU_TYPE_OPERATOR) {
+ size = sizeof(bUserMenuItem_Op);
+ }
+ else if (type == USER_MENU_TYPE_SEP) {
+ size = sizeof(bUserMenuItem);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ bUserMenuItem *umi = MEM_callocN(size, __func__);
+ umi->type = type;
+ BLI_addtail(lb, umi);
+ return umi;
+}
+
+void BKE_blender_user_menu_item_free(bUserMenuItem *umi)
+{
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
+ if (umi_op->prop) {
+ IDP_FreeProperty(umi_op->prop);
+ MEM_freeN(umi_op->prop);
+ }
+ }
+ MEM_freeN(umi);
+}
+
+void BKE_blender_user_menu_item_free_list(ListBase *lb)
+{
+ for (bUserMenuItem *umi = lb->first, *umi_next; umi; umi = umi_next) {
+ umi_next = umi->next;
+ BKE_blender_user_menu_item_free(umi);
+ }
+ BLI_listbase_clear(lb);
+}
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index aa5530704c6..27b5089b092 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -32,6 +32,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -48,11 +49,13 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_ipo.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -93,7 +96,7 @@ static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
{
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
- if (win->screen->scene == scene) {
+ if (win->scene == scene) {
return true;
}
}
@@ -164,17 +167,22 @@ static void setup_app_data(
* (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
* see: T43424
*/
+ wmWindow *win;
bScreen *curscreen = NULL;
+ ViewLayer *cur_view_layer;
bool track_undo_scene;
/* comes from readfile.c */
SWAP(ListBase, bmain->wm, bfd->main->wm);
+ SWAP(ListBase, bmain->workspaces, bfd->main->workspaces);
SWAP(ListBase, bmain->screen, bfd->main->screen);
- /* we re-use current screen */
+ /* we re-use current window and screen */
+ win = CTX_wm_window(C);
curscreen = CTX_wm_screen(C);
- /* but use new Scene pointer */
+ /* but use Scene pointer from new file */
curscene = bfd->curscene;
+ cur_view_layer = bfd->cur_view_layer;
track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
@@ -185,34 +193,41 @@ static void setup_app_data(
if (curscene == NULL) {
curscene = BKE_scene_add(bfd->main, "Empty");
}
+ if (cur_view_layer == NULL) {
+ /* fallback to scene layer */
+ cur_view_layer = BKE_view_layer_default_view(curscene);
+ }
if (track_undo_scene) {
/* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
* replace it with 'curscene' if its needed */
}
- else {
- /* and we enforce curscene to be in current screen */
- if (curscreen) {
- /* can run in bgmode */
- curscreen->scene = curscene;
- }
+ /* and we enforce curscene to be in current screen */
+ else if (win) { /* can run in bgmode */
+ win->scene = curscene;
}
/* BKE_blender_globals_clear will free G_MAIN, here we can still restore pointers */
- blo_lib_link_screen_restore(bfd->main, curscreen, curscene);
- /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */
- if (curscreen) {
- curscene = curscreen->scene;
+ blo_lib_link_restore(bfd->main, CTX_wm_manager(C), curscene, cur_view_layer);
+ if (win) {
+ curscene = win->scene;
}
if (track_undo_scene) {
wmWindowManager *wm = bfd->main->wm.first;
if (wm_scene_is_visible(wm, bfd->curscene) == false) {
curscene = bfd->curscene;
- curscreen->scene = curscene;
- BKE_screen_view3d_scene_sync(curscreen);
+ win->scene = curscene;
+ BKE_screen_view3d_scene_sync(curscreen, curscene);
}
}
+
+ /* We need to tag this here because events may be handled immediately after.
+ * only the current screen is important because we wont have to handle
+ * events from multiple screens at once.*/
+ {
+ BKE_screen_manipulator_tag_refresh(curscreen);
+ }
}
/* free G_MAIN Main database */
@@ -227,6 +242,7 @@ static void setup_app_data(
CTX_data_main_set(C, bmain);
if (bfd->user) {
+
/* only here free userdef themes... */
BKE_blender_userdef_data_set_and_free(bfd->user);
bfd->user = NULL;
@@ -262,12 +278,14 @@ static void setup_app_data(
/* this can happen when active scene was lib-linked, and doesn't exist anymore */
if (CTX_data_scene(C) == NULL) {
+ wmWindow *win = CTX_wm_window(C);
+
/* in case we don't even have a local scene, add one */
if (!bmain->scene.first)
BKE_scene_add(bmain, "Empty");
CTX_data_scene_set(C, bmain->scene.first);
- CTX_wm_screen(C)->scene = CTX_data_scene(C);
+ win->scene = CTX_data_scene(C);
curscene = CTX_data_scene(C);
}
@@ -316,20 +334,27 @@ static void setup_app_data(
wmWindowManager *wm = bmain->wm.first;
if (wm) {
- wmWindow *win;
-
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen && win->screen->scene) /* zealous check... */
- if (win->screen->scene != curscene)
- BKE_scene_set_background(bmain, win->screen->scene);
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene && win->scene != curscene) {
+ BKE_scene_set_background(bmain, win->scene);
+ }
}
}
}
+
+ /* Setting scene might require having a dependency graph, with copy on write
+ * we need to make sure we ensure scene has correct color management before
+ * constructing dependency graph.
+ */
+ if (mode != LOAD_UNDO) {
+ IMB_colormanagement_check_file_config(bmain);
+ }
+
BKE_scene_set_background(bmain, curscene);
if (mode != LOAD_UNDO) {
+ /* TODO(sergey): Can this be also move above? */
RE_FreeAllPersistentData();
- IMB_colormanagement_check_file_config(bmain);
}
MEM_freeN(bfd);
@@ -536,6 +561,48 @@ bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *
return ok;
}
+WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, ReportList *reports)
+{
+ BlendFileData *bfd;
+ WorkspaceConfigFileData *workspace_config = NULL;
+
+ bfd = BLO_read_from_file(filepath, reports, BLO_READ_SKIP_USERDEF);
+ if (bfd) {
+ workspace_config = MEM_mallocN(sizeof(*workspace_config), __func__);
+ workspace_config->main = bfd->main;
+ workspace_config->workspaces = bfd->main->workspaces;
+
+ MEM_freeN(bfd);
+ }
+
+ return workspace_config;
+}
+
+bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports)
+{
+ int fileflags = G.fileflags & ~(G_FILE_NO_UI | G_FILE_HISTORY);
+ bool retval = false;
+
+ BKE_blendfile_write_partial_begin(bmain);
+
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_blendfile_write_partial_tag_ID(&workspace->id, true);
+ }
+
+ if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) {
+ retval = true;
+ }
+
+ BKE_blendfile_write_partial_end(bmain);
+
+ return retval;
+}
+
+void BKE_blendfile_workspace_config_data_free(WorkspaceConfigFileData *workspace_config)
+{
+ BKE_main_free(workspace_config->main);
+ MEM_freeN(workspace_config);
+}
/** \} */
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index 39f8d7703ab..f47d09d7dc2 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -132,6 +132,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val,
if (eff == NULL && gabr->ob) {
memset(&temp_eff, 0, sizeof(EffectorCache));
temp_eff.ob = gabr->ob;
+ temp_eff.depsgraph = bbd->sim->depsgraph;
temp_eff.scene = bbd->sim->scene;
eff = &temp_eff;
get_effector_data(eff, &efd, &epoint, 0);
@@ -1264,7 +1265,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa)
/* account for effectors */
pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
- pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
+ BKE_effectors_apply(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
float length = normalize_v3(force);
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 0b191e1f69b..7c9e57b039e 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -588,14 +588,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
}
break;
}
- case ID_TE:
- {
- Tex *tex = (Tex *)id;
- if (tex->type == TEX_VOXELDATA && TEX_VD_IS_SOURCE_PATH(tex->vd->file_format)) {
- rewrite_path_fixed(tex->vd->source_path, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
case ID_SCE:
{
Scene *scene = (Scene *)id;
diff --git a/source/blender/blenkernel/intern/bullet.c b/source/blender/blenkernel/intern/bullet.c
deleted file mode 100644
index 827577d873b..00000000000
--- a/source/blender/blenkernel/intern/bullet.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * ***** 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) Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/bullet.c
- * \ingroup bke
- */
-
-
-#include "MEM_guardedalloc.h"
-
-/* types */
-#include "DNA_object_force_types.h" /* here is the softbody struct */
-
-#include "BKE_bullet.h"
-
-
-/* ************ Object level, exported functions *************** */
-
-/* allocates and initializes general main data */
-BulletSoftBody *bsbNew(void)
-{
- BulletSoftBody *bsb;
-
- bsb = MEM_callocN(sizeof(BulletSoftBody), "bulletsoftbody");
-
- bsb->flag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT;
- bsb->linStiff = 0.5f;
- bsb->angStiff = 1.0f;
- bsb->volume = 1.0f;
-
-
- bsb->viterations = 0;
- bsb->piterations = 2;
- bsb->diterations = 0;
- bsb->citerations = 4;
-
- bsb->kSRHR_CL = 0.1f;
- bsb->kSKHR_CL = 1.f;
- bsb->kSSHR_CL = 0.5f;
- bsb->kSR_SPLT_CL = 0.5f;
-
- bsb->kSK_SPLT_CL = 0.5f;
- bsb->kSS_SPLT_CL = 0.5f;
- bsb->kVCF = 1;
- bsb->kDP = 0;
-
- bsb->kDG = 0;
- bsb->kLF = 0;
- bsb->kPR = 0;
- bsb->kVC = 0;
-
- bsb->kDF = 0.2f;
- bsb->kMT = 0.05;
- bsb->kCHR = 1.0f;
- bsb->kKHR = 0.1f;
-
- bsb->kSHR = 1.0f;
- bsb->kAHR = 0.7f;
-
- bsb->collisionflags = 0;
- //bsb->collisionflags = OB_BSB_COL_CL_RS + OB_BSB_COL_CL_SS;
- bsb->numclusteriterations = 64;
- bsb->welding = 0.f;
-
- return bsb;
-}
-
-/* frees all */
-void bsbFree(BulletSoftBody *bsb)
-{
- /* no internal data yet */
- MEM_freeN(bsb);
-}
-
-
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index c678f71dff9..1a7c4e2a4a0 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -34,6 +34,7 @@
#include <math.h>
#include <assert.h>
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
@@ -43,6 +44,8 @@
#include "BKE_DerivedMesh.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "MEM_guardedalloc.h"
@@ -423,7 +426,8 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
const MVert *vert, const int verts_num,
const BLI_bitmap *verts_mask, int verts_num_active)
{
- BLI_assert(vert != NULL);
+ BVHTree *tree = NULL;
+
if (verts_mask) {
BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
}
@@ -431,17 +435,19 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
verts_num_active = verts_num;
}
- BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+ if (verts_num_active) {
+ tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (int i = 0; i < verts_num; i++) {
- if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
- continue;
+ if (tree) {
+ for (int i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
+ }
+ BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
- BLI_bvhtree_insert(tree, i, vert[i].co, 1);
+ BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
}
- BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
}
return tree;
@@ -567,29 +573,31 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(
const BLI_bitmap *edges_mask, int edges_num_active,
float epsilon, int tree_type, int axis)
{
+ BVHTree *tree = NULL;
+
if (edges_mask) {
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
}
else {
edges_num_active = edge_num;
}
- BLI_assert(vert != NULL);
- BLI_assert(edge != NULL);
- /* Create a bvh-tree of the given target */
- BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (int i = 0; i < edge_num; i++) {
- if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
- continue;
- }
- float co[2][3];
- copy_v3_v3(co[0], vert[edge[i].v1].co);
- copy_v3_v3(co[1], vert[edge[i].v2].co);
+ if (edges_num_active) {
+ /* Create a bvh-tree of the given target */
+ tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ for (int i = 0; i < edge_num; i++) {
+ if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
+ continue;
+ }
+ float co[2][3];
+ copy_v3_v3(co[0], vert[edge[i].v1].co);
+ copy_v3_v3(co[1], vert[edge[i].v2].co);
- BLI_bvhtree_insert(tree, i, co[0], 2);
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_bvhtree_balance(tree);
}
- BLI_bvhtree_balance(tree);
}
return tree;
@@ -833,22 +841,21 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
const BLI_bitmap *looptri_mask, int looptri_num_active)
{
BVHTree *tree = NULL;
- int i;
- if (looptri_num) {
- if (looptri_mask) {
- BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
- }
- else {
- looptri_num_active = looptri_num;
- }
+ if (looptri_mask) {
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
+ }
+ else {
+ looptri_num_active = looptri_num;
+ }
+ if (looptri_num_active) {
/* Create a bvh-tree of the given target */
/* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
if (tree) {
if (vert && looptri) {
- for (i = 0; i < looptri_num; i++) {
+ for (int i = 0; i < looptri_num; i++) {
float co[3][3];
if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) {
continue;
@@ -902,23 +909,23 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(
/* BMESH specific check that we have tessfaces,
* we _could_ tessellate here but rather not - campbell */
- BVHTree *tree;
+ BVHTree *tree = NULL;
if (bvhCache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
+ bool in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
- if (tree == NULL) {
+ if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
- if (tree == NULL) {
+ in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
+ if (in_cache == false) {
tree = bvhtree_from_editmesh_looptri_create_tree(
epsilon, tree_type, axis,
em, em->tottri, looptri_mask, looptri_num_active);
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
- }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
+
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
@@ -976,6 +983,55 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
return tree;
}
+static BLI_bitmap *loose_verts_map_get(
+ const MEdge *medge, int edges_num,
+ const MVert *UNUSED(mvert), int verts_num,
+ int *r_loose_vert_num)
+{
+ BLI_bitmap *loose_verts_mask = BLI_BITMAP_NEW(verts_num, __func__);
+ BLI_BITMAP_SET_ALL(loose_verts_mask, true, verts_num);
+
+ const MEdge *e = medge;
+ int num_linked_verts = 0;
+ for (;edges_num--; e++) {
+ if (BLI_BITMAP_TEST(loose_verts_mask, e->v1)) {
+ BLI_BITMAP_DISABLE(loose_verts_mask, e->v1);
+ num_linked_verts++;
+ }
+ if (BLI_BITMAP_TEST(loose_verts_mask, e->v2)) {
+ BLI_BITMAP_DISABLE(loose_verts_mask, e->v2);
+ num_linked_verts++;
+ }
+ }
+
+ *r_loose_vert_num = verts_num - num_linked_verts;
+
+ return loose_verts_mask;
+}
+
+static BLI_bitmap *loose_edges_map_get(
+ const MEdge *medge, const int edges_len,
+ int *r_loose_edge_len)
+{
+ BLI_bitmap *loose_edges_mask = BLI_BITMAP_NEW(edges_len, __func__);
+
+ int loose_edges_len = 0;
+ const MEdge *e = medge;
+ for (int i = 0; i < edges_len; i++, e++) {
+ if (e->flag & ME_LOOSEEDGE) {
+ BLI_BITMAP_ENABLE(loose_edges_mask, i);
+ loose_edges_len++;
+ }
+ else {
+ BLI_BITMAP_DISABLE(loose_edges_mask, i);
+ }
+ }
+
+ *r_loose_edge_len = loose_edges_len;
+
+ return loose_edges_mask;
+}
+
/**
* Builds or queries a bvhcache for the cache bvhtree of the request type.
*/
@@ -1000,54 +1056,94 @@ BVHTree *bvhtree_from_mesh_get(
bool looptri_allocated = false;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(dm->bvhCache, type);
+ bool in_cache = bvhcache_find(dm->bvhCache, type, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
+ if (in_cache && tree == NULL) {
+ memset(data, 0, sizeof(*data));
+ return tree;
+ }
+
switch (type) {
case BVHTREE_FROM_VERTS:
+ case BVHTREE_FROM_LOOSEVERTS:
raycast_callback = mesh_verts_spherecast;
mvert = DM_get_vert_array(dm, &vert_allocated);
- if (tree == NULL) {
- /* Not in cache */
+ if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS);
- if (tree == NULL) {
+ in_cache = bvhcache_find(dm->bvhCache, type, &tree);
+ if (in_cache == false) {
+ BLI_bitmap *loose_verts_mask = NULL;
+ int loose_vert_num = -1;
+ int verts_num = dm->getNumVerts(dm);
+
+ if (type == BVHTREE_FROM_LOOSEVERTS) {
+ medge = DM_get_edge_array(dm, &edge_allocated);
+
+ loose_verts_mask = loose_verts_map_get(
+ medge, dm->getNumEdges(dm), mvert,
+ verts_num, &loose_vert_num);
+
+ if (edge_allocated) {
+ MEM_freeN(medge);
+ edge_allocated = false;
+ }
+ medge = NULL;
+ }
+
tree = bvhtree_from_mesh_verts_create_tree(
- 0.0, tree_type, 6, mvert, dm->getNumVerts(dm), NULL, -1);
+ 0.0, tree_type, 6, mvert, verts_num,
+ loose_verts_mask, loose_vert_num);
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS);
+ if (loose_verts_mask != NULL) {
+ MEM_freeN(loose_verts_mask);
}
+
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&dm->bvhCache, tree, type);
+
}
+
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
case BVHTREE_FROM_EDGES:
+ case BVHTREE_FROM_LOOSEEDGES:
nearest_callback = mesh_edges_nearest_point;
raycast_callback = mesh_edges_spherecast;
mvert = DM_get_vert_array(dm, &vert_allocated);
medge = DM_get_edge_array(dm, &edge_allocated);
- if (tree == NULL) {
- /* Not in cache */
+ if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
- if (tree == NULL) {
+ in_cache = bvhcache_find(dm->bvhCache, type, &tree);
+ if (in_cache == false) {
+ BLI_bitmap *loose_edges_mask = NULL;
+ int loose_edges_num = -1;
+ int edges_num = dm->getNumEdges(dm);
+
+ if (type == BVHTREE_FROM_LOOSEEDGES) {
+ loose_edges_mask = loose_edges_map_get(
+ medge, edges_num, &loose_edges_num);
+ }
+
tree = bvhtree_from_mesh_edges_create_tree(
- mvert, medge, dm->getNumEdges(dm),
- NULL, -1, 0.0, tree_type, 6);
+ mvert, medge, edges_num,
+ loose_edges_mask, loose_edges_num, 0.0, tree_type, 6);
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES);
+ if (loose_edges_mask != NULL) {
+ MEM_freeN(loose_edges_mask);
}
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&dm->bvhCache, tree, type);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
@@ -1060,22 +1156,19 @@ BVHTree *bvhtree_from_mesh_get(
mvert = DM_get_vert_array(dm, &vert_allocated);
mface = DM_get_tessface_array(dm, &face_allocated);
- if (tree == NULL) {
- /* Not in cache */
+ if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES);
- if (tree == NULL) {
+ in_cache = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES, &tree);
+ if (in_cache == false) {
int numFaces = dm->getNumTessFaces(dm);
BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0));
tree = bvhtree_from_mesh_faces_create_tree(
0.0, tree_type, 6, mvert, mface, numFaces, NULL, -1);
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_FACES);
- }
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_FACES);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
@@ -1089,11 +1182,10 @@ BVHTree *bvhtree_from_mesh_get(
mloop = DM_get_loop_array(dm, &loop_allocated);
looptri = dm->getLoopTriArray(dm);
- if (tree == NULL) {
- /* Not in cache */
+ if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
- if (tree == NULL) {
+ in_cache = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI, &tree);
+ if (in_cache == false) {
int looptri_num = dm->getNumLoopTri(dm);
/* this assert checks we have looptris,
@@ -1103,11 +1195,10 @@ BVHTree *bvhtree_from_mesh_get(
tree = bvhtree_from_mesh_looptri_create_tree(
0.0, tree_type, 6,
mvert, mloop, looptri, looptri_num, NULL, -1);
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_LOOPTRI);
- }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_LOOPTRI);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
@@ -1152,7 +1243,7 @@ BVHTree *bvhtree_from_mesh_get(
MEM_freeN(mloop);
}
if (looptri_allocated) {
- MEM_freeN((void*)looptri);
+ MEM_freeN((void *)looptri);
}
memset(data, 0, sizeof(*data));
@@ -1161,6 +1252,181 @@ BVHTree *bvhtree_from_mesh_get(
return tree;
}
+/**
+ * Builds or queries a bvhcache for the cache bvhtree of the request type.
+ */
+BVHTree *BKE_bvhtree_from_mesh_get(
+ struct BVHTreeFromMesh *data, struct Mesh *mesh,
+ const int type, const int tree_type)
+{
+ struct BVHTreeFromMesh data_cp = {0};
+
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data_cp.cached && data_cp.tree == NULL) {
+ memset(data, 0, sizeof(*data));
+ return data_cp.tree;
+ }
+
+ switch (type) {
+ case BVHTREE_FROM_VERTS:
+ case BVHTREE_FROM_LOOSEVERTS:
+ data_cp.raycast_callback = mesh_verts_spherecast;
+
+ data_cp.vert = mesh->mvert;
+
+ if (data_cp.cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, type, &data_cp.tree);
+
+ if (data_cp.cached == false) {
+ BLI_bitmap *loose_verts_mask = NULL;
+ int loose_vert_len = -1;
+ int verts_len = mesh->totvert;
+
+ if (type == BVHTREE_FROM_LOOSEVERTS) {
+ loose_verts_mask = loose_verts_map_get(
+ mesh->medge, mesh->totedge, data_cp.vert,
+ verts_len, &loose_vert_len);
+ }
+
+ data_cp.tree = bvhtree_from_mesh_verts_create_tree(
+ 0.0, tree_type, 6, data_cp.vert, verts_len,
+ loose_verts_mask, loose_vert_len);
+
+ if (loose_verts_mask != NULL) {
+ MEM_freeN(loose_verts_mask);
+ }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ break;
+
+ case BVHTREE_FROM_EDGES:
+ case BVHTREE_FROM_LOOSEEDGES:
+ data_cp.nearest_callback = mesh_edges_nearest_point;
+ data_cp.raycast_callback = mesh_edges_spherecast;
+
+ data_cp.vert = mesh->mvert;
+ data_cp.edge = mesh->medge;
+
+ if (data_cp.cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
+ if (data_cp.cached == false) {
+ BLI_bitmap *loose_edges_mask = NULL;
+ int loose_edges_len = -1;
+ int edges_len = mesh->totedge;
+
+ if (type == BVHTREE_FROM_LOOSEEDGES) {
+ loose_edges_mask = loose_edges_map_get(
+ data_cp.edge, edges_len, &loose_edges_len);
+ }
+
+ data_cp.tree = bvhtree_from_mesh_edges_create_tree(
+ data_cp.vert, data_cp.edge, edges_len,
+ loose_edges_mask, loose_edges_len, 0.0, tree_type, 6);
+
+ if (loose_edges_mask != NULL) {
+ MEM_freeN(loose_edges_mask);
+ }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ break;
+
+ case BVHTREE_FROM_FACES:
+ data_cp.nearest_callback = mesh_faces_nearest_point;
+ data_cp.raycast_callback = mesh_faces_spherecast;
+
+ data_cp.vert = mesh->mvert;
+ data_cp.face = mesh->mface;
+
+ if (data_cp.cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, BVHTREE_FROM_FACES, &data_cp.tree);
+ if (data_cp.cached == false) {
+ int num_faces = mesh->totface;
+ BLI_assert(!(num_faces == 0 && mesh->totpoly != 0));
+
+ data_cp.tree = bvhtree_from_mesh_faces_create_tree(
+ 0.0, tree_type, 6, data_cp.vert,
+ data_cp.face, num_faces, NULL, -1);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_FACES);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ break;
+
+ case BVHTREE_FROM_LOOPTRI:
+ data_cp.nearest_callback = mesh_looptri_nearest_point;
+ data_cp.raycast_callback = mesh_looptri_spherecast;
+
+ data_cp.vert = mesh->mvert;
+ data_cp.loop = mesh->mloop;
+
+ /* TODO: store looptris somewhere? */
+ data_cp.looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+
+ if (data_cp.cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, BVHTREE_FROM_LOOPTRI, &data_cp.tree);
+ if (data_cp.cached == false) {
+ int looptri_num = BKE_mesh_runtime_looptri_len(mesh);
+ /* this assert checks we have looptris,
+ * if not caller should use DM_ensure_looptri() */
+ BLI_assert(!(looptri_num == 0 && mesh->totpoly != 0));
+
+ data_cp.tree = bvhtree_from_mesh_looptri_create_tree(
+ 0.0, tree_type, 6,
+ data_cp.vert, data_cp.loop,
+ data_cp.looptri, looptri_num, NULL, -1);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_LOOPTRI);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ break;
+ }
+
+ if (data_cp.tree != NULL) {
+#ifdef DEBUG
+ if (BLI_bvhtree_get_tree_type(data_cp.tree) != tree_type) {
+ printf("tree_type %d obtained instead of %d\n",
+ BLI_bvhtree_get_tree_type(data_cp.tree), tree_type);
+ }
+#endif
+ data_cp.cached = true;
+ memcpy(data, &data_cp, sizeof(*data));
+ }
+ else {
+ free_bvhtree_from_mesh(&data_cp);
+ memset(data, 0, sizeof(*data));
+ }
+
+ return data_cp.tree;
+}
+
/** \} */
@@ -1216,16 +1482,17 @@ typedef struct BVHCacheItem {
/**
* Queries a bvhcache for the cache bvhtree of the request type
*/
-BVHTree *bvhcache_find(BVHCache *cache, int type)
+bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree)
{
while (cache) {
const BVHCacheItem *item = cache->link;
if (item->type == type) {
- return item->tree;
+ *r_tree = item->tree;
+ return true;
}
cache = cache->next;
}
- return NULL;
+ return false;
}
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
@@ -1251,11 +1518,9 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
{
BVHCacheItem *item = NULL;
- assert(tree != NULL);
- assert(bvhcache_find(*cache_p, type) == NULL);
+ assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false);
item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
- assert(item != NULL);
item->type = type;
item->tree = tree;
@@ -1264,13 +1529,8 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
}
/**
- * inits and frees a bvhcache
+ * frees a bvhcache
*/
-void bvhcache_init(BVHCache **cache_p)
-{
- *cache_p = NULL;
-}
-
static void bvhcacheitem_free(void *_item)
{
BVHCacheItem *item = (BVHCacheItem *)_item;
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 5f7759c7b55..c7d7a3a98eb 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -89,13 +89,22 @@ void BKE_cachefile_free(CacheFile *cache_file)
{
BKE_animdata_free((ID *)cache_file, false);
+ if (cache_file->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
+
+ if (cache_file->handle) {
#ifdef WITH_ALEMBIC
- ABC_free_handle(cache_file->handle);
+ ABC_free_handle(cache_file->handle);
#endif
-
+ cache_file->handle = NULL;
+ }
if (cache_file->handle_mutex) {
BLI_mutex_free(cache_file->handle_mutex);
+ cache_file->handle_mutex = NULL;
}
+
BLI_freelistN(&cache_file->object_paths);
}
@@ -110,8 +119,14 @@ void BKE_cachefile_free(CacheFile *cache_file)
void BKE_cachefile_copy_data(
Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag))
{
+ if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
+
cache_file_dst->handle = NULL;
- BLI_listbase_clear(&cache_file_dst->object_paths);
+ cache_file_dst->handle_mutex = NULL;
+ BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths);
}
CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file)
@@ -153,20 +168,24 @@ void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
BLI_mutex_lock(cache_file->handle_mutex);
if (cache_file->handle == NULL) {
+ /* Assigning to a CoW copy is a bad idea; assign to the original instead. */
+ BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
BKE_cachefile_reload(bmain, cache_file);
}
BLI_mutex_unlock(cache_file->handle_mutex);
}
-void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps)
+void BKE_cachefile_update_frame(
+ Main *bmain, struct Depsgraph *depsgraph, Scene *scene,
+ const float ctime, const float fps)
{
CacheFile *cache_file;
char filename[FILE_MAX];
for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
/* Execute drivers only, as animation has already been done. */
- BKE_animsys_evaluate_animdata(scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
if (!cache_file->is_sequence) {
continue;
@@ -175,7 +194,7 @@ void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, co
const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
- BKE_cachefile_clean(scene, cache_file);
+ BKE_cachefile_clean(bmain, cache_file);
#ifdef WITH_ALEMBIC
ABC_free_handle(cache_file->handle);
cache_file->handle = ABC_create_handle(filename, NULL);
@@ -215,11 +234,9 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f
}
/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
-void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
+void BKE_cachefile_clean(struct Main *bmain, CacheFile *cache_file)
{
- for (Base *base = scene->base.first; base; base = base->next) {
- Object *ob = base->object;
-
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
if (md) {
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index bda26c95815..778eb17f822 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -40,6 +40,7 @@
#include "DNA_ID.h"
#include "BLI_math.h"
+#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -47,6 +48,7 @@
#include "BKE_animsys.h"
#include "BKE_camera.h"
#include "BKE_object.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
@@ -54,7 +56,9 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "GPU_compositing.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
/****************************** Camera Datablock *****************************/
@@ -62,7 +66,7 @@ void BKE_camera_init(Camera *cam)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cam, id));
- cam->lens = 35.0f;
+ cam->lens = 50.0f;
cam->sensor_x = DEFAULT_SENSOR_WIDTH;
cam->sensor_y = DEFAULT_SENSOR_HEIGHT;
cam->clipsta = 0.1f;
@@ -72,8 +76,6 @@ void BKE_camera_init(Camera *cam)
cam->flag |= CAM_SHOWPASSEPARTOUT;
cam->passepartalpha = 0.5f;
- GPU_fx_compositor_init_dof_settings(&cam->gpu_dof);
-
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
cam->stereo.convergence_distance = 30.f * 0.065f;
@@ -100,9 +102,19 @@ void *BKE_camera_add(Main *bmain, const char *name)
*
* \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *UNUSED(cam_dst), const Camera *UNUSED(cam_src), const int UNUSED(flag))
+void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *cam_dst, const Camera *cam_src, const int flag)
{
- /* Nothing to do! */
+ BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ for (CameraBGImage *bgpic = cam_dst->bg_images.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
+ id_us_plus((ID *)bgpic->ima);
+ }
+ else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
+ id_us_plus((ID *)bgpic->clip);
+ }
+ }
+ }
}
Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
@@ -120,6 +132,16 @@ void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local)
/** Free (or release) any data used by this camera (does not free the camera itself). */
void BKE_camera_free(Camera *ca)
{
+ for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
+ id_us_min((ID *)bgpic->ima);
+ }
+ else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
+ id_us_min((ID *)bgpic->clip);
+ }
+ }
+ BLI_freelistN(&ca->bg_images);
+
BKE_animdata_free((ID *)ca, false);
}
@@ -237,7 +259,7 @@ void BKE_camera_params_from_object(CameraParams *params, const Object *ob)
}
}
-void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, const RegionView3D *rv3d)
+void BKE_camera_params_from_view3d(CameraParams *params, Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d)
{
/* common */
params->lens = v3d->lens;
@@ -246,7 +268,8 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons
if (rv3d->persp == RV3D_CAMOB) {
/* camera view */
- BKE_camera_params_from_object(params, v3d->camera);
+ const Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ BKE_camera_params_from_object(params, ob_camera_eval);
params->zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
@@ -281,10 +304,7 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
float pixsize, viewfac, sensor_size, dx, dy;
int sensor_fit;
- /* fields rendering */
params->ycor = yasp / xasp;
- if (params->use_fields)
- params->ycor *= 2.0f;
if (params->is_ortho) {
/* orthographic camera */
@@ -326,18 +346,6 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
viewplane.xmax += dx;
viewplane.ymax += dy;
- /* fields offset */
- if (params->field_second) {
- if (params->field_odd) {
- viewplane.ymin -= 0.5f * params->ycor;
- viewplane.ymax -= 0.5f * params->ycor;
- }
- else {
- viewplane.ymin += 0.5f * params->ycor;
- viewplane.ymax += 0.5f * params->ycor;
- }
- }
-
/* the window matrix is used for clipping, and not changed during OSA steps */
/* using an offset of +0.5 here would give clip errors on edges */
viewplane.xmin *= pixsize;
@@ -641,7 +649,7 @@ static bool camera_frame_fit_calc_from_data(
/* don't move the camera, just yield the fit location */
/* r_scale only valid/useful for ortho cameras */
bool BKE_camera_view_frame_fit_to_scene(
- Main *bmain, Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3], float *r_scale)
+ Depsgraph *depsgraph, Scene *scene, Object *camera_ob, float r_co[3], float *r_scale)
{
CameraParams params;
CameraViewFrameData data_cb;
@@ -652,22 +660,24 @@ bool BKE_camera_view_frame_fit_to_scene(
camera_frame_fit_data_init(scene, camera_ob, &params, &data_cb);
/* run callback on all visible points */
- BKE_scene_foreach_display_point(bmain, scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb);
+ BKE_scene_foreach_display_point(depsgraph, camera_to_frame_view_cb, &data_cb);
return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
bool BKE_camera_view_frame_fit_to_coords(
- const Scene *scene, const float (*cos)[3], int num_cos, const Object *camera_ob,
+ const Depsgraph *depsgraph, const float (*cos)[3], int num_cos, Object *camera_ob,
float r_co[3], float *r_scale)
{
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob);
CameraParams params;
CameraViewFrameData data_cb;
/* just in case */
*r_scale = 1.0f;
- camera_frame_fit_data_init(scene, camera_ob, &params, &data_cb);
+ camera_frame_fit_data_init(scene_eval, camera_ob_eval, &params, &data_cb);
/* run callback on all given coordinates */
while (num_cos--) {
@@ -679,12 +689,12 @@ bool BKE_camera_view_frame_fit_to_coords(
/******************* multiview matrix functions ***********************/
-static void camera_model_matrix(Object *camera, float r_modelmat[4][4])
+static void camera_model_matrix(const Object *camera, float r_modelmat[4][4])
{
copy_m4_m4(r_modelmat, camera->obmat);
}
-static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4])
+static void camera_stereo3d_model_matrix(const Object *camera, const bool is_left, float r_modelmat[4][4])
{
Camera *data = (Camera *)camera->data;
float interocular_distance, convergence_distance;
@@ -782,7 +792,7 @@ static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, flo
}
/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
-void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4])
+void BKE_camera_multiview_view_matrix(RenderData *rd, const Object *camera, const bool is_left, float r_viewmat[4][4])
{
BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
invert_m4(r_viewmat);
@@ -797,7 +807,7 @@ static bool camera_is_left(const char *viewname)
return true;
}
-void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4])
+void BKE_camera_multiview_model_matrix(RenderData *rd, const Object *camera, const char *viewname, float r_modelmat[4][4])
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
@@ -814,7 +824,7 @@ void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const cha
normalize_m4(r_modelmat);
}
-bool BKE_camera_multiview_spherical_stereo(RenderData *rd, Object *camera)
+bool BKE_camera_multiview_spherical_stereo(RenderData *rd, const Object *camera)
{
Camera *cam;
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
@@ -861,9 +871,9 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha
}
if (name[0] != '\0') {
- Base *base = BKE_scene_base_find_by_name(scene, name);
- if (base) {
- return base->object;
+ Object *ob = BKE_scene_object_find_by_name(scene, name);
+ if (ob != NULL) {
+ return ob;
}
}
@@ -887,7 +897,7 @@ Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *vi
}
}
-static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
+static float camera_stereo3d_shift_x(const Object *camera, const char *viewname)
{
Camera *data = camera->data;
float shift = data->shiftx;
@@ -925,7 +935,7 @@ static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
return shift;
}
-float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *viewname)
+float BKE_camera_multiview_shift_x(RenderData *rd, const Object *camera, const char *viewname)
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
Camera *data = camera->data;
@@ -943,7 +953,7 @@ float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *v
}
}
-void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, Object *camera, const char *viewname)
+void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, const Object *camera, const char *viewname)
{
if (camera->type == OB_CAMERA) {
params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname);
@@ -960,3 +970,39 @@ void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_set
r_fx_settings->dof->focus_distance = BKE_camera_object_dof_distance(camera);
}
}
+
+CameraBGImage *BKE_camera_background_image_new(Camera *cam)
+{
+ CameraBGImage *bgpic = MEM_callocN(sizeof(CameraBGImage), "Background Image");
+
+ bgpic->scale = 1.0f;
+ bgpic->alpha = 0.5f;
+ bgpic->iuser.fie_ima = 2;
+ bgpic->iuser.ok = 1;
+ bgpic->iuser.flag |= IMA_ANIM_ALWAYS;
+ bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED;
+
+ BLI_addtail(&cam->bg_images, bgpic);
+
+ return bgpic;
+}
+
+void BKE_camera_background_image_remove(Camera *cam, CameraBGImage *bgpic)
+{
+ BLI_remlink(&cam->bg_images, bgpic);
+
+ MEM_freeN(bgpic);
+}
+
+void BKE_camera_background_image_clear(Camera *cam)
+{
+ CameraBGImage *bgpic = cam->bg_images.first;
+
+ while (bgpic) {
+ CameraBGImage *next_bgpic = bgpic->next;
+
+ BKE_camera_background_image_remove(cam, bgpic);
+
+ bgpic = next_bgpic;
+ }
+}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 1c5b1ca242c..72a1f941c26 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -46,6 +46,7 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_editmesh.h"
#include "BKE_curve.h"
@@ -57,12 +58,6 @@
#include "MEM_guardedalloc.h"
-#include "GPU_buffers.h"
-#include "GPU_draw.h"
-#include "GPU_glew.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
#include <string.h>
#include <limits.h>
#include <math.h>
@@ -295,7 +290,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
* this derivedmesh is just original mesh. it's the multires subsurf dm
* that this is actually for, to support a pbvh on a modified mesh */
if (!cddm->pbvh && ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
MLoopTri *looptri;
bool deformed;
@@ -330,7 +325,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
totvert = deformdm->getNumVerts(deformdm);
vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos");
deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos, totvert);
MEM_freeN(vertCos);
}
}
@@ -338,1450 +333,6 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
return cddm->pbvh;
}
-/* update vertex normals so that drawing smooth faces works during sculpt
- * TODO: proper fix is to support the pbvh in all drawing modes */
-static void cdDM_update_normals_from_pbvh(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- float (*face_nors)[3];
-
- /* Some callbacks do not use optimal PBVH draw, so needs all the
- * possible data (like normals) to be copied from PBVH back to DM.
- *
- * This is safe to do if PBVH and DM are representing the same mesh,
- * which could be wrong when modifiers are enabled for sculpt.
- * So here we only doing update when there's no modifiers applied
- * during sculpt.
- *
- * It's safe to do nothing if there are modifiers, because in this
- * case modifier stack is re-constructed from scratch on every
- * update.
- */
- if (!cddm->pbvh_draw) {
- return;
- }
-
- face_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
- BKE_pbvh_update(cddm->pbvh, PBVH_UpdateNormals, face_nors);
-}
-
-static void cdDM_drawVerts(DerivedMesh *dm)
-{
- GPU_vertex_setup(dm);
- if (dm->drawObject->tot_loop_verts)
- glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loop_verts);
- else
- glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loose_point);
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawUVEdges(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- int totpoly = dm->getNumPolys(dm);
- int prevstart = 0;
- bool prevdraw = true;
- int curpos = 0;
- int i;
-
- GPU_uvedge_setup(dm);
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool draw = (mpoly->flag & ME_HIDE) == 0;
-
- if (prevdraw != draw) {
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- prevstart = curpos;
- }
-
- curpos += 2 * mpoly->totloop;
- prevdraw = draw;
- }
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- GPUDrawObject *gdo;
- if (cddm->pbvh && cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH)
- {
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, true, false);
-
- return;
- }
-
- GPU_edge_setup(dm);
- gdo = dm->drawObject;
- if (gdo->edges && gdo->points) {
- if (drawAllEdges && drawLooseEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->totedge * 2);
- }
- else if (drawAllEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2);
- }
- else {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2);
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, dm->drawObject->tot_loose_edge_drawn * 2);
- }
- }
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawLooseEdges(DerivedMesh *dm)
-{
- int start;
- int count;
-
- GPU_edge_setup(dm);
-
- start = (dm->drawObject->loose_edge_offset * 2);
- count = (dm->drawObject->totedge - dm->drawObject->loose_edge_offset) * 2;
-
- if (count) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count);
- }
-
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawFacesSolid(
- DerivedMesh *dm,
- float (*partial_redraw_planes)[4],
- bool UNUSED(fast), DMSetMaterial setMaterial)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- int a;
-
- if (cddm->pbvh) {
- if (cddm->pbvh_draw && BKE_pbvh_has_faces(cddm->pbvh)) {
- float (*face_nors)[3] = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
- BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors,
- setMaterial, false, false);
- return;
- }
- }
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- for (a = 0; a < dm->drawObject->totmaterial; a++) {
- if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
- GPU_buffer_draw_elements(
- dm->drawObject->triangles, GL_TRIANGLES,
- dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
- }
- }
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawFacesTex_common(
- DerivedMesh *dm,
- DMSetDrawOptionsTex drawParams,
- DMSetDrawOptionsMappedTex drawParamsMapped,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- const MLoopCol *mloopcol = NULL;
- int i;
- int colType, start_element, tot_drawn;
- const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
- const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
- const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
- int totpoly;
- int next_actualFace;
- int mat_index;
- int tot_element;
-
- /* double lookup */
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- /* TODO: not entirely correct, but currently dynamic topology will
- * destroy UVs anyway, so textured display wouldn't work anyway
- *
- * this will do more like solid view with lights set up for
- * textured view, but object itself will be displayed gray
- * (the same as it'll display without UV maps in textured view)
- */
- if (cddm->pbvh) {
- if (cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
- BKE_pbvh_has_faces(cddm->pbvh))
- {
- GPU_set_tpage(NULL, false, false);
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
- return;
- }
- else {
- cdDM_update_normals_from_pbvh(dm);
- }
- }
-
- if (use_colors) {
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- }
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- if (flag & DM_DRAW_USE_TEXPAINT_UV)
- GPU_texpaint_uv_setup(dm);
- else
- GPU_uv_setup(dm);
- if (mloopcol) {
- GPU_color_setup(dm, colType);
- }
-
- /* lastFlag = 0; */ /* UNUSED */
- for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
- GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
- next_actualFace = bufmat->polys[0];
- totpoly = bufmat->totpolys;
-
- tot_element = 0;
- tot_drawn = 0;
- start_element = 0;
-
- for (i = 0; i < totpoly; i++) {
- int actualFace = bufmat->polys[i];
- DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
- int flush = 0;
- int tot_tri_verts;
-
- if (i != totpoly - 1)
- next_actualFace = bufmat->polys[i + 1];
-
- if (use_hide && (mpoly[actualFace].flag & ME_HIDE)) {
- draw_option = DM_DRAW_OPTION_SKIP;
- }
- else if (drawParams) {
- MTexPoly *tp = use_tface && mtexpoly ? &mtexpoly[actualFace] : NULL;
- draw_option = drawParams(tp, (mloopcol != NULL), mpoly[actualFace].mat_nr);
- }
- else {
- if (index_mp_to_orig) {
- const int orig = index_mp_to_orig[actualFace];
- if (orig == ORIGINDEX_NONE) {
- /* XXX, this is not really correct
- * it will draw the previous faces context for this one when we don't know its settings.
- * but better then skipping it altogether. - campbell */
- draw_option = DM_DRAW_OPTION_NORMAL;
- }
- else if (drawParamsMapped) {
- draw_option = drawParamsMapped(userData, orig, mpoly[actualFace].mat_nr);
- }
- }
- else if (drawParamsMapped) {
- draw_option = drawParamsMapped(userData, actualFace, mpoly[actualFace].mat_nr);
- }
- }
-
- /* flush buffer if current triangle isn't drawable or it's last triangle */
- flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1);
-
- if (!flush && compareDrawOptions) {
- /* also compare draw options and flush buffer if they're different
- * need for face selection highlight in edit mode */
- flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
- }
-
- tot_tri_verts = ME_POLY_TRI_TOT(&mpoly[actualFace]) * 3;
- tot_element += tot_tri_verts;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP)
- tot_drawn += tot_tri_verts;
-
- if (tot_drawn) {
- if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL)
- GPU_color_switch(1);
- else
- GPU_color_switch(0);
-
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
- tot_drawn = 0;
- }
- start_element = tot_element;
- }
- else {
- tot_drawn += tot_tri_verts;
- }
- }
- }
-
- GPU_buffers_unbind();
-
-}
-
-static void cdDM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
-}
-
-static void cdDM_drawMappedFaces(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- const MLoopCol *mloopcol = NULL;
- const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
- const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
- int colType;
- int i, j;
- int start_element = 0, tot_element, tot_drawn;
- int totpoly;
- int tot_tri_elem;
- int mat_index;
- GPUBuffer *findex_buffer = NULL;
-
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- if (cddm->pbvh) {
- if (G.debug_value == 14)
- BKE_pbvh_draw_BB(cddm->pbvh);
- }
-
- /* fist, setup common buffers */
- GPU_vertex_setup(dm);
- GPU_triangle_setup(dm);
-
- totpoly = dm->getNumPolys(dm);
-
- /* if we do selection, fill the selection buffer color */
- if (G.f & G_BACKBUFSEL) {
- if (!(flag & DM_DRAW_SKIP_SELECT)) {
- Mesh *me = NULL;
- BMesh *bm = NULL;
- unsigned int *fi_map;
-
- if (flag & DM_DRAW_SELECT_USE_EDITMODE)
- bm = userData;
- else
- me = userData;
-
- findex_buffer = GPU_buffer_alloc(dm->drawObject->tot_loop_verts * sizeof(int));
- fi_map = GPU_buffer_lock(findex_buffer, GPU_BINDING_ARRAY);
-
- if (fi_map) {
- for (i = 0; i < totpoly; i++, mpoly++) {
- int selcol = 0xFFFFFFFF;
- const int orig = (index_mp_to_orig) ? index_mp_to_orig[i] : i;
- bool is_hidden;
-
- if (orig != ORIGINDEX_NONE) {
- if (use_hide) {
- if (flag & DM_DRAW_SELECT_USE_EDITMODE) {
- BMFace *efa = BM_face_at_index(bm, orig);
- is_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0;
- }
- else {
- is_hidden = (me->mpoly[orig].flag & ME_HIDE) != 0;
- }
-
- if (!is_hidden) {
- GPU_select_index_get(orig + 1, &selcol);
- }
- }
- else {
- GPU_select_index_get(orig + 1, &selcol);
- }
- }
-
- for (j = 0; j < mpoly->totloop; j++)
- fi_map[start_element++] = selcol;
- }
-
- start_element = 0;
- mpoly = cddm->mpoly;
-
- GPU_buffer_unlock(findex_buffer, GPU_BINDING_ARRAY);
- GPU_buffer_bind_as_color(findex_buffer);
- }
- }
- }
- else {
- GPU_normal_setup(dm);
-
- if (use_colors) {
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = DM_get_loop_data_layer(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = DM_get_loop_data_layer(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = DM_get_loop_data_layer(dm, colType);
- }
-
- if (use_colors && mloopcol) {
- GPU_color_setup(dm, colType);
- }
- }
- }
-
- tot_tri_elem = dm->drawObject->tot_triangle_point;
-
- if (tot_tri_elem == 0) {
- /* avoid buffer problems in following code */
- }
- else if (setDrawOptions == NULL) {
- /* just draw the entire face array */
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, tot_tri_elem);
- }
- else {
- for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
- GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
- DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
- int next_actualFace = bufmat->polys[0];
- totpoly = use_hide ? bufmat->totvisiblepolys : bufmat->totpolys;
-
- tot_element = 0;
- start_element = 0;
- tot_drawn = 0;
-
- if (setMaterial)
- draw_option = setMaterial(bufmat->mat_nr + 1, NULL);
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- DMDrawOption last_draw_option = DM_DRAW_OPTION_NORMAL;
-
- for (i = 0; i < totpoly; i++) {
- int actualFace = next_actualFace;
- int flush = 0;
- int tot_tri_verts;
-
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (i != totpoly - 1)
- next_actualFace = bufmat->polys[i + 1];
-
- if (setDrawOptions) {
- const int orig = (index_mp_to_orig) ? index_mp_to_orig[actualFace] : actualFace;
-
- if (orig != ORIGINDEX_NONE) {
- draw_option = setDrawOptions(userData, orig);
- }
- }
-
- /* Goal is to draw as long of a contiguous triangle
- * array as possible, so draw when we hit either an
- * invisible triangle or at the end of the array */
-
- /* flush buffer if current triangle isn't drawable or it's last triangle... */
- flush = (draw_option != last_draw_option) || (i == totpoly - 1);
-
- if (!flush && compareDrawOptions) {
- flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
- }
-
- tot_tri_verts = ME_POLY_TRI_TOT(&mpoly[actualFace]) * 3;
- tot_element += tot_tri_verts;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- tot_drawn += tot_tri_verts;
-
- if (last_draw_option != draw_option) {
- if (draw_option == DM_DRAW_OPTION_STIPPLE) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- }
- }
-
- if (tot_drawn) {
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
- tot_drawn = 0;
- }
-
- last_draw_option = draw_option;
- start_element = tot_element;
- }
- else {
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- tot_drawn += tot_tri_verts;
- }
- else {
- start_element = tot_element;
- }
- }
- }
- }
- }
- }
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-
- GPU_buffers_unbind();
-
- if (findex_buffer)
- GPU_buffer_free(findex_buffer);
-
-}
-
-static void cdDM_drawMappedFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
-}
-
-static void cddm_draw_attrib_vertex(
- DMVertexAttribs *attribs, const MVert *mvert, int a, int index, int loop, int vert,
- const float *lnor, const bool smoothnormal)
-{
- DM_draw_attrib_vertex(attribs, a, index, vert, loop);
-
- /* vertex normal */
- if (lnor) {
- glNormal3fv(lnor);
- }
- else if (smoothnormal) {
- glNormal3sv(mvert[index].no);
- }
-
- /* vertex coordinate */
- glVertex3fv(mvert[index].co);
-}
-
-typedef struct {
- DMVertexAttribs attribs;
- int numdata;
-
- GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/
-} GPUMaterialConv;
-
-static void cdDM_drawMappedFacesGLSL(
- DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- GPUVertexAttribs gattribs;
- const MVert *mvert = cddm->mvert;
- const MPoly *mpoly = cddm->mpoly;
- const MLoop *mloop = cddm->mloop;
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
- const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- const int totpoly = dm->getNumPolys(dm);
- const short dm_totmat = dm->totmat;
- int a, b, matnr, new_matnr;
- bool do_draw;
- int orig;
-
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- /* TODO: same as for solid draw, not entirely correct, but works fine for now,
- * will skip using textures (dyntopo currently destroys UV anyway) and
- * works fine for matcap
- */
- if (cddm->pbvh) {
- if (cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
- BKE_pbvh_has_faces(cddm->pbvh))
- {
- setMaterial(1, &gattribs);
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
- return;
- }
- else {
- cdDM_update_normals_from_pbvh(dm);
- }
- }
-
- matnr = -1;
- do_draw = false;
-
- if (setDrawOptions != NULL) {
- DMVertexAttribs attribs;
- DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n");
- memset(&attribs, 0, sizeof(attribs));
-
- glBegin(GL_TRIANGLES);
-
- for (a = 0; a < tottri; a++, lt++) {
- const MPoly *mp = &mpoly[lt->poly];
- const unsigned int vtri[3] = {mloop[lt->tri[0]].v, mloop[lt->tri[1]].v, mloop[lt->tri[2]].v};
- const unsigned int *ltri = lt->tri;
- const float *ln1 = NULL, *ln2 = NULL, *ln3 = NULL;
- const bool smoothnormal = lnors || (mp->flag & ME_SMOOTH);
- new_matnr = mp->mat_nr;
-
- if (new_matnr != matnr) {
- glEnd();
-
- matnr = new_matnr;
- do_draw = setMaterial(matnr + 1, &gattribs);
- if (do_draw) {
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- DM_draw_attrib_vertex_uniforms(&attribs);
- }
-
- glBegin(GL_TRIANGLES);
- }
-
- if (!do_draw) {
- continue;
- }
- else /* if (setDrawOptions) */ {
- orig = (index_mp_to_orig) ? index_mp_to_orig[lt->poly] : lt->poly;
-
- if (orig == ORIGINDEX_NONE) {
- /* since the material is set by setMaterial(), faces with no
- * origin can be assumed to be generated by a modifier */
-
- /* continue */
- }
- else if (setDrawOptions(userData, orig) == DM_DRAW_OPTION_SKIP)
- continue;
- }
-
- if (!smoothnormal) {
- if (nors) {
- glNormal3fv(nors[lt->poly]);
- }
- else {
- /* TODO ideally a normal layer should always be available */
- float nor[3];
- normal_tri_v3(nor, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- glNormal3fv(nor);
- }
- }
- else if (lnors) {
- ln1 = lnors[ltri[0]];
- ln2 = lnors[ltri[1]];
- ln3 = lnors[ltri[2]];
- }
-
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[0], ltri[0], 0, ln1, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[1], ltri[1], 1, ln2, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal);
- }
- glEnd();
- }
- else {
- GPUMaterialConv *matconv;
- int offset;
- int *mat_orig_to_new;
- int tot_active_mat;
- GPUBuffer *buffer = NULL;
- unsigned char *varray;
- size_t max_element_size = 0;
- int tot_loops = 0;
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
-
- tot_active_mat = dm->drawObject->totmaterial;
-
- matconv = MEM_calloc_arrayN(tot_active_mat, sizeof(*matconv),
- "cdDM_drawMappedFacesGLSL.matconv");
- mat_orig_to_new = MEM_malloc_arrayN(dm->totmat, sizeof(*mat_orig_to_new),
- "cdDM_drawMappedFacesGLSL.mat_orig_to_new");
-
- /* part one, check what attributes are needed per material */
- for (a = 0; a < tot_active_mat; a++) {
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- /* map from original material index to new
- * GPUBufferMaterial index */
- mat_orig_to_new[new_matnr] = a;
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- int numdata = 0;
- DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs);
-
- if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
- matconv[a].datatypes[numdata].size = 3;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- for (b = 0; b < matconv[a].attribs.tottface; b++) {
- if (matconv[a].attribs.tface[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 2;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.totmcol; b++) {
- if (matconv[a].attribs.mcol[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.tottang; b++) {
- if (matconv[a].attribs.tang[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- if (numdata != 0) {
- matconv[a].numdata = numdata;
- max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size);
- }
- }
- }
-
- /* part two, generate and fill the arrays with the data */
- if (max_element_size > 0) {
- buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts);
-
- varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY);
- if (varray == NULL) {
- GPU_buffers_unbind();
- GPU_buffer_free(buffer);
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- fprintf(stderr, "Out of memory, can't draw object\n");
- return;
- }
-
- for (a = 0; a < totpoly; a++, mpoly++) {
- const short mat_nr = ME_MAT_NR_TEST(mpoly->mat_nr, dm_totmat);
- int j;
- int i = mat_orig_to_new[mat_nr];
- offset = tot_loops * max_element_size;
-
- if (matconv[i].numdata != 0) {
- if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) {
- for (j = 0; j < mpoly->totloop; j++)
- copy_v3_v3((float *)&varray[offset + j * max_element_size],
- (float *)matconv[i].attribs.orco.array[mloop[mpoly->loopstart + j].v]);
- offset += sizeof(float) * 3;
- }
- for (b = 0; b < matconv[i].attribs.tottface; b++) {
- if (matconv[i].attribs.tface[b].array) {
- const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v2_v2((float *)&varray[offset + j * max_element_size], mloopuv[mpoly->loopstart + j].uv);
- offset += sizeof(float) * 2;
- }
- }
- for (b = 0; b < matconv[i].attribs.totmcol; b++) {
- if (matconv[i].attribs.mcol[b].array) {
- const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v4_v4_uchar(&varray[offset + j * max_element_size], &mloopcol[mpoly->loopstart + j].r);
- offset += sizeof(unsigned char) * 4;
- }
- }
- for (b = 0; b < matconv[i].attribs.tottang; b++) {
- if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
- const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
- offset += sizeof(float) * 4;
- }
- }
- }
-
- tot_loops += mpoly->totloop;
- }
- GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY);
- }
-
- for (a = 0; a < tot_active_mat; a++) {
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size);
- }
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES,
- dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_unbind();
- }
- }
- }
-
- GPU_buffers_unbind();
- if (buffer)
- GPU_buffer_free(buffer);
-
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- }
-}
-
-static void cdDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-static void cdDM_drawMappedFacesMat(
- DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- GPUVertexAttribs gattribs;
- DMVertexAttribs attribs;
- MVert *mvert = cddm->mvert;
- const MPoly *mpoly = cddm->mpoly;
- const MLoop *mloop = cddm->mloop;
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int a, matnr, new_matnr;
- int orig;
-
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- /* TODO: same as for solid draw, not entirely correct, but works fine for now,
- * will skip using textures (dyntopo currently destroys UV anyway) and
- * works fine for matcap
- */
-
- if (cddm->pbvh) {
- if (cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
- BKE_pbvh_has_faces(cddm->pbvh))
- {
- setMaterial(userData, 1, &gattribs);
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
- return;
- }
- else {
- cdDM_update_normals_from_pbvh(dm);
- }
- }
-
- matnr = -1;
-
- memset(&attribs, 0, sizeof(attribs));
-
- glBegin(GL_TRIANGLES);
-
- for (a = 0; a < tottri; a++, lt++) {
- const MPoly *mp = &mpoly[lt->poly];
- const unsigned int vtri[3] = {mloop[lt->tri[0]].v, mloop[lt->tri[1]].v, mloop[lt->tri[2]].v};
- const unsigned int *ltri = lt->tri;
- const bool smoothnormal = lnors || (mp->flag & ME_SMOOTH);
- const float *ln1 = NULL, *ln2 = NULL, *ln3 = NULL;
-
- /* material */
- new_matnr = mp->mat_nr + 1;
-
- if (new_matnr != matnr) {
- glEnd();
-
- setMaterial(userData, matnr = new_matnr, &gattribs);
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- DM_draw_attrib_vertex_uniforms(&attribs);
-
- glBegin(GL_TRIANGLES);
- }
-
- /* skipping faces */
- if (setFace) {
- orig = (index_mp_to_orig) ? index_mp_to_orig[lt->poly] : lt->poly;
-
- if (orig != ORIGINDEX_NONE && !setFace(userData, orig))
- continue;
- }
-
- /* smooth normal */
- if (!smoothnormal) {
- if (nors) {
- glNormal3fv(nors[lt->poly]);
- }
- else {
- /* TODO ideally a normal layer should always be available */
- float nor[3];
- normal_tri_v3(nor, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- glNormal3fv(nor);
- }
- }
- else if (lnors) {
- ln1 = lnors[ltri[0]];
- ln2 = lnors[ltri[1]];
- ln3 = lnors[ltri[2]];
- }
-
- /* vertices */
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[0], ltri[0], 0, ln1, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[1], ltri[1], 1, ln2, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal);
- }
- glEnd();
-}
-
-static void cdDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- MVert *vert = cddm->mvert;
- MEdge *edge = cddm->medge;
- int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
-
- glBegin(GL_LINES);
- for (i = 0; i < dm->numEdgeData; i++, edge++) {
- if (index) {
- orig = *index++;
- if (setDrawOptions && orig == ORIGINDEX_NONE) continue;
- }
- else
- orig = i;
-
- if (!setDrawOptions || (setDrawOptions(userData, orig) != DM_DRAW_OPTION_SKIP)) {
- glVertex3fv(vert[edge->v1].co);
- glVertex3fv(vert[edge->v2].co);
- }
- }
- glEnd();
-}
-
-typedef struct FaceCount {
- unsigned int i_visible;
- unsigned int i_hidden;
- unsigned int i_tri_visible;
- unsigned int i_tri_hidden;
-} FaceCount;
-
-static void cdDM_buffer_copy_triangles(
- DerivedMesh *dm, unsigned int *varray,
- const int *mat_orig_to_new)
-{
- GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials;
- int i, j, start;
-
- const int gpu_totmat = dm->drawObject->totmaterial;
- const short dm_totmat = dm->totmat;
- const MPoly *mpoly = dm->getPolyArray(dm);
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const int totpoly = dm->getNumPolys(dm);
-
- FaceCount *fc = MEM_malloc_arrayN(gpu_totmat, sizeof(*fc), "gpumaterial.facecount");
-
- for (i = 0; i < gpu_totmat; i++) {
- fc[i].i_visible = 0;
- fc[i].i_tri_visible = 0;
- fc[i].i_hidden = gpumaterials[i].totpolys - 1;
- fc[i].i_tri_hidden = gpumaterials[i].totelements - 1;
- }
-
- for (i = 0; i < totpoly; i++) {
- const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat);
- int tottri = ME_POLY_TRI_TOT(&mpoly[i]);
- int mati = mat_orig_to_new[mat_nr];
- gpumat = gpumaterials + mati;
-
- if (mpoly[i].flag & ME_HIDE) {
- for (j = 0; j < tottri; j++, lt++) {
- start = gpumat->start + fc[mati].i_tri_hidden;
- /* v1 v2 v3 */
- varray[start--] = lt->tri[2];
- varray[start--] = lt->tri[1];
- varray[start--] = lt->tri[0];
- fc[mati].i_tri_hidden -= 3;
- }
- gpumat->polys[fc[mati].i_hidden--] = i;
- }
- else {
- for (j = 0; j < tottri; j++, lt++) {
- start = gpumat->start + fc[mati].i_tri_visible;
- /* v1 v2 v3 */
- varray[start++] = lt->tri[0];
- varray[start++] = lt->tri[1];
- varray[start++] = lt->tri[2];
- fc[mati].i_tri_visible += 3;
- }
- gpumat->polys[fc[mati].i_visible++] = i;
- }
- }
-
- /* set the visible polygons */
- for (i = 0; i < gpu_totmat; i++) {
- gpumaterials[i].totvisiblepolys = fc[i].i_visible;
- }
-
- MEM_freeN(fc);
-}
-
-static void cdDM_buffer_copy_vertex(
- DerivedMesh *dm, float *varray)
-{
- const MVert *mvert;
- const MPoly *mpoly;
- const MLoop *mloop;
-
- int i, j, start, totpoly;
-
- mvert = dm->getVertArray(dm);
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
- totpoly = dm->getNumPolys(dm);
-
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v3_v3(&varray[start], mvert[mloop[mpoly->loopstart + j].v].co);
- start += 3;
- }
- }
-
- /* copy loose points */
- j = dm->drawObject->tot_loop_verts * 3;
- for (i = 0; i < dm->drawObject->totvert; i++) {
- if (dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_loop_verts) {
- copy_v3_v3(&varray[j], mvert[i].co);
- j += 3;
- }
- }
-}
-
-static void cdDM_buffer_copy_normal(
- DerivedMesh *dm, short *varray)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- int i, j, totpoly;
- int start;
-
- const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-
- const MVert *mvert;
- const MPoly *mpoly;
- const MLoop *mloop;
-
- mvert = dm->getVertArray(dm);
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
- totpoly = dm->getNumPolys(dm);
-
- /* we are in sculpt mode, disable loop normals (since they won't get updated) */
- if (cddm->pbvh)
- lnors = NULL;
-
- start = 0;
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool smoothnormal = (mpoly->flag & ME_SMOOTH) != 0;
-
- if (lnors) {
- /* Copy loop normals */
- for (j = 0; j < mpoly->totloop; j++, start += 4) {
- normal_float_to_short_v3(&varray[start], lnors[mpoly->loopstart + j]);
- }
- }
- else if (smoothnormal) {
- /* Copy vertex normal */
- for (j = 0; j < mpoly->totloop; j++, start += 4) {
- copy_v3_v3_short(&varray[start], mvert[mloop[mpoly->loopstart + j].v].no);
- }
- }
- else {
- /* Copy cached OR calculated face normal */
- short f_no_s[3];
-
- if (nors) {
- normal_float_to_short_v3(f_no_s, nors[i]);
- }
- else {
- float f_no[3];
- BKE_mesh_calc_poly_normal(mpoly, &mloop[mpoly->loopstart], mvert, f_no);
- normal_float_to_short_v3(f_no_s, f_no);
- }
-
- for (j = 0; j < mpoly->totloop; j++, start += 4) {
- copy_v3_v3_short(&varray[start], f_no_s);
- }
- }
- }
-}
-
-static void cdDM_buffer_copy_uv(
- DerivedMesh *dm, float *varray)
-{
- int i, j, totpoly;
- int start;
-
- const MPoly *mpoly;
- const MLoopUV *mloopuv;
-
- if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
- return;
- }
-
- mpoly = dm->getPolyArray(dm);
- totpoly = dm->getNumPolys(dm);
-
- start = 0;
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
- start += 2;
- }
- }
-}
-
-static void cdDM_buffer_copy_uv_texpaint(
- DerivedMesh *dm, float *varray)
-{
- int i, j, totpoly;
- int start;
-
- const MPoly *mpoly;
-
- int totmaterial = dm->totmat;
- const MLoopUV **uv_base;
- const MLoopUV *uv_stencil_base;
- int stencil;
-
- totpoly = dm->getNumPolys(dm);
-
- /* should have been checked for before, reassert */
- BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV));
- uv_base = MEM_malloc_arrayN(totmaterial, sizeof(*uv_base), "texslots");
-
- for (i = 0; i < totmaterial; i++) {
- uv_base[i] = DM_paint_uvlayer_active_get(dm, i);
- }
-
- stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV);
- uv_stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil);
-
- mpoly = dm->getPolyArray(dm);
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- int mat_i = mpoly->mat_nr;
-
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], uv_base[mat_i][mpoly->loopstart + j].uv);
- copy_v2_v2(&varray[start + 2], uv_stencil_base[mpoly->loopstart + j].uv);
- start += 4;
- }
- }
-
- MEM_freeN((void *)uv_base);
-}
-
-/* treat varray_ as an array of MCol, four MCol's per face */
-static void cdDM_buffer_copy_mcol(
- DerivedMesh *dm, unsigned char *varray,
- const void *user_data)
-{
- int i, j, totpoly;
- int start;
-
- const MLoopCol *mloopcol = user_data;
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- totpoly = dm->getNumPolys(dm);
-
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v4_v4_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r);
- start += 4;
- }
- }
-}
-
-static void cdDM_buffer_copy_edge(
- DerivedMesh *dm, unsigned int *varray)
-{
- MEdge *medge, *medge_base;
- int i, totedge, iloose, inorm, iloosehidden, inormhidden;
- int tot_loose_hidden = 0, tot_loose = 0;
- int tot_hidden = 0, tot = 0;
-
- medge_base = medge = dm->getEdgeArray(dm);
- totedge = dm->getNumEdges(dm);
-
- for (i = 0; i < totedge; i++, medge++) {
- if (medge->flag & ME_EDGEDRAW) {
- if (medge->flag & ME_LOOSEEDGE) tot_loose++;
- else tot++;
- }
- else {
- if (medge->flag & ME_LOOSEEDGE) tot_loose_hidden++;
- else tot_hidden++;
- }
- }
-
- inorm = 0;
- inormhidden = tot;
- iloose = tot + tot_hidden;
- iloosehidden = iloose + tot_loose;
-
- medge = medge_base;
- for (i = 0; i < totedge; i++, medge++) {
- if (medge->flag & ME_EDGEDRAW) {
- if (medge->flag & ME_LOOSEEDGE) {
- varray[iloose * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[iloose * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- iloose++;
- }
- else {
- varray[inorm * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[inorm * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- inorm++;
- }
- }
- else {
- if (medge->flag & ME_LOOSEEDGE) {
- varray[iloosehidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[iloosehidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- iloosehidden++;
- }
- else {
- varray[inormhidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[inormhidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- inormhidden++;
- }
- }
- }
-
- dm->drawObject->tot_loose_edge_drawn = tot_loose;
- dm->drawObject->loose_edge_offset = tot + tot_hidden;
- dm->drawObject->tot_edge_drawn = tot;
-}
-
-static void cdDM_buffer_copy_uvedge(
- DerivedMesh *dm, float *varray)
-{
- int i, j, totpoly;
- int start;
- const MLoopUV *mloopuv;
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
- return;
- }
-
- totpoly = dm->getNumPolys(dm);
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv);
- start += 4;
- }
- }
-}
-
-static void cdDM_copy_gpu_data(
- DerivedMesh *dm, int type, void *varray_p,
- const int *mat_orig_to_new, const void *user_data)
-{
- /* 'varray_p' cast is redundant but include for self-documentation */
- switch (type) {
- case GPU_BUFFER_VERTEX:
- cdDM_buffer_copy_vertex(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_NORMAL:
- cdDM_buffer_copy_normal(dm, (short *)varray_p);
- break;
- case GPU_BUFFER_COLOR:
- cdDM_buffer_copy_mcol(dm, (unsigned char *)varray_p, user_data);
- break;
- case GPU_BUFFER_UV:
- cdDM_buffer_copy_uv(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_UV_TEXPAINT:
- cdDM_buffer_copy_uv_texpaint(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_EDGE:
- cdDM_buffer_copy_edge(dm, (unsigned int *)varray_p);
- break;
- case GPU_BUFFER_UVEDGE:
- cdDM_buffer_copy_uvedge(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_TRIANGLES:
- cdDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new);
- break;
- default:
- break;
- }
-}
-
-/* add a new point to the list of points related to a particular
- * vertex */
-#ifdef USE_GPU_POINT_LINK
-
-static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
-{
- GPUVertPointLink *lnk;
-
- lnk = &gdo->vert_points[vert_index];
-
- /* if first link is in use, add a new link at the end */
- if (lnk->point_index != -1) {
- /* get last link */
- for (; lnk->next; lnk = lnk->next) ;
-
- /* add a new link from the pool */
- lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage];
- gdo->vert_points_usage++;
- }
-
- lnk->point_index = point_index;
-}
-
-#else
-
-static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
-{
- GPUVertPointLink *lnk;
- lnk = &gdo->vert_points[vert_index];
- if (lnk->point_index == -1) {
- lnk->point_index = point_index;
- }
-}
-
-#endif /* USE_GPU_POINT_LINK */
-
-/* for each vertex, build a list of points related to it; these lists
- * are stored in an array sized to the number of vertices */
-static void cdDM_drawobject_init_vert_points(
- GPUDrawObject *gdo,
- const MPoly *mpoly, const MLoop *mloop,
- int tot_poly)
-{
- int i;
- int tot_loops = 0;
-
- /* allocate the array and space for links */
- gdo->vert_points = MEM_malloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink),
- "GPUDrawObject.vert_points");
-#ifdef USE_GPU_POINT_LINK
- gdo->vert_points_mem = MEM_calloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink),
- "GPUDrawObject.vert_points_mem");
- gdo->vert_points_usage = 0;
-#endif
-
- /* -1 indicates the link is not yet used */
- for (i = 0; i < gdo->totvert; i++) {
-#ifdef USE_GPU_POINT_LINK
- gdo->vert_points[i].link = NULL;
-#endif
- gdo->vert_points[i].point_index = -1;
- }
-
- for (i = 0; i < tot_poly; i++) {
- int j;
- const MPoly *mp = &mpoly[i];
-
- /* assign unique indices to vertices of the mesh */
- for (j = 0; j < mp->totloop; j++) {
- cdDM_drawobject_add_vert_point(gdo, mloop[mp->loopstart + j].v, tot_loops + j);
- }
- tot_loops += mp->totloop;
- }
-
- /* map any unused vertices to loose points */
- for (i = 0; i < gdo->totvert; i++) {
- if (gdo->vert_points[i].point_index == -1) {
- gdo->vert_points[i].point_index = gdo->tot_loop_verts + gdo->tot_loose_point;
- gdo->tot_loose_point++;
- }
- }
-}
-
-/* see GPUDrawObject's structure definition for a description of the
- * data being initialized here */
-static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm)
-{
- GPUDrawObject *gdo;
- const MPoly *mpoly;
- const MLoop *mloop;
- const short dm_totmat = dm->totmat;
- GPUBufferMaterial *mat_info;
- int i, totloops, totpolys;
-
- /* object contains at least one material (default included) so zero means uninitialized dm */
- BLI_assert(dm_totmat != 0);
-
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
-
- totpolys = dm->getNumPolys(dm);
- totloops = dm->getNumLoops(dm);
-
- /* get the number of points used by each material, treating
- * each quad as two triangles */
- mat_info = MEM_calloc_arrayN(dm_totmat, sizeof(*mat_info), "GPU_drawobject_new.mat_orig_to_new");
-
- for (i = 0; i < totpolys; i++) {
- const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat);
- mat_info[mat_nr].totpolys++;
- mat_info[mat_nr].totelements += 3 * ME_POLY_TRI_TOT(&mpoly[i]);
- mat_info[mat_nr].totloops += mpoly[i].totloop;
- }
- /* create the GPUDrawObject */
- gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
- gdo->totvert = dm->getNumVerts(dm);
- gdo->totedge = dm->getNumEdges(dm);
-
- GPU_buffer_material_finalize(gdo, mat_info, dm_totmat);
-
- gdo->tot_loop_verts = totloops;
-
- /* store total number of points used for triangles */
- gdo->tot_triangle_point = poly_to_tri_count(totpolys, totloops) * 3;
-
- cdDM_drawobject_init_vert_points(gdo, mpoly, mloop, totpolys);
-
- return gdo;
-}
-
static void cdDM_foreachMappedVert(
DerivedMesh *dm,
void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
@@ -1913,7 +464,7 @@ void CDDM_recalc_tessellation_ex(DerivedMesh *dm, const bool do_face_nor_cpy)
/* Tessellation recreated faceData, and the active layer indices need to get re-propagated
* from loops and polys to faces */
- CustomData_bmesh_update_active_layers(&dm->faceData, &dm->polyData, &dm->loopData);
+ CustomData_bmesh_update_active_layers(&dm->faceData, &dm->loopData);
}
void CDDM_recalc_tessellation(DerivedMesh *dm)
@@ -2005,24 +556,6 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getPBVH = cdDM_getPBVH;
dm->getPolyMap = cdDM_getPolyMap;
- dm->drawVerts = cdDM_drawVerts;
-
- dm->drawUVEdges = cdDM_drawUVEdges;
- dm->drawEdges = cdDM_drawEdges;
- dm->drawLooseEdges = cdDM_drawLooseEdges;
- dm->drawMappedEdges = cdDM_drawMappedEdges;
-
- dm->drawFacesSolid = cdDM_drawFacesSolid;
- dm->drawFacesTex = cdDM_drawFacesTex;
- dm->drawFacesGLSL = cdDM_drawFacesGLSL;
- dm->drawMappedFaces = cdDM_drawMappedFaces;
- dm->drawMappedFacesTex = cdDM_drawMappedFacesTex;
- dm->drawMappedFacesGLSL = cdDM_drawMappedFacesGLSL;
- dm->drawMappedFacesMat = cdDM_drawMappedFacesMat;
-
- dm->gpuObjectNew = cdDM_GPUobject_new;
- dm->copy_gpu_data = cdDM_copy_gpu_data;
-
dm->foreachMappedVert = cdDM_foreachMappedVert;
dm->foreachMappedEdge = cdDM_foreachMappedEdge;
dm->foreachMappedLoop = cdDM_foreachMappedLoop;
@@ -2062,20 +595,31 @@ DerivedMesh *CDDM_new(int numVerts, int numEdges, int numTessFaces, int numLoops
DerivedMesh *CDDM_from_mesh(Mesh *mesh)
{
+ return CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_MESH);
+}
+
+DerivedMesh *CDDM_from_mesh_ex(Mesh *mesh, eCDAllocType alloctype, CustomDataMask mask)
+{
CDDerivedMesh *cddm = cdDM_create(__func__);
DerivedMesh *dm = &cddm->dm;
- CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS);
- int alloctype;
+
+ mask &= ~CD_MASK_MDISPS;
/* this does a referenced copy, with an exception for fluidsim */
DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, 0 /* mesh->totface */,
mesh->totloop, mesh->totpoly);
+ /* This should actually be dm->deformedOnly = mesh->runtime.deformed_only,
+ * but only if the original mesh had its deformed_only flag correctly set
+ * (which isn't generally the case). */
dm->deformedOnly = 1;
dm->cd_flag = mesh->cd_flag;
- alloctype = CD_REFERENCE;
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ dm->dirty |= DM_DIRTY_NORMALS;
+ }
+ /* TODO DM_DIRTY_TESS_CDLAYERS ? Maybe not though, since we probably want to switch to looptris ? */
CustomData_merge(&mesh->vdata, &dm->vertData, mask, alloctype,
mesh->totvert);
@@ -2153,7 +697,6 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase)
if (alluv) {
const char *uvname = "Orco";
- CustomData_add_layer_named(&cddm->dm.polyData, CD_MTEXPOLY, CD_DEFAULT, NULL, totpoly, uvname);
CustomData_add_layer_named(&cddm->dm.loopData, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
}
@@ -2168,22 +711,18 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase)
static void loops_to_customdata_corners(
BMesh *bm, CustomData *facedata,
int cdindex, const BMLoop *l3[3],
- int numCol, int numTex)
+ int numCol, int numUV)
{
const BMLoop *l;
- BMFace *f = l3[0]->f;
+// BMFace *f = l3[0]->f;
MTFace *texface;
- MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
int i, j, hasPCol = CustomData_has_layer(&bm->ldata, CD_PREVIEW_MLOOPCOL);
- for (i = 0; i < numTex; i++) {
+ for (i = 0; i < numUV; i++) {
texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
- texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
-
- ME_MTEXFACE_CPY(texface, texpoly);
for (j = 0; j < 3; j++) {
l = l3[j];
@@ -2237,7 +776,7 @@ static DerivedMesh *cddm_from_bmesh_ex(
MLoop *mloop = cddm->mloop;
MPoly *mpoly = cddm->mpoly;
int numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
- int numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ int numUV = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
int *index, add_orig;
CustomDataMask mask;
unsigned int i, j;
@@ -2267,7 +806,7 @@ static DerivedMesh *cddm_from_bmesh_ex(
/* add tessellation mface layers */
if (use_tessface) {
- CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, em_tottri);
+ CustomData_from_bmeshpoly(&dm->faceData, &dm->loopData, em_tottri);
}
index = dm->getVertDataArray(dm, CD_ORIGINDEX);
@@ -2339,7 +878,7 @@ static DerivedMesh *cddm_from_bmesh_ex(
/* map mfaces to polygons in the same cddm intentionally */
*index++ = BM_elem_index_get(efa);
- loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex);
+ loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numUV);
test_index_face(mf, &dm->faceData, i, 3);
}
}
@@ -2772,7 +1311,8 @@ void CDDM_calc_normals_tessface(DerivedMesh *dm)
}
#if 1
-
+/* TODO(sybren): Delete everything in this #if block after we have ported the modifiers
+ * to use Mesh instead of DerivedMesh. The code has been copied to mesh_merge.c and ported. */
/**
* Poly compare with vtargetmap
* Function used by #CDDM_merge_verts.
@@ -2950,7 +1490,7 @@ static bool poly_gset_compare_fn(const void *k1, const void *k2)
* \param vtargetmap The table that maps vertices to target vertices. a value of -1
* indicates a vertex is a target, and is to be kept.
* This array is aligned with 'dm->numVertData'
- * \warning \a vtergatmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported
+ * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported
* and will likely generate corrupted geometry.
*
* \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size)
@@ -2974,6 +1514,7 @@ static bool poly_gset_compare_fn(const void *k1, const void *k2)
*/
DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
{
+// This was commented out back in 2013, see commit f45d8827bafe6b9eaf9de42f4054e9d84a21955d.
// #define USE_LOOPS
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
CDDerivedMesh *cddm2 = NULL;
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index a91f3b909e1..bfe59e5366d 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -33,6 +33,7 @@
#include "DNA_cloth_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
@@ -40,10 +41,14 @@
#include "BLI_edgehash.h"
#include "BLI_linklist.h"
-#include "BKE_cdderivedmesh.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "BKE_bvhutils.h"
#include "BKE_cloth.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
@@ -55,13 +60,13 @@
/* Prototypes for internal functions.
*/
static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*vertexCos)[3]);
-static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm );
-static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first);
+static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh );
+static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, float framenr, int first);
static void cloth_update_springs( ClothModifierData *clmd );
-static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm );
-static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm );
-static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
-static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh );
+static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh );
+static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh );
+static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh );
/******************************************************************************
*
@@ -317,7 +322,7 @@ void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr);
}
-static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
+static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int framenr)
{
PointCache *cache;
@@ -345,7 +350,7 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
return 1;
}
-static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
+static int do_step_cloth(struct Depsgraph *depsgraph, Scene *scene, Object *ob, ClothModifierData *clmd, Mesh *result, int framenr)
{
ClothVertex *verts = NULL;
Cloth *cloth;
@@ -357,7 +362,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/* simulate 1 frame forward */
cloth = clmd->clothObject;
verts = cloth->verts;
- mvert = result->getVertArray(result);
+ mvert = result->mvert;
/* force any pinned verts to their constrained location. */
for (i = 0; i < clmd->clothObject->mvert_num; i++, verts++) {
@@ -370,7 +375,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
mul_m4_v3(ob->obmat, verts->xconst);
}
- effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights, true);
+ effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, clmd->sim_parms->effector_weights);
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH )
cloth_update_verts ( ob, clmd, result );
@@ -386,11 +391,11 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
// TIMEIT_START(cloth_step)
/* call the solver. */
- ret = BPH_cloth_solve(ob, framenr, clmd, effectors);
+ ret = BPH_cloth_solve(scene, ob, framenr, clmd, effectors);
// TIMEIT_END(cloth_step)
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
// printf ( "%f\n", ( float ) tval() );
@@ -400,7 +405,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/************************************************
* clothModifier_do - main simulation function
************************************************/
-void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, DerivedMesh *dm, float (*vertexCos)[3])
+void clothModifier_do(ClothModifierData *clmd, struct Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh, float (*vertexCos)[3])
{
PointCache *cache;
PTCacheID pid;
@@ -408,15 +413,14 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
int framenr, startframe, endframe;
int cache_result;
- clmd->scene= scene; /* nice to pass on later :) */
- framenr= (int)scene->r.cfra;
+ framenr = DEG_get_ctime(depsgraph);
cache= clmd->point_cache;
BKE_ptcache_id_from_cloth(&pid, ob, clmd);
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
clmd->sim_parms->timescale= timescale * clmd->sim_parms->time_scale;
- if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->mvert_num)) {
+ if (clmd->sim_parms->reset || (clmd->clothObject && mesh->totvert != clmd->clothObject->mvert_num)) {
clmd->sim_parms->reset = 0;
cache->flag |= PTCACHE_OUTDATED;
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
@@ -438,12 +442,12 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
}
/* initialize simulation data if it didn't exist already */
- if (!do_init_cloth(ob, clmd, dm, framenr))
+ if (!do_init_cloth(ob, clmd, mesh, framenr))
return;
if (framenr == startframe) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- do_init_cloth(ob, clmd, dm, framenr);
+ do_init_cloth(ob, clmd, mesh, framenr);
BKE_ptcache_validate(cache, framenr);
cache->flag &= ~PTCACHE_REDO_NEEDED;
clmd->clothObject->last_frame= framenr;
@@ -479,9 +483,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
return;
}
- if (!can_simulate)
- return;
-
/* if on second frame, write cache for first frame */
if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
BKE_ptcache_write(&pid, startframe);
@@ -491,7 +492,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
/* do simulation */
BKE_ptcache_validate(cache, framenr);
- if (!do_step_cloth(ob, clmd, dm, framenr)) {
+ if (!do_step_cloth(depsgraph, scene, ob, clmd, mesh, framenr)) {
BKE_ptcache_invalidate(cache);
}
else
@@ -674,7 +675,7 @@ int cloth_uses_vgroup(ClothModifierData *clmd)
*
**/
/* can be optimized to do all groups in one loop */
-static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh )
{
int i = 0;
int j = 0;
@@ -684,11 +685,11 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
/* float goalfac = 0; */ /* UNUSED */
ClothVertex *verts = NULL;
- if (!clmd || !dm) return;
+ if (!clmd || !mesh) return;
clothObj = clmd->clothObject;
- mvert_num = dm->getNumVerts(dm);
+ mvert_num = mesh->totvert;
verts = clothObj->verts;
@@ -708,7 +709,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
verts->flags &= ~CLOTH_VERT_FLAG_PINNED;
verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL;
- dvert = dm->getVertData ( dm, i, CD_MDEFORMVERT );
+ dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
if ( dvert ) {
for ( j = 0; j < dvert->totweight; j++ ) {
if (( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass-1)) && (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )) {
@@ -774,7 +775,7 @@ static float cloth_shrink_factor(ClothModifierData *clmd, ClothVertex *verts, in
return 1.0f;
}
-static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first)
+static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, float UNUSED(framenr), int first)
{
int i = 0;
MVert *mvert = NULL;
@@ -804,25 +805,25 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
return 0;
}
- // mesh input objects need DerivedMesh
- if ( !dm )
+ // mesh input objects need Mesh
+ if ( !mesh )
return 0;
- cloth_from_mesh ( clmd, dm );
+ cloth_from_mesh ( clmd, mesh );
// create springs
clmd->clothObject->springs = NULL;
clmd->clothObject->numsprings = -1;
if ( clmd->sim_parms->shapekey_rest && !(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) )
- shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO );
+ shapekey_rest = CustomData_get_layer(&mesh->vdata, CD_CLOTH_ORCO);
- mvert = dm->getVertArray (dm);
+ mvert = mesh->mvert;
verts = clmd->clothObject->verts;
// set initial values
- for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) {
+ for ( i = 0; i < mesh->totvert; i++, verts++ ) {
if (first) {
copy_v3_v3(verts->x, mvert[i].co);
@@ -860,9 +861,9 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
// apply / set vertex groups
// has to be happen before springs are build!
- cloth_apply_vgroup (clmd, dm);
+ cloth_apply_vgroup (clmd, mesh);
- if ( !cloth_build_springs ( clmd, dm ) ) {
+ if ( !cloth_build_springs ( clmd, mesh ) ) {
cloth_free_modifier ( clmd );
modifier_setError(&(clmd->modifier), "Cannot build springs");
printf("cloth_free_modifier cloth_build_springs\n");
@@ -877,7 +878,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) );
- for (i = 0; i < dm->getNumVerts(dm); i++) {
+ for (i = 0; i < mesh->totvert; i++) {
maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f));
}
@@ -886,12 +887,12 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
return 1;
}
-static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh )
{
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- const unsigned int mvert_num = dm->getNumVerts(dm);
- const unsigned int looptri_num = dm->getNumLoopTri(dm);
+ const MLoop *mloop = mesh->mloop;
+ const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const unsigned int mvert_num = mesh->totvert;
+ const unsigned int looptri_num = mesh->runtime.looptris.len;
/* Allocate our vertices. */
clmd->clothObject->mvert_num = mvert_num;
@@ -912,7 +913,7 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
printf("cloth_free_modifier clmd->clothObject->looptri\n");
return;
}
- DM_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
+ BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
/* Free the springs since they can't be correct if the vertices
* changed.
@@ -923,7 +924,7 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
}
/***************************************************************************************
- * SPRING NETWORK BUILDING IMPLEMENTATION BEGIN
+ * SPRING NETWORK GWN_BATCH_BUILDING IMPLEMENTATION BEGIN
***************************************************************************************/
BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
@@ -1154,27 +1155,27 @@ static void cloth_update_springs( ClothModifierData *clmd )
}
/* Update rest verts, for dynamically deformable cloth */
-static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh )
{
unsigned int i = 0;
- MVert *mvert = dm->getVertArray (dm);
+ MVert *mvert = mesh->mvert;
ClothVertex *verts = clmd->clothObject->verts;
/* vertex count is already ensured to match */
- for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) {
+ for ( i = 0; i < mesh->totvert; i++, verts++ ) {
copy_v3_v3(verts->xrest, mvert[i].co);
mul_m4_v3(ob->obmat, verts->xrest);
}
}
/* Update spring rest lenght, for dynamically deformable cloth */
-static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh )
{
Cloth *cloth = clmd->clothObject;
LinkNode *search = cloth->springs;
unsigned int struct_springs = 0;
unsigned int i = 0;
- unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+ unsigned int mvert_num = (unsigned int)mesh->totvert;
float shrink_factor;
clmd->sim_parms->avg_spring_len = 0.0f;
@@ -1249,19 +1250,19 @@ void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3]
mul_m3_m3m3(mat, rot, mat);
}
-static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
+static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh )
{
Cloth *cloth = clmd->clothObject;
ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0, struct_springs_real = 0;
unsigned int i = 0;
- unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
- unsigned int numedges = (unsigned int)dm->getNumEdges (dm);
- unsigned int numpolys = (unsigned int)dm->getNumPolys(dm);
+ unsigned int mvert_num = (unsigned int)mesh->totvert;
+ unsigned int numedges = (unsigned int)mesh->totedge;
+ unsigned int numpolys = (unsigned int)mesh->totpoly;
float shrink_factor;
- const MEdge *medge = dm->getEdgeArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
+ const MEdge *medge = mesh->medge;
+ const MPoly *mpoly = mesh->mpoly;
+ const MLoop *mloop = mesh->mloop;
int index2 = 0; // our second vertex index
LinkNodePair *edgelist;
EdgeSet *edgeset = NULL;
@@ -1505,6 +1506,6 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
} /* cloth_build_springs */
/***************************************************************************************
- * SPRING NETWORK BUILDING IMPLEMENTATION END
+ * SPRING NETWORK GWN_BATCH_BUILDING IMPLEMENTATION END
***************************************************************************************/
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
new file mode 100644
index 00000000000..eef4a6210c8
--- /dev/null
+++ b/source/blender/blenkernel/intern/collection.c
@@ -0,0 +1,1171 @@
+/*
+ * ***** 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.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/collection.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_iterator.h"
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_threads.h"
+#include "BLT_translation.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_collection.h"
+#include "BKE_icons.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+
+#include "DNA_group_types.h"
+#include "DNA_ID.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
+
+/******************************** Prototypes ********************************/
+
+static bool collection_child_add(Collection *parent, Collection *collection, int flag, const bool add_us);
+static bool collection_child_remove(Collection *parent, Collection *collection);
+static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us);
+static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us);
+
+static CollectionChild *collection_find_child(Collection *parent, Collection *collection);
+static CollectionParent *collection_find_parent(Collection *child, Collection *collection);
+
+static bool collection_find_child_recursive(Collection *parent, Collection *collection);
+
+/***************************** Add Collection *******************************/
+
+/* Add new collection, without view layer syncing. */
+static Collection *collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
+{
+ /* Determine new collection name. */
+ char name[MAX_NAME];
+
+ if (name_custom) {
+ STRNCPY(name, name_custom);
+ }
+ else {
+ BKE_collection_new_name_get(collection_parent, name);
+ }
+
+ /* Create new collection. */
+ Collection *collection = BKE_libblock_alloc(bmain, ID_GR, name, 0);
+
+ /* We increase collection user count when linking to Collections. */
+ id_us_min(&collection->id);
+
+ /* Optionally add to parent collection. */
+ if (collection_parent) {
+ collection_child_add(collection_parent, collection, 0, true);
+ }
+
+ return collection;
+}
+
+/**
+ * Add a collection to a collection ListBase and syncronize all render layers
+ * The ListBase is NULL when the collection is to be added to the master collection
+ */
+Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
+{
+ Collection *collection = collection_add(bmain, collection_parent, name_custom);
+ BKE_main_collection_sync(bmain);
+ return collection;
+}
+
+/*********************** Free and Delete Collection ****************************/
+
+/** Free (or release) any data used by this collection (does not free the collection itself). */
+void BKE_collection_free(Collection *collection)
+{
+ /* No animdata here. */
+ BKE_previewimg_free(&collection->preview);
+
+ BLI_freelistN(&collection->gobject);
+ BLI_freelistN(&collection->children);
+ BLI_freelistN(&collection->parents);
+
+ BKE_collection_object_cache_free(collection);
+}
+
+/**
+ * Remove a collection, optionally removing its child objects or moving
+ * them to parent collections.
+ */
+bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
+{
+ /* Master collection is not real datablock, can't be removed. */
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BLI_assert("!Scene master collection can't be deleted");
+ return false;
+ }
+
+ if (hierarchy) {
+ /* Remove child objects. */
+ CollectionObject *cob = collection->gobject.first;
+ while (cob != NULL) {
+ collection_object_remove(bmain, collection, cob->ob, true);
+ cob = collection->gobject.first;
+ }
+
+ /* Delete all child collections recursively. */
+ CollectionChild *child = collection->children.first;
+ while (child != NULL) {
+ BKE_collection_delete(bmain, child->collection, hierarchy);
+ child = collection->children.first;
+ }
+ }
+ else {
+ /* Link child collections into parent collection. */
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ Collection *parent = cparent->collection;
+ collection_child_add(parent, child->collection, 0, true);
+ }
+ }
+
+ CollectionObject *cob = collection->gobject.first;
+ while (cob != NULL) {
+ /* Link child object into parent collections. */
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ Collection *parent = cparent->collection;
+ collection_object_add(bmain, parent, cob->ob, 0, true);
+ }
+
+ /* Remove child object. */
+ collection_object_remove(bmain, collection, cob->ob, true);
+ cob = collection->gobject.first;
+ }
+ }
+
+ BKE_libblock_delete(bmain, collection);
+
+ BKE_main_collection_sync(bmain);
+
+ return true;
+}
+
+/***************************** Collection Copy *******************************/
+
+/**
+ * Only copy internal data of Collection ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_collection_copy_data(
+ Main *bmain, Collection *collection_dst, const Collection *collection_src, const int flag)
+{
+ /* Do not copy collection's preview (same behavior as for objects). */
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
+ BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id);
+ }
+ else {
+ collection_dst->preview = NULL;
+ }
+
+ collection_dst->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ BLI_listbase_clear(&collection_dst->object_cache);
+
+ BLI_listbase_clear(&collection_dst->gobject);
+ BLI_listbase_clear(&collection_dst->children);
+ BLI_listbase_clear(&collection_dst->parents);
+
+ for (CollectionChild *child = collection_src->children.first; child; child = child->next) {
+ collection_child_add(collection_dst, child->collection, flag, false);
+ }
+ for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) {
+ collection_object_add(bmain, collection_dst, cob->ob, flag, false);
+ }
+}
+
+/**
+ * Makes a shallow copy of a Collection
+ *
+ * Add a new collection in the same level as the old one, copy any nested collections
+ * but link the objects to the new collection (as oppose to copy them).
+ */
+Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection)
+{
+ /* It's not allowed to copy the master collection. */
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BLI_assert("!Master collection can't be copied");
+ return NULL;
+ }
+
+ Collection *collection_new;
+ BKE_id_copy_ex(bmain, &collection->id, (ID **)&collection_new, 0, false);
+
+ /* Optionally add to parent. */
+ if (parent) {
+ if (collection_child_add(parent, collection_new, 0, true)) {
+ /* Put collection right after existing one. */
+ CollectionChild *child = collection_find_child(parent, collection);
+ CollectionChild *child_new = collection_find_child(parent, collection_new);
+
+ if (child && child_new) {
+ BLI_remlink(&parent->children, child_new);
+ BLI_insertlinkafter(&parent->children, child, child_new);
+ }
+ }
+ }
+
+ BKE_main_collection_sync(bmain);
+
+ return collection_new;
+}
+
+Collection *BKE_collection_copy_master(Main *bmain, Collection *collection, const int flag)
+{
+ BLI_assert(collection->flag & COLLECTION_IS_MASTER);
+
+ Collection *collection_dst = MEM_dupallocN(collection);
+ BKE_collection_copy_data(bmain, collection_dst, collection, flag);
+ return collection_dst;
+}
+
+void BKE_collection_copy_full(Main *UNUSED(bmain), Collection *UNUSED(collection))
+{
+ // TODO: implement full scene copy
+}
+
+void BKE_collection_make_local(Main *bmain, Collection *collection, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &collection->id, true, lib_local);
+}
+
+/********************************* Naming *******************************/
+
+/**
+ * The automatic/fallback name of a new collection.
+ */
+void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
+{
+ char *name;
+
+ if (!collection_parent) {
+ name = BLI_sprintfN("Collection");
+ }
+ else if (collection_parent->flag & COLLECTION_IS_MASTER) {
+ name = BLI_sprintfN("Collection %d", BLI_listbase_count(&collection_parent->children) + 1);
+ }
+ else {
+ const int number = BLI_listbase_count(&collection_parent->children) + 1;
+ const int digits = integer_digits_i(number);
+ const int max_len =
+ sizeof(collection_parent->id.name) - 1 /* NULL terminator */ - (1 + digits) /* " %d" */ - 2 /* ID */;
+ name = BLI_sprintfN("%.*s %d", max_len, collection_parent->id.name + 2, number);
+ }
+
+ BLI_strncpy(rname, name, MAX_NAME);
+ MEM_freeN(name);
+}
+
+/* **************** Object List Cache *******************/
+
+static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict)
+{
+ int child_restrict = collection->flag | parent_restrict;
+
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BLI_findptr(lb, cob->ob, offsetof(Base, object));
+
+ if (base == NULL) {
+ base = MEM_callocN(sizeof(Base), "Object Base");
+ base->object = cob->ob;
+ BLI_addtail(lb, base);
+ }
+
+ int object_restrict = base->object->restrictflag;
+
+ if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
+ ((object_restrict & OB_RESTRICT_VIEW) == 0))
+ {
+ base->flag |= BASE_VISIBLE_VIEWPORT;
+ }
+
+ if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) &&
+ ((object_restrict & OB_RESTRICT_RENDER) == 0))
+ {
+ base->flag |= BASE_VISIBLE_RENDER;
+ }
+ }
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ collection_object_cache_fill(lb, child->collection, child_restrict);
+ }
+}
+
+ListBase BKE_collection_object_cache_get(Collection *collection)
+{
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
+ static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER;
+
+ BLI_mutex_lock(&cache_lock);
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
+ collection_object_cache_fill(&collection->object_cache, collection, 0);
+ collection->flag |= COLLECTION_HAS_OBJECT_CACHE;
+ }
+ BLI_mutex_unlock(&cache_lock);
+ }
+
+ return collection->object_cache;
+}
+
+static void collection_object_cache_free(Collection *collection)
+{
+ /* Clear own cache an for all parents, since those are affected by changes as well. */
+ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ BLI_freelistN(&collection->object_cache);
+
+ for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
+ collection_object_cache_free(parent->collection);
+ }
+}
+
+void BKE_collection_object_cache_free(Collection *collection)
+{
+ collection_object_cache_free(collection);
+}
+
+Base *BKE_collection_or_layer_objects(const Depsgraph *depsgraph,
+ const Scene *scene,
+ const ViewLayer *view_layer,
+ Collection *collection)
+{
+ // TODO: this is used by physics to get objects from a collection, but the
+ // the physics systems are not all using the depsgraph correctly which means
+ // we try different things. Instead we should explicitly get evaluated or
+ // non-evaluated data and always have the depsgraph available when needed
+
+ if (collection) {
+ return BKE_collection_object_cache_get(collection).first;
+ }
+ else if (depsgraph) {
+ view_layer = DEG_get_evaluated_view_layer(depsgraph);
+
+ if (view_layer) {
+ return FIRSTBASE(view_layer);
+ }
+ else {
+ view_layer = DEG_get_input_view_layer(depsgraph);
+ return FIRSTBASE(view_layer);
+ }
+ }
+ else if (view_layer) {
+ return FIRSTBASE(view_layer);
+ }
+ else {
+ /* depsgraph is NULL during deg build */
+ return FIRSTBASE(BKE_view_layer_context_active_PLACEHOLDER(scene));
+ }
+}
+
+/*********************** Scene Master Collection ***************/
+
+Collection *BKE_collection_master_add()
+{
+ /* Not an actual datablock, but owned by scene. */
+ Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection");
+ STRNCPY(master_collection->id.name, "GRMaster Collection");
+ master_collection->flag |= COLLECTION_IS_MASTER;
+ return master_collection;
+}
+
+Collection *BKE_collection_master(const Scene *scene)
+{
+ return scene->master_collection;
+}
+
+/*********************** Cyclic Checks ************************/
+
+static bool collection_object_cyclic_check_internal(Object *object, Collection *collection)
+{
+ if (object->dup_group) {
+ Collection *dup_collection = object->dup_group;
+ if ((dup_collection->id.tag & LIB_TAG_DOIT) == 0) {
+ /* Cycle already exists in collections, let's prevent further crappyness */
+ return true;
+ }
+ /* flag the object to identify cyclic dependencies in further dupli collections */
+ dup_collection->id.tag &= ~LIB_TAG_DOIT;
+
+ if (dup_collection == collection) {
+ return true;
+ }
+ else {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(dup_collection, collection_object)
+ {
+ if (collection_object_cyclic_check_internal(collection_object, dup_collection)) {
+ return true;
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+
+ /* un-flag the object, it's allowed to have the same collection multiple times in parallel */
+ dup_collection->id.tag |= LIB_TAG_DOIT;
+ }
+
+ return false;
+}
+
+bool BKE_collection_object_cyclic_check(Main *bmain, Object *object, Collection *collection)
+{
+ /* first flag all collections */
+ BKE_main_id_tag_listbase(&bmain->collection, LIB_TAG_DOIT, true);
+
+ return collection_object_cyclic_check_internal(object, collection);
+}
+
+/******************* Collection Object Membership *******************/
+
+bool BKE_collection_has_object(Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ return (BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)));
+}
+
+bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ const ListBase objects = BKE_collection_object_cache_get(collection);
+ return (BLI_findptr(&objects, ob, offsetof(Base, object)));
+}
+
+Collection *BKE_collection_object_find(Main *bmain, Collection *collection, Object *ob)
+{
+ if (collection)
+ collection = collection->id.next;
+ else
+ collection = bmain->collection.first;
+
+ while (collection) {
+ if (BKE_collection_has_object(collection, ob))
+ return collection;
+ collection = collection->id.next;
+ }
+ return NULL;
+}
+
+/********************** Collection Objects *********************/
+
+static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us)
+{
+ if (ob->dup_group) {
+ /* Cyclic dependency check. */
+ if (collection_find_child_recursive(collection, ob->dup_group)) {
+ return false;
+ }
+ }
+
+ CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
+ if (cob) {
+ return false;
+ }
+
+ cob = MEM_callocN(sizeof(CollectionObject), __func__);
+ cob->ob = ob;
+ BLI_addtail(&collection->gobject, cob);
+ BKE_collection_object_cache_free(collection);
+
+ if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(&ob->id);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
+ return true;
+}
+
+static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us)
+{
+ CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
+ if (cob == NULL) {
+ return false;
+ }
+
+ BLI_freelinkN(&collection->gobject, cob);
+ BKE_collection_object_cache_free(collection);
+
+ if (free_us) {
+ BKE_libblock_free_us(bmain, ob);
+ }
+ else {
+ id_us_min(&ob->id);
+ }
+
+ DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+
+ return true;
+}
+
+/**
+ * Add object to collection
+ */
+bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ if (!collection_object_add(bmain, collection, ob, 0, true)) {
+ return false;
+ }
+
+ if (BKE_collection_is_in_scene(collection)) {
+ BKE_main_collection_sync(bmain);
+ }
+
+ return true;
+}
+
+/**
+ * Add object to all scene collections that reference objects is in
+ * (used to copy objects)
+ */
+void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
+{
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
+ {
+ if (BKE_collection_has_object(collection, ob_src)) {
+ collection_object_add(bmain, collection, ob_dst, 0, true);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ BKE_main_collection_sync(bmain);
+}
+
+/**
+ * Remove object from collection.
+ */
+bool BKE_collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ if (!collection_object_remove(bmain, collection, ob, free_us)) {
+ return false;
+ }
+
+ if (BKE_collection_is_in_scene(collection)) {
+ BKE_main_collection_sync(bmain);
+ }
+
+ return true;
+}
+
+/**
+ * Remove object from all collections of scene
+ * \param scene_collection_skip: Don't remove base from this collection.
+ */
+static bool scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us,
+ Collection *collection_skip)
+{
+ bool removed = false;
+
+ BKE_scene_remove_rigidbody_object(bmain, scene, ob);
+
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
+ {
+ if (collection != collection_skip) {
+ removed |= collection_object_remove(bmain, collection, ob, free_us);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ BKE_main_collection_sync(bmain);
+
+ return removed;
+}
+
+/**
+ * Remove object from all collections of scene
+ */
+bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
+{
+ return scene_collections_object_remove(bmain, scene, ob, free_us, NULL);
+}
+
+/*
+ * Remove all NULL objects from non-scene collections.
+ * This is used for library remapping, where these pointers have been set to NULL.
+ * Otherwise this should never happen.
+ */
+void BKE_collections_object_remove_nulls(Main *bmain)
+{
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ if (!BKE_collection_is_in_scene(collection)) {
+ bool changed = false;
+
+ for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
+ cob_next = cob->next;
+
+ if (cob->ob == NULL) {
+ BLI_freelinkN(&collection->gobject, cob);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ BKE_collection_object_cache_free(collection);
+ }
+ }
+ }
+}
+
+/*
+ * Remove all NULL children from parent objects of changed old_collection.
+ * This is used for library remapping, where these pointers have been set to NULL.
+ * Otherwise this should never happen.
+ */
+void BKE_collections_child_remove_nulls(Main *bmain, Collection *old_collection)
+{
+ bool changed = false;
+
+ for (CollectionChild *child = old_collection->children.first; child; child = child->next) {
+ CollectionParent *cparent = collection_find_parent(child->collection, old_collection);
+ if (cparent) {
+ BLI_freelinkN(&child->collection->parents, cparent);
+ }
+ }
+
+ for (CollectionParent *cparent = old_collection->parents.first; cparent; cparent = cparent->next) {
+ Collection *parent = cparent->collection;
+
+ for (CollectionChild *child = parent->children.first, *child_next = NULL; child; child = child_next) {
+ child_next = child->next;
+
+ if (child->collection == NULL) {
+ BLI_freelinkN(&parent->children, child);
+ changed = true;
+ }
+ }
+ }
+
+ BLI_freelistN(&old_collection->parents);
+
+ if (changed) {
+ BKE_main_collection_sync(bmain);
+ }
+}
+
+/**
+ * Move object from a collection into another
+ *
+ * If source collection is NULL move it from all the existing collections.
+ */
+void BKE_collection_object_move(
+ Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
+{
+ /* In both cases we first add the object, then remove it from the other collections.
+ * Otherwise we lose the original base and whether it was active and selected. */
+ if (collection_src != NULL) {
+ if (BKE_collection_object_add(bmain, collection_dst, ob)) {
+ BKE_collection_object_remove(bmain, collection_src, ob, false);
+ }
+ }
+ else {
+ /* Adding will fail if object is already in collection.
+ * However we still need to remove it from the other collections. */
+ BKE_collection_object_add(bmain, collection_dst, ob);
+ scene_collections_object_remove(bmain, scene, ob, false, collection_dst);
+ }
+}
+
+/***************** Collection Scene Membership ****************/
+
+bool BKE_collection_is_in_scene(Collection *collection)
+{
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return true;
+ }
+
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ if (BKE_collection_is_in_scene(cparent->collection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void BKE_collections_after_lib_link(Main *bmain)
+{
+ /* Update view layer collections to match any changes in linked
+ * collections after file load. */
+ BKE_main_collection_sync(bmain);
+}
+
+/********************** Collection Children *******************/
+
+bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection)
+{
+ if (collection == new_ancestor) {
+ return true;
+ }
+
+ for (CollectionParent *parent = new_ancestor->parents.first; parent; parent = parent->next) {
+ if (BKE_collection_find_cycle(parent->collection, collection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static CollectionChild *collection_find_child(Collection *parent, Collection *collection)
+{
+ return BLI_findptr(&parent->children, collection, offsetof(CollectionChild, collection));
+}
+
+static bool collection_find_child_recursive(Collection *parent, Collection *collection)
+{
+ for (CollectionChild *child = parent->children.first; child; child = child->next) {
+ if (child->collection == collection) {
+ return true;
+ }
+
+ if (collection_find_child_recursive(child->collection, collection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static CollectionParent *collection_find_parent(Collection *child, Collection *collection)
+{
+ return BLI_findptr(&child->parents, collection, offsetof(CollectionParent, collection));
+}
+
+static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us)
+{
+ CollectionChild *child = collection_find_child(parent, collection);
+ if (child) {
+ return false;
+ }
+ if (BKE_collection_find_cycle(parent, collection)) {
+ return false;
+ }
+
+ child = MEM_callocN(sizeof(CollectionChild), "CollectionChild");
+ child->collection = collection;
+ BLI_addtail(&parent->children, child);
+
+ /* Don't add parent links for depsgraph datablocks, these are not kept in sync. */
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), "CollectionParent");
+ cparent->collection = parent;
+ BLI_addtail(&collection->parents, cparent);
+ }
+
+ if (add_us) {
+ id_us_plus(&collection->id);
+ }
+
+ BKE_collection_object_cache_free(parent);
+
+ return true;
+}
+
+static bool collection_child_remove(Collection *parent, Collection *collection)
+{
+ CollectionChild *child = collection_find_child(parent, collection);
+ if (child == NULL) {
+ return false;
+ }
+
+ CollectionParent *cparent = collection_find_parent(collection, parent);
+ BLI_freelinkN(&collection->parents, cparent);
+ BLI_freelinkN(&parent->children, child);
+
+ id_us_min(&collection->id);
+
+ BKE_collection_object_cache_free(parent);
+
+ return true;
+}
+
+bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child)
+{
+ if (!collection_child_add(parent, child, 0, true)) {
+ return false;
+ }
+
+ BKE_main_collection_sync(bmain);
+ return true;
+}
+
+bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
+{
+ if (!collection_child_remove(parent, child)) {
+ return false;
+ }
+
+ BKE_main_collection_sync(bmain);
+ return true;
+}
+
+/********************** Collection index *********************/
+
+static Collection *collection_from_index_recursive(Collection *collection, const int index, int *index_current)
+{
+ if (index == (*index_current)) {
+ return collection;
+ }
+
+ (*index_current)++;
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ Collection *nested = collection_from_index_recursive(child->collection, index, index_current);
+ if (nested != NULL) {
+ return nested;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Return Scene Collection for a given index.
+ *
+ * The index is calculated from top to bottom counting the children before the siblings.
+ */
+Collection *BKE_collection_from_index(Scene *scene, const int index)
+{
+ int index_current = 0;
+ Collection *master_collection = BKE_collection_master(scene);
+ return collection_from_index_recursive(master_collection, index, &index_current);
+}
+
+static bool collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
+{
+ bool changed = false;
+
+ if (collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
+
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+
+ if (base) {
+ if (deselect) {
+ if (base->flag & BASE_SELECTED) {
+ base->flag &= ~BASE_SELECTED;
+ changed = true;
+ }
+ }
+ else {
+ if ((base->flag & BASE_SELECTABLED) && !(base->flag & BASE_SELECTED)) {
+ base->flag |= BASE_SELECTED;
+ changed = true;
+ }
+ }
+ }
+ }
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ if (collection_objects_select(view_layer, collection, deselect)) {
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+/**
+ * Select all the objects in this Collection (and its nested collections) for this ViewLayer.
+ * Return true if any object was selected.
+ */
+bool BKE_collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
+{
+ LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer, collection);
+
+ if (layer_collection != NULL) {
+ return BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
+ }
+ else {
+ return collection_objects_select(view_layer, collection, deselect);
+ }
+}
+
+/***************** Collection move (outliner drag & drop) *********************/
+
+bool BKE_collection_move(Main *bmain,
+ Collection *to_parent,
+ Collection *from_parent,
+ Collection *relative,
+ bool relative_after,
+ Collection *collection)
+{
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return false;
+ }
+ if (BKE_collection_find_cycle(to_parent, collection)) {
+ return false;
+ }
+
+ /* Move to new parent collection */
+ if (from_parent) {
+ collection_child_remove(from_parent, collection);
+ }
+
+ collection_child_add(to_parent, collection, 0, true);
+
+ /* Move to specified location under parent. */
+ if (relative) {
+ CollectionChild *child = collection_find_child(to_parent, collection);
+ CollectionChild *relative_child = collection_find_child(to_parent, relative);
+
+ if (relative_child) {
+ BLI_remlink(&to_parent->children, child);
+
+ if (relative_after) {
+ BLI_insertlinkafter(&to_parent->children, relative_child, child);
+ }
+ else {
+ BLI_insertlinkbefore(&to_parent->children, relative_child, child);
+ }
+
+ BKE_collection_object_cache_free(to_parent);
+ }
+ }
+
+ BKE_main_collection_sync(bmain);
+
+ return true;
+}
+
+/**************************** Iterators ******************************/
+
+/* scene collection iteractor */
+
+typedef struct CollectionsIteratorData {
+ Scene *scene;
+ void **array;
+ int tot, cur;
+} CollectionsIteratorData;
+
+static void scene_collection_callback(Collection *collection, BKE_scene_collections_Cb callback, void *data)
+{
+ callback(collection, data);
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ scene_collection_callback(child->collection, callback, data);
+ }
+}
+
+static void scene_collections_count(Collection *UNUSED(collection), void *data)
+{
+ int *tot = data;
+ (*tot)++;
+}
+
+static void scene_collections_build_array(Collection *collection, void *data)
+{
+ Collection ***array = data;
+ **array = collection;
+ (*array)++;
+}
+
+static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot)
+{
+ Collection *collection;
+ Collection **array;
+
+ *collections_array = NULL;
+ *tot = 0;
+
+ if (scene == NULL) {
+ return;
+ }
+
+ collection = BKE_collection_master(scene);
+ BLI_assert(collection != NULL);
+ scene_collection_callback(collection, scene_collections_count, tot);
+
+ if (*tot == 0)
+ return;
+
+ *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray");
+ scene_collection_callback(collection, scene_collections_build_array, &array);
+}
+
+/**
+ * Only use this in non-performance critical situations
+ * (it iterates over all scene collections twice)
+ */
+void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ Scene *scene = data_in;
+ CollectionsIteratorData *data = MEM_callocN(sizeof(CollectionsIteratorData), __func__);
+
+ data->scene = scene;
+ iter->data = data;
+ iter->valid = true;
+
+ scene_collections_array(scene, (Collection ***)&data->array, &data->tot);
+ BLI_assert(data->tot != 0);
+
+ data->cur = 0;
+ iter->current = data->array[data->cur];
+}
+
+void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter)
+{
+ CollectionsIteratorData *data = iter->data;
+
+ if (++data->cur < data->tot) {
+ iter->current = data->array[data->cur];
+ }
+ else {
+ iter->valid = false;
+ }
+}
+
+void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter)
+{
+ CollectionsIteratorData *data = iter->data;
+
+ if (data) {
+ if (data->array) {
+ MEM_freeN(data->array);
+ }
+ MEM_freeN(data);
+ }
+ iter->valid = false;
+}
+
+
+/* scene objects iteractor */
+
+typedef struct SceneObjectsIteratorData {
+ GSet *visited;
+ CollectionObject *cob_next;
+ BLI_Iterator scene_collection_iter;
+} SceneObjectsIteratorData;
+
+void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ Scene *scene = data_in;
+ SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __func__);
+ iter->data = data;
+
+ /* lookup list ot make sure each object is object called once */
+ data->visited = BLI_gset_ptr_new(__func__);
+
+ /* we wrap the scenecollection iterator here to go over the scene collections */
+ BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene);
+
+ Collection *collection = data->scene_collection_iter.current;
+ if (collection->gobject.first != NULL) {
+ iter->current = ((CollectionObject *)collection->gobject.first)->ob;
+ }
+ else {
+ BKE_scene_objects_iterator_next(iter);
+ }
+}
+
+/**
+ * Gets the first unique object in the sequence
+ */
+static CollectionObject *object_base_unique(GSet *gs, CollectionObject *cob)
+{
+ for (; cob != NULL; cob = cob->next) {
+ Object *ob = cob->ob;
+ void **ob_key_p;
+ if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) {
+ *ob_key_p = ob;
+ return cob;
+ }
+ }
+ return NULL;
+}
+
+void BKE_scene_objects_iterator_next(BLI_Iterator *iter)
+{
+ SceneObjectsIteratorData *data = iter->data;
+ CollectionObject *cob = data->cob_next ? object_base_unique(data->visited, data->cob_next) : NULL;
+
+ if (cob) {
+ data->cob_next = cob->next;
+ iter->current = cob->ob;
+ }
+ else {
+ /* if this is the last object of this ListBase look at the next Collection */
+ Collection *collection;
+ BKE_scene_collections_iterator_next(&data->scene_collection_iter);
+ do {
+ collection = data->scene_collection_iter.current;
+ /* get the first unique object of this collection */
+ CollectionObject *new_cob = object_base_unique(data->visited, collection->gobject.first);
+ if (new_cob) {
+ data->cob_next = new_cob->next;
+ iter->current = new_cob->ob;
+ return;
+ }
+ BKE_scene_collections_iterator_next(&data->scene_collection_iter);
+ } while (data->scene_collection_iter.valid);
+
+ if (!data->scene_collection_iter.valid) {
+ iter->valid = false;
+ }
+ }
+}
+
+void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
+{
+ SceneObjectsIteratorData *data = iter->data;
+ if (data) {
+ BKE_scene_collections_iterator_end(&data->scene_collection_iter);
+ BLI_gset_free(data->visited, NULL);
+ MEM_freeN(data);
+ }
+}
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index b38d6b8bceb..b41c4633ccb 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -46,7 +46,9 @@
#include "BLI_edgehash.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
#include "BKE_effect.h"
+#include "BKE_layer.h"
#include "BKE_modifier.h"
#include "BKE_scene.h"
@@ -501,40 +503,44 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned
/* objects in dupli groups, one level only for now */
if (ob->dup_group && level == 0) {
- GroupObject *go;
- Group *group= ob->dup_group;
+ Collection *collection= ob->dup_group;
/* add objects */
- for (go= group->gobject.first; go; go= go->next)
- add_collision_object(objs, numobj, maxobj, go->ob, self, level+1, modifier_type);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
+ {
+ add_collision_object(objs, numobj, maxobj, object, self, level+1, modifier_type);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
}
// return all collision objects in scene
// collision object will exclude self
-Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
+Object **get_collisionobjects_ext(Scene *scene, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
{
- Base *base;
Object **objs;
- GroupObject *go;
unsigned int numobj= 0, maxobj= 100;
int level = dupli ? 0 : 1;
objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray");
/* gather all collision objects */
- if (group) {
- /* use specified group */
- for (go= group->gobject.first; go; go= go->next)
- add_collision_object(&objs, &numobj, &maxobj, go->ob, self, level, modifier_type);
+ if (collection) {
+ /* use specified collection */
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
+ {
+ add_collision_object(&objs, &numobj, &maxobj, object, self, level, modifier_type);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
else {
Scene *sce_iter;
+ Base *base;
/* add objects in same layer in scene */
for (SETLOOPER(scene, sce_iter, base)) {
- if ( base->lay & layer )
+ if ((base->flag & BASE_VISIBLED) != 0) {
add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type);
-
+ }
}
}
@@ -543,11 +549,11 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int
return objs;
}
-Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type)
+Object **get_collisionobjects(Scene *scene, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type)
{
/* Need to check for active layers, too.
Otherwise this check fails if the objects are not on the same layer - DG */
- return get_collisionobjects_ext(scene, self, group, self->lay | scene->lay, numcollobj, modifier_type, true);
+ return get_collisionobjects_ext(scene, self, collection, numcollobj, modifier_type, true);
}
static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, int level)
@@ -573,26 +579,30 @@ static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self,
BLI_addtail(*objs, col);
}
- /* objects in dupli groups, one level only for now */
+ /* objects in dupli collection, one level only for now */
if (ob->dup_group && level == 0) {
- GroupObject *go;
- Group *group= ob->dup_group;
+ Collection *collection= ob->dup_group;
/* add objects */
- for (go= group->gobject.first; go; go= go->next)
- add_collider_cache_object(objs, go->ob, self, level+1);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
+ {
+ add_collider_cache_object(objs, object, self, level+1);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
}
-ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
+ListBase *get_collider_cache(Scene *scene, Object *self, Collection *collection)
{
- GroupObject *go;
ListBase *objs= NULL;
/* add object in same layer in scene */
- if (group) {
- for (go= group->gobject.first; go; go= go->next)
- add_collider_cache_object(&objs, go->ob, self, 0);
+ if (collection) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
+ {
+ add_collider_cache_object(&objs, object, self, 0);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
else {
Scene *sce_iter;
@@ -600,7 +610,7 @@ ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
/* add objects in same layer in scene */
for (SETLOOPER(scene, sce_iter, base)) {
- if (!self || (base->lay & self->lay))
+ if (!self || ((base->flag & BASE_VISIBLED) != 0))
add_collider_cache_object(&objs, base->object, self, 0);
}
@@ -676,7 +686,7 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
}
// cloth - object collisions
-int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt )
+int cloth_bvh_objcollision(Scene *scene, Object *ob, ClothModifierData *clmd, float step, float dt )
{
Cloth *cloth= clmd->clothObject;
BVHTree *cloth_bvh= cloth->bvhtree;
@@ -702,7 +712,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
bvhtree_update_from_cloth ( clmd, 1 ); // 0 means STATIC, 1 means MOVING (see later in this function)
bvhselftree_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function)
- collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ collobjs = get_collisionobjects(scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
if (!collobjs)
return 0;
@@ -1197,7 +1207,7 @@ static int cloth_points_objcollisions_resolve(
}
// cloth - object collisions
-int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt)
+int cloth_points_objcollision(Scene *scene, Object *ob, ClothModifierData *clmd, float step, float dt)
{
Cloth *cloth= clmd->clothObject;
BVHTree *cloth_bvh;
@@ -1230,7 +1240,7 @@ int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, f
/* balance tree */
BLI_bvhtree_balance(cloth_bvh);
- collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ collobjs = get_collisionobjects(scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
if (!collobjs)
return 0;
@@ -1319,7 +1329,7 @@ int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, f
return 1|MIN2 ( ret, 1 );
}
-void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, float dt,
+void cloth_find_point_contacts(Scene *scene, Object *ob, ClothModifierData *clmd, float step, float dt,
ColliderContacts **r_collider_contacts, int *r_totcolliders)
{
Cloth *cloth= clmd->clothObject;
@@ -1353,7 +1363,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
/* balance tree */
BLI_bvhtree_balance(cloth_bvh);
- collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ collobjs = get_collisionobjects(scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
if (!collobjs) {
*r_collider_contacts = NULL;
*r_totcolliders = 0;
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 2a5a0cf9ae7..ac47a9e0756 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -84,6 +84,9 @@
#include "BIK_api.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#ifdef WITH_PYTHON
# include "BPY_extern.h"
#endif
@@ -98,11 +101,6 @@
/* Constraint Target Macros */
#define VALID_CONS_TARGET(ct) ((ct) && (ct->tar))
-/* Workaround for cyclic depenndnecy with curves.
- * In such case curve_cache might not be ready yet,
- */
-#define CYCLIC_DEPENDENCY_WORKAROUND
-
/* ************************ Constraints - General Utilities *************************** */
/* These functions here don't act on any specific constraints, and are therefore should/will
* not require any of the special function-pointers afforded by the relevant constraint
@@ -121,7 +119,7 @@ void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
/* package an object/bone for use in constraint evaluation */
/* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */
-bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subdata, short datatype)
+bConstraintOb *BKE_constraints_make_evalob(Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
{
bConstraintOb *cob;
@@ -130,6 +128,7 @@ bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subda
/* for system time, part of deglobalization, code nicer later with local time (ton) */
cob->scene = scene;
+ cob->depsgraph = depsgraph;
/* based on type of available data */
switch (datatype) {
@@ -689,7 +688,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
/* This function should be used for the get_target_matrix member of all
* constraints that are not picky about what happens to their target matrix.
*/
-static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
+static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct))
constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
@@ -1158,7 +1157,7 @@ static void kinematic_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
{
bKinematicConstraint *data = con->data;
@@ -1245,7 +1244,9 @@ static void followpath_flush_tars(bConstraint *con, ListBase *list, bool no_copy
}
}
-static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con, bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
bFollowPathConstraint *data = con->data;
@@ -1260,13 +1261,7 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
* currently for paths to work it needs to go through the bevlist/displist system (ton)
*/
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
-#endif
-
- if (ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) {
+ if (ct->tar->curve_cache && ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) {
float quat[4];
if ((data->followflag & FOLLOWPATH_STATIC) == 0) {
/* animated position along curve depending on time */
@@ -2028,21 +2023,19 @@ static void pycon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userd
}
/* Whether this approach is maintained remains to be seen (aligorith) */
-static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con, bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
#ifdef WITH_PYTHON
bPythonConstraint *data = con->data;
#endif
if (VALID_CONS_TARGET(ct)) {
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- /* special exception for curves - depsgraph issues */
- if (ct->tar->type == OB_CURVE) {
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
+ if (ct->tar->type == OB_CURVE && ct->tar->curve_cache == NULL) {
+ unit_m4(ct->matrix);
+ return;
}
-#endif
/* firstly calculate the matrix the normal way, then let the py-function override
* this matrix if it needs to do so
@@ -2146,7 +2139,7 @@ static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
{
bActionConstraint *data = con->data;
@@ -3039,66 +3032,6 @@ static bConstraintTypeInfo CTI_MINMAX = {
minmax_evaluate /* evaluate */
};
-/* ------- RigidBody Joint ---------- */
-
-static void rbj_new_data(void *cdata)
-{
- bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)cdata;
-
- /* removed code which set target of this constraint */
- data->type = 1;
-}
-
-static void rbj_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
-{
- bRigidBodyJointConstraint *data = con->data;
-
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
- func(con, (ID **)&data->child, false, userdata);
-}
-
-static int rbj_get_tars(bConstraint *con, ListBase *list)
-{
- if (con && list) {
- bRigidBodyJointConstraint *data = con->data;
- bConstraintTarget *ct;
-
- /* standard target-getting macro for single-target constraints without subtargets */
- SINGLETARGETNS_GET_TARS(con, data->tar, ct, list);
-
- return 1;
- }
-
- return 0;
-}
-
-static void rbj_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
-{
- if (con && list) {
- bRigidBodyJointConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
-
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy);
- }
-}
-
-static bConstraintTypeInfo CTI_RIGIDBODYJOINT = {
- CONSTRAINT_TYPE_RIGIDBODYJOINT, /* type */
- sizeof(bRigidBodyJointConstraint), /* size */
- "Rigid Body Joint", /* name */
- "bRigidBodyJointConstraint", /* struct name */
- NULL, /* free data */
- rbj_id_looper, /* id looper */
- NULL, /* copy data */
- rbj_new_data, /* new data */
- rbj_get_tars, /* get constraint targets */
- rbj_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- NULL /* evaluate - this is not solved here... is just an interface for game-engine */
-};
-
/* -------- Clamp To ---------- */
static void clampto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -3135,16 +3068,10 @@ static void clampto_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void clampto_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void clampto_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (VALID_CONS_TARGET(ct)) {
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
- }
-#endif
-
/* technically, this isn't really needed for evaluation, but we don't know what else
* might end up calling this...
*/
@@ -3478,7 +3405,7 @@ static void shrinkwrap_flush_tars(bConstraint *con, ListBase *list, bool no_copy
}
-static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
{
bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data;
@@ -3809,16 +3736,10 @@ static void splineik_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void splineik_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void splineik_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (VALID_CONS_TARGET(ct)) {
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
- }
-#endif
-
/* technically, this isn't really needed for evaluation, but we don't know what else
* might end up calling this...
*/
@@ -3986,20 +3907,25 @@ static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void
static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
+ Depsgraph *depsgraph = cob->depsgraph;
Scene *scene = cob->scene;
bFollowTrackConstraint *data = con->data;
MovieClip *clip = data->clip;
MovieTracking *tracking;
MovieTrackingTrack *track;
MovieTrackingObject *tracking_object;
- Object *camob = data->camera ? data->camera : scene->camera;
- float ctime = BKE_scene_frame_get(scene);
+
+ Object *camob_eval = DEG_get_evaluated_object(
+ depsgraph,
+ data->camera ? data->camera : scene->camera);
+
+ float ctime = DEG_get_ctime(depsgraph);;
float framenr;
if (data->flag & FOLLOWTRACK_ACTIVECLIP)
clip = scene->clip;
- if (!clip || !data->track[0] || !camob)
+ if (!clip || !data->track[0] || !camob_eval)
return;
tracking = &clip->tracking;
@@ -4028,7 +3954,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
float imat[4][4];
- copy_m4_m4(mat, camob->obmat);
+ copy_m4_m4(mat, camob_eval->obmat);
BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, imat);
invert_m4(imat);
@@ -4037,7 +3963,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
}
else {
- BKE_tracking_get_camera_object_matrix(cob->scene, camob, mat);
+ BKE_tracking_get_camera_object_matrix(depsgraph, cob->scene, camob_eval, mat);
mul_m4_m4m4(cob->matrix, obmat, mat);
translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
@@ -4049,7 +3975,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
float len, d;
- BKE_object_where_is_calc_mat4(scene, camob, mat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, camob_eval, mat);
/* camera axis */
vec[0] = 0.0f;
@@ -4117,7 +4043,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
}
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, camob);
+ BKE_camera_params_from_object(&params, camob_eval);
if (params.is_ortho) {
vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx);
@@ -4129,9 +4055,9 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
else
vec[0] *= aspect;
- mul_v3_m4v3(disp, camob->obmat, vec);
+ mul_v3_m4v3(disp, camob_eval->obmat, vec);
- copy_m4_m4(rmat, camob->obmat);
+ copy_m4_m4(rmat, camob_eval->obmat);
zero_v3(rmat[3]);
mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
@@ -4149,10 +4075,10 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
else
vec[0] *= aspect;
- mul_v3_m4v3(disp, camob->obmat, vec);
+ mul_v3_m4v3(disp, camob_eval->obmat, vec);
/* apply camera rotation so Z-axis would be co-linear */
- copy_m4_m4(rmat, camob->obmat);
+ copy_m4_m4(rmat, camob_eval->obmat);
zero_v3(rmat[3]);
mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
@@ -4171,7 +4097,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
invert_m4_m4(imat, depth_ob->obmat);
- mul_v3_m4v3(ray_start, imat, camob->obmat[3]);
+ mul_v3_m4v3(ray_start, imat, camob_eval->obmat[3]);
mul_v3_m4v3(ray_end, imat, cob->matrix[3]);
sub_v3_v3v3(ray_nor, ray_end, ray_start);
@@ -4230,6 +4156,7 @@ static void camerasolver_id_looper(bConstraint *con, ConstraintIDFunc func, void
static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
+ Depsgraph *depsgraph = cob->depsgraph;
Scene *scene = cob->scene;
bCameraSolverConstraint *data = con->data;
MovieClip *clip = data->clip;
@@ -4241,7 +4168,7 @@ static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
float mat[4][4], obmat[4][4];
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object = BKE_tracking_object_get_camera(tracking);
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = DEG_get_ctime(depsgraph);
float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
@@ -4288,6 +4215,7 @@ static void objectsolver_id_looper(bConstraint *con, ConstraintIDFunc func, void
static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
+ Depsgraph *depsgraph = cob->depsgraph;
Scene *scene = cob->scene;
bObjectSolverConstraint *data = con->data;
MovieClip *clip = data->clip;
@@ -4307,10 +4235,10 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
if (object) {
float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4];
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = DEG_get_ctime(depsgraph);
float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
- BKE_object_where_is_calc_mat4(scene, camob, cammat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, camob, cammat);
BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
@@ -4362,7 +4290,7 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
return;
}
- const float frame = BKE_scene_frame_get(scene);
+ const float frame = DEG_get_ctime(cob->depsgraph);
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
BKE_cachefile_ensure_handle(G.main, cache_file);
@@ -4460,7 +4388,7 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[14] = &CTI_DISTLIMIT; /* Limit Distance Constraint */
constraintsTypeInfo[15] = &CTI_STRETCHTO; /* StretchTo Constaint */
constraintsTypeInfo[16] = &CTI_MINMAX; /* Floor Constraint */
- constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */
+ /* constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; */ /* RigidBody Constraint - Deprecated */
constraintsTypeInfo[18] = &CTI_CLAMPTO; /* ClampTo Constraint */
constraintsTypeInfo[19] = &CTI_TRANSFORM; /* Transformation Constraint */
constraintsTypeInfo[20] = &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */
@@ -4612,7 +4540,7 @@ static bConstraint *add_new_constraint_internal(const char *name, short type)
/* Set up a generic constraint datablock */
con->type = type;
- con->flag |= CONSTRAINT_EXPAND;
+ con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_STATICOVERRIDE_LOCAL;
con->enforce = 1.0f;
/* Determine a basic name, and info */
@@ -4739,6 +4667,43 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool i
id_us_plus(*idpoin);
}
+/** Copies a single constraint's data (\a dst must already be a shallow copy of \a src). */
+static void constraint_copy_data_ex(bConstraint *dst, bConstraint *src, const int flag, const bool do_extern)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(src);
+
+ /* make a new copy of the constraint's data */
+ dst->data = MEM_dupallocN(dst->data);
+
+ /* only do specific constraints if required */
+ if (cti) {
+ /* perform custom copying operations if needed */
+ if (cti->copy_data)
+ cti->copy_data(dst, src);
+
+ /* Fix usercounts for all referenced data that need it. */
+ if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ cti->id_looper(dst, con_fix_copied_refs_cb, NULL);
+ }
+
+ /* for proxies we don't want to make extern */
+ if (do_extern) {
+ /* go over used ID-links for this constraint to ensure that they are valid for proxies */
+ if (cti->id_looper)
+ cti->id_looper(dst, con_extern_cb, NULL);
+ }
+ }
+}
+
+/** Allocate and duplicate a single constraint, ouside of any object/pose context. */
+bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern)
+{
+ bConstraint *dst = MEM_dupallocN(src);
+ constraint_copy_data_ex(dst, src, flag, do_extern);
+ dst->next = dst->prev = NULL;
+ return dst;
+}
+
/* duplicate all of the constraints in a constraint stack */
void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
{
@@ -4748,29 +4713,7 @@ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag,
BLI_duplicatelist(dst, src);
for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- /* make a new copy of the constraint's data */
- con->data = MEM_dupallocN(con->data);
-
- /* only do specific constraints if required */
- if (cti) {
- /* perform custom copying operations if needed */
- if (cti->copy_data)
- cti->copy_data(con, srccon);
-
- /* Fix usercounts for all referenced data that need it. */
- if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- cti->id_looper(con, con_fix_copied_refs_cb, NULL);
- }
-
- /* for proxies we don't want to make extern */
- if (do_extern) {
- /* go over used ID-links for this constraint to ensure that they are valid for proxies */
- if (cti->id_looper)
- cti->id_looper(con, con_extern_cb, NULL);
- }
- }
+ constraint_copy_data_ex(con, srccon, flag, do_extern);
}
}
@@ -4867,7 +4810,7 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
* None of the actual calculations of the matrices should be done here! Also, this function is
* not to be used by any new constraints, particularly any that have multiple targets.
*/
-void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime)
+void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime)
{
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
@@ -4879,6 +4822,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
cob = MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb");
cob->type = ownertype;
cob->scene = scene;
+ cob->depsgraph = depsgraph;
switch (ownertype) {
case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */
{
@@ -4918,7 +4862,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
if (ct) {
if (cti->get_target_matrix)
- cti->get_target_matrix(con, cob, ct, ctime);
+ cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
copy_m4_m4(mat, ct->matrix);
}
@@ -4934,7 +4878,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
}
/* Get the list of targets required for solving a constraint */
-void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
+void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
{
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
@@ -4952,7 +4896,7 @@ void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob
*/
if (cti->get_target_matrix) {
for (ct = targets->first; ct; ct = ct->next)
- cti->get_target_matrix(con, cob, ct, ctime);
+ cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
}
else {
for (ct = targets->first; ct; ct = ct->next)
@@ -4969,7 +4913,7 @@ void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob
* BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and
* after running this function, to sort out cob
*/
-void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime)
+void BKE_constraints_solve(struct Depsgraph *depsgraph, ListBase *conlist, bConstraintOb *cob, float ctime)
{
bConstraint *con;
float oldmat[4][4];
@@ -5004,7 +4948,7 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime)
BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
/* prepare targets for constraint solving */
- BKE_constraint_targets_for_solving_get(con, cob, &targets, ctime);
+ BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime);
/* Solve the constraint and put result in cob->matrix */
cti->evaluate_constraint(con, cob, &targets);
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 966abad3739..ee907fa496f 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -38,6 +39,9 @@
#include "DNA_object_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_workspace_types.h"
+
+#include "DEG_depsgraph.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -47,9 +51,14 @@
#include "BLT_translation.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
+#include "BKE_workspace.h"
+
+#include "RE_engine.h"
#include "RNA_access.h"
@@ -66,10 +75,12 @@ struct bContext {
struct {
struct wmWindowManager *manager;
struct wmWindow *window;
+ struct WorkSpace *workspace;
struct bScreen *screen;
struct ScrArea *area;
struct ARegion *region;
struct ARegion *menu;
+ struct wmManipulatorGroup *manipulator_group;
struct bContextStore *store;
const char *operator_poll_msg; /* reason for poll failing */
} wm;
@@ -627,6 +638,11 @@ wmWindow *CTX_wm_window(const bContext *C)
return ctx_wm_python_context_get(C, "window", &RNA_Window, C->wm.window);
}
+WorkSpace *CTX_wm_workspace(const bContext *C)
+{
+ return ctx_wm_python_context_get(C, "workspace", &RNA_WorkSpace, C->wm.workspace);
+}
+
bScreen *CTX_wm_screen(const bContext *C)
{
return ctx_wm_python_context_get(C, "screen", &RNA_Screen, C->wm.screen);
@@ -659,6 +675,16 @@ struct ARegion *CTX_wm_menu(const bContext *C)
return C->wm.menu;
}
+struct wmManipulatorGroup *CTX_wm_manipulator_group(const bContext *C)
+{
+ return C->wm.manipulator_group;
+}
+
+struct wmMsgBus *CTX_wm_message_bus(const bContext *C)
+{
+ return C->wm.manager ? C->wm.manager->message_bus : NULL;
+}
+
struct ReportList *CTX_wm_reports(const bContext *C)
{
if (C->wm.manager)
@@ -750,14 +776,6 @@ struct SpaceNla *CTX_wm_space_nla(const bContext *C)
return NULL;
}
-struct SpaceTime *CTX_wm_space_time(const bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_TIME)
- return sa->spacedata.first;
- return NULL;
-}
-
struct SpaceNode *CTX_wm_space_node(const bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
@@ -766,14 +784,6 @@ struct SpaceNode *CTX_wm_space_node(const bContext *C)
return NULL;
}
-struct SpaceLogic *CTX_wm_space_logic(const bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_LOGIC)
- return sa->spacedata.first;
- return NULL;
-}
-
struct SpaceIpo *CTX_wm_space_graph(const bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
@@ -814,6 +824,14 @@ struct SpaceClip *CTX_wm_space_clip(const bContext *C)
return NULL;
}
+struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_TOPBAR)
+ return sa->spacedata.first;
+ return NULL;
+}
+
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
C->wm.manager = wm;
@@ -826,9 +844,11 @@ void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
void CTX_wm_window_set(bContext *C, wmWindow *win)
{
C->wm.window = win;
- C->wm.screen = (win) ? win->screen : NULL;
- if (C->wm.screen)
- C->data.scene = C->wm.screen->scene;
+ if (win) {
+ C->data.scene = win->scene;
+ }
+ C->wm.workspace = (win) ? BKE_workspace_active_get(win->workspace_hook) : NULL;
+ C->wm.screen = (win) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL;
C->wm.area = NULL;
C->wm.region = NULL;
}
@@ -836,8 +856,6 @@ void CTX_wm_window_set(bContext *C, wmWindow *win)
void CTX_wm_screen_set(bContext *C, bScreen *screen)
{
C->wm.screen = screen;
- if (C->wm.screen)
- C->data.scene = C->wm.screen->scene;
C->wm.area = NULL;
C->wm.region = NULL;
}
@@ -858,6 +876,11 @@ void CTX_wm_menu_set(bContext *C, ARegion *menu)
C->wm.menu = menu;
}
+void CTX_wm_manipulator_group_set(bContext *C, struct wmManipulatorGroup *mgroup)
+{
+ C->wm.manipulator_group = mgroup;
+}
+
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
{
C->wm.operator_poll_msg = msg;
@@ -896,10 +919,66 @@ Scene *CTX_data_scene(const bContext *C)
return C->data.scene;
}
-int CTX_data_mode_enum(const bContext *C)
+ViewLayer *CTX_data_view_layer(const bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer;
+ if (ctx_data_pointer_verify(C, "view_layer", (void *)&view_layer)) {
+ return view_layer;
+ }
+ else {
+ return BKE_view_layer_from_workspace_get(CTX_data_scene(C), CTX_wm_workspace(C));
+ }
+}
+
+RenderEngineType *CTX_data_engine_type(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ return RE_engines_find(scene->r.engine);
+}
+
+/**
+ * This is tricky. Sometimes the user overrides the render_layer
+ * but not the scene_collection. In this case what to do?
+ *
+ * If the scene_collection is linked to the ViewLayer we use it.
+ * Otherwise we fallback to the active one of the ViewLayer.
+ */
+LayerCollection *CTX_data_layer_collection(const bContext *C)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *layer_collection;
+
+ if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) {
+ if (BKE_view_layer_has_collection(view_layer, layer_collection->collection)) {
+ return layer_collection;
+ }
+ }
+
+ /* fallback */
+ return BKE_layer_collection_get_active(view_layer);
+}
+
+Collection *CTX_data_collection(const bContext *C)
+{
+ Collection *collection;
+ if (ctx_data_pointer_verify(C, "collection", (void *)&collection)) {
+ return collection;
+ }
+
+ LayerCollection *layer_collection = CTX_data_layer_collection(C);
+ if (layer_collection) {
+ return layer_collection->collection;
+ }
+
+ /* fallback */
+ Scene *scene = CTX_data_scene(C);
+ return BKE_collection_master(scene);
+}
+
+int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectMode object_mode)
+{
+ // Object *obedit = CTX_data_edit_object(C);
if (obedit) {
switch (obedit->type) {
case OB_MESH:
@@ -919,21 +998,26 @@ int CTX_data_mode_enum(const bContext *C)
}
}
else {
- Object *ob = CTX_data_active_object(C);
-
+ // Object *ob = CTX_data_active_object(C);
if (ob) {
- if (ob->mode & OB_MODE_POSE) return CTX_MODE_POSE;
- else if (ob->mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT;
- else if (ob->mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT;
- else if (ob->mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
- else if (ob->mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
- else if (ob->mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
+ if (object_mode & OB_MODE_POSE) return CTX_MODE_POSE;
+ else if (object_mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT;
+ else if (object_mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT;
+ else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
+ else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
+ else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
}
}
return CTX_MODE_OBJECT;
}
+int CTX_data_mode_enum(const bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Object *obact = obedit ? NULL : CTX_data_active_object(C);
+ return CTX_data_mode_enum_ex(obedit, obact, obact ? obact->mode : OB_MODE_OBJECT);
+}
/* would prefer if we can use the enum version below over this one - Campbell */
/* must be aligned with above enum */
@@ -954,6 +1038,7 @@ static const char *data_mode_strings[] = {
"objectmode",
NULL
};
+BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode")
const char *CTX_data_mode_string(const bContext *C)
{
return data_mode_strings[CTX_data_mode_enum(C)];
@@ -1154,3 +1239,16 @@ int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
return ctx_data_collection_get(C, "editable_gpencil_strokes", list);
}
+Depsgraph *CTX_data_depsgraph(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return BKE_scene_get_depsgraph(scene, view_layer, true);
+}
+
+Depsgraph *CTX_data_depsgraph_on_load(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return BKE_scene_get_depsgraph(scene, view_layer, false);
+}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 56df8e51eba..0a31411d638 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -99,7 +99,8 @@ static int modifiers_disable_subsurf_temporary(Object *ob)
}
/* disable subsurf temporal, get mapped cos, and enable it */
-float (*BKE_crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3]
+float (*BKE_crazyspace_get_mapped_editverts(
+ struct Depsgraph *depsgraph, Scene *scene, Object *obedit))[3]
{
Mesh *me = obedit->data;
DerivedMesh *dm;
@@ -109,13 +110,13 @@ float (*BKE_crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3]
/* disable subsurf temporal, get mapped cos, and enable it */
if (modifiers_disable_subsurf_temporary(obedit)) {
/* need to make new derivemesh */
- makeDerivedMesh(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH, false);
+ makeDerivedMesh(depsgraph, scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH, false);
}
/* now get the cage */
vertexcos = MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map");
- dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
+ dm = editbmesh_get_derived_cage(depsgraph, scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
mesh_get_mapped_verts_coords(dm, vertexcos, nverts);
@@ -250,8 +251,9 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me, float (*origcos)[3], float (*mapped
/** returns an array of deform matrices for crazyspace correction, and the
* number of modifiers left */
-int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob, BMEditMesh *em,
- float (**deformmats)[3][3], float (**deformcos)[3])
+int BKE_crazyspace_get_first_deform_matrices_editbmesh(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em,
+ float (**deformmats)[3][3], float (**deformcos)[3])
{
ModifierData *md;
DerivedMesh *dm;
@@ -259,6 +261,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
VirtualModifierData virtualModifierData;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
modifiers_clearErrors(ob);
@@ -274,7 +277,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
if (!editbmesh_modifier_is_enabled(scene, md, dm))
continue;
- if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
+ if (mti->type == eModifierTypeType_OnlyDeform && (mti->deformMatricesEM || mti->deformMatricesEM_DM)) {
if (!defmats) {
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
CustomDataMask data_mask = CD_MASK_BAREMESH;
@@ -290,8 +293,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
unit_m3(defmats[a]);
}
- mti->deformMatricesEM(md, ob, em, dm, deformedVerts, defmats,
- numVerts);
+ modifier_deformMatricesEM_DM_deprecated(md, &mectx, em, dm, deformedVerts, defmats, numVerts);
}
else
break;
@@ -310,7 +312,9 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
return numleft;
}
-int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
+int BKE_sculpt_get_first_deform_matrices(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
{
ModifierData *md;
DerivedMesh *dm;
@@ -320,6 +324,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
int numleft = 0;
VirtualModifierData virtualModifierData;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
if (has_multires) {
*deformmats = NULL;
@@ -346,7 +351,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
unit_m3(defmats[a]);
}
- if (mti->deformMatrices) mti->deformMatrices(md, ob, dm, deformedVerts, defmats, numVerts);
+ if (mti->deformMatrices || mti->deformMatrices_DM) {
+ modifier_deformMatrices_DM_deprecated(md, &mectx, dm, deformedVerts, defmats, numVerts);
+ }
else break;
}
}
@@ -369,9 +376,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
return numleft;
}
-void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
+void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
{
- int totleft = BKE_sculpt_get_first_deform_matrices(scene, ob, deformmats, deformcos);
+ int totleft = BKE_sculpt_get_first_deform_matrices(depsgraph, scene, ob, deformmats, deformcos);
if (totleft) {
/* there are deformation modifier which doesn't support deformation matrices
@@ -383,6 +390,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[
int i, deformed = 0;
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
Mesh *me = (Mesh *)ob->data;
for (; md; md = md->next) {
@@ -393,10 +401,10 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[
if (mti->type == eModifierTypeType_OnlyDeform) {
/* skip leading modifiers which have been already
* handled in sculpt_get_first_deform_matrices */
- if (mti->deformMatrices && !deformed)
+ if ((mti->deformMatrices || mti->deformMatrices_DM) && !deformed)
continue;
- mti->deformVerts(md, ob, NULL, deformedVerts, me->totvert, 0);
+ modifier_deformVerts_DM_deprecated(md, &mectx, NULL, deformedVerts, me->totvert);
deformed = 1;
}
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index af978a2b516..f6dd630e077 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -53,7 +53,6 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_font.h"
#include "BKE_global.h"
@@ -129,6 +128,8 @@ void BKE_curve_free(Curve *cu)
{
BKE_animdata_free((ID *)cu, false);
+ BKE_curve_batch_cache_free(cu);
+
BKE_nurbList_free(&cu->nurb);
BKE_curve_editfont_free(cu);
@@ -209,8 +210,9 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const
cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
cu_dst->tb = MEM_dupallocN(cu_src->tb);
cu_dst->bb = MEM_dupallocN(cu_src->bb);
+ cu_dst->batch_cache = NULL;
- if (cu_src->key) {
+ if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag, false);
}
@@ -221,7 +223,7 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const
Curve *BKE_curve_copy(Main *bmain, const Curve *cu)
{
Curve *cu_copy;
- BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, 0, false);
+ BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, LIB_ID_COPY_SHAPEKEY, false);
return cu_copy;
}
@@ -1622,7 +1624,7 @@ float *BKE_curve_surf_make_orco(Object *ob)
/* NOTE: This routine is tied to the order of vertex
* built by displist and as passed to the renderer.
*/
-float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
+float *BKE_curve_make_orco(Depsgraph *depsgraph, Scene *scene, Object *ob, int *r_numVerts)
{
Curve *cu = ob->data;
DispList *dl;
@@ -1630,7 +1632,7 @@ float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
float *fp, *coord_array;
ListBase disp = {NULL, NULL};
- BKE_displist_make_curveTypes_forOrco(scene, ob, &disp);
+ BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
numVerts = 0;
for (dl = disp.first; dl; dl = dl->next) {
@@ -1721,8 +1723,9 @@ float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
/* ***************** BEVEL ****************** */
-void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
- const bool for_render, const bool use_render_resolution)
+void BKE_curve_bevel_make(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *disp,
+ const bool for_render, const bool use_render_resolution)
{
DispList *dl, *dlnew;
Curve *bevcu, *cu;
@@ -1746,7 +1749,7 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
facy = cu->bevobj->size[1];
if (for_render) {
- BKE_displist_make_curveTypes_forRender(scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution);
+ BKE_displist_make_curveTypes_forRender(depsgraph, scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution);
dl = bevdisp.first;
}
else if (cu->bevobj->curve_cache) {
@@ -5185,7 +5188,7 @@ int BKE_curve_material_index_validate(Curve *cu)
}
if (!is_valid) {
- DAG_id_tag_update(&cu->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&cu->id, OB_RECALC_DATA);
return true;
}
else {
@@ -5252,11 +5255,28 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t
/* **** Depsgraph evaluation **** */
-void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+void BKE_curve_eval_geometry(Depsgraph *depsgraph,
Curve *curve)
{
- DEG_debug_print_eval(__func__, curve->id.name, curve);
+ DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve);
if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
BKE_curve_texspace_calc(curve);
}
}
+
+/* Draw Engine */
+void (*BKE_curve_batch_cache_dirty_cb)(Curve *cu, int mode) = NULL;
+void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
+
+void BKE_curve_batch_cache_dirty(Curve *cu, int mode)
+{
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_dirty_cb(cu, mode);
+ }
+}
+void BKE_curve_batch_cache_free(Curve *cu)
+{
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_free_cb(cu);
+ }
+}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 28280c45922..b9328051699 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -390,37 +390,19 @@ static void layerSwap_tface(void *data, const int *corner_indices)
{
MTFace *tf = data;
float uv[4][2];
- static const short pin_flags[4] = { TF_PIN1, TF_PIN2, TF_PIN3, TF_PIN4 };
- static const char sel_flags[4] = { TF_SEL1, TF_SEL2, TF_SEL3, TF_SEL4 };
- short unwrap = tf->unwrap & ~(TF_PIN1 | TF_PIN2 | TF_PIN3 | TF_PIN4);
- char flag = tf->flag & ~(TF_SEL1 | TF_SEL2 | TF_SEL3 | TF_SEL4);
int j;
for (j = 0; j < 4; ++j) {
const int source_index = corner_indices[j];
-
copy_v2_v2(uv[j], tf->uv[source_index]);
-
- /* swap pinning flags around */
- if (tf->unwrap & pin_flags[source_index]) {
- unwrap |= pin_flags[j];
- }
-
- /* swap selection flags around */
- if (tf->flag & sel_flags[source_index]) {
- flag |= sel_flags[j];
- }
}
memcpy(tf->uv, uv, sizeof(tf->uv));
- tf->unwrap = unwrap;
- tf->flag = flag;
}
static void layerDefault_tface(void *data, int count)
{
- static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, NULL,
- 0, 0, TF_DYNAMIC | TF_CONVERTED, 0, 0};
+ static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
MTFace *tf = (MTFace *)data;
int i;
@@ -1190,6 +1172,15 @@ static void layerSwap_flnor(void *data, const int *corner_indices)
memcpy(flnors, nors, sizeof(nors));
}
+static void layerDefault_fmap(void *data, int count)
+{
+ int *fmap_num = (int *)data;
+ int i;
+ for (i = 0; i < count; i++) {
+ *fmap_num = -1;
+ }
+}
+
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
@@ -1215,8 +1206,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 3 floats per normal vector */
{sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal},
- /* 9: CD_POLYINDEX */ /* DEPRECATED */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 9: CD_FACEMAP */
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
/* 10: CD_PROP_FLT */
{sizeof(MFloatProperty), "MFloatProperty", 1, N_("Float"), layerCopy_propFloat, NULL, NULL, NULL},
/* 11: CD_PROP_INT */
@@ -1228,10 +1219,9 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face},
/* 14: CD_ORCO */
{sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 15: CD_MTEXPOLY */
+ /* 15: CD_MTEXPOLY */ /* DEPRECATED */
/* note, when we expose the UV Map / TexFace split to the user, change this back to face Texture */
- {sizeof(MTexPoly), "MTexPoly", 1, N_("UVMap") /* "Face Texture" */, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_tface},
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 16: CD_MLOOPUV */
{sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap"), NULL, NULL, layerInterp_mloopuv, NULL, NULL,
layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv,
@@ -1310,7 +1300,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace",
- /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags",
+ /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFaceMap",
/* 10-14 */ "CDMFloatProperty", "CDMIntProperty", "CDMStringProperty", "CDOrigSpace", "CDOrco",
/* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps",
/* 20-24 */ "CDPreviewMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDMRecast",
@@ -1325,41 +1315,41 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
const CustomDataMask CD_MASK_BAREMESH =
- CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT;
+ CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_MESH =
CD_MASK_MVERT | CD_MASK_MEDGE |
CD_MASK_MDEFORMVERT |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP |
- CD_MASK_MTEXPOLY | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
+ CD_MASK_RECAST | CD_MASK_PAINT_MASK |
CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_EDITMESH =
CD_MASK_MDEFORMVERT | CD_MASK_MLOOPUV |
- CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX |
+ CD_MASK_MLOOPCOL | CD_MASK_SHAPE_KEYINDEX |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR |
CD_MASK_MDISPS | CD_MASK_SHAPEKEY | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MDEFORMVERT |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PREVIEW_MLOOPCOL |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL |
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT |
CD_MASK_PREVIEW_MCOL | CD_MASK_SHAPEKEY | CD_MASK_RECAST |
CD_MASK_ORIGINDEX | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_BMESH =
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS |
CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
/**
* cover values copied by #BKE_mesh_loops_to_tessdata
*/
const CustomDataMask CD_MASK_FACECORNERS =
- CD_MASK_MTFACE | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
+ CD_MASK_MTFACE | CD_MASK_MLOOPUV |
CD_MASK_MCOL | CD_MASK_MLOOPCOL |
CD_MASK_PREVIEW_MCOL | CD_MASK_PREVIEW_MLOOPCOL |
CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP |
@@ -1368,7 +1358,7 @@ const CustomDataMask CD_MASK_FACECORNERS =
const CustomDataMask CD_MASK_EVERYTHING =
CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT |
- CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
+ CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL | CD_MASK_TANGENT | CD_MASK_MDISPS | CD_MASK_PREVIEW_MCOL | CD_MASK_CLOTH_ORCO | CD_MASK_RECAST |
/* BMESH ONLY START */
CD_MASK_MPOLY | CD_MASK_MLOOP | CD_MASK_SHAPE_KEYINDEX | CD_MASK_SHAPEKEY | CD_MASK_BWEIGHT | CD_MASK_CREASE |
@@ -1376,7 +1366,7 @@ const CustomDataMask CD_MASK_EVERYTHING =
/* BMESH ONLY END */
CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN |
CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
static const LayerTypeInfo *layerType_getInfo(int type)
{
@@ -1407,8 +1397,9 @@ void customData_mask_layers__print(CustomDataMask mask)
/********************* CustomData functions *********************/
static void customData_update_offsets(CustomData *data);
-static CustomDataLayer *customData_add_layer__internal(CustomData *data, int type, int alloctype, void *layerdata,
- int totelem, const char *name);
+static CustomDataLayer *customData_add_layer__internal(
+ CustomData *data, int type, eCDAllocType alloctype, void *layerdata,
+ int totelem, const char *name);
void CustomData_update_typemap(CustomData *data)
{
@@ -1437,8 +1428,9 @@ static bool customdata_typemap_is_valid(const CustomData *data)
}
#endif
-bool CustomData_merge(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem)
+bool CustomData_merge(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem)
{
/*const LayerTypeInfo *typeInfo;*/
CustomDataLayer *layer, *newlayer;
@@ -1520,8 +1512,9 @@ void CustomData_realloc(CustomData *data, int totelem)
}
}
-void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem)
+void CustomData_copy(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem)
{
CustomData_reset(dest);
@@ -1820,8 +1813,9 @@ static int customData_resize(CustomData *data, int amount)
return 1;
}
-static CustomDataLayer *customData_add_layer__internal(CustomData *data, int type, int alloctype, void *layerdata,
- int totelem, const char *name)
+static CustomDataLayer *customData_add_layer__internal(
+ CustomData *data, int type, eCDAllocType alloctype, void *layerdata,
+ int totelem, const char *name)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
int flag = 0, index = data->totlayer;
@@ -1908,8 +1902,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
return &data->layers[index];
}
-void *CustomData_add_layer(CustomData *data, int type, int alloctype,
- void *layerdata, int totelem)
+void *CustomData_add_layer(
+ CustomData *data, int type, eCDAllocType alloctype,
+ void *layerdata, int totelem)
{
CustomDataLayer *layer;
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -1925,8 +1920,9 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype,
}
/*same as above but accepts a name*/
-void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
- void *layerdata, int totelem, const char *name)
+void *CustomData_add_layer_named(
+ CustomData *data, int type, eCDAllocType alloctype,
+ void *layerdata, int totelem, const char *name)
{
CustomDataLayer *layer;
@@ -2501,13 +2497,10 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou
/* BMesh functions */
/* needed to convert to/from different face reps */
-void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata,
- int totloop, int totpoly)
+void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
{
- int i;
- for (i = 0; i < fdata->totlayer; i++) {
+ for (int i = 0; i < fdata->totlayer; i++) {
if (fdata->layers[i].type == CD_MTFACE) {
- CustomData_add_layer_named(pdata, CD_MTEXPOLY, CD_CALLOC, NULL, totpoly, fdata->layers[i].name);
CustomData_add_layer_named(ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MCOL) {
@@ -2522,19 +2515,18 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *l
}
}
-void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total)
+void CustomData_from_bmeshpoly(
+ CustomData *fdata, CustomData *ldata, int total)
{
int i;
/* avoid accumulating extra layers */
- BLI_assert(!CustomData_from_bmeshpoly_test(fdata, pdata, ldata, false));
+ BLI_assert(!CustomData_from_bmeshpoly_test(fdata, ldata, false));
- for (i = 0; i < pdata->totlayer; i++) {
- if (pdata->layers[i].type == CD_MTEXPOLY) {
- CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, pdata->layers[i].name);
- }
- }
for (i = 0; i < ldata->totlayer; i++) {
+ if (ldata->layers[i].type == CD_MLOOPUV) {
+ CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
if (ldata->layers[i].type == CD_MLOOPCOL) {
CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
}
@@ -2552,7 +2544,7 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData
}
}
- CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
+ CustomData_bmesh_update_active_layers(fdata, ldata);
}
#ifndef NDEBUG
@@ -2562,13 +2554,13 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData
* \param fallback: Use when there are no layers to handle,
* since callers may expect success or failure.
*/
-bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback)
+bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback)
{
int a_num = 0, b_num = 0;
#define LAYER_CMP(l_a, t_a, l_b, t_b) \
((a_num += CustomData_number_of_layers(l_a, t_a)) == (b_num += CustomData_number_of_layers(l_b, t_b)))
- if (!LAYER_CMP(pdata, CD_MTEXPOLY, fdata, CD_MTFACE))
+ if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE))
return false;
if (!LAYER_CMP(ldata, CD_MLOOPCOL, fdata, CD_MCOL))
return false;
@@ -2590,25 +2582,21 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom
#endif
-void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
- if (CustomData_has_layer(pdata, CD_MTEXPOLY)) {
- act = CustomData_get_active_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
+ if (CustomData_has_layer(ldata, CD_MLOOPUV)) {
+ act = CustomData_get_active_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_active(fdata, CD_MTFACE, act);
- act = CustomData_get_render_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_render_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_render(fdata, CD_MTFACE, act);
- act = CustomData_get_clone_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_clone_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_clone(fdata, CD_MTFACE, act);
- act = CustomData_get_stencil_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_stencil_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_stencil(fdata, CD_MTFACE, act);
}
@@ -2632,25 +2620,21 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata,
* used by do_versions in readfile.c when creating pdata and ldata for pre-bmesh
* meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files
*/
-void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
if (CustomData_has_layer(fdata, CD_MTFACE)) {
act = CustomData_get_active_layer(fdata, CD_MTFACE);
- CustomData_set_layer_active(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
act = CustomData_get_render_layer(fdata, CD_MTFACE);
- CustomData_set_layer_render(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
act = CustomData_get_clone_layer(fdata, CD_MTFACE);
- CustomData_set_layer_clone(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
act = CustomData_get_stencil_layer(fdata, CD_MTFACE);
- CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
}
@@ -2695,7 +2679,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
bool CustomData_bmesh_merge(
const CustomData *source, CustomData *dest,
- CustomDataMask mask, int alloctype, BMesh *bm, const char htype)
+ CustomDataMask mask, eCDAllocType alloctype, BMesh *bm, const char htype)
{
BMHeader *h;
BMIter iter;
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 38340575e74..7006e4ddaa6 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -42,14 +42,13 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_mesh_remap.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
@@ -79,7 +78,7 @@ CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types
cddata_mask |= CD_MASK_MDEFORMVERT; /* Exception for vgroups :/ */
}
else if (cddata_type == CD_FAKE_UV) {
- cddata_mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV;
+ cddata_mask |= CD_MASK_MLOOPUV;
}
else if (cddata_type == CD_FAKE_LNOR) {
cddata_mask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
@@ -256,77 +255,76 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
/* Generic pre/post processing, only used by custom loop normals currently. */
static void data_transfer_dtdata_type_preprocess(
- Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
- const int dtdata_type, const bool dirty_nors_dst, const bool use_split_nors_src, const float split_angle_src)
+ Mesh *me_src, Mesh *me_dst,
+ const int dtdata_type, const bool dirty_nors_dst)
{
if (dtdata_type == DT_TYPE_LNOR) {
/* Compute custom normals into regular loop normals, which will be used for the transfer. */
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
- CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
const float split_angle_dst = me_dst->smoothresh;
- dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
+ BKE_mesh_calc_normals_split(me_src);
- if (dm_dst) {
- dm_dst->calcLoopNormals(dm_dst, use_split_nors_dst, split_angle_dst);
- }
- else {
- float (*poly_nors_dst)[3];
- float (*loop_nors_dst)[3];
- short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
-
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- if (dirty_nors_dst || !poly_nors_dst) {
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- BKE_mesh_calc_normals_poly(verts_dst, NULL, num_verts_dst, loops_dst, polys_dst,
- num_loops_dst, num_polys_dst, poly_nors_dst, true);
- }
- /* Cache loop nors into a temp CDLayer. */
- loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
- if (dirty_nors_dst || loop_nors_dst) {
- if (!loop_nors_dst) {
- loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
- CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- BKE_mesh_normals_loop_split(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
- loops_dst, loop_nors_dst, num_loops_dst,
- polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
- use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
- }
+ float (*poly_nors_dst)[3];
+ float (*loop_nors_dst)[3];
+ short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
+
+ /* Cache poly nors into a temp CDLayer. */
+ poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ const bool do_poly_nors_dst = (poly_nors_dst == NULL);
+ if (do_poly_nors_dst) {
+ poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
+ CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_poly_nors_dst) {
+ BKE_mesh_calc_normals_poly(
+ verts_dst, NULL, num_verts_dst, loops_dst, polys_dst,
+ num_loops_dst, num_polys_dst, poly_nors_dst, true);
+ }
+ /* Cache loop nors into a temp CDLayer. */
+ loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
+ const bool do_loop_nors_dst = (loop_nors_dst == NULL);
+ if (do_loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_loop_nors_dst) {
+ BKE_mesh_normals_loop_split(
+ verts_dst, num_verts_dst, edges_dst, num_edges_dst,
+ loops_dst, loop_nors_dst, num_loops_dst,
+ polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
+ use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
}
}
}
static void data_transfer_dtdata_type_postprocess(
- Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *UNUSED(dm_src), DerivedMesh *dm_dst, Mesh *me_dst,
+ Object *UNUSED(ob_src), Object *UNUSED(ob_dst), Mesh *UNUSED(me_src), Mesh *me_dst,
const int dtdata_type, const bool changed)
{
if (dtdata_type == DT_TYPE_LNOR) {
/* Bake edited destination loop normals into custom normals again. */
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
- CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL);
float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL);
@@ -530,7 +528,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
continue;
}
data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (fro; ;odifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_src, num_elem_dst);
}
@@ -574,7 +572,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
data_dst_to_delete[idx_dst] = false;
}
if (r_map) {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -632,7 +630,7 @@ static bool data_transfer_layersmapping_cdlayers(
data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
}
else if (use_dupref_dst && r_map) {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst);
}
@@ -659,7 +657,7 @@ static bool data_transfer_layersmapping_cdlayers(
if (tolayers >= 0) { /* Real-layer index */
idx_dst = tolayers;
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -675,7 +673,7 @@ static bool data_transfer_layersmapping_cdlayers(
data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
}
else {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -696,7 +694,7 @@ static bool data_transfer_layersmapping_cdlayers(
CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
}
}
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -713,7 +711,7 @@ static bool data_transfer_layersmapping_cdlayers(
CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
}
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -762,7 +760,7 @@ static bool data_transfer_layersmapping_cdlayers(
}
static bool data_transfer_layersmapping_generate(
- ListBase *r_map, Object *ob_src, Object *ob_dst, DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
+ ListBase *r_map, Object *ob_src, Object *ob_dst, Mesh *me_src, Mesh *me_dst,
const int elem_type, int cddata_type, int mix_mode, float mix_factor, const float *mix_weights,
const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers,
SpaceTransform *space_transform)
@@ -774,12 +772,12 @@ static bool data_transfer_layersmapping_generate(
if (elem_type == ME_VERT) {
if (!(cddata_type & CD_FAKE)) {
- cd_src = dm_src->getVertDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata;
+ cd_src = &me_src->vdata;
+ cd_dst = &me_dst->vdata;
if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
- cd_src, cd_dst, dm_dst != NULL,
+ cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -794,24 +792,17 @@ static bool data_transfer_layersmapping_generate(
const size_t data_offset = offsetof(MVert, bweight);
const uint64_t data_flag = 0;
- if (!(dm_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) {
- if (use_delete && !dm_dst) {
+ if (!(me_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) {
+ if (use_delete) {
me_dst->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT;
}
return true;
}
- if (dm_dst) {
- dm_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- }
- else {
- me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- }
+ me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
if (r_map) {
data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getVertArray(dm_src),
- dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert,
- dm_src->getNumVerts(dm_src),
- dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert,
+ me_src->mvert, me_dst->mvert,
+ me_src->totvert, me_dst->totvert,
elem_size, data_size, data_offset, data_flag,
data_transfer_interp_char, interp_data);
}
@@ -820,12 +811,12 @@ static bool data_transfer_layersmapping_generate(
else if (cddata_type == CD_FAKE_MDEFORMVERT) {
bool ret;
- cd_src = dm_src->getVertDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata;
+ cd_src = &me_src->vdata;
+ cd_dst = &me_dst->vdata;
ret = data_transfer_layersmapping_vgroups(r_map, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
- ob_src, ob_dst, cd_src, cd_dst, dm_dst != NULL,
+ ob_src, ob_dst, cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers);
/* Mesh stores its dvert in a specific pointer too. :( */
@@ -839,12 +830,12 @@ static bool data_transfer_layersmapping_generate(
}
else if (elem_type == ME_EDGE) {
if (!(cddata_type & CD_FAKE)) { /* Unused for edges, currently... */
- cd_src = dm_src->getEdgeDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getEdgeDataLayout(dm_dst) : &me_dst->edata;
+ cd_src = &me_src->edata;
+ cd_dst = &me_dst->edata;
if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
- cd_src, cd_dst, dm_dst != NULL,
+ cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -859,24 +850,17 @@ static bool data_transfer_layersmapping_generate(
const size_t data_offset = offsetof(MEdge, crease);
const uint64_t data_flag = 0;
- if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
- if (use_delete && !dm_dst) {
+ if (!(me_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
+ if (use_delete && !me_dst) {
me_dst->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
}
return true;
}
- if (dm_dst) {
- dm_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
- else {
- me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
+ me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
if (r_map) {
data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getEdgeArray(dm_src),
- dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
- dm_src->getNumEdges(dm_src),
- dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
+ me_src->medge, me_dst->medge,
+ me_src->totedge, me_dst->totedge,
elem_size, data_size, data_offset, data_flag,
data_transfer_interp_char, interp_data);
}
@@ -888,24 +872,17 @@ static bool data_transfer_layersmapping_generate(
const size_t data_offset = offsetof(MEdge, bweight);
const uint64_t data_flag = 0;
- if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) {
- if (use_delete && !dm_dst) {
+ if (!(me_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) {
+ if (use_delete && !me_dst) {
me_dst->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT;
}
return true;
}
- if (dm_dst) {
- dm_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- }
- else {
- me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- }
+ me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
if (r_map) {
data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getEdgeArray(dm_src),
- dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
- dm_src->getNumEdges(dm_src),
- dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
+ me_src->medge, me_dst->medge,
+ me_src->totedge, me_dst->totedge,
elem_size, data_size, data_offset, data_flag,
data_transfer_interp_char, interp_data);
}
@@ -919,10 +896,8 @@ static bool data_transfer_layersmapping_generate(
data_transfer_layersmapping_add_item(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getEdgeArray(dm_src),
- dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
- dm_src->getNumEdges(dm_src),
- dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
+ me_src->medge, me_dst->medge,
+ me_src->totedge, me_dst->totedge,
elem_size, data_size, data_offset, data_flag, NULL, interp_data);
return true;
}
@@ -942,12 +917,12 @@ static bool data_transfer_layersmapping_generate(
}
if (!(cddata_type & CD_FAKE)) {
- cd_src = dm_src->getLoopDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ cd_src = &me_src->ldata;
+ cd_dst = &me_dst->ldata;
if (!data_transfer_layersmapping_cdlayers(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
+ num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -962,16 +937,16 @@ static bool data_transfer_layersmapping_generate(
}
else if (elem_type == ME_POLY) {
if (cddata_type == CD_FAKE_UV) {
- cddata_type = CD_MTEXPOLY;
+ cddata_type = CD_MLOOPUV;
}
if (!(cddata_type & CD_FAKE)) {
- cd_src = dm_src->getPolyDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
+ cd_src = &me_src->pdata;
+ cd_dst = &me_dst->pdata;
if (!data_transfer_layersmapping_cdlayers(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
+ num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -988,10 +963,8 @@ static bool data_transfer_layersmapping_generate(
data_transfer_layersmapping_add_item(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getPolyArray(dm_src),
- dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly,
- dm_src->getNumPolys(dm_src),
- dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly,
+ me_src->mpoly, me_dst->mpoly,
+ me_src->totpoly, me_dst->totpoly,
elem_size, data_size, data_offset, data_flag, NULL, interp_data);
return true;
}
@@ -1010,25 +983,26 @@ static bool data_transfer_layersmapping_generate(
* to get (as much as possible) exact copy of source data layout.
*/
void BKE_object_data_transfer_layout(
- Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete,
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX])
{
- DerivedMesh *dm_src;
+ Mesh *me_src;
Mesh *me_dst;
int i;
const bool use_create = true; /* We always create needed layers here. */
- CustomDataMask dm_src_mask = CD_MASK_BAREMESH;
+ CustomDataMask me_src_mask = CD_MASK_BAREMESH;
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
me_dst = ob_dst->data;
- /* Get source DM.*/
- dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
- dm_src = mesh_get_derived_final(scene, ob_src, dm_src_mask);
- if (!dm_src) {
+ /* Get source evaluated mesh.*/
+ me_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
+ me_src = mesh_get_eval_final(depsgraph, scene, ob_src, me_src_mask);
+ if (!me_src) {
return;
}
@@ -1057,37 +1031,37 @@ void BKE_object_data_transfer_layout(
const int num_elem_dst = me_dst->totvert;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
const int num_elem_dst = me_dst->totedge;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
const int num_elem_dst = me_dst->totloop;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_POLY(dtdata_type)) {
const int num_elem_dst = me_dst->totpoly;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
}
}
-bool BKE_object_data_transfer_dm(
- Scene *scene, Object *ob_src, Object *ob_dst, DerivedMesh *dm_dst, const int data_types, bool use_create,
- const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
- SpaceTransform *space_transform, const bool auto_transform,
+bool BKE_object_data_transfer_ex(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, Mesh *me_dst,
+ const int data_types, bool use_create, const int map_vert_mode, const int map_edge_mode,
+ const int map_loop_mode, const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform,
const float max_distance, const float ray_radius, const float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
@@ -1101,9 +1075,8 @@ bool BKE_object_data_transfer_dm(
SpaceTransform auto_space_transform;
- DerivedMesh *dm_src;
- Mesh *me_dst, *me_src;
- bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */
+ Mesh *me_src;
+ bool dirty_nors_dst = true; /* Assumed always true if not using an evaluated mesh as destination. */
int i;
MDeformVert *mdef = NULL;
@@ -1117,53 +1090,40 @@ bool BKE_object_data_transfer_dm(
const bool use_delete = false; /* We never delete data layers from destination here. */
- CustomDataMask dm_src_mask = CD_MASK_BAREMESH;
+ CustomDataMask me_src_mask = CD_MASK_BAREMESH;
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
- me_dst = ob_dst->data;
- me_src = ob_src->data;
- if (dm_dst) {
- dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0;
- use_create = false; /* Never create needed custom layers on DM (modifier case). */
+ if (me_dst) {
+ dirty_nors_dst = (me_dst->runtime.cd_dirty_vert & CD_NORMAL) != 0;
+ /* Never create needed custom layers on passed destination mesh
+ * (assumed to *not* be ob_dst->data, aka modifier case). */
+ use_create = false;
+ }
+ else {
+ me_dst = ob_dst->data;
}
if (vgroup_name) {
- if (dm_dst) {
- mdef = dm_dst->getVertDataArray(dm_dst, CD_MDEFORMVERT);
- }
- else {
- mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
- }
+ mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
if (mdef) {
vg_idx = defgroup_name_index(ob_dst, vgroup_name);
}
}
- /* Get source DM.*/
- dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
- /* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm,
- * can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers...
- * Issue is, this means we cannot be sure to have requested cd layers in source.
- *
- * Also, we need to make a local copy of dm_src, otherwise we may end with concurrent creation
- * of data in it (multi-threaded evaluation of the modifier stack, see T46672).
- */
- dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask);
- if (!dm_src) {
+ /* Get source evaluated mesh.*/
+ me_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
+ me_src = mesh_get_eval_final(depsgraph, scene, ob_src, me_src_mask);
+ if (!me_src) {
return changed;
}
- dm_src = CDDM_copy(dm_src);
if (auto_transform) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
-
if (space_transform == NULL) {
space_transform = &auto_space_transform;
}
- BKE_mesh_remap_find_best_match_from_dm(verts_dst, num_verts_dst, dm_src, space_transform);
+ BKE_mesh_remap_find_best_match_from_mesh(me_dst->mvert, me_dst->totvert, me_src, space_transform);
}
/* Check all possible data types.
@@ -1177,9 +1137,7 @@ bool BKE_object_data_transfer_dm(
continue;
}
- data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst,
- dtdata_type, dirty_nors_dst,
- (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh);
+ data_transfer_dtdata_type_preprocess(me_src, me_dst, dtdata_type, dirty_nors_dst);
cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
@@ -1193,11 +1151,11 @@ bool BKE_object_data_transfer_dm(
}
if (DT_DATATYPE_IS_VERT(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
if (!geom_map_init[VDATA]) {
- const int num_verts_src = dm_src->getNumVerts(dm_src);
+ const int num_verts_src = me_src->totvert;
if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1205,13 +1163,13 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_vert_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ if ((map_vert_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any edges, "
"None of the 'Edge' mappings can be used in this case");
continue;
}
- if ((map_vert_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ if ((map_vert_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any faces, "
"None of the 'Face' mappings can be used in this case");
@@ -1223,9 +1181,9 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_verts_from_dm(
+ BKE_mesh_remap_calc_verts_from_mesh(
map_vert_mode, space_transform, max_distance, ray_radius,
- verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]);
+ verts_dst, num_verts_dst, dirty_nors_dst, me_src, &geom_map[VDATA]);
geom_map_init[VDATA] = true;
}
@@ -1235,7 +1193,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_VERT,
cddata_type, mix_mode, mix_factor, weights[VDATA],
num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1251,13 +1209,13 @@ bool BKE_object_data_transfer_dm(
}
}
if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
if (!geom_map_init[EDATA]) {
- const int num_edges_src = dm_src->getNumEdges(dm_src);
+ const int num_edges_src = me_src->totedge;
if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1265,7 +1223,7 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_edge_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ if ((map_edge_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any faces, "
"None of the 'Face' mappings can be used in this case");
@@ -1277,10 +1235,10 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_edges_from_dm(
+ BKE_mesh_remap_calc_edges_from_mesh(
map_edge_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst,
- dm_src, &geom_map[EDATA]);
+ me_src, &geom_map[EDATA]);
geom_map_init[EDATA] = true;
}
@@ -1292,7 +1250,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_EDGE,
cddata_type, mix_mode, mix_factor, weights[EDATA],
num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1308,21 +1266,21 @@ bool BKE_object_data_transfer_dm(
}
}
if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
- CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
if (!geom_map_init[LDATA]) {
- const int num_loops_src = dm_src->getNumLoops(dm_src);
+ const int num_loops_src = me_src->totloop;
if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1330,7 +1288,7 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_loop_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ if ((map_loop_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any edges, "
"None of the 'Edge' mappings can be used in this case");
@@ -1342,13 +1300,13 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_loops_from_dm(
+ BKE_mesh_remap_calc_loops_from_mesh(
map_loop_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst,
loops_dst, num_loops_dst, polys_dst, num_polys_dst,
ldata_dst, pdata_dst,
(me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst,
- dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh,
+ me_src,
island_callback, islands_handling_precision, &geom_map[LDATA]);
geom_map_init[LDATA] = true;
}
@@ -1361,7 +1319,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_LOOP,
cddata_type, mix_mode, mix_factor, weights[LDATA],
num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1377,16 +1335,16 @@ bool BKE_object_data_transfer_dm(
}
}
if (DT_DATATYPE_IS_POLY(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
if (!geom_map_init[PDATA]) {
- const int num_polys_src = dm_src->getNumPolys(dm_src);
+ const int num_polys_src = me_src->totpoly;
if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1394,7 +1352,7 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_poly_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ if ((map_poly_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any edges, "
"None of the 'Edge' mappings can be used in this case");
@@ -1406,11 +1364,11 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_polys_from_dm(
+ BKE_mesh_remap_calc_polys_from_mesh(
map_poly_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, loops_dst, num_loops_dst,
polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst,
- dm_src, &geom_map[PDATA]);
+ me_src, &geom_map[PDATA]);
geom_map_init[PDATA] = true;
}
@@ -1422,7 +1380,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_POLY,
cddata_type, mix_mode, mix_factor, weights[PDATA],
num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1438,14 +1396,13 @@ bool BKE_object_data_transfer_dm(
}
}
- data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed);
+ data_transfer_dtdata_type_postprocess(ob_src, ob_dst, me_src, me_dst, dtdata_type, changed);
}
for (i = 0; i < DATAMAX; i++) {
BKE_mesh_remap_free(&geom_map[i]);
MEM_SAFE_FREE(weights[i]);
}
- dm_src->release(dm_src);
return changed;
@@ -1457,16 +1414,16 @@ bool BKE_object_data_transfer_dm(
}
bool BKE_object_data_transfer_mesh(
- Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_create,
- const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
- SpaceTransform *space_transform, const bool auto_transform,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, const int data_types,
+ const bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode,
+ const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform,
const float max_distance, const float ray_radius, const float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
ReportList *reports)
{
- return BKE_object_data_transfer_dm(
- scene, ob_src, ob_dst, NULL, data_types, use_create,
+ return BKE_object_data_transfer_ex(
+ depsgraph, scene, ob_src, ob_dst, NULL, data_types, use_create,
map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode,
space_transform, auto_transform,
max_distance, ray_radius, islands_handling_precision,
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index f33f17019b3..2da157d5b88 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -54,6 +54,7 @@
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h" /* own include */
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_object_deform.h"
@@ -73,6 +74,8 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name)
BLI_addtail(&ob->defbase, defgroup);
defgroup_unique_name(defgroup, ob);
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
return defgroup;
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
deleted file mode 100644
index 734aac8a1f7..00000000000
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ /dev/null
@@ -1,3745 +0,0 @@
-/*
- * ***** 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) 2004 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/depsgraph.c
- * \ingroup bke
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#ifdef WIN32
-# include "BLI_winstuff.h"
-#endif
-
-#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
-#include "BLI_ghash.h"
-#include "BLI_threads.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_cachefile_types.h"
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_key_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_node_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_rigidbody_types.h"
-
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
-#include "BKE_action.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_collision.h"
-#include "BKE_curve.h"
-#include "BKE_effect.h"
-#include "BKE_fcurve.h"
-#include "BKE_global.h"
-#include "BKE_idcode.h"
-#include "BKE_image.h"
-#include "BKE_key.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
-#include "BKE_node.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-#include "BKE_pointcache.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
-#include "BKE_tracking.h"
-
-#include "GPU_buffers.h"
-
-#include "atomic_ops.h"
-
-#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
- *
- * the queue store a list of freenodes to avoid successive alloc/dealloc
- */
-
-DagNodeQueue *queue_create(int slots)
-{
- DagNodeQueue *queue;
- DagNodeQueueElem *elem;
- int i;
-
- queue = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue");
- queue->freenodes = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue");
- queue->count = 0;
- queue->maxlevel = 0;
- queue->first = queue->last = NULL;
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem3");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->first = queue->freenodes->last = elem;
-
- for (i = 1; i < slots; i++) {
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem4");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->last->next = elem;
- queue->freenodes->last = elem;
- }
- queue->freenodes->count = slots;
- return queue;
-}
-
-void queue_raz(DagNodeQueue *queue)
-{
- DagNodeQueueElem *elem;
-
- elem = queue->first;
- if (queue->freenodes->last)
- queue->freenodes->last->next = elem;
- else
- queue->freenodes->first = queue->freenodes->last = elem;
-
- elem->node = NULL;
- queue->freenodes->count++;
- while (elem->next) {
- elem = elem->next;
- elem->node = NULL;
- queue->freenodes->count++;
- }
- queue->freenodes->last = elem;
- queue->count = 0;
-}
-
-void queue_delete(DagNodeQueue *queue)
-{
- DagNodeQueueElem *elem;
- DagNodeQueueElem *temp;
-
- elem = queue->first;
- while (elem) {
- temp = elem;
- elem = elem->next;
- MEM_freeN(temp);
- }
-
- elem = queue->freenodes->first;
- while (elem) {
- temp = elem;
- elem = elem->next;
- MEM_freeN(temp);
- }
-
- MEM_freeN(queue->freenodes);
- MEM_freeN(queue);
-}
-
-/* insert in queue, remove in front */
-void push_queue(DagNodeQueue *queue, DagNode *node)
-{
- DagNodeQueueElem *elem;
- int i;
-
- if (node == NULL) {
- fprintf(stderr, "pushing null node\n");
- return;
- }
- /*fprintf(stderr, "BFS push : %s %d\n", ((ID *) node->ob)->name, queue->count);*/
-
- elem = queue->freenodes->first;
- if (elem != NULL) {
- queue->freenodes->first = elem->next;
- if (queue->freenodes->last == elem) {
- queue->freenodes->last = NULL;
- queue->freenodes->first = NULL;
- }
- queue->freenodes->count--;
- }
- else { /* alllocating more */
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->first = queue->freenodes->last = elem;
-
- for (i = 1; i < DAGQUEUEALLOC; i++) {
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->last->next = elem;
- queue->freenodes->last = elem;
- }
- queue->freenodes->count = DAGQUEUEALLOC;
-
- elem = queue->freenodes->first;
- queue->freenodes->first = elem->next;
- }
- elem->next = NULL;
- elem->node = node;
- if (queue->last != NULL)
- queue->last->next = elem;
- queue->last = elem;
- if (queue->first == NULL) {
- queue->first = elem;
- }
- queue->count++;
-}
-
-
-/* insert in front, remove in front */
-void push_stack(DagNodeQueue *queue, DagNode *node)
-{
- DagNodeQueueElem *elem;
- int i;
-
- elem = queue->freenodes->first;
- if (elem != NULL) {
- queue->freenodes->first = elem->next;
- if (queue->freenodes->last == elem) {
- queue->freenodes->last = NULL;
- queue->freenodes->first = NULL;
- }
- queue->freenodes->count--;
- }
- else { /* alllocating more */
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->first = queue->freenodes->last = elem;
-
- for (i = 1; i < DAGQUEUEALLOC; i++) {
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->last->next = elem;
- queue->freenodes->last = elem;
- }
- queue->freenodes->count = DAGQUEUEALLOC;
-
- elem = queue->freenodes->first;
- queue->freenodes->first = elem->next;
- }
- elem->next = queue->first;
- elem->node = node;
- queue->first = elem;
- if (queue->last == NULL)
- queue->last = elem;
- queue->count++;
-}
-
-
-DagNode *pop_queue(DagNodeQueue *queue)
-{
- DagNodeQueueElem *elem;
- DagNode *node;
-
- elem = queue->first;
- if (elem) {
- queue->first = elem->next;
- if (queue->last == elem) {
- queue->last = NULL;
- queue->first = NULL;
- }
- queue->count--;
- if (queue->freenodes->last)
- queue->freenodes->last->next = elem;
- queue->freenodes->last = elem;
- if (queue->freenodes->first == NULL)
- queue->freenodes->first = elem;
- node = elem->node;
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->count++;
- return node;
- }
- else {
- fprintf(stderr, "return null\n");
- return NULL;
- }
-}
-
-DagNode *get_top_node_queue(DagNodeQueue *queue)
-{
- return queue->first->node;
-}
-
-DagForest *dag_init(void)
-{
- DagForest *forest;
- /* use callocN to init all zero */
- forest = MEM_callocN(sizeof(DagForest), "DAG root");
- forest->ugly_hack_sorry = true;
- return forest;
-}
-
-/* isdata = object data... */
-/* XXX this needs to be extended to be more flexible (so that not only objects are evaluated via depsgraph)... */
-static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node, int isdata)
-{
- FCurve *fcu;
- DagNode *node1;
-
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
- int isdata_fcu = (isdata) || (fcu->rna_path && strstr(fcu->rna_path, "modifiers["));
-
- /* loop over variables to get the target relationships */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only used targets */
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id) {
- /* FIXME: other data types need to be added here so that they can work! */
- if (GS(dtar->id->name) == ID_OB) {
- Object *ob = (Object *)dtar->id;
-
- /* normal channel-drives-channel */
- node1 = dag_get_node(dag, dtar->id);
-
- /* check if bone... */
- if ((ob->type == OB_ARMATURE) &&
- ( ((dtar->rna_path) && strstr(dtar->rna_path, "pose.bones[")) ||
- ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) ))
- {
- dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver");
- }
- /* check if ob data */
- else if (dtar->rna_path && strstr(dtar->rna_path, "data."))
- dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver");
- /* normal */
- else
- dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_OB_DATA : DAG_RL_OB_OB, "Driver");
- }
- }
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
-}
-
-/* XXX: forward def for material driver handling... */
-static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma);
-
-/* recursive handling for shader nodetree drivers */
-static void dag_add_shader_nodetree_driver_relations(DagForest *dag, DagNode *node, bNodeTree *ntree)
-{
- bNode *n;
-
- /* nodetree itself */
- if (ntree->adt) {
- dag_add_driver_relation(ntree->adt, dag, node, 1);
- }
-
- /* nodetree's nodes... */
- for (n = ntree->nodes.first; n; n = n->next) {
- if (n->id) {
- if (GS(n->id->name) == ID_MA) {
- dag_add_material_driver_relations(dag, node, (Material *)n->id);
- }
- else if (n->type == NODE_GROUP) {
- dag_add_shader_nodetree_driver_relations(dag, node, (bNodeTree *)n->id);
- }
- }
- }
-}
-
-/* recursive handling for material drivers */
-static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma)
-{
- /* Prevent infinite recursion by checking (and tagging the material) as having been visited
- * already (see build_dag()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else
- * in the meantime... [#32017]
- */
- if (ma->id.tag & LIB_TAG_DOIT)
- return;
-
- ma->id.tag |= LIB_TAG_DOIT;
-
- /* material itself */
- if (ma->adt)
- dag_add_driver_relation(ma->adt, dag, node, 1);
-
- /* textures */
- // TODO...
- //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id);
-
- /* material's nodetree */
- if (ma->nodetree)
- dag_add_shader_nodetree_driver_relations(dag, node, ma->nodetree);
-
- ma->id.tag &= ~LIB_TAG_DOIT;
-}
-
-/* recursive handling for lamp drivers */
-static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *la)
-{
- /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited
- * already (see build_dag()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else
- * in the meantime... [#32017]
- */
- if (la->id.tag & LIB_TAG_DOIT)
- return;
-
- la->id.tag |= LIB_TAG_DOIT;
-
- /* lamp itself */
- if (la->adt)
- dag_add_driver_relation(la->adt, dag, node, 1);
-
- /* textures */
- // TODO...
- //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id);
-
- /* lamp's nodetree */
- if (la->nodetree)
- dag_add_shader_nodetree_driver_relations(dag, node, la->nodetree);
-
- la->id.tag &= ~LIB_TAG_DOIT;
-}
-
-static void create_collision_relation(DagForest *dag, DagNode *node, Object *ob1, const char *name)
-{
- DagNode *node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, name);
-}
-
-void dag_add_collision_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name)
-{
- unsigned int numcollobj;
- Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli);
-
- for (unsigned int i = 0; i < numcollobj; i++) {
- Object *ob1 = collobjs[i];
-
- if (!fn || fn(ob1, modifiers_findByType(ob1, modifier_type))) {
- create_collision_relation(dag, node, ob1, name);
- }
- }
-
- if (collobjs)
- MEM_freeN(collobjs);
-}
-
-void dag_add_forcefield_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name)
-{
- ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false);
-
- if (effectors) {
- for (EffectorCache *eff = effectors->first; eff; eff = eff->next) {
- if (eff->ob != ob && eff->pd->forcefield != skip_forcefield) {
- create_collision_relation(dag, node, eff->ob, name);
-
- if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- create_collision_relation(dag, node, eff->pd->f_source, "Smoke Force Domain");
- }
-
- if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
- /* Actual code uses get_collider_cache */
- dag_add_collision_relations(dag, scene, ob, node, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption");
- }
- }
- }
- }
-
- pdEndEffectors(&effectors);
-}
-
-static bool build_deg_tracking_constraints(DagForest *dag,
- Scene *scene,
- DagNode *scenenode,
- bConstraint *con,
- const bConstraintTypeInfo *cti,
- DagNode *node,
- bool is_data)
-{
- if (!ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK,
- CONSTRAINT_TYPE_CAMERASOLVER,
- CONSTRAINT_TYPE_OBJECTSOLVER))
- {
- return false;
- }
- bool depends_on_camera = false;
- if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data;
- if ((data->clip || data->flag & FOLLOWTRACK_ACTIVECLIP) && data->track[0]) {
- depends_on_camera = true;
- }
- if (data->depth_ob != NULL) {
- DagNode *node2 = dag_get_node(dag, data->depth_ob);
- dag_add_relation(dag,
- node2, node,
- (is_data) ? (DAG_RL_DATA_DATA | DAG_RL_OB_DATA)
- : (DAG_RL_DATA_OB | DAG_RL_OB_OB),
- cti->name);
- }
- }
- else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- depends_on_camera = true;
- }
- if (depends_on_camera && scene->camera != NULL) {
- DagNode *node2 = dag_get_node(dag, scene->camera);
- dag_add_relation(dag,
- node2, node,
- (is_data) ? (DAG_RL_DATA_DATA | DAG_RL_OB_DATA)
- : (DAG_RL_DATA_OB | DAG_RL_OB_OB),
- cti->name);
- }
- dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
- return true;
-}
-
-static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, Object *ob, int mask)
-{
- bConstraint *con;
- DagNode *node;
- DagNode *node2;
- DagNode *node3;
- Key *key;
- ParticleSystem *psys;
- int addtoroot = 1;
-
- node = dag_get_node(dag, ob);
-
- if ((ob->data) && (mask & DAG_RL_DATA)) {
- node2 = dag_get_node(dag, ob->data);
- dag_add_relation(dag, node, node2, DAG_RL_DATA, "Object-Data Relation");
- node2->first_ancestor = ob;
- node2->ancestor_count += 1;
- }
-
- /* also build a custom data mask for dependencies that need certain layers */
-
- if (ob->type == OB_ARMATURE) {
- if (ob->pose) {
- bPoseChannel *pchan;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (!cti) {
- continue;
- }
-
- if (build_deg_tracking_constraints(dag, scene, scenenode, con, cti, node, true)) {
- /* pass */
- }
- else if (cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar && ct->tar != ob) {
- // fprintf(stderr, "armature %s target :%s\n", ob->id.name, target->id.name);
- node3 = dag_get_node(dag, ct->tar);
-
- if (ct->subtarget[0]) {
- dag_add_relation(dag, node3, node, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, cti->name);
- if (ct->tar->type == OB_MESH)
- node3->customdata_mask |= CD_MASK_MDEFORMVERT;
- }
- else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH,
- CONSTRAINT_TYPE_CLAMPTO,
- CONSTRAINT_TYPE_SPLINEIK,
- CONSTRAINT_TYPE_SHRINKWRAP))
- {
- dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name);
- }
- else {
- dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name);
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
-
- }
- }
- }
- }
-
- /* driver dependencies, nla modifiers */
-#if 0 // XXX old animation system
- if (ob->nlastrips.first) {
- bActionStrip *strip;
- bActionChannel *chan;
- for (strip = ob->nlastrips.first; strip; strip = strip->next) {
- if (strip->modifiers.first) {
- bActionModifier *amod;
- for (amod = strip->modifiers.first; amod; amod = amod->next) {
- if (amod->ob) {
- node2 = dag_get_node(dag, amod->ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "NLA Strip Modifier");
- }
- }
- }
- }
- }
-#endif // XXX old animation system
- if (ob->adt)
- dag_add_driver_relation(ob->adt, dag, node, (ob->type == OB_ARMATURE)); // XXX isdata arg here doesn't give an accurate picture of situation
-
- key = BKE_key_from_object(ob);
- if (key && key->adt)
- dag_add_driver_relation(key->adt, dag, node, 1);
-
- if (ob->modifiers.first) {
- ModifierData *md;
- ModifierUpdateDepsgraphContext ctx = {
- .scene = scene,
- .object = ob,
-
- .forest = dag,
- .obNode = node,
- };
- for (md = ob->modifiers.first; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (mti->updateDepgraph) mti->updateDepgraph(md, &ctx);
- }
- }
- if (ob->parent) {
- node2 = dag_get_node(dag, ob->parent);
-
- switch (ob->partype) {
- case PARSKEL:
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Parent");
- break;
- case PARVERT1: case PARVERT3:
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Vertex Parent");
- node2->customdata_mask |= CD_MASK_ORIGINDEX;
- break;
- case PARBONE:
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Bone Parent");
- break;
- default:
- if (ob->parent->type == OB_LATTICE)
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Lattice Parent");
- else if (ob->parent->type == OB_CURVE) {
- Curve *cu = ob->parent->data;
- if (cu->flag & CU_PATH)
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Curve Parent");
- else
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Curve Parent");
- }
- else
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Parent");
- break;
- }
- /* exception case: parent is duplivert */
- if (ob->type == OB_MBALL && (ob->parent->transflag & OB_DUPLIVERTS)) {
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Duplivert");
- }
-
- addtoroot = 0;
- }
- if (ob->proxy) {
- node2 = dag_get_node(dag, ob->proxy);
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Proxy");
- /* inverted relation, so addtoroot shouldn't be set to zero */
- }
-
- if (ob->transflag & OB_DUPLI) {
- if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
- GroupObject *go;
- for (go = ob->dup_group->gobject.first; go; go = go->next) {
- if (go->ob) {
- node2 = dag_get_node(dag, go->ob);
- /* node2 changes node1, this keeps animations updated in groups?? not logical? */
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Dupligroup");
- }
- }
- }
- }
-
- /* rigidbody force fields */
- if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_LATTICE)) {
- if (ob->rigidbody_object && scene->rigidbody_world) {
- dag_add_forcefield_relations(dag, scene, ob, node, scene->rigidbody_world->effector_weights, true, 0, "Force Field");
- }
- }
-
- /* object data drivers */
- if (ob->data) {
- AnimData *adt = BKE_animdata_from_id((ID *)ob->data);
- if (adt)
- dag_add_driver_relation(adt, dag, node, 1);
- }
-
- /* object type/data relationships */
- switch (ob->type) {
- case OB_CAMERA:
- {
- Camera *cam = (Camera *)ob->data;
-
- if (cam->dof_ob) {
- node2 = dag_get_node(dag, cam->dof_ob);
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Camera DoF");
- }
- break;
- }
- case OB_MBALL:
- {
- Object *mom = BKE_mball_basis_find(G.main, G.main->eval_ctx, scene, ob);
-
- if (mom != ob) {
- node2 = dag_get_node(dag, mom);
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Metaball"); /* mom depends on children! */
- }
- break;
- }
- case OB_CURVE:
- case OB_FONT:
- {
- Curve *cu = ob->data;
-
- if (cu->bevobj) {
- node2 = dag_get_node(dag, cu->bevobj);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Bevel");
- }
- if (cu->taperobj) {
- node2 = dag_get_node(dag, cu->taperobj);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Taper");
- }
- if (ob->type == OB_FONT) {
- /* Really rather dirty hack. needs to support font family to work
- * reliably on render export.
- *
- * This totally mimics behavior of regular verts duplication with
- * parenting. The only tricky thing here is to get list of objects
- * used for the custom "font".
- *
- * This shouldn't harm so much because this code only runs on DAG
- * rebuild and this feature is not that commonly used.
- *
- * - sergey -
- */
- if (cu->family[0] != '\n') {
- ListBase *duplilist;
- DupliObject *dob;
- duplilist = object_duplilist(G.main, G.main->eval_ctx, scene, ob);
- for (dob = duplilist->first; dob; dob = dob->next) {
- node2 = dag_get_node(dag, dob->ob);
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Object Font");
- }
- free_object_duplilist(duplilist);
- }
-
- if (cu->textoncurve) {
- node2 = dag_get_node(dag, cu->textoncurve);
- /* Text on curve requires path to be evaluated for the target curve. */
- node2->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Texture On Curve");
- }
- }
- break;
- }
- }
-
- /* material drivers */
- if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
- Material *ma = give_current_material(ob, a);
-
- if (ma) {
- /* recursively figure out if there are drivers, and hook these up to this object */
- dag_add_material_driver_relations(dag, node, ma);
- }
- }
- }
- else if (ob->type == OB_LAMP) {
- dag_add_lamp_driver_relations(dag, node, ob->data);
- }
-
- /* particles */
- psys = ob->particlesystem.first;
- if (psys) {
- GroupObject *go;
-
- for (; psys; psys = psys->next) {
- BoidRule *rule = NULL;
- BoidState *state = NULL;
- ParticleSettings *part = psys->part;
-
- if (part->adt) {
- dag_add_driver_relation(part->adt, dag, node, 1);
- }
-
- dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation");
-
- if (!psys_check_enabled(ob, psys, G.is_rendering))
- continue;
-
- if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
- ParticleTarget *pt = psys->targets.first;
-
- for (; pt; pt = pt->next) {
- if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) {
- node2 = dag_get_node(dag, pt->ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets");
- }
- }
- }
-
- if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
- node2 = dag_get_node(dag, part->dup_ob);
- /* note that this relation actually runs in the wrong direction, the problem
- * is that dupli system all have this (due to parenting), and the render
- * engine instancing assumes particular ordering of objects in list */
- dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization");
- if (part->dup_ob->type == OB_MBALL)
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization");
- }
-
- if (part->ren_as == PART_DRAW_GR && part->dup_group) {
- for (go = part->dup_group->gobject.first; go; go = go->next) {
- node2 = dag_get_node(dag, go->ob);
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization");
- }
- }
-
- if (part->type != PART_HAIR) {
- /* Actual code uses get_collider_cache */
- dag_add_collision_relations(dag, scene, ob, node, part->collision_group, ob->lay, eModifierType_Collision, NULL, true, "Particle Collision");
- }
- else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) {
- /* Hair uses cloth simulation, i.e. get_collision_objects */
- dag_add_collision_relations(dag, scene, ob, node, psys->clmd->coll_parms->group, ob->lay | scene->lay, eModifierType_Collision, NULL, true, "Hair Collision");
- }
-
- dag_add_forcefield_relations(dag, scene, ob, node, part->effector_weights, part->type == PART_HAIR, 0, "Particle Force Field");
-
- if (part->boids) {
- for (state = part->boids->states.first; state; state = state->next) {
- for (rule = state->rules.first; rule; rule = rule->next) {
- Object *ruleob = NULL;
- if (rule->type == eBoidRuleType_Avoid)
- ruleob = ((BoidRuleGoalAvoid *)rule)->ob;
- else if (rule->type == eBoidRuleType_FollowLeader)
- ruleob = ((BoidRuleFollowLeader *)rule)->ob;
-
- if (ruleob) {
- node2 = dag_get_node(dag, ruleob);
- dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Boid Rule");
- }
- }
- }
- }
- }
- }
-
- /* object constraints */
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (!cti)
- continue;
-
- /* special case for camera tracking -- it doesn't use targets to define relations */
- if (build_deg_tracking_constraints(dag, scene, scenenode, con, cti, node, false)) {
- addtoroot = 0;
- }
- else if (cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- Object *obt;
-
- if (ct->tar)
- obt = ct->tar;
- else
- continue;
-
- node2 = dag_get_node(dag, obt);
- if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name);
- else {
- if (ELEM(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) {
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name);
- if (obt->type == OB_MESH)
- node2->customdata_mask |= CD_MASK_MDEFORMVERT;
- }
- else if (cti->type == CONSTRAINT_TYPE_SHRINKWRAP) {
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name);
- }
- else {
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, cti->name);
- }
- }
- addtoroot = 0;
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
-
- if (addtoroot == 1)
- dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
-}
-
-static void build_dag_group(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Group *group, short mask)
-{
- GroupObject *go;
-
- if (group->id.tag & LIB_TAG_DOIT)
- return;
-
- group->id.tag |= LIB_TAG_DOIT;
-
- for (go = group->gobject.first; go; go = go->next) {
- build_dag_object(dag, scenenode, scene, go->ob, mask);
- if (go->ob->dup_group)
- build_dag_group(dag, scenenode, bmain, scene, go->ob->dup_group, mask);
- }
-}
-
-DagForest *build_dag(Main *bmain, Scene *sce, short mask)
-{
- Base *base;
- Object *ob;
- DagNode *node;
- DagNode *scenenode;
- DagForest *dag;
- DagAdjList *itA;
-
- dag = sce->theDag;
- if (dag)
- free_forest(dag);
- else {
- dag = dag_init();
- sce->theDag = dag;
- }
- dag->need_update = false;
-
- BKE_main_id_tag_idcode(bmain, ID_OB, LIB_TAG_DOIT, false);
-
- /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */
- BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- /* add base node for scene. scene is always the first node in DAG */
- scenenode = dag_add_node(dag, sce);
-
- /* add current scene objects */
- for (base = sce->base.first; base; base = base->next) {
- ob = base->object;
- ob->id.tag |= LIB_TAG_DOIT;
- build_dag_object(dag, scenenode, sce, ob, mask);
- if (ob->proxy)
- build_dag_object(dag, scenenode, sce, ob->proxy, mask);
- if (ob->dup_group)
- build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask);
- }
-
- /* There might be situations when object from current scene depends on
- * objects form other scene AND objects from other scene has own
- * dependencies on objects from other scene.
- *
- * This is really important to include such indirect dependencies in order
- * to keep threaded update safe but since we don't really know if object is
- * coming from current scene or another scene we do rather stupid tag-based
- * check here: all the objects for which build_dag_object() was called are
- * getting tagged with LIB_TAG_DOIT. This way if some node has untagged
- * object we know it's an object from other scene.
- *
- * It should be enough to to it once, because if there's longer chain of
- * indirect dependencies, all the new nodes will be added to the end of the
- * list, meaning we'll keep covering them in this for loop.
- */
- for (node = sce->theDag->DagNode.first; node != NULL; node = node->next) {
- if (node->type == ID_OB) {
- ob = node->ob;
- if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
- ob->id.tag |= LIB_TAG_DOIT;
- build_dag_object(dag, scenenode, sce, ob, mask);
- if (ob->proxy)
- build_dag_object(dag, scenenode, sce, ob->proxy, mask);
- if (ob->dup_group)
- build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask);
- }
- }
- }
-
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- /* Now all relations were built, but we need to solve 1 exceptional case;
- * When objects have multiple "parents" (for example parent + constraint working on same object)
- * the relation type has to be synced. One of the parents can change, and should give same event to child */
-
- /* nodes were callocced, so we can use node->color for temporal storage */
- for (node = sce->theDag->DagNode.first; node; node = node->next) {
- if (node->type == ID_OB) {
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- itA->node->color |= itA->type;
- }
- }
-
- /* also flush custom data mask */
- ((Object *)node->ob)->customdata_mask = node->customdata_mask;
-
- if (node->parent == NULL) {
- dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
- }
- }
- }
- /* now set relations equal, so that when only one parent changes, the correct recalcs are found */
- for (node = sce->theDag->DagNode.first; node; node = node->next) {
- if (node->type == ID_OB) {
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- itA->type |= itA->node->color;
- }
- }
- }
- }
-
- /* cycle detection and solving */
- // solve_cycles(dag);
-
- return dag;
-}
-
-
-void free_forest(DagForest *Dag)
-{ /* remove all nodes and deps */
- DagNode *tempN;
- DagAdjList *tempA;
- DagAdjList *itA;
- DagNode *itN = Dag->DagNode.first;
-
- while (itN) {
- itA = itN->child;
- while (itA) {
- tempA = itA;
- itA = itA->next;
- MEM_freeN(tempA);
- }
-
- itA = itN->parent;
- while (itA) {
- tempA = itA;
- itA = itA->next;
- MEM_freeN(tempA);
- }
-
- tempN = itN;
- itN = itN->next;
- MEM_freeN(tempN);
- }
-
- BLI_ghash_free(Dag->nodeHash, NULL, NULL);
- Dag->nodeHash = NULL;
- Dag->DagNode.first = NULL;
- Dag->DagNode.last = NULL;
- Dag->numNodes = 0;
-
-}
-
-DagNode *dag_find_node(DagForest *forest, void *fob)
-{
- if (forest->nodeHash)
- return BLI_ghash_lookup(forest->nodeHash, fob);
-
- return NULL;
-}
-
-static int dag_print_dependencies = 0; /* debugging */
-
-/* no checking of existence, use dag_find_node first or dag_get_node */
-DagNode *dag_add_node(DagForest *forest, void *fob)
-{
- DagNode *node;
-
- node = MEM_callocN(sizeof(DagNode), "DAG node");
- if (node) {
- node->ob = fob;
- node->color = DAG_WHITE;
-
- if (forest->ugly_hack_sorry) node->type = GS(((ID *) fob)->name); /* sorry, done for pose sorting */
- if (forest->numNodes) {
- ((DagNode *) forest->DagNode.last)->next = node;
- forest->DagNode.last = node;
- forest->numNodes++;
- }
- else {
- forest->DagNode.last = node;
- forest->DagNode.first = node;
- forest->numNodes = 1;
- }
-
- if (!forest->nodeHash)
- forest->nodeHash = BLI_ghash_ptr_new("dag_add_node gh");
- BLI_ghash_insert(forest->nodeHash, fob, node);
- }
-
- return node;
-}
-
-DagNode *dag_get_node(DagForest *forest, void *fob)
-{
- DagNode *node;
-
- node = dag_find_node(forest, fob);
- if (!node)
- node = dag_add_node(forest, fob);
- return node;
-}
-
-
-
-DagNode *dag_get_sub_node(DagForest *forest, void *fob)
-{
- DagNode *node;
- DagAdjList *mainchild, *prev = NULL;
-
- mainchild = ((DagNode *) forest->DagNode.first)->child;
- /* remove from first node (scene) adj list if present */
- while (mainchild) {
- if (mainchild->node == fob) {
- if (prev) {
- prev->next = mainchild->next;
- MEM_freeN(mainchild);
- break;
- }
- else {
- ((DagNode *) forest->DagNode.first)->child = mainchild->next;
- MEM_freeN(mainchild);
- break;
- }
- }
- prev = mainchild;
- mainchild = mainchild->next;
- }
- node = dag_find_node(forest, fob);
- if (!node)
- node = dag_add_node(forest, fob);
- return node;
-}
-
-static void dag_add_parent_relation(DagForest *UNUSED(forest), DagNode *fob1, DagNode *fob2, short rel, const char *name)
-{
- DagAdjList *itA = fob2->parent;
-
- while (itA) { /* search if relation exist already */
- if (itA->node == fob1) {
- itA->type |= rel;
- itA->count += 1;
- return;
- }
- itA = itA->next;
- }
- /* create new relation and insert at head. MALLOC alert! */
- itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list");
- itA->node = fob1;
- itA->type = rel;
- itA->count = 1;
- itA->next = fob2->parent;
- itA->name = name;
- fob2->parent = itA;
-}
-
-void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name)
-{
- DagAdjList *itA = fob1->child;
-
- /* parent relation is for cycle checking */
- dag_add_parent_relation(forest, fob1, fob2, rel, name);
-
- /* TODO(sergey): Find a better place for this. */
-#ifdef WITH_OPENSUBDIV
- if ((rel & (DAG_RL_DATA_DATA | DAG_RL_DATA_OB)) != 0) {
- if (fob1->type == ID_OB) {
- if ((fob1->eval_flags & DAG_EVAL_NEED_CPU) == 0) {
- Object *ob2 = fob2->ob;
- if (ob2->recalc & OB_RECALC_ALL) {
- /* Make sure object has all the data on CPU. */
- Object *ob1 = fob1->ob;
- ob1->recalc |= OB_RECALC_DATA;
- }
- fob1->eval_flags |= DAG_EVAL_NEED_CPU;
- }
- }
- }
-#endif
-
- while (itA) { /* search if relation exist already */
- if (itA->node == fob2) {
- itA->type |= rel;
- itA->count += 1;
- return;
- }
- itA = itA->next;
- }
- /* create new relation and insert at head. MALLOC alert! */
- itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list");
- itA->node = fob2;
- itA->type = rel;
- itA->count = 1;
- itA->next = fob1->child;
- itA->name = name;
- fob1->child = itA;
-}
-
-static const char *dag_node_name(DagForest *dag, DagNode *node)
-{
- if (node->ob == NULL)
- return "null";
- else if (dag->ugly_hack_sorry)
- return ((ID *)(node->ob))->name + 2;
- else
- return ((bPoseChannel *)(node->ob))->name;
-}
-
-static void dag_node_print_dependencies(DagForest *dag, DagNode *node)
-{
- DagAdjList *itA;
-
- printf("%s depends on:\n", dag_node_name(dag, node));
-
- for (itA = node->parent; itA; itA = itA->next)
- printf(" %s through %s\n", dag_node_name(dag, itA->node), itA->name);
- printf("\n");
-}
-
-static int dag_node_print_dependency_recurs(DagForest *dag, DagNode *node, DagNode *endnode)
-{
- DagAdjList *itA;
-
- if (node->color == DAG_BLACK)
- return 0;
-
- node->color = DAG_BLACK;
-
- if (node == endnode)
- return 1;
-
- for (itA = node->parent; itA; itA = itA->next) {
- if (dag_node_print_dependency_recurs(dag, itA->node, endnode)) {
- printf(" %s depends on %s through %s.\n", dag_node_name(dag, node), dag_node_name(dag, itA->node), itA->name);
- return 1;
- }
- }
-
- return 0;
-}
-
-static void dag_node_print_dependency_cycle(DagForest *dag, DagNode *startnode, DagNode *endnode, const char *name)
-{
- DagNode *node;
-
- for (node = dag->DagNode.first; node; node = node->next)
- node->color = DAG_WHITE;
-
- printf(" %s depends on %s through %s.\n", dag_node_name(dag, endnode), dag_node_name(dag, startnode), name);
- dag_node_print_dependency_recurs(dag, startnode, endnode);
- printf("\n");
-}
-
-static int dag_node_recurs_level(DagNode *node, int level)
-{
- DagAdjList *itA;
- int newlevel;
-
- node->color = DAG_BLACK; /* done */
- newlevel = ++level;
-
- for (itA = node->parent; itA; itA = itA->next) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->ancestor_count = dag_node_recurs_level(itA->node, level);
- newlevel = MAX2(newlevel, level + itA->node->ancestor_count);
- }
- else
- newlevel = MAX2(newlevel, level + itA->node->ancestor_count);
- }
-
- return newlevel;
-}
-
-static void dag_check_cycle(DagForest *dag)
-{
- DagNode *node;
- DagAdjList *itA;
-
- dag->is_acyclic = true;
-
- /* debugging print */
- if (dag_print_dependencies)
- for (node = dag->DagNode.first; node; node = node->next)
- dag_node_print_dependencies(dag, node);
-
- /* tag nodes unchecked */
- for (node = dag->DagNode.first; node; node = node->next)
- node->color = DAG_WHITE;
-
- for (node = dag->DagNode.first; node; node = node->next) {
- if (node->color == DAG_WHITE) {
- node->ancestor_count = dag_node_recurs_level(node, 0);
- }
- }
-
- /* check relations, and print errors */
- for (node = dag->DagNode.first; node; node = node->next) {
- for (itA = node->parent; itA; itA = itA->next) {
- if (itA->node->ancestor_count > node->ancestor_count) {
- if (node->ob && itA->node->ob) {
- dag->is_acyclic = false;
- printf("Dependency cycle detected:\n");
- dag_node_print_dependency_cycle(dag, itA->node, node, itA->name);
- }
- }
- }
- }
-
- /* parent relations are only needed for cycle checking, so free now */
- for (node = dag->DagNode.first; node; node = node->next) {
- while (node->parent) {
- itA = node->parent->next;
- MEM_freeN(node->parent);
- node->parent = itA;
- }
- }
-}
-
-/* debug test functions */
-
-void graph_print_queue(DagNodeQueue *nqueue)
-{
- DagNodeQueueElem *queueElem;
-
- queueElem = nqueue->first;
- while (queueElem) {
- fprintf(stderr, "** %s %i %i-%i ", ((ID *) queueElem->node->ob)->name, queueElem->node->color, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm);
- queueElem = queueElem->next;
- }
- fprintf(stderr, "\n");
-}
-
-void graph_print_queue_dist(DagNodeQueue *nqueue)
-{
- DagNodeQueueElem *queueElem;
- int count;
-
- queueElem = nqueue->first;
- count = 0;
- while (queueElem) {
- fprintf(stderr, "** %25s %2.2i-%2.2i ", ((ID *) queueElem->node->ob)->name, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm);
- while (count < queueElem->node->DFS_dvtm - 1) { fputc(' ', stderr); count++; }
- fputc('|', stderr);
- while (count < queueElem->node->DFS_fntm - 2) { fputc('-', stderr); count++; }
- fputc('|', stderr);
- fputc('\n', stderr);
- count = 0;
- queueElem = queueElem->next;
- }
- fprintf(stderr, "\n");
-}
-
-void graph_print_adj_list(DagForest *dag)
-{
- DagNode *node;
- DagAdjList *itA;
-
- node = dag->DagNode.first;
- while (node) {
- fprintf(stderr, "node : %s col: %i", ((ID *) node->ob)->name, node->color);
- itA = node->child;
- while (itA) {
- fprintf(stderr, "-- %s ", ((ID *) itA->node->ob)->name);
-
- itA = itA->next;
- }
- fprintf(stderr, "\n");
- node = node->next;
- }
-}
-
-/* ************************ API *********************** */
-
-/* mechanism to allow editors to be informed of depsgraph updates,
- * to do their own updates based on changes... */
-static void (*EditorsUpdateIDCb)(Main *bmain, ID *id) = NULL;
-static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NULL;
-static void (*EditorsUpdateScenePreCb)(Main *bmain, Scene *scene, bool time) = NULL;
-
-void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id),
- void (*scene_func)(Main *bmain, Scene *scene, int updated),
- void (*scene_pre_func)(Main *bmain, Scene *scene, bool time))
-{
- if (DEG_depsgraph_use_legacy()) {
- EditorsUpdateIDCb = id_func;
- EditorsUpdateSceneCb = scene_func;
- EditorsUpdateScenePreCb = scene_pre_func;
- }
- else {
- /* New dependency graph. */
- DEG_editors_set_update_cb(id_func, scene_func, scene_pre_func);
- }
-}
-
-void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time)
-{
- if (DEG_depsgraph_use_legacy()) {
- if (EditorsUpdateScenePreCb != NULL) {
- EditorsUpdateScenePreCb(bmain, scene, time);
- }
- }
- else {
- DEG_editors_update_pre(bmain, scene, time);
- }
-}
-
-static void dag_editors_id_update(Main *bmain, ID *id)
-{
- if (EditorsUpdateIDCb)
- EditorsUpdateIDCb(bmain, id);
-}
-
-static void dag_editors_scene_update(Main *bmain, Scene *scene, int updated)
-{
- if (EditorsUpdateSceneCb)
- EditorsUpdateSceneCb(bmain, scene, updated);
-}
-
-/* groups with objects in this scene need to be put in the right order as well */
-static void scene_sort_groups(Main *bmain, Scene *sce)
-{
- Base *base;
- Group *group;
- GroupObject *go;
- Object *ob;
-
- /* test; are group objects all in this scene? */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- ob->id.tag &= ~LIB_TAG_DOIT;
- }
- for (base = sce->base.first; base; base = base->next)
- base->object->id.tag |= LIB_TAG_DOIT;
-
- for (group = bmain->group.first; group; group = group->id.next) {
- for (go = group->gobject.first; go; go = go->next) {
- if ((go->ob->id.tag & LIB_TAG_DOIT) == 0)
- break;
- }
- /* this group is entirely in this scene */
- if (go == NULL) {
- ListBase listb = {NULL, NULL};
-
- for (go = group->gobject.first; go; go = go->next)
- go->ob->id.newid = (ID *)go;
-
- /* in order of sorted bases we reinsert group objects */
- for (base = sce->base.first; base; base = base->next) {
-
- if (base->object->id.newid) {
- go = (GroupObject *)base->object->id.newid;
- base->object->id.newid = NULL;
- BLI_remlink(&group->gobject, go);
- BLI_addtail(&listb, go);
- }
- }
- /* copy the newly sorted listbase */
- group->gobject = listb;
- }
- }
-
- /* newid abused for GroupObject, cleanup. */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- ob->id.newid = NULL;
- }
-}
-
-static void dag_scene_tag_rebuild(Scene *sce)
-{
- if (sce->theDag) {
- sce->theDag->need_update = true;
- }
-}
-
-/* free the depency graph */
-static void dag_scene_free(Scene *sce)
-{
- if (sce->theDag) {
- free_forest(sce->theDag);
- MEM_freeN(sce->theDag);
- sce->theDag = NULL;
- }
-}
-
-/* Check whether object data needs to be evaluated before it
- * might be used by others.
- *
- * Means that mesh object needs to have proper derivedFinal,
- * curves-typed objects are to have proper curve cache.
- *
- * Other objects or objects which are tagged for data update are
- * not considered to be in need of evaluation.
- */
-static bool check_object_needs_evaluation(Object *object)
-{
- if (object->recalc & OB_RECALC_ALL) {
- /* Object is tagged for update anyway, no need to re-tag it. */
- return false;
- }
-
- if (object->type == OB_MESH) {
- return object->derivedFinal == NULL;
- }
- else if (ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
- return object->curve_cache == NULL;
- }
-
- return false;
-}
-
-/* Check whether object data is tagged for update. */
-static bool check_object_tagged_for_update(Object *object)
-{
- if (object->recalc & OB_RECALC_ALL) {
- return true;
- }
-
- if (ELEM(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
- ID *data_id = object->data;
- return (data_id->recalc & ID_RECALC_ALL) != 0;
- }
-
- return false;
-}
-
-/* Flush changes from tagged objects in the scene to their
- * dependencies which are not evaluated yet.
- *
- * This is needed to ensure all the dependencies are met
- * before objects gets handled by object_handle_update(),
- *
- * This is needed when visible layers are changed or changing
- * scene graph layout which involved usage of objects which
- * aren't in the scene or weren't visible yet.
- */
-static void dag_invisible_dependencies_flush(Scene *scene)
-{
- DagNode *root_node = scene->theDag->DagNode.first, *node;
- DagNodeQueue *queue;
-
- for (node = root_node; node != NULL; node = node->next) {
- node->color = DAG_WHITE;
- }
-
- queue = queue_create(DAGQUEUEALLOC);
-
- for (node = root_node; node != NULL; node = node->next) {
- if (node->color == DAG_WHITE) {
- push_stack(queue, node);
- node->color = DAG_GRAY;
-
- while (queue->count) {
- DagNode *current_node = get_top_node_queue(queue);
- DagAdjList *itA;
- bool skip = false;
-
- for (itA = current_node->child; itA; itA = itA->next) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->color = DAG_GRAY;
- push_stack(queue, itA->node);
- skip = true;
- break;
- }
- }
-
- if (!skip) {
- current_node = pop_queue(queue);
-
- if (current_node->type == ID_OB) {
- Object *current_object = current_node->ob;
- if (check_object_needs_evaluation(current_object)) {
- for (itA = current_node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- Object *object = itA->node->ob;
- if (check_object_tagged_for_update(object)) {
- current_object->recalc |= OB_RECALC_OB | OB_RECALC_DATA;
- }
- }
- }
- }
- }
- node->color = DAG_BLACK;
- }
- }
- }
- }
-
- queue_delete(queue);
-}
-
-static void dag_invisible_dependencies_check_flush(Main *bmain, Scene *scene)
-{
- if (DAG_id_type_tagged(bmain, ID_OB) ||
- DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */
- DAG_id_type_tagged(bmain, ID_CU) || /* Curve */
- DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */
- DAG_id_type_tagged(bmain, ID_LT)) /* Lattice */
- {
- dag_invisible_dependencies_flush(scene);
- }
-}
-
-/* sort the base list on dependency order */
-static void dag_scene_build(Main *bmain, Scene *sce)
-{
- DagNode *node, *rootnode;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
- int time;
- int skip = 0;
- ListBase tempbase;
- Base *base;
-
- BLI_listbase_clear(&tempbase);
-
- build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA);
-
- dag_check_cycle(sce->theDag);
-
- nqueue = queue_create(DAGQUEUEALLOC);
-
- for (node = sce->theDag->DagNode.first; node; node = node->next) {
- node->color = DAG_WHITE;
- }
-
- time = 1;
-
- rootnode = sce->theDag->DagNode.first;
- rootnode->color = DAG_GRAY;
- time++;
- push_stack(nqueue, rootnode);
-
- while (nqueue->count) {
-
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->DFS_dvtm = time;
- itA->node->color = DAG_GRAY;
-
- time++;
- push_stack(nqueue, itA->node);
- skip = 1;
- break;
- }
- itA = itA->next;
- }
-
- if (!skip) {
- if (node) {
- node = pop_queue(nqueue);
- if (node->ob == sce) /* we are done */
- break;
- node->color = DAG_BLACK;
-
- time++;
- base = sce->base.first;
- while (base && base->object != node->ob)
- base = base->next;
- if (base) {
- BLI_remlink(&sce->base, base);
- BLI_addhead(&tempbase, base);
- }
- }
- }
- }
-
- /* temporal correction for circular dependencies */
- base = sce->base.first;
- while (base) {
- BLI_remlink(&sce->base, base);
- BLI_addhead(&tempbase, base);
- //if (G.debug & G_DEBUG)
- printf("cyclic %s\n", base->object->id.name);
- base = sce->base.first;
- }
-
- sce->base = tempbase;
- queue_delete(nqueue);
-
- /* all groups with objects in this scene gets resorted too */
- scene_sort_groups(bmain, sce);
-
- if (G.debug & G_DEBUG) {
- printf("\nordered\n");
- for (base = sce->base.first; base; base = base->next) {
- printf(" %s\n", base->object->id.name);
- }
- }
-
- /* Make sure that new dependencies which came from invisible layers
- * are tagged for update (if they're needed for objects which were
- * tagged for update).
- */
- dag_invisible_dependencies_check_flush(bmain, sce);
-}
-
-/* clear all dependency graphs */
-void DAG_relations_tag_update(Main *bmain)
-{
- if (DEG_depsgraph_use_legacy()) {
- Scene *sce;
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- dag_scene_tag_rebuild(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)
-{
- 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 (DEG_depsgraph_use_legacy()) {
- if (!sce->theDag || sce->theDag->need_update)
- 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 (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;
- }
- }
-}
-
-static void lib_id_recalc_tag(Main *bmain, ID *id)
-{
- id->recalc |= ID_RECALC;
- DAG_id_type_tag(bmain, GS(id->name));
-}
-
-static void lib_id_recalc_data_tag(Main *bmain, ID *id)
-{
- id->recalc |= ID_RECALC_DATA;
- DAG_id_type_tag(bmain, GS(id->name));
-}
-
-/* node was checked to have lasttime != curtime and is if type ID_OB */
-static void flush_update_node(Main *bmain, DagNode *node, unsigned int layer, int curtime)
-{
- DagAdjList *itA;
- Object *ob, *obc;
- int oldflag;
- bool changed = false;
- unsigned int all_layer;
-
- node->lasttime = curtime;
-
- ob = node->ob;
- if (ob && (ob->recalc & OB_RECALC_ALL)) {
- all_layer = node->scelay;
-
- /* got an object node that changes, now check relations */
- for (itA = node->child; itA; itA = itA->next) {
- all_layer |= itA->lay;
- /* the relationship is visible */
- if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit)
- if (itA->node->type == ID_OB) {
- obc = itA->node->ob;
- oldflag = obc->recalc;
-
- /* got a ob->obc relation, now check if flag needs flush */
- if (ob->recalc & OB_RECALC_OB) {
- if (itA->type & DAG_RL_OB_OB) {
- //printf("ob %s changes ob %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_OB;
- lib_id_recalc_tag(bmain, &obc->id);
- }
- if (itA->type & DAG_RL_OB_DATA) {
- //printf("ob %s changes obdata %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obc->id);
- }
- }
- if (ob->recalc & OB_RECALC_DATA) {
- if (itA->type & DAG_RL_DATA_OB) {
- //printf("obdata %s changes ob %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_OB;
- lib_id_recalc_tag(bmain, &obc->id);
- }
- if (itA->type & DAG_RL_DATA_DATA) {
- //printf("obdata %s changes obdata %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obc->id);
- }
- }
- if (oldflag != obc->recalc) changed = 1;
- }
- }
- }
- /* even nicer, we can clear recalc flags... */
- if ((all_layer & layer) == 0) { // XXX && (ob != obedit)) {
- /* but existing displaylists or derivedmesh should be freed */
- if (ob->recalc & OB_RECALC_DATA)
- BKE_object_free_derived_caches(ob);
-
- ob->recalc &= ~OB_RECALC_ALL;
- }
- }
-
- /* check case where child changes and parent forcing obdata to change */
- /* should be done regardless if this ob has recalc set */
- /* could merge this in with loop above...? (ton) */
- for (itA = node->child; itA; itA = itA->next) {
- /* the relationship is visible */
- if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit)
- if (itA->node->type == ID_OB) {
- obc = itA->node->ob;
- /* child moves */
- if ((obc->recalc & OB_RECALC_ALL) == OB_RECALC_OB) {
- /* parent has deforming info */
- if (itA->type & (DAG_RL_OB_DATA | DAG_RL_DATA_DATA)) {
- // printf("parent %s changes ob %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obc->id);
- }
- }
- }
- }
- }
-
- /* we only go deeper if node not checked or something changed */
- for (itA = node->child; itA; itA = itA->next) {
- if (changed || itA->node->lasttime != curtime)
- flush_update_node(bmain, itA->node, layer, curtime);
- }
-
-}
-
-/* node was checked to have lasttime != curtime, and is of type ID_OB */
-static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime)
-{
- DagAdjList *itA;
-
- node->lasttime = curtime;
- node->lay = node->scelay;
-
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- if (itA->node->lasttime != curtime) {
- itA->lay = flush_layer_node(sce, itA->node, curtime); /* lay is only set once for each relation */
- }
- else {
- itA->lay = itA->node->lay;
- }
-
- node->lay |= itA->lay;
- }
- }
-
- return node->lay;
-}
-
-/* node was checked to have lasttime != curtime, and is of type ID_OB */
-static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node,
- int curtime, unsigned int lay, bool reset)
-{
- DagAdjList *itA;
- Object *ob;
-
- node->lasttime = curtime;
-
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- if (itA->node->lasttime != curtime) {
- ob = (Object *)(itA->node->ob);
-
- if (reset || (ob->recalc & OB_RECALC_ALL)) {
- if (BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH)) {
- /* Don't tag nodes which are on invisible layer. */
- if (itA->node->lay & lay) {
- ob->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &ob->id);
- }
- }
-
- flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, true);
- }
- else
- flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, false);
- }
- }
- }
-}
-
-/* flush layer flags to dependencies */
-static void dag_scene_flush_layers(Scene *sce, int lay)
-{
- DagNode *node, *firstnode;
- DagAdjList *itA;
- Base *base;
- int lasttime;
-
- firstnode = sce->theDag->DagNode.first; /* always scene node */
-
- for (itA = firstnode->child; itA; itA = itA->next)
- itA->lay = 0;
-
- sce->theDag->time++; /* so we know which nodes were accessed */
- lasttime = sce->theDag->time;
-
- /* update layer flags in nodes */
- for (base = sce->base.first; base; base = base->next) {
- node = dag_get_node(sce->theDag, base->object);
- node->scelay = base->object->lay;
- }
-
- /* ensure cameras are set as if they are on a visible layer, because
- * they ared still used for rendering or setting the camera view
- *
- * XXX, this wont work for local view / unlocked camera's */
- if (sce->camera) {
- node = dag_get_node(sce->theDag, sce->camera);
- node->scelay |= lay;
- }
-
-#ifdef DURIAN_CAMERA_SWITCH
- {
- TimeMarker *m;
-
- for (m = sce->markers.first; m; m = m->next) {
- if (m->camera) {
- node = dag_get_node(sce->theDag, m->camera);
- node->scelay |= lay;
- }
- }
- }
-#endif
-
- /* flush layer nodes to dependencies */
- for (itA = firstnode->child; itA; itA = itA->next)
- if (itA->node->lasttime != lasttime && itA->node->type == ID_OB)
- flush_layer_node(sce, itA->node, lasttime);
-}
-
-static void dag_tag_renderlayers(Scene *sce, unsigned int lay)
-{
- if (sce->nodetree) {
- bNode *node;
- Base *base;
- unsigned int lay_changed = 0;
-
- for (base = sce->base.first; base; base = base->next)
- if (base->lay & lay)
- if (base->object->recalc)
- lay_changed |= base->lay;
-
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->id == (ID *)sce) {
- SceneRenderLayer *srl = BLI_findlink(&sce->r.layers, node->custom1);
- if (srl && (srl->lay & lay_changed))
- nodeUpdate(sce->nodetree, node);
- }
- }
- }
-}
-
-/* flushes all recalc flags in objects down the dependency tree */
-void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const short time)
-{
- DagNode *firstnode;
- DagAdjList *itA;
- Object *ob;
- int lasttime;
-
- if (!DEG_depsgraph_use_legacy()) {
- DEG_scene_flush_update(bmain, sce);
- return;
- }
-
- if (sce->theDag == NULL || sce->theDag->need_update) {
- printf("DAG zero... not allowed to happen!\n");
- DAG_scene_relations_update(bmain, sce);
- }
-
- firstnode = sce->theDag->DagNode.first; /* always scene node */
-
- /* first we flush the layer flags */
- dag_scene_flush_layers(sce, lay);
-
- /* then we use the relationships + layer info to flush update events */
- sce->theDag->time++; /* so we know which nodes were accessed */
- lasttime = sce->theDag->time;
- for (itA = firstnode->child; itA; itA = itA->next)
- if (itA->node->lasttime != lasttime && itA->node->type == ID_OB)
- flush_update_node(bmain, itA->node, lay, lasttime);
-
- /* if update is not due to time change, do pointcache clears */
- if (!time) {
- sce->theDag->time++; /* so we know which nodes were accessed */
- lasttime = sce->theDag->time;
- for (itA = firstnode->child; itA; itA = itA->next) {
- if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) {
- ob = (Object *)(itA->node->ob);
-
- if (ob->recalc & OB_RECALC_ALL) {
- if (BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH)) {
- ob->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &ob->id);
- }
-
- flush_pointcache_reset(bmain, sce, itA->node, lasttime,
- lay, true);
- }
- else
- flush_pointcache_reset(bmain, sce, itA->node, lasttime,
- lay, false);
- }
- }
- }
-
- dag_tag_renderlayers(sce, lay);
-}
-
-static bool modifier_nlastrips_use_time(ListBase *strips)
-{
- NlaStrip *strip;
-
- if (strips) {
- for (strip = strips->first; strip; strip = strip->next) {
- if (modifier_nlastrips_use_time(&strip->strips)) {
- return true;
- }
- else if (strip->act) {
- FCurve *fcu;
-
- for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, "modifiers["))
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-static bool object_modifiers_use_time(Object *ob)
-{
- ModifierData *md;
-
- /* check if a modifier in modifier stack needs time input */
- for (md = ob->modifiers.first; md; md = md->next) {
- if (modifier_dependsOnTime(md))
- return true;
- }
-
- /* check whether any modifiers are animated */
- if (ob->adt) {
- AnimData *adt = ob->adt;
- NlaTrack *nlt;
- FCurve *fcu;
-
- /* action - check for F-Curves with paths containing 'modifiers[' */
- if (adt->action) {
- for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, "modifiers["))
- 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 = adt->drivers.first; fcu; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, "modifiers["))
- return true;
- }
-
- /* Also check NLA Strips... [#T45938] */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- if (modifier_nlastrips_use_time(&nlt->strips))
- return true;
- }
- }
-
- return false;
-}
-
-static short animdata_use_time(AnimData *adt)
-{
- NlaTrack *nlt;
-
- if (adt == NULL) return 0;
-
- /* check action - only if assigned, and it has anim curves */
- if (adt->action && adt->action->curves.first)
- return 1;
-
- /* check NLA tracks + strips */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- if (nlt->strips.first)
- return 1;
- }
-
- /* If we have drivers, more likely than not, on a frame change
- * they'll need updating because their owner changed
- *
- * This is kindof a hack to get around a whole host of problems
- * involving drivers using non-object datablock data (which the
- * depsgraph currently has no way of representing let alone correctly
- * dependency sort+tagging). By doing this, at least we ensure that
- * some commonly attempted drivers (such as scene -> current frame;
- * see "Driver updates fail" thread on Bf-committers dated July 2)
- * will work correctly, and that other non-object datablocks will have
- * their drivers update at least on frame change.
- *
- * -- Aligorith, July 4 2011
- */
- if (adt->drivers.first)
- return 1;
-
- return 0;
-}
-
-static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
-{
- if (ob->constraints.first) {
- bConstraint *con;
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti) {
- /* special case for camera tracking -- it doesn't use targets to define relations */
- if (ELEM(cti->type,
- CONSTRAINT_TYPE_FOLLOWTRACK,
- CONSTRAINT_TYPE_CAMERASOLVER,
- CONSTRAINT_TYPE_OBJECTSOLVER,
- CONSTRAINT_TYPE_TRANSFORM_CACHE))
- {
- ob->recalc |= OB_RECALC_OB;
- }
- else if (cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar) {
- ob->recalc |= OB_RECALC_OB;
- break;
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
-
- }
- }
- }
-
- if (ob->parent) {
- /* motion path or bone child */
- if (ob->parent->type == OB_CURVE || ob->parent->type == OB_ARMATURE) ob->recalc |= OB_RECALC_OB;
- }
-
-#if 0 // XXX old animation system
- if (ob->nlastrips.first) {
- if (ob->dup_group) {
- bActionStrip *strip;
- /* this case is for groups with nla, whilst nla target has no action or nla */
- for (strip = ob->nlastrips.first; strip; strip = strip->next) {
- if (strip->object)
- strip->object->recalc |= OB_RECALC_ALL;
- }
- }
- }
-#endif // XXX old animation system
-
- if (animdata_use_time(ob->adt)) {
- ob->recalc |= OB_RECALC_OB;
- ob->adt->recalc |= ADT_RECALC_ANIM;
- }
-
- if ((ob->adt) && (ob->type == OB_ARMATURE)) ob->recalc |= OB_RECALC_DATA;
-
- if (object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA;
- if ((ob->pose) && (ob->pose->flag & POSE_CONSTRAINTS_TIMEDEPEND)) ob->recalc |= OB_RECALC_DATA;
-
- // XXX: scene here may not be the scene that contains the rigidbody world affecting this!
- if (ob->rigidbody_object && BKE_scene_check_rigidbody_active(scene))
- ob->recalc |= OB_RECALC_OB;
-
- {
- AnimData *adt = BKE_animdata_from_id((ID *)ob->data);
- Mesh *me;
- Curve *cu;
- Lattice *lt;
-
- switch (ob->type) {
- case OB_MESH:
- me = ob->data;
- if (me->key) {
- if (!(ob->shapeflag & OB_SHAPE_LOCK)) {
- ob->recalc |= OB_RECALC_DATA;
- }
- }
- if (ob->particlesystem.first)
- ob->recalc |= OB_RECALC_DATA;
- break;
- case OB_CURVE:
- case OB_SURF:
- cu = ob->data;
- if (cu->key) {
- if (!(ob->shapeflag & OB_SHAPE_LOCK)) {
- ob->recalc |= OB_RECALC_DATA;
- }
- }
- break;
- case OB_FONT:
- cu = ob->data;
- if (cu->str && cu->vfont) {
- /* Can be in the curve-cache or the curve. */
- if (ob->curve_cache && !BLI_listbase_is_empty(&ob->curve_cache->disp)) {
- /* pass */
- }
- else if (!BLI_listbase_is_empty(&cu->nurb)) {
- /* pass */
- }
- else {
- ob->recalc |= OB_RECALC_DATA;
- }
- }
- break;
- case OB_LATTICE:
- lt = ob->data;
- if (lt->key) {
- if (!(ob->shapeflag & OB_SHAPE_LOCK)) {
- ob->recalc |= OB_RECALC_DATA;
- }
- }
- break;
- case OB_MBALL:
- if (ob->transflag & OB_DUPLI) ob->recalc |= OB_RECALC_DATA;
- break;
- case OB_EMPTY:
- /* update animated images */
- if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
- if (BKE_image_is_animated(ob->data))
- ob->recalc |= OB_RECALC_DATA;
- break;
- }
-
- if (animdata_use_time(adt)) {
- ob->recalc |= OB_RECALC_DATA;
- adt->recalc |= ADT_RECALC_ANIM;
- }
-
- if (ob->particlesystem.first) {
- ParticleSystem *psys = ob->particlesystem.first;
-
- for (; psys; psys = psys->next) {
- if (psys_check_enabled(ob, psys, G.is_rendering)) {
- ob->recalc |= OB_RECALC_DATA;
- break;
- }
- }
- }
- }
-
- if (ob->recalc & OB_RECALC_OB)
- lib_id_recalc_tag(bmain, &ob->id);
- if (ob->recalc & OB_RECALC_DATA)
- lib_id_recalc_data_tag(bmain, &ob->id);
-
-}
-
-/* recursively update objects in groups, each group is done at most once */
-static void dag_group_update_flags(Main *bmain, Scene *scene, Group *group, const bool do_time)
-{
- GroupObject *go;
-
- if (group->id.tag & LIB_TAG_DOIT)
- return;
-
- group->id.tag |= LIB_TAG_DOIT;
-
- for (go = group->gobject.first; go; go = go->next) {
- if (do_time)
- dag_object_time_update_flags(bmain, scene, go->ob);
- if (go->ob->dup_group)
- dag_group_update_flags(bmain, scene, go->ob->dup_group, do_time);
- }
-}
-
-/* flag all objects that need recalc, for changes in time for example */
-/* do_time: make this optional because undo resets objects to their animated locations without this */
-void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const bool do_time, const bool do_invisible_flush)
-{
- Base *base;
- Object *ob;
- Group *group;
- GroupObject *go;
- Scene *sce_iter;
-
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- /* set ob flags where animated systems are */
- for (SETLOOPER(scene, sce_iter, base)) {
- ob = base->object;
-
- if (do_time) {
- /* now if DagNode were part of base, the node->lay could be checked... */
- /* we do all now, since the scene_flush checks layers and clears recalc flags even */
-
- /* NOTE: "sce_iter" not "scene" so that rigidbodies in background scenes work
- * (i.e. muting + rbw availability can be checked and tagged properly) [#33970]
- */
- dag_object_time_update_flags(bmain, sce_iter, ob);
- }
-
- /* recursively tag groups with LIB_TAG_DOIT, and update flags for objects */
- if (ob->dup_group)
- dag_group_update_flags(bmain, scene, ob->dup_group, do_time);
- }
-
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
- DAG_scene_flush_update(bmain, sce_iter, lay, 1);
-
- if (do_time) {
- /* test: set time flag, to disable baked systems to update */
- for (SETLOOPER(scene, sce_iter, base)) {
- ob = base->object;
- if (ob->recalc & OB_RECALC_ALL)
- ob->recalc |= OB_RECALC_TIME;
- }
-
- /* hrmf... an exception to look at once, for invisible camera object we do it over */
- if (scene->camera)
- dag_object_time_update_flags(bmain, scene, scene->camera);
- }
-
- /* and store the info in groupobject */
- for (group = bmain->group.first; group; group = group->id.next) {
- if (group->id.tag & LIB_TAG_DOIT) {
- for (go = group->gobject.first; go; go = go->next) {
- go->recalc = go->ob->recalc;
- // printf("ob %s recalc %d\n", go->ob->id.name, go->recalc);
- }
- group->id.tag &= ~LIB_TAG_DOIT;
- }
- }
-
- if (do_invisible_flush) {
- dag_invisible_dependencies_check_flush(bmain, scene);
- }
-}
-
-/* struct returned by DagSceneLayer */
-typedef struct DagSceneLayer {
- struct DagSceneLayer *next, *prev;
- Scene *scene;
- unsigned int layer;
-} DagSceneLayer;
-
-/* returns visible scenes with valid DAG */
-static void dag_current_scene_layers(Main *bmain, ListBase *lb)
-{
- wmWindowManager *wm;
- wmWindow *win;
-
- BLI_listbase_clear(lb);
-
- /* if we have a windowmanager, look into windows */
- if ((wm = bmain->wm.first)) {
-
- BKE_main_id_flag_listbase(&bmain->scene, LIB_TAG_DOIT, 1);
-
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen && win->screen->scene->theDag) {
- Scene *scene = win->screen->scene;
- DagSceneLayer *dsl;
-
- if (scene->id.tag & LIB_TAG_DOIT) {
- dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer");
-
- BLI_addtail(lb, dsl);
-
- dsl->scene = scene;
- dsl->layer = BKE_screen_visible_layers(win->screen, scene);
-
- scene->id.tag &= ~LIB_TAG_DOIT;
- }
- else {
- /* It is possible that multiple windows shares the same scene
- * and have different layers visible.
- *
- * Here we deal with such cases by squashing layers bits from
- * multiple windoew to the DagSceneLayer.
- *
- * TODO(sergey): Such a lookup could be optimized perhaps,
- * however should be fine for now since we usually have only
- * few open windows.
- */
- for (dsl = lb->first; dsl; dsl = dsl->next) {
- if (dsl->scene == scene) {
- dsl->layer |= BKE_screen_visible_layers(win->screen, scene);
- break;
- }
- }
- }
- }
- }
- }
- else {
- /* if not, use the first sce */
- DagSceneLayer *dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer");
-
- BLI_addtail(lb, dsl);
-
- dsl->scene = bmain->scene.first;
- dsl->layer = dsl->scene->lay;
-
- /* XXX for background mode, we should get the scene
- * from somewhere, for the -S option, but it's in
- * the context, how to get it here? */
- }
-}
-
-static void dag_group_on_visible_update(Scene *scene, Group *group)
-{
- GroupObject *go;
-
- if (group->id.tag & LIB_TAG_DOIT)
- return;
-
- group->id.tag |= LIB_TAG_DOIT;
-
- for (go = group->gobject.first; go; go = go->next) {
- if (ELEM(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
- go->ob->recalc |= OB_RECALC_DATA;
- go->ob->id.tag |= LIB_TAG_DOIT;
- lib_id_recalc_tag(G.main, &go->ob->id);
- }
- if (go->ob->proxy_from) {
- go->ob->recalc |= OB_RECALC_OB;
- go->ob->id.tag |= LIB_TAG_DOIT;
- lib_id_recalc_tag(G.main, &go->ob->id);
- }
-
- if (go->ob->dup_group)
- dag_group_on_visible_update(scene, go->ob->dup_group);
- }
-}
-
-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);
-
- for (dsl = listbase.first; dsl; dsl = dsl->next) {
- Scene *scene = dsl->scene;
- Scene *sce_iter;
- Base *base;
- Object *ob;
- DagNode *node;
- unsigned int lay = dsl->layer, oblay;
-
- /* derivedmeshes and displists are not saved to file so need to be
- * remade, tag them so they get remade in the scene update loop,
- * note armature poses or object matrices are preserved and do not
- * require updates, so we skip those */
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
- dag_scene_flush_layers(sce_iter, lay);
-
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- for (SETLOOPER(scene, sce_iter, base)) {
- ob = base->object;
- node = (sce_iter->theDag) ? dag_get_node(sce_iter->theDag, ob) : NULL;
- oblay = (node) ? node->lay : ob->lay;
-
- if ((oblay & lay) & ~scene->lay_updated) {
- /* 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);
- }
- /* This should not be needed here, but in some cases, like after a redo, we can end up with
- * a wrong final matrix (see T42472).
- * Quoting Sergey, this comes from BKE_object_handle_update_ex, which is calling
- * BKE_object_where_is_calc_ex when it shouldn't, but that issue is not easily fixable.
- */
- else {
- ob->recalc |= OB_RECALC_OB;
- lib_id_recalc_tag(bmain, &ob->id);
- }
- if (ob->proxy && (ob->proxy_group == NULL)) {
- ob->proxy->recalc |= OB_RECALC_DATA;
- lib_id_recalc_tag(bmain, &ob->id);
- }
- if (ob->dup_group)
- dag_group_on_visible_update(scene, ob->dup_group);
- }
- }
-
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- /* now tag update flags, to ensure deformers get calculated on redraw */
- DAG_scene_update_flags(bmain, scene, lay, do_time, true);
- scene->lay_updated |= lay;
- }
-
- BLI_freelistN(&listbase);
-
- /* hack to get objects updating on layer changes */
- DAG_id_type_tag(bmain, ID_OB);
-
- /* so masks update on load */
- if (bmain->mask.first) {
- Mask *mask;
-
- for (mask = bmain->mask.first; mask; mask = mask->id.next) {
- DAG_id_tag_update(&mask->id, 0);
- }
- }
-}
-
-static void dag_id_flush_update__isDependentTexture(
- void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cb_flag))
-{
- struct { ID *id; bool is_dependent; } *data = userData;
-
- if (*idpoin && GS((*idpoin)->name) == ID_TE) {
- if (data->id == (*idpoin))
- data->is_dependent = 1;
- }
-}
-
-static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
-{
- Object *obt, *ob = NULL;
- short idtype;
-
- /* here we flush a few things before actual scene wide flush, mostly
- * due to only objects and not other datablocks being in the depsgraph */
-
- /* set flags & pointcache for object */
- if (GS(id->name) == ID_OB) {
- ob = (Object *)id;
- BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH);
-
- /* So if someone tagged object recalc directly,
- * id_tag_update bit-field stays relevant
- */
- if (ob->recalc & OB_RECALC_ALL) {
- DAG_id_type_tag(bmain, GS(id->name));
- }
-
- if (ob->recalc & OB_RECALC_DATA) {
- /* all users of this ob->data should be checked */
- id = ob->data;
-
- /* no point in trying in this cases */
- if (id && id->us <= 1) {
- dag_editors_id_update(bmain, id);
- id = NULL;
- }
- }
- }
-
- /* set flags & pointcache for object data */
- if (id) {
- idtype = GS(id->name);
-
-
- if (OB_DATA_SUPPORT_ID(idtype)) {
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- if (!(ob && obt == ob) && obt->data == id) {
- obt->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obt->id);
- BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
- }
- }
- }
- else if (idtype == ID_VF) {
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- if (obt->type == OB_FONT) {
- Curve *cu = obt->data;
- if (ELEM((struct VFont *)id, CURVE_VFONT_ANY(cu))) {
- obt->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obt->id);
- }
- }
- }
- }
-
- /* set flags based on textures - can influence depgraph via modifiers */
- if (idtype == ID_TE) {
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- struct { ID *id; bool is_dependent; } data;
- data.id = id;
- data.is_dependent = 0;
-
- modifiers_foreachIDLink(obt, dag_id_flush_update__isDependentTexture, &data);
- if (data.is_dependent) {
- obt->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obt->id);
- }
-
- /* particle settings can use the texture as well */
- if (obt->particlesystem.first) {
- ParticleSystem *psys = obt->particlesystem.first;
- MTex **mtexp, *mtex;
- int a;
- for (; psys; psys = psys->next) {
- mtexp = psys->part->mtex;
- for (a = 0; a < MAX_MTEX; a++, mtexp++) {
- mtex = *mtexp;
- if (mtex && mtex->tex == (Tex *)id) {
- obt->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obt->id);
-
- if (mtex->mapto & PAMAP_INIT)
- psys->recalc |= PSYS_RECALC_RESET;
- if (mtex->mapto & PAMAP_CHILD)
- psys->recalc |= PSYS_RECALC_CHILD;
-
- BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
- }
- }
- }
- }
- }
- }
-
- /* set flags based on ShapeKey */
- if (idtype == ID_KE) {
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- Key *key = BKE_key_from_object(obt);
- if (!(ob && obt == ob) && ((ID *)key == id)) {
- obt->flag |= (OB_RECALC_OB | OB_RECALC_DATA);
- lib_id_recalc_tag(bmain, &obt->id);
- lib_id_recalc_data_tag(bmain, &obt->id);
- BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
- }
- }
- }
-
- /* set flags based on particle settings */
- if (idtype == ID_PA) {
- ParticleSystem *psys;
- for (obt = bmain->object.first; obt; obt = obt->id.next)
- for (psys = obt->particlesystem.first; psys; psys = psys->next)
- if (&psys->part->id == id)
- BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
- }
-
- if (ELEM(idtype, ID_MA, ID_TE)) {
- obt = sce->basact ? sce->basact->object : NULL;
- if (obt && obt->mode & OB_MODE_TEXTURE_PAINT) {
- BKE_texpaint_slots_refresh_object(sce, obt);
- BKE_paint_proj_mesh_data_check(sce, obt, NULL, NULL, NULL, NULL);
- GPU_drawobject_free(obt->derivedFinal);
- }
- }
-
- if (idtype == ID_MC) {
- MovieClip *clip = (MovieClip *) id;
-
- BKE_tracking_dopesheet_tag_update(&clip->tracking);
-
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- bConstraint *con;
- for (con = obt->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER,
- CONSTRAINT_TYPE_OBJECTSOLVER))
- {
- obt->recalc |= OB_RECALC_OB;
- lib_id_recalc_tag(bmain, &obt->id);
- break;
- }
- }
- }
-
- if (sce->nodetree) {
- bNode *node;
-
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->id == id) {
- nodeUpdate(sce->nodetree, node);
- }
- }
- }
- }
-
- /* Not pretty to iterate all the nodes here, but it's as good as it
- * could be with the current depsgraph design/
- */
- if (idtype == ID_IM) {
- FOREACH_NODETREE(bmain, ntree, parent_id) {
- if (ntree->type == NTREE_SHADER) {
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id == id) {
- lib_id_recalc_tag(bmain, &ntree->id);
- break;
- }
- }
- }
- } FOREACH_NODETREE_END
- }
-
- if (idtype == ID_MSK) {
- if (sce->nodetree) {
- bNode *node;
-
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->id == id) {
- nodeUpdate(sce->nodetree, node);
- }
- }
- }
- }
-
- /* camera's matrix is used to orient reconstructed stuff,
- * so it should happen tracking-related constraints recalculation
- * when camera is changing (sergey) */
- if (sce->camera && &sce->camera->id == id) {
- MovieClip *clip = BKE_object_movieclip_get(sce, sce->camera, true);
-
- if (clip)
- dag_id_flush_update(bmain, sce, &clip->id);
- }
-
- /* update editors */
- dag_editors_id_update(bmain, id);
- }
-}
-
-void DAG_ids_flush_tagged(Main *bmain)
-{
- ListBase listbase;
- DagSceneLayer *dsl;
- 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);
-
- if (BLI_listbase_is_empty(&listbase))
- return;
-
- /* loop over all ID types */
- a = set_listbasepointers(bmain, lbarray);
-
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id = lb->first;
-
- if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
- for (; id; id = id->next) {
- if (id->recalc & ID_RECALC_ALL) {
- for (dsl = listbase.first; dsl; dsl = dsl->next)
- dag_id_flush_update(bmain, dsl->scene, id);
-
- do_flush = true;
- }
- }
- }
- }
-
- /* flush changes to other objects */
- if (do_flush) {
- for (dsl = listbase.first; dsl; dsl = dsl->next)
- DAG_scene_flush_update(bmain, dsl->scene, dsl->layer, 0);
- }
-
- BLI_freelistN(&listbase);
-}
-
-void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- 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);
-
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id = lb->first;
-
- if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
- updated = true;
- break;
- }
- }
-
- dag_editors_scene_update(bmain, scene, (updated || time));
-}
-
-/* It is possible that scene_update_post and frame_update_post handlers
- * will modify objects. The issue is that DAG_ids_clear_recalc is called
- * just after callbacks, which leaves objects with recalc flags but no
- * corresponding bit in ID recalc bitfield. This leads to some kind of
- * regression when using ID type tag fields to check whether there objects
- * to be updated internally comparing threaded DAG with legacy one.
- *
- * For now let's have a workaround which will preserve tag for ID_OB
- * if there're objects with OB_RECALC_ALL bits. This keeps behavior
- * unchanged comparing with 2.69 release.
- *
- * TODO(sergey): Need to get rid of such a workaround.
- *
- * - sergey -
- */
-
-#define POST_UPDATE_HANDLER_WORKAROUND
-
-void DAG_ids_clear_recalc(Main *bmain)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- bNodeTree *ntree;
- int a;
-
-#ifdef POST_UPDATE_HANDLER_WORKAROUND
- bool have_updated_objects = false;
-
- if (DAG_id_type_tagged(bmain, ID_OB)) {
- ListBase listbase;
- DagSceneLayer *dsl;
-
- /* We need to check all visible scenes, otherwise resetting
- * OB_ID changed flag will only work fine for first scene of
- * multiple visible and all the rest will skip update.
- *
- * This could also lead to wrong behavior scene update handlers
- * because of missing ID datablock changed flags.
- *
- * This is a bit of a bummer to allocate list here, but likely
- * it wouldn't become too much bad because it only happens when
- * objects were actually changed.
- */
- dag_current_scene_layers(bmain, &listbase);
-
- for (dsl = listbase.first; dsl; dsl = dsl->next) {
- Scene *scene = dsl->scene;
- DagNode *node;
- for (node = scene->theDag->DagNode.first;
- node != NULL && have_updated_objects == false;
- node = node->next)
- {
- if (node->type == ID_OB) {
- Object *object = (Object *) node->ob;
- if (object->recalc & OB_RECALC_ALL) {
- have_updated_objects = true;
- break;
- }
- }
- }
- }
-
- BLI_freelistN(&listbase);
- }
-#endif
-
- /* loop over all ID types */
- a = set_listbasepointers(bmain, lbarray);
-
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id = lb->first;
-
- if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
- for (; id; id = id->next) {
- id->recalc &= ~ID_RECALC_ALL;
-
- /* some ID's contain semi-datablock nodetree */
- ntree = ntreeFromID(id);
- if (ntree)
- ntree->id.recalc &= ~ID_RECALC_ALL;
- }
- }
- }
-
- memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update));
-
-#ifdef POST_UPDATE_HANDLER_WORKAROUND
- if (have_updated_objects) {
- DAG_id_type_tag(bmain, ID_OB);
- }
-#endif
-}
-
-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_TAG) {
- printf("%s: id=%s flag=%d\n", __func__, id->name, flag);
- }
-
- /* tag ID for update */
- if (flag) {
- if (flag & OB_RECALC_OB)
- lib_id_recalc_tag(bmain, id);
- if (flag & (OB_RECALC_DATA | PSYS_RECALC))
- lib_id_recalc_data_tag(bmain, id);
- }
- else
- lib_id_recalc_tag(bmain, id);
-
- /* flag is for objects and particle systems */
- if (flag) {
- Object *ob;
- short idtype = GS(id->name);
-
- if (idtype == ID_OB) {
- /* only quick tag */
- ob = (Object *)id;
- ob->recalc |= (flag & OB_RECALC_ALL);
- }
- else if (idtype == ID_PA) {
- ParticleSystem *psys;
- /* this is weak still, should be done delayed as well */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (&psys->part->id == id) {
- ob->recalc |= (flag & OB_RECALC_ALL);
- psys->recalc |= (flag & PSYS_RECALC);
- lib_id_recalc_tag(bmain, &ob->id);
- lib_id_recalc_data_tag(bmain, &ob->id);
- }
- }
- }
- }
- else {
- /* disable because this is called on various ID types automatically.
- * where printing warning is not useful. for now just ignore */
- /* BLI_assert(!"invalid flag for this 'idtype'"); */
- }
- }
- else if (GS(id->name) == ID_CF) {
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
- ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
-
- if (md) {
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
-
- if (mcmd->cache_file && (&mcmd->cache_file->id == id)) {
- ob->recalc |= OB_RECALC_ALL;
- continue;
- }
- }
-
- for (bConstraint *con = ob->constraints.first; con; con = con->next) {
- if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
- continue;
- }
-
- bTransformCacheConstraint *data = con->data;
-
- if (data->cache_file && (&data->cache_file->id == id)) {
- ob->recalc |= OB_RECALC_ALL;
- break;
- }
- }
- }
- }
-}
-
-void DAG_id_tag_update(ID *id, short flag)
-{
- DAG_id_tag_update_ex(G.main, id, flag);
-}
-
-void DAG_id_type_tag(Main *bmain, short idtype)
-{
- if (idtype == ID_NT) {
- /* stupid workaround so parent datablocks of nested nodetree get looped
- * over when we loop over tagged datablock types */
- DAG_id_type_tag(bmain, ID_MA);
- DAG_id_type_tag(bmain, ID_TE);
- DAG_id_type_tag(bmain, ID_LA);
- DAG_id_type_tag(bmain, ID_WO);
- DAG_id_type_tag(bmain, ID_SCE);
- }
-
- atomic_fetch_and_or_uint8((uint8_t *)&bmain->id_tag_update[BKE_idcode_to_index(idtype)], 1);
-}
-
-int DAG_id_type_tagged(Main *bmain, short idtype)
-{
- return bmain->id_tag_update[BKE_idcode_to_index(idtype)];
-}
-
-#if 0 // UNUSED
-/* recursively descends tree, each node only checked once */
-/* node is checked to be of type object */
-static int parent_check_node(DagNode *node, int curtime)
-{
- DagAdjList *itA;
-
- node->lasttime = curtime;
-
- if (node->color == DAG_GRAY)
- return DAG_GRAY;
-
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
-
- if (itA->node->color == DAG_GRAY)
- return DAG_GRAY;
-
- /* descend if not done */
- if (itA->node->lasttime != curtime) {
- itA->node->color = parent_check_node(itA->node, curtime);
-
- if (itA->node->color == DAG_GRAY)
- return DAG_GRAY;
- }
- }
- }
-
- return DAG_WHITE;
-}
-#endif
-
-/* ******************* DAG FOR ARMATURE POSE ***************** */
-
-/* we assume its an armature with pose */
-void DAG_pose_sort(Object *ob)
-{
- bPose *pose = ob->pose;
- bPoseChannel *pchan;
- bConstraint *con;
- DagNode *node;
- DagNode *node2, *node3;
- DagNode *rootnode;
- DagForest *dag;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
- ListBase tempbase;
- int skip = 0;
-
- dag = dag_init();
- dag->ugly_hack_sorry = false; /* no ID structs */
-
- rootnode = dag_add_node(dag, NULL); /* node->ob becomes NULL */
-
- /* we add the hierarchy and the constraints */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- int addtoroot = 1;
-
- node = dag_get_node(dag, pchan);
-
- if (pchan->parent) {
- node2 = dag_get_node(dag, pchan->parent);
- dag_add_relation(dag, node2, node, 0, "Parent Relation");
- addtoroot = 0;
- }
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob && ct->subtarget[0]) {
- bPoseChannel *target = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
- if (target) {
- node2 = dag_get_node(dag, target);
- dag_add_relation(dag, node2, node, 0, "Pose Constraint");
-
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data = (bKinematicConstraint *)con->data;
- bPoseChannel *parchan;
- int segcount = 0;
-
- /* exclude tip from chain? */
- if (!(data->flag & CONSTRAINT_IK_TIP))
- parchan = pchan->parent;
- else
- parchan = pchan;
-
- /* Walk to the chain's root */
- while (parchan) {
- node3 = dag_get_node(dag, parchan);
- dag_add_relation(dag, node2, node3, 0, "IK Constraint");
-
- segcount++;
- if (segcount == data->rootbone || segcount > 255) break; /* 255 is weak */
- parchan = parchan->parent;
- }
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
- if (addtoroot == 1) {
- dag_add_relation(dag, rootnode, node, 0, "Root Bone Relation");
- }
- }
-
- dag_check_cycle(dag);
-
- /* now we try to sort... */
- BLI_listbase_clear(&tempbase);
-
- nqueue = queue_create(DAGQUEUEALLOC);
-
- /* tag nodes unchecked */
- for (node = dag->DagNode.first; node; node = node->next)
- node->color = DAG_WHITE;
-
- rootnode->color = DAG_GRAY;
- push_stack(nqueue, rootnode);
-
- while (nqueue->count) {
-
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->color = DAG_GRAY;
- push_stack(nqueue, itA->node);
- skip = 1;
- break;
- }
- itA = itA->next;
- }
-
- if (!skip) {
- if (node) {
- node = pop_queue(nqueue);
- if (node->ob == NULL) /* we are done */
- break;
- node->color = DAG_BLACK;
-
- /* put node in new list */
- BLI_remlink(&pose->chanbase, node->ob);
- BLI_addhead(&tempbase, node->ob);
- }
- }
- }
-
- /* temporal correction for circular dependencies */
- while (pose->chanbase.first) {
- pchan = pose->chanbase.first;
- BLI_remlink(&pose->chanbase, pchan);
- BLI_addhead(&tempbase, pchan);
-
- printf("cyclic %s\n", pchan->name);
- }
-
- pose->chanbase = tempbase;
- queue_delete(nqueue);
-
-// printf("\nordered\n");
-// for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
-// printf(" %s\n", pchan->name);
-// }
-
- free_forest(dag);
- MEM_freeN(dag);
-}
-
-/* ************************ DAG FOR THREADED UPDATE ********************* */
-
-/* Initialize run-time data in the graph needed for traversing it
- * from multiple threads and start threaded tree traversal by adding
- * the root node to the queue.
- *
- * This will mark DAG nodes as object/non-object and will calculate
- * num_pending_parents of nodes (which is how many non-updated parents node
- * have, which helps a lot checking whether node could be scheduled
- * already or not).
- */
-void DAG_threaded_update_begin(Scene *scene,
- void (*func)(void *node, void *user_data),
- void *user_data)
-{
- DagNode *node;
-
- /* We reset num_pending_parents to zero first and tag node as not scheduled yet... */
- for (node = scene->theDag->DagNode.first; node; node = node->next) {
- node->num_pending_parents = 0;
- node->scheduled = false;
- }
-
- /* ... and then iterate over all the nodes and
- * increase num_pending_parents for node childs.
- */
- for (node = scene->theDag->DagNode.first; node; node = node->next) {
- DagAdjList *itA;
-
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node != node) {
- itA->node->num_pending_parents++;
- }
- }
- }
-
- /* Add root nodes to the queue. */
- BLI_spin_lock(&threaded_update_lock);
- for (node = scene->theDag->DagNode.first; node; node = node->next) {
- if (node->num_pending_parents == 0) {
- node->scheduled = true;
- func(node, user_data);
- }
- }
- BLI_spin_unlock(&threaded_update_lock);
-}
-
-/* This function is called when handling node is done.
- *
- * This function updates num_pending_parents for all childs and
- * schedules them if they're ready.
- */
-void DAG_threaded_update_handle_node_updated(void *node_v,
- void (*func)(void *node, void *user_data),
- void *user_data)
-{
- DagNode *node = node_v;
- DagAdjList *itA;
-
- for (itA = node->child; itA; itA = itA->next) {
- DagNode *child_node = itA->node;
- if (child_node != node) {
- atomic_sub_and_fetch_uint32(&child_node->num_pending_parents, 1);
-
- if (child_node->num_pending_parents == 0) {
- bool need_schedule;
-
- BLI_spin_lock(&threaded_update_lock);
- need_schedule = child_node->scheduled == false;
- child_node->scheduled = true;
- BLI_spin_unlock(&threaded_update_lock);
-
- if (need_schedule) {
- func(child_node, user_data);
- }
- }
- }
- }
-}
-
-/* ************************ DAG DEBUGGING ********************* */
-
-void DAG_print_dependencies(Main *bmain, Scene *scene, Object *ob)
-{
- /* utility for debugging dependencies */
- dag_print_dependencies = 1;
-
- if (ob && (ob->mode & OB_MODE_POSE)) {
- printf("\nDEPENDENCY RELATIONS for %s\n\n", ob->id.name + 2);
- DAG_pose_sort(ob);
- }
- else {
- printf("\nDEPENDENCY RELATIONS for %s\n\n", scene->id.name + 2);
- DAG_scene_relations_rebuild(bmain, scene);
- }
-
- dag_print_dependencies = 0;
-}
-
-/* ************************ DAG querying ********************* */
-
-/* Will return Object ID if node represents Object,
- * and will return NULL otherwise.
- */
-Object *DAG_get_node_object(void *node_v)
-{
- DagNode *node = node_v;
-
- if (node->type == ID_OB) {
- return node->ob;
- }
-
- return NULL;
-}
-
-/* Returns node name, used for debug output only, atm. */
-const char *DAG_get_node_name(Scene *scene, void *node_v)
-{
- DagNode *node = node_v;
-
- return dag_node_name(scene->theDag, node);
-}
-
-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.
- *
- * Currently harmless because it's only called for temporary
- * objects which are out of the DAG anyway.
- */
- return 0;
- }
-
- node = dag_find_node(scene->theDag, object);
-
- if (node) {
- return node->eval_flags;
- }
- else {
- /* Happens when external render engine exports temporary objects
- * which are not in the DAG.
- */
-
- /* TODO(sergey): Doublecheck objects with Curve Deform exports all fine. */
-
- /* TODO(sergey): Weak but currently we can't really access proper DAG from
- * the modifiers stack. This is because in most cases modifier is to use
- * the foreground scene, but to access evaluation flags we need to know
- * active background scene, which we don't know.
- */
- if (scene->set) {
- return DAG_get_eval_flags_for_object(scene->set, object);
- }
- return 0;
- }
-}
-
-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_EditorUpdateScenePreCb scene_func_pre)
-{
- DEG_editors_set_update_cb(id_func, scene_func, scene_func_pre);
-}
-
-void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time)
-{
- DEG_editors_update_pre(bmain, scene, time);
-}
-
-/* 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_relations_graphviz(scene->depsgraph, stdout, "Depsgraph");
-}
-
-#endif
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index dea1a3718dd..84bac76202a 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
@@ -48,13 +49,14 @@
#include "BLI_utildefines.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_object.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mball_tessellate.h"
+#include "BKE_mesh.h"
#include "BKE_curve.h"
#include "BKE_key.h"
#include "BKE_anim.h"
@@ -64,6 +66,9 @@
#include "BLI_sys_types.h" // for intptr_t support
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
static void boundbox_displist_object(Object *ob);
void BKE_displist_elem_free(DispList *dl)
@@ -680,7 +685,7 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis
* - first point left, last point right
* - based on subdivided points in original curve, not on points in taper curve (still)
*/
-static float displist_calc_taper(Scene *scene, Object *taperobj, float fac)
+static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, float fac)
{
DispList *dl;
@@ -689,7 +694,7 @@ static float displist_calc_taper(Scene *scene, Object *taperobj, float fac)
dl = taperobj->curve_cache ? taperobj->curve_cache->disp.first : NULL;
if (dl == NULL) {
- BKE_displist_make_curveTypes(scene, taperobj, 0);
+ BKE_displist_make_curveTypes(depsgraph, scene, taperobj, 0);
dl = taperobj->curve_cache->disp.first;
}
if (dl) {
@@ -720,19 +725,19 @@ static float displist_calc_taper(Scene *scene, Object *taperobj, float fac)
return 1.0;
}
-float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot)
+float BKE_displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, int cur, int tot)
{
float fac = ((float)cur) / (float)(tot - 1);
- return displist_calc_taper(scene, taperobj, fac);
+ return displist_calc_taper(depsgraph, scene, taperobj, fac);
}
-void BKE_displist_make_mball(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob)
+void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
if (!ob || ob->type != OB_MBALL)
return;
- if (ob == BKE_mball_basis_find(bmain, eval_ctx, scene, ob)) {
+ if (ob == BKE_mball_basis_find(scene, ob)) {
if (ob->curve_cache) {
BKE_displist_free(&(ob->curve_cache->disp));
}
@@ -740,7 +745,7 @@ void BKE_displist_make_mball(Main *bmain, EvaluationContext *eval_ctx, Scene *sc
ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
}
- BKE_mball_polygonize(bmain, eval_ctx, scene, ob, &ob->curve_cache->disp);
+ BKE_mball_polygonize(depsgraph, scene, ob, &ob->curve_cache->disp);
BKE_mball_texspace_calc(ob);
object_deform_mball(ob, &ob->curve_cache->disp);
@@ -750,9 +755,9 @@ void BKE_displist_make_mball(Main *bmain, EvaluationContext *eval_ctx, Scene *sc
}
}
-void BKE_displist_make_mball_forRender(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
+void BKE_displist_make_mball_forRender(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
- BKE_mball_polygonize(bmain, eval_ctx, scene, ob, dispbase);
+ BKE_mball_polygonize(depsgraph, scene, ob, dispbase);
BKE_mball_texspace_calc(ob);
object_deform_mball(ob, dispbase);
@@ -800,8 +805,9 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob,
return pretessellatePoint;
}
-static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
- const bool for_render, const bool use_render_resolution)
+static void curve_calc_modifiers_pre(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
+ const bool for_render, const bool use_render_resolution)
{
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
@@ -825,6 +831,8 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
else
required_mode = eModifierMode_Realtime;
+ const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+
pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
if (editmode)
@@ -847,8 +855,6 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!modifier_isEnabled(scene, md, required_mode))
continue;
if (mti->type != eModifierTypeType_OnlyDeform)
@@ -858,7 +864,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
deformedVerts = BKE_curve_nurbs_vertexCos_get(nurb, &numVerts);
}
- mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, app_flag);
+ modifier_deformVerts_DM_deprecated(md, &mectx, NULL, deformedVerts, numVerts);
if (md == pretessellatePoint)
break;
@@ -910,9 +916,10 @@ static void displist_apply_allverts(ListBase *dispbase, float (*allverts)[3])
}
}
-static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
- ListBase *dispbase, DerivedMesh **r_dm_final,
- const bool for_render, const bool use_render_resolution)
+static void curve_calc_modifiers_post(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
+ ListBase *dispbase, DerivedMesh **r_dm_final,
+ const bool for_render, const bool use_render_resolution)
{
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
@@ -920,7 +927,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
Curve *cu = ob->data;
int required_mode = 0, totvert = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- DerivedMesh *dm = NULL, *ndm;
+ Mesh *modified = NULL, *mesh_applied;
float (*vertCos)[3] = NULL;
int useCache = !for_render;
ModifierApplyFlag app_flag = 0;
@@ -932,6 +939,11 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
else
required_mode = eModifierMode_Realtime;
+ const ModifierEvalContext mectx_deform = {depsgraph, ob,
+ editmode ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ const ModifierEvalContext mectx_apply = {depsgraph, ob,
+ useCache ? app_flag | MOD_APPLY_USECACHE : app_flag};
+
pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
if (editmode)
@@ -947,33 +959,26 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- ModifierApplyFlag appf = app_flag;
-
- md->scene = scene;
if (!modifier_isEnabled(scene, md, required_mode))
continue;
if (mti->type == eModifierTypeType_OnlyDeform ||
- (mti->type == eModifierTypeType_DeformOrConstruct && !dm))
+ (mti->type == eModifierTypeType_DeformOrConstruct && !modified))
{
- if (editmode)
- appf |= MOD_APPLY_USECACHE;
- if (dm) {
+ if (modified) {
if (!vertCos) {
- totvert = dm->getNumVerts(dm);
- vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "dfmv");
- dm->getVertCos(dm, vertCos);
+ vertCos = BKE_mesh_vertexCos_get(modified, &totvert);
}
- mti->deformVerts(md, ob, dm, vertCos, totvert, appf);
+ modifier_deformVerts(md, &mectx_deform, modified, vertCos, totvert);
}
else {
if (!vertCos) {
vertCos = displist_get_allverts(dispbase, &totvert);
}
- mti->deformVerts(md, ob, NULL, vertCos, totvert, appf);
+ modifier_deformVerts(md, &mectx_deform, NULL, vertCos, totvert);
}
}
else {
@@ -985,13 +990,17 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
break;
}
- if (dm) {
+ if (modified) {
if (vertCos) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
-
- CDDM_apply_vert_coords(dm, vertCos);
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
}
}
else {
@@ -1003,7 +1012,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
curve_to_filledpoly(cu, nurb, dispbase);
}
- dm = CDDM_from_curve_displist(ob, dispbase);
+ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
}
if (vertCos) {
@@ -1012,29 +1021,31 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
vertCos = NULL;
}
- if (useCache)
- appf |= MOD_APPLY_USECACHE;
+ mesh_applied = modifier_applyModifier(md, &mectx_apply, modified);
- ndm = modwrap_applyModifier(md, ob, dm, appf);
-
- if (ndm) {
+ if (mesh_applied) {
/* Modifier returned a new derived mesh */
- if (dm && dm != ndm) /* Modifier */
- dm->release(dm);
- dm = ndm;
+ if (modified && modified != mesh_applied) /* Modifier */
+ BKE_id_free(NULL, modified);
+ modified = mesh_applied;
}
}
}
if (vertCos) {
- if (dm) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
+ if (modified) {
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
+ BKE_mesh_calc_normals_mapping_simple(modified);
- CDDM_apply_vert_coords(dm, vertCos);
- CDDM_calc_normals_mapping(dm);
MEM_freeN(vertCos);
}
else {
@@ -1045,22 +1056,27 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
}
if (r_dm_final) {
- if (dm) {
+ if (modified) {
/* see: mesh_calc_modifiers */
- if (dm->getNumTessFaces(dm) == 0) {
- dm->recalcTessellation(dm);
+ if (modified->totface == 0) {
+ BKE_mesh_tessface_calc(modified);
}
/* Even if tessellation is not needed, some modifiers might have modified CD layers
* (like mloopcol or mloopuv), hence we have to update those. */
- else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
- DM_update_tessface_data(dm);
+ else if (modified->runtime.cd_dirty_vert & CD_MASK_TESSLOOPNORMAL) {
+ BKE_mesh_tessface_calc(modified);
}
- if (dm->type == DM_TYPE_CDDM) {
- CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true);
- }
+ /* XXX2.8(Sybren): make sure the face normals are recalculated as well */
+ BKE_mesh_ensure_normals(modified);
+
+ (*r_dm_final) = CDDM_from_mesh_ex(modified, CD_DUPLICATE, CD_MASK_MESH);
+ BKE_id_free(NULL, modified);
+ }
+ else {
+ (*r_dm_final) = NULL;
}
- (*r_dm_final) = dm;
+
}
}
@@ -1092,13 +1108,15 @@ static void displist_surf_indices(DispList *dl)
}
}
-static DerivedMesh *create_orco_dm(Scene *scene, Object *ob)
+/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
+static DerivedMesh *create_orco_dm(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
DerivedMesh *dm;
ListBase disp = {NULL, NULL};
/* OrcoDM should be created from underformed disp lists */
- BKE_displist_make_curveTypes_forOrco(scene, ob, &disp);
+ BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
dm = CDDM_from_curve_displist(ob, &disp);
BKE_displist_free(&disp);
@@ -1135,9 +1153,13 @@ static void add_orco_dm(Object *ob, DerivedMesh *dm, DerivedMesh *orcodm)
else
DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco);
}
+#endif
-static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
- const bool for_render, const bool use_render_resolution)
+/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
+static void curve_calc_orcodm(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final,
+ const bool for_render, const bool use_render_resolution)
{
/* this function represents logic of mesh's orcodm calculation
* for displist-based objects
@@ -1158,6 +1180,8 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
else
required_mode = eModifierMode_Realtime;
+ const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+
pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
if (editmode)
@@ -1174,7 +1198,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
* This means we can create ORCO DM in advance and assume it's
* never NULL.
*/
- orcodm = create_orco_dm(scene, ob);
+ orcodm = create_orco_dm(depsgraph, scene, ob);
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
@@ -1186,7 +1210,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
if (mti->type != eModifierTypeType_Constructive)
continue;
- ndm = modwrap_applyModifier(md, ob, orcodm, app_flag);
+ ndm = modwrap_applyModifier(md, &mectx, orcodm);
if (ndm) {
/* if the modifier returned a new dm, release the old one */
@@ -1202,10 +1226,12 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
orcodm->release(orcodm);
}
+#endif
-void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final,
- const bool for_render, const bool for_orco, const bool use_render_resolution)
+void BKE_displist_make_surf(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
+ DerivedMesh **r_dm_final,
+ const bool for_render, const bool for_orco, const bool use_render_resolution)
{
ListBase nubase = {NULL, NULL};
Nurb *nu;
@@ -1222,7 +1248,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
}
if (!for_orco)
- curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution);
+ curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
for (nu = nubase.first; nu; nu = nu->next) {
if ((for_render || nu->hide == 0) && BKE_nurb_check_valid_uv(nu)) {
@@ -1289,7 +1315,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
if (!for_orco) {
BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final,
+ curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_dm_final,
for_render, use_render_resolution);
}
@@ -1515,9 +1541,10 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu,
}
}
-static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final,
- const bool for_render, const bool for_orco, const bool use_render_resolution)
+static void do_makeDispListCurveTypes(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
+ DerivedMesh **r_dm_final,
+ const bool for_render, const bool for_orco, const bool use_render_resolution)
{
Curve *cu = ob->data;
@@ -1525,7 +1552,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return;
if (ob->type == OB_SURF) {
- BKE_displist_make_surf(scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution);
+ BKE_displist_make_surf(depsgraph, scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution);
}
else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
ListBase dlbev;
@@ -1550,12 +1577,12 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
if (!for_orco)
- curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution);
+ curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
BKE_curve_bevelList_make(ob, &nubase, for_render != false);
/* If curve has no bevel will return nothing */
- BKE_curve_bevel_make(scene, ob, &dlbev, for_render, use_render_resolution);
+ BKE_curve_bevel_make(depsgraph, scene, ob, &dlbev, for_render, use_render_resolution);
/* no bevel or extrude, and no width correction? */
if (!dlbev.first && cu->width == 1.0f) {
@@ -1690,7 +1717,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
taper_fac -= (1.0f - lastblend) / len;
}
- fac = displist_calc_taper(scene, cu->taperobj, taper_fac);
+ fac = displist_calc_taper(depsgraph, scene, cu->taperobj, taper_fac);
}
if (bevp->split_tag) {
@@ -1743,7 +1770,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (!for_orco) {
if ((cu->flag & CU_PATH) ||
- DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CURVE_PATH)
+ DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH)
{
calc_curvepath(ob, &nubase);
}
@@ -1751,7 +1778,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (!for_orco) {
BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution);
+ curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution);
}
if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) {
@@ -1762,7 +1789,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
}
-void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco)
+void BKE_displist_make_curveTypes(Depsgraph *depsgraph, Scene *scene, Object *ob, const bool for_orco)
{
ListBase *dispbase;
@@ -1780,35 +1807,40 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco)
dispbase = &(ob->curve_cache->disp);
- do_makeDispListCurveTypes(scene, ob, dispbase, &ob->derivedFinal, 0, for_orco, 0);
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, &ob->derivedFinal, 0, for_orco, 0);
boundbox_displist_object(ob);
}
-void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final, const bool for_orco,
- const bool use_render_resolution)
+void BKE_displist_make_curveTypes_forRender(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
+ DerivedMesh **r_dm_final, const bool for_orco,
+ const bool use_render_resolution)
{
if (ob->curve_cache == NULL) {
ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
- do_makeDispListCurveTypes(scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution);
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution);
}
-void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase)
+void BKE_displist_make_curveTypes_forOrco(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
if (ob->curve_cache == NULL) {
ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
- do_makeDispListCurveTypes(scene, ob, dispbase, NULL, 1, 1, 1);
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, NULL, 1, 1, 1);
}
/* add Orco layer to the displist object which has got derived mesh and return orco */
-float *BKE_displist_make_orco(Scene *scene, Object *ob, DerivedMesh *dm_final,
- const bool for_render,
- const bool use_render_resolution)
+/* XXX2.8(Sybren): can be removed once DerivedMesh port is done */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
+float *BKE_displist_make_orco(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final,
+ const bool for_render,
+ const bool use_render_resolution)
{
float *orco;
@@ -1816,7 +1848,7 @@ float *BKE_displist_make_orco(Scene *scene, Object *ob, DerivedMesh *dm_final,
dm_final = ob->derivedFinal;
if (!dm_final->getVertDataArray(dm_final, CD_ORCO)) {
- curve_calc_orcodm(scene, ob, dm_final, for_render, use_render_resolution);
+ curve_calc_orcodm(depsgraph, scene, ob, dm_final, for_render, use_render_resolution);
}
orco = dm_final->getVertDataArray(dm_final, CD_ORCO);
@@ -1827,6 +1859,7 @@ float *BKE_displist_make_orco(Scene *scene, Object *ob, DerivedMesh *dm_final,
return orco;
}
+#endif
void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3])
{
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index ab5fe1d45f5..173dc8050a1 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -43,7 +43,7 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_dynamicpaint_types.h"
-#include "DNA_group_types.h" /*GroupObject*/
+#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -55,12 +55,12 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h" /* bvh tree */
+#include "BKE_collection.h"
#include "BKE_colorband.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_constraint.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_dynamicpaint.h"
#include "BKE_effect.h"
@@ -75,6 +75,9 @@
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
/* for image output */
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -487,36 +490,22 @@ static void scene_setSubframe(Scene *scene, float subframe)
scene->r.subframe = subframe;
}
-static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene)
+static int surface_getBrushFlags(DynamicPaintSurface *surface, const Depsgraph *depsgraph)
{
- Base *base = NULL;
- GroupObject *go = NULL;
+ Base *base = BKE_collection_or_layer_objects(depsgraph, NULL, NULL, surface->brush_group);
Object *brushObj = NULL;
ModifierData *md = NULL;
int flags = 0;
- if (surface->brush_group)
- go = surface->brush_group->gobject.first;
- else
- base = scene->base.first;
-
- while (base || go) {
+ while (base) {
brushObj = NULL;
/* select object */
- if (surface->brush_group) {
- if (go->ob)
- brushObj = go->ob;
- }
- else {
- brushObj = base->object;
- }
+ brushObj = base->object;
- if (surface->brush_group)
- go = go->next;
- else
- base = base->next;
+ /* next item */
+ base = base->next;
if (!brushObj) {
continue;
@@ -538,11 +527,6 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
return flags;
}
-static int brush_usesMaterial(const DynamicPaintBrushSettings *brush, const Scene *scene)
-{
- return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!BKE_scene_use_new_shading_nodes(scene)));
-}
-
/* check whether two bounds intersect */
static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
{
@@ -1103,7 +1087,6 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
brush->collision = MOD_DPAINT_COL_VOLUME;
- brush->mat = NULL;
brush->r = 0.15f;
brush->g = 0.4f;
brush->b = 0.8f;
@@ -1243,7 +1226,6 @@ void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, stru
t_brush->flags = brush->flags;
t_brush->collision = brush->collision;
- t_brush->mat = brush->mat;
t_brush->r = brush->r;
t_brush->g = brush->g;
t_brush->b = brush->b;
@@ -2073,7 +2055,8 @@ static void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMe
* Updates derived mesh copy and processes dynamic paint step / caches.
*/
static void dynamicPaint_frameUpdate(
- Main *bmain, EvaluationContext *eval_ctx, DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+ DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, DerivedMesh *dm)
{
if (pmd->canvas) {
DynamicPaintCanvasSettings *canvas = pmd->canvas;
@@ -2136,7 +2119,7 @@ static void dynamicPaint_frameUpdate(
else if (can_simulate) {
/* calculate surface frame */
canvas->flags |= MOD_DPAINT_BAKING;
- dynamicPaint_calculateFrame(bmain, eval_ctx, surface, scene, ob, current_frame);
+ dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame);
canvas->flags &= ~MOD_DPAINT_BAKING;
/* restore canvas derivedmesh if required */
@@ -2155,14 +2138,15 @@ static void dynamicPaint_frameUpdate(
}
/* Modifier call. Processes dynamic paint modifier step. */
-DerivedMesh *dynamicPaint_Modifier_do(Main *bmain,
- EvaluationContext *eval_ctx, DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+DerivedMesh *dynamicPaint_Modifier_do(
+ DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, DerivedMesh *dm)
{
if (pmd->canvas) {
DerivedMesh *ret;
/* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(bmain, eval_ctx, pmd, scene, ob, dm);
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, dm);
/* Return output mesh */
ret = dynamicPaint_Modifier_apply(pmd, ob, dm);
@@ -2171,7 +2155,7 @@ DerivedMesh *dynamicPaint_Modifier_do(Main *bmain,
}
else {
/* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(bmain, eval_ctx, pmd, scene, ob, dm);
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, dm);
/* Return output mesh */
return dynamicPaint_Modifier_apply(pmd, ob, dm);
@@ -3341,91 +3325,6 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
}
-/***************************** Material / Texture Sampling ******************************/
-
-/* stores a copy of required materials to allow doing adjustments
- * without interfering the render/preview */
-typedef struct BrushMaterials {
- Material *mat;
- Material **ob_mats;
- int tot;
-} BrushMaterials;
-
-/* Initialize materials for brush object:
- * Calculates inverse matrices for linked objects, updates
- * volume caches etc. */
-static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats)
-{
- /* Calculate inverse transformation matrix
- * for this object */
- invert_m4_m4(brushOb->imat, brushOb->obmat);
- copy_m4_m4(brushOb->imat_ren, brushOb->imat);
-
- /* Now process every material linked to this brush object */
- if ((ui_mat == NULL) && brushOb->mat && brushOb->totcol) {
- int i, tot = (*give_totcolp(brushOb));
-
- /* allocate material pointer array */
- if (tot) {
- bMats->ob_mats = MEM_callocN(sizeof(Material *) * (tot), "BrushMaterials");
- for (i = 0; i < tot; i++) {
- bMats->ob_mats[i] = RE_sample_material_init(give_current_material(brushOb, (i + 1)), scene);
- }
- }
- bMats->tot = tot;
- }
- else {
- bMats->mat = RE_sample_material_init(ui_mat, scene);
- }
-}
-
-/* free all data allocated by dynamicPaint_updateBrushMaterials() */
-static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
-{
- /* Now process every material linked to this brush object */
- if (bMats->ob_mats) {
- int i;
- for (i = 0; i < bMats->tot; i++) {
- RE_sample_material_free(bMats->ob_mats[i]);
- }
- MEM_freeN(bMats->ob_mats);
- }
- else if (bMats->mat) {
- RE_sample_material_free(bMats->mat);
- }
-}
-
-/*
- * Get material diffuse color and alpha (including linked textures) in given coordinates
- */
-static void dynamicPaint_doMaterialTex(
- const BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
- const float volume_co[3], const float surface_co[3],
- int triIndex, DerivedMesh *orcoDm)
-{
- Material *mat = bMats->mat;
-
- const MLoopTri *mlooptri = orcoDm->getLoopTriArray(orcoDm);
- const MPoly *mpoly = orcoDm->getPolyArray(orcoDm);
-
- /* If no material defined, use the one assigned to the mesh face */
- if (mat == NULL) {
- if (bMats->ob_mats) {
- int mat_nr = mpoly[mlooptri[triIndex].poly].mat_nr;
- if (mat_nr >= (*give_totcolp(brushOb)))
- return;
- mat = bMats->ob_mats[mat_nr];
- if (mat == NULL)
- return; /* No material assigned */
- }
- else {
- return;
- }
- }
- RE_sample_material_color(mat, color, alpha, volume_co, surface_co, triIndex, orcoDm, brushOb);
-}
-
-
/***************************** Ray / Nearest Point Utils ******************************/
@@ -3746,7 +3645,7 @@ static void dynamic_paint_brush_velocity_compute_cb(
}
static void dynamicPaint_brushMeshCalculateVelocity(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene,
+ Depsgraph *depsgraph, Scene *scene,
Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
{
float prev_obmat[4][4];
@@ -3769,7 +3668,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(
scene->r.subframe = prev_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_p = CDDM_copy(brush->dm);
numOfVerts_p = dm_p->getNumVerts(dm_p);
mvert_p = dm_p->getVertArray(dm_p);
@@ -3780,7 +3679,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(
scene->r.subframe = cur_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_c = brush->dm;
numOfVerts_c = dm_c->getNumVerts(dm_c);
mvert_c = dm_p->getVertArray(dm_c);
@@ -3812,7 +3711,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(
/* calculate velocity for object center point */
static void dynamicPaint_brushObjectCalculateVelocity(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
{
float prev_obmat[4][4];
float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
@@ -3831,14 +3730,14 @@ static void dynamicPaint_brushObjectCalculateVelocity(
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
copy_m4_m4(prev_obmat, ob->obmat);
/* current frame dm */
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
/* calculate speed */
mul_m4_v3(prev_obmat, prev_loc);
@@ -3852,7 +3751,6 @@ typedef struct DynamicPaintPaintData {
const DynamicPaintSurface *surface;
const DynamicPaintBrushSettings *brush;
Object *brushOb;
- const BrushMaterials *bMats;
const Scene *scene;
const float timescale;
const int c_index;
@@ -3889,14 +3787,10 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
VolumeGrid *grid = bData->grid;
const DynamicPaintBrushSettings *brush = data->brush;
- Object *brushOb = data->brushOb;
- const BrushMaterials *bMats = data->bMats;
- const Scene *scene = data->scene;
const float timescale = data->timescale;
const int c_index = data->c_index;
- DerivedMesh *dm = data->dm;
const MVert *mvert = data->mvert;
const MLoop *mloop = data->mloop;
const MLoopTri *mlooptri = data->mlooptri;
@@ -4156,13 +4050,6 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
sampleColor[1] = brush->g;
sampleColor[2] = brush->b;
- /* Get material+textures color on hit point if required */
- if (brush_usesMaterial(brush, scene)) {
- dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb,
- bData->realCoord[bData->s_pos[index] + ss].v,
- hitCoord, hitTri, dm);
- }
-
/* Sample proximity colorband if required */
if ((hit_found == HIT_PROXIMITY) &&
(brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP))
@@ -4210,12 +4097,9 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
}
}
-static int dynamicPaint_paintMesh(Main *bmain,
- EvaluationContext *eval_ctx,
- DynamicPaintSurface *surface,
+static int dynamicPaint_paintMesh(Depsgraph *depsgraph, DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
Object *brushOb,
- BrushMaterials *bMats,
Scene *scene,
float timescale)
{
@@ -4228,7 +4112,7 @@ static int dynamicPaint_paintMesh(Main *bmain,
const MLoop *mloop = NULL;
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushMeshCalculateVelocity(bmain, eval_ctx, scene, brushOb, brush, &brushVelocity, timescale);
+ dynamicPaint_brushMeshCalculateVelocity(depsgraph, scene, brushOb, brush, &brushVelocity, timescale);
if (!brush->dm)
return 0;
@@ -4293,7 +4177,7 @@ static int dynamicPaint_paintMesh(Main *bmain,
/* loop through cell points and process brush */
DynamicPaintPaintData data = {
.surface = surface,
- .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .brush = brush, .brushOb = brushOb,
.scene = scene, .timescale = timescale, .c_index = c_index,
.dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
.brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
@@ -4618,13 +4502,9 @@ static void dynamic_paint_paint_single_point_cb_ex(
const PaintBakeData *bData = sData->bData;
const DynamicPaintBrushSettings *brush = data->brush;
- Object *brushOb = data->brushOb;
- const BrushMaterials *bMats = data->bMats;
- const Scene *scene = data->scene;
const float timescale = data->timescale;
- const MVert *mvert = data->mvert;
const float brush_radius = data->brush_radius;
const Vec3f *brushVelocity = data->brushVelocity;
@@ -4653,17 +4533,6 @@ static void dynamic_paint_paint_single_point_cb_ex(
float depth = 0.0f;
float velocity_val = 0.0f;
- /* material */
- if (brush_usesMaterial(brush, scene)) {
- float alpha_factor = 1.0f;
- float hit_coord[3];
- /* use dummy coord of first vertex */
- mul_v3_m4v3(hit_coord, brushOb->obmat, mvert[0].co);
-
- dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb,
- bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
- }
-
/* color ramp */
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband))
@@ -4701,11 +4570,9 @@ static void dynamic_paint_paint_single_point_cb_ex(
paintColor[2] = colorband[2];
}
else {
- if (!brush_usesMaterial(brush, scene)) {
- paintColor[0] = brush->r;
- paintColor[1] = brush->g;
- paintColor[2] = brush->b;
- }
+ paintColor[0] = brush->r;
+ paintColor[1] = brush->g;
+ paintColor[2] = brush->b;
}
}
else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
@@ -4718,15 +4585,15 @@ static void dynamic_paint_paint_single_point_cb_ex(
}
static int dynamicPaint_paintSinglePoint(
- Main *bmain, EvaluationContext *eval_ctx, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
- Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
+ Depsgraph *depsgraph, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
+ Object *brushOb, Scene *scene, float timescale)
{
PaintSurfaceData *sData = surface->data;
float brush_radius = brush->paint_distance * surface->radius_scale;
Vec3f brushVel;
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushObjectCalculateVelocity(bmain, eval_ctx, scene, brushOb, &brushVel, timescale);
+ dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale);
const MVert *mvert = brush->dm->getVertArray(brush->dm);
@@ -4735,7 +4602,7 @@ static int dynamicPaint_paintSinglePoint(
*/
DynamicPaintPaintData data = {
.surface = surface,
- .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .brush = brush, .brushOb = brushOb,
.scene = scene, .timescale = timescale,
.mvert = mvert,
.brush_radius = brush_radius, .brushVelocity = &brushVel,
@@ -5019,7 +4886,7 @@ static void dynamic_paint_prepare_effect_cb(
EffectedPoint epoint;
pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
epoint.vel_to_sec = 1.0f;
- pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
}
/* if global gravity is enabled, add it too */
@@ -5048,7 +4915,7 @@ static void dynamic_paint_prepare_effect_cb(
}
static int dynamicPaint_prepareEffectStep(
- DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
+ struct Depsgraph *depsgraph, DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
{
double average_force = 0.0f;
float shrink_speed = 0.0f, spread_speed = 0.0f;
@@ -5059,7 +4926,7 @@ static int dynamicPaint_prepareEffectStep(
/* Init force data if required */
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, surface->effector_weights);
/* allocate memory for force data (dir vector + strength) */
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
@@ -5083,7 +4950,7 @@ static int dynamicPaint_prepareEffectStep(
}
average_force /= sData->total_points;
}
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
}
/* Get number of required steps using average point distance
@@ -5891,7 +5758,7 @@ static void dynamic_paint_generate_bake_data_cb(
}
}
-static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
+static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Depsgraph *depsgraph, Object *ob)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
@@ -5899,7 +5766,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
int index;
bool new_bdata = false;
const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
- (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY));
+ (surface_getBrushFlags(surface, depsgraph) & BRUSH_USES_VELOCITY));
const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
int canvasNumOfVerts = dm->getNumVerts(dm);
@@ -6017,12 +5884,13 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
* Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface.
*/
static int dynamicPaint_doStep(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene,
+ Depsgraph *depsgraph, Scene *scene,
Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
int ret = 1;
if (sData->total_points < 1)
@@ -6043,36 +5911,21 @@ static int dynamicPaint_doStep(
* Loop through surface's target paint objects and do painting
*/
{
- Base *base = NULL;
- GroupObject *go = NULL;
Object *brushObj = NULL;
ModifierData *md = NULL;
+ Base *base = BKE_collection_or_layer_objects(depsgraph, NULL, NULL, surface->brush_group);
/* backup current scene frame */
int scene_frame = scene->r.cfra;
float scene_subframe = scene->r.subframe;
- /* either from group or from all objects */
- if (surface->brush_group)
- go = surface->brush_group->gobject.first;
- else
- base = scene->base.first;
-
- while (base || go) {
+ while (base) {
brushObj = NULL;
/* select object */
- if (surface->brush_group) {
- if (go->ob)
- brushObj = go->ob;
- }
- else
- brushObj = base->object;
+ brushObj = base->object;
/* next item */
- if (surface->brush_group)
- go = go->next;
- else
- base = base->next;
+ base = base->next;
if (!brushObj) {
/* skip item */
@@ -6086,7 +5939,6 @@ static int dynamicPaint_doStep(
/* make sure we're dealing with a brush */
if (pmd2->brush) {
DynamicPaintBrushSettings *brush = pmd2->brush;
- BrushMaterials bMats = {NULL};
/* calculate brush speed vectors if required */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
@@ -6101,44 +5953,35 @@ static int dynamicPaint_doStep(
/* update object data on this subframe */
if (subframe) {
scene_setSubframe(scene, subframe);
- BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
- /* Prepare materials if required */
- if (brush_usesMaterial(brush, scene))
- dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats);
+
/* Apply brush on the surface depending on it's collision type */
- /* Particle brush: */
- if (brush->collision == MOD_DPAINT_COL_PSYS) {
- if (brush->psys && brush->psys->part &&
- ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
- psys_check_enabled(brushObj, brush->psys, G.is_rendering))
- {
- /* Paint a particle system */
- BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt,
- BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
- dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
- }
+ if (brush->psys && brush->psys->part &&
+ ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
+ psys_check_enabled(brushObj, brush->psys, for_render))
+ {
+ /* Paint a particle system */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &brush->psys->part->id, brush->psys->part->adt,
+ BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
+ dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
}
/* Object center distance: */
- else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
- dynamicPaint_paintSinglePoint(
- bmain, eval_ctx, surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale);
+ if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
+ dynamicPaint_paintSinglePoint(depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale);
}
/* Mesh volume/proximity: */
else if (brushObj != ob) {
- dynamicPaint_paintMesh(bmain, eval_ctx, surface, brush, brushObj, &bMats, scene, timescale);
+ dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale);
}
- /* free temp material data */
- if (brush_usesMaterial(brush, scene))
- dynamicPaint_freeBrushMaterials(&bMats);
/* reset object to it's original state */
if (subframe) {
scene->r.cfra = scene_frame;
scene->r.subframe = scene_subframe;
- BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
@@ -6173,7 +6016,7 @@ static int dynamicPaint_doStep(
return setError(canvas, N_("Not enough free memory"));
/* Prepare effects and get number of required steps */
- steps = dynamicPaint_prepareEffectStep(surface, scene, ob, &force, timescale);
+ steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale);
for (s = 0; s < steps; s++) {
dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps);
}
@@ -6198,7 +6041,8 @@ static int dynamicPaint_doStep(
* Calculate a single frame and included subframes for surface
*/
int dynamicPaint_calculateFrame(
- Main *bmain, EvaluationContext *eval_ctx, DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame)
+ DynamicPaintSurface *surface, struct Depsgraph *depsgraph,
+ Scene *scene, Object *cObject, int frame)
{
float timescale = 1.0f;
@@ -6207,7 +6051,7 @@ int dynamicPaint_calculateFrame(
dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm);
/* update bake data */
- dynamicPaint_generateBakeData(surface, scene, cObject);
+ dynamicPaint_generateBakeData(surface, depsgraph, cObject);
/* don't do substeps for first frame */
if (surface->substeps && (frame != surface->start_frame)) {
@@ -6216,10 +6060,10 @@ int dynamicPaint_calculateFrame(
for (st = 1; st <= surface->substeps; st++) {
float subframe = ((float) st) / (surface->substeps + 1);
- if (!dynamicPaint_doStep(bmain, eval_ctx, scene, cObject, surface, timescale, subframe))
+ if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe))
return 0;
}
}
- return dynamicPaint_doStep(bmain, eval_ctx, scene, cObject, surface, timescale, 0.0f);
+ return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f);
}
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index fa4e4372273..f5e5a37c7d7 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -52,32 +52,20 @@
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
+#include "BKE_editmesh_tangent.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "MEM_guardedalloc.h"
-#include "GPU_glew.h"
-#include "GPU_buffers.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
-static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4]);
-
typedef struct EditDerivedBMesh {
DerivedMesh dm;
BMEditMesh *em;
- /** when set, \a vertexNos, polyNos are lazy initialized */
- const float (*vertexCos)[3];
-
- /** lazy initialize (when \a vertexCos is set) */
- float const (*vertexNos)[3];
- float const (*polyNos)[3];
- /** also lazy init but dont depend on \a vertexCos */
- const float (*polyCos)[3];
+ EditMeshData emd;
} EditDerivedBMesh;
/* -------------------------------------------------------------------- */
@@ -87,7 +75,7 @@ static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm);
static void emDM_ensureVertNormals(EditDerivedBMesh *bmdm)
{
- if (bmdm->vertexCos && (bmdm->vertexNos == NULL)) {
+ if (bmdm->emd.vertexCos && (bmdm->emd.vertexNos == NULL)) {
BMesh *bm = bmdm->em->bm;
const float (*vertexCos)[3], (*polyNos)[3];
@@ -98,19 +86,19 @@ static void emDM_ensureVertNormals(EditDerivedBMesh *bmdm)
BM_mesh_elem_index_ensure(bm, BM_FACE);
- polyNos = bmdm->polyNos;
- vertexCos = bmdm->vertexCos;
+ polyNos = bmdm->emd.polyNos;
+ vertexCos = bmdm->emd.vertexCos;
vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__);
BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos);
- bmdm->vertexNos = (const float (*)[3])vertexNos;
+ bmdm->emd.vertexNos = (const float (*)[3])vertexNos;
}
}
static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm)
{
- if (bmdm->vertexCos && (bmdm->polyNos == NULL)) {
+ if (bmdm->emd.vertexCos && (bmdm->emd.polyNos == NULL)) {
BMesh *bm = bmdm->em->bm;
const float (*vertexCos)[3];
float (*polyNos)[3];
@@ -123,7 +111,7 @@ static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm)
polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__);
- vertexCos = bmdm->vertexCos;
+ vertexCos = bmdm->emd.vertexCos;
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
BM_elem_index_set(efa, i); /* set_inline */
@@ -131,13 +119,13 @@ static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm)
}
bm->elem_index_dirty &= ~BM_FACE;
- bmdm->polyNos = (const float (*)[3])polyNos;
+ bmdm->emd.polyNos = (const float (*)[3])polyNos;
}
}
static void emDM_ensurePolyCenters(EditDerivedBMesh *bmdm)
{
- if (bmdm->polyCos == NULL) {
+ if (bmdm->emd.polyCos == NULL) {
BMesh *bm = bmdm->em->bm;
float (*polyCos)[3];
@@ -147,9 +135,9 @@ static void emDM_ensurePolyCenters(EditDerivedBMesh *bmdm)
polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__);
- if (bmdm->vertexCos) {
+ if (bmdm->emd.vertexCos) {
const float (*vertexCos)[3];
- vertexCos = bmdm->vertexCos;
+ vertexCos = bmdm->emd.vertexCos;
BM_mesh_elem_index_ensure(bm, BM_VERT);
@@ -163,7 +151,7 @@ static void emDM_ensurePolyCenters(EditDerivedBMesh *bmdm)
}
}
- bmdm->polyCos = (const float (*)[3])polyCos;
+ bmdm->emd.polyCos = (const float (*)[3])polyCos;
}
}
@@ -199,9 +187,9 @@ static void emDM_calcLoopNormalsSpaceArray(
emDM_ensurePolyNormals(bmdm);
dm->dirty &= ~DM_DIRTY_NORMALS;
- vertexCos = bmdm->vertexCos;
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
+ vertexCos = bmdm->emd.vertexCos;
+ vertexNos = bmdm->emd.vertexNos;
+ polyNos = bmdm->emd.polyNos;
loopNos = dm->getLoopDataArray(dm, CD_NORMAL);
if (!loopNos) {
@@ -242,392 +230,29 @@ static void emDM_calcLoopNormalsSpaceArray(
#endif
}
-
-/** \name Tangent Space Calculation
- * \{ */
-
-/* Necessary complexity to handle looptri's as quads for correct tangents */
-#define USE_LOOPTRI_DETECT_QUADS
-
-typedef struct {
- const float (*precomputedFaceNormals)[3];
- const float (*precomputedLoopNormals)[3];
- const BMLoop *(*looptris)[3];
- int cd_loop_uv_offset; /* texture coordinates */
- const float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
-#endif
-
-} SGLSLEditMeshToTangent;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-/* seems weak but only used on quads */
-static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
-{
- const BMLoop *l = BM_FACE_FIRST_LOOP(f);
- while (vert_index--) {
- l = l->next;
- }
- return l;
-}
-#endif
-
-/* interface */
-#include "mikktspace.h"
-
-static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
-#else
- return pMesh->numTessFaces;
-#endif
-}
-
-static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
-#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- if (pMesh->face_as_quad_map) {
- const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- return 4;
- }
- }
- return 3;
-#else
- UNUSED_VARS(pContext, face_num);
- return 3;
-#endif
-}
-
-static void emdm_ts_GetPosition(
- const SMikkTSpaceContext *pContext, float r_co[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
- const float *co;
-
-finally:
- co = l->v->co;
- copy_v3_v3(r_co, co);
-}
-
-static void emdm_ts_GetTextureCoordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
-finally:
- if (pMesh->cd_loop_uv_offset != -1) {
- const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
- copy_v2_v2(r_uv, uv);
- }
- else {
- const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
- }
-}
-
-static void emdm_ts_GetNormal(
- const SMikkTSpaceContext *pContext, float r_no[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
-finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
- }
- else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
- }
- else {
- copy_v3_v3(r_no, l->f->no);
- }
- }
- else {
- copy_v3_v3(r_no, l->v->no);
- }
-}
-
-static void emdm_ts_SetTSpace(
- const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
- float *pRes;
-
-finally:
- pRes = pMesh->tangent[BM_elem_index_get(l)];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
-}
-
-static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
- /* new computation method */
- {
- SMikkTSpaceContext sContext = {NULL};
- SMikkTSpaceInterface sInterface = {NULL};
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = emdm_ts_GetPosition;
- sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = emdm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
-}
-
-/**
- * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data.
- *
- * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
- * This is done because #CD_TANGENT is cache data used only for drawing.
- */
-
static void emDM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count)
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len)
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BMEditMesh *em = bmdm->em;
- BMesh *bm = bmdm->em->bm;
-
- int act_uv_n = -1;
- int ren_uv_n = -1;
- bool calc_act = false;
- bool calc_ren = false;
- char act_uv_name[MAX_NAME];
- char ren_uv_name[MAX_NAME];
- short tangent_mask = 0;
-
- DM_calc_loop_tangents_step_0(
- &bm->ldata, calc_active_tangent, tangent_names, tangent_names_count,
- &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
-
- if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
- for (int i = 0; i < tangent_names_count; i++)
- if (tangent_names[i][0])
- DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]);
- if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1)
- CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, "");
- if (calc_act && act_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name);
- if (calc_ren && ren_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name);
- int totface = em->tottri;
-#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (bmdm->em->tottri != bm->totface) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
- int i, j;
- for (i = 0, j = 0; j < totface; i++, j++) {
- face_as_quad_map[i] = j;
- /* step over all quads */
- if (em->looptris[j][0]->f->len == 4) {
- j++; /* skips the nest looptri */
- }
- }
- num_face_as_quad_map = i;
- }
- else {
- num_face_as_quad_map = totface;
- }
-#endif
- /* Calculation */
- {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
-
- dm->tangent_mask = 0;
- /* Calculate tangent layers */
- SGLSLEditMeshToTangent data_array[MAX_MTFACE];
- int index = 0;
- int n = 0;
- CustomData_update_typemap(&dm->loopData);
- const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
- for (n = 0; n < tangent_layer_num; n++) {
- index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
- BLI_assert(n < MAX_MTFACE);
- SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
- mesh2tangent->numTessFaces = em->tottri;
-#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent->face_as_quad_map = face_as_quad_map;
- mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
-#endif
- mesh2tangent->precomputedFaceNormals = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- mesh2tangent->precomputedLoopNormals = CustomData_get_layer(&dm->loopData, CD_NORMAL);
- mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
-
- /* needed for indexing loop-tangents */
- int htype_index = BM_LOOP;
- if (mesh2tangent->cd_loop_uv_offset == -1) {
- mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
- if (!mesh2tangent->orco)
- continue;
- /* needed for orco lookups */
- htype_index |= BM_VERT;
- dm->tangent_mask |= DM_TANGENT_MASK_ORCO;
- }
- else {
- /* Fill the resulting tangent_mask */
- int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name);
- int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- dm->tangent_mask |= 1 << (uv_ind - uv_start);
- }
-
- if (mesh2tangent->precomputedFaceNormals) {
- /* needed for face normal lookups */
- htype_index |= BM_FACE;
- }
- BM_mesh_elem_index_ensure(bm, htype_index);
-
- mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
- mesh2tangent->tangent = dm->loopData.layers[index].data;
- BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
- }
-
- BLI_assert(dm->tangent_mask == tangent_mask);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- }
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (face_as_quad_map) {
- MEM_freeN(face_as_quad_map);
- }
-#undef USE_LOOPTRI_DETECT_QUADS
-#endif
+ if (CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV) == 0) {
+ return;
}
- /* Update active layer index */
- int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
- if (act_uv_index >= 0) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
-
- /* Update render layer index */
- int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
- if (ren_uv_index >= 0) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
+ const float (*poly_normals)[3] = bmdm->emd.polyNos;
+ const float (*loop_normals)[3] = CustomData_get_layer(&dm->loopData, CD_NORMAL);
+ const float (*vert_orco)[3] = dm->getVertDataArray(dm, CD_ORCO); /* can be NULL */
+ BKE_editmesh_loop_tangent_calc(
+ em, calc_active_tangent,
+ tangent_names, tangent_names_len,
+ poly_normals, loop_normals,
+ vert_orco,
+ &dm->loopData, dm->numLoopData,
+ &dm->tangent_mask);
}
-/** \} */
-
static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))
{
@@ -680,13 +305,13 @@ static void emDM_foreachMappedVert(
BMIter iter;
int i;
- if (bmdm->vertexCos) {
- const float (*vertexCos)[3] = bmdm->vertexCos;
+ if (bmdm->emd.vertexCos) {
+ const float (*vertexCos)[3] = bmdm->emd.vertexCos;
const float (*vertexNos)[3];
if (flag & DM_FOREACH_USE_NORMAL) {
emDM_ensureVertNormals(bmdm);
- vertexNos = bmdm->vertexNos;
+ vertexNos = bmdm->emd.vertexNos;
}
else {
vertexNos = NULL;
@@ -715,14 +340,14 @@ static void emDM_foreachMappedEdge(
BMIter iter;
int i;
- if (bmdm->vertexCos) {
+ if (bmdm->emd.vertexCos) {
BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
func(userData, i,
- bmdm->vertexCos[BM_elem_index_get(eed->v1)],
- bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
+ bmdm->emd.vertexCos[BM_elem_index_get(eed->v1)],
+ bmdm->emd.vertexCos[BM_elem_index_get(eed->v2)]);
}
}
else {
@@ -732,123 +357,6 @@ static void emDM_foreachMappedEdge(
}
}
-static void emDM_drawMappedEdges(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *eed;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]);
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
- }
- }
- glEnd();
- }
- else {
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- glVertex3fv(eed->v1->co);
- glVertex3fv(eed->v2->co);
- }
- }
- glEnd();
- }
-}
-static void emDM_drawEdges(
- DerivedMesh *dm,
- bool UNUSED(drawLooseEdges),
- bool UNUSED(drawAllEdges))
-{
- emDM_drawMappedEdges(dm, NULL, NULL);
-}
-
-static void emDM_drawMappedEdgesInterp(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetDrawInterpOptions setDrawInterpOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *eed;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- setDrawInterpOptions(userData, i, 0.0);
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]);
- setDrawInterpOptions(userData, i, 1.0);
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
- }
- }
- glEnd();
- }
- else {
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- setDrawInterpOptions(userData, i, 0.0);
- glVertex3fv(eed->v1->co);
- setDrawInterpOptions(userData, i, 1.0);
- glVertex3fv(eed->v2->co);
- }
- }
- glEnd();
- }
-}
-
-static void emDM_drawUVEdges(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMFace *efa;
- BMIter iter;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- if (UNLIKELY(cd_loop_uv_offset == -1)) {
- return;
- }
-
- glBegin(GL_LINES);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- const float *uv, *uv_prev;
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
- continue;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter->prev, cd_loop_uv_offset))->uv;
- do {
- uv = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- glVertex2fv(uv);
- glVertex2fv(uv_prev);
- uv_prev = uv;
- } while ((l_iter = l_iter->next) != l_first);
- }
- glEnd();
-}
-
static void emDM_foreachMappedLoop(
DerivedMesh *dm,
void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
@@ -864,7 +372,7 @@ static void emDM_foreachMappedLoop(
BMFace *efa;
BMIter iter;
- const float (*vertexCos)[3] = bmdm->vertexCos;
+ const float (*vertexCos)[3] = bmdm->emd.vertexCos;
int f_idx;
BM_mesh_elem_index_ensure(bm, BM_VERT);
@@ -897,11 +405,11 @@ static void emDM_foreachMappedFaceCenter(
int i;
emDM_ensurePolyCenters(bmdm);
- polyCos = bmdm->polyCos; /* always set */
+ polyCos = bmdm->emd.polyCos; /* always set */
if (flag & DM_FOREACH_USE_NORMAL) {
emDM_ensurePolyNormals(bmdm);
- polyNos = bmdm->polyNos; /* maybe NULL */
+ polyNos = bmdm->emd.polyNos; /* maybe NULL */
}
else {
polyNos = NULL;
@@ -921,783 +429,6 @@ static void emDM_foreachMappedFaceCenter(
}
}
-static void emDM_drawMappedFaces(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- /* currently unused -- each original face is handled separately */
- DMCompareDrawOptions UNUSED(compareDrawOptions),
- void *userData,
- DMDrawFlag flag)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- BMFace *efa;
- struct BMLoop *(*looptris)[3] = bmdm->em->looptris;
- const int tottri = bmdm->em->tottri;
- DMDrawOption draw_option;
- int i;
- const int skip_normals = !(flag & DM_DRAW_NEED_NORMALS);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */;
- unsigned char(*color_vert_array)[4] = em->derivedVertColor;
- unsigned char(*color_face_array)[4] = em->derivedFaceColor;
- bool has_vcol_preview = (color_vert_array != NULL) && !skip_normals;
- bool has_fcol_preview = (color_face_array != NULL) && !skip_normals;
- bool has_vcol_any = has_vcol_preview;
-
- /* GL_ZERO is used to detect if drawing has started or not */
- GLenum poly_prev = GL_ZERO;
- GLenum shade_prev = GL_ZERO;
- DMDrawOption draw_option_prev = DM_DRAW_OPTION_SKIP;
-
- /* call again below is ok */
- if (has_vcol_preview) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
- if (has_fcol_preview) {
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- }
- if (has_vcol_preview || has_fcol_preview) {
- flag |= DM_DRAW_ALWAYS_SMOOTH;
- /* weak, this logic should really be moved higher up */
- setMaterial = NULL;
- }
-
- if (bmdm->vertexCos) {
- short prev_mat_nr = -1;
-
- /* add direct access */
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
-
- if (skip_normals) {
- vertexNos = NULL;
- polyNos = NULL;
- }
- else {
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
- }
-
- BM_mesh_elem_index_ensure(bm, lnors ? BM_VERT | BM_FACE | BM_LOOP : BM_VERT | BM_FACE);
-
- for (i = 0; i < tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
- drawSmooth = lnors || ((flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : BM_elem_flag_test(efa, BM_ELEM_SMOOTH));
-
- draw_option = (!setDrawOptions ?
- DM_DRAW_OPTION_NORMAL :
- 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 (draw_option_prev != draw_option) {
- if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- draw_option_prev = draw_option;
- }
-
-
- if (efa->mat_nr != prev_mat_nr) {
- if (setMaterial) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- 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();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
-
- if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
- else if (has_fcol_preview) glColor3ubv((const GLubyte *)&(color_face_array[BM_elem_index_get(efa)]));
- if (skip_normals) {
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- const GLenum shade_type = drawSmooth ? GL_SMOOTH : GL_FLAT;
- if (shade_type != shade_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glShadeModel((shade_prev = shade_type)); /* same as below but switch shading */
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
-
- if (!drawSmooth) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- }
- }
- }
- }
- 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++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
- drawSmooth = lnors || ((flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : BM_elem_flag_test(efa, BM_ELEM_SMOOTH));
-
- draw_option = (setDrawOptions ?
- setDrawOptions(userData, BM_elem_index_get(efa)) :
- DM_DRAW_OPTION_NORMAL);
-
- 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 (draw_option_prev != draw_option) {
- if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- draw_option_prev = draw_option;
- }
-
- if (efa->mat_nr != prev_mat_nr) {
- if (setMaterial) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- 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();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
-
- if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
- else if (has_fcol_preview) glColor3ubv((const GLubyte *)&(color_face_array[BM_elem_index_get(efa)]));
-
- if (skip_normals) {
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- const GLenum shade_type = drawSmooth ? GL_SMOOTH : GL_FLAT;
- if (shade_type != shade_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glShadeModel((shade_prev = shade_type)); /* same as below but switch shading */
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
-
- if (!drawSmooth) {
- glNormal3fv(efa->no);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(ltri[0]->v->no);
- glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(ltri[1]->v->no);
- glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(ltri[2]->v->no);
- glVertex3fv(ltri[2]->v->co);
- }
- }
- }
- }
- }
-
- /* if non zero we know a face was rendered */
- if (poly_prev != GL_ZERO) glEnd();
-
- if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
-
- if (shade_prev == GL_FLAT) {
- glShadeModel(GL_SMOOTH);
- }
-}
-
-static void bmdm_get_tri_uv(BMLoop *ltri[3], MLoopUV *luv[3], const int cd_loop_uv_offset)
-{
- luv[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_uv_offset);
- luv[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_uv_offset);
- luv[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_uv_offset);
-}
-
-static void bmdm_get_tri_col(BMLoop *ltri[3], MLoopCol *lcol[3], const int cd_loop_color_offset)
-{
- lcol[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_color_offset);
- lcol[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_color_offset);
- lcol[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_color_offset);
-}
-
-static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4])
-{
- lcol[0] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[0]->v)];
- lcol[1] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[1]->v)];
- lcol[2] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[2]->v)];
-}
-
-static void emDM_drawFacesTex_common(
- DerivedMesh *dm,
- DMSetDrawOptionsTex drawParams,
- DMSetDrawOptionsMappedTex drawParamsMapped,
- DMCompareDrawOptions compareDrawOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- struct BMLoop *(*looptris)[3] = em->looptris;
- BMFace *efa;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- MLoopUV *luv[3], dummyluv = {{0}};
- MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
- unsigned char(*color_vert_array)[4] = em->derivedVertColor;
- bool has_uv = (cd_loop_uv_offset != -1);
- bool has_vcol_preview = (color_vert_array != NULL);
- bool has_vcol = (cd_loop_color_offset != -1) && (has_vcol_preview == false);
- bool has_vcol_any = (has_vcol_preview || has_vcol);
- int i;
-
- (void) compareDrawOptions;
-
- luv[0] = luv[1] = luv[2] = &dummyluv;
-
- // dummylcol.r = dummylcol.g = dummylcol.b = dummylcol.a = 255; /* UNUSED */
-
- /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- BM_mesh_elem_index_ensure(bm, BM_FACE);
-
- /* call again below is ok */
- if (has_vcol_preview) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
-
- if (bmdm->vertexCos) {
- /* add direct access */
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
-
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT);
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL;
- /*unsigned char *cp = NULL;*/ /*UNUSED*/
- int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH);
- DMDrawOption draw_option;
-
- efa = ltri[0]->f;
-
- if (drawParams) {
- draw_option = drawParams(tp, has_vcol, efa->mat_nr);
- }
- else if (drawParamsMapped)
- draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr);
- else
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
-
- if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset);
- if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset);
- else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
-
- glBegin(GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
-
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- glEnd();
- }
- }
- }
- else {
- BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT);
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL;
- /*unsigned char *cp = NULL;*/ /*UNUSED*/
- int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH);
- DMDrawOption draw_option;
-
- efa = ltri[0]->f;
-
- if (drawParams)
- draw_option = drawParams(tp, has_vcol, efa->mat_nr);
- else if (drawParamsMapped)
- draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr);
- else
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
-
- if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset);
- if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset);
- else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
-
- glBegin(GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(efa->no);
-
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(ltri[0]->v->no);
- glVertex3fv(ltri[0]->v->co);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(ltri[1]->v->no);
- glVertex3fv(ltri[1]->v->co);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(ltri[2]->v->no);
- glVertex3fv(ltri[2]->v->co);
- }
- glEnd();
- }
- }
- }
-}
-
-static void emDM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag UNUSED(flag))
-{
- emDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
-}
-
-static void emDM_drawMappedFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag UNUSED(flag))
-{
- emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
-}
-
-/**
- * \note
- *
- * For UV's:
- * const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, attribs->tface[i].em_offset);
- *
- * This is intentionally different to calling:
- * CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPUV, i);
- *
- * ... 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)
-{
- BMVert *eve = loop->v;
- int i;
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- if (attribs->totorco) {
- int index = BM_elem_index_get(eve);
- const float *orco = (attribs->orco.array) ? attribs->orco.array[index] : zero;
-
- if (attribs->orco.gl_texco)
- glTexCoord3fv(orco);
- else
- glVertexAttrib3fv(attribs->orco.gl_index, orco);
- }
- for (i = 0; i < attribs->tottface; i++) {
- const float *uv;
-
- if (attribs->tface[i].em_offset != -1) {
- const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, attribs->tface[i].em_offset);
- uv = luv->uv;
- }
- else {
- uv = zero;
- }
-
- if (attribs->tface[i].gl_texco)
- glTexCoord2fv(uv);
- else
- glVertexAttrib2fv(attribs->tface[i].gl_index, uv);
- }
- for (i = 0; i < attribs->totmcol; i++) {
- float col[4];
- if (attribs->mcol[i].em_offset != -1) {
- const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset);
- rgba_uchar_to_float(col, &cp->r);
- }
- else {
- col[0] = 0.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 0.0f;
- }
- glVertexAttrib4fv(attribs->mcol[i].gl_index, col);
- }
-
- for (i = 0; i < attribs->tottang; i++) {
- const float *tang;
- if (attribs->tang[i].em_offset != -1) {
- tang = attribs->tang[i].array[BM_elem_index_get(loop)];
- }
- else {
- tang = zero;
- }
- glVertexAttrib4fv(attribs->tang[i].gl_index, tang);
- }
-}
-
-static void emDM_drawMappedFacesGLSL(
- DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- struct BMLoop *(*looptris)[3] = em->looptris;
- /* add direct access */
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-
- BMFace *efa;
- DMVertexAttribs attribs;
- GPUVertexAttribs gattribs;
-
- int i, matnr, new_matnr, fi;
- bool do_draw;
-
- do_draw = false;
- matnr = -1;
-
- memset(&attribs, 0, sizeof(attribs));
-
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
-
- if (setDrawOptions && (setDrawOptions(userData, BM_elem_index_get(efa)) == DM_DRAW_OPTION_SKIP))
- continue;
-
- /* material */
- new_matnr = efa->mat_nr + 1;
- if (new_matnr != matnr) {
- if (matnr != -1)
- glEnd();
-
- do_draw = setMaterial(matnr = new_matnr, &gattribs);
- if (do_draw) {
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- DM_draw_attrib_vertex_uniforms(&attribs);
- if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
- BM_mesh_elem_index_ensure(bm, BM_LOOP);
- }
- }
-
- glBegin(GL_TRIANGLES);
- }
-
- if (do_draw) {
-
- /* draw face */
- drawSmooth = lnors || BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
-
- if (!drawSmooth) {
- if (vertexCos) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- 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]);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- else {
- 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]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(vertexNos[j]);
- glVertex3fv(vertexCos[j]);
- }
- }
- else {
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(ltri[fi]->v->no);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- }
- }
-
- if (matnr != -1) {
- glEnd();
- }
-}
-
-static void emDM_drawFacesGLSL(
- DerivedMesh *dm,
- int (*setMaterial)(int matnr, void *attribs))
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-static void emDM_drawMappedFacesMat(
- DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- struct BMLoop *(*looptris)[3] = em->looptris;
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- BMFace *efa;
- DMVertexAttribs attribs = {{{NULL}}};
- GPUVertexAttribs gattribs;
- int i, matnr, new_matnr, fi;
-
- matnr = -1;
-
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
-
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
-
- /* face hiding */
- if (setFace && !setFace(userData, BM_elem_index_get(efa)))
- continue;
-
- /* material */
- new_matnr = efa->mat_nr + 1;
- if (new_matnr != matnr) {
- if (matnr != -1)
- glEnd();
-
- setMaterial(userData, matnr = new_matnr, &gattribs);
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
- BM_mesh_elem_index_ensure(bm, BM_LOOP);
- }
-
- glBegin(GL_TRIANGLES);
- }
-
- /* draw face */
- drawSmooth = lnors || BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
-
- if (!drawSmooth) {
- if (vertexCos) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- 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]);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- else {
- 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]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(vertexNos[j]);
- glVertex3fv(vertexCos[j]);
- }
- }
- else {
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(ltri[fi]->v->no);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- }
-
- if (matnr != -1) {
- glEnd();
- }
-}
-
static void emDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3])
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
@@ -1707,9 +438,9 @@ static void emDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3])
int i;
if (bm->totvert) {
- if (bmdm->vertexCos) {
+ if (bmdm->emd.vertexCos) {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- minmax_v3v3_v3(r_min, r_max, bmdm->vertexCos[i]);
+ minmax_v3v3_v3(r_min, r_max, bmdm->emd.vertexCos[i]);
}
}
else {
@@ -1789,8 +520,8 @@ static void emDM_getVert(DerivedMesh *dm, int index, MVert *r_vert)
// ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */
bmvert_to_mvert(bm, ev, r_vert);
- if (bmdm->vertexCos)
- copy_v3_v3(r_vert->co, bmdm->vertexCos[index]);
+ if (bmdm->emd.vertexCos)
+ copy_v3_v3(r_vert->co, bmdm->emd.vertexCos[index]);
}
static void emDM_getVertCo(DerivedMesh *dm, int index, float r_co[3])
@@ -1803,8 +534,8 @@ static void emDM_getVertCo(DerivedMesh *dm, int index, float r_co[3])
return;
}
- if (bmdm->vertexCos) {
- copy_v3_v3(r_co, bmdm->vertexCos[index]);
+ if (bmdm->emd.vertexCos) {
+ copy_v3_v3(r_co, bmdm->emd.vertexCos[index]);
}
else {
BMVert *ev;
@@ -1827,9 +558,9 @@ static void emDM_getVertNo(DerivedMesh *dm, int index, float r_no[3])
}
- if (bmdm->vertexCos) {
+ if (bmdm->emd.vertexCos) {
emDM_ensureVertNormals(bmdm);
- copy_v3_v3(r_no, bmdm->vertexNos[index]);
+ copy_v3_v3(r_no, bmdm->emd.vertexNos[index]);
}
else {
BMVert *ev;
@@ -1851,9 +582,9 @@ static void emDM_getPolyNo(DerivedMesh *dm, int index, float r_no[3])
return;
}
- if (bmdm->vertexCos) {
+ if (bmdm->emd.vertexCos) {
emDM_ensurePolyNormals(bmdm);
- copy_v3_v3(r_no, bmdm->polyNos[index]);
+ copy_v3_v3(r_no, bmdm->emd.polyNos[index]);
}
else {
BMFace *efa;
@@ -1928,11 +659,11 @@ static void emDM_copyVertArray(DerivedMesh *dm, MVert *r_vert)
BMIter iter;
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- if (bmdm->vertexCos) {
+ if (bmdm->emd.vertexCos) {
int i;
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(r_vert->co, bmdm->vertexCos[i]);
+ copy_v3_v3(r_vert->co, bmdm->emd.vertexCos[i]);
normal_float_to_short_v3(r_vert->no, eve->no);
r_vert->flag = BM_vert_flag_to_mflag(eve);
@@ -2061,14 +792,8 @@ static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type)
if (type == CD_MTFACE || type == CD_MCOL) {
const char *bmdata;
char *data;
- bool has_type_source = false;
- if (type == CD_MTFACE) {
- has_type_source = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY);
- }
- else {
- has_type_source = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL);
- }
+ bool has_type_source = CustomData_has_layer(&bm->ldata, (type == CD_MTFACE) ? CD_MLOOPUV : CD_MLOOPCOL);
if (has_type_source) {
/* offset = bm->pdata.layers[index].offset; */ /* UNUSED */
@@ -2084,15 +809,8 @@ static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type)
if (type == CD_MTFACE) {
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
for (i = 0; i < bmdm->em->tottri; i++, data += size) {
- BMFace *efa = looptris[i][0]->f;
-
- // bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY);
- bmdata = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- ME_MTEXFACE_CPY(((MTFace *)data), ((const MTexPoly *)bmdata));
for (j = 0; j < 3; j++) {
// bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPUV);
bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_uv_offset);
@@ -2149,9 +867,9 @@ static void emDM_getVertCos(DerivedMesh *dm, float (*r_cos)[3])
BMIter iter;
int i;
- if (bmdm->vertexCos) {
+ if (bmdm->emd.vertexCos) {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(r_cos[i], bmdm->vertexCos[i]);
+ copy_v3_v3(r_cos[i], bmdm->emd.vertexCos[i]);
}
}
else {
@@ -2166,18 +884,18 @@ static void emDM_release(DerivedMesh *dm)
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
if (DM_release(dm)) {
- if (bmdm->vertexCos) {
- MEM_freeN((void *)bmdm->vertexCos);
- if (bmdm->vertexNos) {
- MEM_freeN((void *)bmdm->vertexNos);
+ if (bmdm->emd.vertexCos) {
+ MEM_freeN((void *)bmdm->emd.vertexCos);
+ if (bmdm->emd.vertexNos) {
+ MEM_freeN((void *)bmdm->emd.vertexNos);
}
- if (bmdm->polyNos) {
- MEM_freeN((void *)bmdm->polyNos);
+ if (bmdm->emd.polyNos) {
+ MEM_freeN((void *)bmdm->emd.polyNos);
}
}
- if (bmdm->polyCos) {
- MEM_freeN((void *)bmdm->polyCos);
+ if (bmdm->emd.polyCos) {
+ MEM_freeN((void *)bmdm->emd.polyCos);
}
MEM_freeN(bmdm);
@@ -2280,20 +998,9 @@ DerivedMesh *getEditDerivedBMesh(
bmdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
bmdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter;
- bmdm->dm.drawEdges = emDM_drawEdges;
- bmdm->dm.drawMappedEdges = emDM_drawMappedEdges;
- bmdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp;
- bmdm->dm.drawMappedFaces = emDM_drawMappedFaces;
- bmdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex;
- bmdm->dm.drawMappedFacesGLSL = emDM_drawMappedFacesGLSL;
- bmdm->dm.drawMappedFacesMat = emDM_drawMappedFacesMat;
- bmdm->dm.drawFacesTex = emDM_drawFacesTex;
- bmdm->dm.drawFacesGLSL = emDM_drawFacesGLSL;
- bmdm->dm.drawUVEdges = emDM_drawUVEdges;
-
bmdm->dm.release = emDM_release;
- bmdm->vertexCos = (const float (*)[3])vertexCos;
+ bmdm->emd.vertexCos = (const float (*)[3])vertexCos;
bmdm->dm.deformedOnly = (vertexCos != NULL);
const int cd_dvert_offset = (data_mask & CD_MASK_MDEFORMVERT) ?
@@ -2721,7 +1428,7 @@ void BKE_editmesh_statvis_calc(
{
BKE_editmesh_color_ensure(em, BM_FACE);
statvis_calc_overhang(
- em, bmdm ? bmdm->polyNos : NULL,
+ em, bmdm ? bmdm->emd.polyNos : NULL,
statvis->overhang_min / (float)M_PI,
statvis->overhang_max / (float)M_PI,
statvis->overhang_axis,
@@ -2733,7 +1440,7 @@ void BKE_editmesh_statvis_calc(
const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
BKE_editmesh_color_ensure(em, BM_FACE);
statvis_calc_thickness(
- em, bmdm ? bmdm->vertexCos : NULL,
+ em, bmdm ? bmdm->emd.vertexCos : NULL,
statvis->thickness_min * scale,
statvis->thickness_max * scale,
statvis->thickness_samples,
@@ -2744,7 +1451,7 @@ void BKE_editmesh_statvis_calc(
{
BKE_editmesh_color_ensure(em, BM_FACE);
statvis_calc_intersect(
- em, bmdm ? bmdm->vertexCos : NULL,
+ em, bmdm ? bmdm->emd.vertexCos : NULL,
em->derivedFaceColor);
break;
}
@@ -2756,7 +1463,7 @@ void BKE_editmesh_statvis_calc(
emDM_ensurePolyNormals(bmdm);
statvis_calc_distort(
- em, bmdm ? bmdm->vertexCos : NULL, bmdm ? bmdm->polyNos : NULL,
+ em, bmdm ? bmdm->emd.vertexCos : NULL, bmdm ? bmdm->emd.polyNos : NULL,
statvis->distort_min,
statvis->distort_max,
em->derivedFaceColor);
@@ -2766,7 +1473,7 @@ void BKE_editmesh_statvis_calc(
{
BKE_editmesh_color_ensure(em, BM_VERT);
statvis_calc_sharp(
- em, bmdm ? bmdm->vertexCos : NULL,
+ em, bmdm ? bmdm->emd.vertexCos : NULL,
statvis->sharp_min,
statvis->sharp_max,
/* in this case they are vertex colors */
@@ -2799,14 +1506,14 @@ static void cage_mapped_verts_callback(
}
}
-float (*BKE_editmesh_vertexCos_get(BMEditMesh *em, Scene *scene, int *r_numVerts))[3]
+float (*BKE_editmesh_vertexCos_get(struct Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, int *r_numVerts))[3]
{
DerivedMesh *cage, *final;
BLI_bitmap *visit_bitmap;
struct CageUserData data;
float (*cos_cage)[3];
- cage = editbmesh_get_derived_cage_and_final(scene, em->ob, em, CD_MASK_BAREMESH, &final);
+ cage = editbmesh_get_derived_cage_and_final(depsgraph, scene, em->ob, em, CD_MASK_BAREMESH, &final);
cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
/* when initializing cage verts, we only want the first cage coordinate for each vertex,
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index fea3c24d322..b63ab276b14 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -89,11 +89,13 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
/* sanity check */
+#if 0 /* disable in mutlti-object edit. */
#ifndef NDEBUG
if (((Mesh *)ob->data)->edit_btmesh) {
BLI_assert(((Mesh *)ob->data)->edit_btmesh->ob == ob);
}
#endif
+#endif
return ((Mesh *)ob->data)->edit_btmesh;
}
@@ -165,26 +167,6 @@ void BKE_editmesh_tessface_calc(BMEditMesh *em)
#endif
}
-void BKE_editmesh_update_linked_customdata(BMEditMesh *em)
-{
- BMesh *bm = em->bm;
- int act;
-
- if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) {
- act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act);
- }
-}
-
void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
{
if (em->derivedCage) {
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
new file mode 100644
index 00000000000..9e8b4fa8782
--- /dev/null
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -0,0 +1,431 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/editmesh_tangent.c
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BKE_DerivedMesh.h"
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h" /* for utility functions */
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_tangent.h"
+
+#include "MEM_guardedalloc.h"
+
+/* interface */
+#include "mikktspace.h"
+
+/** \name Tangent Space Calculation
+ * \{ */
+
+/* Necessary complexity to handle looptri's as quads for correct tangents */
+#define USE_LOOPTRI_DETECT_QUADS
+
+typedef struct {
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const BMLoop *(*looptris)[3];
+ int cd_loop_uv_offset; /* texture coordinates */
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
+#endif
+
+} SGLSLEditMeshToTangent;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+/* seems weak but only used on quads */
+static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
+{
+ const BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ while (vert_index--) {
+ l = l->next;
+ }
+ return l;
+}
+#endif
+
+static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ return pMesh->num_face_as_quad_map;
+#else
+ return pMesh->numTessFaces;
+#endif
+}
+
+static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ return 4;
+ }
+ }
+ return 3;
+#else
+ UNUSED_VARS(pContext, face_num);
+ return 3;
+#endif
+}
+
+static void emdm_ts_GetPosition(
+ const SMikkTSpaceContext *pContext, float r_co[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+ const float *co;
+
+finally:
+ co = l->v->co;
+ copy_v3_v3(r_co, co);
+}
+
+static void emdm_ts_GetTextureCoordinate(
+ const SMikkTSpaceContext *pContext, float r_uv[2],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+finally:
+ if (pMesh->cd_loop_uv_offset != -1) {
+ const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
+ copy_v2_v2(r_uv, uv);
+ }
+ else {
+ const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
+ map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+ }
+}
+
+static void emdm_ts_GetNormal(
+ const SMikkTSpaceContext *pContext, float r_no[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+finally:
+ if (pMesh->precomputedLoopNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
+ }
+ else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
+ if (pMesh->precomputedFaceNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
+ }
+ else {
+ copy_v3_v3(r_no, l->f->no);
+ }
+ }
+ else {
+ copy_v3_v3(r_no, l->v->no);
+ }
+}
+
+static void emdm_ts_SetTSpace(
+ const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+ float *pRes;
+
+finally:
+ pRes = pMesh->tangent[BM_elem_index_get(l)];
+ copy_v3_v3(pRes, fvTangent);
+ pRes[3] = fSign;
+}
+
+static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
+ /* new computation method */
+ {
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+ sContext.m_pUserData = mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = emdm_ts_GetPosition;
+ sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = emdm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
+}
+
+/**
+ * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
+ *
+ * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
+ * This is done because #CD_TANGENT is cache data used only for drawing.
+ */
+void BKE_editmesh_loop_tangent_calc(
+ BMEditMesh *em, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p)
+{
+ BMesh *bm = em->bm;
+
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ short tangent_mask = 0;
+ short tangent_mask_curr = *tangent_mask_curr_p;
+
+ BKE_mesh_calc_loop_tangent_step_0(
+ &bm->ldata, calc_active_tangent, tangent_names, tangent_names_len,
+ &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+
+ if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
+ for (int i = 0; i < tangent_names_len; i++) {
+ if (tangent_names[i][0]) {
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ &bm->ldata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
+ }
+ }
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
+ if (calc_act && act_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
+ int totface = em->tottri;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (em->tottri != bm->totface) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+ int i, j;
+ for (i = 0, j = 0; j < totface; i++, j++) {
+ face_as_quad_map[i] = j;
+ /* step over all quads */
+ if (em->looptris[j][0]->f->len == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = i;
+ }
+ else {
+ num_face_as_quad_map = totface;
+ }
+#endif
+ /* Calculation */
+ if (em->tottri != 0) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ tangent_mask_curr = 0;
+ /* Calculate tangent layers */
+ SGLSLEditMeshToTangent data_array[MAX_MTFACE];
+ int index = 0;
+ int n = 0;
+ CustomData_update_typemap(loopdata_out);
+ const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
+ for (n = 0; n < tangent_layer_num; n++) {
+ index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = em->tottri;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+#endif
+ mesh2tangent->precomputedFaceNormals = poly_normals; /* dm->getPolyDataArray(dm, CD_NORMAL) */
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = loop_normals;
+ mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
+
+ /* needed for indexing loop-tangents */
+ int htype_index = BM_LOOP;
+ if (mesh2tangent->cd_loop_uv_offset == -1) {
+ mesh2tangent->orco = vert_orco;
+ if (!mesh2tangent->orco)
+ continue;
+ /* needed for orco lookups */
+ htype_index |= BM_VERT;
+ tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
+ }
+ else {
+ /* Fill the resulting tangent_mask */
+ int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name);
+ int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ tangent_mask_curr |= 1 << (uv_ind - uv_start);
+ }
+ if (mesh2tangent->precomputedFaceNormals) {
+ /* needed for face normal lookups */
+ htype_index |= BM_FACE;
+ }
+ BM_mesh_elem_index_ensure(bm, htype_index);
+
+ mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
+ mesh2tangent->tangent = loopdata_out->layers[index].data;
+
+ BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
+
+ BLI_assert(tangent_mask_curr == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
+ else {
+ tangent_mask_curr = tangent_mask;
+ }
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+#undef USE_LOOPTRI_DETECT_QUADS
+#endif
+ }
+
+ *tangent_mask_curr_p = tangent_mask_curr;
+
+ int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
+ CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
+
+ /* Update render layer index */
+ int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
+ CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 89f85530439..adf5b5da35e 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -57,6 +57,7 @@
#include "PIL_time.h"
#include "BKE_anim.h" /* needed for where_on_path */
+#include "BKE_collection.h"
#include "BKE_collision.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
@@ -64,6 +65,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -71,6 +73,9 @@
#include "BKE_scene.h"
#include "BKE_smoke.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
@@ -82,7 +87,7 @@
#include <string.h>
#endif // WITH_MOD_FLUID
-EffectorWeights *BKE_add_effector_weights(Group *group)
+EffectorWeights *BKE_add_effector_weights(Collection *collection)
{
EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights");
int i;
@@ -92,7 +97,7 @@ EffectorWeights *BKE_add_effector_weights(Group *group)
weights->global_gravity = 1.0f;
- weights->group = group;
+ weights->group = collection;
return weights;
}
@@ -131,9 +136,8 @@ PartDeflect *object_add_collision_fields(int type)
return pd;
}
-/* ***************** PARTICLES ***************** */
+/************************ PARTICLES ***************************/
-/* -------------------------- Effectors ------------------ */
void free_partdeflect(PartDeflect *pd)
{
if (!pd)
@@ -145,175 +149,187 @@ void free_partdeflect(PartDeflect *pd)
MEM_freeN(pd);
}
-static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
-{
- EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
- eff->scene = scene;
- eff->ob = ob;
- eff->psys = psys;
- eff->pd = pd;
- eff->frame = -1;
- return eff;
-}
-static void add_object_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src, bool for_simulation)
+/******************** EFFECTOR RELATIONS ***********************/
+
+static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *eff)
{
- EffectorCache *eff = NULL;
+ float ctime = DEG_get_ctime(depsgraph);
+ unsigned int cfra = (unsigned int)(ctime >= 0 ? ctime : -ctime);
+ if (!eff->pd->rng)
+ eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
+ else
+ BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
- if ( ob == ob_src )
- return;
+ if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type==OB_CURVE) {
+ Curve *cu= eff->ob->data;
+ if (cu->flag & CU_PATH) {
+ if (eff->ob->curve_cache == NULL || eff->ob->curve_cache->path==NULL || eff->ob->curve_cache->path->data==NULL)
+ BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, 0);
- if (for_simulation) {
- if (weights->weight[ob->pd->forcefield] == 0.0f )
- return;
+ if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) {
+ where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
+ mul_m4_v3(eff->ob->obmat, eff->guide_loc);
+ mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
+ }
+ }
+ }
+ else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
+ eff->surmd = (SurfaceModifierData *)modifiers_findByType( eff->ob, eModifierType_Surface );
+ if (eff->ob->type == OB_CURVE)
+ eff->flag |= PE_USE_NORMAL_DATA;
+ }
+ else if (eff->psys)
+ psys_update_particle_tree(eff->psys, ctime);
- if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal )
- return;
+ /* Store object velocity */
+ if (eff->ob) {
+ float old_vel[3];
+
+ BKE_object_where_is_calc_time(depsgraph, eff->scene, eff->ob, cfra - 1.0f);
+ copy_v3_v3(old_vel, eff->ob->obmat[3]);
+ BKE_object_where_is_calc_time(depsgraph, eff->scene, eff->ob, cfra);
+ sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel);
}
+}
- if (*effectors == NULL)
- *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
+static void add_effector_relation(ListBase *relations, Object *ob, ParticleSystem *psys, PartDeflect *pd)
+{
+ EffectorRelation *relation = MEM_callocN(sizeof(EffectorRelation), "EffectorRelation");
+ relation->ob = ob;
+ relation->psys = psys;
+ relation->pd = pd;
- eff = new_effector_cache(scene, ob, NULL, ob->pd);
+ BLI_addtail(relations, relation);
+}
- /* make sure imat is up to date */
- invert_m4_m4(ob->imat, ob->obmat);
+static void add_effector_evaluation(ListBase **effectors, Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
+{
+ if (*effectors == NULL) {
+ *effectors = MEM_callocN(sizeof(ListBase), "effector effectors");
+ }
+ EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
+ eff->depsgraph = depsgraph;
+ eff->scene = scene;
+ eff->ob = ob;
+ eff->psys = psys;
+ eff->pd = pd;
+ eff->frame = -1;
BLI_addtail(*effectors, eff);
+
+ precalculate_effector(depsgraph, eff);
}
-static void add_particles_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src, bool for_simulation)
+
+/* Create list of effector relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of effectors during evaluation. */
+ListBase *BKE_effector_relations_create(
+ Depsgraph *depsgraph,
+ ViewLayer *view_layer,
+ Collection *collection)
{
- ParticleSettings *part= psys->part;
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ Base *base = BKE_collection_or_layer_objects(NULL, NULL, view_layer, collection);
+ ListBase *relations = MEM_callocN(sizeof(ListBase), "effector relations");
- if ( !psys_check_enabled(ob, psys, G.is_rendering) )
- return;
+ for (; base; base = base->next) {
+ Object *ob = base->object;
- if ( psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0)
- return;
+ if (ob->pd && ob->pd->forcefield) {
+ add_effector_relation(relations, ob, NULL, ob->pd);
+ }
- if ( part->pd && part->pd->forcefield && (!for_simulation || weights->weight[part->pd->forcefield] != 0.0f)) {
- if (*effectors == NULL)
- *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
+ for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
- BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd));
+ if (psys_check_enabled(ob, psys, for_render)) {
+ if (part->pd && part->pd->forcefield) {
+ add_effector_relation(relations, ob, psys, part->pd);
+ }
+ if (part->pd2 && part->pd2->forcefield) {
+ add_effector_relation(relations, ob, psys, part->pd2);
+ }
+ }
+ }
}
- if (part->pd2 && part->pd2->forcefield && (!for_simulation || weights->weight[part->pd2->forcefield] != 0.0f)) {
- if (*effectors == NULL)
- *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
+ return relations;
+}
- BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd2));
+void BKE_effector_relations_free(ListBase *lb)
+{
+ if (lb) {
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
}
}
-/* returns ListBase handle with objects taking part in the effecting */
-ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src,
- EffectorWeights *weights, bool for_simulation)
+/* Create effective list of effectors from relations built beforehand. */
+ListBase *BKE_effectors_create(
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob_src,
+ ParticleSystem *psys_src,
+ EffectorWeights *weights)
{
- Base *base;
- unsigned int layer= ob_src->lay;
+ ListBase *relations = DEG_get_effector_relations(depsgraph, weights->group);
ListBase *effectors = NULL;
- if (weights->group) {
- GroupObject *go;
+ if (!relations) {
+ return NULL;
+ }
- for (go= weights->group->gobject.first; go; go= go->next) {
- if ( (go->ob->lay & layer) ) {
- if ( go->ob->pd && go->ob->pd->forcefield )
- add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src, for_simulation);
+ for (EffectorRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
- if ( go->ob->particlesystem.first ) {
- ParticleSystem *psys= go->ob->particlesystem.first;
+ if (relation->psys) {
+ /* Get evaluated particle system. */
+ ParticleSystem *psys = BLI_findstring(&ob->particlesystem,
+ relation->psys->name, offsetof(ParticleSystem, name));
+ ParticleSettings *part = psys->part;
- for ( ; psys; psys=psys->next )
- add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src, for_simulation);
- }
+ if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) {
+ continue;
}
- }
- }
- else {
- for (base = scene->base.first; base; base= base->next) {
- if ( (base->lay & layer) ) {
- if ( base->object->pd && base->object->pd->forcefield )
- add_object_to_effectors(&effectors, scene, weights, base->object, ob_src, for_simulation);
- if ( base->object->particlesystem.first ) {
- ParticleSystem *psys= base->object->particlesystem.first;
+ PartDeflect *pd = (relation->pd == relation->psys->part->pd) ? part->pd : part->pd2;
+ if (weights->weight[pd->forcefield] == 0.0f) {
+ continue;
+ }
- for ( ; psys; psys=psys->next )
- add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src, for_simulation);
- }
+ add_effector_evaluation(&effectors, depsgraph, scene, ob, psys, pd);
+ }
+ else {
+ /* Object effector. */
+ if (ob == ob_src) {
+ continue;
}
+ else if (weights->weight[ob->pd->forcefield] == 0.0f) {
+ continue;
+ }
+ else if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal) {
+ continue;
+ }
+
+ add_effector_evaluation(&effectors, depsgraph, scene, ob, NULL, ob->pd);
}
}
- if (for_simulation)
- pdPrecalculateEffectors(effectors);
-
return effectors;
}
-void pdEndEffectors(ListBase **effectors)
+void BKE_effectors_free(ListBase *lb)
{
- if (*effectors) {
- EffectorCache *eff = (*effectors)->first;
-
- for (; eff; eff=eff->next) {
- if (eff->guide_data)
+ if (lb) {
+ for (EffectorCache *eff = lb->first; eff; eff = eff->next) {
+ if (eff->guide_data) {
MEM_freeN(eff->guide_data);
- }
-
- BLI_freelistN(*effectors);
- MEM_freeN(*effectors);
- *effectors = NULL;
- }
-}
-
-static void precalculate_effector(EffectorCache *eff)
-{
- unsigned int cfra = (unsigned int)(eff->scene->r.cfra >= 0 ? eff->scene->r.cfra : -eff->scene->r.cfra);
- if (!eff->pd->rng)
- eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
- else
- BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
-
- if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type==OB_CURVE) {
- Curve *cu= eff->ob->data;
- if (cu->flag & CU_PATH) {
- if (eff->ob->curve_cache == NULL || eff->ob->curve_cache->path==NULL || eff->ob->curve_cache->path->data==NULL)
- BKE_displist_make_curveTypes(eff->scene, eff->ob, 0);
-
- if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) {
- where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
- mul_m4_v3(eff->ob->obmat, eff->guide_loc);
- mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
}
}
- }
- else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
- eff->surmd = (SurfaceModifierData *)modifiers_findByType( eff->ob, eModifierType_Surface );
- if (eff->ob->type == OB_CURVE)
- eff->flag |= PE_USE_NORMAL_DATA;
- }
- else if (eff->psys)
- psys_update_particle_tree(eff->psys, eff->scene->r.cfra);
-
- /* Store object velocity */
- if (eff->ob) {
- float old_vel[3];
- BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra - 1.0f);
- copy_v3_v3(old_vel, eff->ob->obmat[3]);
- BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra);
- sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel);
- }
-}
-
-void pdPrecalculateEffectors(ListBase *effectors)
-{
- if (effectors) {
- EffectorCache *eff = effectors->first;
- for (; eff; eff=eff->next)
- precalculate_effector(eff);
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
}
}
@@ -565,7 +581,7 @@ int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], floa
}
int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity)
{
- float cfra = eff->scene->r.cfra;
+ float cfra = DEG_get_ctime(eff->depsgraph);
int ret = 0;
/* In case surface object is in Edit mode when loading the .blend, surface modifier is never executed
@@ -612,6 +628,7 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
}
else {
ParticleSimulationData sim= {NULL};
+ sim.depsgraph = eff->depsgraph;
sim.scene= eff->scene;
sim.ob= eff->ob;
sim.psys= eff->psys;
@@ -971,7 +988,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
}
}
-/* -------- pdDoEffectors() --------
+/* -------- BKE_effectors_apply() --------
* generic force/speed system, now used for particles and softbodies
* scene = scene where it runs in, for time and stuff
* lb = listbase with objects that take part in effecting
@@ -984,7 +1001,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
* flags = only used for softbody wind now
* guide = old speed of particle
*/
-void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
+void BKE_effectors_apply(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
{
/*
* Modifies the force on a particle according to its
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 524919b3dc0..e63d99a35ee 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1922,13 +1922,14 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
* - "evaltime" is the frame at which F-Curve is being evaluated
* - has to return a float value
+ * - driver_orig is where we cache Python expressions, in case of COW
*/
-float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime)
+float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime)
{
DriverVar *dvar;
/* check if driver can be evaluated */
- if (driver->flag & DRIVER_FLAG_INVALID)
+ if (driver_orig->flag & DRIVER_FLAG_INVALID)
return 0.0f;
switch (driver->type) {
@@ -1998,8 +1999,8 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const fl
{
#ifdef WITH_PYTHON
/* check for empty or invalid expression */
- if ( (driver->expression[0] == '\0') ||
- (driver->flag & DRIVER_FLAG_INVALID) )
+ if ( (driver_orig->expression[0] == '\0') ||
+ (driver_orig->flag & DRIVER_FLAG_INVALID) )
{
driver->curval = 0.0f;
}
@@ -2009,7 +2010,7 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const fl
*/
BLI_mutex_lock(&python_driver_lock);
- driver->curval = BPY_driver_exec(anim_rna, driver, evaltime);
+ driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime);
BLI_mutex_unlock(&python_driver_lock);
}
@@ -2705,7 +2706,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime)
return evaluate_fcurve_ex(fcu, evaltime, 0.0);
}
-float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
+float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, ChannelDriver *driver_orig, float evaltime)
{
BLI_assert(fcu->driver != NULL);
float cvalue = 0.0f;
@@ -2715,7 +2716,7 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evalt
*/
if (fcu->driver) {
/* evaltime now serves as input for the curve */
- evaltime = evaluate_driver(anim_rna, fcu->driver, evaltime);
+ evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, evaltime);
/* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */
if (fcu->totvert == 0) {
@@ -2762,7 +2763,7 @@ float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
/* calculate and set curval (evaluates driver too if necessary) */
float curval;
if (fcu->driver) {
- curval = evaluate_fcurve_driver(anim_rna, fcu, evaltime);
+ curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, evaltime);
}
else {
curval = evaluate_fcurve(fcu, evaltime);
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index 7dc6e3575b2..c79b2bb4aee 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -64,7 +64,7 @@
// file handling
//-------------------------------------------------------------------------------
-void initElbeemMesh(struct Scene *scene, struct Object *ob,
+void initElbeemMesh(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
int *numVertices, float **vertices,
int *numTriangles, int **triangles,
int useGlobalCoords, int modifierIndex)
@@ -77,7 +77,7 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob,
float *verts;
int *tris;
- dm = mesh_create_derived_index_render(scene, ob, CD_MASK_BAREMESH, modifierIndex);
+ dm = mesh_create_derived_index_render(depsgraph, scene, ob, CD_MASK_BAREMESH, modifierIndex);
mvert = dm->getVertArray(dm);
mloop = dm->getLoopArray(dm);
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index cf2521509b5..36633663f9d 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -1022,7 +1022,7 @@ makebreak:
/* top and top-baseline are the same when text-boxes are used */
if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) {
/* all previous textboxes are 'full', only align the last used text-box */
- float yoff;
+ float yoff = 0.0f;
int lines;
struct CharTrans *ct_last, *ct_textbox;
@@ -1051,7 +1051,7 @@ makebreak:
else {
/* non text-box case handled separately */
ct = chartransdata;
- float yoff;
+ float yoff = 0.0f;
if (cu->align_y == CU_ALIGN_Y_TOP) {
yoff = -linedist;
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 686fe3bda93..d439b5e7a6e 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -61,17 +61,21 @@ void BKE_freestyle_config_init(FreestyleConfig *config)
BLI_listbase_clear(&config->linesets);
}
-void BKE_freestyle_config_free(FreestyleConfig *config)
+void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user)
{
FreestyleLineSet *lineset;
for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
if (lineset->group) {
- id_us_min(&lineset->group->id);
+ if (do_id_user) {
+ id_us_min(&lineset->group->id);
+ }
lineset->group = NULL;
}
if (lineset->linestyle) {
- id_us_min(&lineset->linestyle->id);
+ if (do_id_user) {
+ id_us_min(&lineset->linestyle->id);
+ }
lineset->linestyle = NULL;
}
}
@@ -79,7 +83,7 @@ void BKE_freestyle_config_free(FreestyleConfig *config)
BLI_freelistN(&config->modules);
}
-void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag)
+void BKE_freestyle_config_copy(FreestyleConfig *new_config, const FreestyleConfig *config, const int flag)
{
FreestyleLineSet *lineset, *new_lineset;
FreestyleModuleConfig *module, *new_module;
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
deleted file mode 100644
index 62f608f8565..00000000000
--- a/source/blender/blenkernel/intern/group.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * ***** 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) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/group.c
- * \ingroup bke
- */
-
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_group_types.h"
-#include "DNA_material_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_particle_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-
-
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-#include "BKE_group.h"
-#include "BKE_icons.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-#include "BKE_scene.h" /* BKE_scene_base_find */
-
-static void free_group_object(GroupObject *go)
-{
- MEM_freeN(go);
-}
-
-/** Free (or release) any data used by this group (does not free the group itself). */
-void BKE_group_free(Group *group)
-{
- /* don't free group itself */
- GroupObject *go;
-
- /* No animdata here. */
-
- while ((go = BLI_pophead(&group->gobject))) {
- free_group_object(go);
- }
-
- BKE_previewimg_free(&group->preview);
-}
-
-Group *BKE_group_add(Main *bmain, const char *name)
-{
- Group *group;
-
- group = BKE_libblock_alloc(bmain, ID_GR, name, 0);
- id_us_min(&group->id);
- id_us_ensure_real(&group->id);
- group->layer = (1 << 20) - 1;
-
- group->preview = NULL;
-
- return group;
-}
-
-/**
- * Only copy internal data of Group ID from source to already allocated/initialized destination.
- * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
- *
- * WARNING! This function will not handle ID user count!
- *
- * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
- */
-void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag)
-{
- BLI_duplicatelist(&group_dst->gobject, &group_src->gobject);
-
- /* Do not copy group's preview (same behavior as for objects). */
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
- BKE_previewimg_id_copy(&group_dst->id, &group_src->id);
- }
- else {
- group_dst->preview = NULL;
- }
-}
-
-Group *BKE_group_copy(Main *bmain, const Group *group)
-{
- Group *group_copy;
- BKE_id_copy_ex(bmain, &group->id, (ID **)&group_copy, 0, false);
- return group_copy;
-}
-
-void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local)
-{
- BKE_id_make_local_generic(bmain, &group->id, true, lib_local);
-}
-
-/* external */
-static bool group_object_add_internal(Group *group, Object *ob)
-{
- GroupObject *go;
-
- if (group == NULL || ob == NULL) {
- return false;
- }
-
- /* check if the object has been added already */
- if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) {
- return false;
- }
-
- go = MEM_callocN(sizeof(GroupObject), "groupobject");
- BLI_addtail(&group->gobject, go);
-
- go->ob = ob;
- id_us_ensure_real(&go->ob->id);
-
- return true;
-}
-
-bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base)
-{
- if (group_object_add_internal(group, object)) {
- if ((object->flag & OB_FROMGROUP) == 0) {
-
- if (scene && base == NULL)
- base = BKE_scene_base_find(scene, object);
-
- object->flag |= OB_FROMGROUP;
-
- if (base)
- base->flag |= OB_FROMGROUP;
- }
- return true;
- }
- else {
- return false;
- }
-}
-
-/* also used for (ob == NULL) */
-static int group_object_unlink_internal(Group *group, Object *ob)
-{
- GroupObject *go, *gon;
- int removed = 0;
- if (group == NULL) return 0;
-
- go = group->gobject.first;
- while (go) {
- gon = go->next;
- if (go->ob == ob) {
- BLI_remlink(&group->gobject, go);
- free_group_object(go);
- removed = 1;
- /* should break here since an object being in a group twice cant happen? */
- }
- go = gon;
- }
- return removed;
-}
-
-static bool group_object_cyclic_check_internal(Object *object, Group *group)
-{
- if (object->dup_group) {
- Group *dup_group = object->dup_group;
- if ((dup_group->id.tag & LIB_TAG_DOIT) == 0) {
- /* Cycle already exists in groups, let's prevent further crappyness */
- return true;
- }
- /* flag the object to identify cyclic dependencies in further dupli groups */
- dup_group->id.tag &= ~LIB_TAG_DOIT;
-
- if (dup_group == group)
- return true;
- else {
- GroupObject *gob;
- for (gob = dup_group->gobject.first; gob; gob = gob->next) {
- if (group_object_cyclic_check_internal(gob->ob, group)) {
- return true;
- }
- }
- }
-
- /* un-flag the object, it's allowed to have the same group multiple times in parallel */
- dup_group->id.tag |= LIB_TAG_DOIT;
- }
-
- return false;
-}
-
-bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group)
-{
- /* first flag all groups */
- BKE_main_id_tag_listbase(&bmain->group, LIB_TAG_DOIT, true);
-
- return group_object_cyclic_check_internal(object, group);
-}
-
-bool BKE_group_object_unlink(Main *bmain, Group *group, Object *object, Scene *scene, Base *base)
-{
- if (group_object_unlink_internal(group, object)) {
- /* object can be NULL */
- if (object && BKE_group_object_find(bmain, NULL, object) == NULL) {
- if (scene && base == NULL)
- base = BKE_scene_base_find(scene, object);
-
- object->flag &= ~OB_FROMGROUP;
-
- if (base)
- base->flag &= ~OB_FROMGROUP;
- }
- return true;
- }
- else {
- return false;
- }
-}
-
-bool BKE_group_object_exists(Group *group, Object *ob)
-{
- if (group == NULL || ob == NULL) {
- return false;
- }
- else {
- return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
- }
-}
-
-Group *BKE_group_object_find(Main *bmain, Group *group, Object *ob)
-{
- if (group)
- group = group->id.next;
- else
- group = bmain->group.first;
-
- while (group) {
- if (BKE_group_object_exists(group, ob))
- return group;
- group = group->id.next;
- }
- return NULL;
-}
-
-bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
-{
- GroupObject *go;
-
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
- if (parent->nlastrips.first)
- return 1;
-#endif
-
- for (go = group->gobject.first; go; go = go->next)
- if (go->ob && go->ob->proxy)
- return true;
-
- return false;
-}
-
-#if 0 // add back when timeoffset & animsys work again
-/* only replaces object strips or action when parent nla instructs it */
-/* keep checking nla.c though, in case internal structure of strip changes */
-static void group_replaces_nla(Object *parent, Object *target, char mode)
-{
- static ListBase nlastrips = {NULL, NULL};
- static bAction *action = NULL;
- static bool done = false;
- bActionStrip *strip, *nstrip;
-
- if (mode == 's') {
-
- for (strip = parent->nlastrips.first; strip; strip = strip->next) {
- if (strip->object == target) {
- if (done == 0) {
- /* clear nla & action from object */
- nlastrips = target->nlastrips;
- BLI_listbase_clear(&target->nlastrips);
- action = target->action;
- target->action = NULL;
- target->nlaflag |= OB_NLA_OVERRIDE;
- done = true;
- }
- nstrip = MEM_dupallocN(strip);
- BLI_addtail(&target->nlastrips, nstrip);
- }
- }
- }
- else if (mode == 'e') {
- if (done) {
- BLI_freelistN(&target->nlastrips);
- target->nlastrips = nlastrips;
- target->action = action;
-
- BLI_listbase_clear(&nlastrips); /* not needed, but yah... :) */
- action = NULL;
- done = false;
- }
- }
-}
-#endif
-
-/* puts all group members in local timing system, after this call
- * you can draw everything, leaves tags in objects to signal it needs further updating */
-
-/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
-void BKE_group_handle_recalc_and_update(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group)
-{
- GroupObject *go;
-
-#if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time,
- * not just on frame change.
- * This isn't working because the animation data is only re-evaluated on frame change so commenting for now
- * but when its enabled at some point it will need to be changed so as not to update so much - campbell */
-
- /* if animated group... */
- if (parent->nlastrips.first) {
- int cfrao;
-
- /* switch to local time */
- cfrao = scene->r.cfra;
-
- /* we need a DAG per group... */
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob && go->recalc) {
- go->ob->recalc = go->recalc;
-
- group_replaces_nla(parent, go->ob, 's');
- BKE_object_handle_update(eval_ctx, scene, go->ob);
- group_replaces_nla(parent, go->ob, 'e');
-
- /* leave recalc tags in case group members are in normal scene */
- go->ob->recalc = go->recalc;
- }
- }
-
- /* restore */
- scene->r.cfra = cfrao;
- }
- else
-#endif
- {
- /* only do existing tags, as set by regular depsgraph */
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob) {
- if (go->ob->recalc) {
- BKE_object_handle_update(bmain, eval_ctx, scene, go->ob);
- }
- }
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 071c10acaa5..37f53e81236 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -42,6 +42,7 @@
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "DNA_brush_types.h"
@@ -50,10 +51,12 @@
#include "BLI_ghash.h"
#include "BLI_linklist_lockfree.h"
#include "BLI_string.h"
+#include "BLI_fileops.h"
#include "BLI_threads.h"
#include "BKE_icons.h"
#include "BKE_global.h" /* only for G.background test */
+#include "BKE_studiolight.h"
#include "BLI_sys_types.h" // for intptr_t support
@@ -63,6 +66,14 @@
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
+/**
+ * Only allow non-managed icons to be removed (by Python for eg).
+ * Previews & ID's have their own functions to remove icons.
+ */
+enum {
+ ICON_FLAG_MANAGED = (1 << 0),
+};
+
/* GLOBALS */
static GHash *gIcons = NULL;
@@ -85,6 +96,19 @@ static void icon_free(void *val)
Icon *icon = val;
if (icon) {
+ if (icon->obj_type == ICON_DATA_GEOM) {
+ struct Icon_Geom *obj = icon->obj;
+ if (obj->mem) {
+ /* coords & colors are part of this memory. */
+ MEM_freeN((void *)obj->mem);
+ }
+ else {
+ MEM_freeN((void *)obj->coords);
+ MEM_freeN((void *)obj->colors);
+ }
+ MEM_freeN(icon->obj);
+ }
+
if (icon->drawinfo_free) {
icon->drawinfo_free(icon->drawinfo);
}
@@ -95,6 +119,28 @@ static void icon_free(void *val)
}
}
+static void icon_free_data(int icon_id, Icon *icon)
+{
+ if (icon->obj_type == ICON_DATA_ID) {
+ ((ID *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_PREVIEW) {
+ ((PreviewImage *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_GEOM) {
+ ((struct Icon_Geom *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
+ StudioLight *sl = icon->obj;
+ if (sl != NULL) {
+ BKE_studiolight_unset_icon_id(sl, icon_id);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+}
+
/* create an id for a new icon and make sure that ids from deleted icons get reused
* after the integer number range is used up */
static int get_next_free_id(void)
@@ -282,8 +328,9 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id)
ID_PRV_CASE(ID_IM, Image);
ID_PRV_CASE(ID_BR, Brush);
ID_PRV_CASE(ID_OB, Object);
- ID_PRV_CASE(ID_GR, Group);
+ ID_PRV_CASE(ID_GR, Collection);
ID_PRV_CASE(ID_SCE, Scene);
+ ID_PRV_CASE(ID_SCR, bScreen);
#undef ID_PRV_CASE
default:
break;
@@ -476,6 +523,7 @@ void BKE_icon_changed(const int icon_id)
if (icon) {
/* We *only* expect ID-tied icons here, not non-ID icon/preview! */
BLI_assert(icon->id_type != 0);
+ BLI_assert(icon->obj_type == ICON_DATA_ID);
/* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here ,
* we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */
@@ -492,22 +540,31 @@ void BKE_icon_changed(const int icon_id)
}
}
-static int icon_id_ensure_create_icon(struct ID *id)
+static Icon *icon_create(int icon_id, int obj_type, void *obj)
{
- BLI_assert(BLI_thread_is_main());
+ Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__);
- Icon *new_icon = NULL;
-
- new_icon = MEM_mallocN(sizeof(Icon), __func__);
-
- new_icon->obj = id;
- new_icon->id_type = GS(id->name);
+ new_icon->obj_type = obj_type;
+ new_icon->obj = obj;
+ new_icon->id_type = 0;
+ new_icon->flag = 0;
/* next two lines make sure image gets created */
new_icon->drawinfo = NULL;
new_icon->drawinfo_free = NULL;
- BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon);
+ BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(icon_id), new_icon);
+
+ return new_icon;
+}
+
+static int icon_id_ensure_create_icon(struct ID *id)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ Icon *icon = icon_create(id->icon_id, ICON_DATA_ID, id);
+ icon->id_type = GS(id->name);
+ icon->flag = ICON_FLAG_MANAGED;
return id->icon_id;
}
@@ -546,8 +603,6 @@ int BKE_icon_id_ensure(struct ID *id)
*/
int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
{
- Icon *new_icon = NULL;
-
if (!preview || G.background)
return 0;
@@ -578,16 +633,8 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
return icon_id_ensure_create_icon(id);
}
- new_icon = MEM_mallocN(sizeof(Icon), __func__);
-
- new_icon->obj = preview;
- new_icon->id_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);
+ Icon *icon = icon_create(preview->icon_id, ICON_DATA_PREVIEW, preview);
+ icon->flag = ICON_FLAG_MANAGED;
return preview->icon_id;
}
@@ -649,21 +696,128 @@ void BKE_icon_id_delete(struct ID *id)
/**
* Remove icon and free data.
*/
-void BKE_icon_delete(const int icon_id)
+bool BKE_icon_delete(const int icon_id)
{
- Icon *icon;
+ if (icon_id == 0) {
+ /* no icon defined for library object */
+ return false;
+ }
- if (!icon_id) return; /* no icon defined for library object */
+ Icon *icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL);
+ if (icon) {
+ icon_free_data(icon_id, icon);
+ icon_free(icon);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
- icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL);
+bool BKE_icon_delete_unmanaged(const int icon_id)
+{
+ if (icon_id == 0) {
+ /* no icon defined for library object */
+ return false;
+ }
+ Icon *icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL);
if (icon) {
- if (icon->id_type != 0) {
- ((ID *)(icon->obj))->icon_id = 0;
+ if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) {
+ BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(icon_id), icon);
+ return false;
}
else {
- ((PreviewImage *)(icon->obj))->icon_id = 0;
+ icon_free_data(icon_id, icon);
+ icon_free(icon);
+ return true;
}
- icon_free(icon);
+ }
+ else {
+ return false;
}
}
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Icon
+ * \{ */
+
+int BKE_icon_geom_ensure(struct Icon_Geom *geom)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ if (geom->icon_id) {
+ return geom->icon_id;
+ }
+
+ geom->icon_id = get_next_free_id();
+
+ icon_create(geom->icon_id, ICON_DATA_GEOM, geom);
+ /* Not managed for now, we may want this to be configurable per icon). */
+
+ return geom->icon_id;
+}
+
+struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len)
+{
+ BLI_assert(BLI_thread_is_main());
+ if (data_len <= 8) {
+ goto fail;
+ }
+ /* Skip the header. */
+ data_len -= 8;
+ const int div = 3 * 2 * 3;
+ const int coords_len = data_len / div;
+ if (coords_len * div != data_len) {
+ goto fail;
+ }
+
+ const uchar header[4] = {'V', 'C', 'O', 0};
+ const uchar *p = data;
+ if (memcmp(p, header, ARRAY_SIZE(header)) != 0) {
+ goto fail;
+ }
+ p += 4;
+
+ struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__);
+ geom->coords_range[0] = (int)*p++;
+ geom->coords_range[1] = (int)*p++;
+ /* x, y ignored for now */
+ p += 2;
+
+ geom->coords_len = coords_len;
+ geom->coords = (const void *)p;
+ geom->colors = (const void *)(p + (data_len / 3));
+ geom->icon_id = 0;
+ geom->mem = data;
+ return geom;
+
+fail:
+ MEM_freeN((void *)data);
+ return NULL;
+}
+
+struct Icon_Geom *BKE_icon_geom_from_file(const char *filename)
+{
+ BLI_assert(BLI_thread_is_main());
+ size_t data_len;
+ uchar *data = BLI_file_read_binary_as_mem(filename, 0, &data_len);
+ if (data == NULL) {
+ return NULL;
+ }
+ return BKE_icon_geom_from_memory(data, data_len);
+}
+
+/** \} */
+
+/** \name Studio Light Icon
+ * \{ */
+int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
+{
+ int icon_id = get_next_free_id();
+ Icon *icon = icon_create(icon_id, ICON_DATA_STUDIOLIGHT, sl);
+ icon->id_type = id_type;
+ return icon_id;
+}
+/** \} */
+
diff --git a/source/blender/blenkernel/intern/icons_rasterize.c b/source/blender/blenkernel/intern/icons_rasterize.c
new file mode 100644
index 00000000000..24576c24953
--- /dev/null
+++ b/source/blender/blenkernel/intern/icons_rasterize.c
@@ -0,0 +1,146 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenkernel/intern/icons_rasterize.c
+ * \ingroup bke
+ */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_bitmap_draw_2d.h"
+#include "BLI_math_geom.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_icons.h"
+
+#include "BLI_strict_flags.h"
+
+struct UserRasterInfo {
+ int pt[3][2];
+ const uint *color;
+ /* only for smooth shading */
+ struct {
+ float pt_fl[3][2];
+ uint color_u[3][4];
+ } smooth;
+ int rect_size[2];
+ uint *rect;
+};
+
+static void tri_fill_flat(int x, int x_end, int y, void *user_data)
+{
+ struct UserRasterInfo *data = user_data;
+ uint *p = &data->rect[(y * data->rect_size[1]) + x];
+ uint col = data->color[0];
+ while (x++ != x_end) {
+ *p++ = col;
+ }
+}
+
+static void tri_fill_smooth(int x, int x_end, int y, void *user_data)
+{
+ struct UserRasterInfo *data = user_data;
+ uint *p = &data->rect[(y * data->rect_size[1]) + x];
+ float pt_step_fl[2] = {(float)x, (float)y};
+ while (x++ != x_end) {
+ float w[3];
+ barycentric_weights_v2_clamped(UNPACK3(data->smooth.pt_fl), pt_step_fl, w);
+
+ uint col_u[4] = {0, 0, 0, 0};
+ for (uint corner = 0; corner < 3; corner++) {
+ for (uint chan = 0; chan < 4; chan++) {
+ col_u[chan] += data->smooth.color_u[corner][chan] * (uint)(w[corner] * 255.0f);
+ }
+ }
+ union {
+ uint as_u32;
+ uchar as_bytes[4];
+ } col;
+ col.as_bytes[0] = (uchar)(col_u[0] / 255);
+ col.as_bytes[1] = (uchar)(col_u[1] / 255);
+ col.as_bytes[2] = (uchar)(col_u[2] / 255);
+ col.as_bytes[3] = (uchar)(col_u[3] / 255);
+ *p++ = col.as_u32;
+
+ pt_step_fl[0] += 1.0f;
+ }
+}
+
+ImBuf *BKE_icon_geom_rasterize(
+ const struct Icon_Geom *geom,
+ const unsigned int size_x, const unsigned int size_y)
+{
+ const int coords_len = geom->coords_len;
+
+ const uchar (*pos)[2] = geom->coords;
+ const uint *col = (void *)geom->colors;
+
+ /* TODO(campbell): Currently rasterizes to fixed size, then scales.
+ * Should rasterize to double size for eg instead. */
+ const int rect_size[2] = {max_ii(256, (int)size_x * 2), max_ii(256, (int)size_y * 2)};
+
+ ImBuf *ibuf = IMB_allocImBuf((uint)rect_size[0], (uint)rect_size[1], 32, IB_rect);
+
+ struct UserRasterInfo data;
+
+ data.rect_size[0] = rect_size[0];
+ data.rect_size[1] = rect_size[1];
+
+ data.rect = ibuf->rect;
+
+ float scale[2];
+ const bool use_scale = (rect_size[0] != 256) || (rect_size[1] != 256);
+
+ if (use_scale) {
+ scale[0] = ((float)rect_size[0] / 256.0f);
+ scale[1] = ((float)rect_size[1] / 256.0f);
+ }
+
+ for (int t = 0; t < coords_len; t += 1, pos += 3, col += 3) {
+ if (use_scale) {
+ ARRAY_SET_ITEMS(data.pt[0], (int)(pos[0][0] * scale[0]), (int)(pos[0][1] * scale[1]));
+ ARRAY_SET_ITEMS(data.pt[1], (int)(pos[1][0] * scale[0]), (int)(pos[1][1] * scale[1]));
+ ARRAY_SET_ITEMS(data.pt[2], (int)(pos[2][0] * scale[0]), (int)(pos[2][1] * scale[1]));
+ }
+ else {
+ ARRAY_SET_ITEMS(data.pt[0], UNPACK2(pos[0]));
+ ARRAY_SET_ITEMS(data.pt[1], UNPACK2(pos[1]));
+ ARRAY_SET_ITEMS(data.pt[2], UNPACK2(pos[2]));
+ }
+ data.color = col;
+ if ((col[0] == col[1]) && (col[0] == col[2])) {
+ BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_flat, &data);
+ }
+ else {
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[0], UNPACK2_EX((float), data.pt[0], ));
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[1], UNPACK2_EX((float), data.pt[1], ));
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[2], UNPACK2_EX((float), data.pt[2], ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[0], UNPACK4_EX((uint), ((uchar *)(col + 0)), ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[1], UNPACK4_EX((uint), ((uchar *)(col + 1)), ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[2], UNPACK4_EX((uint), ((uchar *)(col + 2)), ));
+ BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_smooth, &data);
+ }
+ }
+ IMB_scaleImBuf(ibuf, size_x, size_y);
+ return ibuf;
+}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index d995dce1259..0edeaab8900 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -61,9 +61,9 @@ static IDType idtypes[] = {
{ ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE },
{ ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE },
{ ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_GR, "Collection", "collections", BLT_I18NCONTEXT_ID_COLLECTION, IDTYPE_FLAGS_ISLINKABLE },
{ ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
- { ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE },
{ ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */
{ ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 },
@@ -81,8 +81,9 @@ static IDType idtypes[] = {
{ ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE },
{ ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_LP, "LightProbe", "light_probes", BLT_I18NCONTEXT_ID_LIGHTPROBE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, 0 },
+ { ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, IDTYPE_FLAGS_ISLINKABLE },
{ ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */
{ ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE },
{ ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE },
@@ -91,6 +92,7 @@ static IDType idtypes[] = {
{ ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+ { ID_WS, "WorkSpace", "workspaces", BLT_I18NCONTEXT_ID_WORKSPACE, IDTYPE_FLAGS_ISLINKABLE },
/** Keep last, not an ID exactly, only include for completeness */
{ ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
@@ -203,6 +205,7 @@ int BKE_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(PA);
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
+ CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
@@ -210,6 +213,7 @@ int BKE_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(TXT);
CASE_IDFILTER(VF);
CASE_IDFILTER(WO);
+ CASE_IDFILTER(WS);
default:
return 0;
}
@@ -247,6 +251,7 @@ short BKE_idcode_from_idfilter(const int idfilter)
CASE_IDFILTER(PA);
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
+ CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
@@ -294,6 +299,7 @@ int BKE_idcode_to_index(const short idcode)
CASE_IDINDEX(PA);
CASE_IDINDEX(PAL);
CASE_IDINDEX(PC);
+ CASE_IDINDEX(LP);
CASE_IDINDEX(SCE);
CASE_IDINDEX(SCR);
CASE_IDINDEX(SPK);
@@ -303,6 +309,7 @@ int BKE_idcode_to_index(const short idcode)
CASE_IDINDEX(VF);
CASE_IDINDEX(WM);
CASE_IDINDEX(WO);
+ CASE_IDINDEX(WS);
}
BLI_assert(0);
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 1ce4044464e..ae9236e35fe 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -476,6 +476,7 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
BLI_assert(prop->type == IDP_GROUP);
newp = idp_generic_copy(prop, flag);
newp->len = prop->len;
+ newp->subtype = prop->subtype;
for (link = prop->data.group.first; link; link = link->next) {
BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
@@ -601,8 +602,9 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
/**
* If a property is missing in \a dest, add it.
+ * Do it recursively.
*/
-void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
+void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag)
{
IDProperty *prop;
@@ -611,14 +613,30 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw
if (do_overwrite) {
for (prop = src->data.group.first; prop; prop = prop->next) {
- IDProperty *copy = IDP_CopyProperty(prop);
+ if (prop->type == IDP_GROUP) {
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+
+ if (prop_exist != NULL) {
+ IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
+ continue;
+ }
+ }
+
+ IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
IDP_ReplaceInGroup(dest, copy);
}
}
else {
for (prop = src->data.group.first; prop; prop = prop->next) {
- if (IDP_GetPropertyFromGroup(dest, prop->name) == NULL) {
- IDProperty *copy = IDP_CopyProperty(prop);
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+ if (prop_exist != NULL) {
+ if (prop->type == IDP_GROUP) {
+ IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
+ continue;
+ }
+ }
+ else {
+ IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
dest->len++;
BLI_addtail(&dest->data.group, copy);
}
@@ -627,6 +645,15 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw
}
/**
+ * If a property is missing in \a dest, add it.
+ * Do it recursively.
+ */
+void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
+{
+ IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
+}
+
+/**
* This function has a sanity check to make sure ID properties with the same name don't
* get added to the group.
*
@@ -1067,5 +1094,16 @@ void IDP_ClearProperty(IDProperty *prop)
prop->len = prop->totallen = 0;
}
+void IDP_Reset(IDProperty *prop, const IDProperty *reference)
+{
+ if (prop == NULL) {
+ return;
+ }
+ IDP_ClearProperty(prop);
+ if (reference != NULL) {
+ IDP_MergeGroup(prop, reference, true);
+ }
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 76cf7317b19..b5abdcae2d4 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -82,6 +82,7 @@
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_sequencer.h" /* seq_foreground_frame_get() */
+#include "BKE_workspace.h"
#include "BLF_api.h"
@@ -341,19 +342,18 @@ void BKE_image_free_buffers(Image *ima)
/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free(Image *ima)
{
- int a;
-
/* Also frees animdata. */
BKE_image_free_buffers(ima);
image_free_packedfiles(ima);
- for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) {
- if (ima->renders[a]) {
- RE_FreeRenderResult(ima->renders[a]);
- ima->renders[a] = NULL;
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots) {
+ if (slot->render) {
+ RE_FreeRenderResult(slot->render);
+ slot->render = NULL;
}
}
+ BLI_freelistN(&ima->renderslots);
BKE_image_free_views(ima);
MEM_SAFE_FREE(ima->stereo3d_format);
@@ -369,7 +369,6 @@ static void image_init(Image *ima, short source, short type)
ima->ok = IMA_OK;
- ima->xrep = ima->yrep = 1;
ima->aspx = ima->aspy = 1.0;
ima->gen_x = 1024; ima->gen_y = 1024;
ima->gen_type = IMA_GENTYPE_GRID;
@@ -380,6 +379,12 @@ static void image_init(Image *ima, short source, short type)
if (source == IMA_SRC_VIEWER)
ima->flag |= IMA_VIEW_AS_RENDER;
+ if (type == IMA_TYPE_R_RESULT) {
+ for (int i = 0; i < 8; i++) {
+ BKE_image_add_renderslot(ima, NULL);
+ }
+ }
+
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
}
@@ -466,18 +471,17 @@ void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_s
/* Cleanup stuff that cannot be copied. */
ima_dst->cache = NULL;
ima_dst->rr = NULL;
- for (int i = 0; i < IMA_MAX_RENDER_SLOT; i++) {
- ima_dst->renders[i] = NULL;
+
+ BLI_duplicatelist(&ima_dst->renderslots, &ima_src->renderslots);
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima_dst->renderslots) {
+ slot->render = NULL;
}
BLI_listbase_clear(&ima_dst->anims);
- ima_dst->totbind = 0;
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- ima_dst->bindcode[i] = 0;
ima_dst->gputexture[i] = NULL;
}
- ima_dst->repbind = NULL;
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
BKE_previewimg_id_copy(&ima_dst->id, &ima_src->id);
@@ -540,16 +544,14 @@ bool BKE_image_scale(Image *image, int width, int height)
return (ibuf != NULL);
}
-bool BKE_image_has_bindcode(Image *ima)
+bool BKE_image_has_opengl_texture(Image *ima)
{
- bool has_bindcode = false;
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->bindcode[i]) {
- has_bindcode = true;
- break;
+ if (ima->gputexture[i]) {
+ return true;
}
}
- return has_bindcode;
+ return false;
}
static void image_init_color_management(Image *ima)
@@ -932,21 +934,6 @@ void BKE_image_tag_time(Image *ima)
ima->lastused = PIL_check_seconds_timer_i();
}
-#if 0
-static void tag_all_images_time(Main *bmain)
-{
- Image *ima;
- int ctime = PIL_check_seconds_timer_i();
-
- ima = bmain->image.first;
- while (ima) {
- if (ima->bindcode || ima->repbind || ima->ibufs.first) {
- ima->lastused = ctime;
- }
- }
-}
-#endif
-
static uintptr_t image_mem_size(Image *image)
{
uintptr_t size = 0;
@@ -1208,7 +1195,6 @@ bool BKE_imtype_is_movie(const char imtype)
case R_IMF_IMTYPE_H264:
case R_IMF_IMTYPE_THEORA:
case R_IMF_IMTYPE_XVID:
- case R_IMF_IMTYPE_FRAMESERVER:
return true;
}
return false;
@@ -1349,7 +1335,6 @@ char BKE_imtype_from_arg(const char *imtype_arg)
else if (STREQ(imtype_arg, "MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER;
#endif
else if (STREQ(imtype_arg, "FFMPEG")) return R_IMF_IMTYPE_FFMPEG;
- else if (STREQ(imtype_arg, "FRAMESERVER")) return R_IMF_IMTYPE_FRAMESERVER;
#ifdef WITH_CINEON
else if (STREQ(imtype_arg, "CINEON")) return R_IMF_IMTYPE_CINEON;
else if (STREQ(imtype_arg, "DPX")) return R_IMF_IMTYPE_DPX;
@@ -2654,19 +2639,19 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata,
}
}
+ for (Camera *cam = mainp->camera.first; cam; cam = cam->id.next) {
+ for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ callback(bgpic->ima, &bgpic->iuser, customdata);
+ }
+ }
+
/* image window, compo node users */
for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
- BGpic *bgpic;
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- callback(bgpic->ima, &bgpic->iuser, customdata);
- }
- }
- else if (sa->spacetype == SPACE_IMAGE) {
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_IMAGE) {
SpaceImage *sima = sa->spacedata.first;
callback(sima->image, &sima->iuser, customdata);
}
@@ -3019,7 +3004,7 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
if (ima->render_slot == ima->last_render_slot)
rr = RE_AcquireResultRead(RE_GetSceneRender(scene));
else
- rr = ima->renders[ima->render_slot];
+ rr = BKE_image_get_renderslot(ima, ima->render_slot)->render;
/* set proper views */
image_init_multilayer_multiview(ima, rr);
@@ -3053,27 +3038,39 @@ bool BKE_image_is_openexr(struct Image *ima)
void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
{
- /* called right before rendering, ima->renders contains render
+ /* called right before rendering, ima->renderslots contains render
* result pointers for everything but the current render */
Render *re = RE_GetSceneRender(scene);
- int slot = ima->render_slot, last = ima->last_render_slot;
- if (slot != last) {
- ima->renders[last] = NULL;
- RE_SwapResult(re, &ima->renders[last]);
+ /* Ensure we always have a valid render slot. */
+ if (!ima->renderslots.first) {
+ BKE_image_add_renderslot(ima, NULL);
+ ima->render_slot = 0;
+ ima->last_render_slot = 0;
+ }
+ else if (ima->render_slot >= BLI_listbase_count(&ima->renderslots)) {
+ ima->render_slot = 0;
+ ima->last_render_slot = 0;
+ }
+
+ RenderSlot *last_slot = BKE_image_get_renderslot(ima, ima->last_render_slot);
+ RenderSlot *cur_slot = BKE_image_get_renderslot(ima, ima->render_slot);
- if (ima->renders[slot]) {
+ if (last_slot && ima->render_slot != ima->last_render_slot) {
+ last_slot->render = NULL;
+ RE_SwapResult(re, &last_slot->render);
+
+ if (cur_slot->render) {
if (free_current_slot) {
- RE_FreeRenderResult(ima->renders[slot]);
- ima->renders[slot] = NULL;
+ BKE_image_clear_renderslot(ima, NULL, ima->render_slot);
}
else {
- RE_SwapResult(re, &ima->renders[slot]);
+ RE_SwapResult(re, &cur_slot->render);
}
}
}
- ima->last_render_slot = slot;
+ ima->last_render_slot = ima->render_slot;
}
/**************************** multiview load openexr *********************************/
@@ -3691,11 +3688,12 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO))
actview = iuser->multiview_eye;
+ RenderSlot *slot;
if (from_render) {
RE_AcquireResultImage(re, &rres, actview);
}
- else if (ima->renders[ima->render_slot]) {
- rres = *(ima->renders[ima->render_slot]);
+ else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) {
+ rres = *(slot->render);
rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL;
}
else
@@ -4725,3 +4723,97 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
}
}
}
+
+/**************************** Render Slots ***************************/
+
+RenderSlot *BKE_image_add_renderslot(Image *ima, const char *name)
+{
+ RenderSlot *slot = MEM_callocN(sizeof(RenderSlot), "Image new Render Slot");
+ if (name && name[0]) {
+ BLI_strncpy(slot->name, name, sizeof(slot->name));
+ }
+ else {
+ int n = BLI_listbase_count(&ima->renderslots) + 1;
+ BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", n);
+ }
+ BLI_addtail(&ima->renderslots, slot);
+ return slot;
+}
+
+bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int index)
+{
+ int num_slots = BLI_listbase_count(&ima->renderslots);
+ if (index >= num_slots || num_slots == 1) {
+ return false;
+ }
+
+ RenderSlot *remove_slot = BLI_findlink(&ima->renderslots, index);
+ RenderSlot *current_slot = BLI_findlink(&ima->renderslots, ima->render_slot);
+ RenderSlot *current_last_slot = BLI_findlink(&ima->renderslots, ima->last_render_slot);
+
+ RenderSlot *next_slot;
+ if (current_slot == remove_slot) {
+ next_slot = BLI_findlink(&ima->renderslots, (index == num_slots - 1) ? index - 1 : index + 1);
+ }
+ else {
+ next_slot = current_slot;
+ }
+
+ /* If the slot to be removed is the slot with the last render, make another slot the last render slot. */
+ if (remove_slot == current_last_slot) {
+ /* Choose the currently selected slot unless that one is being removed, in that case take the next one. */
+ RenderSlot *next_last_slot;
+ if (current_slot == remove_slot)
+ next_last_slot = next_slot;
+ else
+ next_last_slot = current_slot;
+
+ if (!iuser) return false;
+ Render *re = RE_GetSceneRender(iuser->scene);
+ if (!re) return false;
+ RE_SwapResult(re, &current_last_slot->render);
+ RE_SwapResult(re, &next_last_slot->render);
+ current_last_slot = next_last_slot;
+ }
+
+ current_slot = next_slot;
+
+ BLI_remlink(&ima->renderslots, remove_slot);
+
+ ima->render_slot = BLI_findindex(&ima->renderslots, current_slot);
+ ima->last_render_slot = BLI_findindex(&ima->renderslots, current_last_slot);
+
+ if (remove_slot->render) {
+ RE_FreeRenderResult(remove_slot->render);
+ }
+ MEM_freeN(remove_slot);
+
+ return true;
+}
+
+bool BKE_image_clear_renderslot(Image *ima, ImageUser *iuser, int index)
+{
+ if (index == ima->last_render_slot) {
+ if (!iuser) return false;
+ if (G.is_rendering) return false;
+ Render *re = RE_GetSceneRender(iuser->scene);
+ if (!re) return false;
+ RE_ClearResult(re);
+ return true;
+ }
+ else {
+ RenderSlot *slot = BLI_findlink(&ima->renderslots, index);
+ if (!slot) return false;
+ if (slot->render) {
+ RE_FreeRenderResult(slot->render);
+ slot->render = NULL;
+ }
+ return true;
+ }
+}
+
+RenderSlot *BKE_image_get_renderslot(Image *ima, int index)
+{
+ /* Can be NULL for images without render slots. */
+ return BLI_findlink(&ima->renderslots, index);
+}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 52a7ed5cd7e..eeb09931211 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -46,7 +46,6 @@
/* since we have versioning code here */
#define DNA_DEPRECATED_ALLOW
-#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
#include "DNA_constraint_types.h"
#include "DNA_camera_types.h"
@@ -146,17 +145,6 @@ static AdrBit2Path ob_layer_bits[] = {
{(1 << 19), "layers", 19}
};
-/* Material mode */
-static AdrBit2Path ma_mode_bits[] = {
-// {MA_TRACEBLE, "traceable", 0},
-// {MA_SHADOW, "shadow", 0},
-// {MA_SHLESS, "shadeless", 0},
-// ...
- {MA_RAYTRANSP, "transparency", 0},
- {MA_RAYMIRROR, "raytrace_mirror.enabled", 0},
-// {MA_HALO, "type", MA_TYPE_HALO}
-};
-
/* ----------------- */
/* quick macro for returning the appropriate array for adrcode_bitmaps_to_paths() */
@@ -173,9 +161,6 @@ static AdrBit2Path *adrcode_bitmaps_to_paths(int blocktype, int adrcode, int *to
if ((blocktype == ID_OB) && (adrcode == OB_LAY)) {
RET_ABP(ob_layer_bits);
}
- else if ((blocktype == ID_MA) && (adrcode == MA_MODE)) {
- RET_ABP(ma_mode_bits);
- }
// XXX TODO: add other types...
/* Normal curve */
@@ -1768,23 +1753,6 @@ void do_versions_ipos_to_animato(Main *bmain)
ipo_to_animdata(bmain, id, ob->ipo, NULL, NULL, NULL);
id_us_min(&ob->ipo->id);
ob->ipo = NULL;
-
- {
- /* If we have any empty action actuators, assume they were
- * converted IPO Actuators using the object IPO */
- bActuator *act;
- bActionActuator *aa;
-
- for (act = ob->actuators.first; act; act = act->next) {
- /* Any actuators set to ACT_IPO at this point are actually Action Actuators that
- * need this converted IPO to finish converting the actuator. */
- if (act->type == ACT_IPO) {
- aa = (bActionActuator *)act->data;
- aa->act = ob->adt->action;
- act->type = ACT_ACTION;
- }
- }
- }
}
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 4689575655e..13f7716cd80 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -1767,16 +1767,16 @@ void BKE_keyblock_update_from_mesh(Mesh *me, KeyBlock *kb)
}
}
-void BKE_keyblock_convert_from_mesh(Mesh *me, KeyBlock *kb)
+void BKE_keyblock_convert_from_mesh(Mesh *me, Key *key, KeyBlock *kb)
{
- int tot = me->totvert;
+ const int len = me->totvert;
if (me->totvert == 0) return;
MEM_SAFE_FREE(kb->data);
- kb->data = MEM_mallocN(me->key->elemsize * tot, __func__);
- kb->totelem = tot;
+ kb->data = MEM_malloc_arrayN((size_t)len, (size_t)key->elemsize, __func__);
+ kb->totelem = len;
BKE_keyblock_update_from_mesh(me, kb);
}
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 3051bbdd7ed..1d5b6de22f4 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -59,47 +59,36 @@ void BKE_lamp_init(Lamp *la)
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(la, id));
la->r = la->g = la->b = la->k = 1.0f;
- la->haint = la->energy = 1.0f;
+ la->energy = 10.0f;
la->dist = 25.0f;
la->spotsize = DEG2RADF(45.0f);
la->spotblend = 0.15f;
la->att2 = 1.0f;
- la->mode = LA_SHAD_BUF;
+ la->mode = LA_SHADOW;
la->bufsize = 512;
la->clipsta = 0.5f;
la->clipend = 40.0f;
+ la->bleedexp = 2.5f;
la->samp = 3;
la->bias = 1.0f;
la->soft = 3.0f;
- la->compressthresh = 0.05f;
- la->ray_samp = la->ray_sampy = la->ray_sampz = 1;
- la->area_size = la->area_sizey = la->area_sizez = 0.1f;
+ la->area_size = la->area_sizey = la->area_sizez = 0.25f;
la->buffers = 1;
- la->buftype = LA_SHADBUF_HALFWAY;
- la->ray_samp_method = LA_SAMP_HALTON;
- la->adapt_thresh = 0.001f;
la->preview = NULL;
la->falloff_type = LA_FALLOFF_INVSQUARE;
la->coeff_const = 1.0f;
la->coeff_lin = 0.0f;
la->coeff_quad = 0.0f;
la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
- la->sun_effect_type = 0;
- la->horizon_brightness = 1.0;
- la->spread = 1.0;
- la->sun_brightness = 1.0;
- la->sun_size = 1.0;
- la->backscattered_light = 1.0f;
- la->atm_turbidity = 2.0f;
- la->atm_inscattering_factor = 1.0f;
- la->atm_extinction_factor = 1.0f;
- la->atm_distance_factor = 1.0f;
- la->sun_intensity = 1.0f;
- la->skyblendtype = MA_RAMP_ADD;
- la->skyblendfac = 1.0f;
- la->sky_colorspace = BLI_XYZ_CIE;
- la->sky_exposure = 1.0f;
- la->shadow_frustum_size = 10.0f;
+ la->cascade_max_dist = 1000.0f;
+ la->cascade_count = 4;
+ la->cascade_exponent = 0.8f;
+ la->cascade_fade = 0.1f;
+ la->contact_dist = 1.0f;
+ la->contact_bias = 0.03f;
+ la->contact_spread = 0.2f;
+ la->contact_thickness = 0.5f;
+ la->spec_fac = 1.0f;
curvemapping_initialize(la->curfalloff);
}
@@ -125,13 +114,6 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
*/
void BKE_lamp_copy_data(Main *bmain, Lamp *la_dst, const Lamp *la_src, const int flag)
{
- for (int a = 0; a < MAX_MTEX; a++) {
- if (la_dst->mtex[a]) {
- la_dst->mtex[a] = MEM_mallocN(sizeof(*la_dst->mtex[a]), __func__);
- *la_dst->mtex[a] = *la_src->mtex[a];
- }
- }
-
la_dst->curfalloff = curvemapping_copy(la_src->curfalloff);
if (la_src->nodetree) {
@@ -164,17 +146,7 @@ Lamp *BKE_lamp_localize(Lamp *la)
*
* ... Once f*** nodes are fully converted to that too :( */
- Lamp *lan;
- int a;
-
- lan = BKE_libblock_copy_nolib(&la->id, false);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (lan->mtex[a]) {
- lan->mtex[a] = MEM_mallocN(sizeof(MTex), __func__);
- memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex));
- }
- }
+ Lamp *lan = BKE_libblock_copy_nolib(&la->id, false);
lan->curfalloff = curvemapping_copy(la->curfalloff);
@@ -193,12 +165,6 @@ void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local)
void BKE_lamp_free(Lamp *la)
{
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(la->mtex[a]);
- }
-
BKE_animdata_free((ID *)la, false);
curvemapping_free(la->curfalloff);
@@ -214,41 +180,3 @@ void BKE_lamp_free(Lamp *la)
BKE_icon_id_delete(&la->id);
la->id.icon_id = 0;
}
-
-/* Calculate all drivers for lamps, see material_drivers_update for why this is a bad hack */
-
-static void lamp_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime)
-{
- bNode *node;
-
- /* nodetree itself */
- if (ntree->adt && ntree->adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS);
-
- /* nodes */
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->id && node->type == NODE_GROUP)
- lamp_node_drivers_update(scene, (bNodeTree *)node->id, ctime);
-}
-
-void lamp_drivers_update(Scene *scene, Lamp *la, float ctime)
-{
- /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited already
- * (see BKE_scene_update_tagged()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else
- * in the meantime... [#32017] */
- if (la->id.tag & LIB_TAG_DOIT)
- return;
-
- la->id.tag |= LIB_TAG_DOIT;
-
- /* lamp itself */
- if (la->adt && la->adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, &la->id, la->adt, ctime, ADT_RECALC_DRIVERS);
-
- /* nodes */
- if (la->nodetree)
- lamp_node_drivers_update(scene, la->nodetree, ctime);
-
- la->id.tag &= ~LIB_TAG_DOIT;
-}
-
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index c344cfa157c..0af329449ca 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -53,7 +53,6 @@
#include "BKE_anim.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
@@ -66,10 +65,7 @@
#include "BKE_deform.h"
-/* Workaround for cyclic dependency with curves.
- * In such case curve_cache might not be ready yet,
- */
-#define CYCLIC_DEPENDENCY_WORKAROUND
+#include "DEG_depsgraph_query.h"
int BKE_lattice_index_from_uvw(Lattice *lt,
const int u, const int v, const int w)
@@ -215,8 +211,10 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
/* works best if we force to linear type (endpoints match) */
lt->typeu = lt->typev = lt->typew = KEY_LINEAR;
- /* prevent using deformed locations */
- BKE_displist_free(&ltOb->curve_cache->disp);
+ if (ltOb->curve_cache) {
+ /* prevent using deformed locations */
+ BKE_displist_free(&ltOb->curve_cache->disp);
+ }
copy_m4_m4(mat, ltOb->obmat);
unit_m4(ltOb->obmat);
@@ -288,7 +286,7 @@ void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src,
{
lt_dst->def = MEM_dupallocN(lt_src->def);
- if (lt_src->key) {
+ if (lt_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &lt_src->key->id, (ID **)&lt_dst->key, flag, false);
}
@@ -304,7 +302,7 @@ void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src,
Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt)
{
Lattice *lt_copy;
- BKE_id_copy_ex(bmain, &lt->id, (ID **)&lt_copy, 0, false);
+ BKE_id_copy_ex(bmain, &lt->id, (ID **)&lt_copy, LIB_ID_COPY_SHAPEKEY, false);
return lt_copy;
}
@@ -313,6 +311,8 @@ void BKE_lattice_free(Lattice *lt)
{
BKE_animdata_free(&lt->id, false);
+ BKE_lattice_batch_cache_free(lt);
+
MEM_SAFE_FREE(lt->def);
if (lt->dvert) {
BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
@@ -420,10 +420,11 @@ void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float
int defgrp_index = -1;
float co_prev[3], weight_blend = 0.0f;
MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);
+ float *__restrict latticedata = lattice_deform_data->latticedata;
if (lt->editlatt) lt = lt->editlatt->latt;
- if (lattice_deform_data->latticedata == NULL) return;
+ if (latticedata == NULL) return;
if (lt->vgroup[0] && dvert) {
defgrp_index = defgroup_name_index(ob, lt->vgroup);
@@ -504,7 +505,7 @@ void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float
idx_u = idx_v;
}
- madd_v3_v3fl(co, &lattice_deform_data->latticedata[idx_u * 3], u);
+ madd_v3_v3fl(co, &latticedata[idx_u * 3], u);
if (defgrp_index != -1)
weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index));
@@ -601,7 +602,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
/* co: local coord, result local too */
/* returns quaternion for rotation, using cd->no_rot_axis */
/* axis is using another define!!! */
-static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
+static bool calc_curve_deform(Object *par, float co[3],
const short axis, CurveDeform *cd, float r_quat[4])
{
Curve *cu = par->data;
@@ -609,12 +610,10 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
short index;
const bool is_neg_axis = (axis > 2);
- /* to be sure, mostly after file load, also cyclic dependencies */
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
if (par->curve_cache == NULL) {
- BKE_displist_make_curveTypes(scene, par, false);
+ /* Happens with a cyclic dependencies. */
+ return false;
}
-#endif
if (par->curve_cache->path == NULL) {
return false; /* happens on append, cyclic dependencies and empty curves */
@@ -705,7 +704,7 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
}
void curve_deform_verts(
- Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
+ Object *cuOb, Object *target, Mesh *mesh, float (*vertexCos)[3],
int numVerts, const char *vgroup, short defaxis)
{
Curve *cu;
@@ -741,8 +740,8 @@ void curve_deform_verts(
if (defgrp_index != -1) {
/* if there's derived data without deformverts, don't use vgroups */
- if (dm) {
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ if (mesh) {
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
}
else if (target->type == OB_LATTICE) {
dvert = ((Lattice *)target->data)->dvert;
@@ -764,7 +763,7 @@ void curve_deform_verts(
if (weight > 0.0f) {
mul_m4_v3(cd.curvespace, vertexCos[a]);
copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
@@ -787,7 +786,7 @@ void curve_deform_verts(
if (weight > 0.0f) {
/* already in 'cd.curvespace', prev for loop */
copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
@@ -798,7 +797,7 @@ void curve_deform_verts(
if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
for (a = 0; a < numVerts; a++) {
mul_m4_v3(cd.curvespace, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
}
@@ -813,7 +812,7 @@ void curve_deform_verts(
for (a = 0; a < numVerts; a++) {
/* already in 'cd.curvespace', prev for loop */
- calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
}
@@ -823,7 +822,7 @@ void curve_deform_verts(
/* input vec and orco = local coord in armature space */
/* orco is original not-animated or deformed reference point */
/* result written in vec and mat */
-void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
+void curve_deform_vector(Object *cuOb, Object *target,
float orco[3], float vec[3], float mat[3][3], int no_rot_axis)
{
CurveDeform cd;
@@ -842,7 +841,7 @@ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
mul_m4_v3(cd.curvespace, vec);
- if (calc_curve_deform(scene, cuOb, vec, target->trackflag, &cd, quat)) {
+ if (calc_curve_deform(cuOb, vec, target->trackflag, &cd, quat)) {
float qmat[3][3];
quat_to_mat3(qmat, quat);
@@ -855,7 +854,7 @@ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
}
-void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
+void lattice_deform_verts(Object *laOb, Object *target, Mesh *mesh,
float (*vertexCos)[3], int numVerts, const char *vgroup, float fac)
{
LatticeDeformData *lattice_deform_data;
@@ -876,8 +875,8 @@ void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
if (defgrp_index != -1) {
/* if there's derived data without deformverts, don't use vgroups */
- if (dm) {
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ if (mesh) {
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
}
else if (target->type == OB_LATTICE) {
dvert = ((Lattice *)target->data)->dvert;
@@ -1025,13 +1024,16 @@ void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3])
}
}
-void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
+void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
Lattice *lt = ob->data;
+ /* Get vertex coordinates from the original copy; otherwise we get already-modified coordinates. */
+ Object *ob_orig = DEG_get_original_object(ob);
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
float (*vertexCos)[3] = NULL;
int numVerts, editmode = (lt->editlatt != NULL);
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
if (ob->curve_cache) {
BKE_displist_free(&ob->curve_cache->disp);
@@ -1043,22 +1045,26 @@ void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) continue;
if (!(md->mode & eModifierMode_Realtime)) continue;
if (editmode && !(md->mode & eModifierMode_Editmode)) continue;
- if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue;
if (mti->type != eModifierTypeType_OnlyDeform) continue;
- if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts);
- mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0);
+ if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
+ modifier_deformVerts_DM_deprecated(md, &mectx, NULL, vertexCos, numVerts);
}
- /* always displist to make this work like derivedmesh */
- if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts);
+ if (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ if (vertexCos) {
+ BKE_lattice_vertexcos_apply(ob, vertexCos);
+ MEM_freeN(vertexCos);
+ }
+ }
+ else {
+ /* Displist won't do anything; this is just for posterity's sake until we remove it. */
+ if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
- {
DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
dl->type = DL_VERTS;
dl->parts = 1;
@@ -1224,10 +1230,42 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
}
}
+bool BKE_lattice_is_any_selected(const Lattice *lt)
+{
+ /* Intentionally don't handle 'lt->editlatt' (caller must do this). */
+ const BPoint *bp = lt->def;
+ int a = lt->pntsu * lt->pntsv * lt->pntsw;
+ while (a--) {
+ if (bp->hide == 0) {
+ if (bp->f1 & SELECT) {
+ return true;
+ }
+ }
+ bp++;
+ }
+ return false;
+}
+
/* **** Depsgraph evaluation **** */
-void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+void BKE_lattice_eval_geometry(struct Depsgraph *UNUSED(depsgraph),
Lattice *UNUSED(latt))
{
}
+/* Draw Engine */
+void (*BKE_lattice_batch_cache_dirty_cb)(Lattice *lt, int mode) = NULL;
+void (*BKE_lattice_batch_cache_free_cb)(Lattice *lt) = NULL;
+
+void BKE_lattice_batch_cache_dirty(Lattice *lt, int mode)
+{
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_dirty_cb(lt, mode);
+ }
+}
+void BKE_lattice_batch_cache_free(Lattice *lt)
+{
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_free_cb(lt);
+ }
+}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
new file mode 100644
index 00000000000..42e6cec253a
--- /dev/null
+++ b/source/blender/blenkernel/intern/layer.c
@@ -0,0 +1,1426 @@
+/*
+ * ***** 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.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/layer.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_array.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLI_threads.h"
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
+#include "BKE_collection.h"
+#include "BKE_freestyle.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_workspace.h"
+#include "BKE_object.h"
+
+#include "DNA_group_types.h"
+#include "DNA_ID.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DRW_engine.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* prototype */
+static void object_bases_iterator_next(BLI_Iterator *iter, const int flag);
+
+
+/*********************** Layer Collections and bases *************************/
+
+static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection)
+{
+ LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
+ lc->collection = collection;
+ BLI_addtail(lb_parent, lc);
+
+ return lc;
+}
+
+static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc == view_layer->active_collection) {
+ view_layer->active_collection = view_layer->layer_collections.first;
+ }
+
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ layer_collection_free(view_layer, nlc);
+ }
+
+ BLI_freelistN(&lc->layer_collections);
+}
+
+static Base *object_base_new(Object *ob)
+{
+ Base *base = MEM_callocN(sizeof(Base), "Object Base");
+ base->object = ob;
+ return base;
+}
+
+/********************************* View Layer ********************************/
+
+
+/* RenderLayer */
+
+/* Returns the default view layer to view in workspaces if there is
+ * none linked to the workspace yet. */
+ViewLayer *BKE_view_layer_default_view(const Scene *scene)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (!(view_layer->flag & VIEW_LAYER_RENDER)) {
+ return view_layer;
+ }
+ }
+
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
+}
+
+/* Returns the default view layer to render if we need to render just one. */
+ViewLayer *BKE_view_layer_default_render(const Scene *scene)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (view_layer->flag & VIEW_LAYER_RENDER) {
+ return view_layer;
+ }
+ }
+
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
+}
+
+/**
+ * Returns the ViewLayer to be used for drawing, outliner, and other context related areas.
+ */
+ViewLayer *BKE_view_layer_from_workspace_get(const struct Scene *scene, const struct WorkSpace *workspace)
+{
+ return BKE_workspace_view_layer_get(workspace, scene);
+}
+
+/**
+ * This is a placeholder to know which areas of the code need to be addressed for the Workspace changes.
+ * Never use this, you should either use BKE_view_layer_from_workspace_get or get ViewLayer explicitly.
+ */
+ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
+{
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
+}
+
+static ViewLayer *view_layer_add(const char *name)
+{
+ if (!name) {
+ name = DATA_("View Layer");
+ }
+
+ ViewLayer *view_layer = MEM_callocN(sizeof(ViewLayer), "View Layer");
+ view_layer->flag = VIEW_LAYER_RENDER | VIEW_LAYER_FREESTYLE;
+
+ BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name));
+
+ /* Pure rendering pipeline settings. */
+ view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */
+ view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
+ view_layer->pass_alpha_threshold = 0.5f;
+ BKE_freestyle_config_init(&view_layer->freestyle_config);
+
+ return view_layer;
+}
+
+/**
+ * Add a new view layer
+ * by default, a view layer has the master collection
+ */
+ViewLayer *BKE_view_layer_add(Scene *scene, const char *name)
+{
+ ViewLayer *view_layer = view_layer_add(name);
+
+ BLI_addtail(&scene->view_layers, view_layer);
+
+ /* unique name */
+ BLI_uniquename(
+ &scene->view_layers, view_layer, DATA_("ViewLayer"), '.',
+ offsetof(ViewLayer, name), sizeof(view_layer->name));
+
+ BKE_layer_collection_sync(scene, view_layer);
+
+ return view_layer;
+}
+
+void BKE_view_layer_free(ViewLayer *view_layer)
+{
+ BKE_view_layer_free_ex(view_layer, true);
+}
+
+/**
+ * Free (or release) any data used by this ViewLayer.
+ */
+void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
+{
+ view_layer->basact = NULL;
+
+ BLI_freelistN(&view_layer->object_bases);
+
+ if (view_layer->object_bases_hash) {
+ BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
+ }
+
+ for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
+ layer_collection_free(view_layer, lc);
+ }
+ BLI_freelistN(&view_layer->layer_collections);
+
+ for (ViewLayerEngineData *sled = view_layer->drawdata.first; sled; sled = sled->next) {
+ if (sled->storage) {
+ if (sled->free) {
+ sled->free(sled->storage);
+ }
+ MEM_freeN(sled->storage);
+ }
+ }
+ BLI_freelistN(&view_layer->drawdata);
+
+ MEM_SAFE_FREE(view_layer->stats);
+
+ BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user);
+
+ if (view_layer->id_properties) {
+ IDP_FreeProperty(view_layer->id_properties);
+ MEM_freeN(view_layer->id_properties);
+ }
+
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ MEM_freeN(view_layer);
+}
+
+/**
+ * Tag all the selected objects of a renderlayer
+ */
+void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTED) != 0) {
+ base->object->flag |= tag;
+ }
+ else {
+ base->object->flag &= ~tag;
+ }
+ }
+}
+
+static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc)
+{
+ for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) {
+ if (lcn == lc) {
+ return true;
+ }
+ if (find_scene_collection_in_scene_collections(&lcn->layer_collections, lc)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Fallback for when a Scene has no camera to use
+ *
+ * \param view_layer: in general you want to use the same ViewLayer that is used
+ * for depsgraph. If rendering you pass the scene active layer, when viewing in the viewport
+ * you want to get ViewLayer from context.
+ */
+Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->type == OB_CAMERA) {
+ return base->object;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Find the ViewLayer a LayerCollection belongs to
+ */
+ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) {
+ return view_layer;
+ }
+ }
+
+ return NULL;
+}
+
+/* Base */
+
+static void view_layer_bases_hash_create(ViewLayer *view_layer)
+{
+ static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER;
+
+ if (!view_layer->object_bases_hash) {
+ BLI_mutex_lock(&hash_lock);
+
+ view_layer->object_bases_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
+ }
+
+ BLI_mutex_unlock(&hash_lock);
+ }
+}
+
+Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
+{
+ if (!view_layer->object_bases_hash) {
+ view_layer_bases_hash_create(view_layer);
+ }
+
+ return BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+}
+
+void BKE_view_layer_base_deselect_all(ViewLayer *view_layer)
+{
+ Base *base;
+
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag &= ~BASE_SELECTED;
+ }
+}
+
+void BKE_view_layer_base_select(struct ViewLayer *view_layer, Base *selbase)
+{
+ view_layer->basact = selbase;
+ if ((selbase->flag & BASE_SELECTABLED) != 0) {
+ selbase->flag |= BASE_SELECTED;
+ }
+}
+
+/**************************** Copy View Layer and Layer Collections ***********************/
+
+static void layer_collections_copy_data(ListBase *layer_collections_dst, const ListBase *layer_collections_src)
+{
+ BLI_duplicatelist(layer_collections_dst, layer_collections_src);
+
+ LayerCollection *layer_collection_dst = layer_collections_dst->first;
+ const LayerCollection *layer_collection_src = layer_collections_src->first;
+
+ while (layer_collection_dst != NULL) {
+ layer_collections_copy_data(
+ &layer_collection_dst->layer_collections,
+ &layer_collection_src->layer_collections);
+
+ layer_collection_dst = layer_collection_dst->next;
+ layer_collection_src = layer_collection_src->next;
+ }
+}
+
+/**
+ * Only copy internal data of ViewLayer from source to already allocated/initialized destination.
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_view_layer_copy_data(
+ Scene *UNUSED(scene_dst), const Scene *UNUSED(scene_src),
+ ViewLayer *view_layer_dst, const ViewLayer *view_layer_src,
+ const int flag)
+{
+ if (view_layer_dst->id_properties != NULL) {
+ view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag);
+ }
+ BKE_freestyle_config_copy(&view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag);
+
+ view_layer_dst->stats = NULL;
+
+ /* Clear temporary data. */
+ BLI_listbase_clear(&view_layer_dst->drawdata);
+ view_layer_dst->object_bases_array = NULL;
+ view_layer_dst->object_bases_hash = NULL;
+
+ /* Copy layer collections and object bases. */
+ /* Inline 'BLI_duplicatelist' and update the active base. */
+ BLI_listbase_clear(&view_layer_dst->object_bases);
+ for (Base *base_src = view_layer_src->object_bases.first; base_src; base_src = base_src->next) {
+ Base *base_dst = MEM_dupallocN(base_src);
+ BLI_addtail(&view_layer_dst->object_bases, base_dst);
+ if (view_layer_src->basact == base_src) {
+ view_layer_dst->basact = base_dst;
+ }
+ }
+
+ layer_collections_copy_data(&view_layer_dst->layer_collections, &view_layer_src->layer_collections);
+
+ // TODO: not always safe to free BKE_layer_collection_sync(scene_dst, view_layer_dst);
+}
+
+void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, const char *newname)
+{
+ char oldname[sizeof(view_layer->name)];
+
+ BLI_strncpy(oldname, view_layer->name, sizeof(view_layer->name));
+
+ BLI_strncpy_utf8(view_layer->name, newname, sizeof(view_layer->name));
+ BLI_uniquename(&scene->view_layers, view_layer, DATA_("ViewLayer"), '.', offsetof(ViewLayer, name), sizeof(view_layer->name));
+
+ if (scene->nodetree) {
+ bNode *node;
+ int index = BLI_findindex(&scene->view_layers, view_layer);
+
+ for (node = scene->nodetree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS && node->id == NULL) {
+ if (node->custom1 == index)
+ BLI_strncpy(node->name, view_layer->name, NODE_MAXSTR);
+ }
+ }
+ }
+
+ /* fix all the animation data and workspace which may link to this */
+ BKE_animdata_fix_paths_rename_all(NULL, "view_layers", oldname, view_layer->name);
+ BKE_workspace_view_layer_rename(bmain, scene, oldname, view_layer->name);
+
+ /* Dependency graph uses view layer name based lookups. */
+ DEG_id_tag_update(&scene->id, 0);
+}
+
+/* LayerCollection */
+
+/**
+ * Recursively get the collection for a given index
+ */
+static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i)
+{
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ if (*i == number) {
+ return lc;
+ }
+
+ (*i)++;
+ }
+
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i);
+ if (lc_nested) {
+ return lc_nested;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Get the collection for a given index
+ */
+LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const int index)
+{
+ int i = 0;
+ return collection_from_index(&view_layer->layer_collections, index, &i);
+}
+
+/**
+ * Get the active collection
+ */
+LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer)
+{
+ return view_layer->active_collection;
+}
+
+/*
+ * Activate collection
+ */
+bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ return false;
+ }
+
+ view_layer->active_collection = lc;
+ return true;
+}
+
+/**
+ * Activate first parent collection
+ */
+LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc)
+{
+ CollectionParent *parent = lc->collection->parents.first;
+
+ if (parent) {
+ lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection);
+ }
+ else {
+ lc = NULL;
+ }
+
+ if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ /* Don't activate excluded collections. */
+ return BKE_layer_collection_activate_parent(view_layer, lc);
+ }
+
+ if (!lc) {
+ lc = view_layer->layer_collections.first;
+ }
+
+ view_layer->active_collection = lc;
+ return lc;
+}
+
+/**
+ * Recursively get the count of collections
+ */
+static int collection_count(ListBase *lb)
+{
+ int i = 0;
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ i += collection_count(&lc->layer_collections) + 1;
+ }
+ return i;
+}
+
+/**
+ * Get the total number of collections
+ * (including all the nested collections)
+ */
+int BKE_layer_collection_count(ViewLayer *view_layer)
+{
+ return collection_count(&view_layer->layer_collections);
+}
+
+/**
+ * Recursively get the index for a given collection
+ */
+static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i)
+{
+ for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ if (lcol == lc) {
+ return *i;
+ }
+
+ (*i)++;
+ }
+
+ for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ int i_nested = index_from_collection(&lcol->layer_collections, lc, i);
+ if (i_nested != -1) {
+ return i_nested;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Return -1 if not found
+ */
+int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection *lc)
+{
+ int i = 0;
+ return index_from_collection(&view_layer->layer_collections, lc, &i);
+}
+
+/*********************************** Syncing *********************************
+ *
+ * The layer collection tree mirrors the scene collection tree. Whenever that
+ * changes we need to synchronize them so that there is a corresponding layer
+ * collection for each collection. Note that the scene collection tree can
+ * contain link or override collections, and so this is also called on .blend
+ * file load to ensure any new or removed collections are synced.
+ *
+ * The view layer also contains a list of bases for each object that exists
+ * in at least one layer collection. That list is also synchronized here, and
+ * stores state like selection. */
+
+static int layer_collection_sync(
+ ViewLayer *view_layer, const ListBase *lb_scene,
+ ListBase *lb_layer, ListBase *new_object_bases,
+ int parent_exclude, int parent_restrict)
+{
+ /* TODO: support recovery after removal of intermediate collections, reordering, ..
+ * For local edits we can make editing operating do the appropriate thing, but for
+ * linking we can only sync after the fact. */
+
+ /* Remove layer collections that no longer have a corresponding scene collection. */
+ for (LayerCollection *lc = lb_layer->first; lc;) {
+ /* Note ID remap can set lc->collection to NULL when deleting collections. */
+ LayerCollection *lc_next = lc->next;
+ Collection *collection = (lc->collection) ?
+ BLI_findptr(lb_scene, lc->collection, offsetof(CollectionChild, collection)) : NULL;
+
+ if (!collection) {
+ /* Free recursively. */
+ layer_collection_free(view_layer, lc);
+ BLI_freelinkN(lb_layer, lc);
+ }
+
+ lc = lc_next;
+ }
+
+ /* Add layer collections for any new scene collections, and ensure order is the same. */
+ ListBase new_lb_layer = {NULL, NULL};
+ int runtime_flag = 0;
+
+ for (const CollectionChild *child = lb_scene->first; child; child = child->next) {
+ Collection *collection = child->collection;
+ LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection));
+
+ if (lc) {
+ BLI_remlink(lb_layer, lc);
+ BLI_addtail(&new_lb_layer, lc);
+ }
+ else {
+ lc = layer_collection_add(&new_lb_layer, collection);
+ lc->flag = parent_exclude;
+ }
+
+ /* Collection restrict is inherited. */
+ int child_restrict = parent_restrict;
+ if (!(collection->flag & COLLECTION_IS_MASTER)) {
+ child_restrict |= collection->flag;
+ }
+
+ /* Sync child collections. */
+ int child_runtime_flag = layer_collection_sync(
+ view_layer, &collection->children,
+ &lc->layer_collections, new_object_bases,
+ lc->flag, child_restrict);
+
+ /* Layer collection exclude is not inherited. */
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ lc->runtime_flag = 0;
+ continue;
+ }
+ else {
+ lc->runtime_flag = child_runtime_flag;
+ }
+
+ /* Sync objects, except if collection was excluded. */
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, cob->ob);
+
+ if (base) {
+ /* Move from old base list to new base list. Base might have already
+ * been moved to the new base list and the first/last test ensure that
+ * case also works. */
+ if (!ELEM(base, new_object_bases->first, new_object_bases->last)) {
+ BLI_remlink(&view_layer->object_bases, base);
+ BLI_addtail(new_object_bases, base);
+ }
+ }
+ else {
+ /* Create new base. */
+ base = object_base_new(cob->ob);
+ BLI_addtail(new_object_bases, base);
+ BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
+ }
+
+ int object_restrict = base->object->restrictflag;
+
+ if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
+ ((object_restrict & OB_RESTRICT_VIEW) == 0))
+ {
+ base->flag |= BASE_VISIBLED | BASE_VISIBLE_VIEWPORT;
+
+ if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0) &&
+ ((object_restrict & OB_RESTRICT_SELECT) == 0))
+ {
+ base->flag |= BASE_SELECTABLED;
+ }
+ }
+
+ if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) &&
+ ((object_restrict & OB_RESTRICT_RENDER) == 0))
+
+ {
+ base->flag |= BASE_VISIBLE_RENDER;
+ }
+
+ /* Update runtime flags used for display and tools. */
+ if (base->flag & BASE_VISIBLED) {
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_ENABLED_OBJECTS;
+ }
+
+ if (base->flag & BASE_HIDE) {
+ view_layer->runtime_flag |= VIEW_LAYER_HAS_HIDE;
+ }
+ else if (base->flag & BASE_VISIBLED) {
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_VISIBLE_OBJECTS;
+ }
+
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
+ }
+
+ runtime_flag |= lc->runtime_flag;
+ }
+
+ /* Replace layer collection list with new one. */
+ *lb_layer = new_lb_layer;
+ BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer));
+
+ return runtime_flag;
+}
+
+/**
+ * Update view layer collection tree from collections used in the scene.
+ * This is used when collections are removed or added, both while editing
+ * and on file loaded in case linked data changed or went missing.
+ */
+void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
+{
+ if (!scene->master_collection) {
+ /* Happens for old files that don't have versioning applied yet. */
+ return;
+ }
+
+ /* Free cache. */
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ /* Create object to base hash if it does not exist yet. */
+ if (!view_layer->object_bases_hash) {
+ view_layer_bases_hash_create(view_layer);
+ }
+
+ /* Clear visible and selectable flags to be reset. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED | BASE_VISIBLE_VIEWPORT | BASE_VISIBLE_RENDER);
+ }
+
+ view_layer->runtime_flag = 0;
+
+ /* Generate new layer connections and object bases when collections changed. */
+ CollectionChild child = {NULL, NULL, scene->master_collection};
+ const ListBase collections = {&child, &child};
+ ListBase new_object_bases = {NULL, NULL};
+
+ const int parent_exclude = 0, parent_restrict = 0;
+ layer_collection_sync(
+ view_layer, &collections,
+ &view_layer->layer_collections, &new_object_bases,
+ parent_exclude, parent_restrict);
+
+ /* Any remaning object bases are to be removed. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (view_layer->basact == base) {
+ view_layer->basact = NULL;
+ }
+
+ BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL);
+ }
+
+ BLI_freelistN(&view_layer->object_bases);
+ view_layer->object_bases = new_object_bases;
+
+ /* Always set a valid active collection. */
+ LayerCollection *active = view_layer->active_collection;
+
+ if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) {
+ BKE_layer_collection_activate_parent(view_layer, active);
+ }
+ else if (active == NULL) {
+ view_layer->active_collection = view_layer->layer_collections.first;
+ }
+}
+
+void BKE_scene_collection_sync(const Scene *scene)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ BKE_layer_collection_sync(scene, view_layer);
+ }
+}
+
+void BKE_main_collection_sync(const Main *bmain)
+{
+ /* TODO: if a single collection changed, figure out which
+ * scenes it belongs to and only update those. */
+
+ /* TODO: optimize for file load so only linked collections get checked? */
+
+ for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ BKE_scene_collection_sync(scene);
+ }
+}
+
+void BKE_main_collection_sync_remap(const Main *bmain)
+{
+ /* On remapping of object or collection pointers free caches. */
+ /* TODO: try to make this faster */
+
+ for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ if (view_layer->object_bases_hash) {
+ BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
+ view_layer->object_bases_hash = NULL;
+ }
+ }
+ }
+
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ BKE_collection_object_cache_free(collection);
+ DEG_id_tag_update_ex((Main *)bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
+ BKE_main_collection_sync(bmain);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Select all the objects of this layer collection
+ *
+ * It also select the objects that are in nested collections.
+ * \note Recursive
+ */
+bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect)
+{
+ if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
+
+ bool changed = false;
+
+ if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+
+ if (base) {
+ if (deselect) {
+ if (base->flag & BASE_SELECTED) {
+ base->flag &= ~BASE_SELECTED;
+ changed = true;
+ }
+ }
+ else {
+ if ((base->flag & BASE_SELECTABLED) && !(base->flag & BASE_SELECTED)) {
+ base->flag |= BASE_SELECTED;
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect);
+ }
+
+ return changed;
+}
+
+bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
+
+ if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+
+ if (base && (base->flag & BASE_SELECTED)) {
+ return true;
+ }
+ }
+ }
+
+ for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ if (BKE_layer_collection_has_selected_objects(view_layer, iter)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* Test base visibility when BASE_VISIBLED has not been set yet. */
+static bool base_is_visible(Base *base, eEvaluationMode mode)
+{
+ if (mode == DAG_EVAL_VIEWPORT) {
+ return ((base->flag & BASE_VISIBLE_VIEWPORT) != 0) &&
+ ((base->flag & BASE_HIDE) == 0);
+ }
+ else {
+ return ((base->flag & BASE_VISIBLE_RENDER) != 0);
+ }
+}
+
+/* Update after toggling visibility of an object base. */
+void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool extend)
+{
+ if (!extend) {
+ /* Make only one base visible. */
+ for (Base *other = view_layer->object_bases.first; other; other = other->next) {
+ other->flag |= BASE_HIDE;
+ }
+
+ base->flag &= ~BASE_HIDE;
+ }
+ else {
+ /* Toggle visibility of one base. */
+ base->flag ^= BASE_HIDE;
+ }
+
+ BKE_layer_collection_sync(scene, view_layer);
+}
+
+void BKE_layer_collection_set_visible(Scene *scene, ViewLayer *view_layer, LayerCollection *lc, bool extend)
+{
+ if (!extend) {
+ /* Make only objects from one collection visible. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag |= BASE_HIDE;
+ }
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(lc->collection, ob)
+ {
+ Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+
+ if (base) {
+ base->flag &= ~BASE_HIDE;
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ BKE_layer_collection_activate(view_layer, lc);
+ }
+ else {
+ /* Toggle visibility of objects from collection. */
+ bool hide = (lc->runtime_flag & LAYER_COLLECTION_HAS_VISIBLE_OBJECTS) != 0;
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(lc->collection, ob)
+ {
+ Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+
+ if (base) {
+ if (hide) {
+ base->flag |= BASE_HIDE;
+ }
+ else {
+ base->flag &= ~BASE_HIDE;
+ }
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+
+ BKE_layer_collection_sync(scene, view_layer);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const Collection *collection)
+{
+ if (lc->collection == collection) {
+ return lc;
+ }
+
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection);
+ if (found) {
+ return found;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Return the first matching LayerCollection in the ViewLayer for the Collection.
+ */
+LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const Collection *collection)
+{
+ for (LayerCollection *layer_collection = view_layer->layer_collections.first;
+ layer_collection != NULL;
+ layer_collection = layer_collection->next)
+ {
+ LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, collection);
+
+ if (found != NULL) {
+ return found;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * See if view layer has the scene collection linked directly, or indirectly (nested)
+ */
+bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *collection)
+{
+ return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL;
+}
+
+/**
+ * See if the object is in any of the scene layers of the scene
+ */
+bool BKE_scene_has_object(Scene *scene, Object *ob)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Override */
+
+/**
+ * Add a new datablock override
+ */
+void BKE_override_view_layer_datablock_add(
+ ViewLayer *view_layer, int id_type, const char *data_path, const ID *owner_id)
+{
+ UNUSED_VARS(view_layer, id_type, data_path, owner_id);
+ TODO_LAYER_OVERRIDE;
+}
+
+/**
+ * Add a new int override
+ */
+void BKE_override_view_layer_int_add(
+ ViewLayer *view_layer, int id_type, const char *data_path, const int value)
+{
+ UNUSED_VARS(view_layer, id_type, data_path, value);
+ TODO_LAYER_OVERRIDE;
+}
+
+/**
+ * Add a new boolean override
+ */
+void BKE_override_layer_collection_boolean_add(
+ struct LayerCollection *layer_collection, int id_type, const char *data_path, const bool value)
+{
+ UNUSED_VARS(layer_collection, id_type, data_path, value);
+ TODO_LAYER_OVERRIDE;
+}
+
+/** \} */
+
+/* Iterators */
+
+/* -------------------------------------------------------------------- */
+/** \name Private Iterator Helpers
+ * \{ */
+
+static void object_bases_iterator_begin(BLI_Iterator *iter, void *data_in, const int flag)
+{
+ ViewLayer *view_layer = data_in;
+ Base *base = view_layer->object_bases.first;
+
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->valid = false;
+ return;
+ }
+
+ iter->data = base;
+
+ if ((base->flag & flag) == 0) {
+ object_bases_iterator_next(iter, flag);
+ }
+ else {
+ iter->current = base;
+ }
+}
+
+static void object_bases_iterator_next(BLI_Iterator *iter, const int flag)
+{
+ Base *base = ((Base *)iter->data)->next;
+
+ while (base) {
+ if ((base->flag & flag) != 0) {
+ iter->current = base;
+ iter->data = base;
+ return;
+ }
+ base = base->next;
+ }
+
+ iter->valid = false;
+}
+
+static void objects_iterator_begin(BLI_Iterator *iter, void *data_in, const int flag)
+{
+ object_bases_iterator_begin(iter, data_in, flag);
+
+ if (iter->valid) {
+ iter->current = ((Base *)iter->current)->object;
+ }
+}
+
+static void objects_iterator_next(BLI_Iterator *iter, const int flag)
+{
+ object_bases_iterator_next(iter, flag);
+
+ if (iter->valid) {
+ iter->current = ((Base *)iter->current)->object;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_selected_objects_iterator
+ * See: #FOREACH_SELECTED_OBJECT_BEGIN
+ * \{ */
+
+void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter)
+{
+ objects_iterator_next(iter, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_visible_objects_iterator
+ * \{ */
+
+void BKE_view_layer_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_VISIBLED);
+}
+
+void BKE_view_layer_visible_objects_iterator_next(BLI_Iterator *iter)
+{
+ objects_iterator_next(iter, BASE_VISIBLED);
+}
+
+void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_selected_editable_objects_iterator
+ * \{ */
+
+void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_SELECTED);
+ if (iter->valid) {
+ if (BKE_object_is_libdata((Object *)iter->current) == false) {
+ // First object is valid (selectable and not libdata) -> all good.
+ return;
+ }
+ else {
+ // Object is selectable but not editable -> search for another one.
+ BKE_view_layer_selected_editable_objects_iterator_next(iter);
+ }
+ }
+}
+
+void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter)
+{
+ // Search while there are objects and the one we have is not editable (editable = not libdata).
+ do {
+ objects_iterator_next(iter, BASE_SELECTED);
+ } while (iter->valid && BKE_object_is_libdata((Object *)iter->current) != false);
+}
+
+void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_selected_bases_iterator
+ * \{ */
+
+void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ object_bases_iterator_begin(iter, data_in, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter)
+{
+ object_bases_iterator_next(iter, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_visible_bases_iterator
+ * \{ */
+
+void BKE_view_layer_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ object_bases_iterator_begin(iter, data_in, BASE_VISIBLED);
+}
+
+void BKE_view_layer_visible_bases_iterator_next(BLI_Iterator *iter)
+{
+ object_bases_iterator_next(iter, BASE_VISIBLED);
+}
+
+void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_renderable_objects_iterator
+ * \{ */
+
+void BKE_view_layer_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ struct ObjectsRenderableIteratorData *data = data_in;
+
+ /* Tag objects to prevent going over the same object twice. */
+ for (Scene *scene = data->scene; scene; scene = scene->set) {
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->object->id.flag |= LIB_TAG_DOIT;
+ }
+ }
+ }
+
+ ViewLayer *view_layer = data->scene->view_layers.first;
+ data->iter.view_layer = view_layer;
+
+ data->base_temp.next = view_layer->object_bases.first;
+ data->iter.base = &data->base_temp;
+
+ data->iter.set = NULL;
+
+ iter->data = data_in;
+ BKE_view_layer_renderable_objects_iterator_next(iter);
+}
+
+void BKE_view_layer_renderable_objects_iterator_next(BLI_Iterator *iter)
+{
+ /* Set it early in case we need to exit and we are running from within a loop. */
+ iter->skip = true;
+
+ struct ObjectsRenderableIteratorData *data = iter->data;
+ Base *base = data->iter.base->next;
+
+ /* There is still a base in the current scene layer. */
+ if (base != NULL) {
+ Object *ob = base->object;
+
+ /* We need to set the iter.base even if the rest fail otherwise
+ * we keep checking the exactly same base over and over again. */
+ data->iter.base = base;
+
+ if (ob->id.flag & LIB_TAG_DOIT) {
+ ob->id.flag &= ~LIB_TAG_DOIT;
+
+ if ((base->flag & BASE_VISIBLED) != 0) {
+ iter->skip = false;
+ iter->current = ob;
+ }
+ }
+ return;
+ }
+
+ /* Time to go to the next scene layer. */
+ if (data->iter.set == NULL) {
+ while ((data->iter.view_layer = data->iter.view_layer->next)) {
+ ViewLayer *view_layer = data->iter.view_layer;
+ if (view_layer->flag & VIEW_LAYER_RENDER) {
+ data->base_temp.next = view_layer->object_bases.first;
+ data->iter.base = &data->base_temp;
+ return;
+ }
+ }
+
+ /* Setup the "set" for the next iteration. */
+ data->scene_temp.set = data->scene;
+ data->iter.set = &data->scene_temp;
+ return;
+ }
+
+ /* Look for an object in the next set. */
+ while ((data->iter.set = data->iter.set->set)) {
+ ViewLayer *view_layer = BKE_view_layer_default_render(data->iter.set);
+ data->base_temp.next = view_layer->object_bases.first;
+ data->iter.base = &data->base_temp;
+ return;
+ }
+
+ iter->valid = false;
+}
+
+void BKE_view_layer_renderable_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* Do nothing - iter->data was static allocated, we can't free it. */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_bases_in_mode_iterator
+ * \{ */
+
+void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ struct ObjectsInModeIteratorData *data = data_in;
+ Base *base = data->base_active;
+
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->valid = false;
+ return;
+ }
+ iter->data = data_in;
+ iter->current = base;
+}
+
+void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter)
+{
+ struct ObjectsInModeIteratorData *data = iter->data;
+ Base *base = iter->current;
+
+ if (base == data->base_active) {
+ /* first step */
+ base = data->view_layer->object_bases.first;
+ if (base == data->base_active) {
+ base = base->next;
+ }
+ }
+ else {
+ base = base->next;
+ }
+
+ while (base) {
+ if ((base->object->type == data->base_active->object->type) &&
+ (base != data->base_active) &&
+ (base->object->mode & data->object_mode))
+ {
+ iter->current = base;
+ return;
+ }
+ base = base->next;
+ }
+ iter->valid = false;
+}
+
+void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* Evaluation */
+
+void BKE_layer_eval_view_layer(
+ struct Depsgraph *depsgraph,
+ struct Scene *UNUSED(scene),
+ ViewLayer *view_layer)
+{
+ DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer);
+
+ /* Visibility based on depsgraph mode. */
+ const eEvaluationMode mode = DEG_get_mode(depsgraph);
+
+ /* Create array of bases, for fast index-based lookup. */
+ const int num_object_bases = BLI_listbase_count(&view_layer->object_bases);
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+ view_layer->object_bases_array = MEM_malloc_arrayN(
+ num_object_bases, sizeof(Base *), "view_layer->object_bases_array");
+ int base_index = 0;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ /* Set visibility. */
+ if (base_is_visible(base, mode)) {
+ base->flag |= BASE_VISIBLED;
+ }
+ else {
+ base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED);
+ }
+
+ /* If base is not selectabled, clear select. */
+ if ((base->flag & BASE_SELECTABLED) == 0) {
+ base->flag &= ~BASE_SELECTED;
+ }
+
+ view_layer->object_bases_array[base_index++] = base;
+ }
+
+ /* Flush back base flag to the original view layer for editing. */
+ if (view_layer == DEG_get_evaluated_view_layer(depsgraph)) {
+ ViewLayer *view_layer_orig = DEG_get_input_view_layer(depsgraph);
+ Base *base_orig = view_layer_orig->object_bases.first;
+ const Base *base_eval = view_layer->object_bases.first;
+ while (base_orig != NULL) {
+ base_orig->flag = base_eval->flag;
+ base_orig = base_orig->next;
+ base_eval = base_eval->next;
+ }
+ }
+}
+
+void BKE_layer_eval_view_layer_indexed(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ int view_layer_index)
+{
+ BLI_assert(view_layer_index >= 0);
+ ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
+ BLI_assert(view_layer != NULL);
+ BKE_layer_eval_view_layer(depsgraph, scene, view_layer);
+}
diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c
new file mode 100644
index 00000000000..94bac8a33d6
--- /dev/null
+++ b/source/blender/blenkernel/intern/layer_utils.c
@@ -0,0 +1,125 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/layer_utils.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_array.h"
+#include "BLI_listbase.h"
+
+#include "BKE_collection.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+
+#include "DNA_ID.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+Base **BKE_view_layer_array_from_bases_in_mode_params(
+ ViewLayer *view_layer, uint *r_len,
+ const struct ObjectsInModeParams *params)
+{
+ if (params->no_dup_data) {
+ FOREACH_BASE_IN_MODE_BEGIN(view_layer, params->object_mode, base_iter) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ } FOREACH_BASE_IN_MODE_END;
+ }
+
+ Base **base_array = NULL;
+ BLI_array_declare(base_array);
+
+ FOREACH_BASE_IN_MODE_BEGIN(view_layer, params->object_mode, base_iter) {
+ if (params->filter_fn) {
+ if (!params->filter_fn(base_iter->object, params->filter_userdata)) {
+ continue;
+ }
+ }
+ if (params->no_dup_data) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ if (id->tag & LIB_TAG_DOIT) {
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+ BLI_array_append(base_array, base_iter);
+ } FOREACH_BASE_IN_MODE_END;
+
+ if (base_array != NULL) {
+ base_array = MEM_reallocN(base_array, sizeof(*base_array) * BLI_array_len(base_array));
+ }
+ *r_len = BLI_array_len(base_array);
+ return base_array;
+}
+
+Object **BKE_view_layer_array_from_objects_in_mode_params(
+ ViewLayer *view_layer, uint *r_len,
+ const struct ObjectsInModeParams *params)
+{
+ Base **base_array = BKE_view_layer_array_from_bases_in_mode_params(
+ view_layer, r_len, params);
+ if (base_array != NULL) {
+ for (uint i = 0; i < *r_len; i++) {
+ ((Object **)base_array)[i] = base_array[i]->object;
+ }
+ }
+ return (Object **)base_array;
+}
+
+bool BKE_view_layer_filter_edit_mesh_has_uvs(Object *ob, void *UNUSED(user_data))
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em != NULL) {
+ if (CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV) != -1) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool BKE_view_layer_filter_edit_mesh_has_edges(Object *ob, void *UNUSED(user_data))
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em != NULL) {
+ if (em->bm->totedge != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 00c542bcd4a..c2cdc8df1e6 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -62,6 +62,7 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -70,6 +71,7 @@
#include "DNA_vfont_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_world_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -78,8 +80,8 @@
#include "BLI_memarena.h"
#include "BLI_mempool.h"
#include "BLI_string_utils.h"
-
#include "BLI_threads.h"
+
#include "BLT_translation.h"
#include "BKE_action.h"
@@ -89,12 +91,11 @@
#include "BKE_brush.h"
#include "BKE_camera.h"
#include "BKE_cachefile.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_font.h"
#include "BKE_global.h"
-#include "BKE_group.h"
#include "BKE_gpencil.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
@@ -103,6 +104,7 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -117,6 +119,7 @@
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
+#include "BKE_lightprobe.h"
#include "BKE_sound.h"
#include "BKE_speaker.h"
#include "BKE_scene.h"
@@ -418,6 +421,9 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
case ID_SPK:
if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local);
return true;
+ case ID_LP:
+ if (!test) BKE_lightprobe_make_local(bmain, (LightProbe *)id, lib_local);
+ return true;
case ID_WO:
if (!test) BKE_world_make_local(bmain, (World *)id, lib_local);
return true;
@@ -431,7 +437,7 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local);
return true;
case ID_GR:
- if (!test) BKE_group_make_local(bmain, (Group *)id, lib_local);
+ if (!test) BKE_collection_make_local(bmain, (Collection *)id, lib_local);
return true;
case ID_AR:
if (!test) BKE_armature_make_local(bmain, (bArmature *)id, lib_local);
@@ -469,7 +475,11 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
case ID_CF:
if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local);
return true;
+ case ID_WS:
case ID_SCR:
+ /* A bit special: can be appended but not linked. Return false
+ * since supporting make-local doesn't make much sense. */
+ return false;
case ID_LI:
case ID_KE:
case ID_WM:
@@ -589,6 +599,9 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
case ID_SPK:
BKE_speaker_copy_data(bmain, (Speaker *)*r_newid, (Speaker *)id, flag);
break;
+ case ID_LP:
+ BKE_lightprobe_copy_data(bmain, (LightProbe *)*r_newid, (LightProbe *)id, flag);
+ break;
case ID_CA:
BKE_camera_copy_data(bmain, (Camera *)*r_newid, (Camera *)id, flag);
break;
@@ -602,7 +615,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag);
break;
case ID_GR:
- BKE_group_copy_data(bmain, (Group *)*r_newid, (Group *)id, flag);
+ BKE_collection_copy_data(bmain, (Collection *)*r_newid, (Collection *)id, flag);
break;
case ID_AR:
BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag);
@@ -649,6 +662,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
case ID_LI:
case ID_SCR:
case ID_WM:
+ case ID_WS:
case ID_IP:
BLI_assert(0); /* Should have been rejected at start of function! */
break;
@@ -677,7 +691,76 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
*/
bool id_copy(Main *bmain, const ID *id, ID **newid, bool test)
{
- return BKE_id_copy_ex(bmain, id, newid, 0, test);
+ return BKE_id_copy_ex(bmain, id, newid, LIB_ID_COPY_SHAPEKEY, test);
+}
+
+/** Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note Most internal ID data itself is not swapped (only IDProperties are). */
+void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b)
+{
+ BLI_assert(GS(id_a->name) == GS(id_b->name));
+
+ const ID id_a_back = *id_a;
+ const ID id_b_back = *id_b;
+
+#define CASE_SWAP(_gs, _type) \
+ case _gs: \
+ SWAP(_type, *(_type *)id_a, *(_type *)id_b); \
+ break
+
+ switch ((ID_Type)GS(id_a->name)) {
+ CASE_SWAP(ID_SCE, Scene);
+ CASE_SWAP(ID_LI, Library);
+ CASE_SWAP(ID_OB, Object);
+ CASE_SWAP(ID_ME, Mesh);
+ CASE_SWAP(ID_CU, Curve);
+ CASE_SWAP(ID_MB, MetaBall);
+ CASE_SWAP(ID_MA, Material);
+ CASE_SWAP(ID_TE, Tex);
+ CASE_SWAP(ID_IM, Image);
+ CASE_SWAP(ID_LT, Lattice);
+ CASE_SWAP(ID_LA, Lamp);
+ CASE_SWAP(ID_LP, LightProbe);
+ CASE_SWAP(ID_CA, Camera);
+ CASE_SWAP(ID_KE, Key);
+ CASE_SWAP(ID_WO, World);
+ CASE_SWAP(ID_SCR, bScreen);
+ CASE_SWAP(ID_VF, VFont);
+ CASE_SWAP(ID_TXT, Text);
+ CASE_SWAP(ID_SPK, Speaker);
+ CASE_SWAP(ID_SO, bSound);
+ CASE_SWAP(ID_GR, Collection);
+ CASE_SWAP(ID_AR, bArmature);
+ CASE_SWAP(ID_AC, bAction);
+ CASE_SWAP(ID_NT, bNodeTree);
+ CASE_SWAP(ID_BR, Brush);
+ CASE_SWAP(ID_PA, ParticleSettings);
+ CASE_SWAP(ID_WM, wmWindowManager);
+ CASE_SWAP(ID_WS, WorkSpace);
+ CASE_SWAP(ID_GD, bGPdata);
+ CASE_SWAP(ID_MC, MovieClip);
+ CASE_SWAP(ID_MSK, Mask);
+ CASE_SWAP(ID_LS, FreestyleLineStyle);
+ CASE_SWAP(ID_PAL, Palette);
+ CASE_SWAP(ID_PC, PaintCurve);
+ CASE_SWAP(ID_CF, CacheFile);
+ case ID_IP:
+ break; /* Deprecated. */
+ }
+
+#undef CASE_SWAP
+
+ /* Restore original ID's internal data. */
+ *id_a = id_a_back;
+ *id_b = id_b_back;
+
+ /* Exception: IDProperties. */
+ id_a->properties = id_b_back.properties;
+ id_b->properties = id_a_back.properties;
+
+ /* Swap will have broken internal references to itself, restore them. */
+ BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false);
+ BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false);
}
/** Does *not* set ID->newid pointer. */
@@ -848,10 +931,12 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->text);
case ID_SPK:
return &(mainlib->speaker);
+ case ID_LP:
+ return &(mainlib->lightprobe);
case ID_SO:
return &(mainlib->sound);
case ID_GR:
- return &(mainlib->group);
+ return &(mainlib->collection);
case ID_AR:
return &(mainlib->armature);
case ID_AC:
@@ -878,6 +963,8 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->paintcurves);
case ID_CF:
return &(mainlib->cachefiles);
+ case ID_WS:
+ return &(mainlib->workspaces);
}
return NULL;
}
@@ -963,11 +1050,11 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
/* flag for full recalc */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ID_IS_LINKED(ob)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
}
- DAG_id_type_tag(bmain, ID_OB);
+ DEG_id_type_tag(bmain, ID_OB);
}
/**
@@ -1010,12 +1097,13 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[INDEX_ID_TXT] = &(main->text);
lb[INDEX_ID_SO] = &(main->sound);
- lb[INDEX_ID_GR] = &(main->group);
+ lb[INDEX_ID_GR] = &(main->collection);
lb[INDEX_ID_PAL] = &(main->palettes);
lb[INDEX_ID_PC] = &(main->paintcurves);
lb[INDEX_ID_BR] = &(main->brush);
lb[INDEX_ID_PA] = &(main->particle);
lb[INDEX_ID_SPK] = &(main->speaker);
+ lb[INDEX_ID_LP] = &(main->lightprobe);
lb[INDEX_ID_WO] = &(main->world);
lb[INDEX_ID_MC] = &(main->movieclip);
@@ -1023,6 +1111,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[INDEX_ID_OB] = &(main->object);
lb[INDEX_ID_LS] = &(main->linestyle); /* referenced by scenes */
lb[INDEX_ID_SCE] = &(main->scene);
+ lb[INDEX_ID_WS] = &(main->workspaces); /* before wm, so it's freed after it! */
lb[INDEX_ID_WM] = &(main->wm);
lb[INDEX_ID_MSK] = &(main->mask);
@@ -1075,8 +1164,9 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
CASE_RETURN(ID_VF, VFont);
CASE_RETURN(ID_TXT, Text);
CASE_RETURN(ID_SPK, Speaker);
+ CASE_RETURN(ID_LP, LightProbe);
CASE_RETURN(ID_SO, bSound);
- CASE_RETURN(ID_GR, Group);
+ CASE_RETURN(ID_GR, Collection);
CASE_RETURN(ID_AR, bArmature);
CASE_RETURN(ID_AC, bAction);
CASE_RETURN(ID_NT, bNodeTree);
@@ -1090,6 +1180,7 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
CASE_RETURN(ID_PAL, Palette);
CASE_RETURN(ID_PC, PaintCurve);
CASE_RETURN(ID_CF, CacheFile);
+ CASE_RETURN(ID_WS, WorkSpace);
}
return 0;
#undef CASE_RETURN
@@ -1147,7 +1238,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
/* TODO to be removed from here! */
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) {
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
}
}
else {
@@ -1206,6 +1297,9 @@ void BKE_libblock_init_empty(ID *id)
case ID_SPK:
BKE_speaker_init((Speaker *)id);
break;
+ case ID_LP:
+ BKE_lightprobe_init((LightProbe *)id);
+ break;
case ID_CA:
BKE_camera_init((Camera *)id);
break;
@@ -1275,6 +1369,41 @@ void BKE_libblock_init_empty(ID *id)
}
}
+/** Generic helper to create a new empty datablock of given type in given \a bmain database.
+ *
+ * \param name can be NULL, in which case we get default name for this ID type. */
+void *BKE_id_new(Main *bmain, const short type, const char *name)
+{
+ BLI_assert(bmain != NULL);
+
+ if (name == NULL) {
+ name = DATA_(BKE_idcode_to_name(type));
+ }
+
+ ID *id = BKE_libblock_alloc(bmain, type, name, 0);
+ BKE_libblock_init_empty(id);
+
+ return id;
+}
+
+/** Generic helper to create a new temporary empty datablock of given type, *outside* of any Main database.
+ *
+ * \param name can be NULL, in which case we get default name for this ID type. */
+void *BKE_id_new_nomain(const short type, const char *name)
+{
+ if (name == NULL) {
+ name = DATA_(BKE_idcode_to_name(type));
+ }
+
+ ID *id = BKE_libblock_alloc(NULL, type, name,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG);
+ BKE_libblock_init_empty(id);
+
+ return id;
+}
+
/* by spec, animdata is first item after ID */
/* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */
static void id_copy_animdata(Main *bmain, ID *id, const bool do_action)
@@ -1283,7 +1412,7 @@ static void id_copy_animdata(Main *bmain, ID *id, const bool do_action)
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
- iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action); /* could be set to false, need to investigate */
+ iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action, true); /* could be set to false, need to investigate */
}
}
@@ -1299,6 +1428,8 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
+ /* Never implicitely copy shapekeys when generating temp data outside of Main database. */
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_COPY_SHAPEKEY) == 0);
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
/* r_newid already contains pointer to allocated memory. */
@@ -1326,12 +1457,27 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
}
+ /* XXX Again... We need a way to control what we copy in a much more refined way.
+ * We cannot always copy this, some internal copying will die on it! */
+ /* For now, upper level code will have to do that itself when required. */
+#if 0
+ if (id->override != NULL) {
+ BKE_override_copy(new_id, id);
+ }
+#endif
+
/* the duplicate should get a copy of the animdata */
- BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
- id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) {
+ BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ }
+ else if (id_can_have_animdata(new_id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)new_id;
+ iat->adt = NULL;
+ }
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- DAG_id_type_tag(bmain, GS(new_id->name));
+ DEG_id_type_tag(bmain, GS(new_id->name));
}
*r_newid = new_id;
@@ -1365,7 +1511,6 @@ void BKE_library_free(Library *lib)
Main *BKE_main_new(void)
{
Main *bmain = MEM_callocN(sizeof(Main), "new main");
- 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;
@@ -1440,7 +1585,6 @@ void BKE_main_free(Main *mainvar)
BLI_spin_end((SpinLock *)mainvar->lock);
MEM_freeN(mainvar->lock);
- DEG_evaluation_context_free(mainvar->eval_ctx);
MEM_freeN(mainvar);
}
@@ -2417,8 +2561,8 @@ void BKE_id_tag_clear_atomic(ID *id, int tag)
/** Check that given ID pointer actually is in G_MAIN.
* Main intended use is for debug asserts in places we cannot easily get rid of G_Main... */
-bool BKE_id_is_in_gobal_main(ID *id) {
+bool BKE_id_is_in_gobal_main(ID *id)
+{
/* We do not want to fail when id is NULL here, even though this is a bit strange behavior... */
return (id == NULL || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1);
}
-
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
new file mode 100644
index 00000000000..31e621b236f
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -0,0 +1,771 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Bastien Montagne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/library_override.c
+ * \ingroup bke
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_object_types.h"
+
+#include "DEG_depsgraph.h"
+#include "BKE_library.h"
+#include "BKE_library_override.h"
+#include "BKE_library_remap.h"
+#include "BKE_main.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "PIL_time.h"
+#include "PIL_time_utildefines.h"
+
+#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */
+
+static void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src);
+static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src);
+
+static void bke_override_property_clear(IDOverrideStaticProperty *op);
+static void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop);
+
+/** Initialize empty overriding of \a reference_id by \a local_id. */
+IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id)
+{
+ /* If reference_id is NULL, we are creating an override template for purely local data.
+ * Else, reference *must* be linked data. */
+ BLI_assert(reference_id == NULL || reference_id->lib != NULL);
+ BLI_assert(local_id->override_static == NULL);
+
+ ID *ancestor_id;
+ for (ancestor_id = reference_id;
+ ancestor_id != NULL && ancestor_id->override_static != NULL && ancestor_id->override_static->reference != NULL;
+ ancestor_id = ancestor_id->override_static->reference);
+
+ if (ancestor_id != NULL && ancestor_id->override_static != NULL) {
+ /* Original ID has a template, use it! */
+ BKE_override_static_copy(local_id, ancestor_id);
+ if (local_id->override_static->reference != reference_id) {
+ id_us_min(local_id->override_static->reference);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(local_id->override_static->reference);
+ }
+ return local_id->override_static;
+ }
+
+ /* Else, generate new empty override. */
+ local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(local_id->override_static->reference);
+ local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ /* TODO do we want to add tag or flag to referee to mark it as such? */
+ return local_id->override_static;
+}
+
+/** Deep copy of a whole override from \a src_id to \a dst_id. */
+void BKE_override_static_copy(ID *dst_id, const ID *src_id)
+{
+ BLI_assert(src_id->override_static != NULL);
+
+ if (dst_id->override_static != NULL) {
+ if (src_id->override_static == NULL) {
+ BKE_override_static_free(&dst_id->override_static);
+ return;
+ }
+ else {
+ BKE_override_static_clear(dst_id->override_static);
+ }
+ }
+ else if (src_id->override_static == NULL) {
+ return;
+ }
+ else {
+ BKE_override_static_init(dst_id, NULL);
+ }
+
+ /* Source is already overriding data, we copy it but reuse its reference for dest ID.
+ * otherwise, source is only an override template, it then becomes reference of dest ID. */
+ dst_id->override_static->reference = src_id->override_static->reference ? src_id->override_static->reference : (ID *)src_id;
+ id_us_plus(dst_id->override_static->reference);
+
+ BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties);
+ for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first, *op_src = src_id->override_static->properties.first;
+ op_dst;
+ op_dst = op_dst->next, op_src = op_src->next)
+ {
+ bke_override_property_copy(op_dst, op_src);
+ }
+
+ dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+}
+
+/** Clear any overriding data from given \a override. */
+void BKE_override_static_clear(IDOverrideStatic *override)
+{
+ BLI_assert(override != NULL);
+
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ bke_override_property_clear(op);
+ }
+ BLI_freelistN(&override->properties);
+
+ id_us_min(override->reference);
+ /* override->storage should never be refcounted... */
+}
+
+/** Free given \a override. */
+void BKE_override_static_free(struct IDOverrideStatic **override)
+{
+ BLI_assert(*override != NULL);
+
+ BKE_override_static_clear(*override);
+ MEM_freeN(*override);
+ *override = NULL;
+}
+
+static ID *override_static_create_from(Main *bmain, ID *reference_id)
+{
+ ID *local_id;
+
+ if (!id_copy(bmain, reference_id, (ID **)&local_id, false)) {
+ return NULL;
+ }
+ id_us_min(local_id);
+
+ BKE_override_static_init(local_id, reference_id);
+ local_id->override_static->flag |= STATICOVERRIDE_AUTO;
+
+ return local_id;
+}
+
+
+/** Create an overriden local copy of linked reference. */
+ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id)
+{
+ BLI_assert(reference_id != NULL);
+ BLI_assert(reference_id->lib != NULL);
+
+ ID *local_id = override_static_create_from(bmain, reference_id);
+
+ /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overriden ID). */
+ BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+
+ return local_id;
+}
+
+/** Create overriden local copies of all tagged data-blocks in given Main.
+ *
+ * \note Set id->newid of overridden libs with newly created overrides, caller is responsible to clean those pointers
+ * before/after usage as needed.
+ *
+ * \return \a true on success, \a false otherwise.
+ */
+bool BKE_override_static_create_from_tag(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+ bool ret = true;
+
+ const int num_types = a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) {
+ if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) {
+ ret = false;
+ }
+ }
+ }
+ }
+
+ /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overriden ID). */
+ a = num_types;
+ while (a--) {
+ for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && reference_id->newid != NULL) {
+ ID *local_id = reference_id->newid;
+ BKE_libblock_remap(bmain, reference_id, local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Find override property from given RNA path, if it exists.
+ */
+IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override, const char *rna_path)
+{
+ /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
+ return BLI_findstring_ptr(&override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path));
+}
+
+/**
+ * Find override property from given RNA path, or create it if it does not exist.
+ */
+IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override, const char *rna_path, bool *r_created)
+{
+ /* XXX TODO we'll most likely want a runtime ghash to store taht mapping at some point. */
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path);
+
+ if (op == NULL) {
+ op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__);
+ op->rna_path = BLI_strdup(rna_path);
+ BLI_addtail(&override->properties, op);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return op;
+}
+
+void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src)
+{
+ op_dst->rna_path = BLI_strdup(op_src->rna_path);
+ BLI_duplicatelist(&op_dst->operations, &op_src->operations);
+
+ for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first, *opop_src = op_src->operations.first;
+ opop_dst;
+ opop_dst = opop_dst->next, opop_src = opop_src->next)
+ {
+ bke_override_property_operation_copy(opop_dst, opop_src);
+ }
+}
+
+void bke_override_property_clear(IDOverrideStaticProperty *op)
+{
+ BLI_assert(op->rna_path != NULL);
+
+ MEM_freeN(op->rna_path);
+
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ bke_override_property_operation_clear(opop);
+ }
+ BLI_freelistN(&op->operations);
+}
+
+/**
+ * Remove and free given \a override_property from given ID \a override.
+ */
+void BKE_override_static_property_delete(IDOverrideStatic *override, IDOverrideStaticProperty *override_property)
+{
+ bke_override_property_clear(override_property);
+ BLI_freelinkN(&override->properties, override_property);
+}
+
+/**
+ * Find override property operation from given sub-item(s), if it exists.
+ */
+IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find(
+ IDOverrideStaticProperty *override_property,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict)
+{
+ IDOverrideStaticPropertyOperation *opop;
+ const int subitem_defindex = -1;
+
+ if (r_strict) {
+ *r_strict = true;
+ }
+
+ if (subitem_locname != NULL) {
+ opop = BLI_findstring_ptr(&override_property->operations, subitem_locname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_name));
+
+ if (opop == NULL) {
+ return NULL;
+ }
+
+ if (subitem_refname == NULL || opop->subitem_reference_name == NULL) {
+ return subitem_refname == opop->subitem_reference_name ? opop : NULL;
+ }
+ return (subitem_refname != NULL && opop->subitem_reference_name != NULL &&
+ STREQ(subitem_refname, opop->subitem_reference_name)) ? opop : NULL;
+ }
+
+ if (subitem_refname != NULL) {
+ opop = BLI_findstring_ptr(&override_property->operations, subitem_refname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name));
+
+ if (opop == NULL) {
+ return NULL;
+ }
+
+ if (subitem_locname == NULL || opop->subitem_local_name == NULL) {
+ return subitem_locname == opop->subitem_local_name ? opop : NULL;
+ }
+ return (subitem_locname != NULL && opop->subitem_local_name != NULL &&
+ STREQ(subitem_locname, opop->subitem_local_name)) ? opop : NULL;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_locindex, sizeof(subitem_locindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
+ {
+ return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_refindex, sizeof(subitem_refindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index))))
+ {
+ return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL;
+ }
+
+ /* index == -1 means all indices, that is valid fallback in case we requested specific index. */
+ if (!strict && (subitem_locindex != subitem_defindex) &&
+ (opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_defindex, sizeof(subitem_defindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
+ {
+ if (r_strict) {
+ *r_strict = false;
+ }
+ return opop;
+ }
+
+ return NULL;
+}
+
+/**
+ * Find override property operation from given sub-item(s), or create it if it does not exist.
+ */
+IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get(
+ IDOverrideStaticProperty *override_property, const short operation,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex,
+ const bool strict, bool *r_strict, bool *r_created)
+{
+ IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(override_property,
+ subitem_refname, subitem_locname,
+ subitem_refindex, subitem_locindex,
+ strict, r_strict);
+
+ if (opop == NULL) {
+ opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__);
+ opop->operation = operation;
+ if (subitem_locname) {
+ opop->subitem_local_name = BLI_strdup(subitem_locname);
+ }
+ if (subitem_refname) {
+ opop->subitem_reference_name = BLI_strdup(subitem_refname);
+ }
+ opop->subitem_local_index = subitem_locindex;
+ opop->subitem_reference_index = subitem_refindex;
+
+ BLI_addtail(&override_property->operations, opop);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return opop;
+}
+
+void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src)
+{
+ if (opop_src->subitem_reference_name) {
+ opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name);
+ }
+ if (opop_src->subitem_local_name) {
+ opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name);
+ }
+}
+
+void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop)
+{
+ if (opop->subitem_reference_name) {
+ MEM_freeN(opop->subitem_reference_name);
+ }
+ if (opop->subitem_local_name) {
+ MEM_freeN(opop->subitem_local_name);
+ }
+}
+
+/**
+ * Remove and free given \a override_property_operation from given ID \a override_property.
+ */
+void BKE_override_static_property_operation_delete(
+ IDOverrideStaticProperty *override_property, IDOverrideStaticPropertyOperation *override_property_operation)
+{
+ bke_override_property_operation_clear(override_property_operation);
+ BLI_freelinkN(&override_property->operations, override_property_operation);
+}
+
+/**
+ * Check that status of local data-block is still valid against current reference one.
+ *
+ * It means that all overridable, but not overridden, properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some property has been changed in local and a new IDOverrideProperty
+ * (of IDOverridePropertyOperation) has to be added.
+ *
+ * \return true if status is OK, false otherwise. */
+bool BKE_override_static_status_check_local(ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ ID *reference = local->override_static->reference;
+
+ if (reference == NULL) {
+ /* This is an override template, local status is always OK! */
+ return true;
+ }
+
+ BLI_assert(GS(local->name) == GS(reference->name));
+
+ /* Note that reference is assumed always valid, caller has to ensure that itself. */
+
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
+
+ if (!RNA_struct_override_matches(
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
+ {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Check that status of reference data-block is still valid against current local one.
+ *
+ * It means that all non-overridden properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some reference has changed and local needs to be updated against it.
+ *
+ * \return true if status is OK, false otherwise. */
+bool BKE_override_static_status_check_reference(ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ ID *reference = local->override_static->reference;
+
+ if (reference == NULL) {
+ /* This is an override template, reference is virtual, so its status is always OK! */
+ return true;
+ }
+
+ BLI_assert(GS(local->name) == GS(reference->name));
+
+ if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
+ if (!BKE_override_static_status_check_reference(reference)) {
+ /* If reference is also override of another data-block, and its status is not OK,
+ * then this override is not OK either.
+ * Note that this should only happen when reloading libraries... */
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+ }
+
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
+
+ if (!RNA_struct_override_matches(
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
+ {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Compares local and reference data-blocks and create new override operations as needed,
+ * or reset to reference values if overriding is not allowed.
+ *
+ * \note Defining override operations is only mandatory before saving a .blend file on disk (not for undo!).
+ * Knowing that info at runtime is only useful for UI/UX feedback.
+ *
+ * \note This is by far the biggest operation (the more time-consuming) of the three so far, since it has to go over
+ * all properties in depth (all overridable ones at least). Generating diff values and applying overrides
+ * are much cheaper.
+ *
+ * \return true if new overriding op was created, or some local data was reset. */
+bool BKE_override_static_operations_create(ID *local, const bool force_auto)
+{
+ BLI_assert(local->override_static != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
+ bool ret = false;
+
+ if (!is_template && (force_auto || local->override_static->flag & STATICOVERRIDE_AUTO)) {
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+
+ eRNAOverrideMatchResult report_flags = 0;
+ RNA_struct_override_matches(
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags);
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
+ ret = true;
+ }
+#ifndef NDEBUG
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
+ printf("We did restore some properties of %s from its reference.\n", local->name);
+ }
+ if (ret) {
+ printf("We did generate static override rules for %s\n", local->name);
+ }
+ else {
+ printf("No new static override rules for %s\n", local->name);
+ }
+#endif
+ }
+ return ret;
+}
+
+/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
+void BKE_main_override_static_operations_create(Main *bmain, const bool force_auto)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (force_auto ||
+ (ID_IS_STATIC_OVERRIDE_AUTO(id) && (id->tag & LIB_TAG_OVERRIDESTATIC_AUTOREFRESH)))
+ {
+ BKE_override_static_operations_create(id, force_auto);
+ id->tag &= ~LIB_TAG_OVERRIDESTATIC_AUTOREFRESH;
+ }
+ }
+ }
+}
+
+/** Update given override from its reference (re-applying overriden properties). */
+void BKE_override_static_update(Main *bmain, ID *local)
+{
+ if (local->override_static == NULL || local->override_static->reference == NULL) {
+ return;
+ }
+
+ /* Recursively do 'ancestors' overrides first, if any. */
+ if (local->override_static->reference->override_static && (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
+ BKE_override_static_update(bmain, local->override_static->reference);
+ }
+
+ /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based
+ * on reference than on current override.
+ * So we work on temp copy of reference, and 'swap' its content with local. */
+
+ /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)!
+ * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do,
+ * as innefficient as it is. :/
+ * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep
+ * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data
+ * also remain correct). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first if extra useless usual user handling is actually
+ * a (performances) issue here. */
+
+ ID *tmp_id;
+ id_copy(bmain, local->override_static->reference, &tmp_id, false);
+
+ if (tmp_id == NULL) {
+ return;
+ }
+
+ PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL;
+ RNA_id_pointer_create(local, &rnaptr_src);
+ RNA_id_pointer_create(tmp_id, &rnaptr_dst);
+ if (local->override_static->storage) {
+ rnaptr_storage = &rnaptr_storage_stack;
+ RNA_id_pointer_create(local->override_static->storage, rnaptr_storage);
+ }
+
+ RNA_struct_override_apply(&rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
+
+ /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id,
+ * we'll actually free old, outdated data from local. */
+ BKE_id_swap(bmain, local, tmp_id);
+
+ /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */
+ /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */
+ BKE_libblock_free_ex(bmain, tmp_id, true, false);
+
+ if (local->override_static->storage) {
+ /* We know this datablock is not used anywhere besides local->override->storage. */
+ /* XXX For until we get fully shadow copies, we still need to ensure storage releases
+ * its usage of any ID pointers it may have. */
+ BKE_libblock_free_ex(bmain, local->override_static->storage, true, false);
+ local->override_static->storage = NULL;
+ }
+
+ local->tag |= LIB_TAG_OVERRIDESTATIC_REFOK;
+
+ /* Full rebuild of Depsgraph! */
+ DEG_on_visible_update(bmain, true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */
+}
+
+/** Update all overrides from given \a bmain. */
+void BKE_main_override_static_update(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (id->override_static != NULL && id->lib == NULL) {
+ BKE_override_static_update(bmain, id);
+ }
+ }
+ }
+}
+
+/***********************************************************************************************************************
+ * Storage (how to wtore overriding data into .blend files).
+ *
+ * Basically:
+ * I) Only 'differential' storage needs special handling here. All others (replacing values or
+ * inserting/removing items from a collection) can be handled with simply storing current content of local data-block.
+ * II) We store the differential value into a second 'ghost' data-block, which is an empty ID of same type as local one,
+ * where we only define values that need differential data.
+ *
+ * This avoids us having to modify 'real' data-block at write time (and retoring it afterwards), which is inneficient,
+ * and potentially dangerous (in case of concurrent access...), while not using much extra memory in typical cases.
+ * It also ensures stored data-block always contains exact same data as "desired" ones (kind of "baked" data-blocks).
+ */
+
+/** Initialize an override storage. */
+OverrideStaticStorage *BKE_override_static_operations_store_initialize(void)
+{
+ return BKE_main_new();
+}
+
+/**
+ * Generate suitable 'write' data (this only affects differential override operations).
+ *
+ * Note that \a local ID is no more modified by this call, all extra data are stored in its temp \a storage_id copy. */
+ID *BKE_override_static_operations_store_start(OverrideStaticStorage *override_storage, ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+ BLI_assert(override_storage != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
+
+ if (is_template) {
+ /* This is actually purely local data with an override template, nothing to do here! */
+ return NULL;
+ }
+
+ /* Forcefully ensure we know about all needed override operations. */
+ BKE_override_static_operations_create(local, false);
+
+ ID *storage_id;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(BKE_override_operations_store_start);
+#endif
+
+ /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable
+ * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first is extra useless usual user handling is actually
+ * a (performances) issue here, before doing it. */
+ id_copy((Main *)override_storage, local, &storage_id, false);
+
+ if (storage_id != NULL) {
+ PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage;
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+ RNA_id_pointer_create(local, &rnaptr_final);
+ RNA_id_pointer_create(storage_id, &rnaptr_storage);
+
+ if (!RNA_struct_override_store(&rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) {
+ BKE_libblock_free_ex(override_storage, storage_id, true, false);
+ storage_id = NULL;
+ }
+ }
+
+ local->override_static->storage = storage_id;
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(BKE_override_operations_store_start);
+#endif
+ return storage_id;
+}
+
+/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */
+void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage), ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until
+ * whole file is written anyway (otherwise we'd get mem pointers overlap...). */
+ local->override_static->storage = NULL;
+}
+
+void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage)
+{
+ /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs
+ * without increasing usercount of used data-blocks... */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(override_storage, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ while ((id = lb->first)) {
+ BKE_libblock_free_ex(override_storage, id, true, false);
+ }
+ }
+
+ BKE_main_free(override_storage);
+}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index d59658a2a07..f23d8720a65 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -31,13 +31,11 @@
#include "MEM_guardedalloc.h"
-#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
-#include "DNA_controller_types.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
@@ -52,15 +50,17 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_force_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "DNA_sensor_types.h"
#include "DNA_sequence_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
#include "DNA_sound_types.h"
#include "DNA_text_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "BLI_utildefines.h"
@@ -69,6 +69,7 @@
#include "BLI_linklist_stack.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
#include "BKE_idprop.h"
@@ -79,9 +80,9 @@
#include "BKE_node.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
-#include "BKE_sca.h"
#include "BKE_sequencer.h"
#include "BKE_tracking.h"
+#include "BKE_workspace.h"
#define FOREACH_FINALIZE _finalize
@@ -213,33 +214,6 @@ static void library_foreach_particlesystemsObjectLooper(
FOREACH_FINALIZE_VOID;
}
-static void library_foreach_sensorsObjectLooper(
- bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_controllersObjectLooper(
- bController *UNUSED(controller), ID **id_pointer, void *user_data, int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_actuatorsObjectLooper(
- bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip)
{
NlaStrip *substrip;
@@ -312,6 +286,16 @@ static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
+{
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ FOREACH_CALLBACK_INVOKE(data, lc->collection, IDWALK_CB_NOP);
+ library_foreach_layer_collection(data, &lc->layer_collections);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_ID_as_subdata_link(
ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
{
@@ -384,6 +368,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
continue;
}
+ if (id->override_static != NULL) {
+ CALLBACK_INVOKE_ID(id->override_static->reference, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
+ CALLBACK_INVOKE_ID(id->override_static->storage, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
+ }
+
library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
AnimData *adt = BKE_animdata_from_id(id);
@@ -402,8 +391,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
{
Scene *scene = (Scene *) id;
ToolSettings *toolsett = scene->toolsettings;
- SceneRenderLayer *srl;
- Base *base;
CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
@@ -413,35 +400,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&scene->nodetree, callback, user_data, flag, &data);
}
- /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later,
- * since basact is just a pointer to one of those items. */
- CALLBACK_INVOKE(scene->obedit, IDWALK_CB_NOP);
-
- for (srl = scene->r.layers.first; srl; srl = srl->next) {
- FreestyleModuleConfig *fmc;
- FreestyleLineSet *fls;
-
- if (srl->mat_override) {
- CALLBACK_INVOKE(srl->mat_override, IDWALK_CB_USER);
- }
- if (srl->light_override) {
- CALLBACK_INVOKE(srl->light_override, IDWALK_CB_USER);
- }
- for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
- if (fmc->script) {
- CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
- }
- }
- for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
- if (fls->group) {
- CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
- }
- if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
- }
- }
- }
-
if (scene->ed) {
Sequence *seq;
SEQP_BEGIN(scene->ed, seq)
@@ -461,8 +419,36 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
- for (base = scene->base.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_CB_USER);
+ for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) {
+ CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
+ }
+ for (CollectionChild *child = scene->master_collection->children.first; child; child = child->next) {
+ CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
+ }
+
+ ViewLayer *view_layer;
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ CALLBACK_INVOKE(base->object, IDWALK_CB_NOP);
+ }
+
+ library_foreach_layer_collection(&data, &view_layer->layer_collections);
+
+ for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
+ if (fmc->script) {
+ CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
+ }
+ }
+
+ for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
+ if (fls->group) {
+ CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
+ }
+
+ if (fls->linestyle) {
+ CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
+ }
+ }
}
for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
@@ -470,8 +456,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
if (toolsett) {
- CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_CB_NOP);
-
CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP);
CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP);
CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP);
@@ -500,8 +484,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
}
- CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_CB_NOP);
-
break;
}
@@ -599,10 +581,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
}
}
-
- BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data);
- BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data);
- BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data);
break;
}
@@ -624,31 +602,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
for (i = 0; i < mesh->totcol; i++) {
CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
}
-
- /* XXX Really not happy with this - probably texface should rather use some kind of
- * 'texture slots' and just set indices in each poly/face item - would also save some memory.
- * Maybe a nice TODO for blender2.8? */
- if (mesh->mtface || mesh->mtpoly) {
- for (i = 0; i < mesh->pdata.totlayer; i++) {
- if (mesh->pdata.layers[i].type == CD_MTEXPOLY) {
- MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data;
-
- for (int j = 0; j < mesh->totpoly; j++, txface++) {
- CALLBACK_INVOKE(txface->tpage, IDWALK_CB_USER_ONE);
- }
- }
- }
-
- for (i = 0; i < mesh->fdata.totlayer; i++) {
- if (mesh->fdata.layers[i].type == CD_MTFACE) {
- MTFace *tface = (MTFace *)mesh->fdata.layers[i].data;
-
- for (int j = 0; j < mesh->totface; j++, tface++) {
- CALLBACK_INVOKE(tface->tpage, IDWALK_CB_USER_ONE);
- }
- }
- }
- }
break;
}
@@ -681,16 +634,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_MA:
{
Material *material = (Material *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (material->mtex[i]) {
- library_foreach_mtex(&data, material->mtex[i]);
- }
- }
if (material->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data);
}
- CALLBACK_INVOKE(material->group, IDWALK_CB_USER);
if (material->texpaintslot != NULL) {
CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
}
@@ -705,16 +652,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, callback, user_data, flag, &data);
}
CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
- if (texture->env) {
- CALLBACK_INVOKE(texture->env->object, IDWALK_CB_NOP);
- CALLBACK_INVOKE(texture->env->ima, IDWALK_CB_USER);
- }
- if (texture->pd)
- CALLBACK_INVOKE(texture->pd->object, IDWALK_CB_NOP);
- if (texture->vd)
- CALLBACK_INVOKE(texture->vd->object, IDWALK_CB_NOP);
- if (texture->ot)
- CALLBACK_INVOKE(texture->ot->object, IDWALK_CB_NOP);
break;
}
@@ -728,11 +665,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_LA:
{
Lamp *lamp = (Lamp *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (lamp->mtex[i]) {
- library_foreach_mtex(&data, lamp->mtex[i]);
- }
- }
if (lamp->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, callback, user_data, flag, &data);
@@ -754,21 +686,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
break;
}
- case ID_SCR:
- {
- bScreen *screen = (bScreen *) id;
- CALLBACK_INVOKE(screen->scene, IDWALK_CB_USER_ONE);
- break;
- }
-
case ID_WO:
{
World *world = (World *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (world->mtex[i]) {
- library_foreach_mtex(&data, world->mtex[i]);
- }
- }
if (world->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&world->nodetree, callback, user_data, flag, &data);
@@ -783,12 +703,22 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
break;
}
+ case ID_LP:
+ {
+ LightProbe *probe = (LightProbe *) id;
+ CALLBACK_INVOKE(probe->image, IDWALK_CB_USER);
+ CALLBACK_INVOKE(probe->visibility_grp, IDWALK_CB_NOP);
+ break;
+ }
+
case ID_GR:
{
- Group *group = (Group *) id;
- GroupObject *gob;
- for (gob = group->gobject.first; gob; gob = gob->next) {
- CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE);
+ Collection *collection = (Collection *) id;
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
+ }
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
}
break;
}
@@ -971,6 +901,43 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
break;
}
+
+ case ID_WM:
+ {
+ wmWindowManager *wm = (wmWindowManager *)id;
+
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
+
+ CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE);
+
+ CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP);
+ /* allow callback to set a different workspace */
+ BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
+ }
+ break;
+ }
+
+ case ID_WS:
+ {
+ WorkSpace *workspace = (WorkSpace *)id;
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer.
+ * However we can't acess layout->screen here since we are outside the workspace project. */
+ CALLBACK_INVOKE(screen, IDWALK_CB_NOP);
+ /* allow callback to set a different screen */
+ BKE_workspace_layout_screen_set(layout, screen);
+ }
+
+ for (WorkSpaceSceneRelation *relation = workspace->scene_layer_relations.first; relation; relation = relation->next) {
+ CALLBACK_INVOKE(relation->scene, IDWALK_CB_NOP);
+ }
+ break;
+ }
case ID_GD:
{
bGPdata *gpencil = (bGPdata *) id;
@@ -982,11 +949,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
/* Nothing needed for those... */
+ case ID_SCR:
case ID_IM:
case ID_VF:
case ID_TXT:
case ID_SO:
- case ID_WM:
case ID_PAL:
case ID_PC:
case ID_CF:
@@ -1067,7 +1034,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
#if 0
return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA, /* obdata */
ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_PA, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC
- /* + constraints, modifiers and game logic ID types... */);
+ /* + constraints and modifiers ... */);
#else
return true;
#endif
@@ -1096,7 +1063,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_SPK:
return ELEM(id_type_used, ID_SO);
case ID_GR:
- return ELEM(id_type_used, ID_OB);
+ return ELEM(id_type_used, ID_OB, ID_GR);
case ID_NT:
/* Could be the following, but node.id has no type restriction... */
#if 0
@@ -1114,6 +1081,10 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
case ID_LS:
return (ELEM(id_type_used, ID_TE, ID_OB));
+ case ID_LP:
+ return ELEM(id_type_used, ID_IM);
+ case ID_WS:
+ return ELEM(id_type_used, ID_SCR, ID_SCE);
case ID_IM:
case ID_VF:
case ID_TXT:
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 2819b0312aa..f34a2ff7f84 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -53,6 +53,7 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -60,6 +61,7 @@
#include "DNA_text_types.h"
#include "DNA_vfont_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "BLI_blenlib.h"
@@ -71,11 +73,10 @@
#include "BKE_brush.h"
#include "BKE_camera.h"
#include "BKE_cachefile.h"
+#include "BKE_collection.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_font.h"
-#include "BKE_group.h"
#include "BKE_gpencil.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
@@ -83,7 +84,9 @@
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -99,15 +102,19 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
-#include "BKE_sca.h"
+#include "BKE_lightprobe.h"
#include "BKE_speaker.h"
#include "BKE_sound.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
#include "BKE_text.h"
#include "BKE_texture.h"
+#include "BKE_workspace.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
@@ -173,6 +180,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
if (*id_p && (*id_p == old_id)) {
+ const bool is_reference = (cb_flag & IDWALK_CB_STATIC_OVERRIDE_REFERENCE) != 0;
const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
@@ -183,11 +191,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
(id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
+ const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_STATIC_OVERRIDE) != 0;
const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
#ifdef DEBUG_PRINT
- printf("In %s: Remapping %s (%p) to %s (%p) (is_indirect: %d, skip_indirect: %d)\n",
- id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, is_indirect, skip_indirect);
+ printf("In %s (lib %p): Remapping %s (%p) to %s (%p) "
+ "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
+ id->name, id->lib, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id,
+ is_indirect, skip_indirect, is_reference, skip_reference);
#endif
if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
@@ -199,7 +210,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
* (skipped_indirect too). */
if ((is_never_null && skip_never_null) ||
(is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) ||
- (skip_indirect && is_indirect))
+ (skip_indirect && is_indirect) ||
+ (is_reference && skip_reference))
{
if (is_indirect) {
id_remap_data->skipped_indirect++;
@@ -212,7 +224,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
}
}
- else if (is_never_null || is_obj_editmode) {
+ else if (is_never_null || is_obj_editmode || is_reference) {
id_remap_data->skipped_direct++;
}
else {
@@ -229,7 +241,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
else {
if (!is_never_null) {
*id_p = new_id;
- DAG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update_ex(id_remap_data->bmain, id_self, DEG_TAG_TRANSFORM | DEG_TAG_TIME | DEG_TAG_GEOMETRY);
}
if (cb_flag & IDWALK_CB_USER) {
id_us_min(old_id);
@@ -252,23 +264,43 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */
-static void libblock_remap_data_preprocess_scene_base_unlink(
- IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect)
+static void libblock_remap_data_preprocess_scene_object_unlink(
+ IDRemap *r_id_remap_data, Scene *sce, Object *ob, const bool skip_indirect, const bool is_indirect)
{
if (skip_indirect && is_indirect) {
r_id_remap_data->skipped_indirect++;
r_id_remap_data->skipped_refcounted++;
}
else {
- id_us_min((ID *)base->object);
- BKE_scene_base_unlink(sce, base);
- MEM_freeN(base);
+ /* Remove object from all collections in the scene. free_use is false
+ * to avoid recursively calling object free again. */
+ BKE_scene_collections_object_remove(r_id_remap_data->bmain, sce, ob, false);
if (!is_indirect) {
r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
}
}
}
+static void libblock_remap_data_preprocess_collection_unlink(
+ IDRemap *r_id_remap_data, Object *ob, const bool skip_indirect, const bool is_indirect)
+{
+ Main *bmain = r_id_remap_data->bmain;
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ if (!BKE_collection_is_in_scene(collection) && BKE_collection_has_object(collection, ob)) {
+ if (skip_indirect && is_indirect) {
+ r_id_remap_data->skipped_indirect++;
+ r_id_remap_data->skipped_refcounted++;
+ }
+ else {
+ BKE_collection_object_remove(bmain, collection, ob, false);
+ if (!is_indirect) {
+ r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+ }
+ }
+}
+
static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
{
switch (GS(r_id_remap_data->id->name)) {
@@ -282,24 +314,27 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
/* In case we are unlinking... */
if (!r_id_remap_data->old_id) {
+ /* TODO: how is it valid to iterator over a scene while
+ * removing objects from it? can't this crash? */
/* ... everything from scene. */
- Base *base, *base_next;
- for (base = sce->base.first; base; base = base_next) {
- base_next = base->next;
- libblock_remap_data_preprocess_scene_base_unlink(
- r_id_remap_data, sce, base, skip_indirect, is_indirect);
+ FOREACH_SCENE_OBJECT_BEGIN(sce, ob_iter)
+ {
+ libblock_remap_data_preprocess_scene_object_unlink(
+ r_id_remap_data, sce, ob_iter, skip_indirect, is_indirect);
+ libblock_remap_data_preprocess_collection_unlink(
+ r_id_remap_data, ob_iter, skip_indirect, is_indirect);
}
+ FOREACH_SCENE_OBJECT_END;
}
else if (GS(r_id_remap_data->old_id->name) == ID_OB) {
/* ... a specific object from scene. */
Object *old_ob = (Object *)r_id_remap_data->old_id;
- Base *base = BKE_scene_base_find(sce, old_ob);
-
- if (base) {
- libblock_remap_data_preprocess_scene_base_unlink(
- r_id_remap_data, sce, base, skip_indirect, is_indirect);
- }
+ libblock_remap_data_preprocess_scene_object_unlink(
+ r_id_remap_data, sce, old_ob, skip_indirect, is_indirect);
+ libblock_remap_data_preprocess_collection_unlink(
+ r_id_remap_data, old_ob, skip_indirect, is_indirect);
}
+
}
break;
}
@@ -330,55 +365,35 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *new_ob)
{
- if (old_ob->flag & OB_FROMGROUP) {
- /* Note that for Scene's BaseObject->flag, either we:
- * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
- * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is.
- * So in any case, no need to update them here. */
- if (BKE_group_object_find(bmain, NULL, old_ob) == NULL) {
- old_ob->flag &= ~OB_FROMGROUP;
- }
- if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */
- for (Group *group = bmain->group.first; group; group = group->id.next) {
- BKE_group_object_unlink(bmain, group, NULL, NULL, NULL);
- }
- }
- else {
- new_ob->flag |= OB_FROMGROUP;
- }
+ if (new_ob == NULL) {
+ /* In case we unlinked old_ob (new_ob is NULL), the object has already
+ * been removed from the scenes and their collections. We still have
+ * to remove the NULL children from collections not used in any scene. */
+ BKE_collections_object_remove_nulls(bmain);
}
+ else {
+ BKE_main_collection_sync_remap(bmain);
+ }
+
if (old_ob->type == OB_MBALL) {
for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
}
}
-static void libblock_remap_data_postprocess_group_scene_unlink(Main *bmain, Scene *sce, ID *old_id)
+static void libblock_remap_data_postprocess_collection_update(Main *bmain, Collection *old_collection, Collection *new_collection)
{
- /* Note that here we assume no object has no base (i.e. all objects are assumed instanced
- * in one scene...). */
- for (Base *base = sce->base.first; base; base = base->next) {
- if (base->flag & OB_FROMGROUP) {
- Object *ob = base->object;
-
- if (ob->flag & OB_FROMGROUP) {
- Group *grp = BKE_group_object_find(bmain, NULL, ob);
-
- /* Unlinked group (old_id) is still in bmain... */
- if (grp && (&grp->id == old_id || grp->id.us == 0)) {
- grp = BKE_group_object_find(bmain, grp, ob);
- }
- if (!grp) {
- ob->flag &= ~OB_FROMGROUP;
- }
- }
- if (!(ob->flag & OB_FROMGROUP)) {
- base->flag &= ~OB_FROMGROUP;
- }
- }
+ if (new_collection == NULL) {
+ /* In case we unlinked old_collection (new_collection is NULL), we need
+ * to remove any collection children that have been set to NULL in the
+ * because of pointer replacement. */
+ BKE_collections_child_remove_nulls(bmain, old_collection);
+ }
+ else {
+ BKE_main_collection_sync_remap(bmain);
}
}
@@ -480,10 +495,6 @@ ATTR_NONNULL(1) static void libblock_remap_data(
}
}
- if (old_id && GS(old_id->name) == ID_OB) {
- BKE_sca_logic_links_remap(bmain, (Object *)old_id, (Object *)new_id);
- }
-
/* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
* though, we can always add an option (flag) to control this later if needed. */
if (old_id && (old_id->flag & LIB_FAKEUSER)) {
@@ -567,11 +578,7 @@ void BKE_libblock_remap_locked(
libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
break;
case ID_GR:
- if (!new_id) { /* Only affects us in case group was unlinked. */
- for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
- libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
- }
- }
+ libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id);
break;
case ID_ME:
case ID_CU:
@@ -594,8 +601,8 @@ void BKE_libblock_remap_locked(
libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
BKE_main_lock(bmain);
- /* Full rebuild of DAG! */
- DAG_relations_tag_update(bmain);
+ /* Full rebuild of DEG! */
+ DEG_relations_tag_update(bmain);
}
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
@@ -668,8 +675,6 @@ void BKE_libblock_relink_ex(
switch (GS(id->name)) {
case ID_SCE:
{
- Scene *sce = (Scene *)id;
-
if (old_id) {
switch (GS(old_id->name)) {
case ID_OB:
@@ -678,21 +683,19 @@ void BKE_libblock_relink_ex(
break;
}
case ID_GR:
- if (!new_id) { /* Only affects us in case group was unlinked. */
- libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
- }
+ libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id);
break;
default:
break;
}
}
else {
- /* No choice but to check whole objects/groups. */
+ /* No choice but to check whole objects/collections. */
for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
libblock_remap_data_postprocess_object_update(bmain, ob, NULL);
}
- for (Group *grp = bmain->group.first; grp; grp = grp->id.next) {
- libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL);
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ libblock_remap_data_postprocess_collection_update(bmain, collection, NULL);
}
}
break;
@@ -747,6 +750,10 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user)
MEM_freeN(id->properties);
}
+ if (id->override_static) {
+ BKE_override_static_free(&id->override_static);
+ }
+
/* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */
}
@@ -755,7 +762,7 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
const short type = GS(id->name);
switch (type) {
case ID_SCE:
- BKE_scene_free((Scene *)id);
+ BKE_scene_free_ex((Scene *)id, false);
break;
case ID_LI:
BKE_library_free((Library *)id);
@@ -811,11 +818,14 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
case ID_SPK:
BKE_speaker_free((Speaker *)id);
break;
+ case ID_LP:
+ BKE_lightprobe_free((LightProbe *)id);
+ break;
case ID_SO:
BKE_sound_free((bSound *)id);
break;
case ID_GR:
- BKE_group_free((Group *)id);
+ BKE_collection_free((Collection *)id);
break;
case ID_AR:
BKE_armature_free((bArmature *)id);
@@ -857,6 +867,9 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
case ID_CF:
BKE_cachefile_free((CacheFile *)id);
break;
+ case ID_WS:
+ BKE_workspace_free((WorkSpace *)id);
+ break;
}
}
@@ -867,7 +880,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
if (use_flag_from_idtag) {
if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
- flag |= LIB_ID_FREE_NO_MAIN;
+ flag |= LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_UI_USER | LIB_ID_FREE_NO_DEG_TAG;
}
else {
flag &= ~LIB_ID_FREE_NO_MAIN;
@@ -895,7 +908,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
const short type = GS(id->name);
if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) {
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
}
#ifdef WITH_PYTHON
@@ -958,7 +971,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b
short type = GS(id->name);
ListBase *lb = which_libbase(bmain, type);
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
#ifdef WITH_PYTHON
#ifdef WITH_PYTHON_SAFETY
@@ -1007,8 +1020,8 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
id_us_min(id);
- /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
- * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
+ /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding collections when deleting an object.
+ * Since only 'user_one' usage of objects is collections, and only 'real user' usage of objects is scenes,
* removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
* fully unlinked.
* But only for local objects, not linked ones!
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
new file mode 100644
index 00000000000..057b6aaaf65
--- /dev/null
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -0,0 +1,101 @@
+/*
+ * ***** 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) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/lightprobe.c
+ * \ingroup bke
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_animsys.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_lightprobe.h"
+
+void BKE_lightprobe_init(LightProbe *probe)
+{
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(probe, id));
+
+ probe->grid_resolution_x = probe->grid_resolution_y = probe->grid_resolution_z = 4;
+ probe->distinf = 2.5f;
+ probe->distpar = 2.5f;
+ probe->falloff = 0.2f;
+ probe->clipsta = 0.8f;
+ probe->clipend = 40.0f;
+ probe->vis_bias = 1.0f;
+ probe->vis_blur = 0.2f;
+ probe->intensity = 1.0f;
+ probe->data_draw_size = 1.0f;
+
+ probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA;
+}
+
+void *BKE_lightprobe_add(Main *bmain, const char *name)
+{
+ LightProbe *probe;
+
+ probe = BKE_libblock_alloc(bmain, ID_LP, name, 0);
+
+ BKE_lightprobe_init(probe);
+
+ return probe;
+}
+
+/**
+ * Only copy internal data of LightProbe ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_lightprobe_copy_data(
+ Main *UNUSED(bmain), LightProbe *UNUSED(probe_dst), const LightProbe *UNUSED(probe_src), const int UNUSED(flag))
+{
+ /* Nothing to do here. */
+}
+
+LightProbe *BKE_lightprobe_copy(Main *bmain, const LightProbe *probe)
+{
+ LightProbe *probe_copy;
+ BKE_id_copy_ex(bmain, &probe->id, (ID **)&probe_copy, 0, false);
+ return probe_copy;
+}
+
+void BKE_lightprobe_make_local(Main *bmain, LightProbe *probe, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &probe->id, true, lib_local);
+}
+
+void BKE_lightprobe_free(LightProbe *probe)
+{
+ BKE_animdata_free((ID *)probe, false);
+}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index e00884c8a9d..5757ae7480b 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -212,20 +212,11 @@ void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle,
BKE_id_make_local_generic(bmain, &linestyle->id, true, lib_local);
}
-FreestyleLineStyle *BKE_linestyle_active_from_scene(Scene *scene)
+FreestyleLineStyle *BKE_linestyle_active_from_view_layer(ViewLayer *view_layer)
{
- SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- if (!actsrl) {
- return NULL;
- }
-
- FreestyleConfig *config = &actsrl->freestyleConfig;
+ FreestyleConfig *config = &view_layer->freestyle_config;
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
-
- if (lineset) {
- return lineset->linestyle;
- }
- return NULL;
+ return (lineset) ? lineset->linestyle : NULL;
}
static LineStyleModifier *new_modifier(const char *name, int type, size_t size)
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index b5742dbdbb7..ba5a6a25048 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -51,7 +51,7 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
+
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mask.h"
@@ -61,6 +61,8 @@
#include "BKE_movieclip.h"
#include "BKE_image.h"
+#include "DEG_depsgraph_build.h"
+
static struct {
ListBase splines;
struct GHash *id_hash;
@@ -817,7 +819,7 @@ Mask *BKE_mask_new(Main *bmain, const char *name)
mask->sfra = 1;
mask->efra = 100;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
return mask;
}
@@ -1457,18 +1459,6 @@ void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const bool do_newfram
}
}
-void BKE_mask_update_scene(Main *bmain, Scene *scene)
-{
- Mask *mask;
-
- for (mask = bmain->mask.first; mask; mask = mask->id.next) {
- if (mask->id.recalc & ID_RECALC_ALL) {
- bool do_new_frame = (mask->id.recalc & ID_RECALC_DATA) != 0;
- BKE_mask_evaluate_all_masks(bmain, CFRA, do_new_frame);
- }
- }
-}
-
void BKE_mask_parent_init(MaskParent *parent)
{
parent->id_type = ID_MC;
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index e2a9691e577..55939f8eadf 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -40,12 +40,13 @@
#include "BLI_math.h"
#include "DNA_mask_types.h"
+#include "DNA_object_types.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_mask.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height)
{
@@ -897,24 +898,26 @@ void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime)
}
}
-void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask)
+void BKE_mask_eval_animation(struct Depsgraph *depsgraph, Mask *mask)
{
- DEG_debug_print_eval(__func__, mask->id.name, mask);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
for (MaskLayer *mask_layer = mask->masklayers.first;
mask_layer != NULL;
mask_layer = mask_layer->next)
{
- BKE_mask_layer_evaluate_animation(mask_layer, eval_ctx->ctime);
+ BKE_mask_layer_evaluate_animation(mask_layer, ctime);
}
}
-void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask)
+void BKE_mask_eval_update(struct Depsgraph *depsgraph, Mask *mask)
{
- DEG_debug_print_eval(__func__, mask->id.name, mask);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
for (MaskLayer *mask_layer = mask->masklayers.first;
mask_layer != NULL;
mask_layer = mask_layer->next)
{
- BKE_mask_layer_evaluate_deform(mask_layer, eval_ctx->ctime);
+ BKE_mask_layer_evaluate_deform(mask_layer, ctime);
}
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 74866fd1d94..0d41385a39c 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -58,7 +58,6 @@
#include "BKE_animsys.h"
#include "BKE_displist.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
@@ -73,6 +72,9 @@
#include "BKE_editmesh.h"
#include "BKE_font.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "GPU_material.h"
/* used in UI and render */
@@ -87,16 +89,10 @@ void init_def_material(void)
/** Free (or release) any data used by this material (does not free the material itself). */
void BKE_material_free(Material *ma)
{
- int a;
-
BKE_animdata_free((ID *)ma, false);
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(ma->mtex[a]);
- }
-
- MEM_SAFE_FREE(ma->ramp_col);
- MEM_SAFE_FREE(ma->ramp_spec);
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
/* is no lib link block, but material extension */
if (ma->nodetree) {
@@ -107,8 +103,6 @@ void BKE_material_free(Material *ma)
MEM_SAFE_FREE(ma->texpaintslot);
- GPU_material_free(&ma->gpumaterial);
-
BKE_icon_id_delete((ID *)ma);
BKE_previewimg_free(&ma->preview);
}
@@ -117,95 +111,19 @@ void BKE_material_init(Material *ma)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id));
- ma->r = ma->g = ma->b = ma->ref = 0.8;
+ ma->r = ma->g = ma->b = 0.8;
ma->specr = ma->specg = ma->specb = 1.0;
- ma->mirr = ma->mirg = ma->mirb = 1.0;
- ma->spectra = 1.0;
- ma->amb = 1.0;
- ma->alpha = 1.0;
- ma->spec = ma->hasize = 0.5;
- ma->har = 50;
- ma->starc = ma->ringc = 4;
- ma->linec = 12;
- ma->flarec = 1;
- ma->flaresize = ma->subsize = 1.0;
- ma->flareboost = 1;
- ma->seed2 = 6;
- ma->friction = 0.5;
- ma->refrac = 4.0;
- ma->roughness = 0.5;
- ma->param[0] = 0.5;
- ma->param[1] = 0.1;
- ma->param[2] = 0.5;
- ma->param[3] = 0.1;
- ma->rms = 0.1;
- ma->darkness = 1.0;
-
- ma->strand_sta = ma->strand_end = 1.0f;
-
- ma->ang = 1.0;
- ma->ray_depth = 2;
- ma->ray_depth_tra = 2;
- ma->fresnel_mir = 0.0;
- ma->fresnel_tra = 0.0;
- ma->fresnel_tra_i = 1.25;
- ma->fresnel_mir_i = 1.25;
- ma->tx_limit = 0.0;
- ma->tx_falloff = 1.0;
- ma->shad_alpha = 1.0f;
- ma->vcol_alpha = 0;
-
- ma->gloss_mir = ma->gloss_tra = 1.0;
- ma->samp_gloss_mir = ma->samp_gloss_tra = 18;
- ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005;
- ma->dist_mir = 0.0;
- ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
-
- ma->rampfac_col = 1.0;
- ma->rampfac_spec = 1.0;
+ // ma->alpha = 1.0; /* DEPRECATED */
+ ma->spec = 0.5;
+
+ ma->roughness = 0.25f;
+
ma->pr_lamp = 3; /* two lamps, is bits */
ma->pr_type = MA_SPHERE;
- ma->sss_radius[0] = 1.0f;
- ma->sss_radius[1] = 1.0f;
- ma->sss_radius[2] = 1.0f;
- ma->sss_col[0] = 1.0f;
- ma->sss_col[1] = 1.0f;
- ma->sss_col[2] = 1.0f;
- ma->sss_error = 0.05f;
- ma->sss_scale = 0.1f;
- ma->sss_ior = 1.3f;
- ma->sss_colfac = 1.0f;
- ma->sss_texfac = 0.0f;
- ma->sss_front = 1.0f;
- ma->sss_back = 1.0f;
-
- ma->vol.density = 1.0f;
- ma->vol.emission = 0.0f;
- ma->vol.scattering = 1.0f;
- ma->vol.reflection = 1.0f;
- ma->vol.transmission_col[0] = ma->vol.transmission_col[1] = ma->vol.transmission_col[2] = 1.0f;
- ma->vol.reflection_col[0] = ma->vol.reflection_col[1] = ma->vol.reflection_col[2] = 1.0f;
- ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f;
- ma->vol.density_scale = 1.0f;
- ma->vol.depth_cutoff = 0.01f;
- ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED;
- ma->vol.stepsize = 0.2f;
- ma->vol.shade_type = MA_VOL_SHADE_SHADED;
- ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
- ma->vol.precache_resolution = 50;
- ma->vol.ms_spread = 0.2f;
- ma->vol.ms_diff = 1.f;
- ma->vol.ms_intensity = 1.f;
-
- ma->game.flag = GEMAT_BACKCULL;
- ma->game.alpha_blend = 0;
- ma->game.face_orientation = 0;
-
- ma->mode = MA_TRACEBLE | MA_SHADBUF | MA_SHADOW | MA_RAYBIAS | MA_TANGENT_STR | MA_ZTRANSP;
- ma->mode2 = MA_CASTSHADOW;
- ma->shade_flag = MA_APPROX_OCCLUSION;
ma->preview = NULL;
+
+ ma->alpha_threshold = 0.5f;
}
Material *BKE_material_add(Main *bmain, const char *name)
@@ -229,20 +147,6 @@ Material *BKE_material_add(Main *bmain, const char *name)
*/
void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag)
{
- for (int a = 0; a < MAX_MTEX; a++) {
- if (ma_src->mtex[a]) {
- ma_dst->mtex[a] = MEM_mallocN(sizeof(*ma_dst->mtex[a]), __func__);
- *ma_dst->mtex[a] = *ma_src->mtex[a];
- }
- }
-
- if (ma_src->ramp_col) {
- ma_dst->ramp_col = MEM_dupallocN(ma_src->ramp_col);
- }
- if (ma_src->ramp_spec) {
- ma_dst->ramp_spec = MEM_dupallocN(ma_src->ramp_spec);
- }
-
if (ma_src->nodetree) {
/* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
* (see BKE_libblock_copy_ex()). */
@@ -261,6 +165,8 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr
}
BLI_listbase_clear(&ma_dst->gpumaterial);
+
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
}
Material *BKE_material_copy(Main *bmain, const Material *ma)
@@ -281,29 +187,24 @@ Material *BKE_material_localize(Material *ma)
* ... Once f*** nodes are fully converted to that too :( */
Material *man;
- int a;
-
- man = BKE_libblock_copy_nolib(&ma->id, false);
-
- /* no increment for texture ID users, in previewrender.c it prevents decrement */
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- man->mtex[a] = MEM_mallocN(sizeof(MTex), "copymaterial");
- memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex));
- }
- }
- if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col);
- if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec);
+ BKE_id_copy_ex(
+ NULL, &ma->id, (ID **)&man,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_COPY_NO_PREVIEW |
+ LIB_ID_COPY_NO_ANIMDATA),
+ false);
man->texpaintslot = NULL;
man->preview = NULL;
- if (ma->nodetree)
- man->nodetree = ntreeLocalize(ma->nodetree);
-
BLI_listbase_clear(&man->gpumaterial);
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
+
+ man->id.tag |= LIB_TAG_LOCALIZED;
+
return man;
}
@@ -458,7 +359,8 @@ void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user)
}
*totcolp = totcol;
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
@@ -475,7 +377,9 @@ void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
id_us_plus((ID *)ma);
test_all_objects_materials(bmain, id);
- DAG_relations_tag_update(bmain);
+
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
@@ -509,7 +413,8 @@ Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data
material_data_index_remove_id(id, index);
}
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
@@ -536,7 +441,8 @@ void BKE_material_clear_id(Main *bmain, ID *id, bool update_data)
material_data_index_clear_id(id);
}
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
@@ -631,7 +537,8 @@ void BKE_material_resize_object(Main *bmain, Object *ob, const short totcol, boo
if (ob->totcol && ob->actcol == 0) ob->actcol = 1;
if (ob->actcol > ob->totcol) ob->actcol = ob->totcol;
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
void test_object_materials(Main *bmain, Object *ob, ID *id)
@@ -936,278 +843,8 @@ bool BKE_object_material_slot_add(Main *bmain, Object *ob)
return true;
}
-static void do_init_render_material(Main *bmain, Material *ma, int r_mode, float *amb)
-{
- MTex *mtex;
- int a, needuv = 0, needtang = 0;
-
- if (ma->flarec == 0) ma->flarec = 1;
-
- /* add all texcoflags from mtex, texco and mapto were cleared in advance */
- for (a = 0; a < MAX_MTEX; a++) {
-
- /* separate tex switching */
- if (ma->septex & (1 << a)) continue;
-
- mtex = ma->mtex[a];
- if (mtex && mtex->tex && (mtex->tex->type | (mtex->tex->use_nodes && mtex->tex->nodetree) )) {
-
- ma->texco |= mtex->texco;
- ma->mapto |= mtex->mapto;
-
- /* always get derivatives for these textures */
- if (ELEM(mtex->tex->type, TEX_IMAGE, TEX_ENVMAP)) ma->texco |= TEXCO_OSA;
- else if (mtex->texflag & (MTEX_COMPAT_BUMP | MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)) ma->texco |= TEXCO_OSA;
-
- if (ma->texco & (TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM | TEXCO_STRAND | TEXCO_STRESS)) needuv = 1;
- else if (ma->texco & (TEXCO_GLOB | TEXCO_UV | TEXCO_OBJECT | TEXCO_SPEED)) needuv = 1;
- else if (ma->texco & (TEXCO_LAVECTOR | TEXCO_VIEW)) needuv = 1;
-
- if ((ma->mapto & MAP_NORM) && (mtex->normapspace == MTEX_NSPACE_TANGENT))
- needtang = 1;
- }
- }
-
- if (needtang) ma->mode |= MA_NORMAP_TANG;
- else ma->mode &= ~MA_NORMAP_TANG;
-
- if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) {
- needuv = 1;
- if (r_mode & R_OSA) ma->texco |= TEXCO_OSA; /* for texfaces */
- }
- if (needuv) ma->texco |= NEED_UV;
-
- /* since the raytracer doesnt recalc O structs for each ray, we have to preset them all */
- if (r_mode & R_RAYTRACE) {
- if ((ma->mode & (MA_RAYMIRROR | MA_SHADOW_TRA)) || ((ma->mode & MA_TRANSP) && (ma->mode & MA_RAYTRANSP))) {
- ma->texco |= NEED_UV | TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM;
- if (r_mode & R_OSA) ma->texco |= TEXCO_OSA;
- }
- }
-
- if (amb) {
- ma->ambr = ma->amb * amb[0];
- ma->ambg = ma->amb * amb[1];
- ma->ambb = ma->amb * amb[2];
- }
-
- /* local group override */
- if ((ma->shade_flag & MA_GROUP_LOCAL) && ma->id.lib && ma->group && ma->group->id.lib) {
- Group *group;
-
- for (group = bmain->group.first; group; group = group->id.next) {
- if (!ID_IS_LINKED(group) && STREQ(group->id.name, ma->group->id.name)) {
- ma->group = group;
- }
- }
- }
-}
-
-static void init_render_nodetree(Main *bmain, bNodeTree *ntree, Material *basemat, int r_mode, float *amb)
-{
- bNode *node;
-
- /* parses the geom+tex nodes */
- ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name) == ID_MA) {
- Material *ma = (Material *)node->id;
- if (ma != basemat) {
- do_init_render_material(bmain, ma, r_mode, amb);
- basemat->texco |= ma->texco;
- }
-
- basemat->mode_l |= ma->mode & ~(MA_MODE_PIPELINE | MA_SHLESS);
- basemat->mode2_l |= ma->mode2 & ~MA_MODE2_PIPELINE;
- /* basemat only considered shadeless if all node materials are too */
- if (!(ma->mode & MA_SHLESS))
- basemat->mode_l &= ~MA_SHLESS;
-
- if (ma->strand_surfnor > 0.0f)
- basemat->mode_l |= MA_STR_SURFDIFF;
- }
- else if (node->type == NODE_GROUP)
- init_render_nodetree(bmain, (bNodeTree *)node->id, basemat, r_mode, amb);
- }
- else if (node->typeinfo->type == SH_NODE_NORMAL_MAP) {
- basemat->mode2_l |= MA_TANGENT_CONCRETE;
- NodeShaderNormalMap *nm = node->storage;
- bool taken_into_account = false;
- for (int i = 0; i < basemat->nmap_tangent_names_count; i++) {
- if (STREQ(basemat->nmap_tangent_names[i], nm->uv_map)) {
- taken_into_account = true;
- break;
- }
- }
- if (!taken_into_account) {
- BLI_assert(basemat->nmap_tangent_names_count < MAX_MTFACE + 1);
- strcpy(basemat->nmap_tangent_names[basemat->nmap_tangent_names_count++], nm->uv_map);
- }
- }
- }
-}
-
-void init_render_material(Main *bmain, Material *mat, int r_mode, float *amb)
-{
-
- do_init_render_material(bmain, mat, r_mode, amb);
-
- if (mat->nodetree && mat->use_nodes) {
- /* mode_l will take the pipeline options from the main material, and the or-ed
- * result of non-pipeline options from the nodes. shadeless is an exception,
- * mode_l will have it set when all node materials are shadeless. */
- mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS;
- mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE;
- mat->nmap_tangent_names_count = 0;
- init_render_nodetree(bmain, mat->nodetree, mat, r_mode, amb);
-
- if (!mat->nodetree->execdata)
- mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree);
- }
- else {
- mat->mode_l = mat->mode;
- mat->mode2_l = mat->mode2;
-
- if (mat->strand_surfnor > 0.0f)
- mat->mode_l |= MA_STR_SURFDIFF;
- }
-}
-
-void init_render_materials(Main *bmain, int r_mode, float *amb, bool do_default_material)
-{
- Material *ma;
-
- /* clear these flags before going over materials, to make sure they
- * are cleared only once, otherwise node materials contained in other
- * node materials can go wrong */
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->id.us) {
- ma->texco = 0;
- ma->mapto = 0;
- }
- }
-
- /* two steps, first initialize, then or the flags for layers */
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- /* is_used flag comes back in convertblender.c */
- ma->flag &= ~MA_IS_USED;
- if (ma->id.us)
- init_render_material(bmain, ma, r_mode, amb);
- }
-
- if (do_default_material) {
- init_render_material(bmain, &defmaterial, r_mode, amb);
- }
-}
-
-/* only needed for nodes now */
-void end_render_material(Material *mat)
-{
- if (mat && mat->nodetree && mat->use_nodes) {
- if (mat->nodetree->execdata)
- ntreeShaderEndExecTree(mat->nodetree->execdata);
- }
-}
-
-void end_render_materials(Main *bmain)
-{
- Material *ma;
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->id.us)
- end_render_material(ma);
-}
-
-static bool material_in_nodetree(bNodeTree *ntree, Material *mat)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name) == ID_MA) {
- if (node->id == (ID *)mat) {
- return true;
- }
- }
- else if (node->type == NODE_GROUP) {
- if (material_in_nodetree((bNodeTree *)node->id, mat)) {
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-bool material_in_material(Material *parmat, Material *mat)
-{
- if (parmat == mat)
- return true;
- else if (parmat->nodetree && parmat->use_nodes)
- return material_in_nodetree(parmat->nodetree, mat);
- else
- return false;
-}
-
-
/* ****************** */
-/* Update drivers for materials in a nodetree */
-static void material_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime)
-{
- bNode *node;
-
- /* nodetree itself */
- if (ntree->adt && ntree->adt->drivers.first) {
- BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* nodes */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name) == ID_MA) {
- material_drivers_update(scene, (Material *)node->id, ctime);
- }
- else if (node->type == NODE_GROUP) {
- material_node_drivers_update(scene, (bNodeTree *)node->id, ctime);
- }
- }
- }
-}
-
-/* Calculate all drivers for materials
- * FIXME: this is really a terrible method which may result in some things being calculated
- * multiple times. However, without proper despgraph support for these things, we are forced
- * into this sort of thing...
- */
-void material_drivers_update(Scene *scene, Material *ma, float ctime)
-{
- //if (G.f & G_DEBUG)
- // printf("material_drivers_update(%s, %s)\n", scene->id.name, ma->id.name);
-
- /* Prevent infinite recursion by checking (and tagging the material) as having been visited already
- * (see BKE_scene_update_tagged()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else
- * in the meantime... [#32017]
- */
- if (ma->id.tag & LIB_TAG_DOIT)
- return;
-
- ma->id.tag |= LIB_TAG_DOIT;
-
- /* material itself */
- if (ma->adt && ma->adt->drivers.first) {
- BKE_animsys_evaluate_animdata(scene, &ma->id, ma->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* nodes */
- if (ma->nodetree) {
- material_node_drivers_update(scene, ma->nodetree, ctime);
- }
-
- ma->id.tag &= ~LIB_TAG_DOIT;
-}
-
bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
{
Material *mao, ***matarar;
@@ -1297,13 +934,6 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
return true;
}
-static bool get_mtex_slot_valid_texpaint(struct MTex *mtex)
-{
- return (mtex && (mtex->texco == TEXCO_UV) &&
- mtex->tex && (mtex->tex->type == TEX_IMAGE) &&
- mtex->tex->ima);
-}
-
static bNode *nodetree_uv_node_recursive(bNode *node)
{
bNode *inode;
@@ -1326,12 +956,8 @@ static bNode *nodetree_uv_node_recursive(bNode *node)
void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
{
- MTex **mtex;
short count = 0;
- short index = 0, i;
-
- bool use_nodes = BKE_scene_use_new_shading_nodes(scene);
- bool is_bi = BKE_scene_uses_blender_internal(scene) || BKE_scene_uses_blender_game(scene);
+ short index = 0;
if (!ma)
return;
@@ -1348,88 +974,50 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
return;
}
- if (use_nodes || ma->use_nodes) {
- bNode *node, *active_node;
+ bNode *node, *active_node;
- if (!(ma->nodetree)) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
+ if (!(ma->nodetree)) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
+ }
- for (node = ma->nodetree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id)
- count++;
- }
+ for (node = ma->nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id)
+ count++;
+ }
- if (count == 0) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
- ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
-
- active_node = nodeGetActiveTexture(ma->nodetree);
-
- for (node = ma->nodetree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
- if (active_node == node)
- ma->paint_active_slot = index;
- ma->texpaintslot[index].ima = (Image *)node->id;
-
- /* for new renderer, we need to traverse the treeback in search of a UV node */
- if (use_nodes) {
- bNode *uvnode = nodetree_uv_node_recursive(node);
-
- if (uvnode) {
- NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
- ma->texpaintslot[index].uvname = storage->uv_map;
- /* set a value to index so UI knows that we have a valid pointer for the mesh */
- ma->texpaintslot[index].index = 0;
- }
- else {
- /* just invalidate the index here so UV map does not get displayed on the UI */
- ma->texpaintslot[index].index = -1;
- }
- }
- else {
- ma->texpaintslot[index].index = -1;
- }
- index++;
- }
- }
+ if (count == 0) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
}
- else if (is_bi) {
- for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
- if (get_mtex_slot_valid_texpaint(*mtex)) {
- count++;
- }
- }
+ ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
- if (count == 0) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
+ active_node = nodeGetActiveTexture(ma->nodetree);
- ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+ for (node = ma->nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+ if (active_node == node)
+ ma->paint_active_slot = index;
+ ma->texpaintslot[index].ima = (Image *)node->id;
- for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
- if (get_mtex_slot_valid_texpaint(*mtex)) {
- ma->texpaintslot[index].ima = (*mtex)->tex->ima;
- ma->texpaintslot[index].uvname = (*mtex)->uvname;
- ma->texpaintslot[index].index = i;
+ /* for new renderer, we need to traverse the treeback in search of a UV node */
+ bNode *uvnode = nodetree_uv_node_recursive(node);
- index++;
+ if (uvnode) {
+ NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
+ ma->texpaintslot[index].uvname = storage->uv_map;
+ /* set a value to index so UI knows that we have a valid pointer for the mesh */
+ ma->texpaintslot[index].valid = true;
+ }
+ else {
+ /* just invalidate the index here so UV map does not get displayed on the UI */
+ ma->texpaintslot[index].valid = false;
}
+ index++;
}
}
- else {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
-
ma->tot_slots = count;
@@ -1685,21 +1273,6 @@ void clear_matcopybuf(void)
void free_matcopybuf(void)
{
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (matcopybuf.mtex[a]) {
- MEM_freeN(matcopybuf.mtex[a]);
- matcopybuf.mtex[a] = NULL;
- }
- }
-
- if (matcopybuf.ramp_col) MEM_freeN(matcopybuf.ramp_col);
- if (matcopybuf.ramp_spec) MEM_freeN(matcopybuf.ramp_spec);
-
- matcopybuf.ramp_col = NULL;
- matcopybuf.ramp_spec = NULL;
-
if (matcopybuf.nodetree) {
ntreeFreeTree(matcopybuf.nodetree);
MEM_freeN(matcopybuf.nodetree);
@@ -1711,575 +1284,42 @@ void free_matcopybuf(void)
void copy_matcopybuf(Main *bmain, Material *ma)
{
- int a;
- MTex *mtex;
-
if (matcopied)
free_matcopybuf();
memcpy(&matcopybuf, ma, sizeof(Material));
- if (matcopybuf.ramp_col) matcopybuf.ramp_col = MEM_dupallocN(matcopybuf.ramp_col);
- if (matcopybuf.ramp_spec) matcopybuf.ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = matcopybuf.mtex[a];
- if (mtex) {
- matcopybuf.mtex[a] = MEM_dupallocN(mtex);
- }
- }
matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, bmain, false);
matcopybuf.preview = NULL;
BLI_listbase_clear(&matcopybuf.gpumaterial);
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
matcopied = 1;
}
void paste_matcopybuf(Main *bmain, Material *ma)
{
- int a;
- MTex *mtex;
ID id;
if (matcopied == 0)
return;
- /* free current mat */
- if (ma->ramp_col) MEM_freeN(ma->ramp_col);
- if (ma->ramp_spec) MEM_freeN(ma->ramp_spec);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
- }
+
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
if (ma->nodetree) {
ntreeFreeTree(ma->nodetree);
MEM_freeN(ma->nodetree);
}
- GPU_material_free(&ma->gpumaterial);
-
id = (ma->id);
memcpy(ma, &matcopybuf, sizeof(Material));
(ma->id) = id;
- if (matcopybuf.ramp_col) ma->ramp_col = MEM_dupallocN(matcopybuf.ramp_col);
- if (matcopybuf.ramp_spec) ma->ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec);
-
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
- if (mtex) {
- ma->mtex[a] = MEM_dupallocN(mtex);
- if (mtex->tex) {
- /* first check this is in main (we may have loaded another file) [#35500] */
- if (BLI_findindex(&bmain->tex, mtex->tex) != -1) {
- id_us_plus((ID *)mtex->tex);
- }
- else {
- ma->mtex[a]->tex = NULL;
- }
- }
- }
- }
-
ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false);
}
-
-/*********************** texface to material convert functions **********************/
-/* encode all the TF information into a single int */
-static int encode_tfaceflag(MTFace *tf, int convertall)
-{
- /* calculate the flag */
- int flag = tf->mode;
-
- /* options that change the material offline render */
- if (!convertall) {
- flag &= ~TF_OBCOL;
- }
-
- /* clean flags that are not being converted */
- flag &= ~TF_TEX;
- flag &= ~TF_SHAREDVERT;
- flag &= ~TF_SHAREDCOL;
- flag &= ~TF_CONVERTED;
-
- /* light tface flag is ignored in GLSL mode */
- flag &= ~TF_LIGHT;
-
- /* 15 is how big the flag can be - hardcoded here and in decode_tfaceflag() */
- flag |= tf->transp << 15;
-
- /* increase 1 so flag 0 is different than no flag yet */
- return flag + 1;
-}
-
-/* set the material options based in the tface flag */
-static void decode_tfaceflag(Material *ma, int flag, int convertall)
-{
- int alphablend;
- GameSettings *game = &ma->game;
-
- /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
- flag -= 1;
-
- alphablend = flag >> 15; /* encoded in the encode_tfaceflag function */
- (*game).flag = 0;
-
- /* General Material Options */
- if ((flag & TF_DYNAMIC) == 0) (*game).flag |= GEMAT_NOPHYSICS;
-
- /* Material Offline Rendering Properties */
- if (convertall) {
- if (flag & TF_OBCOL) ma->shade_flag |= MA_OBCOLOR;
- }
-
- /* Special Face Properties */
- if ((flag & TF_TWOSIDE) == 0) (*game).flag |= GEMAT_BACKCULL;
- if (flag & TF_INVISIBLE) (*game).flag |= GEMAT_INVISIBLE;
- if (flag & TF_BMFONT) (*game).flag |= GEMAT_TEXT;
-
- /* Face Orientation */
- if (flag & TF_BILLBOARD) (*game).face_orientation |= GEMAT_HALO;
- else if (flag & TF_BILLBOARD2) (*game).face_orientation |= GEMAT_BILLBOARD;
- else if (flag & TF_SHADOW) (*game).face_orientation |= GEMAT_SHADOW;
-
- /* Alpha Blend */
- if (flag & TF_ALPHASORT && ELEM(alphablend, TF_ALPHA, TF_ADD)) (*game).alpha_blend = GEMAT_ALPHA_SORT;
- else if (alphablend & TF_ALPHA) (*game).alpha_blend = GEMAT_ALPHA;
- else if (alphablend & TF_ADD) (*game).alpha_blend = GEMAT_ADD;
- else if (alphablend & TF_CLIP) (*game).alpha_blend = GEMAT_CLIP;
-}
-
-/* boolean check to see if the mesh needs a material */
-static int check_tfaceneedmaterial(int flag)
-{
- /* check if the flags we have are not deprecated != than default material options
- * also if only flags are visible and collision see if all objects using this mesh have this option in physics */
-
- /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
- flag -= 1;
-
- /* deprecated flags */
- flag &= ~TF_OBCOL;
- flag &= ~TF_SHAREDVERT;
- flag &= ~TF_SHAREDCOL;
-
- /* light tface flag is ignored in GLSL mode */
- flag &= ~TF_LIGHT;
-
- /* automatic detected if tex image has alpha */
- flag &= ~(TF_ALPHA << 15);
- /* automatic detected if using texture */
- flag &= ~TF_TEX;
-
- /* settings for the default NoMaterial */
- if (flag == TF_DYNAMIC)
- return 0;
-
- else
- return 1;
-}
-
-/* return number of digits of an integer */
-/* XXX to be optmized or replaced by an equivalent blender internal function */
-static int integer_getdigits(int number)
-{
- int i = 0;
- if (number == 0) return 1;
-
- while (number != 0) {
- number = (int)(number / 10);
- i++;
- }
- return i;
-}
-
-static void calculate_tface_materialname(char *matname, char *newname, int flag)
-{
- /* if flag has only light and collision and material matches those values
- * you can do strcpy(name, mat_name);
- * otherwise do: */
- int digits = integer_getdigits(flag);
- /* clamp the old name, remove the MA prefix and add the .TF.flag suffix
- * e.g. matname = "MALoooooooooooooongName"; newname = "Loooooooooooooon.TF.2" */
- BLI_snprintf(newname, MAX_ID_NAME, "%.*s.TF.%0*d", MAX_ID_NAME - (digits + 5), matname, digits, flag);
-}
-
-/* returns -1 if no match */
-static short mesh_getmaterialnumber(Mesh *me, Material *ma)
-{
- short a;
-
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a] == ma) {
- return a;
- }
- }
-
- return -1;
-}
-
-/* append material */
-static short mesh_addmaterial(Main *bmain, Mesh *me, Material *ma)
+void BKE_material_eval(struct Depsgraph *depsgraph, Material *material)
{
- BKE_material_append_id(bmain, &me->id, NULL);
- me->mat[me->totcol - 1] = ma;
-
- id_us_plus(&ma->id);
-
- return me->totcol - 1;
+ DEG_debug_print_eval(depsgraph, __func__, material->id.name, material);
+ GPU_material_free(&material->gpumaterial);
}
-
-static void set_facetexture_flags(Material *ma, Image *image)
-{
- if (image) {
- ma->mode |= MA_FACETEXTURE;
- /* we could check if the texture has alpha, but then more meshes sharing the same
- * material may need it. Let's make it simple. */
- if (BKE_image_has_alpha(image))
- ma->mode |= MA_FACETEXTURE_ALPHA;
- }
-}
-
-/* returns material number */
-static short convert_tfacenomaterial(Main *bmain, Mesh *me, MTFace *tf, int flag)
-{
- Material *ma;
- char idname[MAX_ID_NAME];
- short mat_nr = -1;
-
- /* new material, the name uses the flag*/
- BLI_snprintf(idname, sizeof(idname), "MAMaterial.TF.%0*d", integer_getdigits(flag), flag);
-
- if ((ma = BLI_findstring(&bmain->mat, idname + 2, offsetof(ID, name) + 2))) {
- mat_nr = mesh_getmaterialnumber(me, ma);
- /* assign the material to the mesh */
- if (mat_nr == -1) mat_nr = mesh_addmaterial(bmain, me, ma);
-
- /* if needed set "Face Textures [Alpha]" Material options */
- set_facetexture_flags(ma, tf->tpage);
- }
- /* create a new material */
- else {
- ma = BKE_material_add(bmain, idname + 2);
-
- if (ma) {
- printf("TexFace Convert: Material \"%s\" created.\n", idname + 2);
- mat_nr = mesh_addmaterial(bmain, me, ma);
-
- /* if needed set "Face Textures [Alpha]" Material options */
- set_facetexture_flags(ma, tf->tpage);
-
- decode_tfaceflag(ma, flag, 1);
- /* the final decoding will happen after, outside the main loop
- * for now store the flag into the material and change light/tex/collision
- * store the flag as a negative number */
- ma->game.flag = -flag;
- id_us_min((ID *)ma);
- }
- else {
- printf("Error: Unable to create Material \"%s\" for Mesh \"%s\".", idname + 2, me->id.name + 2);
- }
- }
-
- /* set as converted, no need to go bad to this face */
- tf->mode |= TF_CONVERTED;
- return mat_nr;
-}
-
-/* Function to fully convert materials */
-static void convert_tfacematerial(Main *bmain, Material *ma)
-{
- Mesh *me;
- Material *mat_new;
- MFace *mf;
- MTFace *tf;
- int flag, index;
- int a;
- short mat_nr;
- CustomDataLayer *cdl;
- char idname[MAX_ID_NAME];
-
- for (me = bmain->mesh.first; me; me = me->id.next) {
- /* check if this mesh uses this material */
- for (a = 0; a < me->totcol; a++)
- if (me->mat[a] == ma) break;
-
- /* no material found */
- if (a == me->totcol) continue;
-
- /* get the active tface layer */
- index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl = (index == -1) ? NULL : &me->fdata.layers[index];
- if (!cdl) continue;
-
- /* loop over all the faces and stop at the ones that use the material*/
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (me->mat[mf->mat_nr] != ma) continue;
-
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
- flag = encode_tfaceflag(tf, 1);
-
- /* the name of the new material */
- calculate_tface_materialname(ma->id.name, (char *)&idname, flag);
-
- if ((mat_new = BLI_findstring(&bmain->mat, idname + 2, offsetof(ID, name) + 2))) {
- /* material already existent, see if the mesh has it */
- mat_nr = mesh_getmaterialnumber(me, mat_new);
- /* material is not in the mesh, add it */
- if (mat_nr == -1) mat_nr = mesh_addmaterial(bmain, me, mat_new);
- }
- /* create a new material */
- else {
- mat_new = BKE_material_copy(bmain, ma);
- if (mat_new) {
- /* rename the material*/
- BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name));
- id_us_min((ID *)mat_new);
-
- mat_nr = mesh_addmaterial(bmain, me, mat_new);
- decode_tfaceflag(mat_new, flag, 1);
- }
- else {
- printf("Error: Unable to create Material \"%s\" for Mesh \"%s.", idname + 2, me->id.name + 2);
- mat_nr = mf->mat_nr;
- continue;
- }
- }
-
- /* if the material has a texture but no texture channel
- * set "Face Textures [Alpha]" Material options
- * actually we need to run it always, because of old behavior
- * of using face texture if any texture channel was present (multitex) */
- //if ((!mat_new->mtex[0]) && (!mat_new->mtex[0]->tex))
- set_facetexture_flags(mat_new, tf->tpage);
-
- /* set the material number to the face*/
- mf->mat_nr = mat_nr;
- }
- /* remove material from mesh */
- for (a = 0; a < me->totcol; ) {
- if (me->mat[a] == ma) {
- BKE_material_pop_id(bmain, &me->id, a, true);
- }
- else {
- a++;
- }
- }
- }
-}
-
-
-#define MAT_BGE_DISPUTED -99999
-
-int do_version_tface(Main *main)
-{
- Mesh *me;
- Material *ma;
- MFace *mf;
- MTFace *tf;
- CustomDataLayer *cdl;
- int a;
- int flag;
- int index;
-
- /* Operator in help menu has been removed for 2.7x */
- int fileload = 1;
-
- /* sometimes mesh has no materials but will need a new one. In those
- * cases we need to ignore the mf->mat_nr and only look at the face
- * mode because it can be zero as uninitialized or the 1st created material
- */
- int nomaterialslots;
-
- /* alert to user to check the console */
- int nowarning = 1;
-
- /* mark all the materials to conversion with a flag
- * if there is tface create a complete flag for that storing in flag
- * if there is tface and flag > 0: creates a new flag based on this face
- * if flags are different set flag to -1
- */
-
- /* 1st part: marking mesh materials to update */
- for (me = main->mesh.first; me; me = me->id.next) {
- if (ID_IS_LINKED(me)) continue;
-
- /* get the active tface layer */
- index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl = (index == -1) ? NULL : &me->fdata.layers[index];
- if (!cdl) continue;
-
- nomaterialslots = (me->totcol == 0 ? 1 : 0);
-
- /* loop over all the faces*/
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
-
- /* conversion should happen only once */
- if (fileload)
- tf->mode &= ~TF_CONVERTED;
- else {
- if ((tf->mode & TF_CONVERTED)) continue;
- else tf->mode |= TF_CONVERTED;
- }
-
- /* no material slots */
- if (nomaterialslots) {
- flag = encode_tfaceflag(tf, 1);
-
- /* create/find a new material and assign to the face */
- if (check_tfaceneedmaterial(flag)) {
- mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag);
- }
- /* else mark them as no-material to be reverted to 0 later */
- else {
- mf->mat_nr = -1;
- }
- }
- else if (mf->mat_nr < me->totcol) {
- ma = me->mat[mf->mat_nr];
-
- /* no material create one if necessary */
- if (!ma) {
- /* find a new material and assign to the face */
- flag = encode_tfaceflag(tf, 1);
-
- /* create/find a new material and assign to the face */
- if (check_tfaceneedmaterial(flag))
- mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag);
-
- continue;
- }
-
- /* we can't read from this if it comes from a library,
- * at doversion time: direct_link might not have happened on it,
- * so ma->mtex is not pointing to valid memory yet.
- * later we could, but it's better not */
- else if (ID_IS_LINKED(ma))
- continue;
-
- /* material already marked as disputed */
- else if (ma->game.flag == MAT_BGE_DISPUTED)
- continue;
-
- /* found a material */
- else {
- flag = encode_tfaceflag(tf, ((fileload) ? 0 : 1));
-
- /* first time changing this material */
- if (ma->game.flag == 0)
- ma->game.flag = -flag;
-
- /* mark material as disputed */
- else if (ma->game.flag != -flag) {
- ma->game.flag = MAT_BGE_DISPUTED;
- continue;
- }
-
- /* material ok so far */
- else {
- ma->game.flag = -flag;
-
- /* some people uses multitexture with TexFace by creating a texture
- * channel which not necessarily the tf->tpage image. But the game engine
- * was enabling it. Now it's required to set "Face Texture [Alpha] in the
- * material settings. */
- if (!fileload)
- set_facetexture_flags(ma, tf->tpage);
- }
- }
- }
- else {
- continue;
- }
- }
-
- /* if we didn't have material slot and now we do, we need to
- * make sure the materials are correct */
- if (nomaterialslots) {
- if (me->totcol > 0) {
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (mf->mat_nr == -1) {
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
- mf->mat_nr = convert_tfacenomaterial(main, me, tf, encode_tfaceflag(tf, 1));
- }
- }
- }
- else {
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- mf->mat_nr = 0;
- }
- }
- }
-
- }
-
- /* 2nd part - conversion */
- /* skip library files */
-
- /* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */
- for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) {
- if (ID_IS_LINKED(ma)) continue;
-
- /* disputed material */
- if (ma->game.flag == MAT_BGE_DISPUTED) {
- ma->game.flag = 0;
- if (fileload) {
- printf("Warning: material \"%s\" skipped.\n", ma->id.name + 2);
- nowarning = 0;
- }
- else {
- convert_tfacematerial(main, ma);
- }
- continue;
- }
-
- /* no conflicts in this material - 90% of cases
- * convert from tface system to material */
- else if (ma->game.flag < 0) {
- decode_tfaceflag(ma, -(ma->game.flag), 1);
-
- /* material is good make sure all faces using
- * this material are set to converted */
- if (fileload) {
- for (me = main->mesh.first; me; me = me->id.next) {
- /* check if this mesh uses this material */
- for (a = 0; a < me->totcol; a++)
- if (me->mat[a] == ma) break;
-
- /* no material found */
- if (a == me->totcol) continue;
-
- /* get the active tface layer */
- index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl = (index == -1) ? NULL : &me->fdata.layers[index];
- if (!cdl) continue;
-
- /* loop over all the faces and stop at the ones that use the material*/
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (me->mat[mf->mat_nr] == ma) {
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
- tf->mode |= TF_CONVERTED;
- }
- }
- }
- }
- }
- /* material is not used by faces with texface
- * set the default flag - do it only once */
- else {
- if (fileload) {
- ma->game.flag = GEMAT_BACKCULL;
- }
- }
- }
-
- return nowarning;
-}
-
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 9e926e5ef53..2ff69c5ee6d 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -57,7 +57,6 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_scene.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -67,6 +66,8 @@
#include "BKE_object.h"
#include "BKE_material.h"
+//#include "DEG_depsgraph.h"
+
/* Functions */
/** Free (or release) any data used by this mball (does not free the mball itself). */
@@ -74,6 +75,8 @@ void BKE_mball_free(MetaBall *mb)
{
BKE_animdata_free((ID *)mb, false);
+ BKE_mball_batch_cache_free(mb);
+
MEM_SAFE_FREE(mb->mat);
BLI_freelistN(&mb->elems);
@@ -119,6 +122,7 @@ void BKE_mball_copy_data(Main *UNUSED(bmain), MetaBall *mb_dst, const MetaBall *
mb_dst->editelems = NULL;
mb_dst->lastelem = NULL;
+ mb_dst->batch_cache = NULL;
}
MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb)
@@ -310,13 +314,33 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
}
}
+bool BKE_mball_is_any_selected(const MetaBall *mb)
+{
+ for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_mball_is_any_unselected(const MetaBall *mb)
+{
+ for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
+ if ((ml->flag & SELECT) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
/* \brief copy some properties from object to other metaball object with same base name
*
* When some properties (wiresize, threshold, update flags) of metaball are changed, then this properties
* are copied to all metaballs in same "group" (metaballs with same base name: MBall,
* MBall.001, MBall.002, etc). The most important is to copy properties to the base metaball,
* because this metaball influence polygonisation of metaballs. */
-void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *active_object)
+void BKE_mball_properties_copy(Scene *scene, Object *active_object)
{
Scene *sce_iter = scene;
Base *base;
@@ -328,8 +352,11 @@ void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *
BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.');
- BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &ob)) {
+ /* Pass depsgraph as NULL, which means we will not expand into
+ * duplis unlike when we generate the mball. Expanding duplis
+ * would not be compatible when editing multiple view layers. */
+ BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 1, &base, &ob)) {
if (ob->type == OB_MBALL) {
if (ob != active_object) {
BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
@@ -359,28 +386,27 @@ void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *
*
* warning!, is_basis_mball() can fail on returned object, see long note above.
*/
-Object *BKE_mball_basis_find(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *basis)
+Object *BKE_mball_basis_find(Scene *scene, Object *basis)
{
- Scene *sce_iter = scene;
- Base *base;
- Object *ob, *bob = basis;
+ Object *bob = basis;
int basisnr, obnr;
char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
- SceneBaseIter iter;
BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &ob)) {
- if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) {
- if (ob != bob) {
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* object ob has to be in same "group" ... it means, that it has to have same base of its name */
- if (STREQ(obname, basisname)) {
- if (obnr < basisnr) {
- basis = ob;
- basisnr = obnr;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) {
+ if (ob != bob) {
+ BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
+
+ /* object ob has to be in same "group" ... it means, that it has to have same base of its name */
+ if (STREQ(obname, basisname)) {
+ if (obnr < basisnr) {
+ basis = ob;
+ basisnr = obnr;
+ }
}
}
}
@@ -537,7 +563,20 @@ void BKE_mball_select_swap(struct MetaBall *mb)
/* **** Depsgraph evaluation **** */
-void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
- MetaBall *UNUSED(mball))
+/* Draw Engine */
+
+void (*BKE_mball_batch_cache_dirty_cb)(MetaBall *mb, int mode) = NULL;
+void (*BKE_mball_batch_cache_free_cb)(MetaBall *mb) = NULL;
+
+void BKE_mball_batch_cache_dirty(MetaBall *mb, int mode)
+{
+ if (mb->batch_cache) {
+ BKE_mball_batch_cache_dirty_cb(mb, mode);
+ }
+}
+void BKE_mball_batch_cache_free(MetaBall *mb)
{
+ if (mb->batch_cache) {
+ BKE_mball_batch_cache_free_cb(mb);
+ }
}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index cc82d12a776..7e26a0f7713 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -48,12 +48,14 @@
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_main.h"
#include "BKE_mball_tessellate.h" /* own include */
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "BLI_strict_flags.h"
/* experimental (faster) normal calculation */
@@ -1056,7 +1058,7 @@ static void polygonize(PROCESS *process)
* Iterates over ALL objects in the scene and all of its sets, including
* making all duplis(not only metas). Copies metas to mainb array.
* Computes bounding boxes for building BVH. */
-static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob)
+static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Object *ob)
{
Scene *sce_iter = scene;
Base *base;
@@ -1075,13 +1077,13 @@ static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process
BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
/* make main array */
- BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &bob)) {
+ BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 1, &base, &bob)) {
if (bob->type == OB_MBALL) {
zero_size = 0;
ml = NULL;
- if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) {
+ if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) {
mb = ob->data;
if (mb->editelems) ml = mb->editelems->first;
@@ -1233,12 +1235,13 @@ static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process
}
}
-void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
+void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
MetaBall *mb;
DispList *dl;
unsigned int a;
PROCESS process = {0};
+ bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
mb = ob->data;
@@ -1249,10 +1252,10 @@ void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene
else if (process.thresh < 0.1f) process.converge_res = 4;
else process.converge_res = 2;
- if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return;
+ if (is_render && (mb->flag == MB_UPDATE_NEVER)) return;
if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return;
- if (eval_ctx->mode == DAG_EVAL_RENDER) {
+ if (is_render) {
process.size = mb->rendersize;
}
else {
@@ -1267,7 +1270,7 @@ void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene
process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena");
/* initialize all mainb (MetaElems) */
- init_meta(bmain, eval_ctx, &process, scene, ob);
+ init_meta(depsgraph, &process, scene, ob);
if (process.totelem > 0) {
build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 4fabf9ebdf8..f502d7e394f 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -41,15 +41,16 @@
#include "BLI_string.h"
#include "BKE_animsys.h"
+#include "BKE_idcode.h"
#include "BKE_main.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_editmesh.h"
@@ -109,7 +110,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
for (i = 0; i < c1->totlayer; i++) {
if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i1++;
}
@@ -117,7 +118,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
for (i = 0; i < c2->totlayer; i++) {
if (ELEM(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i2++;
}
@@ -131,14 +132,14 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
i1 = 0; i2 = 0;
for (i = 0; i < tot; i++) {
while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i1++;
l1++;
}
while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i2++;
l2++;
@@ -306,7 +307,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
* Callers could also check but safer to do here - campbell */
}
else {
- const int tottex_original = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+ const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
@@ -317,7 +318,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
{
BKE_mesh_tessface_clear(me);
- CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface);
+ CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface);
/* TODO - add some --debug-mesh option */
if (G.debug & G_DEBUG) {
@@ -326,7 +327,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
* and check if there was any data to begin with, for now just print the warning with
* some info to help troubleshoot whats going on - campbell */
printf("%s: warning! Tessellation uvs or vcol data got out of sync, "
- "had to reset!\n CD_MTFACE: %d != CD_MTEXPOLY: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n",
+ "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n",
__func__, tottex_tessface, tottex_original, totcol_tessface, totcol_original);
}
}
@@ -370,6 +371,48 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
}
}
+bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me)
+{
+ BMesh *bm = me->edit_btmesh ? me->edit_btmesh->bm : NULL;
+ bool changed = false;
+ if (bm) {
+ if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
+ BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP);
+ changed = true;
+ }
+ }
+ else {
+ if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ CustomData_add_layer(&me->pdata,
+ CD_FACEMAP,
+ CD_DEFAULT,
+ NULL,
+ me->totpoly);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
+bool BKE_mesh_clear_facemap_customdata(struct Mesh *me)
+{
+ BMesh *bm = me->edit_btmesh ? me->edit_btmesh->bm : NULL;
+ bool changed = false;
+ if (bm) {
+ if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
+ BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP);
+ changed = true;
+ }
+ }
+ else {
+ if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ CustomData_free_layers(&me->pdata, CD_FACEMAP, me->totpoly);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
/* this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
* mloopcol and mcol) have the same relative active/render/clone/mask indices.
*
@@ -378,14 +421,11 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
* versions of the mesh. - campbell*/
static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd)
{
- if (me->edit_btmesh)
- BKE_editmesh_update_linked_customdata(me->edit_btmesh);
-
if (do_ensure_tess_cd) {
mesh_ensure_tessellation_customdata(me);
}
- CustomData_bmesh_update_active_layers(&me->fdata, &me->pdata, &me->ldata);
+ CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata);
}
void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
@@ -404,7 +444,6 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
- me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY);
me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
}
@@ -424,6 +463,8 @@ void BKE_mesh_free(Mesh *me)
{
BKE_animdata_free(&me->id, false);
+ BKE_mesh_runtime_clear_cache(me);
+
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
@@ -494,15 +535,22 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int flag)
{
const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */
+ CustomDataMask mask = CD_MASK_MESH;
+
+ if (me_src->id.tag & LIB_TAG_NO_MAIN) {
+ /* For copies in depsgraph, keep data like origindex and orco. */
+ mask |= CD_MASK_DERIVEDMESH;
+ }
me_dst->mat = MEM_dupallocN(me_src->mat);
- CustomData_copy(&me_src->vdata, &me_dst->vdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totvert);
- CustomData_copy(&me_src->edata, &me_dst->edata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totedge);
- CustomData_copy(&me_src->ldata, &me_dst->ldata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totloop);
- CustomData_copy(&me_src->pdata, &me_dst->pdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totpoly);
+ const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, mask, alloc_type, me_dst->totvert);
+ CustomData_copy(&me_src->edata, &me_dst->edata, mask, alloc_type, me_dst->totedge);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, mask, alloc_type, me_dst->totloop);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, mask, alloc_type, me_dst->totpoly);
if (do_tessface) {
- CustomData_copy(&me_src->fdata, &me_dst->fdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totface);
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, mask, alloc_type, me_dst->totface);
}
else {
mesh_tessface_clear_intern(me_dst, false);
@@ -512,159 +560,262 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int
me_dst->edit_btmesh = NULL;
+ /* Call BKE_mesh_runtime_reset? */
+ me_dst->runtime.batch_cache = NULL;
+ me_dst->runtime.looptris.array = NULL;
+ me_dst->runtime.bvh_cache = NULL;
+
+ if (me_src->id.tag & LIB_TAG_NO_MAIN) {
+ me_dst->runtime.deformed_only = me_src->runtime.deformed_only;
+ }
+ else {
+ /* This is a direct copy of a main mesh, so for now it has the same topology. */
+ me_dst->runtime.deformed_only = 1;
+ }
+
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
me_dst->bb = MEM_dupallocN(me_dst->bb);
/* TODO Do we want to add flag to prevent this? */
- if (me_src->key) {
+ if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag, false);
}
}
+/* Custom data layer functions; those assume that totXXX are set correctly. */
+static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface)
+{
+ if (!CustomData_get_layer(&mesh->vdata, CD_MVERT))
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+ if (!CustomData_get_layer(&mesh->edata, CD_MEDGE))
+ CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+ if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP))
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
+ if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY))
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
+
+ if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE))
+ CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface);
+}
+static void mesh_ensure_cdlayers_origindex(Mesh *mesh, bool do_tessface)
+{
+ if (!CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
+ if (!CustomData_get_layer(&mesh->edata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
+ if (!CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly);
+
+ if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->fdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
+}
+
+Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
+{
+ Mesh *mesh = BKE_libblock_alloc(
+ NULL, ID_ME,
+ BKE_idcode_to_name(ID_ME),
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG);
+ BKE_libblock_init_empty(&mesh->id);
+
+ /* don't use CustomData_reset(...); because we dont want to touch customdata */
+ copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1);
+
+ mesh->totvert = verts_len;
+ mesh->totedge = edges_len;
+ mesh->totface = tessface_len;
+ mesh->totloop = loops_len;
+ mesh->totpoly = polys_len;
+
+ mesh_ensure_cdlayers_primary(mesh, true);
+ mesh_ensure_cdlayers_origindex(mesh, true);
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ return mesh;
+}
+
+static Mesh *mesh_new_nomain_from_template_ex(
+ const Mesh *me_src,
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len,
+ CustomDataMask mask)
+{
+ const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */
+
+ Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
+
+ me_dst->mat = MEM_dupallocN(me_src->mat);
+ me_dst->mselect = MEM_dupallocN(me_dst->mselect);
+
+ me_dst->totvert = verts_len;
+ me_dst->totedge = edges_len;
+ me_dst->totface = tessface_len;
+ me_dst->totloop = loops_len;
+ me_dst->totpoly = polys_len;
+
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, mask, CD_CALLOC, verts_len);
+ CustomData_copy(&me_src->edata, &me_dst->edata, mask, CD_CALLOC, edges_len);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, mask, CD_CALLOC, loops_len);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, mask, CD_CALLOC, polys_len);
+ if (do_tessface) {
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, mask, CD_CALLOC, tessface_len);
+ }
+ else {
+ mesh_tessface_clear_intern(me_dst, false);
+ }
+
+ /* The destination mesh should at least have valid primary CD layers,
+ * even in cases where the source mesh does not. */
+ mesh_ensure_cdlayers_primary(me_dst, do_tessface);
+ mesh_ensure_cdlayers_origindex(me_dst, false);
+ BKE_mesh_update_customdata_pointers(me_dst, false);
+
+ return me_dst;
+}
+
+Mesh * BKE_mesh_new_nomain_from_template(
+ const Mesh *me_src,
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len)
+{
+ return mesh_new_nomain_from_template_ex(
+ me_src,
+ verts_len, edges_len, tessface_len,
+ loops_len, polys_len,
+ CD_MASK_EVERYTHING);
+}
+
Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me)
{
Mesh *me_copy;
- BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, 0, false);
+ BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, LIB_ID_COPY_SHAPEKEY, false);
return me_copy;
}
-BMesh *BKE_mesh_to_bmesh(
- Mesh *me, Object *ob,
- const bool add_key_index, const struct BMeshCreateParams *params)
+BMesh *BKE_mesh_to_bmesh_ex(
+ Mesh *me,
+ const struct BMeshCreateParams *create_params,
+ const struct BMeshFromMeshParams *convert_params)
{
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
- bm = BM_mesh_create(&allocsize, params);
-
- BM_mesh_bm_from_me(
- bm, me, (&(struct BMeshFromMeshParams){
- .add_key_index = add_key_index, .use_shapekey = true, .active_shapekey = ob->shapenr,
- }));
+ bm = BM_mesh_create(&allocsize, create_params);
+ BM_mesh_bm_from_me(bm, me, convert_params);
return bm;
}
+BMesh *BKE_mesh_to_bmesh(
+ Mesh *me, Object *ob,
+ const bool add_key_index, const struct BMeshCreateParams *params)
+{
+ return BKE_mesh_to_bmesh_ex(
+ me, params,
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = false,
+ .add_key_index = add_key_index,
+ .use_shapekey = true,
+ .active_shapekey = ob->shapenr,
+ });
+}
+
+Mesh *BKE_bmesh_to_mesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params)
+{
+ BLI_assert(params->calc_object_remap == false);
+ Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
+ BM_mesh_bm_to_me(NULL, bm, mesh, params);
+ return mesh;
+}
+
void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &me->id, true, lib_local);
}
-bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int loop_index, const int face_index,
- const char *new_name, const bool do_tessface)
+bool BKE_mesh_uv_cdlayer_rename_index(
+ Mesh *me, const int loop_index, const int face_index,
+ const char *new_name, const bool do_tessface)
{
- CustomData *pdata, *ldata, *fdata;
- CustomDataLayer *cdlp, *cdlu, *cdlf;
- const int step = do_tessface ? 3 : 2;
- int i;
+ CustomData *ldata, *fdata;
+ CustomDataLayer *cdlu, *cdlf;
if (me->edit_btmesh) {
- pdata = &me->edit_btmesh->bm->pdata;
ldata = &me->edit_btmesh->bm->ldata;
fdata = NULL; /* No tessellated data in BMesh! */
}
else {
- pdata = &me->pdata;
ldata = &me->ldata;
fdata = &me->fdata;
}
- cdlp = &pdata->layers[poly_index];
+
cdlu = &ldata->layers[loop_index];
- cdlf = fdata && do_tessface ? &fdata->layers[face_index] : NULL;
+ cdlf = (face_index != -1) && fdata && do_tessface ? &fdata->layers[face_index] : NULL;
- if (cdlp->name != new_name) {
+ if (cdlu->name != new_name) {
/* Mesh validate passes a name from the CD layer as the new name,
* Avoid memcpy from self to self in this case.
*/
- BLI_strncpy(cdlp->name, new_name, sizeof(cdlp->name));
- CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers);
+ BLI_strncpy(cdlu->name, new_name, sizeof(cdlu->name));
+ CustomData_set_layer_unique_name(ldata, loop_index);
}
- /* Loop until we do have exactly the same name for all layers! */
- for (i = 1; !STREQ(cdlp->name, cdlu->name) || (cdlf && !STREQ(cdlp->name, cdlf->name)); i++) {
- switch (i % step) {
- case 0:
- BLI_strncpy(cdlp->name, cdlu->name, sizeof(cdlp->name));
- CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers);
- break;
- case 1:
- BLI_strncpy(cdlu->name, cdlp->name, sizeof(cdlu->name));
- CustomData_set_layer_unique_name(ldata, cdlu - ldata->layers);
- break;
- case 2:
- if (cdlf) {
- BLI_strncpy(cdlf->name, cdlp->name, sizeof(cdlf->name));
- CustomData_set_layer_unique_name(fdata, cdlf - fdata->layers);
- }
- break;
- }
+ if (cdlf == NULL) {
+ return false;
}
+ BLI_strncpy(cdlf->name, cdlu->name, sizeof(cdlf->name));
+ CustomData_set_layer_unique_name(fdata, face_index);
+
return true;
}
bool BKE_mesh_uv_cdlayer_rename(Mesh *me, const char *old_name, const char *new_name, bool do_tessface)
{
- CustomData *pdata, *ldata, *fdata;
+ CustomData *ldata, *fdata;
if (me->edit_btmesh) {
- pdata = &me->edit_btmesh->bm->pdata;
ldata = &me->edit_btmesh->bm->ldata;
/* No tessellated data in BMesh! */
fdata = NULL;
do_tessface = false;
}
else {
- pdata = &me->pdata;
ldata = &me->ldata;
fdata = &me->fdata;
do_tessface = (do_tessface && fdata->totlayer);
}
{
- const int pidx_start = CustomData_get_layer_index(pdata, CD_MTEXPOLY);
const int lidx_start = CustomData_get_layer_index(ldata, CD_MLOOPUV);
const int fidx_start = do_tessface ? CustomData_get_layer_index(fdata, CD_MTFACE) : -1;
- int pidx = CustomData_get_named_layer(pdata, CD_MTEXPOLY, old_name);
int lidx = CustomData_get_named_layer(ldata, CD_MLOOPUV, old_name);
int fidx = do_tessface ? CustomData_get_named_layer(fdata, CD_MTFACE, old_name) : -1;
/* None of those cases should happen, in theory!
* Note this assume we have the same number of mtexpoly, mloopuv and mtface layers!
*/
- if (pidx == -1) {
- if (lidx == -1) {
- if (fidx == -1) {
- /* No layer found with this name! */
- return false;
- }
- else {
- lidx = fidx;
- }
+ if (lidx == -1) {
+ if (fidx == -1) {
+ /* No layer found with this name! */
+ return false;
}
- pidx = lidx;
- }
- else {
- if (lidx == -1) {
- lidx = pidx;
- }
- if (fidx == -1 && do_tessface) {
- fidx = pidx;
+ else {
+ lidx = fidx;
}
}
-#if 0
- /* For now, we do not consider mismatch in indices (i.e. same name leading to (relative) different indices). */
- else if (pidx != lidx) {
- lidx = pidx;
- }
-#endif
/* Go back to absolute indices! */
- pidx += pidx_start;
lidx += lidx_start;
if (fidx != -1)
fidx += fidx_start;
- return BKE_mesh_uv_cdlayer_rename_index(me, pidx, lidx, fidx, new_name, do_tessface);
+ return BKE_mesh_uv_cdlayer_rename_index(me, lidx, fidx, new_name, do_tessface);
}
}
@@ -742,6 +893,18 @@ void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_siz
if (r_size) copy_v3_v3(r_size, me->size);
}
+void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size)
+{
+ if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(me);
+ }
+
+ if (r_texflag != NULL) *r_texflag = &me->texflag;
+ if (r_loc != NULL) *r_loc = me->loc;
+ if (r_rot != NULL) *r_rot = me->rot;
+ if (r_size != NULL) *r_size = me->size;
+}
+
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
{
float *texloc, *texrot, *texsize;
@@ -901,7 +1064,6 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
test_object_modifiers(ob);
}
-
void BKE_mesh_material_index_remove(Mesh *me, short index)
{
MPoly *mp;
@@ -996,15 +1158,15 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
/**
* Return a newly MEM_malloc'd array of all the mesh vertex locations
- * \note \a r_numVerts may be NULL
+ * \note \a r_verts_len may be NULL
*/
-float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3]
+float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_verts_len))[3]
{
- int i, numVerts = me->totvert;
- float (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "vertexcos1");
+ int i, verts_len = me->totvert;
+ float (*cos)[3] = MEM_malloc_arrayN(verts_len, sizeof(*cos), "vertexcos1");
- if (r_numVerts) *r_numVerts = numVerts;
- for (i = 0; i < numVerts; i++)
+ if (r_verts_len) *r_verts_len = verts_len;
+ for (i = 0; i < verts_len; i++)
copy_v3_v3(cos[i], me->mvert[i].co);
return cos;
@@ -1135,13 +1297,13 @@ void BKE_mesh_ensure_navmesh(Mesh *me)
{
if (!CustomData_has_layer(&me->pdata, CD_RECAST)) {
int i;
- int numFaces = me->totpoly;
+ int polys_len = me->totpoly;
int *recastData;
- recastData = (int *)MEM_malloc_arrayN(numFaces, sizeof(int), __func__);
- for (i = 0; i < numFaces; i++) {
+ recastData = (int *)MEM_malloc_arrayN(polys_len, sizeof(int), __func__);
+ for (i = 0; i < polys_len; i++) {
recastData[i] = i + 1;
}
- CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_ASSIGN, recastData, numFaces, "recastData");
+ CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_ASSIGN, recastData, polys_len, "recastData");
}
}
@@ -1332,6 +1494,22 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
(me->mselect[me->totselect - 1].type == type));
}
+
+void BKE_mesh_apply_vert_coords(Mesh *mesh, float (*vertCoords)[3])
+{
+ MVert *vert;
+ int i;
+
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ mesh->mvert = vert;
+
+ for (i = 0; i < mesh->totvert; ++i, ++vert)
+ copy_v3_v3(vert->co, vertCoords[i]);
+
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+}
+
/**
* Compute 'split' (aka loop, or per face corner's) normals.
*
@@ -1383,6 +1561,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
if (free_polynors) {
MEM_freeN(polynors);
}
+
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_split(Mesh *mesh)
@@ -1416,25 +1596,25 @@ static int split_faces_prepare_new_verts(
* dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */
BLI_assert(lnors_spacearr != NULL);
- const int num_loops = mesh->totloop;
- int num_verts = mesh->totvert;
+ const int loops_len = mesh->totloop;
+ int verts_len = mesh->totvert;
MVert *mvert = mesh->mvert;
MLoop *mloop = mesh->mloop;
- BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__);
- BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
+ BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__);
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__);
MLoop *ml = mloop;
MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX);
- for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) {
+ for (int loop_idx = 0; loop_idx < loops_len; loop_idx++, ml++, lnor_space++) {
if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
const int vert_idx = ml->v;
const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
/* If vert is already used by another smooth fan, we need a new vert for this one. */
- const int new_vert_idx = vert_used ? num_verts++ : vert_idx;
+ const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
BLI_assert(*lnor_space);
@@ -1479,7 +1659,7 @@ static int split_faces_prepare_new_verts(
MEM_freeN(done_loops);
MEM_freeN(verts_used);
- return num_verts - mesh->totvert;
+ return verts_len - mesh->totvert;
}
/* Detect needed new edges, and update accordingly loops' edge indices.
@@ -1547,12 +1727,12 @@ static int split_faces_prepare_new_edges(
static void split_faces_split_new_verts(
Mesh *mesh, SplitFaceNewVert *new_verts, const int num_new_verts)
{
- const int num_verts = mesh->totvert - num_new_verts;
+ const int verts_len = mesh->totvert - num_new_verts;
MVert *mvert = mesh->mvert;
/* Remember new_verts is a single linklist, so its items are in reversed order... */
MVert *new_mv = &mvert[mesh->totvert - 1];
- for (int i = mesh->totvert - 1; i >= num_verts ; i--, new_mv--, new_verts = new_verts->next) {
+ for (int i = mesh->totvert - 1; i >= verts_len ; i--, new_mv--, new_verts = new_verts->next) {
BLI_assert(new_verts->new_index == i);
BLI_assert(new_verts->new_index != new_verts->orig_index);
CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
@@ -1647,13 +1827,12 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
#endif
}
-
/* **** Depsgraph evaluation **** */
-void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+void BKE_mesh_eval_geometry(Depsgraph *depsgraph,
Mesh *mesh)
{
- DEG_debug_print_eval(__func__, mesh->id.name, mesh);
+ DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
BKE_mesh_texspace_calc(mesh);
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index d376c90f1c2..3fc5d1ca51c 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -22,9 +22,11 @@
* \ingroup bke
*/
+
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
+#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
@@ -39,24 +41,33 @@
#include "BKE_main.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_key.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
#include "BKE_displist.h"
#include "BKE_library.h"
#include "BKE_material.h"
-#include "BKE_modifier.h"
#include "BKE_mball.h"
-#include "BKE_depsgraph.h"
+/* these 2 are only used by conversion functions */
#include "BKE_curve.h"
/* -- */
#include "BKE_object.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
/* Define for cases when you want extra validation of mesh
* after certain modifications.
*/
// #undef VALIDATE_MESH
+#ifdef VALIDATE_MESH
+# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
+#else
+# define ASSERT_IS_VALID_MESH(mesh)
+#endif
+
void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
{
DispList *dl;
@@ -479,10 +490,62 @@ int BKE_mesh_nurbs_displist_to_mdata(
return 0;
}
+Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
+{
+ Curve *cu = ob->data;
+ Mesh *mesh;
+ MVert *allvert;
+ MEdge *alledge;
+ MLoop *allloop;
+ MPoly *allpoly;
+ MLoopUV *alluv = NULL;
+ int totvert, totedge, totloop, totpoly;
+ bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
+
+ if (BKE_mesh_nurbs_displist_to_mdata(
+ ob, dispbase, &allvert, &totvert, &alledge,
+ &totedge, &allloop, &allpoly, (use_orco_uv) ? &alluv : NULL,
+ &totloop, &totpoly) != 0)
+ {
+ /* Error initializing mdata. This often happens when curve is empty */
+ return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
+ }
+
+ mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly);
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ memcpy(mesh->mvert, allvert, totvert * sizeof(MVert));
+ memcpy(mesh->medge, alledge, totedge * sizeof(MEdge));
+ memcpy(mesh->mloop, allloop, totloop * sizeof(MLoop));
+ memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));
+
+ if (alluv) {
+ const char *uvname = "Orco";
+ CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
+ }
+
+ MEM_freeN(allvert);
+ MEM_freeN(alledge);
+ MEM_freeN(allloop);
+ MEM_freeN(allpoly);
+
+ return mesh;
+}
+
+Mesh *BKE_mesh_new_nomain_from_curve(Object *ob)
+{
+ ListBase disp = {NULL, NULL};
+
+ if (ob->curve_cache) {
+ disp = ob->curve_cache->disp;
+ }
+
+ return BKE_mesh_new_nomain_from_curve_displist(ob, &disp);
+}
/* this may fail replacing ob->data, be sure to check ob->type */
void BKE_mesh_from_nurbs_displist(
- Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name)
+ Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary)
{
Object *ob1;
DerivedMesh *dm = ob->derivedFinal;
@@ -521,7 +584,6 @@ void BKE_mesh_from_nurbs_displist(
if (alluv) {
const char *uvname = "Orco";
- me->mtpoly = CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname);
me->mloopuv = CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
}
@@ -568,7 +630,16 @@ void BKE_mesh_from_nurbs_displist(
ob1 = ob1->id.next;
}
- BKE_libblock_free_us(bmain, cu);
+ if (temporary) {
+ /* For temporary objects in BKE_mesh_new_from_object don't remap
+ * the entire scene with associated depsgraph updates, which are
+ * problematic for renderers exporting data. */
+ id_us_min(&cu->id);
+ BKE_libblock_free(bmain, cu);
+ }
+ else {
+ BKE_libblock_free_us(bmain, cu);
+ }
}
void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
@@ -581,7 +652,7 @@ void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
disp = ob->curve_cache->disp;
}
- BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name);
+ BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false);
}
typedef struct EdgeLink {
@@ -608,15 +679,15 @@ static void appendPolyLineVert(ListBase *lb, unsigned int index)
BLI_addtail(lb, vl);
}
-void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int edge_users_test)
+void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int edge_users_test)
{
- MVert *mvert = dm->getVertArray(dm);
- MEdge *med, *medge = dm->getEdgeArray(dm);
- MPoly *mp, *mpoly = dm->getPolyArray(dm);
- MLoop *mloop = dm->getLoopArray(dm);
+ MVert *mvert = me->mvert;
+ MEdge *med, *medge = me->medge;
+ MPoly *mp, *mpoly = me->mpoly;
+ MLoop *mloop = me->mloop;
- int dm_totedge = dm->getNumEdges(dm);
- int dm_totpoly = dm->getNumPolys(dm);
+ int medge_len = me->totedge;
+ int mpoly_len = me->totpoly;
int totedges = 0;
int i;
@@ -626,8 +697,8 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
ListBase edges = {NULL, NULL};
/* get boundary edges */
- edge_users = MEM_calloc_arrayN(dm_totedge, sizeof(int), __func__);
- for (i = 0, mp = mpoly; i < dm_totpoly; i++, mp++) {
+ edge_users = MEM_calloc_arrayN(medge_len, sizeof(int), __func__);
+ for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
MLoop *ml = &mloop[mp->loopstart];
int j;
for (j = 0; j < mp->totloop; j++, ml++) {
@@ -637,7 +708,7 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
/* create edges from all faces (so as to find edges not in any faces) */
med = medge;
- for (i = 0; i < dm_totedge; i++, med++) {
+ for (i = 0; i < medge_len; i++, med++) {
if (edge_users[i] == edge_users_test) {
EdgeLink *edl = MEM_callocN(sizeof(EdgeLink), "EdgeLink");
edl->edge = med;
@@ -741,15 +812,14 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
}
}
-void BKE_mesh_to_curve(Main *bmain, Scene *scene, Object *ob)
+void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
/* make new mesh data from the original copy */
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_MESH);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_MESH);
ListBase nurblist = {NULL, NULL};
- bool needsFree = false;
- BKE_mesh_to_curve_nurblist(dm, &nurblist, 0);
- BKE_mesh_to_curve_nurblist(dm, &nurblist, 1);
+ BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 0);
+ BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 1);
if (nurblist.first) {
Curve *cu = BKE_curve_add(bmain, ob->id.name + 2, OB_CURVE);
@@ -761,33 +831,19 @@ void BKE_mesh_to_curve(Main *bmain, Scene *scene, Object *ob)
ob->data = cu;
ob->type = OB_CURVE;
- /* curve objects can't contain DM in usual cases, we could free memory */
- needsFree = true;
- }
-
- dm->needsFree = needsFree;
- dm->release(dm);
-
- if (needsFree) {
- ob->derivedFinal = NULL;
-
- /* curve object could have got bounding box only in special cases */
- if (ob->bb) {
- MEM_freeN(ob->bb);
- ob->bb = NULL;
- }
+ BKE_object_free_derived_caches(ob);
}
}
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_object(
- Main *bmain, Scene *sce, Object *ob,
- int apply_modifiers, int settings, int calc_tessface, int calc_undeformed)
+ Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob,
+ const bool apply_modifiers, const bool calc_tessface, const bool calc_undeformed)
{
Mesh *tmpmesh;
Curve *tmpcu = NULL, *copycu;
int i;
- const bool render = (settings == eModifierMode_Render);
+ const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const bool cage = !apply_modifiers;
bool do_mat_id_data_us = true;
@@ -804,9 +860,8 @@ Mesh *BKE_mesh_new_from_object(
/* copies object and modifiers (but not the data) */
Object *tmpobj;
/* TODO: make it temp copy outside bmain! */
- BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES, false);
+ BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES | LIB_ID_CREATE_NO_DEG_TAG, false);
tmpcu = (Curve *)tmpobj->data;
- id_us_min(&tmpcu->id);
/* Copy cached display list, it might be needed by the stack evaluation.
* Ideally stack should be able to use render-time display list, but doing
@@ -826,7 +881,8 @@ Mesh *BKE_mesh_new_from_object(
BKE_object_free_modifiers(tmpobj, 0);
/* copies the data */
- copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data);
+ BKE_id_copy_ex(bmain, ob->data, (ID **)&copycu, LIB_ID_CREATE_NO_DEG_TAG, false);
+ tmpobj->data = copycu;
/* make sure texture space is calculated for a copy of curve,
* it will be used for the final result.
@@ -840,7 +896,7 @@ Mesh *BKE_mesh_new_from_object(
copycu->editnurb = tmpcu->editnurb;
/* get updated display list, and convert to a mesh */
- BKE_displist_make_curveTypes_forRender(sce, tmpobj, &dispbase, &derivedFinal, false, render);
+ BKE_displist_make_curveTypes_forRender(depsgraph, sce, tmpobj, &dispbase, &derivedFinal, false, render);
copycu->editfont = NULL;
copycu->editnurb = NULL;
@@ -849,7 +905,7 @@ Mesh *BKE_mesh_new_from_object(
/* convert object type to mesh */
uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
- BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2);
+ BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true);
tmpmesh = tmpobj->data;
@@ -859,11 +915,11 @@ Mesh *BKE_mesh_new_from_object(
* if it didn't the curve did not have any segments or otherwise
* would have generated an empty mesh */
if (tmpobj->type != OB_MESH) {
- BKE_libblock_free_us(bmain, tmpobj);
+ BKE_libblock_free(bmain, tmpobj);
return NULL;
}
- BKE_libblock_free_us(bmain, tmpobj);
+ BKE_libblock_free(bmain, tmpobj);
/* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist()
* already transfers the ownership of materials from the temp copy of the Curve ID to the new
@@ -876,7 +932,7 @@ Mesh *BKE_mesh_new_from_object(
case OB_MBALL:
{
/* metaballs don't have modifiers, so just convert to mesh */
- Object *basis_ob = BKE_mball_basis_find(bmain, bmain->eval_ctx, sce, ob);
+ Object *basis_ob = BKE_mball_basis_find(sce, ob);
/* todo, re-generatre for render-res */
/* metaball_polygonize(scene, ob) */
@@ -889,13 +945,7 @@ Mesh *BKE_mesh_new_from_object(
if (render) {
ListBase disp = {NULL, NULL};
- /* TODO(sergey): This is gonna to work for until EvaluationContext
- * only contains for_render flag. As soon as CoW is
- * implemented, this is to be rethought.
- */
- EvaluationContext eval_ctx;
- DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER);
- BKE_displist_make_mball_forRender(bmain, &eval_ctx, sce, ob, &disp);
+ BKE_displist_make_mball_forRender(depsgraph, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
}
@@ -934,9 +984,9 @@ Mesh *BKE_mesh_new_from_object(
/* Write the display mesh into the dummy mesh */
if (render)
- dm = mesh_create_derived_render(sce, ob, mask);
+ dm = mesh_create_derived_render(depsgraph, sce, ob, mask);
else
- dm = mesh_create_derived_view(sce, ob, mask);
+ dm = mesh_create_derived_view(depsgraph, sce, ob, mask);
tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
DM_to_mesh(dm, tmpmesh, ob, mask, true);
@@ -1024,3 +1074,339 @@ Mesh *BKE_mesh_new_from_object(
return tmpmesh;
}
+
+
+static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
+{
+ KeyBlock *kb;
+ Key *key = mesh_src->key;
+ int i;
+
+ if (!mesh_src->key)
+ return;
+
+ /* ensure we can use mesh vertex count for derived mesh custom data */
+ if (mesh_src->totvert != mesh_dest->totvert) {
+ fprintf(stderr,
+ "%s: vertex size mismatch (mesh/dm) '%s' (%d != %d)\n",
+ __func__, mesh_src->id.name + 2, mesh_src->totvert, mesh_dest->totvert);
+ return;
+ }
+
+ for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) {
+ int ci;
+ float *array;
+
+ if (mesh_src->totvert != kb->totelem) {
+ fprintf(stderr,
+ "%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n",
+ __func__, mesh_src->id.name + 2, mesh_src->totvert, kb->name, kb->totelem);
+ array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
+ }
+ else {
+ array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
+ memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float));
+ }
+
+ CustomData_add_layer_named(&mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name);
+ ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i);
+
+ mesh_dest->vdata.layers[ci].uid = kb->uid;
+ }
+}
+
+
+Mesh *BKE_mesh_create_derived_for_modifier(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ ModifierData *md, int build_shapekey_layers)
+{
+ Mesh *me = ob->data;
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ Mesh *result;
+ KeyBlock *kb;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
+
+ if (!(md->mode & eModifierMode_Realtime)) {
+ return NULL;
+ }
+
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
+ return NULL;
+ }
+
+ if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) {
+ BKE_keyblock_convert_to_mesh(kb, me);
+ }
+
+ if (mti->type == eModifierTypeType_OnlyDeform) {
+ int numVerts;
+ float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts);
+
+ modifier_deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
+ BKE_id_copy_ex(NULL, &me->id, (ID **)&result,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_mesh_apply_vert_coords(result, deformedVerts);
+
+ if (build_shapekey_layers)
+ add_shapekey_layers(result, me);
+
+ MEM_freeN(deformedVerts);
+ }
+ else {
+ Mesh *mesh_temp;
+ BKE_id_copy_ex(NULL, &me->id, (ID **)&mesh_temp,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+
+ if (build_shapekey_layers)
+ add_shapekey_layers(mesh_temp, me);
+
+ result = modifier_applyModifier(md, &mectx, mesh_temp);
+ ASSERT_IS_VALID_MESH(result);
+
+ if (mesh_temp != result) {
+ BKE_id_free(NULL, mesh_temp);
+ }
+ }
+
+ return result;
+}
+
+/* This is a Mesh-based copy of the same function in DerivedMesh.c */
+static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid)
+{
+ KeyBlock *kb;
+ int i, j, tot;
+
+ if (!mesh_dst->key)
+ return;
+
+ tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY);
+ for (i = 0; i < tot; i++) {
+ CustomDataLayer *layer = &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)];
+ float (*cos)[3], (*kbcos)[3];
+
+ for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ if (kb->uid == layer->uid)
+ break;
+ }
+
+ if (!kb) {
+ kb = BKE_keyblock_add(mesh_dst->key, layer->name);
+ kb->uid = layer->uid;
+ }
+
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i);
+ kb->totelem = mesh_src->totvert;
+
+ kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
+ if (kb->uid == actshape_uid) {
+ MVert *mvert = mesh_src->mvert;
+
+ for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) {
+ copy_v3_v3(*kbcos, mvert->co);
+ }
+ }
+ else {
+ for (j = 0; j < kb->totelem; j++, cos++, kbcos++) {
+ copy_v3_v3(*kbcos, *cos);
+ }
+ }
+ }
+
+ for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ if (kb->totelem != mesh_src->totvert) {
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ kb->totelem = mesh_src->totvert;
+ kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
+ fprintf(stderr, "%s: lost a shapekey layer: '%s'! (bmesh internal error)\n", __func__, kb->name);
+ }
+ }
+}
+
+
+/* This is a Mesh-based copy of DM_to_mesh() */
+void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomDataMask mask, bool take_ownership)
+{
+ /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
+ /* TODO(Sybren): the above claim came from DM_to_mesh(); check whether it is still true with Mesh */
+ Mesh tmp = *mesh_dst;
+ int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
+ int did_shapekeys = 0;
+ eCDAllocType alloctype = CD_DUPLICATE;
+
+ if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) {
+ bool has_any_referenced_layers =
+ CustomData_has_referenced(&mesh_src->vdata) ||
+ CustomData_has_referenced(&mesh_src->edata) ||
+ CustomData_has_referenced(&mesh_src->ldata) ||
+ CustomData_has_referenced(&mesh_src->fdata) ||
+ CustomData_has_referenced(&mesh_src->pdata);
+ if (!has_any_referenced_layers) {
+ alloctype = CD_ASSIGN;
+ }
+ }
+ CustomData_reset(&tmp.vdata);
+ CustomData_reset(&tmp.edata);
+ CustomData_reset(&tmp.fdata);
+ CustomData_reset(&tmp.ldata);
+ CustomData_reset(&tmp.pdata);
+
+ BKE_mesh_ensure_normals(mesh_src);
+
+ totvert = tmp.totvert = mesh_src->totvert;
+ totedge = tmp.totedge = mesh_src->totedge;
+ totloop = tmp.totloop = mesh_src->totloop;
+ totpoly = tmp.totpoly = mesh_src->totpoly;
+ tmp.totface = 0;
+
+ CustomData_copy(&mesh_src->vdata, &tmp.vdata, mask, alloctype, totvert);
+ CustomData_copy(&mesh_src->edata, &tmp.edata, mask, alloctype, totedge);
+ CustomData_copy(&mesh_src->ldata, &tmp.ldata, mask, alloctype, totloop);
+ CustomData_copy(&mesh_src->pdata, &tmp.pdata, mask, alloctype, totpoly);
+ tmp.cd_flag = mesh_src->cd_flag;
+ tmp.runtime.deformed_only = mesh_src->runtime.deformed_only;
+
+ if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
+ KeyBlock *kb;
+ int uid;
+
+ if (ob) {
+ kb = BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1);
+ if (kb) {
+ uid = kb->uid;
+ }
+ else {
+ printf("%s: error - could not find active shapekey %d!\n",
+ __func__, ob->shapenr - 1);
+
+ uid = INT_MAX;
+ }
+ }
+ else {
+ /* if no object, set to INT_MAX so we don't mess up any shapekey layers */
+ uid = INT_MAX;
+ }
+
+ shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid);
+ did_shapekeys = 1;
+ }
+
+ /* copy texture space */
+ if (ob) {
+ BKE_mesh_texspace_copy_from_object(&tmp, ob);
+ }
+
+ /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
+ * we set them here in case they are missing */
+ /* TODO(Sybren): we could probably replace CD_ASSIGN with alloctype and always directly pass mesh_src->mxxx,
+ * instead of using a ternary operator. */
+ if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) {
+ CustomData_add_layer(&tmp.vdata, CD_MVERT, CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->mvert : MEM_dupallocN(mesh_src->mvert),
+ totvert);
+ }
+ if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) {
+ CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->medge : MEM_dupallocN(mesh_src->medge),
+ totedge);
+ }
+ if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
+ /* TODO(Sybren): assigment to tmp.mxxx is probably not necessary due to the
+ * BKE_mesh_update_customdata_pointers() call below. */
+ tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop);
+ tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly);
+
+ CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
+ CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
+ }
+
+ /* object had got displacement layer, should copy this layer to save sculpted data */
+ /* NOTE: maybe some other layers should be copied? nazgul */
+ if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) {
+ if (totloop == mesh_dst->totloop) {
+ MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS);
+ CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
+ }
+ }
+
+ /* yes, must be before _and_ after tessellate */
+ BKE_mesh_update_customdata_pointers(&tmp, false);
+
+ /* since 2.65 caller must do! */
+ // BKE_mesh_tessface_calc(&tmp);
+
+ CustomData_free(&mesh_dst->vdata, mesh_dst->totvert);
+ CustomData_free(&mesh_dst->edata, mesh_dst->totedge);
+ CustomData_free(&mesh_dst->fdata, mesh_dst->totface);
+ CustomData_free(&mesh_dst->ldata, mesh_dst->totloop);
+ CustomData_free(&mesh_dst->pdata, mesh_dst->totpoly);
+
+ /* ok, this should now use new CD shapekey data,
+ * which should be fed through the modifier
+ * stack */
+ if (tmp.totvert != mesh_dst->totvert && !did_shapekeys && mesh_dst->key) {
+ printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name);
+ if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
+ id_us_min(&tmp.key->id);
+ }
+ tmp.key = NULL;
+ }
+
+ /* Clear selection history */
+ MEM_SAFE_FREE(tmp.mselect);
+ tmp.totselect = 0;
+ BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb));
+ if (mesh_dst->bb) {
+ MEM_freeN(mesh_dst->bb);
+ tmp.bb = NULL;
+ }
+
+ /* skip the listbase */
+ MEMCPY_STRUCT_OFS(mesh_dst, &tmp, id.prev);
+
+ if (take_ownership) {
+ if (alloctype == CD_ASSIGN) {
+ CustomData_free_typemask(&mesh_src->vdata, mesh_src->totvert, ~mask);
+ CustomData_free_typemask(&mesh_src->edata, mesh_src->totedge, ~mask);
+ CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask);
+ CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask);
+ }
+ BKE_id_free(NULL, mesh_src);
+ }
+}
+
+/* This is a Mesh-based copy of DM_to_meshkey() */
+void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
+{
+ int a, totvert = mesh_src->totvert;
+ float *fp;
+ MVert *mvert;
+
+ if (totvert == 0 || mesh_dst->totvert == 0 || mesh_dst->totvert != totvert) {
+ return;
+ }
+
+ if (kb->data) MEM_freeN(kb->data);
+ kb->data = MEM_malloc_arrayN(mesh_dst->key->elemsize, mesh_dst->totvert, "kb->data");
+ kb->totelem = totvert;
+
+ fp = kb->data;
+ mvert = mesh_src->mvert;
+
+ for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) {
+ copy_v3_v3(fp, mvert->co);
+ }
+}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 0c6693be3af..8194e21cbb1 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -88,6 +88,20 @@ static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts)
}
}
+/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(),
+ * and remove the function of the same name below, as that one doesn't seem to be
+ * called anywhere. */
+void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh)
+{
+ const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT);
+
+ BKE_mesh_calc_normals_mapping_ex(
+ mesh->mvert, mesh->totvert,
+ mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL,
+ mesh->mface, mesh->totface, NULL, NULL,
+ only_face_normals);
+}
+
/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-NULL
* and vertex normals are stored in actual mverts.
*/
@@ -332,6 +346,15 @@ void BKE_mesh_calc_normals_poly(
MEM_freeN(lnors_weighted);
}
+void BKE_mesh_ensure_normals(Mesh *mesh)
+{
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ BKE_mesh_calc_normals(mesh);
+ }
+ BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
+}
+
+/* Note that this does not update the CD_NORMAL layer, but does update the normals in the CD_MVERT layer. */
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
@@ -343,6 +366,7 @@ void BKE_mesh_calc_normals(Mesh *mesh)
#ifdef DEBUG_TIME
TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_tessface(
@@ -1828,152 +1852,6 @@ void BKE_mesh_normals_loop_to_vertex(
/* -------------------------------------------------------------------- */
-/** \name Mesh Tangent Calculations
- * \{ */
-
-/* Tangent space utils. */
-
-/* User data. */
-typedef struct {
- const MPoly *mpolys; /* faces */
- const MLoop *mloops; /* faces's vertices */
- const MVert *mverts; /* vertices */
- const MLoopUV *luvs; /* texture coordinates */
- float (*lnors)[3]; /* loops' normals */
- float (*tangents)[4]; /* output tangents */
- int num_polys; /* number of polygons */
-} BKEMeshToTangent;
-
-/* Mikktspace's API */
-static int get_num_faces(const SMikkTSpaceContext *pContext)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- return p_mesh->num_polys;
-}
-
-static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- return p_mesh->mpolys[face_idx].totloop;
-}
-
-static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
- copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
-}
-
-static void get_texture_coordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx,
- const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
-}
-
-static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
-}
-
-static void set_tspace(const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign,
- const int face_idx, const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
- copy_v3_v3(p_res, fv_tangent);
- p_res[3] = face_sign;
-}
-
-/**
- * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
- * split normals can be used to recreate the full tangent space.
- * Note: * The mesh should be made of only tris and quads!
- */
-void BKE_mesh_loop_tangents_ex(
- const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
- float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
- const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
- ReportList *reports)
-{
- BKEMeshToTangent mesh_to_tangent = {NULL};
- SMikkTSpaceContext s_context = {NULL};
- SMikkTSpaceInterface s_interface = {NULL};
-
- const MPoly *mp;
- int mp_index;
-
- /* First check we do have a tris/quads only mesh. */
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- if (mp->totloop > 4) {
- BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
- return;
- }
- }
-
- /* Compute Mikktspace's tangent normals. */
- mesh_to_tangent.mpolys = mpolys;
- mesh_to_tangent.mloops = mloops;
- mesh_to_tangent.mverts = mverts;
- mesh_to_tangent.luvs = loopuvs;
- mesh_to_tangent.lnors = loopnors;
- mesh_to_tangent.tangents = r_looptangent;
- mesh_to_tangent.num_polys = numPolys;
-
- s_context.m_pUserData = &mesh_to_tangent;
- s_context.m_pInterface = &s_interface;
- s_interface.m_getNumFaces = get_num_faces;
- s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
- s_interface.m_getPosition = get_position;
- s_interface.m_getTexCoord = get_texture_coordinate;
- s_interface.m_getNormal = get_normal;
- s_interface.m_setTSpaceBasic = set_tspace;
-
- /* 0 if failed */
- if (genTangSpaceDefault(&s_context) == false) {
- BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
- }
-}
-
-/**
- * Wrapper around BKE_mesh_loop_tangents_ex, which takes care of most boiling code.
- * \note
- * - There must be a valid loop's CD_NORMALS available.
- * - The mesh should be made of only tris and quads!
- */
-void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
-{
- MLoopUV *loopuvs;
- float (*loopnors)[3];
-
- /* Check we have valid texture coordinates first! */
- if (uvmap) {
- loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
- }
- else {
- loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
- }
- if (!loopuvs) {
- BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
- return;
- }
-
- loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- if (!loopnors) {
- BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
- return;
- }
-
- BKE_mesh_loop_tangents_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
- loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
/** \name Polygon Calculations
* \{ */
@@ -2545,12 +2423,12 @@ void BKE_mesh_calc_volume(
*/
void BKE_mesh_loops_to_mface_corners(
CustomData *fdata, CustomData *ldata,
- CustomData *pdata, unsigned int lindex[4], int findex,
- const int polyindex,
+ CustomData *UNUSED(pdata), unsigned int lindex[4], int findex,
+ const int UNUSED(polyindex),
const int mf_len, /* 3 or 4 */
/* cache values to avoid lookups every time */
- const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */
+ const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */
const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */
const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
@@ -2558,17 +2436,13 @@ void BKE_mesh_loops_to_mface_corners(
)
{
MTFace *texface;
- MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
int i, j;
- for (i = 0; i < numTex; i++) {
+ for (i = 0; i < numUV; i++) {
texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
- texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
-
- ME_MTEXFACE_CPY(texface, texpoly);
for (j = 0; j < mf_len; j++) {
mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i);
@@ -2620,14 +2494,14 @@ void BKE_mesh_loops_to_mface_corners(
*
* \note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used.
*/
-void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData *pdata, MFace *mface,
+void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
{
/* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
* Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
* this. Better imho to live with it for now. :/ --mont29
*/
- const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
@@ -2637,17 +2511,14 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData
const int *pidx;
unsigned int (*lidx)[4];
- for (i = 0; i < numTex; i++) {
+ for (i = 0; i < numUV; i++) {
MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
- MTexPoly *texpoly = CustomData_get_layer_n(pdata, CD_MTEXPOLY, i);
MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
for (findex = 0, pidx = polyindices, lidx = loopindices;
findex < num_faces;
pidx++, lidx++, findex++, texface++)
{
- ME_MTEXFACE_CPY(texface, &texpoly[*pidx]);
-
for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
}
@@ -2970,7 +2841,7 @@ int BKE_mesh_recalc_tessellation(
/* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons
* they are directly tessellated from */
CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
- CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
if (do_face_nor_copy) {
/* If polys have a normals layer, copying that to faces can help
@@ -2991,7 +2862,7 @@ int BKE_mesh_recalc_tessellation(
* So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test.
* ...
*/
- BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, NULL, mface_to_poly_map, lindices, totface);
+ BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
/* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
* ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
@@ -3183,7 +3054,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
MPoly *mp, *mpoly;
MFace *mface, *mf;
- const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
@@ -3223,7 +3094,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
- CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
mp = mpoly;
k = 0;
@@ -3245,9 +3116,10 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
mf->v2 = mloop[mf->v2].v;
mf->v3 = mloop[mf->v3].v;
- BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
- lindex, k, i, 3,
- numTex, numCol, hasPCol, hasOrigSpace, hasLNor);
+ BKE_mesh_loops_to_mface_corners(
+ fdata, ldata, pdata,
+ lindex, k, i, 3,
+ numUV, numCol, hasPCol, hasOrigSpace, hasLNor);
test_index_face(mf, fdata, k, 3);
}
else {
@@ -3265,9 +3137,10 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
mf->v3 = mloop[mf->v3].v;
mf->v4 = mloop[mf->v4].v;
- BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
- lindex, k, i, 4,
- numTex, numCol, hasPCol, hasOrigSpace, hasLNor);
+ BKE_mesh_loops_to_mface_corners(
+ fdata, ldata, pdata,
+ lindex, k, i, 4,
+ numUV, numCol, hasPCol, hasOrigSpace, hasLNor);
test_index_face(mf, fdata, k, 4);
}
@@ -3282,11 +3155,11 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
#endif /* USE_BMESH_SAVE_AS_COMPAT */
-static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata,
- MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
+static void bm_corners_to_loops_ex(
+ ID *id, CustomData *fdata, CustomData *ldata,
+ MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
{
MTFace *texface;
- MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
@@ -3297,9 +3170,6 @@ static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata,
for (i = 0; i < numTex; i++) {
texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
- texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, findex, i);
-
- ME_MTEXFACE_CPY(texpoly, texface);
mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++;
@@ -3406,7 +3276,7 @@ void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
mesh->medge, mesh->mface,
&mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly);
- CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->pdata, &mesh->ldata);
+ CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
BKE_mesh_update_customdata_pointers(mesh, true);
}
@@ -3449,7 +3319,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData
CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
- CustomData_to_bmeshpoly(fdata, pdata, ldata, totloop, totpoly);
+ CustomData_to_bmeshpoly(fdata, ldata, totloop);
if (id) {
/* ensure external data is transferred */
@@ -3499,7 +3369,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData
# undef ML
- bm_corners_to_loops_ex(id, fdata, ldata, pdata, mface, totloop, i, mp->loopstart, numTex, numCol);
+ bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
if (polyindex) {
*polyindex = i;
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
new file mode 100644
index 00000000000..48f6b1820f8
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -0,0 +1,154 @@
+/*
+ * ***** 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.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_iterators.c
+ * \ingroup bke
+ *
+ * Functions for iterating mesh features.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
+
+
+/* Copied from cdDM_foreachMappedVert */
+void BKE_mesh_foreach_mapped_vert(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
+ void *userData,
+ MeshForeachFlag flag)
+{
+ MVert *mv = mesh->mvert;
+ const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ int i;
+
+ if (index) {
+ for (i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) continue;
+ func(userData, orig, mv->co, NULL, no);
+ }
+ }
+ else {
+ for (i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ func(userData, i, mv->co, NULL, no);
+ }
+ }
+}
+
+/* Copied from cdDM_foreachMappedEdge */
+void BKE_mesh_foreach_mapped_edge(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
+ void *userData)
+{
+ MVert *mv = mesh->mvert;
+ MEdge *med = mesh->medge;
+ int i, orig, *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
+
+ for (i = 0; i < mesh->totedge; i++, med++) {
+ if (index) {
+ orig = *index++;
+ if (orig == ORIGINDEX_NONE) continue;
+ func(userData, orig, mv[med->v1].co, mv[med->v2].co);
+ }
+ else
+ func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ }
+}
+
+/* Copied from cdDM_foreachMappedLoop */
+void BKE_mesh_foreach_mapped_loop(
+ Mesh *mesh,
+ void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
+{
+ /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
+ * return loop data from bmesh itself. */
+ const float (*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? CustomData_get_layer(&mesh->ldata, CD_NORMAL) : NULL;
+
+ const MVert *mv = mesh->mvert;
+ const MLoop *ml = mesh->mloop;
+ const MPoly *mp = mesh->mpoly;
+ const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+ int p_idx, i;
+
+ for (p_idx = 0; p_idx < mesh->totpoly; ++p_idx, ++mp) {
+ for (i = 0; i < mp->totloop; ++i, ++ml) {
+ const int v_idx = v_index ? v_index[ml->v] : ml->v;
+ const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ if (!ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
+}
+
+/* Copied from cdDM_foreachMappedFaceCenter */
+void BKE_mesh_foreach_mapped_face_center(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float cent[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
+{
+ MVert *mvert = mesh->mvert;
+ MPoly *mp;
+ MLoop *ml;
+ int i, orig, *index;
+
+ index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+ mp = mesh->mpoly;
+ for (i = 0; i < mesh->totpoly; i++, mp++) {
+ float cent[3];
+ float *no, _no[3];
+
+ if (index) {
+ orig = *index++;
+ if (orig == ORIGINDEX_NONE) continue;
+ }
+ else {
+ orig = i;
+ }
+
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, (no = _no));
+ }
+ else {
+ no = NULL;
+ }
+
+ func(userData, orig, cent, no);
+ }
+
+}
diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c
new file mode 100644
index 00000000000..27ba7e76fa3
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_merge.c
@@ -0,0 +1,684 @@
+/*
+ * ***** 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_merge.c
+ * \ingroup bke
+ */
+#include <string.h> // for memcpy
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_utildefines_stack.h"
+#include "BLI_edgehash.h"
+#include "BLI_ghash.h"
+
+#include "BKE_customdata.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+
+/**
+ * Poly compare with vtargetmap
+ * Function used by #BKE_mesh_merge_verts.
+ * The function compares poly_source after applying vtargetmap, with poly_target.
+ * The two polys are identical if they share the same vertices in the same order, or in reverse order,
+ * but starting position loopstart may be different.
+ * The function is called with direct_reverse=1 for same order (i.e. same normal),
+ * and may be called again with direct_reverse=-1 for reverse order.
+ * \return 1 if polys are identical, 0 if polys are different.
+ */
+static int cddm_poly_compare(
+ MLoop *mloop_array,
+ MPoly *mpoly_source, MPoly *mpoly_target,
+ const int *vtargetmap, const int direct_reverse)
+{
+ int vert_source, first_vert_source, vert_target;
+ int i_loop_source;
+ int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted;
+ bool compare_completed = false;
+ bool same_loops = false;
+
+ MLoop *mloop_source, *mloop_target;
+
+ BLI_assert(direct_reverse == 1 || direct_reverse == -1);
+
+ i_loop_source = 0;
+ mloop_source = mloop_array + mpoly_source->loopstart;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ /* Find same vertex within mpoly_target's loops */
+ mloop_target = mloop_array + mpoly_target->loopstart;
+ for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) {
+ if (mloop_target->v == vert_source) {
+ break;
+ }
+ }
+
+ /* If same vertex not found, then polys cannot be equal */
+ if (i_loop_target >= mpoly_target->totloop) {
+ return false;
+ }
+
+ /* Now mloop_source and m_loop_target have one identical vertex */
+ /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */
+ /* Go around the loop and check that all vertices match in same order */
+ /* Skipping source loops when consecutive source vertices are mapped to same target vertex */
+
+ i_loop_target_start = i_loop_target;
+ i_loop_target_offset = 0;
+ first_vert_source = vert_source;
+
+ compare_completed = false;
+ same_loops = false;
+
+ while (!compare_completed) {
+
+ vert_target = mloop_target->v;
+
+ /* First advance i_loop_source, until it points to different vertex, after mapping applied */
+ do {
+ i_loop_source++;
+
+ if (i_loop_source == mpoly_source->totloop) {
+ /* End of loops for source, must match end of loop for target. */
+ if (i_loop_target_offset == mpoly_target->totloop - 1) {
+ compare_completed = true;
+ same_loops = true;
+ break; /* Polys are identical */
+ }
+ else {
+ compare_completed = true;
+ same_loops = false;
+ break; /* Polys are different */
+ }
+ }
+
+ mloop_source++;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ } while (vert_source == vert_target);
+
+ if (compare_completed) {
+ break;
+ }
+
+ /* Now advance i_loop_target as well */
+ i_loop_target_offset++;
+
+ if (i_loop_target_offset == mpoly_target->totloop) {
+ /* End of loops for target only, that means no match */
+ /* except if all remaining source vertices are mapped to first target */
+ for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) {
+ vert_source = vtargetmap[mloop_source->v];
+ if (vert_source != first_vert_source) {
+ compare_completed = true;
+ same_loops = false;
+ break;
+ }
+ }
+ if (!compare_completed) {
+ same_loops = true;
+ }
+ break;
+ }
+
+ /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */
+ i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop;
+ if (i_loop_target_adjusted < 0) {
+ i_loop_target_adjusted += mpoly_target->totloop;
+ }
+ mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted;
+ vert_target = mloop_target->v;
+
+ if (vert_target != vert_source) {
+ same_loops = false; /* Polys are different */
+ break;
+ }
+ }
+ return same_loops;
+}
+
+
+/* Utility stuff for using GHash with polys, used by vertex merging. */
+
+typedef struct PolyKey {
+ int poly_index; /* index of the MPoly within the derived mesh */
+ int totloops; /* number of loops in the poly */
+ unsigned int hash_sum; /* Sum of all vertices indices */
+ unsigned int hash_xor; /* Xor of all vertices indices */
+} PolyKey;
+
+
+static unsigned int poly_gset_hash_fn(const void *key)
+{
+ const PolyKey *pk = key;
+ return pk->hash_sum;
+}
+
+static bool poly_gset_compare_fn(const void *k1, const void *k2)
+{
+ const PolyKey *pk1 = k1;
+ const PolyKey *pk2 = k2;
+ if ((pk1->hash_sum == pk2->hash_sum) &&
+ (pk1->hash_xor == pk2->hash_xor) &&
+ (pk1->totloops == pk2->totloops))
+ {
+ /* Equality - note that this does not mean equality of polys */
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+/**
+ * Merge Verts
+ *
+ * This frees the given mesh and returns a new mesh.
+ *
+ * \param vtargetmap The table that maps vertices to target vertices. a value of -1
+ * indicates a vertex is a target, and is to be kept.
+ * This array is aligned with 'mesh->totvert'
+ * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported
+ * and will likely generate corrupted geometry.
+ *
+ * \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size)
+ *
+ * \param merge_mode enum with two modes.
+ * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED
+ * When called by the Mirror Modifier,
+ * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
+ * of faces sharing the same set of vertices)
+ * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL
+ * When called by the Array Modifier,
+ * In this mode, faces where all vertices are merged are double-checked,
+ * to see whether all target vertices actually make up a poly already.
+ * Indeed it could be that all of a poly's vertices are merged,
+ * but merged to vertices that do not make up a single poly,
+ * in which case the original poly should not be dumped.
+ * Actually this later behavior could apply to the Mirror Modifier as well, but the additional checks are
+ * costly and not necessary in the case of mirror, because each vertex is only merged to its own mirror.
+ *
+ * \note #BKE_mesh_recalc_tessellation has to run on the returned DM if you want to access tessfaces.
+ */
+Mesh *BKE_mesh_merge_verts(Mesh *mesh, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
+{
+ /* This was commented out back in 2013, see commit f45d8827bafe6b9eaf9de42f4054e9d84a21955d. */
+// #define USE_LOOPS
+
+ Mesh *result = NULL;
+
+ const int totvert = mesh->totvert;
+ const int totedge = mesh->totedge;
+ const int totloop = mesh->totloop;
+ const int totpoly = mesh->totpoly;
+
+ const int totvert_final = totvert - tot_vtargetmap;
+
+ MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__);
+ int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__);
+ int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__);
+ STACK_DECLARE(mvert);
+ STACK_DECLARE(oldv);
+
+ /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require
+ * generating new edges, and while in 99% cases we'll still end with less final edges than totedge,
+ * cases can be forged that would end requiring more... */
+ MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__);
+ int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__);
+ int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__);
+ STACK_DECLARE(medge);
+ STACK_DECLARE(olde);
+
+ MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__);
+ int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__);
+#ifdef USE_LOOPS
+ int *newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__);
+#endif
+ STACK_DECLARE(mloop);
+ STACK_DECLARE(oldl);
+
+ MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__);
+ int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__);
+ STACK_DECLARE(mpoly);
+ STACK_DECLARE(oldp);
+
+ EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge);
+
+ int i, j, c;
+
+ PolyKey *poly_keys;
+ GSet *poly_gset = NULL;
+ MeshElemMap *poly_map = NULL;
+ int *poly_map_mem = NULL;
+
+ STACK_INIT(oldv, totvert_final);
+ STACK_INIT(olde, totedge);
+ STACK_INIT(oldl, totloop);
+ STACK_INIT(oldp, totpoly);
+
+ STACK_INIT(mvert, totvert_final);
+ STACK_INIT(medge, totedge);
+ STACK_INIT(mloop, totloop);
+ STACK_INIT(mpoly, totpoly);
+
+ /* fill newv with destination vertex indices */
+ mv = mesh->mvert;
+ c = 0;
+ for (i = 0; i < totvert; i++, mv++) {
+ if (vtargetmap[i] == -1) {
+ STACK_PUSH(oldv, i);
+ STACK_PUSH(mvert, *mv);
+ newv[i] = c++;
+ }
+ else {
+ /* dummy value */
+ newv[i] = 0;
+ }
+ }
+
+ /* now link target vertices to destination indices */
+ for (i = 0; i < totvert; i++) {
+ if (vtargetmap[i] != -1) {
+ newv[i] = newv[vtargetmap[i]];
+ }
+ }
+
+ /* Don't remap vertices in cddm->mloop, because we need to know the original
+ * indices in order to skip faces with all vertices merged.
+ * The "update loop indices..." section further down remaps vertices in mloop.
+ */
+
+ /* now go through and fix edges and faces */
+ med = mesh->medge;
+ c = 0;
+ for (i = 0; i < totedge; i++, med++) {
+ const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ if (LIKELY(v1 != v2)) {
+ void **val_p;
+
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ newe[i] = GET_INT_FROM_POINTER(*val_p);
+ }
+ else {
+ STACK_PUSH(olde, i);
+ STACK_PUSH(medge, *med);
+ newe[i] = c;
+ *val_p = SET_INT_IN_POINTER(c);
+ c++;
+ }
+ }
+ else {
+ newe[i] = -1;
+ }
+ }
+
+ if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* In this mode, we need to determine, whenever a poly' vertices are all mapped */
+ /* if the targets already make up a poly, in which case the new poly is dropped */
+ /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */
+ PolyKey *mpgh;
+ poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__);
+ poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly);
+ /* Duplicates allowed because our compare function is not pure equality */
+ BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
+
+ mp = mesh->mpoly;
+ mpgh = poly_keys;
+ for (i = 0; i < totpoly; i++, mp++, mpgh++) {
+ mpgh->poly_index = i;
+ mpgh->totloops = mp->totloop;
+ ml = mesh->mloop + mp->loopstart;
+ mpgh->hash_sum = mpgh->hash_xor = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ mpgh->hash_sum += ml->v;
+ mpgh->hash_xor ^= ml->v;
+ }
+ BLI_gset_insert(poly_gset, mpgh);
+ }
+
+ /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */
+ /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */
+ BKE_mesh_vert_poly_map_create(&poly_map, &poly_map_mem,
+ mesh->mpoly, mesh->mloop,
+ totvert, totpoly, totloop);
+ } /* done preparing for fast poly compare */
+
+
+ mp = mesh->mpoly;
+ mv = mesh->mvert;
+ for (i = 0; i < totpoly; i++, mp++) {
+ MPoly *mp_new;
+
+ ml = mesh->mloop + mp->loopstart;
+
+ /* check faces with all vertices merged */
+ bool all_vertices_merged = true;
+
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ if (vtargetmap[ml->v] == -1) {
+ all_vertices_merged = false;
+ /* This will be used to check for poly using several time the same vert. */
+ mv[ml->v].flag &= ~ME_VERT_TMP_TAG;
+ }
+ else {
+ /* This will be used to check for poly using several time the same vert. */
+ mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG;
+ }
+ }
+
+ if (UNLIKELY(all_vertices_merged)) {
+ if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_MAPPED) {
+ /* In this mode, all vertices merged is enough to dump face */
+ continue;
+ }
+ else if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* Additional condition for face dump: target vertices must make up an identical face */
+ /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
+ /* (2) second step is thorough but more costly poly compare */
+ int i_poly, v_target;
+ bool found = false;
+ PolyKey pkey;
+
+ /* Use poly_gset for fast (although not 100% certain) identification of same poly */
+ /* First, make up a poly_summary structure */
+ ml = mesh->mloop + mp->loopstart;
+ pkey.hash_sum = pkey.hash_xor = 0;
+ pkey.totloops = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
+ pkey.hash_sum += v_target;
+ pkey.hash_xor ^= v_target;
+ pkey.totloops++;
+ }
+ if (BLI_gset_haskey(poly_gset, &pkey)) {
+
+ /* There might be a poly that matches this one.
+ * We could just leave it there and say there is, and do a "continue".
+ * ... but we are checking whether there is an exact poly match.
+ * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
+ */
+
+ /* Consider current loop again */
+ ml = mesh->mloop + mp->loopstart;
+ /* Consider the target of the loop's first vert */
+ v_target = vtargetmap[ml->v];
+ /* Now see if v_target belongs to a poly that shares all vertices with source poly,
+ * in same order, or reverse order */
+
+ for (i_poly = 0; i_poly < poly_map[v_target].count; i_poly++) {
+ MPoly *target_poly = mesh->mpoly + *(poly_map[v_target].indices + i_poly);
+
+ if (cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, +1) ||
+ cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, -1))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ /* Current poly's vertices are mapped to a poly that is strictly identical */
+ /* Current poly is dumped */
+ continue;
+ }
+ }
+ }
+ }
+
+
+ /* Here either the poly's vertices were not all merged
+ * or they were all merged, but targets do not make up an identical poly,
+ * the poly is retained.
+ */
+ ml = mesh->mloop + mp->loopstart;
+
+ c = 0;
+ MLoop *last_valid_ml = NULL;
+ MLoop *first_valid_ml = NULL;
+ bool need_edge_from_last_valid_ml = false;
+ bool need_edge_to_first_valid_ml = false;
+ int created_edges = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v;
+#ifndef NDEBUG
+ {
+ MLoop *next_ml = mesh->mloop + mp->loopstart + ((j + 1) % mp->totloop);
+ uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v;
+ med = mesh->medge + ml->e;
+ uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1));
+ }
+#endif
+ /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */
+ if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) {
+ mv[mlv].flag |= ME_VERT_TMP_TAG;
+
+ if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) {
+ /* We need to create a new edge between last valid loop and this one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
+ uint v2 = mlv;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = GET_INT_FROM_POINTER(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = SET_INT_IN_POINTER(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_from_last_valid_ml = false;
+ }
+
+#ifdef USE_LOOPS
+ newl[j + mp->loopstart] = STACK_SIZE(mloop);
+#endif
+ STACK_PUSH(oldl, j + mp->loopstart);
+ last_valid_ml = STACK_PUSH_RET_PTR(mloop);
+ *last_valid_ml = *ml;
+ if (first_valid_ml == NULL) {
+ first_valid_ml = last_valid_ml;
+ }
+ c++;
+
+ /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges
+ * in that part of code make remapping later totally unreliable. */
+ BLI_assert(newe[ml->e] != -1);
+ last_valid_ml->e = newe[ml->e];
+ }
+ else {
+ if (last_valid_ml != NULL) {
+ need_edge_from_last_valid_ml = true;
+ }
+ else {
+ need_edge_to_first_valid_ml = true;
+ }
+ }
+ }
+ if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) &&
+ (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml)))
+ {
+ /* We need to create a new edge between last valid loop and first valid one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
+ uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] : first_valid_ml->v;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = GET_INT_FROM_POINTER(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = first_valid_ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = SET_INT_IN_POINTER(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false;
+ }
+
+ if (UNLIKELY(c == 0)) {
+ BLI_assert(created_edges == 0);
+ continue;
+ }
+ else if (UNLIKELY(c < 3)) {
+ STACK_DISCARD(oldl, c);
+ STACK_DISCARD(mloop, c);
+ if (created_edges > 0) {
+ for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) {
+ BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL);
+ }
+ STACK_DISCARD(olde, created_edges);
+ STACK_DISCARD(medge, created_edges);
+ }
+ continue;
+ }
+
+ mp_new = STACK_PUSH_RET_PTR(mpoly);
+ *mp_new = *mp;
+ mp_new->totloop = c;
+ BLI_assert(mp_new->totloop >= 3);
+ mp_new->loopstart = STACK_SIZE(mloop) - c;
+
+ STACK_PUSH(oldp, i);
+ } /* end of the loop that tests polys */
+
+
+ if (poly_gset) {
+ // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset));
+
+ BLI_gset_free(poly_gset, NULL);
+ MEM_freeN(poly_keys);
+ }
+
+ /*create new cddm*/
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, STACK_SIZE(mvert), STACK_SIZE(medge), 0, STACK_SIZE(mloop), STACK_SIZE(mpoly));
+
+ /*update edge indices and copy customdata*/
+ med = medge;
+ for (i = 0; i < result->totedge; i++, med++) {
+ BLI_assert(newv[med->v1] != -1);
+ med->v1 = newv[med->v1];
+ BLI_assert(newv[med->v2] != -1);
+ med->v2 = newv[med->v2];
+
+ /* Can happen in case vtargetmap contains some double chains, we do not support that. */
+ BLI_assert(med->v1 != med->v2);
+
+ CustomData_copy_data(&mesh->edata, &result->edata, olde[i], i, 1);
+ }
+
+ /*update loop indices and copy customdata*/
+ ml = mloop;
+ for (i = 0; i < result->totloop; i++, ml++) {
+ /* Edge remapping has already be done in main loop handling part above. */
+ BLI_assert(newv[ml->v] != -1);
+ ml->v = newv[ml->v];
+
+ CustomData_copy_data(&mesh->ldata, &result->ldata, oldl[i], i, 1);
+ }
+
+ /*copy vertex customdata*/
+ mv = mvert;
+ for (i = 0; i < result->totvert; i++, mv++) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, oldv[i], i, 1);
+ }
+
+ /*copy poly customdata*/
+ mp = mpoly;
+ for (i = 0; i < result->totpoly; i++, mp++) {
+ CustomData_copy_data(&mesh->pdata, &result->pdata, oldp[i], i, 1);
+ }
+
+ /*copy over data. CustomData_add_layer can do this, need to look it up.*/
+ memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
+ memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
+ memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
+ memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
+
+ MEM_freeN(mvert);
+ MEM_freeN(medge);
+ MEM_freeN(mloop);
+ MEM_freeN(mpoly);
+
+ MEM_freeN(newv);
+ MEM_freeN(newe);
+#ifdef USE_LOOPS
+ MEM_freeN(newl);
+#endif
+
+ MEM_freeN(oldv);
+ MEM_freeN(olde);
+ MEM_freeN(oldl);
+ MEM_freeN(oldp);
+
+ BLI_edgehash_free(ehash, NULL);
+
+ if (poly_map != NULL)
+ MEM_freeN(poly_map);
+ if (poly_map_mem != NULL)
+ MEM_freeN(poly_map_mem);
+
+ BKE_id_free(NULL, mesh);
+
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index eef8657482f..c882cc0a7fa 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
@@ -41,10 +42,10 @@
#include "BKE_bvhutils.h"
#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h" /* own include */
+#include "BKE_mesh_runtime.h"
#include "BLI_strict_flags.h"
@@ -121,8 +122,8 @@ static bool mesh_remap_bvhtree_query_raycast(
* In other words, beyond a certain (relatively small) distance, all differences have more or less the same weight
* in final result, which allows to reduce influence of a few high differences, in favor of a global good matching.
*/
-float BKE_mesh_remap_calc_difference_from_dm(
- const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, DerivedMesh *dm_src)
+float BKE_mesh_remap_calc_difference_from_mesh(
+ const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, Mesh *me_src)
{
BVHTreeFromMesh treedata = {NULL};
BVHTreeNearest nearest = {0};
@@ -131,7 +132,7 @@ float BKE_mesh_remap_calc_difference_from_dm(
float result = 0.0f;
int i;
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
@@ -250,8 +251,8 @@ static void mesh_calc_eigen_matrix(
/**
* Set r_space_transform so that best bbox of dst matches best bbox of src.
*/
-void BKE_mesh_remap_find_best_match_from_dm(
- const MVert *verts_dst, const int numverts_dst, DerivedMesh *dm_src, SpaceTransform *r_space_transform)
+void BKE_mesh_remap_find_best_match_from_mesh(
+ const MVert *verts_dst, const int numverts_dst, Mesh *me_src, SpaceTransform *r_space_transform)
{
/* Note that those are done so that we successively get actual mirror matrix (by multiplication of columns)... */
const float mirrors[][3] = {
@@ -269,15 +270,14 @@ void BKE_mesh_remap_find_best_match_from_dm(
float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4];
float best_match = FLT_MAX, match;
- const int numverts_src = dm_src->getNumVerts(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)numverts_src, __func__);
- dm_src->getVertCos(dm_src, vcos_src);
+ const int numverts_src = me_src->totvert;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
mesh_calc_eigen_matrix(NULL, (const float (*)[3])vcos_src, numverts_src, mat_src);
mesh_calc_eigen_matrix(verts_dst, NULL, numverts_dst, mat_dst);
BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
- match = BKE_mesh_remap_calc_difference_from_dm(r_space_transform, verts_dst, numverts_dst, dm_src);
+ match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src);
best_match = match;
copy_m4_m4(best_mat_dst, mat_dst);
@@ -288,7 +288,7 @@ void BKE_mesh_remap_find_best_match_from_dm(
mul_v3_fl(mat_dst[2], (*mirr)[2]);
BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
- match = BKE_mesh_remap_calc_difference_from_dm(r_space_transform, verts_dst, numverts_dst, dm_src);
+ match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src);
if (match < best_match) {
best_match = match;
copy_m4_m4(best_mat_dst, mat_dst);
@@ -430,9 +430,9 @@ typedef struct IslandResult {
/* Will be enough in 99% of cases. */
#define MREMAP_DEFAULT_BUFSIZE 32
-void BKE_mesh_remap_calc_verts_from_dm(
+void BKE_mesh_remap_calc_verts_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
- const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src,
+ const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), Mesh *me_src,
MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@@ -444,7 +444,7 @@ void BKE_mesh_remap_calc_verts_from_dm(
BKE_mesh_remap_init(r_map, numverts_dst);
if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numverts_dst == dm_src->getNumVerts(dm_src));
+ BLI_assert(numverts_dst == me_src->totvert);
for (i = 0; i < numverts_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -457,7 +457,7 @@ void BKE_mesh_remap_calc_verts_from_dm(
float tmp_co[3], tmp_no[3];
if (mode == MREMAP_MODE_VERT_NEAREST) {
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
@@ -478,11 +478,10 @@ void BKE_mesh_remap_calc_verts_from_dm(
}
}
else if (ELEM(mode, MREMAP_MODE_VERT_EDGE_NEAREST, MREMAP_MODE_VERT_EDGEINTERP_NEAREST)) {
- MEdge *edges_src = dm_src->getEdgeArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
- dm_src->getVertCos(dm_src, vcos_src);
+ MEdge *edges_src = me_src->medge;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
@@ -530,18 +529,16 @@ void BKE_mesh_remap_calc_verts_from_dm(
else if (ELEM(mode, MREMAP_MODE_VERT_POLY_NEAREST, MREMAP_MODE_VERT_POLYINTERP_NEAREST,
MREMAP_MODE_VERT_POLYINTERP_VNORPROJ))
{
- MPoly *polys_src = dm_src->getPolyArray(dm_src);
- MLoop *loops_src = dm_src->getLoopArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
+ MPoly *polys_src = me_src->mpoly;
+ MLoop *loops_src = me_src->mloop;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
float (*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__);
float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__);
- dm_src->getVertCos(dm_src, vcos_src);
-
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
for (i = 0; i < numverts_dst; i++) {
@@ -625,10 +622,10 @@ void BKE_mesh_remap_calc_verts_from_dm(
}
}
-void BKE_mesh_remap_calc_edges_from_dm(
+void BKE_mesh_remap_calc_edges_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
const MVert *verts_dst, const int numverts_dst, const MEdge *edges_dst, const int numedges_dst,
- const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src, MeshPairRemap *r_map)
+ const bool UNUSED(dirty_nors_dst), Mesh *me_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
@@ -639,7 +636,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
BKE_mesh_remap_init(r_map, numedges_dst);
if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numedges_dst == dm_src->getNumEdges(dm_src));
+ BLI_assert(numedges_dst == me_src->totedge);
for (i = 0; i < numedges_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -652,10 +649,10 @@ void BKE_mesh_remap_calc_edges_from_dm(
float tmp_co[3], tmp_no[3];
if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) {
- const int num_verts_src = dm_src->getNumVerts(dm_src);
- const int num_edges_src = dm_src->getNumEdges(dm_src);
- MEdge *edges_src = dm_src->getEdgeArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
+ const int num_verts_src = me_src->totvert;
+ const int num_edges_src = me_src->totedge;
+ MEdge *edges_src = me_src->medge;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
MeshElemMap *vert_to_edge_src_map;
int *vert_to_edge_src_map_mem;
@@ -672,9 +669,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
BKE_mesh_vert_edge_map_create(&vert_to_edge_src_map, &vert_to_edge_src_map_mem,
edges_src, num_verts_src, num_edges_src);
- dm_src->getVertCos(dm_src, vcos_src);
-
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
for (i = 0; i < numedges_dst; i++) {
@@ -774,7 +769,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
MEM_freeN(vert_to_edge_src_map_mem);
}
else if (mode == MREMAP_MODE_EDGE_NEAREST) {
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
nearest.index = -1;
for (i = 0; i < numedges_dst; i++) {
@@ -795,13 +790,12 @@ void BKE_mesh_remap_calc_edges_from_dm(
}
}
else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) {
- MEdge *edges_src = dm_src->getEdgeArray(dm_src);
- MPoly *polys_src = dm_src->getPolyArray(dm_src);
- MLoop *loops_src = dm_src->getLoopArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
+ MEdge *edges_src = me_src->medge;
+ MPoly *polys_src = me_src->mpoly;
+ MLoop *loops_src = me_src->mloop;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
- dm_src->getVertCos(dm_src, vcos_src);
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
for (i = 0; i < numedges_dst; i++) {
interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
@@ -820,9 +814,9 @@ void BKE_mesh_remap_calc_edges_from_dm(
int best_eidx_src = -1;
for (; nloops--; ml_src++) {
- MEdge *me_src = &edges_src[ml_src->e];
- float *co1_src = vcos_src[me_src->v1];
- float *co2_src = vcos_src[me_src->v2];
+ MEdge *med_src = &edges_src[ml_src->e];
+ float *co1_src = vcos_src[med_src->v1];
+ float *co2_src = vcos_src[med_src->v2];
float co_src[3];
float dist_sq;
@@ -847,14 +841,14 @@ void BKE_mesh_remap_calc_edges_from_dm(
}
else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) {
const int num_rays_min = 5, num_rays_max = 100;
- const int numedges_src = dm_src->getNumEdges(dm_src);
+ const int numedges_src = me_src->totedge;
/* Subtleness - this one we can allocate only max number of cast rays per edges! */
int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max), __func__);
/* Here it's simpler to just allocate for all edges :/ */
float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__);
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
for (i = 0; i < numedges_dst; i++) {
/* For each dst edge, we sample some rays from it (interpolated from its vertices)
@@ -1106,13 +1100,13 @@ static float mesh_remap_calc_loops_astar_f_cost(
#define ASTAR_STEPS_MAX 64
-void BKE_mesh_remap_calc_loops_from_dm(
+void BKE_mesh_remap_calc_loops_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
MVert *verts_dst, const int numverts_dst, MEdge *edges_dst, const int numedges_dst,
MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst,
CustomData *ldata_dst, CustomData *pdata_dst,
const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
- DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src,
+ Mesh *me_src,
MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@@ -1127,7 +1121,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (mode == MREMAP_MODE_TOPOLOGY) {
/* In topology mapping, we assume meshes are identical, islands included! */
- BLI_assert(numloops_dst == dm_src->getNumLoops(dm_src));
+ BLI_assert(numloops_dst == me_src->totloop);
for (i = 0; i < numloops_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -1169,19 +1163,15 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Unlike above, those are one-to-one mappings, simpler! */
int *loop_to_poly_map_src = NULL;
- bool verts_allocated_src;
- MVert *verts_src = DM_get_vert_array(dm_src, &verts_allocated_src);
- const int num_verts_src = dm_src->getNumVerts(dm_src);
+ MVert *verts_src = me_src->mvert;
+ const int num_verts_src = me_src->totvert;
float (*vcos_src)[3] = NULL;
- bool edges_allocated_src;
- MEdge *edges_src = DM_get_edge_array(dm_src, &edges_allocated_src);
- const int num_edges_src = dm_src->getNumEdges(dm_src);
- bool loops_allocated_src;
- MLoop *loops_src = DM_get_loop_array(dm_src, &loops_allocated_src);
- const int num_loops_src = dm_src->getNumLoops(dm_src);
- bool polys_allocated_src;
- MPoly *polys_src = DM_get_poly_array(dm_src, &polys_allocated_src);
- const int num_polys_src = dm_src->getNumPolys(dm_src);
+ MEdge *edges_src = me_src->medge;
+ const int num_edges_src = me_src->totedge;
+ MLoop *loops_src = me_src->mloop;
+ const int num_loops_src = me_src->totloop;
+ MPoly *polys_src = me_src->mpoly;
+ const int num_polys_src = me_src->totpoly;
const MLoopTri *looptri_src = NULL;
int num_looptri_src = 0;
@@ -1198,8 +1188,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE;
if (!use_from_vert) {
- vcos_src = MEM_mallocN(sizeof(*vcos_src) * (size_t)num_verts_src, __func__);
- dm_src->getVertCos(dm_src, vcos_src);
+ vcos_src = BKE_mesh_vertexCos_get(me_src, NULL);
vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__);
indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__);
@@ -1215,11 +1204,12 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (need_pnors_dst) {
/* Cache poly nors into a temp CDLayer. */
poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ const bool do_poly_nors_dst = (poly_nors_dst == NULL);
if (!poly_nors_dst) {
poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- if (dirty_nors_dst) {
+ if (dirty_nors_dst || do_poly_nors_dst) {
BKE_mesh_calc_normals_poly(verts_dst, NULL, numverts_dst, loops_dst, polys_dst,
numloops_dst, numpolys_dst, poly_nors_dst, true);
}
@@ -1229,11 +1219,12 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Cache poly nors into a temp CDLayer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
- if (dirty_nors_dst || !loop_nors_dst) {
- if (!loop_nors_dst) {
- loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
- CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
+ const bool do_loop_nors_dst = (loop_nors_dst == NULL);
+ if (!loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_loop_nors_dst) {
BKE_mesh_normals_loop_split(verts_dst, numverts_dst, edges_dst, numedges_dst,
loops_dst, loop_nors_dst, numloops_dst,
polys_dst, (const float (*)[3])poly_nors_dst, numpolys_dst,
@@ -1242,13 +1233,17 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
if (need_pnors_src || need_lnors_src) {
/* Simpler for now, calcNormals never stores pnors :( */
- dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
+ if (!CustomData_has_layer(&me_src->pdata, CD_NORMAL)) {
+ CustomData_add_layer(&me_src->pdata, CD_NORMAL, CD_CALLOC, NULL, me_src->totpoly);
+ CustomData_set_layer_flag(&me_src->pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ BKE_mesh_calc_normals_split(me_src);
if (need_pnors_src) {
- poly_nors_src = dm_src->getPolyDataArray(dm_src, CD_NORMAL);
+ poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL);
}
if (need_lnors_src) {
- loop_nors_src = dm_src->getLoopDataArray(dm_src, CD_NORMAL);
+ loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL);
}
}
}
@@ -1344,37 +1339,24 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
}
- /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */
- bvhtree_from_mesh_verts_ex(&treedata[tindex], verts_src, num_verts_src, verts_allocated_src,
+ bvhtree_from_mesh_verts_ex(&treedata[tindex], verts_src, num_verts_src, false,
verts_active, num_verts_active, 0.0, 2, 6);
- if (verts_allocated_src) {
- verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */
- }
}
MEM_freeN(verts_active);
}
else {
BLI_assert(num_trees == 1);
- bvhtree_from_mesh_get(&treedata[0], dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2);
}
}
else { /* We use polygons. */
if (use_islands) {
/* bvhtree here uses looptri faces... */
- const unsigned int dirty_tess_flag = dm_src->dirty & DM_DIRTY_TESS_CDLAYERS;
BLI_bitmap *looptri_active;
- /* We do not care about tessellated data here, only geometry itself is important. */
- if (dirty_tess_flag) {
- dm_src->dirty &= ~dirty_tess_flag;
- }
- if (dirty_tess_flag) {
- dm_src->dirty |= dirty_tess_flag;
- }
-
- looptri_src = dm_src->getLoopTriArray(dm_src);
- num_looptri_src = dm_src->getNumLoopTri(dm_src);
+ looptri_src = BKE_mesh_runtime_looptri_ensure(me_src);
+ num_looptri_src = me_src->runtime.looptris.len;
looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__);
for (tindex = 0; tindex < num_trees; tindex++) {
@@ -1387,26 +1369,19 @@ void BKE_mesh_remap_calc_loops_from_dm(
num_looptri_active++;
}
}
- /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */
bvhtree_from_mesh_looptri_ex(
&treedata[tindex],
- verts_src, verts_allocated_src,
- loops_src, loops_allocated_src,
+ verts_src, false,
+ loops_src, false,
looptri_src, num_looptri_src, false,
looptri_active, num_looptri_active, 0.0, 2, 6);
- if (verts_allocated_src) {
- verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */
- }
- if (loops_allocated_src) {
- loops_allocated_src = false; /* Only 'give' our loops once, to first tree! */
- }
}
MEM_freeN(looptri_active);
}
else {
BLI_assert(num_trees == 1);
- bvhtree_from_mesh_get(&treedata[0], dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRI, 2);
}
}
@@ -1905,21 +1880,9 @@ void BKE_mesh_remap_calc_loops_from_dm(
BLI_astar_solution_free(&as_solution);
}
- if (verts_allocated_src) {
- MEM_freeN(verts_src);
- }
if (vcos_src) {
MEM_freeN(vcos_src);
}
- if (edges_allocated_src) {
- MEM_freeN(edges_src);
- }
- if (loops_allocated_src) {
- MEM_freeN(loops_src);
- }
- if (polys_allocated_src) {
- MEM_freeN(polys_src);
- }
if (vert_to_loop_map_src) {
MEM_freeN(vert_to_loop_map_src);
}
@@ -1962,11 +1925,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
-void BKE_mesh_remap_calc_polys_from_dm(
+void BKE_mesh_remap_calc_polys_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
MVert *verts_dst, const int numverts_dst, MLoop *loops_dst, const int numloops_dst,
MPoly *polys_dst, const int numpolys_dst, CustomData *pdata_dst, const bool dirty_nors_dst,
- DerivedMesh *dm_src, MeshPairRemap *r_map)
+ Mesh *me_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
@@ -1992,7 +1955,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
BKE_mesh_remap_init(r_map, numpolys_dst);
if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numpolys_dst == dm_src->getNumPolys(dm_src));
+ BLI_assert(numpolys_dst == me_src->totpoly);
for (i = 0; i < numpolys_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -2003,7 +1966,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
BVHTreeRayHit rayhit = {0};
float hit_dist;
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
if (mode == MREMAP_MODE_POLY_NEAREST) {
nearest.index = -1;
@@ -2068,7 +2031,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
*/
RNG *rng = BLI_rng_new(0);
- const size_t numpolys_src = (size_t)dm_src->getNumPolys(dm_src);
+ const size_t numpolys_src = (size_t)me_src->totpoly;
/* Here it's simpler to just allocate for all polys :/ */
int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__);
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
new file mode 100644
index 00000000000..657cd3b6c52
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -0,0 +1,376 @@
+/*
+ * ***** 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_runtime.c
+ * \ingroup bke
+ */
+
+#include "atomic_ops.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_geom.h"
+#include "BLI_threads.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#ifdef USE_DERIVEDMESH
+#include "BKE_DerivedMesh.h"
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Runtime Struct Utils
+ * \{ */
+
+static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/**
+ * Default values defined at read time.
+ */
+void BKE_mesh_runtime_reset(Mesh *mesh)
+{
+ memset(&mesh->runtime, 0, sizeof(mesh->runtime));
+}
+
+void BKE_mesh_runtime_clear_cache(Mesh *mesh)
+{
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_mesh_batch_cache_free(mesh);
+ BKE_mesh_runtime_clear_edit_data(mesh);
+}
+
+/* This is a ported copy of DM_ensure_looptri_data(dm) */
+/**
+ * Ensure the array is large enough
+ *
+ * /note This function must always be thread-protected by caller. It should only be used by internal code.
+ */
+static void mesh_ensure_looptri_data(Mesh *mesh)
+{
+ const unsigned int totpoly = mesh->totpoly;
+ const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
+
+ BLI_assert(mesh->runtime.looptris.array_wip == NULL);
+
+ SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+
+ if ((looptris_len > mesh->runtime.looptris.len_alloc) ||
+ (looptris_len < mesh->runtime.looptris.len_alloc * 2) ||
+ (totpoly == 0))
+ {
+ MEM_SAFE_FREE(mesh->runtime.looptris.array_wip);
+ mesh->runtime.looptris.len_alloc = 0;
+ mesh->runtime.looptris.len = 0;
+ }
+
+ if (totpoly) {
+ if (mesh->runtime.looptris.array_wip == NULL) {
+ mesh->runtime.looptris.array_wip = MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__);
+ mesh->runtime.looptris.len_alloc = looptris_len;
+ }
+
+ mesh->runtime.looptris.len = looptris_len;
+ }
+}
+
+/* This is a ported copy of CDDM_recalc_looptri(dm). */
+void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
+{
+ mesh_ensure_looptri_data(mesh);
+ BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != NULL);
+
+ BKE_mesh_recalc_looptri(
+ mesh->mloop, mesh->mpoly,
+ mesh->mvert,
+ mesh->totloop, mesh->totpoly,
+ mesh->runtime.looptris.array_wip);
+
+ BLI_assert(mesh->runtime.looptris.array == NULL);
+ atomic_cas_ptr((void **)&mesh->runtime.looptris.array, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+ mesh->runtime.looptris.array_wip = NULL;
+}
+
+/* This is a ported copy of dm_getNumLoopTri(dm). */
+int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
+{
+ const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
+ BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
+ return looptri_len;
+}
+
+/* This is a ported copy of dm_getLoopTriArray(dm). */
+const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh)
+{
+ MLoopTri *looptri;
+
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ);
+ looptri = mesh->runtime.looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+
+ if (looptri != NULL) {
+ BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
+ }
+ else {
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
+ /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already
+ * recomputed those looptris. */
+ if (mesh->runtime.looptris.array == NULL) {
+ BKE_mesh_runtime_looptri_recalc(mesh);
+ }
+ looptri = mesh->runtime.looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+ }
+ return looptri;
+}
+
+/* This is a copy of DM_verttri_from_looptri(). */
+void BKE_mesh_runtime_verttri_from_looptri(
+ MVertTri *r_verttri, const MLoop *mloop,
+ const MLoopTri *looptri, int looptri_num)
+{
+ int i;
+ for (i = 0; i < looptri_num; i++) {
+ r_verttri[i].tri[0] = mloop[looptri[i].tri[0]].v;
+ r_verttri[i].tri[1] = mloop[looptri[i].tri[1]].v;
+ r_verttri[i].tri[2] = mloop[looptri[i].tri[2]].v;
+ }
+}
+
+
+bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh)
+{
+ if (mesh->runtime.edit_data != NULL) {
+ return false;
+ }
+
+ mesh->runtime.edit_data = MEM_callocN(sizeof(EditMeshData), "EditMeshData");
+ return true;
+}
+
+bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
+{
+ if (mesh->runtime.edit_data == NULL) {
+ return false;
+ }
+
+ if (mesh->runtime.edit_data->polyCos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->polyCos);
+ if (mesh->runtime.edit_data->polyNos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->polyNos);
+ if (mesh->runtime.edit_data->vertexCos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->vertexCos);
+ if (mesh->runtime.edit_data->vertexNos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->vertexNos);
+
+ MEM_SAFE_FREE(mesh->runtime.edit_data);
+ return true;
+}
+
+void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
+{
+ bvhcache_free(&mesh->runtime.bvh_cache);
+ MEM_SAFE_FREE(mesh->runtime.looptris.array);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Batch Cache Callbacks
+ * \{ */
+
+/* Draw Engine */
+void (*BKE_mesh_batch_cache_dirty_cb)(Mesh *me, int mode) = NULL;
+void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL;
+
+void BKE_mesh_batch_cache_dirty(Mesh *me, int mode)
+{
+ if (me->runtime.batch_cache) {
+ BKE_mesh_batch_cache_dirty_cb(me, mode);
+ }
+}
+void BKE_mesh_batch_cache_free(Mesh *me)
+{
+ if (me->runtime.batch_cache) {
+ BKE_mesh_batch_cache_free_cb(me);
+ }
+}
+
+/** \} */
+
+/** \name Mesh runtime debug helpers.
+ * \{ */
+/* evaluated mesh info printing function,
+ * to help track down differences output */
+
+#ifndef NDEBUG
+#include "BLI_dynstr.h"
+
+static void mesh_runtime_debug_info_layers(
+ DynStr *dynstr, CustomData *cd)
+{
+ int type;
+
+ for (type = 0; type < CD_NUMTYPES; type++) {
+ if (CustomData_has_layer(cd, type)) {
+ /* note: doesnt account for multiple layers */
+ const char *name = CustomData_layertype_name(type);
+ const int size = CustomData_sizeof(type);
+ const void *pt = CustomData_get_layer(cd, type);
+ const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(type, &structname, &structnum);
+ BLI_dynstr_appendf(dynstr,
+ " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name, structname, type, (const void *)pt, size, pt_size);
+ }
+ }
+}
+
+char *BKE_mesh_runtime_debug_info(Mesh *me_eval)
+{
+ DynStr *dynstr = BLI_dynstr_new();
+ char *ret;
+
+ BLI_dynstr_appendf(dynstr, "{\n");
+ BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval);
+#if 0
+ const char *tstr;
+ switch (me_eval->type) {
+ case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break;
+ case DM_TYPE_EDITBMESH: tstr = "DM_TYPE_EDITMESH"; break;
+ case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break;
+ default: tstr = "UNKNOWN"; break;
+ }
+ BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
+#endif
+ BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert);
+ BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge);
+ BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface);
+ BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly);
+ BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only);
+
+ BLI_dynstr_appendf(dynstr, " 'vertexLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'edgeLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->edata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'loopLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'polyLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'tessFaceLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, "}\n");
+
+ ret = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ return ret;
+}
+
+void BKE_mesh_runtime_debug_print(Mesh *me_eval)
+{
+ char *str = BKE_mesh_runtime_debug_info(me_eval);
+ puts(str);
+ fflush(stdout);
+ MEM_freeN(str);
+}
+
+/* XXX Should go in customdata file? */
+void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data)
+{
+ int i;
+ const CustomDataLayer *layer;
+
+ printf("{\n");
+
+ for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
+
+ const char *name = CustomData_layertype_name(layer->type);
+ const int size = CustomData_sizeof(layer->type);
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(layer->type, &structname, &structnum);
+ printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name, structname, layer->type, (const void *)layer->data, size, (int)(MEM_allocN_len(layer->data) / size));
+ }
+
+ printf("}\n");
+}
+
+bool BKE_mesh_runtime_is_valid(Mesh *me_eval)
+{
+ const bool do_verbose = true;
+ const bool do_fixes = false;
+
+ bool is_valid = true;
+ bool changed = true;
+
+ if (do_verbose) {
+ printf("MESH: %s\n", me_eval->id.name + 2);
+ }
+
+ is_valid &= BKE_mesh_validate_all_customdata(
+ &me_eval->vdata, &me_eval->edata, &me_eval->ldata, &me_eval->pdata,
+ false, /* setting mask here isn't useful, gives false positives */
+ do_verbose, do_fixes,
+ &changed);
+
+ is_valid &= BKE_mesh_validate_arrays(
+ me_eval,
+ me_eval->mvert, me_eval->totvert,
+ me_eval->medge, me_eval->totedge,
+ me_eval->mface, me_eval->totface,
+ me_eval->mloop, me_eval->totloop,
+ me_eval->mpoly, me_eval->totpoly,
+ me_eval->dvert,
+ do_verbose, do_fixes,
+ &changed);
+
+ BLI_assert(changed == false);
+
+ return is_valid;
+}
+
+#endif /* NDEBUG */
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
new file mode 100644
index 00000000000..05a5a5e8703
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -0,0 +1,691 @@
+/*
+ * ***** 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_tangent.c
+ * \ingroup bke
+ *
+ * Functions to evaluate mesh tangents.
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_stack.h"
+#include "BLI_task.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
+#include "BKE_report.h"
+
+#include "BLI_strict_flags.h"
+
+#include "atomic_ops.h"
+#include "mikktspace.h"
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Mesh Tangent Calculations (Single Layer)
+ * \{ */
+
+/* Tangent space utils. */
+
+/* User data. */
+typedef struct {
+ const MPoly *mpolys; /* faces */
+ const MLoop *mloops; /* faces's vertices */
+ const MVert *mverts; /* vertices */
+ const MLoopUV *luvs; /* texture coordinates */
+ float (*lnors)[3]; /* loops' normals */
+ float (*tangents)[4]; /* output tangents */
+ int num_polys; /* number of polygons */
+} BKEMeshToTangent;
+
+/* Mikktspace's API */
+static int get_num_faces(const SMikkTSpaceContext *pContext)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->num_polys;
+}
+
+static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->mpolys[face_idx].totloop;
+}
+
+static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
+ copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
+}
+
+static void get_texture_coordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx,
+ const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
+}
+
+static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
+}
+
+static void set_tspace(const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign,
+ const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
+ copy_v3_v3(p_res, fv_tangent);
+ p_res[3] = face_sign;
+}
+
+/**
+ * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
+ * split normals can be used to recreate the full tangent space.
+ * Note: * The mesh should be made of only tris and quads!
+ */
+void BKE_mesh_calc_loop_tangent_single_ex(
+ const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
+ float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
+ const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
+ ReportList *reports)
+{
+ BKEMeshToTangent mesh_to_tangent = {NULL};
+ SMikkTSpaceContext s_context = {NULL};
+ SMikkTSpaceInterface s_interface = {NULL};
+
+ const MPoly *mp;
+ int mp_index;
+
+ /* First check we do have a tris/quads only mesh. */
+ for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ if (mp->totloop > 4) {
+ BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
+ return;
+ }
+ }
+
+ /* Compute Mikktspace's tangent normals. */
+ mesh_to_tangent.mpolys = mpolys;
+ mesh_to_tangent.mloops = mloops;
+ mesh_to_tangent.mverts = mverts;
+ mesh_to_tangent.luvs = loopuvs;
+ mesh_to_tangent.lnors = loopnors;
+ mesh_to_tangent.tangents = r_looptangent;
+ mesh_to_tangent.num_polys = numPolys;
+
+ s_context.m_pUserData = &mesh_to_tangent;
+ s_context.m_pInterface = &s_interface;
+ s_interface.m_getNumFaces = get_num_faces;
+ s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
+ s_interface.m_getPosition = get_position;
+ s_interface.m_getTexCoord = get_texture_coordinate;
+ s_interface.m_getNormal = get_normal;
+ s_interface.m_setTSpaceBasic = set_tspace;
+
+ /* 0 if failed */
+ if (genTangSpaceDefault(&s_context) == false) {
+ BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
+ }
+}
+
+/**
+ * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
+ * \note
+ * - There must be a valid loop's CD_NORMALS available.
+ * - The mesh should be made of only tris and quads!
+ */
+void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
+{
+ MLoopUV *loopuvs;
+ float (*loopnors)[3];
+
+ /* Check we have valid texture coordinates first! */
+ if (uvmap) {
+ loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
+ }
+ else {
+ loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
+ }
+ if (!loopuvs) {
+ BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
+ return;
+ }
+
+ loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ if (!loopnors) {
+ BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
+ return;
+ }
+
+ BKE_mesh_calc_loop_tangent_single_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
+ loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Mesh Tangent Calculations (All Layers)
+ * \{ */
+
+
+/* Necessary complexity to handle looptri's as quads for correct tangents */
+#define USE_LOOPTRI_DETECT_QUADS
+
+typedef struct {
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const MLoopTri *looptri;
+ MLoopUV *mloopuv; /* texture coordinates */
+ const MPoly *mpoly; /* indices */
+ const MLoop *mloop; /* indices */
+ const MVert *mvert; /* vertices & normals */
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
+#endif
+
+} SGLSLMeshToTangent;
+
+/* interface */
+static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ return pMesh->num_face_as_quad_map;
+#else
+ return pMesh->numTessFaces;
+#endif
+}
+
+static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ return 4;
+ }
+ }
+ return 3;
+#else
+ UNUSED_VARS(pContext, face_num);
+ return 3;
+#endif
+}
+
+static void dm_ts_GetPosition(
+ const SMikkTSpaceContext *pContext, float r_co[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+ const float *co;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
+ copy_v3_v3(r_co, co);
+}
+
+static void dm_ts_GetTextureCoordinate(
+ const SMikkTSpaceContext *pContext, float r_uv[2],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ if (pMesh->mloopuv != NULL) {
+ const float *uv = pMesh->mloopuv[loop_index].uv;
+ copy_v2_v2(r_uv, uv);
+ }
+ else {
+ const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
+ map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+ }
+}
+
+static void dm_ts_GetNormal(
+ const SMikkTSpaceContext *pContext, float r_no[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ if (pMesh->precomputedLoopNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
+ }
+ else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
+ if (pMesh->precomputedFaceNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
+ }
+ else {
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ normal_quad_v3(
+ r_no,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
+ }
+ else
+#endif
+ {
+ normal_tri_v3(
+ r_no,
+ pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
+ }
+ }
+ }
+ else {
+ const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
+ normal_short_to_float_v3(r_no, no);
+ }
+}
+
+static void dm_ts_SetTSpace(
+ const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+ float *pRes;
+
+finally:
+ pRes = pMesh->tangent[loop_index];
+ copy_v3_v3(pRes, fvTangent);
+ pRes[3] = fSign;
+}
+
+static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct SGLSLMeshToTangent *mesh2tangent = taskdata;
+ /* new computation method */
+ {
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+
+ sContext.m_pUserData = mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = dm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = dm_ts_GetPosition;
+ sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = dm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
+
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
+}
+
+void BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ CustomData *uv_data, CustomData *tan_data, int numLoopData,
+ const char *layer_name)
+{
+ if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
+ CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1)
+ {
+ CustomData_add_layer_named(
+ tan_data, CD_TANGENT, CD_CALLOC, NULL,
+ numLoopData, layer_name);
+ }
+}
+
+/**
+ * Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
+ * Also, we calculate tangent_mask that works as a descriptor of tangents state.
+ * If tangent_mask has changed, then recalculate tangents.
+ */
+void BKE_mesh_calc_loop_tangent_step_0(
+ const CustomData *loopData, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_count,
+ bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+ char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
+{
+ /* Active uv in viewport */
+ int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
+ *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
+ ract_uv_name[0] = 0;
+ if (*ract_uv_n != -1) {
+ strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
+ }
+
+ /* Active tangent in render */
+ *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
+ rren_uv_name[0] = 0;
+ if (*rren_uv_n != -1) {
+ strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
+ }
+
+ /* If active tangent not in tangent_names we take it into account */
+ *rcalc_act = false;
+ *rcalc_ren = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] == 0) {
+ calc_active_tangent = true;
+ }
+ }
+ if (calc_active_tangent) {
+ *rcalc_act = true;
+ *rcalc_ren = true;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (STREQ(ract_uv_name, tangent_names[i]))
+ *rcalc_act = false;
+ if (STREQ(rren_uv_name, tangent_names[i]))
+ *rcalc_ren = false;
+ }
+ }
+ *rtangent_mask = 0;
+
+ const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
+ for (int n = 0; n < uv_layer_num; n++) {
+ const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
+ bool add = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
+ add = true;
+ break;
+ }
+ }
+ if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
+ (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name))))
+ {
+ add = true;
+ }
+ if (add)
+ *rtangent_mask |= (short)(1 << n);
+ }
+
+ if (uv_layer_num == 0)
+ *rtangent_mask |= DM_TANGENT_MASK_ORCO;
+}
+
+/**
+ * See: #BKE_editmesh_loop_tangent_calc (matching logic).
+ */
+void BKE_mesh_calc_loop_tangent_ex(
+ const MVert *mvert,
+ const MPoly *mpoly, const uint mpoly_len,
+ const MLoop *mloop,
+ const MLoopTri *looptri,
+ const uint looptri_len,
+
+ CustomData *loopdata,
+ bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p)
+{
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ short tangent_mask = 0;
+ short tangent_mask_curr = *tangent_mask_curr_p;
+
+ BKE_mesh_calc_loop_tangent_step_0(
+ loopdata, calc_active_tangent, tangent_names, tangent_names_len,
+ &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+ if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
+ /* Check we have all the needed layers */
+ /* Allocate needed tangent layers */
+ for (int i = 0; i < tangent_names_len; i++)
+ if (tangent_names[i][0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
+ if (calc_act && act_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (looptri_len != mpoly_len) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * looptri_len, __func__);
+ int k, j;
+ for (k = 0, j = 0; j < (int)looptri_len; k++, j++) {
+ face_as_quad_map[k] = j;
+ /* step over all quads */
+ if (mpoly[looptri[j].poly].totloop == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = k;
+ }
+ else {
+ num_face_as_quad_map = (int)looptri_len;
+ }
+#endif
+
+ /* Calculation */
+ if (looptri_len != 0) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ tangent_mask_curr = 0;
+ /* Calculate tangent layers */
+ SGLSLMeshToTangent data_array[MAX_MTFACE];
+ const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
+ for (int n = 0; n < tangent_layer_num; n++) {
+ int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = (int)looptri_len;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+#endif
+ mesh2tangent->mvert = mvert;
+ mesh2tangent->mpoly = mpoly;
+ mesh2tangent->mloop = mloop;
+ mesh2tangent->looptri = looptri;
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = loop_normals;
+ mesh2tangent->precomputedFaceNormals = poly_normals;
+
+ mesh2tangent->orco = NULL;
+ mesh2tangent->mloopuv = CustomData_get_layer_named(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
+
+ /* Fill the resulting tangent_mask */
+ if (!mesh2tangent->mloopuv) {
+ mesh2tangent->orco = vert_orco;
+ if (!mesh2tangent->orco)
+ continue;
+
+ tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
+ }
+ else {
+ int uv_ind = CustomData_get_named_layer_index(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
+ int uv_start = CustomData_get_layer_index(loopdata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ tangent_mask_curr |= (short)(1 << (uv_ind - uv_start));
+ }
+
+ mesh2tangent->tangent = loopdata_out->layers[index].data;
+ BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
+
+ BLI_assert(tangent_mask_curr == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
+ else {
+ tangent_mask_curr = tangent_mask;
+ }
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+#undef USE_LOOPTRI_DETECT_QUADS
+
+#endif
+
+ *tangent_mask_curr_p = tangent_mask_curr;
+
+ /* Update active layer index */
+ int act_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name);
+ CustomData_set_layer_active_index(loopdata, CD_TANGENT, tan_index);
+ }/* else tangent has been built from orco */
+
+ /* Update render layer index */
+ int ren_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name);
+ CustomData_set_layer_render_index(loopdata, CD_TANGENT, tan_index);
+ }/* else tangent has been built from orco */
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index b0577fdd50d..2b43d49a10f 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -43,10 +43,11 @@
#include "BLI_math_vector.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
+#include "DEG_depsgraph.h"
+
#include "MEM_guardedalloc.h"
/* loop v/e are unsigned, so using max uint_32 value as invalid marker... */
@@ -936,7 +937,7 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
{
bool is_valid = true;
bool is_change_v, is_change_e, is_change_l, is_change_p;
- int tot_texpoly, tot_uvloop, tot_vcolloop;
+ int tot_uvloop, tot_vcolloop;
CustomDataMask mask = check_meshmask ? CD_MASK_MESH : 0;
is_valid &= mesh_validate_customdata(vdata, mask, do_verbose, do_fixes, &is_change_v);
@@ -944,17 +945,8 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
is_valid &= mesh_validate_customdata(ldata, mask, do_verbose, do_fixes, &is_change_l);
is_valid &= mesh_validate_customdata(pdata, mask, do_verbose, do_fixes, &is_change_p);
- tot_texpoly = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV);
tot_vcolloop = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
- if (tot_texpoly != tot_uvloop) {
- PRINT_ERR("\tCustomDataLayer mismatch, tot_texpoly(%d), tot_uvloop(%d)\n",
- tot_texpoly, tot_uvloop);
- }
- if (tot_texpoly > MAX_MTFACE) {
- PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, tot_texpoly - MAX_MTFACE);
- }
if (tot_uvloop > MAX_MTFACE) {
PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
MAX_MTFACE, tot_uvloop - MAX_MTFACE);
@@ -965,18 +957,10 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
}
/* check indices of clone/stencil */
- if (do_fixes && CustomData_get_clone_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) {
- CustomData_set_layer_clone(pdata, CD_MTEXPOLY, 0);
- is_change_p = true;
- }
if (do_fixes && CustomData_get_clone_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
CustomData_set_layer_clone(ldata, CD_MLOOPUV, 0);
is_change_l = true;
}
- if (do_fixes && CustomData_get_stencil_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) {
- CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, 0);
- is_change_p = true;
- }
if (do_fixes && CustomData_get_stencil_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
CustomData_set_layer_stencil(ldata, CD_MLOOPUV, 0);
is_change_l = true;
@@ -988,7 +972,7 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
}
/**
- * \see #DM_is_valid to call on derived meshes
+ * Validates and corrects a Mesh.
*
* \returns true if a change is made.
*/
@@ -1019,7 +1003,7 @@ int BKE_mesh_validate(Mesh *me, const int do_verbose, const int cddata_check_mas
&changed);
if (changed) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
return true;
}
else {
@@ -1028,61 +1012,39 @@ int BKE_mesh_validate(Mesh *me, const int do_verbose, const int cddata_check_mas
}
/**
- * Duplicate of BM_mesh_cd_validate() for Mesh data.
+ * Checks if a Mesh is valid without any modification. This is always verbose.
+ *
+ * \see #DM_is_valid to call on derived meshes
+ *
+ * \returns is_valid.
*/
-void BKE_mesh_cd_validate(Mesh *me)
+bool BKE_mesh_is_valid(Mesh *me)
{
- int totlayer_mtex = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
- int totlayer_uv = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
- int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
- int mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
- int uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
- int i;
+ const bool do_verbose = true;
+ const bool do_fixes = false;
- /* XXX For now, do not delete those, just warn they are not really usable. */
- if (UNLIKELY(totlayer_mtex > MAX_MTFACE)) {
- printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, totlayer_mtex - MAX_MTFACE);
- }
- if (UNLIKELY(totlayer_uv > MAX_MTFACE)) {
- printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, totlayer_uv - MAX_MTFACE);
- }
- if (UNLIKELY(totlayer_mcol > MAX_MCOL)) {
- printf("WARNING! More VCol layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MCOL, totlayer_mcol - MAX_MCOL);
- }
+ bool is_valid = true;
+ bool changed = true;
- if (LIKELY(totlayer_mtex == totlayer_uv)) {
- /* pass */
- }
- else if (totlayer_mtex < totlayer_uv) {
- do {
- const char *from_name = me->ldata.layers[uv_index + totlayer_mtex].name;
- CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, from_name);
- CustomData_set_layer_unique_name(&me->pdata, totlayer_mtex);
- } while (totlayer_uv != ++totlayer_mtex);
- mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
- }
- else if (totlayer_uv < totlayer_mtex) {
- do {
- const char *from_name = me->pdata.layers[mtex_index + totlayer_uv].name;
- CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, from_name);
- CustomData_set_layer_unique_name(&me->ldata, totlayer_uv);
- } while (totlayer_mtex != ++totlayer_uv);
- uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
- }
+ is_valid &= BKE_mesh_validate_all_customdata(
+ &me->vdata, &me->edata, &me->ldata, &me->pdata,
+ false, /* setting mask here isn't useful, gives false positives */
+ do_verbose, do_fixes, &changed);
- BLI_assert(totlayer_mtex == totlayer_uv);
+ is_valid &= BKE_mesh_validate_arrays(
+ me,
+ me->mvert, me->totvert,
+ me->medge, me->totedge,
+ me->mface, me->totface,
+ me->mloop, me->totloop,
+ me->mpoly, me->totpoly,
+ me->dvert,
+ do_verbose, do_fixes,
+ &changed);
- /* Check uv/tex names match as well!!! */
- for (i = 0; i < totlayer_mtex; i++, mtex_index++, uv_index++) {
- const char *name_src = me->pdata.layers[mtex_index].name;
- const char *name_dst = me->ldata.layers[uv_index].name;
- if (!STREQ(name_src, name_dst)) {
- BKE_mesh_uv_cdlayer_rename_index(me, mtex_index, uv_index, -1, name_src, false);
- }
- }
+ BLI_assert(changed == false);
+
+ return is_valid;
}
/**
@@ -1105,7 +1067,7 @@ int BKE_mesh_validate_material_indices(Mesh *me)
}
if (!is_valid) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
return true;
}
else {
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 9fc3fc4ba64..4c2a58e7126 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -46,6 +46,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
@@ -58,17 +59,25 @@
#include "BLT_translation.h"
#include "BKE_appdir.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
+#include "BKE_idcode.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_DerivedMesh.h"
/* may move these, only for modifier_path_relbase */
#include "BKE_main.h"
/* end */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "MOD_modifiertypes.h"
static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL};
@@ -127,6 +136,7 @@ ModifierData *modifier_new(int type)
md->type = type;
md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded;
+ md->flag = eModifierFlag_StaticOverride_Local;
if (mti->flags & eModifierTypeFlag_EnableInEditmode)
md->mode |= eModifierMode_Editmode;
@@ -313,6 +323,7 @@ void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
target->mode = md->mode;
+ target->flag = md->flag;
if (mti->copyData) {
mti->copyData(md, target);
@@ -338,9 +349,7 @@ bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
- return ((!mti->isDisabled || !mti->isDisabled(md, 0)) &&
+ return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
(mti->flags & eModifierTypeFlag_SupportsEditmode) &&
modifier_supportsMapping(md));
}
@@ -349,11 +358,9 @@ bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
return ((md->mode & eModifierMode_Realtime) &&
(md->mode & eModifierMode_Editmode) &&
- (!mti->isDisabled || !mti->isDisabled(md, 0)) &&
+ (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
modifier_supportsMapping(md));
}
@@ -410,9 +417,7 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
bool supports_mapping;
- md->scene = scene;
-
- if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue;
if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
if (md->mode & eModifierMode_DisableTemporary) continue;
@@ -468,14 +473,12 @@ bool modifiers_isParticleEnabled(Object *ob)
*
* \param scene Current scene, may be NULL, in which case isDisabled callback of the modifier is never called.
*/
-bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode)
+bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int required_mode)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if ((md->mode & required_mode) != required_mode) return false;
- if (scene != NULL && mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false;
+ if (scene != NULL && mti->isDisabled && mti->isDisabled(scene, md, required_mode == eModifierMode_Render)) return false;
if (md->mode & eModifierMode_DisableTemporary) return false;
if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false;
@@ -619,6 +622,27 @@ Object *modifiers_isDeformedByArmature(Object *ob)
return NULL;
}
+Object *modifiers_isDeformedByMeshDeform(Object *ob)
+{
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ MeshDeformModifierData *mdmd = NULL;
+
+ /* return the first selected armature, this lets us use multiple armatures */
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_MeshDeform) {
+ mdmd = (MeshDeformModifierData *) md;
+ if (mdmd->object && (mdmd->object->flag & SELECT))
+ return mdmd->object;
+ }
+ }
+
+ if (mdmd) /* if were still here then return the last armature */
+ return mdmd->object;
+
+ return NULL;
+}
+
/* Takes an object and returns its first selected lattice, else just its lattice
* This should work for multiple lattices per object
*/
@@ -686,7 +710,7 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm)
bool modifier_isCorrectableDeformed(ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return (mti->deformMatricesEM != NULL);
+ return (mti->deformMatricesEM != NULL) || (mti->deformMatricesEM_DM != NULL);
}
bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
@@ -695,9 +719,9 @@ bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
int required_mode = eModifierMode_Realtime;
- if (ob->mode == OB_MODE_EDIT)
+ if (ob->mode == OB_MODE_EDIT) {
required_mode |= eModifierMode_Editmode;
-
+ }
for (; md; md = md->next) {
if (!modifier_isEnabled(scene, md, required_mode)) {
/* pass */
@@ -803,9 +827,8 @@ void modifier_path_init(char *path, int path_maxlen, const char *name)
/* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */
struct DerivedMesh *modwrap_applyModifier(
- ModifierData *md, Object *ob,
- struct DerivedMesh *dm,
- ModifierApplyFlag flag)
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct DerivedMesh *dm)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
@@ -813,14 +836,12 @@ struct DerivedMesh *modwrap_applyModifier(
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
DM_ensure_normals(dm);
}
- return mti->applyModifier(md, ob, dm, flag);
+ return modifier_applyModifier_DM_deprecated(md, ctx, dm);
}
struct DerivedMesh *modwrap_applyModifierEM(
- ModifierData *md, Object *ob,
- struct BMEditMesh *em,
- DerivedMesh *dm,
- ModifierApplyFlag flag)
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *em, DerivedMesh *dm)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
@@ -828,14 +849,12 @@ struct DerivedMesh *modwrap_applyModifierEM(
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
DM_ensure_normals(dm);
}
- return mti->applyModifierEM(md, ob, em, dm, flag);
+ return modifier_applyModifierEM_DM_deprecated(md, ctx, em, dm);
}
void modwrap_deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts,
- ModifierApplyFlag flag)
+ ModifierData *md, const ModifierEvalContext *ctx,
+ DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
@@ -843,11 +862,11 @@ void modwrap_deformVerts(
if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
DM_ensure_normals(dm);
}
- mti->deformVerts(md, ob, dm, vertexCos, numVerts, flag);
+ modifier_deformVerts_DM_deprecated(md, ctx, dm, vertexCos, numVerts);
}
void modwrap_deformVertsEM(
- ModifierData *md, Object *ob,
+ ModifierData *md, const ModifierEvalContext *ctx,
struct BMEditMesh *em, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
{
@@ -857,6 +876,367 @@ void modwrap_deformVertsEM(
if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
DM_ensure_normals(dm);
}
- mti->deformVertsEM(md, ob, em, dm, vertexCos, numVerts);
+ modifier_deformVertsEM_DM_deprecated(md, ctx, em, dm, vertexCos, numVerts);
}
/* end modifier callback wrappers */
+
+
+/* wrappers for modifier callbacks that accept Mesh and select the proper implementation
+ * depending on if the modifier has been ported to Mesh or is still using DerivedMesh
+ */
+
+void modifier_deformVerts(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->deformVerts) {
+ mti->deformVerts(md, ctx, mesh, vertexCos, numVerts);
+ }
+ else {
+ DerivedMesh *dm = NULL;
+ if (mesh) {
+ dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
+ }
+
+ mti->deformVerts_DM(md, ctx, dm, vertexCos, numVerts);
+
+ if (dm) {
+ dm->release(dm);
+ }
+ }
+}
+
+void modifier_deformVerts_ensure_normals(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ BLI_assert(!mesh || CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false);
+
+ if (mesh && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ BKE_mesh_calc_normals(mesh);
+ }
+ modifier_deformVerts(md, ctx, mesh, vertexCos, numVerts);
+}
+
+void modifier_deformMatrices(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *mesh,
+ float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->deformMatrices) {
+ mti->deformMatrices(md, ctx, mesh, vertexCos, defMats, numVerts);
+ }
+ else {
+ DerivedMesh *dm = NULL;
+ if (mesh) {
+ dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
+ }
+
+ mti->deformMatrices_DM(md, ctx, dm, vertexCos, defMats, numVerts);
+
+ if (dm) {
+ dm->release(dm);
+ }
+ }
+}
+
+void modifier_deformVertsEM(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData, struct Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->deformVertsEM) {
+ mti->deformVertsEM(md, ctx, editData, mesh, vertexCos, numVerts);
+ }
+ else {
+ DerivedMesh *dm = NULL;
+ if (mesh) {
+ dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
+ }
+
+ mti->deformVertsEM_DM(md, ctx, editData, dm, vertexCos, numVerts);
+
+ if (dm) {
+ dm->release(dm);
+ }
+ }
+}
+
+void modifier_deformMatricesEM(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData, struct Mesh *mesh,
+ float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->deformMatricesEM) {
+ mti->deformMatricesEM(md, ctx, editData, mesh, vertexCos, defMats, numVerts);
+ }
+ else {
+ DerivedMesh *dm = NULL;
+ if (mesh) {
+ dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
+ }
+
+ mti->deformMatricesEM_DM(md, ctx, editData, dm, vertexCos, defMats, numVerts);
+
+ if (dm) {
+ dm->release(dm);
+ }
+ }
+}
+
+struct Mesh *modifier_applyModifier(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *mesh)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->applyModifier) {
+ return mti->applyModifier(md, ctx, mesh);
+ }
+ else {
+ DerivedMesh *dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
+
+ DerivedMesh *ndm = mti->applyModifier_DM(md, ctx, dm);
+
+ if (ndm != dm) {
+ dm->release(dm);
+ }
+
+ DM_to_mesh(ndm, mesh, ctx->object, CD_MASK_EVERYTHING, true);
+
+ return mesh;
+ }
+}
+
+struct Mesh *modifier_applyModifier_ensure_normals(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *mesh)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false);
+
+ if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ BKE_mesh_calc_normals(mesh);
+ }
+ return modifier_applyModifier(md, ctx, mesh);
+}
+
+struct Mesh *modifier_applyModifierEM(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ struct Mesh *mesh)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->applyModifierEM) {
+ return mti->applyModifierEM(md, ctx, editData, mesh);
+ }
+ else {
+ DerivedMesh *dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
+
+ DerivedMesh *ndm = mti->applyModifierEM_DM(md, ctx, editData, dm);
+
+ if (ndm != dm) {
+ dm->release(dm);
+ }
+
+ DM_to_mesh(ndm, mesh, ctx->object, CD_MASK_EVERYTHING, true);
+
+ return mesh;
+ }
+}
+
+/* depricated variants of above that accept DerivedMesh */
+
+void modifier_deformVerts_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct DerivedMesh *dm,
+ float (*vertexCos)[3], int numVerts)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->deformVerts_DM) {
+ mti->deformVerts_DM(md, ctx, dm, vertexCos, numVerts);
+ }
+ else {
+ /* TODO(sybren): deduplicate all the copies of this code in this file. */
+ Mesh *mesh = NULL;
+ if (dm != NULL) {
+ mesh = BKE_id_new_nomain(ID_ME, NULL);
+ DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
+ }
+
+ mti->deformVerts(md, ctx, mesh, vertexCos, numVerts);
+
+ if (mesh != NULL) {
+ BKE_id_free(NULL, mesh);
+ }
+ }
+}
+
+void modifier_deformMatrices_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct DerivedMesh *dm,
+ float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
+{
+
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->deformMatrices_DM) {
+ mti->deformMatrices_DM(md, ctx, dm, vertexCos, defMats, numVerts);
+ }
+ else {
+ /* TODO(sybren): deduplicate all the copies of this code in this file. */
+ Mesh *mesh = NULL;
+ if (dm != NULL) {
+ mesh = BKE_id_new_nomain(ID_ME, NULL);
+ DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
+ }
+
+ mti->deformMatrices(md, ctx, mesh, vertexCos, defMats, numVerts);
+
+ if (mesh != NULL) {
+ BKE_id_free(NULL, mesh);
+ }
+ }
+}
+
+void modifier_deformVertsEM_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData, struct DerivedMesh *dm,
+ float (*vertexCos)[3], int numVerts)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->deformVertsEM_DM) {
+ mti->deformVertsEM_DM(md, ctx, editData, dm, vertexCos, numVerts);
+ }
+ else {
+ /* TODO(sybren): deduplicate all the copies of this code in this file. */
+ Mesh *mesh = NULL;
+ if (dm != NULL) {
+ mesh = BKE_id_new_nomain(ID_ME, NULL);
+ DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
+ }
+
+ mti->deformVertsEM(md, ctx, editData, mesh, vertexCos, numVerts);
+
+ if (mesh != NULL) {
+ BKE_id_free(NULL, mesh);
+ }
+ }
+}
+
+void modifier_deformMatricesEM_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData, struct DerivedMesh *dm,
+ float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->deformMatricesEM_DM) {
+ mti->deformMatricesEM_DM(md, ctx, editData, dm, vertexCos, defMats, numVerts);
+ }
+ else {
+ /* TODO(sybren): deduplicate all the copies of this code in this file. */
+ Mesh *mesh = NULL;
+ if (dm != NULL) {
+ mesh = BKE_id_new_nomain(ID_ME, NULL);
+ DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
+ }
+
+ mti->deformMatricesEM(md, ctx, editData, mesh, vertexCos, defMats, numVerts);
+
+ if (mesh != NULL) {
+ BKE_id_free(NULL, mesh);
+ }
+ }
+}
+
+struct DerivedMesh *modifier_applyModifier_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct DerivedMesh *dm)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->applyModifier_DM) {
+ return mti->applyModifier_DM(md, ctx, dm);
+ }
+ else {
+ /* TODO(sybren): deduplicate all the copies of this code in this file. */
+ Mesh *mesh = NULL;
+ if (dm != NULL) {
+ mesh = BKE_id_new_nomain(ID_ME, NULL);
+ DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
+ }
+
+ struct Mesh *new_mesh = mti->applyModifier(md, ctx, mesh);
+
+ /* Make a DM that doesn't reference new_mesh so we can free the latter. */
+ DerivedMesh *ndm = CDDM_from_mesh_ex(new_mesh, CD_DUPLICATE, CD_MASK_EVERYTHING);
+
+ if (new_mesh != mesh) {
+ BKE_id_free(NULL, new_mesh);
+ }
+ if (mesh != NULL) {
+ BKE_id_free(NULL, mesh);
+ }
+
+ return ndm;
+ }
+}
+
+struct DerivedMesh *modifier_applyModifierEM_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ struct DerivedMesh *dm)
+{
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->applyModifierEM_DM) {
+ return mti->applyModifierEM_DM(md, ctx, editData, dm);
+ }
+ else {
+ /* TODO(sybren): deduplicate all the copies of this code in this file. */
+ Mesh *mesh = NULL;
+ if (dm != NULL) {
+ mesh = BKE_id_new_nomain(ID_ME, NULL);
+ DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
+ }
+
+ struct Mesh *new_mesh = mti->applyModifierEM(md, ctx, editData, mesh);
+
+ /* Make a DM that doesn't reference new_mesh so we can free the latter. */
+ DerivedMesh *ndm = CDDM_from_mesh_ex(new_mesh, CD_DUPLICATE, CD_MASK_EVERYTHING);
+
+ if (new_mesh != mesh) {
+ BKE_id_free(NULL, new_mesh);
+ }
+ if (mesh != NULL) {
+ BKE_id_free(NULL, mesh);
+ }
+
+ return ndm;
+ }
+}
+
+/**
+ * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
+ * e.g. second operand for boolean modifier.
+ * Note thqt modifiers in stack always get fully evaluated COW ID pointers, never original ones. Makes things simpler.
+ */
+Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, bool *r_free_mesh)
+{
+ Mesh *me;
+
+ if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) {
+ /* Note: currently we have no equivalent to derived cagemesh or even final dm in BMEditMesh...
+ * This is TODO in core depsgraph/modifier stack code still. */
+ BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ me = BKE_bmesh_to_mesh_nomain(em->bm, &(struct BMeshToMeshParams){0});
+ *r_free_mesh = true;
+ }
+ else {
+ me = ob_eval->runtime.mesh_eval;
+ *r_free_mesh = false;
+ }
+
+ return me;
+}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index a11b0c62aa8..98586a5c2f5 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1609,8 +1609,8 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip,
return result;
}
-void BKE_movieclip_eval_update(struct EvaluationContext *UNUSED(eval_ctx), MovieClip *clip)
+void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, MovieClip *clip)
{
- DEG_debug_print_eval(__func__, clip->id.name, clip);
+ DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
BKE_tracking_dopesheet_tag_update(&clip->tracking);
}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 636157b08dd..00a3e5c77d0 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -51,6 +51,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
@@ -277,14 +278,14 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level)
return mdisps;
}
-DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
+DerivedMesh *get_multires_dm(struct Depsgraph *depsgraph, Scene *scene, MultiresModifierData *mmd, Object *ob)
{
ModifierData *md = (ModifierData *)mmd;
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- DerivedMesh *tdm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+ DerivedMesh *tdm = mesh_get_derived_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
DerivedMesh *dm;
+ ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY};
- dm = mti->applyModifier(md, ob, tdm, MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY);
+ dm = modifier_applyModifier_DM_deprecated(md, &mectx, tdm);
if (dm == tdm) {
dm = CDDM_copy(tdm);
}
@@ -336,17 +337,17 @@ MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_f
return mmd;
}
-static int multires_get_level(Object *ob, MultiresModifierData *mmd,
+static int multires_get_level(Scene *scene, 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, true) : mmd->renderlvl;
+ return (scene != NULL) ? get_render_subsurf_level(&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, false) : mmd->lvl;
+ return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->lvl, false) : mmd->lvl;
}
void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl)
@@ -398,10 +399,10 @@ void multires_force_render_update(Object *ob)
multires_force_update(ob);
}
-int multiresModifier_reshapeFromDM(Scene *scene, MultiresModifierData *mmd,
+int multiresModifier_reshapeFromDM(struct Depsgraph *depsgraph, Scene *scene, MultiresModifierData *mmd,
Object *ob, DerivedMesh *srcdm)
{
- DerivedMesh *mrdm = get_multires_dm(scene, mmd, ob);
+ DerivedMesh *mrdm = get_multires_dm(depsgraph, scene, mmd, ob);
if (mrdm && srcdm && mrdm->getNumVerts(mrdm) == srcdm->getNumVerts(srcdm)) {
multires_mvert_to_ss(mrdm, srcdm->getVertArray(srcdm));
@@ -420,30 +421,30 @@ int multiresModifier_reshapeFromDM(Scene *scene, MultiresModifierData *mmd,
}
/* Returns 1 on success, 0 if the src's totvert doesn't match */
-int multiresModifier_reshape(Scene *scene, MultiresModifierData *mmd, Object *dst, Object *src)
+int multiresModifier_reshape(struct Depsgraph *depsgraph, Scene *scene, MultiresModifierData *mmd, Object *dst, Object *src)
{
- DerivedMesh *srcdm = mesh_get_derived_final(scene, src, CD_MASK_BAREMESH);
- return multiresModifier_reshapeFromDM(scene, mmd, dst, srcdm);
+ DerivedMesh *srcdm = mesh_get_derived_final(depsgraph, scene, src, CD_MASK_BAREMESH);
+ return multiresModifier_reshapeFromDM(depsgraph, scene, mmd, dst, srcdm);
}
-int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mmd,
+int multiresModifier_reshapeFromDeformMod(struct Depsgraph *depsgraph, Scene *scene, MultiresModifierData *mmd,
Object *ob, ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
DerivedMesh *dm, *ndm;
int numVerts, result;
float (*deformedVerts)[3];
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
- if (multires_get_level(ob, mmd, false, true) == 0)
+ if (multires_get_level(scene, ob, mmd, false, true) == 0)
return 0;
/* Create DerivedMesh for deformation modifier */
- dm = get_multires_dm(scene, mmd, ob);
+ dm = get_multires_dm(depsgraph, scene, mmd, ob);
numVerts = dm->getNumVerts(dm);
deformedVerts = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "multiresReshape_deformVerts");
dm->getVertCos(dm, deformedVerts);
- mti->deformVerts(md, ob, dm, deformedVerts, numVerts, 0);
+ modifier_deformVerts_DM_deprecated(md, &mectx, dm, deformedVerts, numVerts);
ndm = CDDM_copy(dm);
CDDM_apply_vert_coords(ndm, deformedVerts);
@@ -452,7 +453,7 @@ int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mm
dm->release(dm);
/* Reshaping */
- result = multiresModifier_reshapeFromDM(scene, mmd, ob, ndm);
+ result = multiresModifier_reshapeFromDM(depsgraph, scene, mmd, ob, ndm);
/* Cleanup */
ndm->release(ndm);
@@ -680,10 +681,10 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
}
/* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */
-void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int direction)
+void multiresModifier_del_levels(MultiresModifierData *mmd, Scene *scene, Object *ob, int direction)
{
Mesh *me = BKE_mesh_from_object(ob);
- int lvl = multires_get_level(ob, mmd, false, true);
+ int lvl = multires_get_level(scene, ob, mmd, false, true);
int levels = mmd->totlvl - lvl;
MDisps *mdisps;
@@ -700,7 +701,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire
multires_set_tot_level(ob, mmd, lvl);
}
-static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, bool alloc_paint_mask)
+static DerivedMesh *multires_dm_create_local(Scene *scene, Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, bool alloc_paint_mask)
{
MultiresModifierData mmd = {{NULL}};
MultiresFlags flags = MULTIRES_USE_LOCAL_MMD;
@@ -714,10 +715,12 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv
if (alloc_paint_mask)
flags |= MULTIRES_ALLOC_PAINT_MASK;
- return multires_make_derived_from_derived(dm, &mmd, ob, flags);
+ return multires_make_derived_from_derived(dm, &mmd, scene, ob, flags);
}
-static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal, int plain_uv, int alloc_paint_mask)
+static DerivedMesh *subsurf_dm_create_local(
+ Scene *scene, Object *ob, DerivedMesh *dm,
+ int lvl, int simple, int optimal, int plain_uv, int alloc_paint_mask)
{
SubsurfModifierData smd = {{NULL}};
SubsurfFlags flags = 0;
@@ -736,7 +739,7 @@ static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl
if (alloc_paint_mask)
flags |= SUBSURF_ALLOC_PAINT_MASK;
- return subsurf_make_derived_from_derived(dm, &smd, NULL, flags);
+ return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags);
}
@@ -750,7 +753,7 @@ static float v3_dist_from_plane(float v[3], float center[3], float no[3])
return dot_v3v3(s, no);
}
-void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
+void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object *ob)
{
DerivedMesh *cddm, *dispdm, *origdm;
Mesh *me;
@@ -772,7 +775,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
/* generate highest level with displacements */
cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- dispdm = multires_dm_create_local(ob, cddm, totlvl, totlvl, 0, 0);
+ dispdm = multires_dm_create_local(scene, ob, cddm, totlvl, totlvl, 0, 0);
cddm->release(cddm);
/* copy the new locations of the base verts into the mesh */
@@ -868,7 +871,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
/* subdivide the mesh to highest level without displacements */
cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
+ origdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, 0, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
cddm->release(cddm);
/* calc disps */
@@ -878,7 +881,9 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
dispdm->release(dispdm);
}
-static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl, int updateblock, int simple)
+static void multires_subdivide(
+ MultiresModifierData *mmd, Scene *scene, Object *ob,
+ int totlvl, int updateblock, int simple)
{
Mesh *me = ob->data;
MDisps *mdisps;
@@ -907,11 +912,11 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
/* create subsurf DM from original mesh at high level */
cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
+ highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
ss = ((CCGDerivedMesh *)highdm)->ss;
/* create multires DM from original mesh at low level */
- lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask);
+ lowdm = multires_dm_create_local(scene, ob, cddm, lvl, lvl, simple, has_mask);
BLI_assert(lowdm != cddm);
cddm->release(cddm);
@@ -961,9 +966,9 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
multires_set_tot_level(ob, mmd, totlvl);
}
-void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple)
+void multiresModifier_subdivide(MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple)
{
- multires_subdivide(mmd, ob, mmd->totlvl + 1, updateblock, simple);
+ multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple);
}
static void grid_tangent(const CCGKey *key, int x, int y, int axis, CCGElem *grid, float t[3])
@@ -1196,7 +1201,7 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm
}
}
-void multires_modifier_update_mdisps(struct DerivedMesh *dm)
+void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
Object *ob;
@@ -1228,11 +1233,11 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm)
else cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
+ highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
ss = ((CCGDerivedMesh *)highdm)->ss;
/* create multires DM from original mesh and displacements */
- lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple, has_mask);
+ lowdm = multires_dm_create_local(scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask);
cddm->release(cddm);
/* gather grid data */
@@ -1290,7 +1295,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm)
else cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
+ subdm = subsurf_dm_create_local(scene, ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
cddm->release(cddm);
multiresModifier_disp_run(dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl);
@@ -1332,126 +1337,6 @@ void multires_modifier_update_hidden(DerivedMesh *dm)
}
}
-void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
-{
- DerivedMesh *ccgdm = NULL, *subsurf = NULL;
- CCGElem **gridData, **subGridData = NULL;
- CCGKey key;
- MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- MDisps *mdisps;
- MultiresModifierData *mmd = get_multires_modifier(NULL, ob, 1);
- int *gridOffset, totlvl;
- int i, k, numGrids, gridSize, dGridSize, dSkip;
-
- if (!mmd)
- return;
-
- mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
-
- if (!mdisps) {
- goto cleanup;
- }
-
- totlvl = mmd->totlvl;
- ccgdm = multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple, false);
-
- subsurf = subsurf_dm_create_local(ob, dm, totlvl,
- mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
-
- numGrids = subsurf->getNumGrids(subsurf);
- gridSize = subsurf->getGridSize(subsurf);
- gridData = subsurf->getGridData(subsurf);
- subsurf->getGridKey(subsurf, &key);
-
- subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
-
- for (i = 0; i < numGrids; i++) {
- subGridData[i] = MEM_calloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData");
- memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize);
- }
-
- /* numGrids = ccgdm->dm->getNumGrids((DerivedMesh *)ccgdm); */ /*UNUSED*/
- gridSize = ccgdm->getGridSize((DerivedMesh *)ccgdm);
- gridData = ccgdm->getGridData((DerivedMesh *)ccgdm);
- gridOffset = ccgdm->getGridOffset((DerivedMesh *)ccgdm);
-
- dGridSize = multires_side_tot[totlvl];
- dSkip = (dGridSize - 1) / (gridSize - 1);
-
- k = 0; /*current loop/mdisp index within the mloop array*/
-
- /* TODO: Use BLI_task parallel range for that one too? */
- for (i = 0; i < dm->numPolyData; ++i) {
- const int numVerts = mpoly[i].totloop;
- int S, x, y, gIndex = gridOffset[i];
-
- for (S = 0; S < numVerts; ++S, ++gIndex, ++k) {
- MDisps *mdisp = &mdisps[mpoly[i].loopstart + S];
- /* CCGElem *grid = gridData[gIndex]; */ /* UNUSED */
- CCGElem *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = NULL;
-
- /* when adding new faces in edit mode, need to allocate disps */
- if (!mdisp->disps) {
- mdisp->totdisp = gridSize * gridSize;
- mdisp->level = totlvl;
- mdisp->disps = MEM_calloc_arrayN(mdisp->totdisp, 3 * sizeof(float), "disp in multires_set_space");
- }
-
- dispgrid = mdisp->disps;
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
- float *co = CCG_grid_elem_co(&key, subgrid, x, y);
- float mat[3][3], dco[3];
-
- /* construct tangent space matrix */
- grid_tangent_matrix(mat, &key, x, y, subgrid);
-
- /* convert to absolute coordinates in space */
- if (from == MULTIRES_SPACE_TANGENT) {
- mul_v3_m3v3(dco, mat, data);
- add_v3_v3(dco, co);
- }
- else if (from == MULTIRES_SPACE_OBJECT) {
- add_v3_v3v3(dco, co, data);
- }
- else if (from == MULTIRES_SPACE_ABSOLUTE) {
- copy_v3_v3(dco, data);
- }
-
- /*now, convert to desired displacement type*/
- if (to == MULTIRES_SPACE_TANGENT) {
- invert_m3(mat);
-
- sub_v3_v3(dco, co);
- mul_v3_m3v3(data, mat, dco);
- }
- else if (to == MULTIRES_SPACE_OBJECT) {
- sub_v3_v3(dco, co);
- mul_v3_m3v3(data, mat, dco);
- }
- else if (to == MULTIRES_SPACE_ABSOLUTE) {
- copy_v3_v3(data, dco);
- }
- }
- }
- }
- }
-
-cleanup:
- if (subsurf) {
- subsurf->needsFree = 1;
- subsurf->release(subsurf);
- }
-
- if (ccgdm) {
- ccgdm->needsFree = 1;
- ccgdm->release(ccgdm);
- }
-}
-
void multires_stitch_grids(Object *ob)
{
/* utility for smooth brush */
@@ -1473,6 +1358,7 @@ void multires_stitch_grids(Object *ob)
DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
MultiresModifierData *mmd,
+ Scene *scene,
Object *ob,
MultiresFlags flags)
{
@@ -1483,13 +1369,13 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
CCGKey key;
const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0;
const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0;
- int lvl = multires_get_level(ob, mmd, render, ignore_simplify);
+ int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify);
int i, gridSize, numGrids;
if (lvl == 0)
return dm;
- result = subsurf_dm_create_local(ob, dm, lvl,
+ result = subsurf_dm_create_local(scene, ob, dm, lvl,
mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges,
mmd->flags & eMultiresModifierFlag_PlainUv,
flags & MULTIRES_ALLOC_PAINT_MASK);
@@ -2168,7 +2054,7 @@ void multires_load_old(Object *ob, Mesh *me)
BLI_insertlinkbefore(&ob->modifiers, md, mmd);
for (i = 0; i < me->mr->level_count - 1; ++i)
- multiresModifier_subdivide(mmd, ob, 1, 0);
+ multiresModifier_subdivide(mmd, NULL, ob, 1, 0);
mmd->lvl = mmd->totlvl;
orig = CDDM_from_mesh(me);
@@ -2177,7 +2063,7 @@ void multires_load_old(Object *ob, Mesh *me)
* reference subsurfed dm with this option, before calling multiresModifier_disp_run(),
* which implicitly expects both subsurfs from its first dm and oldGridData parameters to
* be of the same "format"! */
- dm = multires_make_derived_from_derived(orig, mmd, ob, 0);
+ dm = multires_make_derived_from_derived(orig, mmd, NULL, ob, 0);
multires_load_old_dm(dm, me, mmd->totlvl + 1);
@@ -2192,14 +2078,14 @@ void multires_load_old(Object *ob, Mesh *me)
/* 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)
+void multiresModifier_sync_levels_ex(Scene *scene, Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
{
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);
+ multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
}
else {
multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
@@ -2221,7 +2107,7 @@ static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
}
if (mmd_src && mmd_dst) {
- multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst);
+ multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst);
}
}
@@ -2275,7 +2161,7 @@ static void multires_apply_smat_cb(
}
}
-static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
+static void multires_apply_smat(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float smat[3][3])
{
DerivedMesh *dm = NULL, *cddm = NULL, *subdm = NULL;
CCGElem **gridData, **subGridData;
@@ -2300,10 +2186,10 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
high_mmd.lvl = high_mmd.totlvl;
/* unscaled multires with applied displacement */
- subdm = get_multires_dm(scene, &high_mmd, ob);
+ subdm = get_multires_dm(depsgraph, scene, &high_mmd, ob);
/* prepare scaled CDDM to create ccgDN */
- cddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+ cddm = mesh_get_derived_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
totvert = cddm->getNumVerts(cddm);
vertCos = MEM_malloc_arrayN(totvert, sizeof(*vertCos), "multiresScale vertCos");
@@ -2314,7 +2200,7 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
MEM_freeN(vertCos);
/* scaled ccgDM for tangent space of object with applied scale */
- dm = subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
+ dm = subsurf_dm_create_local(scene, ob, cddm, high_mmd.totlvl, high_mmd.simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
cddm->release(cddm);
gridSize = dm->getGridSize(dm);
@@ -2364,17 +2250,17 @@ int multires_mdisp_corners(MDisps *s)
return 0;
}
-void multiresModifier_scale_disp(Scene *scene, Object *ob)
+void multiresModifier_scale_disp(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
float smat[3][3];
/* object's scale matrix */
BKE_object_scale_to_mat3(ob, smat);
- multires_apply_smat(scene, ob, smat);
+ multires_apply_smat(depsgraph, scene, ob, smat);
}
-void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
+void multiresModifier_prepare_join(struct Depsgraph *depsgraph, Scene *scene, Object *ob, Object *to_ob)
{
float smat[3][3], tmat[3][3], mat[3][3];
multires_sync_levels(scene, to_ob, ob);
@@ -2385,7 +2271,7 @@ void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
BKE_object_scale_to_mat3(ob, smat);
mul_m3_m3m3(mat, smat, tmat);
- multires_apply_smat(scene, ob, mat);
+ multires_apply_smat(depsgraph, scene, ob, mat);
}
/* update multires data after topology changing */
diff --git a/source/blender/blenkernel/intern/navmesh_conversion.c b/source/blender/blenkernel/intern/navmesh_conversion.c
deleted file mode 100644
index 35bcca52f63..00000000000
--- a/source/blender/blenkernel/intern/navmesh_conversion.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * ***** 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) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/navmesh_conversion.c
- * \ingroup bke
- */
-
-#include <math.h>
-#include <stdlib.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_meshdata_types.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_math.h"
-#include "BLI_sort.h"
-
-#include "BKE_navmesh_conversion.h"
-#include "BKE_cdderivedmesh.h"
-
-#include "recast-capi.h"
-
-BLI_INLINE float area2(const float *a, const float *b, const float *c)
-{
- return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]);
-}
-
-BLI_INLINE int left(const float *a, const float *b, const float *c)
-{
- return area2(a, b, c) < 0;
-}
-
-int polyNumVerts(const unsigned short *p, const int vertsPerPoly)
-{
- int i, nv = 0;
- for (i = 0; i < vertsPerPoly; i++) {
- if (p[i] == 0xffff)
- break;
- nv++;
- }
- return nv;
-}
-
-int polyIsConvex(const unsigned short *p, const int vertsPerPoly, const float *verts)
-{
- int j, nv = polyNumVerts(p, vertsPerPoly);
- if (nv < 3)
- return 0;
- for (j = 0; j < nv; j++) {
- const float *v = &verts[3 * p[j]];
- const float *v_next = &verts[3 * p[(j + 1) % nv]];
- const float *v_prev = &verts[3 * p[(nv + j - 1) % nv]];
- if (!left(v_prev, v, v_next))
- return 0;
-
- }
- return 1;
-}
-
-/* XXX, could replace with #dist_to_line_segment_v3(), or add a squared version */
-float distPointToSegmentSq(const float point[3], const float a[3], const float b[3])
-{
- float abx[3], dx[3];
- float d, t;
-
- sub_v3_v3v3(abx, b, a);
- sub_v3_v3v3(dx, point, a);
-
- d = abx[0] * abx[0] + abx[2] * abx[2];
- t = abx[0] * dx[0] + abx[2] * dx[2];
-
- if (d > 0.0f)
- t /= d;
- if (t < 0.0f)
- t = 0.0f;
- else if (t > 1.0f)
- t = 1.0f;
- dx[0] = a[0] + t * abx[0] - point[0];
- dx[2] = a[2] + t * abx[2] - point[2];
-
- return dx[0] * dx[0] + dx[2] * dx[2];
-}
-
-int buildRawVertIndicesData(DerivedMesh *dm, int *nverts_r, float **verts_r,
- int *ntris_r, unsigned short **tris_r, int **trisToFacesMap_r,
- int **recastData)
-{
- int vi, fi, triIdx;
- int nverts, ntris;
- int *trisToFacesMap;
- float *verts;
- unsigned short *tris, *tri;
- int nfaces;
- MFace *faces;
-
- nverts = dm->getNumVerts(dm);
- if (nverts >= 0xffff) {
- printf("Converting navmesh: Error! Too many vertices. Max number of vertices %d\n", 0xffff);
- return 0;
- }
- if (nverts == 0) {
- printf("Converting navmesh: Error! There are no vertices!\n");
- return 0;
- }
-
- verts = MEM_mallocN(sizeof(float[3]) * nverts, "buildRawVertIndicesData verts");
- dm->getVertCos(dm, (float(*)[3])verts);
-
- /* flip coordinates */
- for (vi = 0; vi < nverts; vi++) {
- SWAP(float, verts[3 * vi + 1], verts[3 * vi + 2]);
- }
-
- /* calculate number of tris */
- dm->recalcTessellation(dm);
- nfaces = dm->getNumTessFaces(dm);
- if (nfaces == 0) {
- printf("Converting navmesh: Error! There are %i vertices, but no faces!\n", nverts);
- return 0;
- }
-
- faces = dm->getTessFaceArray(dm);
- ntris = nfaces;
- for (fi = 0; fi < nfaces; fi++) {
- MFace *face = &faces[fi];
- if (face->v4)
- ntris++;
- }
-
- /* copy and transform to triangles (reorder on the run) */
- trisToFacesMap = MEM_callocN(sizeof(int) * ntris, "buildRawVertIndicesData trisToFacesMap");
- tris = MEM_callocN(sizeof(unsigned short) * 3 * ntris, "buildRawVertIndicesData tris");
- tri = tris;
- triIdx = 0;
- for (fi = 0; fi < nfaces; fi++) {
- MFace *face = &faces[fi];
- tri[3 * triIdx + 0] = (unsigned short) face->v1;
- tri[3 * triIdx + 1] = (unsigned short) face->v3;
- tri[3 * triIdx + 2] = (unsigned short) face->v2;
- trisToFacesMap[triIdx++] = fi;
- if (face->v4) {
- tri[3 * triIdx + 0] = (unsigned short) face->v1;
- tri[3 * triIdx + 1] = (unsigned short) face->v4;
- tri[3 * triIdx + 2] = (unsigned short) face->v3;
- trisToFacesMap[triIdx++] = fi;
- }
- }
-
- /* carefully, recast data is just reference to data in derived mesh */
- *recastData = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
-
- *nverts_r = nverts;
- *verts_r = verts;
- *ntris_r = ntris;
- *tris_r = tris;
- *trisToFacesMap_r = trisToFacesMap;
-
- return 1;
-}
-
-int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys,
- unsigned short *polys, const unsigned short *dmeshes,
- const float *verts, const unsigned short *dtris,
- const int *dtrisToPolysMap)
-{
- int polyidx;
- int capacity = vertsPerPoly;
- unsigned short *newPoly = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPoly");
- memset(newPoly, 0xff, sizeof(unsigned short) * capacity);
-
- for (polyidx = 0; polyidx < npolys; polyidx++) {
- size_t i;
- int j, k;
- int nv = 0;
- /* search border */
- int tri, btri = -1;
- int edge, bedge = -1;
- int dtrisNum = dmeshes[polyidx * 4 + 3];
- int dtrisBase = dmeshes[polyidx * 4 + 2];
- unsigned char *traversedTris = MEM_callocN(sizeof(unsigned char) * dtrisNum, "buildPolygonsByDetailedMeshes traversedTris");
- unsigned short *adjustedPoly;
- int adjustedNv;
- int allBorderTraversed;
-
- for (j = 0; j < dtrisNum && btri == -1; j++) {
- int curpolytri = dtrisBase + j;
- for (k = 0; k < 3; k++) {
- unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k];
- if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
- btri = curpolytri;
- bedge = k;
- break;
- }
- }
- }
- if (btri == -1 || bedge == -1) {
- /* can't find triangle with border edge */
- MEM_freeN(traversedTris);
- MEM_freeN(newPoly);
-
- return 0;
- }
-
- newPoly[nv++] = dtris[btri * 3 * 2 + bedge];
- tri = btri;
- edge = (bedge + 1) % 3;
- traversedTris[tri - dtrisBase] = 1;
- while (tri != btri || edge != bedge) {
- int neighbortri = dtris[tri * 3 * 2 + 3 + edge];
- if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
- if (nv == capacity) {
- unsigned short *newPolyBig;
- capacity += vertsPerPoly;
- newPolyBig = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPolyBig");
- memset(newPolyBig, 0xff, sizeof(unsigned short) * capacity);
- memcpy(newPolyBig, newPoly, sizeof(unsigned short) * nv);
- MEM_freeN(newPoly);
- newPoly = newPolyBig;
- }
- newPoly[nv++] = dtris[tri * 3 * 2 + edge];
- /* move to next edge */
- edge = (edge + 1) % 3;
- }
- else {
- /* move to next tri */
- int twinedge = -1;
- for (k = 0; k < 3; k++) {
- if (dtris[neighbortri * 3 * 2 + 3 + k] == tri) {
- twinedge = k;
- break;
- }
- }
- if (twinedge == -1) {
- printf("Converting navmesh: Error! Can't find neighbor edge - invalid adjacency info\n");
- MEM_freeN(traversedTris);
- goto returnLabel;
- }
- tri = neighbortri;
- edge = (twinedge + 1) % 3;
- traversedTris[tri - dtrisBase] = 1;
- }
- }
-
- adjustedPoly = MEM_callocN(sizeof(unsigned short) * nv, "buildPolygonsByDetailedMeshes adjustedPoly");
- adjustedNv = 0;
- for (i = 0; i < nv; i++) {
- unsigned short prev = newPoly[(nv + i - 1) % nv];
- unsigned short cur = newPoly[i];
- unsigned short next = newPoly[(i + 1) % nv];
- float distSq = distPointToSegmentSq(&verts[3 * cur], &verts[3 * prev], &verts[3 * next]);
- static const float tolerance = 0.001f;
- if (distSq > tolerance)
- adjustedPoly[adjustedNv++] = cur;
- }
- memcpy(newPoly, adjustedPoly, adjustedNv * sizeof(unsigned short));
- MEM_freeN(adjustedPoly);
- nv = adjustedNv;
-
- allBorderTraversed = 1;
- for (i = 0; i < dtrisNum; i++) {
- if (traversedTris[i] == 0) {
- /* check whether it has border edges */
- int curpolytri = dtrisBase + i;
- for (k = 0; k < 3; k++) {
- unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k];
- if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
- allBorderTraversed = 0;
- break;
- }
- }
- }
- }
-
- if (nv <= vertsPerPoly && allBorderTraversed) {
- for (i = 0; i < nv; i++) {
- polys[polyidx * vertsPerPoly * 2 + i] = newPoly[i];
- }
- }
-
- MEM_freeN(traversedTris);
- }
-
-returnLabel:
- MEM_freeN(newPoly);
-
- return 1;
-}
-
-struct SortContext {
- const int *recastData;
- const int *trisToFacesMap;
-};
-
-static int compareByData(const void *a, const void *b, void *ctx)
-{
- return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)a]] -
- ((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)b]]);
-}
-
-int buildNavMeshData(const int nverts, const float *verts,
- const int ntris, const unsigned short *tris,
- const int *recastData, const int *trisToFacesMap,
- int *ndtris_r, unsigned short **dtris_r,
- int *npolys_r, unsigned short **dmeshes_r, unsigned short **polys_r,
- int *vertsPerPoly_r, int **dtrisToPolysMap_r, int **dtrisToTrisMap_r)
-
-{
- int *trisMapping;
- int i;
- struct SortContext context;
- int validTriStart, prevPolyIdx, curPolyIdx, newPolyIdx, prevpolyidx;
- unsigned short *dmesh;
-
- int ndtris, npolys, vertsPerPoly;
- unsigned short *dtris, *dmeshes, *polys;
- int *dtrisToPolysMap, *dtrisToTrisMap;
-
- if (!recastData) {
- printf("Converting navmesh: Error! Can't find recast custom data\n");
- return 0;
- }
-
- trisMapping = MEM_callocN(sizeof(int) * ntris, "buildNavMeshData trisMapping");
-
- /* sort the triangles by polygon idx */
- for (i = 0; i < ntris; i++)
- trisMapping[i] = i;
- context.recastData = recastData;
- context.trisToFacesMap = trisToFacesMap;
- BLI_qsort_r(trisMapping, ntris, sizeof(int), compareByData, &context);
-
- /* search first valid triangle - triangle of convex polygon */
- validTriStart = -1;
- for (i = 0; i < ntris; i++) {
- if (recastData[trisToFacesMap[trisMapping[i]]] > 0) {
- validTriStart = i;
- break;
- }
- }
-
- if (validTriStart < 0) {
- printf("Converting navmesh: Error! No valid polygons in mesh\n");
- MEM_freeN(trisMapping);
- return 0;
- }
-
- ndtris = ntris - validTriStart;
- /* fill dtris to faces mapping */
- dtrisToTrisMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToTrisMap");
- memcpy(dtrisToTrisMap, &trisMapping[validTriStart], ndtris * sizeof(int));
- MEM_freeN(trisMapping);
-
- /* create detailed mesh triangles - copy only valid triangles
- * and reserve memory for adjacency info */
- dtris = MEM_callocN(sizeof(unsigned short) * 3 * 2 * ndtris, "buildNavMeshData dtris");
- memset(dtris, 0xff, sizeof(unsigned short) * 3 * 2 * ndtris);
- for (i = 0; i < ndtris; i++) {
- memcpy(dtris + 3 * 2 * i, tris + 3 * dtrisToTrisMap[i], sizeof(unsigned short) * 3);
- }
-
- /* create new recast data corresponded to dtris and renumber for continuous indices */
- prevPolyIdx = -1;
- newPolyIdx = 0;
- dtrisToPolysMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToPolysMap");
- for (i = 0; i < ndtris; i++) {
- curPolyIdx = recastData[trisToFacesMap[dtrisToTrisMap[i]]];
- if (curPolyIdx != prevPolyIdx) {
- newPolyIdx++;
- prevPolyIdx = curPolyIdx;
- }
- dtrisToPolysMap[i] = newPolyIdx;
- }
-
-
- /* build adjacency info for detailed mesh triangles */
- if (!recast_buildMeshAdjacency(dtris, ndtris, nverts, 3)) {
- printf("Converting navmesh: Error! Unable to build mesh adjacency information\n");
- MEM_freeN(trisMapping);
- MEM_freeN(dtrisToPolysMap);
- return 0;
- }
-
- /* create detailed mesh description for each navigation polygon */
- npolys = dtrisToPolysMap[ndtris - 1];
- dmeshes = MEM_callocN(sizeof(unsigned short) * npolys * 4, "buildNavMeshData dmeshes");
- memset(dmeshes, 0, npolys * 4 * sizeof(unsigned short));
- dmesh = NULL;
- prevpolyidx = 0;
- for (i = 0; i < ndtris; i++) {
- int curpolyidx = dtrisToPolysMap[i];
- if (curpolyidx != prevpolyidx) {
- if (curpolyidx != prevpolyidx + 1) {
- printf("Converting navmesh: Error! Wrong order of detailed mesh faces\n");
- goto fail;
- }
- dmesh = dmesh == NULL ? dmeshes : dmesh + 4;
- dmesh[2] = (unsigned short)i; /* tbase */
- dmesh[3] = 0; /* tnum */
- prevpolyidx = curpolyidx;
- }
- dmesh[3]++;
- }
-
- /* create navigation polygons */
- vertsPerPoly = 6;
- polys = MEM_callocN(sizeof(unsigned short) * npolys * vertsPerPoly * 2, "buildNavMeshData polys");
- memset(polys, 0xff, sizeof(unsigned short) * vertsPerPoly * 2 * npolys);
-
- if (!buildPolygonsByDetailedMeshes(vertsPerPoly, npolys, polys, dmeshes, verts, dtris, dtrisToPolysMap)) {
- printf("Converting navmesh: Error! Unable to build polygons from detailed mesh\n");
- goto fail;
- }
-
- *ndtris_r = ndtris;
- *npolys_r = npolys;
- *vertsPerPoly_r = vertsPerPoly;
- *dtris_r = dtris;
- *dmeshes_r = dmeshes;
- *polys_r = polys;
- *dtrisToPolysMap_r = dtrisToPolysMap;
- *dtrisToTrisMap_r = dtrisToTrisMap;
-
- return 1;
-
-fail:
- MEM_freeN(dmeshes);
- MEM_freeN(dtrisToPolysMap);
- MEM_freeN(dtrisToTrisMap);
- return 0;
-}
-
-
-int buildNavMeshDataByDerivedMesh(DerivedMesh *dm, int *vertsPerPoly,
- int *nverts, float **verts,
- int *ndtris, unsigned short **dtris,
- int *npolys, unsigned short **dmeshes,
- unsigned short **polys, int **dtrisToPolysMap,
- int **dtrisToTrisMap, int **trisToFacesMap)
-{
- int res;
- int ntris = 0, *recastData = NULL;
- unsigned short *tris = NULL;
-
- res = buildRawVertIndicesData(dm, nverts, verts, &ntris, &tris, trisToFacesMap, &recastData);
- if (!res) {
- printf("Converting navmesh: Error! Can't get raw vertices and indices from mesh\n");
- goto exit;
- }
-
- res = buildNavMeshData(*nverts, *verts, ntris, tris, recastData, *trisToFacesMap,
- ndtris, dtris, npolys, dmeshes, polys, vertsPerPoly,
- dtrisToPolysMap, dtrisToTrisMap);
- if (!res) {
- printf("Converting navmesh: Error! Can't build navmesh data from mesh\n");
- goto exit;
- }
-
-exit:
- if (tris)
- MEM_freeN(tris);
-
- return res;
-}
-
-int polyFindVertex(const unsigned short *p, const int vertsPerPoly, unsigned short vertexIdx)
-{
- int i, res = -1;
- for (i = 0; i < vertsPerPoly; i++) {
- if (p[i] == 0xffff)
- break;
- if (p[i] == vertexIdx) {
- res = i;
- break;
- }
- }
- return res;
-}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index f91d88a8a4a..91340997532 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -60,7 +60,7 @@
#include "BKE_nla.h"
#ifdef WITH_AUDASPACE
-# include AUD_SPECIAL_H
+# include <AUD_Special.h>
#endif
#include "RNA_access.h"
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 5b279de4d8f..9de31205504 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -75,6 +75,8 @@
#include "NOD_shader.h"
#include "NOD_texture.h"
+#include "DEG_depsgraph.h"
+
#define NODE_DEFAULT_MAX_WIDTH 700
/* Fallback types for undefined tree, nodes, sockets */
@@ -1939,15 +1941,15 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
-bNodeTree *ntreeFromID(ID *id)
+bNodeTree *ntreeFromID(const ID *id)
{
switch (GS(id->name)) {
- case ID_MA: return ((Material *)id)->nodetree;
- case ID_LA: return ((Lamp *)id)->nodetree;
- case ID_WO: return ((World *)id)->nodetree;
- case ID_TE: return ((Tex *)id)->nodetree;
- case ID_SCE: return ((Scene *)id)->nodetree;
- case ID_LS: return ((FreestyleLineStyle *)id)->nodetree;
+ case ID_MA: return ((const Material *)id)->nodetree;
+ case ID_LA: return ((const Lamp *)id)->nodetree;
+ case ID_WO: return ((const World *)id)->nodetree;
+ case ID_TE: return ((const Tex *)id)->nodetree;
+ case ID_SCE: return ((const Scene *)id)->nodetree;
+ case ID_LS: return ((const FreestyleLineStyle *)id)->nodetree;
default: return NULL;
}
}
@@ -1995,9 +1997,6 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
if (ntree) {
bNodeTree *ltree;
bNode *node;
- AnimData *adt;
-
- bAction *action_backup = NULL, *tmpact_backup = NULL;
BLI_spin_lock(&spin);
if (!ntree->duplilock) {
@@ -2007,23 +2006,16 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
BLI_mutex_lock(ntree->duplilock);
- /* Workaround for copying an action on each render!
- * set action to NULL so animdata actions don't get copied */
- adt = BKE_animdata_from_id(&ntree->id);
-
- if (adt) {
- action_backup = adt->action;
- tmpact_backup = adt->tmpact;
-
- adt->action = NULL;
- adt->tmpact = NULL;
- }
-
/* Make full copy outside of Main database.
* Note: previews are not copied here.
*/
- BKE_id_copy_ex(NULL, (ID *)ntree, (ID **)&ltree,
- LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_COPY_NO_PREVIEW, false);
+ BKE_id_copy_ex(
+ NULL, &ntree->id, (ID **)&ltree,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_COPY_NO_PREVIEW |
+ LIB_ID_COPY_NO_ANIMDATA),
+ false);
ltree->flag |= NTREE_IS_LOCALIZED;
for (node = ltree->nodes.first; node; node = node->next) {
@@ -2032,31 +2024,19 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
}
}
- if (adt) {
- AnimData *ladt = BKE_animdata_from_id(&ltree->id);
-
- adt->action = ladt->action = action_backup;
- adt->tmpact = ladt->tmpact = tmpact_backup;
-
- if (action_backup)
- id_us_plus(&action_backup->id);
- if (tmpact_backup)
- id_us_plus(&tmpact_backup->id);
-
- }
- /* end animdata uglyness */
-
/* ensures only a single output node is enabled */
ntreeSetOutput(ntree);
for (node = ntree->nodes.first; node; node = node->next) {
/* store new_node pointer to original */
- node->new_node->new_node = node;
+ node->new_node->original = node;
}
if (ntree->typeinfo->localize)
ntree->typeinfo->localize(ltree, ntree);
+ ltree->id.tag |= LIB_TAG_LOCALIZED;
+
BLI_mutex_unlock(ntree->duplilock);
return ltree;
@@ -3127,77 +3107,6 @@ void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
}
-/* nodes that use ID data get synced with local data */
-void nodeSynchronizeID(bNode *node, bool copy_to_id)
-{
- if (node->id == NULL) return;
-
- if (ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) {
- 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 (!(sock->flag & check_flags)) {
- if (copy_to_id) {
- switch (a) {
- case MAT_IN_COLOR:
- copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
- case MAT_IN_SPEC:
- copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
- case MAT_IN_REFL:
- ma->ref = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_MIR:
- copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
- case MAT_IN_AMB:
- ma->amb = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_EMIT:
- ma->emit = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_SPECTRA:
- ma->spectra = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_RAY_MIRROR:
- ma->ray_mirror = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_ALPHA:
- ma->alpha = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_TRANSLUCENCY:
- ma->translucency = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- }
- }
- else {
- switch (a) {
- case MAT_IN_COLOR:
- copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->r); break;
- case MAT_IN_SPEC:
- copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->specr); break;
- case MAT_IN_REFL:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ref; break;
- case MAT_IN_MIR:
- copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->mirr); break;
- case MAT_IN_AMB:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->amb; break;
- case MAT_IN_EMIT:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->emit; break;
- case MAT_IN_SPECTRA:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->spectra; break;
- case MAT_IN_RAY_MIRROR:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ray_mirror; break;
- case MAT_IN_ALPHA:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->alpha; break;
- case MAT_IN_TRANSLUCENCY:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->translucency; break;
- }
- }
- }
- }
- }
-}
-
-
/* ************* node type access ********** */
void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
@@ -3562,10 +3471,7 @@ static void registerShaderNodes(void)
{
register_node_type_sh_group();
- register_node_type_sh_output();
- register_node_type_sh_material();
register_node_type_sh_camera();
- register_node_type_sh_lamp();
register_node_type_sh_gamma();
register_node_type_sh_brightcontrast();
register_node_type_sh_value();
@@ -3576,9 +3482,8 @@ static void registerShaderNodes(void)
register_node_type_sh_mix_rgb();
register_node_type_sh_valtorgb();
register_node_type_sh_rgbtobw();
- register_node_type_sh_texture();
+ register_node_type_sh_shadertorgb();
register_node_type_sh_normal();
- register_node_type_sh_geom();
register_node_type_sh_mapping();
register_node_type_sh_curve_vec();
register_node_type_sh_curve_rgb();
@@ -3586,7 +3491,6 @@ static void registerShaderNodes(void)
register_node_type_sh_vect_math();
register_node_type_sh_vect_transform();
register_node_type_sh_squeeze();
- register_node_type_sh_material_ext();
register_node_type_sh_invert();
register_node_type_sh_seprgb();
register_node_type_sh_combrgb();
@@ -3631,6 +3535,7 @@ static void registerShaderNodes(void)
register_node_type_sh_add_shader();
register_node_type_sh_uvmap();
register_node_type_sh_uvalongstroke();
+ register_node_type_sh_eevee_specular();
register_node_type_sh_output_lamp();
register_node_type_sh_output_material();
@@ -3824,3 +3729,28 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
return true;
}
+
+/* -------------------------------------------------------------------- */
+/* NodeTree kernel functions */
+
+void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index)
+{
+ BLI_assert(layer_index != -1);
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
+ if (node->custom1 == layer_index) {
+ node->custom1 = 0;
+ }
+ else if (node->custom1 > layer_index) {
+ node->custom1--;
+ }
+ }
+ }
+}
+
+void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
+ bNodeTree *ntree_dst,
+ const bNodeTree *ntree_src)
+{
+ DEG_debug_print_eval(depsgraph, __func__, ntree_src->id.name, ntree_dst);
+}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index eeb0ab22bd6..af963d784ec 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -58,7 +58,7 @@
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
#include "DNA_object_types.h"
-#include "DNA_property_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "BLI_blenlib.h"
@@ -76,21 +76,20 @@
#include "BKE_idprop.h"
#include "BKE_armature.h"
#include "BKE_action.h"
-#include "BKE_bullet.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_animsys.h"
#include "BKE_anim.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
-#include "BKE_group.h"
#include "BKE_icons.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
+#include "BKE_layer.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -103,12 +102,12 @@
#include "BKE_multires.h"
#include "BKE_node.h"
#include "BKE_object.h"
+#include "BKE_object_facemap.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "BKE_property.h"
+#include "BKE_lightprobe.h"
#include "BKE_rigidbody.h"
-#include "BKE_sca.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_speaker.h"
@@ -118,6 +117,11 @@
#include "BKE_camera.h"
#include "BKE_image.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DRW_engine.h"
+
#ifdef WITH_MOD_FLUID
#include "LBM_fluidsim.h"
#endif
@@ -129,8 +133,6 @@
#include "CCGSubSurf.h"
#include "atomic_ops.h"
-#include "GPU_material.h"
-
/* Vertex parent modifies original BMesh which is not safe for threading.
* Ideally such a modification should be handled as a separate DAG update
* callback for mesh datablock, but for until it is actually supported use
@@ -152,16 +154,6 @@ void BKE_object_workob_clear(Object *workob)
workob->rotmode = ROT_MODE_EUL;
}
-void BKE_object_update_base_layer(struct Scene *scene, Object *ob)
-{
- Base *base = scene->base.first;
-
- while (base) {
- if (base->object == ob) base->lay = ob->lay;
- base = base->next;
- }
-}
-
void BKE_object_free_particlesystems(Object *ob)
{
ParticleSystem *psys;
@@ -179,14 +171,6 @@ void BKE_object_free_softbody(Object *ob)
}
}
-void BKE_object_free_bulletsoftbody(Object *ob)
-{
- if (ob->bsoft) {
- bsbFree(ob->bsoft);
- ob->bsoft = NULL;
- }
-}
-
void BKE_object_free_curve_cache(Object *ob)
{
if (ob->curve_cache) {
@@ -265,7 +249,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
return true;
}
-void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
+void BKE_object_link_modifiers(Scene *scene, struct Object *ob_dst, const struct Object *ob_src)
{
ModifierData *md;
BKE_object_free_modifiers(ob_dst, 0);
@@ -304,7 +288,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
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);
+ multiresModifier_sync_levels_ex(scene, ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
}
modifier_copyData(md, nmd);
@@ -346,6 +330,34 @@ void BKE_object_free_derived_caches(Object *ob)
ob->bb = NULL;
}
+ BKE_object_free_derived_mesh_caches(ob);
+
+ if (ob->runtime.mesh_eval != NULL) {
+ Mesh *mesh_eval = ob->runtime.mesh_eval;
+ /* Restore initial pointer. */
+ if (ob->data == mesh_eval) {
+ ob->data = ob->runtime.mesh_orig;
+ }
+ /* Evaluated mesh points to edit mesh, but does not own it. */
+ mesh_eval->edit_btmesh = NULL;
+ BKE_mesh_free(mesh_eval);
+ BKE_libblock_free_data(&mesh_eval->id, false);
+ MEM_freeN(mesh_eval);
+ ob->runtime.mesh_eval = NULL;
+ }
+ if (ob->runtime.mesh_deform_eval != NULL) {
+ Mesh *mesh_deform_eval = ob->runtime.mesh_deform_eval;
+ BKE_mesh_free(mesh_deform_eval);
+ BKE_libblock_free_data(&mesh_deform_eval->id, false);
+ MEM_freeN(mesh_deform_eval);
+ ob->runtime.mesh_deform_eval = NULL;
+ }
+
+ BKE_object_free_curve_cache(ob);
+}
+
+void BKE_object_free_derived_mesh_caches(struct Object *ob)
+{
if (ob->derivedFinal) {
ob->derivedFinal->needsFree = 1;
ob->derivedFinal->release(ob->derivedFinal);
@@ -356,8 +368,6 @@ void BKE_object_free_derived_caches(Object *ob)
ob->derivedDeform->release(ob->derivedDeform);
ob->derivedDeform = NULL;
}
-
- BKE_object_free_curve_cache(ob);
}
void BKE_object_free_caches(Object *object)
@@ -381,14 +391,12 @@ void BKE_object_free_caches(Object *object)
for (md = object->modifiers.first; md != NULL; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
- if (psmd->dm_final != NULL) {
- psmd->dm_final->needsFree = 1;
- psmd->dm_final->release(psmd->dm_final);
- psmd->dm_final = NULL;
- if (psmd->dm_deformed != NULL) {
- psmd->dm_deformed->needsFree = 1;
- psmd->dm_deformed->release(psmd->dm_deformed);
- psmd->dm_deformed = NULL;
+ if (psmd->mesh_final) {
+ BKE_id_free(NULL, psmd->mesh_final);
+ psmd->mesh_final = NULL;
+ if (psmd->mesh_original) {
+ BKE_id_free(NULL, psmd->mesh_original);
+ psmd->mesh_original = NULL;
}
psmd->flag |= eParticleSystemFlag_file_loaded;
update_flag |= OB_RECALC_DATA;
@@ -401,7 +409,7 @@ void BKE_object_free_caches(Object *object)
* guaranteed to be in a known state.
*/
if (update_flag != 0) {
- DAG_id_tag_update(&object->id, update_flag);
+ DEG_id_tag_update(&object->id, update_flag);
}
}
@@ -419,6 +427,7 @@ void BKE_object_free(Object *ob)
MEM_SAFE_FREE(ob->bb);
BLI_freelistN(&ob->defbase);
+ BLI_freelistN(&ob->fmaps);
if (ob->pose) {
BKE_pose_free_ex(ob->pose, false);
ob->pose = NULL;
@@ -427,11 +436,6 @@ void BKE_object_free(Object *ob)
animviz_free_motionpath(ob->mpath);
ob->mpath = NULL;
}
- BKE_bproperty_free_list(&ob->prop);
-
- free_sensors(&ob->sensors);
- free_controllers(&ob->controllers);
- free_actuators(&ob->actuators);
BKE_constraints_free_ex(&ob->constraints, false);
@@ -443,11 +447,13 @@ void BKE_object_free(Object *ob)
sbFree(ob->soft);
ob->soft = NULL;
}
- if (ob->bsoft) {
- bsbFree(ob->bsoft);
- ob->bsoft = NULL;
+
+ for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) {
+ if (oed->free != NULL) {
+ oed->free(oed);
+ }
}
- GPU_lamp_free(ob);
+ BLI_freelistN(&ob->drawdata);
BKE_sculptsession_free(ob);
@@ -517,6 +523,30 @@ bool BKE_object_is_in_editmode_vgroup(const Object *ob)
BKE_object_is_in_editmode(ob));
}
+bool BKE_object_data_is_in_editmode(const ID *id)
+{
+ const short type = GS(id->name);
+ BLI_assert(OB_DATA_SUPPORT_EDITMODE(type));
+ switch (type) {
+ case ID_ME:
+ return ((const Mesh *)id)->edit_btmesh != NULL;
+ case ID_CU:
+ return (
+ (((const Curve *)id)->editnurb != NULL) ||
+ (((const Curve *)id)->editfont != NULL)
+ );
+ case ID_MB:
+ return ((const MetaBall *)id)->editelems != NULL;
+ case ID_LT:
+ return ((const Lattice *)id)->editlatt != NULL;
+ case ID_AR:
+ return ((const bArmature *)id)->edbo != NULL;
+ default:
+ BLI_assert(0);
+ return false;
+ }
+}
+
bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
{
if (ob->type == OB_MESH) {
@@ -529,6 +559,72 @@ bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
return false;
}
+bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode)
+{
+ if (object_mode & OB_MODE_EDIT) {
+ if (BKE_object_is_in_editmode(ob)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_VERTEX_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_WEIGHT_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_SCULPT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_POSE) {
+ if (ob->pose != NULL) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
+{
+ return ((ob->mode == object_mode) ||
+ (ob->mode & object_mode) != 0);
+}
+
+/**
+ * Return if the object is visible, as evaluated by depsgraph
+ */
+bool BKE_object_is_visible(Object *ob, const eObjectVisibilityCheck mode)
+{
+ if ((ob->base_flag & BASE_VISIBLED) == 0) {
+ return false;
+ }
+
+ if (mode == OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) {
+ return true;
+ }
+
+ if (((ob->transflag & OB_DUPLI) == 0) &&
+ (ob->particlesystem.first == NULL))
+ {
+ return true;
+ }
+
+ switch (mode) {
+ case OB_VISIBILITY_CHECK_FOR_VIEWPORT:
+ return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT) != 0);
+ case OB_VISIBILITY_CHECK_FOR_RENDER:
+ return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0);
+ default:
+ BLI_assert(!"Object visible test mode not supported.");
+ return false;
+ }
+}
+
bool BKE_object_exists_check(Main *bmain, const Object *obtest)
{
Object *ob;
@@ -582,6 +678,7 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *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_LIGHTPROBE:return BKE_lightprobe_add(bmain, name);
case OB_EMPTY: return NULL;
default:
printf("%s: Internal error, bad type: %d\n", __func__, type);
@@ -633,26 +730,10 @@ void BKE_object_init(Object *ob)
ob->dupsta = 1; ob->dupend = 100;
ob->dupfacesca = 1.0;
- /* Game engine defaults*/
- ob->mass = ob->inertia = 1.0f;
- ob->formfactor = 0.4f;
- ob->damping = 0.04f;
- ob->rdamping = 0.1f;
- ob->anisotropicFriction[0] = 1.0f;
- ob->anisotropicFriction[1] = 1.0f;
- ob->anisotropicFriction[2] = 1.0f;
- ob->gameflag = OB_PROP | OB_COLLISION;
- ob->margin = 0.04f;
- ob->init_state = 1;
- ob->state = 1;
- ob->obstacleRad = 1.0f;
- ob->step_height = 0.15f;
- ob->jump_speed = 10.0f;
- ob->fall_speed = 55.0f;
- ob->max_jumps = 1;
ob->col_group = 0x01;
ob->col_mask = 0xffff;
ob->preview = NULL;
+ ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
/* NT fluid sim defaults */
ob->fluidsimSettings = NULL;
@@ -661,6 +742,8 @@ void BKE_object_init(Object *ob)
/* Animation Visualization defaults */
animviz_settings_init(&ob->avs);
+
+ ob->display.flag = OB_SHOW_SHADOW;
}
/* more general add: creates minimum required data, but without vertices etc. */
@@ -673,6 +756,9 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
+ /* We increase object user count when linking to Collections. */
+ id_us_min(&ob->id);
+
/* default object vars */
ob->type = type;
@@ -681,163 +767,66 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
return ob;
}
-/* 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, const char *name)
+
+static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, const char *name)
{
Object *ob;
- Base *base;
ob = BKE_object_add_only_object(bmain, type, name);
-
ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
+ BKE_view_layer_base_deselect_all(view_layer);
- ob->lay = scene->lay;
-
- base = BKE_scene_base_add(scene, ob);
- BKE_scene_base_deselect_all(scene);
- BKE_scene_base_select(scene, base);
- DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
+ DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
return ob;
}
-
-#ifdef WITH_GAMEENGINE
-
-void BKE_object_lod_add(Object *ob)
-{
- LodLevel *lod = MEM_callocN(sizeof(LodLevel), "LoD Level");
- LodLevel *last = ob->lodlevels.last;
-
- /* If the lod list is empty, initialize it with the base lod level */
- if (!last) {
- LodLevel *base = MEM_callocN(sizeof(LodLevel), "Base LoD Level");
- BLI_addtail(&ob->lodlevels, base);
- base->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
- base->source = ob;
- base->obhysteresis = 10;
- last = ob->currentlod = base;
- }
-
- lod->distance = last->distance + 25.0f;
- lod->obhysteresis = 10;
- lod->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
-
- BLI_addtail(&ob->lodlevels, lod);
-}
-
-static int lod_cmp(const void *a, const void *b)
-{
- const LodLevel *loda = a;
- const LodLevel *lodb = b;
-
- if (loda->distance < lodb->distance) return -1;
- return loda->distance > lodb->distance;
-}
-
-void BKE_object_lod_sort(Object *ob)
-{
- BLI_listbase_sort(&ob->lodlevels, lod_cmp);
-}
-
-bool BKE_object_lod_remove(Object *ob, int level)
-{
- LodLevel *rem;
-
- if (level < 1 || level > BLI_listbase_count(&ob->lodlevels) - 1)
- return false;
-
- rem = BLI_findlink(&ob->lodlevels, level);
-
- if (rem == ob->currentlod) {
- ob->currentlod = rem->prev;
- }
-
- BLI_remlink(&ob->lodlevels, rem);
- MEM_freeN(rem);
-
- /* If there are no user defined lods, remove the base lod as well */
- if (BLI_listbase_is_single(&ob->lodlevels)) {
- LodLevel *base = ob->lodlevels.first;
- BLI_remlink(&ob->lodlevels, base);
- MEM_freeN(base);
- ob->currentlod = NULL;
- }
-
- return true;
-}
-
-static LodLevel *lod_level_select(Object *ob, const float camera_position[3])
+/**
+ * General add: to scene, with layer from area and default name
+ *
+ * Object is added to the active Collection.
+ * If there is no linked collection to the active ViewLayer we create a new one.
+ */
+/* creates minimum required data, but without vertices etc. */
+Object *BKE_object_add(
+ Main *bmain, Scene *UNUSED(scene), ViewLayer *view_layer,
+ int type, const char *name)
{
- LodLevel *current = ob->currentlod;
- float dist_sq;
-
- if (!current) return NULL;
+ Object *ob;
+ Base *base;
+ LayerCollection *layer_collection;
- dist_sq = len_squared_v3v3(ob->obmat[3], camera_position);
+ ob = object_add_common(bmain, view_layer, type, name);
- if (dist_sq < SQUARE(current->distance)) {
- /* check for higher LoD */
- while (current->prev && dist_sq < SQUARE(current->distance)) {
- current = current->prev;
- }
- }
- else {
- /* check for lower LoD */
- while (current->next && dist_sq > SQUARE(current->next->distance)) {
- current = current->next;
- }
- }
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
- return current;
-}
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select(view_layer, base);
-bool BKE_object_lod_is_usable(Object *ob, Scene *scene)
-{
- bool active = (scene) ? ob == OBACT : false;
- return (ob->mode == OB_MODE_OBJECT || !active);
-}
-
-void BKE_object_lod_update(Object *ob, const float camera_position[3])
-{
- LodLevel *cur_level = ob->currentlod;
- LodLevel *new_level = lod_level_select(ob, camera_position);
-
- if (new_level != cur_level) {
- ob->currentlod = new_level;
- }
+ return ob;
}
-static Object *lod_ob_get(Object *ob, Scene *scene, int flag)
+/**
+ * Add a new object, using another one as a reference
+ *
+ * /param ob_src object to use to determine the collections of the new object.
+ */
+Object *BKE_object_add_from(
+ Main *bmain, Scene *scene, ViewLayer *view_layer,
+ int type, const char *name, Object *ob_src)
{
- LodLevel *current = ob->currentlod;
-
- if (!current || !BKE_object_lod_is_usable(ob, scene))
- return ob;
-
- while (current->prev && (!(current->flags & flag) || !current->source || current->source->type != OB_MESH)) {
- current = current->prev;
- }
+ Object *ob;
+ Base *base;
- return current->source;
-}
+ ob = object_add_common(bmain, view_layer, type, name);
+ BKE_collection_object_add_from(bmain, scene, ob_src, ob);
-struct Object *BKE_object_lod_meshob_get(Object *ob, Scene *scene)
-{
- return lod_ob_get(ob, scene, OB_LOD_USE_MESH);
-}
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select(view_layer, base);
-struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
-{
- return lod_ob_get(ob, scene, OB_LOD_USE_MAT);
+ return ob;
}
-#endif /* WITH_GAMEENGINE */
-
-
SoftBody *copy_softbody(const SoftBody *sb, const int flag)
{
SoftBody *sbn;
@@ -883,56 +872,16 @@ SoftBody *copy_softbody(const SoftBody *sb, const int flag)
return sbn;
}
-BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb, const int UNUSED(flag))
-{
- BulletSoftBody *bsbn;
-
- if (bsb == NULL)
- return NULL;
- bsbn = MEM_dupallocN(bsb);
- /* no pointer in this structure yet */
- return bsbn;
-}
-
ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int flag)
{
- ParticleSystem *psysn;
- ParticleData *pa;
- int p;
-
- psysn = MEM_dupallocN(psys);
- psysn->particles = MEM_dupallocN(psys->particles);
- psysn->child = MEM_dupallocN(psys->child);
-
- if (psys->part->type == PART_HAIR) {
- for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++)
- pa->hair = MEM_dupallocN(pa->hair);
- }
+ ParticleSystem *psysn = MEM_dupallocN(psys);
- if (psysn->particles && (psysn->particles->keys || psysn->particles->boid)) {
- ParticleKey *key = psysn->particles->keys;
- BoidParticle *boid = psysn->particles->boid;
-
- if (key)
- key = MEM_dupallocN(key);
-
- if (boid)
- boid = MEM_dupallocN(boid);
-
- for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++) {
- if (boid)
- pa->boid = boid++;
- if (key) {
- pa->keys = key;
- key += pa->totkey;
- }
- }
- }
+ psys_copy_particles(psysn, psys);
if (psys->clmd) {
psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
- psys->hair_in_dm = psys->hair_out_dm = NULL;
+ psys->hair_in_mesh = psys->hair_out_mesh = NULL;
}
BLI_duplicatelist(&psysn->targets, &psys->targets);
@@ -944,13 +893,12 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f
psysn->effectors = NULL;
psysn->tree = NULL;
psysn->bvhtree = NULL;
+ psysn->batch_cache = NULL;
BLI_listbase_clear(&psysn->pathcachebufs);
BLI_listbase_clear(&psysn->childcachebufs);
- psysn->renderdata = NULL;
- /* XXX Never copy caches here? */
- psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag & ~LIB_ID_COPY_CACHES);
+ psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag);
/* XXX - from reading existing code this seems correct but intended usage of
* pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
@@ -1084,12 +1032,103 @@ Object *BKE_object_pose_armature_get(Object *ob)
ob = modifiers_isDeformedByArmature(ob);
+ /* Only use selected check when non-active. */
if (BKE_object_pose_context_check(ob))
return ob;
return NULL;
}
+Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer)
+{
+ Object *ob_armature = BKE_object_pose_armature_get(ob);
+ if (ob_armature) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob_armature);
+ if (base) {
+ if (BASE_VISIBLE(base)) {
+ return ob_armature;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Access pose array with special check to get pose object when in weight paint mode.
+ */
+Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer, uint *r_objects_len, bool unique)
+{
+ Object *ob_active = OBACT(view_layer);
+ Object *ob_pose = BKE_object_pose_armature_get(ob_active);
+ Object **objects = NULL;
+ if (ob_pose == ob_active) {
+ objects = BKE_view_layer_array_from_objects_in_mode(
+ view_layer, r_objects_len, {
+ .object_mode = OB_MODE_POSE,
+ .no_dup_data = unique});
+ }
+ else if (ob_pose != NULL) {
+ *r_objects_len = 1;
+ objects = MEM_mallocN(sizeof(*objects), __func__);
+ objects[0] = ob_pose;
+ }
+ else {
+ *r_objects_len = 0;
+ objects = MEM_mallocN(0, __func__);
+ }
+ return objects;
+}
+Object **BKE_object_pose_array_get_unique(ViewLayer *view_layer, uint *r_objects_len)
+{
+ return BKE_object_pose_array_get_ex(view_layer, r_objects_len, true);
+}
+Object **BKE_object_pose_array_get(ViewLayer *view_layer, uint *r_objects_len)
+{
+ return BKE_object_pose_array_get_ex(view_layer, r_objects_len, false);
+}
+
+Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer, uint *r_bases_len, bool unique)
+{
+ Base *base_active = BASACT(view_layer);
+ Object *ob_pose = base_active ? BKE_object_pose_armature_get(base_active->object) : NULL;
+ Base *base_pose = NULL;
+ Base **bases = NULL;
+
+ if (base_active) {
+ if (ob_pose == base_active->object) {
+ base_pose = base_active;
+ }
+ else {
+ base_pose = BKE_view_layer_base_find(view_layer, ob_pose);
+ }
+ }
+
+ if (base_active && (base_pose == base_active)) {
+ bases = BKE_view_layer_array_from_bases_in_mode(
+ view_layer, r_bases_len, {
+ .object_mode = OB_MODE_POSE,
+ .no_dup_data = unique});
+ }
+ else if (base_pose != NULL) {
+ *r_bases_len = 1;
+ bases = MEM_mallocN(sizeof(*bases), __func__);
+ bases[0] = base_pose;
+ }
+ else {
+ *r_bases_len = 0;
+ bases = MEM_mallocN(0, __func__);
+ }
+ return bases;
+}
+Base **BKE_object_pose_base_array_get_unique(ViewLayer *view_layer, uint *r_bases_len)
+{
+ return BKE_object_pose_base_array_get_ex(view_layer, r_bases_len, true);
+}
+Base **BKE_object_pose_base_array_get(ViewLayer *view_layer, uint *r_bases_len)
+{
+ return BKE_object_pose_base_array_get_ex(view_layer, r_bases_len, false);
+}
+
void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
{
copy_v3_v3(ob_tar->loc, ob_src->loc);
@@ -1125,7 +1164,6 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser);
if (ob_src->bb) ob_dst->bb = MEM_dupallocN(ob_src->bb);
- ob_dst->flag &= ~OB_FROMGROUP;
BLI_listbase_clear(&ob_dst->modifiers);
@@ -1136,11 +1174,6 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
BLI_addtail(&ob_dst->modifiers, nmd);
}
- BLI_listbase_clear(&ob_dst->prop);
- BKE_bproperty_copy_list(&ob_dst->prop, &ob_src->prop);
-
- BKE_sca_logic_copy(ob_dst, ob_src, flag_subdata);
-
if (ob_src->pose) {
copy_object_pose(ob_dst, ob_src, flag_subdata);
/* backwards compat... non-armatures can get poses in older files? */
@@ -1148,6 +1181,7 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
BKE_pose_rebuild(ob_dst, ob_dst->data);
}
defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase);
+ BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps);
BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true);
ob_dst->mode = OB_MODE_OBJECT;
@@ -1160,7 +1194,6 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
}
}
ob_dst->soft = copy_softbody(ob_src->soft, flag_subdata);
- ob_dst->bsoft = copy_bulletsoftbody(ob_src->bsoft, flag_subdata);
ob_dst->rigidbody_object = BKE_rigidbody_copy_object(ob_src, flag_subdata);
ob_dst->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob_src, flag_subdata);
@@ -1170,9 +1203,11 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
ob_dst->derivedFinal = NULL;
BLI_listbase_clear(&ob_dst->gpulamp);
+ BLI_listbase_clear(&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
- ob_dst->mpath = NULL;
+ ob_dst->avs = ob_src->avs;
+ ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);
copy_object_lod(ob_dst, ob_src, flag_subdata);
@@ -1193,6 +1228,10 @@ Object *BKE_object_copy(Main *bmain, const Object *ob)
{
Object *ob_copy;
BKE_id_copy_ex(bmain, &ob->id, (ID **)&ob_copy, 0, false);
+
+ /* We increase object user count when linking to Collections. */
+ id_us_min(&ob_copy->id);
+
return ob_copy;
}
@@ -1316,9 +1355,9 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* proxy rule: lib_object->proxy_from == the one we borrow from, set temporally while object_update */
/* local_object->proxy == pointer to library object, saved in files and read */
-/* local_object->proxy_group == pointer to group dupli-object, saved in files and read */
+/* local_object->proxy_group == pointer to collection dupli-object, saved in files and read */
-void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
+void BKE_object_make_proxy(Object *ob, Object *target, Object *cob)
{
/* paranoia checks */
if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) {
@@ -1327,24 +1366,24 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
}
ob->proxy = target;
- ob->proxy_group = gob;
+ ob->proxy_group = cob;
id_lib_extern(&target->id);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- DAG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* copy transform
- * - gob means this proxy comes from a group, just apply the matrix
+ * - cob means this proxy comes from a collection, just apply the matrix
* so the object wont move from its dupli-transform.
*
- * - no gob means this is being made from a linked object,
+ * - no cob means this is being made from a linked object,
* this is closer to making a copy of the object - in-place. */
- if (gob) {
+ if (cob) {
ob->rotmode = target->rotmode;
- mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat);
- if (gob->dup_group) { /* should always be true */
+ mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat);
+ if (cob->dup_group) { /* should always be true */
float tvec[3];
- mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs);
+ mul_v3_mat3_m4v3(tvec, ob->obmat, cob->dup_group->dupli_ofs);
sub_v3_v3(ob->obmat[3], tvec);
}
BKE_object_apply_mat4(ob, ob->obmat, false, true);
@@ -1653,7 +1692,7 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
if (ob->parent) {
float par_imat[4][4];
- BKE_object_get_parent_matrix(NULL, ob, ob->parent, par_imat);
+ BKE_object_get_parent_matrix(NULL, NULL, ob, ob->parent, par_imat);
invert_m4(par_imat);
mul_m4_m4m4(mat, par_imat, ob->obmat);
}
@@ -1666,21 +1705,24 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
int enable_cu_speed = 1;
/**
- * \param scene: Used when curve cache needs to be calculated, or for dupli-frame time.
+ * \param depsgraph: Used for dupli-frame time.
* \return success if \a mat is set.
*/
-static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
+static bool ob_parcurve(Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob, Object *par, float mat[4][4])
{
Curve *cu = par->data;
float vec[4], dir[3], quat[4], radius, ctime;
+ /* TODO: Make sure this doesn't crash. */
+#if 0
/* only happens on reload file, but violates depsgraph still... fix! */
if (par->curve_cache == NULL) {
if (scene == NULL) {
return false;
}
- BKE_displist_make_curveTypes(scene, par, 0);
+ BKE_displist_make_curveTypes(depsgraph, scene, par, 0);
}
+#endif
if (par->curve_cache->path == NULL) {
return false;
@@ -1705,11 +1747,11 @@ static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
}
else {
/* For dupli-frames only */
- if (scene == NULL) {
+ if (depsgraph == NULL) {
return false;
}
- ctime = BKE_scene_frame_get(scene);
+ ctime = DEG_get_ctime(depsgraph);
if (cu->pathlen) {
ctime /= cu->pathlen;
}
@@ -1960,7 +2002,7 @@ static void ob_parvert3(Object *ob, Object *par, float mat[4][4])
}
-void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4])
+void BKE_object_get_parent_matrix(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, float parentmat[4][4])
{
float tmat[4][4];
float vec[3];
@@ -1971,7 +2013,7 @@ void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float p
ok = 0;
if (par->type == OB_CURVE) {
if ((((Curve *)par->data)->flag & CU_PATH) &&
- (ob_parcurve(scene, ob, par, tmat)))
+ (ob_parcurve(depsgraph, scene, ob, par, tmat)))
{
ok = 1;
}
@@ -2007,7 +2049,8 @@ void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float p
/**
* \param r_originmat Optional matrix that stores the space the object is in (without its own matrix applied)
*/
-static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4][4], float slowmat[4][4],
+static void solve_parenting(Depsgraph *depsgraph,
+ Scene *scene, Object *ob, Object *par, float obmat[4][4], float slowmat[4][4],
float r_originmat[3][3], const bool set_origin)
{
float totmat[4][4];
@@ -2018,7 +2061,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4
if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat);
- BKE_object_get_parent_matrix(scene, ob, par, totmat);
+ BKE_object_get_parent_matrix(depsgraph, scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
@@ -2061,20 +2104,21 @@ static bool where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat
}
/* note, scene is the active scene while actual_scene is the scene the object resides in */
-void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
- RigidBodyWorld *rbw, float r_originmat[3][3])
+void BKE_object_where_is_calc_time_ex(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime,
+ RigidBodyWorld *rbw, float r_originmat[3][3])
{
if (ob == NULL) return;
/* execute drivers only, as animation has already been done */
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS);
if (ob->parent) {
Object *par = ob->parent;
float slowmat[4][4];
/* calculate parent matrix */
- solve_parenting(scene, ob, par, ob->obmat, slowmat, r_originmat, true);
+ solve_parenting(depsgraph, scene, ob, par, ob->obmat, slowmat, r_originmat, true);
/* "slow parent" is definitely not threadsafe, and may also give bad results jumping around
* An old-fashioned hack which probably doesn't really cut it anymore
@@ -2096,8 +2140,8 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
/* solve constraints */
if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) {
bConstraintOb *cob;
- cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
- BKE_constraints_solve(&ob->constraints, cob, ctime);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
BKE_constraints_clear_evalob(cob);
}
@@ -2106,16 +2150,16 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
else ob->transflag &= ~OB_NEG_SCALE;
}
-void BKE_object_where_is_calc_time(Scene *scene, Object *ob, float ctime)
+void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime)
{
- BKE_object_where_is_calc_time_ex(scene, ob, ctime, NULL, NULL);
+ BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, ctime, NULL, NULL);
}
/* get object transformation matrix without recalculating dependencies and
* constraints -- assume dependencies are already solved by depsgraph.
* no changes to object and it's parent would be done.
* used for bundles orientation in 3d space relative to parented blender camera */
-void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4])
+void BKE_object_where_is_calc_mat4(Depsgraph *depsgraph, Scene *scene, Object *ob, float obmat[4][4])
{
if (ob->parent) {
@@ -2123,7 +2167,7 @@ void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4])
Object *par = ob->parent;
- solve_parenting(scene, ob, par, obmat, slowmat, NULL, false);
+ solve_parenting(depsgraph, scene, ob, par, obmat, slowmat, NULL, false);
if (ob->partype & PARSLOW)
where_is_object_parslow(ob, obmat, slowmat);
@@ -2133,52 +2177,69 @@ void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4])
}
}
-void BKE_object_where_is_calc_ex(Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
+void BKE_object_where_is_calc_ex(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
{
- BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), rbw, r_originmat);
+ BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), rbw, r_originmat);
}
-void BKE_object_where_is_calc(Scene *scene, Object *ob)
+void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), NULL, NULL);
+ BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), NULL, NULL);
}
-/* for calculation of the inverse parent transform, only used for editor */
-void BKE_object_workob_calc_parent(Scene *scene, Object *ob, Object *workob)
+/**
+ * For calculation of the inverse parent transform, only used for editor.
+ *
+ * It assumes the object parent is already in the depsgraph.
+ * Otherwise, after changing ob->parent you need to call:
+ * DEG_relations_tag_update(bmain);
+ * BKE_scene_graph_update_tagged(depsgraph, bmain);
+ */
+void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *workob)
{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
BKE_object_workob_clear(workob);
unit_m4(workob->obmat);
unit_m4(workob->parentinv);
unit_m4(workob->constinv);
- workob->parent = ob->parent;
- workob->trackflag = ob->trackflag;
- workob->upflag = ob->upflag;
+ /* Since this is used while calculating parenting, at this moment ob_eval->parent is still NULL. */
+ workob->parent = DEG_get_evaluated_object(depsgraph, ob->parent);
+
+ workob->trackflag = ob_eval->trackflag;
+ workob->upflag = ob_eval->upflag;
- workob->partype = ob->partype;
- workob->par1 = ob->par1;
- workob->par2 = ob->par2;
- workob->par3 = ob->par3;
+ workob->partype = ob_eval->partype;
+ workob->par1 = ob_eval->par1;
+ workob->par2 = ob_eval->par2;
+ workob->par3 = ob_eval->par3;
- workob->constraints.first = ob->constraints.first;
- workob->constraints.last = ob->constraints.last;
+ workob->constraints = ob_eval->constraints;
- BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
+ BLI_strncpy(workob->parsubstr, ob_eval->parsubstr, sizeof(workob->parsubstr));
- BKE_object_where_is_calc(scene, workob);
+ BKE_object_where_is_calc(depsgraph, scene, workob);
}
-/* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
-void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent)
+/**
+ * Applies the global transformation \a mat to the \a ob using a relative parent space if supplied.
+ *
+ * \param mat the global transformation mat that the object should be set object to.
+ * \param parent the parent space in which this object will be set relative to (should probably always be parent_eval).
+ * \param use_compat true to ensure that rotations are set using the min difference between the old and new orientation.
+ */
+void BKE_object_apply_mat4_ex(Object *ob, float mat[4][4], Object *parent, float parentinv[4][4], const bool use_compat)
{
+ /* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
+
float rot[3][3];
- if (use_parent && ob->parent) {
+ if (parent != NULL) {
float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
- BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
+ BKE_object_get_parent_matrix(NULL, NULL, ob, parent, parent_mat);
- mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv);
+ mul_m4_m4m4(diff_mat, parent_mat, parentinv);
invert_m4_m4(imat, diff_mat);
mul_m4_m4m4(rmat, imat, mat); /* get the parent relative matrix */
@@ -2200,10 +2261,16 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c
/* BKE_object_mat3_to_rot handles delta rotations */
}
+/* XXX: should be removed after COW operators port to use BKE_object_apply_mat4_ex directly */
+void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent)
+{
+ BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat);
+}
+
BoundBox *BKE_boundbox_alloc_unit(void)
{
BoundBox *bb;
- const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {-1.0f, -1.0f, -1.0f};
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
BKE_boundbox_init_from_minmax(bb, min, max);
@@ -2408,6 +2475,7 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value)
if (!ob->iuser) {
ob->iuser = MEM_callocN(sizeof(ImageUser), "image user");
ob->iuser->ok = 1;
+ ob->iuser->flag |= IMA_ANIM_ALWAYS;
ob->iuser->frames = 100;
ob->iuser->sfra = 1;
ob->iuser->fie_ima = 2;
@@ -2421,9 +2489,7 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value)
}
}
-bool BKE_object_minmax_dupli(
- Main *bmain, Scene *scene,
- Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
+bool BKE_object_minmax_dupli(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
{
bool ok = false;
if ((ob->transflag & OB_DUPLI) == 0) {
@@ -2432,7 +2498,7 @@ bool BKE_object_minmax_dupli(
else {
ListBase *lb;
DupliObject *dob;
- lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob);
+ lb = object_duplilist(depsgraph, scene, ob);
for (dob = lb->first; dob; dob = dob->next) {
if ((use_hidden == false) && (dob->no_draw != 0)) {
/* pass */
@@ -2464,13 +2530,11 @@ void BKE_object_foreach_display_point(
{
float co[3];
- if (ob->derivedFinal) {
- DerivedMesh *dm = ob->derivedFinal;
- MVert *mv = dm->getVertArray(dm);
- int totvert = dm->getNumVerts(dm);
- int i;
-
- for (i = 0; i < totvert; i++, mv++) {
+ if (ob->runtime.mesh_eval) {
+ const Mesh *me = ob->runtime.mesh_eval;
+ const MVert *mv = me->mvert;
+ const int totvert = me->totvert;
+ for (int i = 0; i < totvert; i++, mv++) {
mul_v3_m4v3(co, obmat, mv->co);
func_cb(co, user_data);
}
@@ -2492,33 +2556,20 @@ void BKE_object_foreach_display_point(
}
void BKE_scene_foreach_display_point(
- Main *bmain, Scene *scene, View3D *v3d, const short flag,
+ Depsgraph *depsgraph,
void (*func_cb)(const float[3], void *), void *user_data)
{
- Base *base;
- Object *ob;
-
- for (base = FIRSTBASE; base; base = base->next) {
- if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag & flag) == flag) {
- ob = base->object;
-
- if ((ob->transflag & OB_DUPLI) == 0) {
- BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
- }
- else {
- ListBase *lb;
- DupliObject *dob;
-
- lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob);
- for (dob = lb->first; dob; dob = dob->next) {
- if (dob->no_draw == 0) {
- BKE_object_foreach_display_point(dob->ob, dob->mat, func_cb, user_data);
- }
- }
- free_object_duplilist(lb); /* does restore */
- }
+ DEG_OBJECT_ITER_BEGIN(
+ depsgraph, ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+ {
+ if ((ob->base_flag & BASE_SELECTED) != 0) {
+ BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
}
}
+ DEG_OBJECT_ITER_END;
}
/* copied from DNA_object_types.h */
@@ -2532,7 +2583,7 @@ typedef struct ObTfmBack {
float obmat[4][4]; /* final worldspace matrix with constraints & animsys applied */
float parentinv[4][4]; /* inverse result of parent, so that object doesn't 'stick' to parent */
float constinv[4][4]; /* inverse result of constraints. doesn't include effect of parent or object local transform */
- float imat[4][4]; /* inverse matrix of 'obmat' for during render, old game engine, temporally: ipokeys of transform */
+ float imat[4][4]; /* inverse matrix of 'obmat' for during render, temporally: ipokeys of transform */
} ObTfmBack;
void *BKE_object_tfm_backup(Object *ob)
@@ -2589,25 +2640,24 @@ bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
return BKE_object_parent_loop_check(par->parent, ob);
}
-static void object_handle_update_proxy(Main *bmain,
- EvaluationContext *eval_ctx,
+static void object_handle_update_proxy(Depsgraph *depsgraph,
Scene *scene,
Object *object,
const bool do_proxy_update)
{
- /* The case when this is a group proxy, object_update is called in group.c */
+ /* The case when this is a collection proxy, object_update is called in collection.c */
if (object->proxy == NULL) {
return;
}
/* set pointer in library proxy target, for copying, but restore it */
object->proxy->proxy_from = object;
- // printf("set proxy pointer for later group stuff %s\n", ob->id.name);
+ // printf("set proxy pointer for later collection stuff %s\n", ob->id.name);
/* the no-group proxy case, we call update */
if (object->proxy_group == NULL) {
if (do_proxy_update) {
// printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
- BKE_object_handle_update(bmain, eval_ctx, scene, object->proxy);
+ BKE_object_handle_update(depsgraph, scene, object->proxy);
}
}
}
@@ -2620,14 +2670,18 @@ static void object_handle_update_proxy(Main *bmain,
/* the main object update call, for object matrix, constraints, keys and displist (modifiers) */
/* requires flags to be set! */
/* Ideally we shouldn't have to pass the rigid body world, but need bigger restructuring to avoid id */
-void BKE_object_handle_update_ex(Main *bmain,
- EvaluationContext *eval_ctx,
+void BKE_object_handle_update_ex(Depsgraph *depsgraph,
Scene *scene, Object *ob,
RigidBodyWorld *rbw,
const bool do_proxy_update)
{
- if ((ob->recalc & OB_RECALC_ALL) == 0) {
- object_handle_update_proxy(bmain, eval_ctx, scene, ob, do_proxy_update);
+ const ID *object_data = ob->data;
+ const bool recalc_object = (ob->id.recalc & ID_RECALC) != 0;
+ const bool recalc_data =
+ (object_data != NULL) ? ((object_data->recalc & ID_RECALC_ALL) != 0)
+ : 0;
+ if (!recalc_object && ! recalc_data) {
+ object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
return;
}
/* Speed optimization for animation lookups. */
@@ -2637,7 +2691,7 @@ void BKE_object_handle_update_ex(Main *bmain,
BKE_pose_update_constraint_flags(ob->pose);
}
}
- if (ob->recalc & OB_RECALC_DATA) {
+ if (recalc_data) {
if (ob->type == OB_ARMATURE) {
/* this happens for reading old files and to match library armatures
* with poses we do it ahead of BKE_object_where_is_calc to ensure animation
@@ -2650,23 +2704,23 @@ void BKE_object_handle_update_ex(Main *bmain,
/* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers,
* which is only in BKE_object_where_is_calc now */
/* XXX: should this case be OB_RECALC_OB instead? */
- if (ob->recalc & OB_RECALC_ALL) {
+ if (recalc_object || recalc_data) {
if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
printf("recalcob %s\n", ob->id.name + 2);
}
/* Handle proxy copy for target. */
- if (!BKE_object_eval_proxy_copy(eval_ctx, ob)) {
- BKE_object_where_is_calc_ex(scene, rbw, ob, NULL);
+ if (!BKE_object_eval_proxy_copy(depsgraph, ob)) {
+ BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, NULL);
}
}
- if (ob->recalc & OB_RECALC_DATA) {
- BKE_object_handle_data_update(bmain, eval_ctx, scene, ob);
+ if (recalc_data) {
+ BKE_object_handle_data_update(depsgraph, scene, ob);
}
- ob->recalc &= ~OB_RECALC_ALL;
+ ob->id.recalc &= ID_RECALC_ALL;
- object_handle_update_proxy(bmain, eval_ctx, scene, ob, do_proxy_update);
+ object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
}
/* WARNING: "scene" here may not be the scene object actually resides in.
@@ -2674,9 +2728,9 @@ void BKE_object_handle_update_ex(Main *bmain,
* e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
* rigid bodies depend on their world so use BKE_object_handle_update_ex() to also pass along the corrent rigid body world
*/
-void BKE_object_handle_update(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob)
+void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_object_handle_update_ex(bmain, eval_ctx, scene, ob, NULL, true);
+ BKE_object_handle_update_ex(depsgraph, scene, ob, NULL, true);
}
void BKE_object_sculpt_modifiers_changed(Object *ob)
@@ -2721,14 +2775,7 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
switch (GS(((ID *)ob->data)->name)) {
case ID_ME:
{
- Mesh *me = ob->data;
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
- if (r_texflag) *r_texflag = &me->texflag;
- if (r_loc) *r_loc = me->loc;
- if (r_size) *r_size = me->size;
- if (r_rot) *r_rot = me->rot;
+ BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size);
break;
}
case ID_CU:
@@ -2758,6 +2805,68 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
return 1;
}
+/** Get evaluated mesh for given (main, original) object and depsgraph. */
+Mesh *BKE_object_get_evaluated_mesh(const Depsgraph *depsgraph, Object *ob)
+{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ return ob_eval->runtime.mesh_eval;
+}
+
+/* Get object's mesh with all modifiers applied. */
+Mesh *BKE_object_get_final_mesh(Object *object)
+{
+ if (object->runtime.mesh_eval != NULL) {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ BLI_assert(object->runtime.mesh_eval == object->data);
+ BLI_assert((object->runtime.mesh_eval->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) != 0);
+ return object->runtime.mesh_eval;
+ }
+ /* Wasn't evaluated yet. */
+ return object->data;
+}
+
+/* Get mesh which is not affected by modifiers:
+ * - For original objects it will be same as object->data, and it is a mesh
+ * which is in the corresponding bmain.
+ * - For copied-on-write objects it will give pointer to a copied-on-write
+ * mesh which corresponds to original object's mesh.
+ */
+Mesh *BKE_object_get_pre_modified_mesh(Object *object)
+{
+ if (object->runtime.mesh_orig != NULL) {
+ BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ BLI_assert(object->id.orig_id != NULL);
+ BLI_assert(object->runtime.mesh_orig->id.orig_id == ((Object *)object->id.orig_id)->data);
+ Mesh *result = object->runtime.mesh_orig;
+ BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
+ return result;
+ }
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ return object->data;
+}
+
+/* Get a mesh which corresponds to very very original mesh from bmain.
+ * - For original objects it will be object->data.
+ * - For evaluated objects it will be same mesh as corresponding original
+ * object uses as data.
+ */
+Mesh *BKE_object_get_original_mesh(Object *object)
+{
+ Mesh *result = NULL;
+ if (object->id.orig_id == NULL) {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ result = object->data;
+ }
+ else {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ result = ((Object *)object->id.orig_id)->data;
+ }
+ BLI_assert(result != NULL);
+ BLI_assert((result->id.tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT)) == 0);
+ return result;
+}
+
static int pc_cmp(const void *a, const void *b)
{
const LinkData *ad = a, *bd = b;
@@ -2832,7 +2941,7 @@ static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const
if (newkey || from_mix == false) {
/* create from mesh */
kb = BKE_keyblock_add_ctime(key, name, false);
- BKE_keyblock_convert_from_mesh(me, kb);
+ BKE_keyblock_convert_from_mesh(me, key, kb);
}
else {
/* copy from current values */
@@ -3260,6 +3369,10 @@ MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
return clip;
}
+void BKE_object_runtime_reset(Object *object)
+{
+ memset(&object->runtime, 0, sizeof(object->runtime));
+}
/*
* Find an associated Armature object
@@ -3295,33 +3408,33 @@ static void obrel_list_add(LinkNode **links, Object *ob)
}
/*
- * Iterates over all objects of the given scene.
+ * Iterates over all objects of the given scene layer.
* Depending on the eObjectSet flag:
* collect either OB_SET_ALL, OB_SET_VISIBLE or OB_SET_SELECTED objects.
* If OB_SET_VISIBLE or OB_SET_SELECTED are collected,
* then also add related objects according to the given includeFilters.
*/
-LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter)
+LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter)
{
LinkNode *links = NULL;
Base *base;
/* Remove markers from all objects */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
/* iterate over all selected and visible objects */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
if (objectSet == OB_SET_ALL) {
/* as we get all anyways just add it */
Object *ob = base->object;
obrel_list_add(&links, ob);
}
else {
- if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(((View3D *)NULL), scene, base)) ||
- (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, base)))
+ if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(base)) ||
+ (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(base)))
{
Object *ob = base->object;
@@ -3350,8 +3463,8 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS
/* child relationship */
if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) {
Base *local_base;
- for (local_base = scene->base.first; local_base; local_base = local_base->next) {
- if (BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, local_base)) {
+ for (local_base = view_layer->object_bases.first; local_base; local_base = local_base->next) {
+ if (BASE_EDITABLE_BGMODE(local_base)) {
Object *child = local_base->object;
if (obrel_list_test(child)) {
@@ -3386,27 +3499,21 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS
*/
struct LinkNode *BKE_object_groups(Main *bmain, Object *ob)
{
- LinkNode *group_linknode = NULL;
- Group *group = NULL;
- while ((group = BKE_group_object_find(bmain, group, ob))) {
- BLI_linklist_prepend(&group_linknode, group);
+ LinkNode *collection_linknode = NULL;
+ Collection *collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, collection, ob))) {
+ BLI_linklist_prepend(&collection_linknode, collection);
}
- return group_linknode;
+ return collection_linknode;
}
-void BKE_object_groups_clear(Main *bmain, Scene *scene, Base *base, Object *object)
+void BKE_object_groups_clear(Main *bmain, Object *ob)
{
- Group *group = NULL;
-
- BLI_assert((base == NULL) || (base->object == object));
-
- if (scene && base == NULL) {
- base = BKE_scene_base_find(scene, object);
- }
-
- while ((group = BKE_group_object_find(bmain, group, base->object))) {
- BKE_group_object_unlink(bmain, group, object, scene, base);
+ Collection *collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, collection, ob))) {
+ BKE_collection_object_remove(bmain, collection, ob, false);
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
}
}
@@ -3586,11 +3693,11 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
}
/* set "ignore cache" flag for all caches on this object */
-static void object_cacheIgnoreClear(Main *bmain, Object *ob, int state)
+static void object_cacheIgnoreClear(Object *ob, int state)
{
ListBase pidlist;
PTCacheID *pid;
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, NULL, 0);
+ BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->cache) {
@@ -3608,10 +3715,8 @@ static void object_cacheIgnoreClear(Main *bmain, Object *ob, int state)
* Avoid calling this in new code unless there is a very good reason for it!
*/
bool BKE_object_modifier_update_subframe(
- Main *bmain, EvaluationContext *eval_ctx,
- Scene *scene, Object *ob, bool update_mesh,
- int parent_recursion, float frame,
- int type)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, bool update_mesh,
+ int parent_recursion, float frame, int type)
{
ModifierData *md = modifiers_findByType(ob, (ModifierType)type);
bConstraint *con;
@@ -3634,8 +3739,8 @@ bool BKE_object_modifier_update_subframe(
if (parent_recursion) {
int recursion = parent_recursion - 1;
bool no_update = false;
- if (ob->parent) no_update |= BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ob->parent, 0, recursion, frame, type);
- if (ob->track) no_update |= BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ob->track, 0, recursion, frame, type);
+ if (ob->parent) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->parent, 0, recursion, frame, type);
+ if (ob->track) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->track, 0, recursion, frame, type);
/* skip subframe if object is parented
* to vertex of a dynamic paint canvas */
@@ -3652,7 +3757,7 @@ bool BKE_object_modifier_update_subframe(
cti->get_constraint_targets(con, &targets);
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar)
- BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ct->tar, 0, recursion, frame, type);
+ BKE_object_modifier_update_subframe(depsgraph, scene, ct->tar, 0, recursion, frame, type);
}
/* free temp targets */
if (cti->flush_constraint_targets)
@@ -3662,28 +3767,29 @@ bool BKE_object_modifier_update_subframe(
}
/* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
- ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
+ /* TODO(sergey): What about animation? */
+ ob->id.recalc |= ID_RECALC_ALL;
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
if (update_mesh) {
/* ignore cache clear during subframe updates
* to not mess up cache validity */
- object_cacheIgnoreClear(bmain, ob, 1);
- BKE_object_handle_update(bmain, eval_ctx, scene, ob);
- object_cacheIgnoreClear(bmain, ob, 0);
+ object_cacheIgnoreClear(ob, 1);
+ BKE_object_handle_update(depsgraph, scene, ob);
+ object_cacheIgnoreClear(ob, 0);
}
else
- BKE_object_where_is_calc_time(scene, ob, frame);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, frame);
/* for curve following objects, parented curve has to be updated too */
if (ob->type == OB_CURVE) {
Curve *cu = ob->data;
- BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
}
/* and armatures... */
if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
- BKE_animsys_evaluate_animdata(scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
- BKE_pose_where_is(scene, ob);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
+ BKE_pose_where_is(depsgraph, scene, ob);
}
return false;
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index aeeabf4360a..2de81864512 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -51,6 +51,7 @@
#include "BKE_editmesh.h"
#include "BKE_object_deform.h" /* own include */
#include "BKE_object.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
/** \name Misc helpers
@@ -405,6 +406,8 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
object_defgroup_remove_edit_mode(ob, defgroup);
else
object_defgroup_remove_object_mode(ob, defgroup);
+
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
}
/**
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 589c4468000..b7748039f62 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -48,20 +48,23 @@
#include "DNA_vfont_types.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_DerivedMesh.h"
-#include "BKE_depsgraph.h"
#include "BKE_font.h"
-#include "BKE_group.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_editmesh.h"
#include "BKE_anim.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "BLI_strict_flags.h"
#include "BLI_hash.h"
@@ -69,16 +72,14 @@
/* Dupli-Geometry */
typedef struct DupliContext {
- EvaluationContext *eval_ctx;
- bool do_update;
- bool animated;
- Group *group; /* XXX child objects are selected from this group if set, could be nicer */
+ Depsgraph *depsgraph;
+ Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */
+ Object *obedit; /* Only to check if the object is in edit-mode. */
- Main *bmain;
Scene *scene;
+ ViewLayer *view_layer;
Object *object;
float space_mat[4][4];
- unsigned int lay;
int persistent_id[MAX_DUPLI_RECUR];
int level;
@@ -98,23 +99,20 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx);
/* create initial context for root object */
static void init_context(
- DupliContext *r_ctx, Main *bmain, EvaluationContext *eval_ctx,
- Scene *scene, Object *ob, float space_mat[4][4], bool update)
+ DupliContext *r_ctx, Depsgraph *depsgraph,
+ Scene *scene, Object *ob, float space_mat[4][4])
{
- r_ctx->eval_ctx = eval_ctx;
- r_ctx->bmain = bmain;
+ r_ctx->depsgraph = depsgraph;
r_ctx->scene = scene;
- /* don't allow BKE_object_handle_update for viewport during render, can crash */
- r_ctx->do_update = update && !(G.is_rendering && eval_ctx->mode != DAG_EVAL_RENDER);
- r_ctx->animated = false;
- r_ctx->group = NULL;
+ r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ r_ctx->collection = NULL;
r_ctx->object = ob;
+ r_ctx->obedit = OBEDIT_FROM_OBACT(ob);
if (space_mat)
copy_m4_m4(r_ctx->space_mat, space_mat);
else
unit_m4(r_ctx->space_mat);
- r_ctx->lay = ob->lay;
r_ctx->level = 0;
r_ctx->gen = get_dupli_generator(r_ctx);
@@ -123,15 +121,13 @@ static void init_context(
}
/* create sub-context for recursive duplis */
-static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated)
+static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
{
*r_ctx = *ctx;
- r_ctx->animated |= animated; /* object animation makes all children animated */
-
/* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
- if (ctx->gen->type == OB_DUPLIGROUP)
- r_ctx->group = ctx->object->dup_group;
+ if (ctx->gen->type == OB_DUPLICOLLECTION)
+ r_ctx->collection = ctx->object->dup_group;
r_ctx->object = ob;
if (mat)
@@ -146,8 +142,7 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj
* mat is transform of the object relative to current context (including object obmat)
*/
static DupliObject *make_dupli(const DupliContext *ctx,
- Object *ob, float mat[4][4], int index,
- bool animated, bool hide)
+ Object *ob, float mat[4][4], int index)
{
DupliObject *dob;
int i;
@@ -164,7 +159,6 @@ static DupliObject *make_dupli(const DupliContext *ctx,
dob->ob = ob;
mul_m4_m4m4(dob->mat, (float (*)[4])ctx->space_mat, mat);
dob->type = ctx->gen->type;
- dob->animated = animated || ctx->animated; /* object itself or some parent is animated */
/* set persistent id, which is an array with a persistent index for each level
* (particle number, vertex number, ..). by comparing this we can find the same
@@ -177,8 +171,6 @@ static DupliObject *make_dupli(const DupliContext *ctx,
for (; i < MAX_DUPLI_RECUR; i++)
dob->persistent_id[i] = INT_MAX;
- if (hide)
- dob->no_draw = true;
/* metaballs never draw in duplis, they are instead merged into one by the basis
* mball outside of the group. this does mean that if that mball is not in the
* scene, they will not show up at all, limitation that should be solved once. */
@@ -208,12 +200,12 @@ static DupliObject *make_dupli(const DupliContext *ctx,
/* recursive dupli objects
* space_mat is the local dupli space (excluding dupli object obmat!)
*/
-static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated)
+static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index)
{
- /* simple preventing of too deep nested groups with MAX_DUPLI_RECUR */
+ /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */
if (ctx->level < MAX_DUPLI_RECUR) {
DupliContext rctx;
- copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated);
+ copy_dupli_context(&rctx, ctx, ob, space_mat, index);
if (rctx.gen) {
rctx.gen->make_duplis(&rctx);
}
@@ -235,41 +227,36 @@ static bool is_child(const Object *ob, const Object *parent)
return false;
}
-/* create duplis from every child in scene or group */
+/* create duplis from every child in scene or collection */
static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb)
{
Object *parent = ctx->object;
- Object *obedit = ctx->scene->obedit;
-
- if (ctx->group) {
- unsigned int lay = ctx->group->layer;
- int groupid = 0;
- GroupObject *go;
- for (go = ctx->group->gobject.first; go; go = go->next, groupid++) {
- Object *ob = go->ob;
- if ((ob->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ if (ctx->collection) {
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(ctx->collection, ob, mode)
+ {
+ if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, _base_id);
/* mballs have a different dupli handling */
- if (ob->type != OB_MBALL)
+ if (ob->type != OB_MBALL) {
ob->flag |= OB_DONE; /* doesnt render */
-
+ }
make_child_duplis_cb(&pctx, userdata, ob);
}
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
else {
- unsigned int lay = ctx->scene->lay;
int baseid = 0;
- Base *base;
- for (base = ctx->scene->base.first; base; base = base->next, baseid++) {
+ ViewLayer *view_layer = ctx->view_layer;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) {
Object *ob = base->object;
-
- if ((base->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid);
/* mballs have a different dupli handling */
if (ob->type != OB_MBALL)
@@ -284,77 +271,49 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
/*---- Implementations ----*/
-/* OB_DUPLIGROUP */
-static void make_duplis_group(const DupliContext *ctx)
+/* OB_DUPLICOLLECTION */
+static void make_duplis_collection(const DupliContext *ctx)
{
- bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
Object *ob = ctx->object;
- Group *group;
- GroupObject *go;
- float group_mat[4][4];
- int id;
- bool animated, hide;
+ Collection *collection;
+ float collection_mat[4][4];
if (ob->dup_group == NULL) return;
- group = ob->dup_group;
+ collection = ob->dup_group;
- /* combine group offset and obmat */
- unit_m4(group_mat);
- sub_v3_v3(group_mat[3], group->dupli_ofs);
- mul_m4_m4m4(group_mat, ob->obmat, group_mat);
+ /* combine collection offset and obmat */
+ unit_m4(collection_mat);
+ sub_v3_v3(collection_mat[3], collection->dupli_ofs);
+ mul_m4_m4m4(collection_mat, ob->obmat, collection_mat);
/* don't access 'ob->obmat' from now on. */
- /* handles animated groups */
-
- /* we need to check update for objects that are not in scene... */
- if (ctx->do_update) {
- /* note: update is optional because we don't always need object
- * transformations to be correct. Also fixes bug [#29616]. */
- BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, ctx->scene, ob, group);
- }
-
- animated = BKE_group_is_animated(group, ob);
-
- for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
- /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
- if (go->ob != ob) {
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(collection, cob, mode)
+ {
+ if (cob != ob) {
float mat[4][4];
- /* Special case for instancing dupli-groups, see: T40051
- * this object may be instanced via dupli-verts/faces, in this case we don't want to render
- * (blender convention), but _do_ show in the viewport.
- *
- * Regular objects work fine but not if we're instancing dupli-groups,
- * because the rules for rendering aren't applied to objects they instance.
- * We could recursively pass down the 'hide' flag instead, but that seems unnecessary.
- */
- if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) {
- continue;
- }
-
- /* group dupli offset, should apply after everything else */
- mul_m4_m4m4(mat, group_mat, go->ob->obmat);
+ /* collection dupli offset, should apply after everything else */
+ mul_m4_m4m4(mat, collection_mat, cob->obmat);
- /* check the group instance and object layers match, also that the object visible flags are ok. */
- hide = (go->ob->lay & group->layer) == 0 ||
- (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW);
-
- make_dupli(ctx, go->ob, mat, id, animated, hide);
+ make_dupli(ctx, cob, mat, _base_id);
/* recursion */
- make_recursive_duplis(ctx, go->ob, group_mat, id, animated);
+ make_recursive_duplis(ctx, cob, collection_mat, _base_id);
}
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
-static const DupliGenerator gen_dupli_group = {
- OB_DUPLIGROUP, /* type */
- make_duplis_group /* make_duplis */
+static const DupliGenerator gen_dupli_collection = {
+ OB_DUPLICOLLECTION, /* type */
+ make_duplis_collection /* make_duplis */
};
/* OB_DUPLIFRAMES */
static void make_duplis_frames(const DupliContext *ctx)
{
+ Depsgraph *depsgraph = ctx->depsgraph;
Scene *scene = ctx->scene;
Object *ob = ctx->object;
extern int enable_cu_speed; /* object.c */
@@ -362,8 +321,8 @@ static void make_duplis_frames(const DupliContext *ctx)
int cfrao = scene->r.cfra;
int dupend = ob->dupend;
- /* dupliframes not supported inside groups */
- if (ctx->group)
+ /* dupliframes not supported inside collections */
+ if (ctx->collection)
return;
/* if we don't have any data/settings which will lead to object movement,
* don't waste time trying, as it will all look the same...
@@ -381,10 +340,6 @@ static void make_duplis_frames(const DupliContext *ctx)
/* duplicate over the required range */
if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed = 0;
- /* special flag to avoid setting recalc flags to notify the depsgraph of
- * updates, as this is not a permanent change to the object */
- ob->id.recalc |= ID_RECALC_SKIP_ANIM_TAG;
-
for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) {
int ok = 1;
@@ -402,10 +357,11 @@ static void make_duplis_frames(const DupliContext *ctx)
* and/or other objects which may affect this object's transforms are not updated either.
* However, this has always been the way that this worked (i.e. pre 2.5), so I guess that it'll be fine!
*/
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */
- BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra);
+ /* ob-eval will do drivers, so we don't need to do them */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra);
- make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false);
+ make_dupli(ctx, ob, ob->obmat, scene->r.cfra);
}
}
@@ -416,8 +372,9 @@ static void make_duplis_frames(const DupliContext *ctx)
*/
scene->r.cfra = cfrao;
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */
- BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra);
+ /* ob-eval will do drivers, so we don't need to do them */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra);
/* but, to make sure unkeyed object transforms are still sane,
* let's copy object's original data back over
@@ -490,13 +447,13 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3],
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false);
+ dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index);
if (vdd->orco)
copy_v3_v3(dob->orco, vdd->orco[index]);
/* recursion */
- make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index, false);
+ make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index);
}
static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child)
@@ -539,7 +496,7 @@ static void make_duplis_verts(const DupliContext *ctx)
{
Scene *scene = ctx->scene;
Object *parent = ctx->object;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
VertexDupliData vdd;
vdd.ctx = ctx;
@@ -551,14 +508,14 @@ static void make_duplis_verts(const DupliContext *ctx)
BMEditMesh *em = BKE_editmesh_from_object(parent);
CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH);
- if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
- vdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
+ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER) {
+ vdd.dm = mesh_create_derived_render(ctx->depsgraph, scene, parent, dm_mask);
}
else if (em) {
- vdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
+ vdd.dm = editbmesh_get_derived_cage(ctx->depsgraph, scene, parent, em, dm_mask);
}
else {
- vdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ vdd.dm = mesh_get_derived_final(ctx->depsgraph, scene, parent, dm_mask);
}
vdd.edit_btmesh = me->edit_btmesh;
@@ -626,8 +583,8 @@ static void make_duplis_font(const DupliContext *ctx)
const wchar_t *text = NULL;
bool text_free = false;
- /* font dupliverts not supported inside groups */
- if (ctx->group)
+ /* font dupliverts not supported inside collections */
+ if (ctx->collection)
return;
copy_m4_m4(pmat, par->obmat);
@@ -655,7 +612,9 @@ static void make_duplis_font(const DupliContext *ctx)
/* advance matching BLI_strncpy_wchar_from_utf8 */
for (a = 0; a < text_len; a++, ct++) {
- ob = find_family_object(ctx->bmain, cu->family, family_len, (unsigned int)text[a], family_gh);
+ /* XXX That G.main is *really* ugly, but not sure what to do here...
+ * Definitively don't think it would be safe to put back Main *bmain pointer in DupliContext as done in 2.7x? */
+ ob = find_family_object(G.main, cu->family, family_len, (unsigned int)text[a], family_gh);
if (ob) {
vec[0] = fsize * (ct->xof - xof);
vec[1] = fsize * (ct->yof - yof);
@@ -675,7 +634,7 @@ static void make_duplis_font(const DupliContext *ctx)
copy_v3_v3(obmat[3], vec);
- make_dupli(ctx, ob, obmat, a, false, false);
+ make_dupli(ctx, ob, obmat, a);
}
}
@@ -743,7 +702,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
float (*orco)[3] = fdd->orco;
MLoopUV *mloopuv = fdd->mloopuv;
int a, totface = fdd->totface;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
float child_imat[4][4];
DupliObject *dob;
@@ -781,7 +740,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(ctx, inst_ob, obmat, a, false, false);
+ dob = make_dupli(ctx, inst_ob, obmat, a);
if (use_texcoords) {
float w = 1.0f / (float)mp->totloop;
@@ -801,7 +760,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
}
/* recursion */
- make_recursive_duplis(ctx, inst_ob, space_mat, a, false);
+ make_recursive_duplis(ctx, inst_ob, space_mat, a);
}
}
@@ -809,7 +768,7 @@ static void make_duplis_faces(const DupliContext *ctx)
{
Scene *scene = ctx->scene;
Object *parent = ctx->object;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
FaceDupliData fdd;
fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0);
@@ -819,14 +778,14 @@ static void make_duplis_faces(const DupliContext *ctx)
BMEditMesh *em = BKE_editmesh_from_object(parent);
CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH);
- if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
- fdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
+ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER) {
+ fdd.dm = mesh_create_derived_render(ctx->depsgraph, scene, parent, dm_mask);
}
else if (em) {
- fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
+ fdd.dm = editbmesh_get_derived_cage(ctx->depsgraph, scene, parent, em, dm_mask);
}
else {
- fdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ fdd.dm = mesh_get_derived_final(ctx->depsgraph, scene, parent, dm_mask);
}
if (use_texcoords) {
@@ -861,10 +820,10 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
{
Scene *scene = ctx->scene;
Object *par = ctx->object;
- bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ bool for_render = mode == DAG_EVAL_RENDER;
+ bool use_texcoords = for_render;
- GroupObject *go;
Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL;
DupliObject *dob;
ParticleDupliWeight *dw;
@@ -877,8 +836,8 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0;
float (*obmat)[4];
int a, b, hair = 0;
- int totpart, totchild, totgroup = 0 /*, pa_num */;
- const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene);
+ int totpart, totchild, totcollection = 0 /*, pa_num */;
+ RNG *rng;
int no_draw_flag = PARS_UNEXIST;
@@ -889,21 +848,22 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part == NULL)
return;
- if (!psys_check_enabled(par, psys, (ctx->eval_ctx->mode == DAG_EVAL_RENDER)))
+ if (!psys_check_enabled(par, psys, for_render))
return;
if (!for_render)
no_draw_flag |= PARS_NO_DISP;
- ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */
+ ctime = DEG_get_ctime(ctx->depsgraph); /* NOTE: in old animsys, used parent object's timeoffset... */
totpart = psys->totpart;
totchild = psys->totchild;
- BLI_srandom((unsigned int)(31415926 + psys->seed));
+ rng = BLI_rng_new_srandom(31415926u + (unsigned int)psys->seed);
- if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
+ if ((for_render || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
ParticleSimulationData sim = {NULL};
+ sim.depsgraph = ctx->depsgraph;
sim.scene = scene;
sim.ob = par;
sim.psys = psys;
@@ -917,10 +877,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
return;
}
else { /*PART_DRAW_GR */
- if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject))
+ if (part->dup_group == NULL)
return;
- if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) {
+ const ListBase dup_collection_objects = BKE_collection_object_cache_get(part->dup_group);
+ if (BLI_listbase_is_empty(&dup_collection_objects))
+ return;
+
+ if (BLI_findptr(&dup_collection_objects, par, offsetof(Base, object))) {
return;
}
}
@@ -943,28 +907,28 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
/* gather list of objects or single object */
if (part->ren_as == PART_DRAW_GR) {
- if (ctx->do_update) {
- BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, scene, par, part->dup_group);
- }
-
if (part->draw & PART_DRAW_COUNT_GR) {
for (dw = part->dupliweights.first; dw; dw = dw->next)
- totgroup += dw->count;
+ totcollection += dw->count;
}
else {
- for (go = part->dup_group->gobject.first; go; go = go->next)
- totgroup++;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ (void) object;
+ totcollection++;
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
/* we also copy the actual objects to restore afterwards, since
* BKE_object_where_is_calc_time will change the object which breaks transform */
- oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list");
- obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list");
+ oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list");
+ obcopylist = MEM_callocN((size_t)totcollection * sizeof(Object), "dupcollection copy list");
- if (part->draw & PART_DRAW_COUNT_GR && totgroup) {
+ if (part->draw & PART_DRAW_COUNT_GR && totcollection) {
dw = part->dupliweights.first;
- for (a = 0; a < totgroup; dw = dw->next) {
+ for (a = 0; a < totcollection; dw = dw->next) {
for (b = 0; b < dw->count; b++, a++) {
oblist[a] = dw->ob;
obcopylist[a] = *dw->ob;
@@ -972,11 +936,18 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
}
else {
- go = part->dup_group->gobject.first;
- for (a = 0; a < totgroup; a++, go = go->next) {
- oblist[a] = go->ob;
- obcopylist[a] = *go->ob;
+ a = 0;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ oblist[a] = object;
+ obcopylist[a] = *object;
+ a++;
+
+ if (a >= totcollection) {
+ continue;
+ }
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
}
else {
@@ -1018,14 +989,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part->ren_as == PART_DRAW_GR) {
/* prevent divide by zero below [#28336] */
- if (totgroup == 0)
+ if (totcollection == 0)
continue;
- /* for groups, pick the object based on settings */
+ /* for collections, pick the object based on settings */
if (part->draw & PART_DRAW_RAND_GR)
- b = BLI_rand() % totgroup;
+ b = BLI_rng_get_int(rng) % totcollection;
else
- b = a % totgroup;
+ b = a % totcollection;
ob = oblist[b];
obmat = oblist[b]->obmat;
@@ -1065,27 +1036,37 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
- for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) {
-
+ b = 0;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
copy_m4_m4(tmat, oblist[b]->obmat);
+
/* apply particle scale */
mul_mat3_m4_fl(tmat, size * scale);
mul_v3_fl(tmat[3], size * scale);
- /* group dupli offset, should apply after everything else */
- if (!is_zero_v3(part->dup_group->dupli_ofs))
+
+ /* collection dupli offset, should apply after everything else */
+ if (!is_zero_v3(part->dup_group->dupli_ofs)) {
sub_v3_v3(tmat[3], part->dup_group->dupli_ofs);
+ }
+
/* individual particle transform */
mul_m4_m4m4(mat, pamat, tmat);
- dob = make_dupli(ctx, go->ob, mat, a, false, false);
+ dob = make_dupli(ctx, object, mat, a);
dob->particle_system = psys;
- if (use_texcoords)
+
+ if (use_texcoords) {
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
+ }
+
+ b++;
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
else {
/* to give ipos in object correct offset */
- BKE_object_where_is_calc_time(scene, ob, ctime - pa_time);
+ BKE_object_where_is_calc_time(ctx->depsgraph, scene, ob, ctime - pa_time);
copy_v3_v3(vec, obmat[3]);
obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;
@@ -1126,20 +1107,16 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part->draw & PART_DRAW_GLOBAL_OB)
add_v3_v3v3(mat[3], mat[3], vec);
- dob = make_dupli(ctx, ob, mat, a, false, false);
+ dob = make_dupli(ctx, ob, mat, a);
dob->particle_system = psys;
if (use_texcoords)
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
- /* XXX blender internal needs this to be set to dupligroup to render
- * groups correctly, but we don't want this hack for cycles */
- if (dupli_type_hack && ctx->group)
- dob->type = OB_DUPLIGROUP;
}
}
/* restore objects since they were changed in BKE_object_where_is_calc_time */
if (part->ren_as == PART_DRAW_GR) {
- for (a = 0; a < totgroup; a++)
+ for (a = 0; a < totcollection; a++)
*(oblist[a]) = obcopylist[a];
}
else
@@ -1156,6 +1133,8 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
end_latt_deform(psys->lattice_deform_data);
psys->lattice_deform_data = NULL;
}
+
+ BLI_rng_free(rng);
}
static void make_duplis_particles(const DupliContext *ctx)
@@ -1167,7 +1146,7 @@ static void make_duplis_particles(const DupliContext *ctx)
for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) {
/* particles create one more level for persistent psys index */
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid);
make_duplis_particle_system(&pctx, psys);
}
}
@@ -1189,7 +1168,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
return NULL;
/* Should the dupli's be generated for this object? - Respect restrict flags */
- if (ctx->eval_ctx->mode == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
+ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
return NULL;
if (transflag & OB_DUPLIPARTS) {
@@ -1210,8 +1189,8 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
else if (transflag & OB_DUPLIFRAMES) {
return &gen_dupli_frames;
}
- else if (transflag & OB_DUPLIGROUP) {
- return &gen_dupli_group;
+ else if (transflag & OB_DUPLICOLLECTION) {
+ return &gen_dupli_collection;
}
return NULL;
@@ -1221,11 +1200,11 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
/* ---- ListBase dupli container implementation ---- */
/* Returns a list of DupliObject */
-ListBase *object_duplilist_ex(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update)
+ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
DupliContext ctx;
- init_context(&ctx, bmain, eval_ctx, scene, ob, NULL, update);
+ init_context(&ctx, depsgraph, sce, ob, NULL);
if (ctx.gen) {
ctx.duplilist = duplilist;
ctx.gen->make_duplis(&ctx);
@@ -1234,13 +1213,6 @@ ListBase *object_duplilist_ex(Main *bmain, EvaluationContext *eval_ctx, Scene *s
return duplilist;
}
-/* note: previously updating was always done, this is why it defaults to be on
- * but there are likely places it can be called without updating */
-ListBase *object_duplilist(Main *bmain, EvaluationContext *eval_ctx, Scene *sce, Object *ob)
-{
- return object_duplilist_ex(bmain, eval_ctx, sce, ob, true);
-}
-
void free_object_duplilist(ListBase *lb)
{
BLI_freelistN(lb);
@@ -1277,7 +1249,7 @@ int count_duplilist(Object *ob)
return 1;
}
-DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
+DupliApplyData *duplilist_apply(Depsgraph *depsgraph, Object *ob, Scene *scene, ListBase *duplilist)
{
DupliApplyData *apply_data = NULL;
int num_objects = BLI_listbase_count(duplilist);
@@ -1293,7 +1265,7 @@ DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
/* make sure derivedmesh is calculated once, before drawing */
if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) {
- mesh_get_derived_final(scene, dob->ob, scene->customdata_mask);
+ mesh_get_derived_final(depsgraph, scene, dob->ob, scene->customdata_mask);
dob->ob->transflag |= OB_DUPLICALCDERIVED;
}
}
diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c
new file mode 100644
index 00000000000..ef254864d2e
--- /dev/null
+++ b/source/blender/blenkernel/intern/object_facemap.c
@@ -0,0 +1,257 @@
+
+/*
+ * ***** 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) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/object_facemap.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_listbase.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_object.h"
+#include "BKE_object_facemap.h" /* own include */
+#include "BKE_object_deform.h"
+
+#include "BLT_translation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+static bool fmap_unique_check(void *arg, const char *name)
+{
+ struct {Object *ob; void *fm; } *data = arg;
+
+ bFaceMap *fmap;
+
+ for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) {
+ if (data->fm != fmap) {
+ if (!strcmp(fmap->name, name)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bFaceMap *fmap_duplicate(bFaceMap *infmap)
+{
+ bFaceMap *outfmap;
+
+ if (!infmap)
+ return NULL;
+
+ outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap");
+
+ /* For now, just copy everything over. */
+ memcpy(outfmap, infmap, sizeof(bFaceMap));
+
+ outfmap->next = outfmap->prev = NULL;
+
+ return outfmap;
+}
+
+void BKE_object_facemap_copy_list(ListBase *outbase, const ListBase *inbase)
+{
+ bFaceMap *fmap, *fmapn;
+
+ BLI_listbase_clear(outbase);
+
+ for (fmap = inbase->first; fmap; fmap = fmap->next) {
+ fmapn = fmap_duplicate(fmap);
+ BLI_addtail(outbase, fmapn);
+ }
+}
+
+void BKE_object_facemap_unique_name(Object *ob, bFaceMap *fmap)
+{
+ struct {Object *ob; void *fmap; } data;
+ data.ob = ob;
+ data.fmap = fmap;
+
+ BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name));
+}
+
+bFaceMap *BKE_object_facemap_add_name(Object *ob, const char *name)
+{
+ bFaceMap *fmap;
+
+ if (!ob || ob->type != OB_MESH)
+ return NULL;
+
+ fmap = MEM_callocN(sizeof(bFaceMap), __func__);
+
+ BLI_strncpy(fmap->name, name, sizeof(fmap->name));
+
+ BLI_addtail(&ob->fmaps, fmap);
+
+ ob->actfmap = BLI_listbase_count(&ob->fmaps);
+
+ BKE_object_facemap_unique_name(ob, fmap);
+
+ return fmap;
+}
+
+bFaceMap *BKE_object_facemap_add(Object *ob)
+{
+ return BKE_object_facemap_add_name(ob, DATA_("FaceMap"));
+}
+
+
+static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge)
+{
+ const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
+
+ if (cd_fmap_offset != -1) {
+ BMFace *efa;
+ BMIter iter;
+ int *map;
+
+ if (purge) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (map) {
+ if (*map == fmap_nr)
+ *map = -1;
+ else if (*map > fmap_nr)
+ *map -= 1;
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (map && *map == fmap_nr && (!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
+ *map = -1;
+ }
+ }
+ }
+ }
+
+ if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
+ ob->actfmap--;
+
+ BLI_remlink(&ob->fmaps, fmap);
+ MEM_freeN(fmap);
+ }
+ }
+}
+
+static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge)
+{
+ const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
+ int i;
+
+ if (map) {
+ for (i = 0; i < me->totpoly; i++) {
+ if (map[i] == fmap_nr)
+ map[i] = -1;
+ else if (purge && map[i] > fmap_nr)
+ map[i]--;
+ }
+ }
+ }
+
+ if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
+ ob->actfmap--;
+
+ BLI_remlink(&ob->fmaps, fmap);
+ MEM_freeN(fmap);
+ }
+}
+
+static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge)
+{
+ if (is_edit_mode)
+ object_fmap_remove_edit_mode(ob, fmap, false, purge);
+ else
+ object_fmap_remove_object_mode(ob, fmap, purge);
+}
+
+void BKE_object_facemap_remove(Object *ob, bFaceMap *fmap)
+{
+ fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true);
+}
+
+void BKE_object_facemap_clear(Object *ob)
+{
+ bFaceMap *fmap = (bFaceMap *)ob->fmaps.first;
+
+ if (fmap) {
+ const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
+
+ while (fmap) {
+ bFaceMap *next_fmap = fmap->next;
+ fmap_remove_exec(ob, fmap, edit_mode, false);
+ fmap = next_fmap;
+ }
+ }
+ /* remove all face-maps */
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0);
+ }
+ ob->actfmap = 0;
+}
+
+int BKE_object_facemap_name_index(Object *ob, const char *name)
+{
+ return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1;
+}
+
+bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name)
+{
+ return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
+}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index bb738033f02..2fc8fe6e0ae 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -32,18 +32,18 @@
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
+#include "DNA_mesh_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_animsys.h"
#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
-#include "BKE_depsgraph.h"
+#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
@@ -53,21 +53,25 @@
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "MEM_guardedalloc.h"
+
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
-static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER;
-void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
- Object *ob)
+void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* calculate local matrix */
BKE_object_to_mat4(ob, ob->obmat);
@@ -75,7 +79,7 @@ void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
/* Evaluate parent */
/* NOTE: based on solve_parenting(), but with the cruft stripped out */
-void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
+void BKE_object_eval_parent(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
@@ -85,14 +89,14 @@ void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
float tmat[4][4];
float locmat[4][4];
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* 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);
+ BKE_object_get_parent_matrix(depsgraph, scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
@@ -107,14 +111,14 @@ void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
}
}
-void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
+void BKE_object_eval_constraints(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
bConstraintOb *cob;
float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* evaluate constraints stack */
/* TODO: split this into:
@@ -125,23 +129,29 @@ void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
* 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);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
BKE_constraints_clear_evalob(cob);
}
-void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+void BKE_object_eval_done(Depsgraph *depsgraph, Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* Set negative scale flag in object. */
if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
else ob->transflag &= ~OB_NEG_SCALE;
+
+ if (DEG_is_active(depsgraph)) {
+ Object *ob_orig = DEG_get_original_object(ob);
+ copy_m4_m4(ob_orig->obmat, ob->obmat);
+ ob_orig->transflag = ob->transflag;
+ ob_orig->flag = ob->flag;
+ }
}
void BKE_object_handle_data_update(
- Main *bmain,
- EvaluationContext *eval_ctx,
+ Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
@@ -156,34 +166,42 @@ void BKE_object_handle_data_update(
/* 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);
+ /* XXX: for mesh types, should we push this to evaluated mesh instead? */
+ BKE_animsys_evaluate_animdata(depsgraph, 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);
+ BKE_animsys_evaluate_animdata(depsgraph, 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;
+#if 0
+ BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
+#else
+ BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_btmesh : NULL;
+ if (em && em->ob != ob) {
+ em = NULL;
+ }
+#endif
+
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) {
+ if (DEG_get_mode(depsgraph) != DAG_EVAL_VIEWPORT) {
data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
}
#endif
if (em) {
- makeDerivedMesh(scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */
+ makeDerivedMesh(depsgraph, scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */
}
else {
- makeDerivedMesh(scene, ob, NULL, data_mask, false);
+ makeDerivedMesh(depsgraph, scene, ob, NULL, data_mask, false);
}
break;
}
@@ -195,22 +213,22 @@ void BKE_object_handle_data_update(
}
}
else {
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(depsgraph, scene, ob);
}
break;
case OB_MBALL:
- BKE_displist_make_mball(bmain, eval_ctx, scene, ob);
+ BKE_displist_make_mball(depsgraph, scene, ob);
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
- BKE_displist_make_curveTypes(scene, ob, 0);
+ BKE_displist_make_curveTypes(depsgraph, scene, ob, 0);
break;
case OB_LATTICE:
- BKE_lattice_modifiers_calc(scene, ob);
+ BKE_lattice_modifiers_calc(depsgraph, scene, ob);
break;
case OB_EMPTY:
@@ -220,50 +238,23 @@ void BKE_object_handle_data_update(
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) {
+ if (!(ob->mode & OB_MODE_EDIT) && ob->particlesystem.first) {
+ const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
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, eval_ctx->mode == DAG_EVAL_RENDER)) {
+ if (psys_check_enabled(ob, psys, use_render_params)) {
/* check use of dupli objects here */
- if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
+ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || use_render_params) &&
((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(bmain, scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER));
+ particle_system_update(depsgraph, scene, ob, psys, use_render_params);
psys = psys->next;
}
else if (psys->flag & PSYS_DELETE) {
@@ -275,28 +266,17 @@ void BKE_object_handle_data_update(
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 */
- CustomDataMask data_mask = CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL;
- dm = mesh_create_derived_render(scene, ob, data_mask);
- dm->release(dm);
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
- }
}
/* quick cache removed */
}
-bool BKE_object_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx),
+bool BKE_object_eval_proxy_copy(Depsgraph *depsgraph,
Object *object)
{
/* Handle proxy copy for target, */
if (ID_IS_LINKED(object) && object->proxy_from) {
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
if (object->proxy_from->proxy_group) {
/* Transform proxy into group space. */
Object *obg = object->proxy_from->proxy_group;
@@ -316,46 +296,126 @@ bool BKE_object_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx),
return false;
}
-void BKE_object_eval_uber_transform(EvaluationContext *eval_ctx, Object *object)
+void BKE_object_eval_uber_transform(Depsgraph *depsgraph, Object *object)
{
- BKE_object_eval_proxy_copy(eval_ctx, object);
- object->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME);
- if (object->data == NULL) {
- object->recalc &= ~OB_RECALC_DATA;
- }
+ BKE_object_eval_proxy_copy(depsgraph, object);
}
-void BKE_object_eval_uber_data(Main *bmain, EvaluationContext *eval_ctx,
+void BKE_object_eval_uber_data(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type != OB_ARMATURE);
- BKE_object_handle_data_update(bmain, eval_ctx, scene, ob);
+ BKE_object_handle_data_update(depsgraph, scene, ob);
- ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ break;
+ case OB_LATTICE:
+ BKE_lattice_batch_cache_dirty(ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
+ break;
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ BKE_curve_batch_cache_dirty(ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
+ break;
+ case OB_MBALL:
+ BKE_mball_batch_cache_dirty(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
+ break;
+ }
}
-void BKE_object_eval_cloth(EvaluationContext *UNUSED(eval_ctx),
+void BKE_object_eval_cloth(Depsgraph *depsgraph,
Scene *scene,
Object *object)
{
- DEG_debug_print_eval(__func__, object->id.name, object);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
}
-void BKE_object_eval_transform_all(EvaluationContext *eval_ctx,
+void BKE_object_eval_transform_all(Depsgraph *depsgraph,
Scene *scene,
Object *object)
{
/* This mimics full transform update chain from new depsgraph. */
- BKE_object_eval_local_transform(eval_ctx, object);
+ BKE_object_eval_local_transform(depsgraph, object);
if (object->parent != NULL) {
- BKE_object_eval_parent(eval_ctx, scene, object);
+ BKE_object_eval_parent(depsgraph, scene, object);
}
if (!BLI_listbase_is_empty(&object->constraints)) {
- BKE_object_eval_constraints(eval_ctx, scene, object);
+ BKE_object_eval_constraints(depsgraph, scene, object);
+ }
+ BKE_object_eval_uber_transform(depsgraph, object);
+ BKE_object_eval_done(depsgraph, object);
+}
+
+void BKE_object_eval_update_shading(Depsgraph *depsgraph, Object *object)
+{
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ if (object->type == OB_MESH) {
+ BKE_mesh_batch_cache_dirty(object->data, BKE_MESH_BATCH_DIRTY_SHADING);
+ }
+}
+
+void BKE_object_data_select_update(Depsgraph *depsgraph, ID *object_data)
+{
+ DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data);
+ switch (GS(object_data->name)) {
+ case ID_ME:
+ BKE_mesh_batch_cache_dirty((Mesh *)object_data,
+ BKE_CURVE_BATCH_DIRTY_SELECT);
+ break;
+ case ID_CU:
+ BKE_curve_batch_cache_dirty((Curve *)object_data,
+ BKE_CURVE_BATCH_DIRTY_SELECT);
+ break;
+ case ID_LT:
+ BKE_lattice_batch_cache_dirty((struct Lattice *)object_data,
+ BKE_CURVE_BATCH_DIRTY_SELECT);
+ break;
+ default:
+ break;
+ }
+}
+
+void BKE_object_eval_flush_base_flags(Depsgraph *depsgraph,
+ Scene *scene, const int view_layer_index,
+ Object *object, int base_index,
+ const bool is_from_set)
+{
+ /* TODO(sergey): Avoid list lookup. */
+ BLI_assert(view_layer_index >= 0);
+ ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
+ BLI_assert(view_layer != NULL);
+ BLI_assert(view_layer->object_bases_array != NULL);
+ BLI_assert(base_index >= 0);
+ BLI_assert(base_index < MEM_allocN_len(view_layer->object_bases_array) / sizeof(Base *));
+ Base *base = view_layer->object_bases_array[base_index];
+ BLI_assert(base->object == object);
+
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+
+ /* Copy flags and settings from base. */
+ object->base_flag = base->flag;
+ if (is_from_set) {
+ object->base_flag |= BASE_FROM_SET;
+ object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLED);
+ }
+
+ /* Copy to original object datablock if needed. */
+ if (DEG_is_active(depsgraph)) {
+ Object *object_orig = DEG_get_original_object(object);
+ object_orig->base_flag = object->base_flag;
+ }
+
+ if (object->mode == OB_MODE_PARTICLE_EDIT) {
+ for (ParticleSystem *psys = object->particlesystem.first;
+ psys != NULL;
+ psys = psys->next)
+ {
+ BKE_particle_batch_cache_dirty(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ }
}
- BKE_object_eval_uber_transform(eval_ctx, object);
- BKE_object_eval_done(eval_ctx, object);
}
diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index 9db9b2ddf54..fb62645ef43 100644
--- a/source/blender/blenkernel/intern/outliner_treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -27,6 +27,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -40,6 +41,7 @@
typedef struct TseGroup {
TreeStoreElem **elems;
+ int lastused;
int size;
int allocated;
} TseGroup;
@@ -53,10 +55,11 @@ static TseGroup *tse_group_create(void)
tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems");
tse_group->size = 0;
tse_group->allocated = 1;
+ tse_group->lastused = 0;
return tse_group;
}
-static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
+static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem)
{
if (UNLIKELY(tse_group->size == tse_group->allocated)) {
tse_group->allocated *= 2;
@@ -66,6 +69,26 @@ static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
tse_group->size++;
}
+static void tse_group_remove_element(TseGroup *tse_group, TreeStoreElem *elem)
+{
+ int min_allocated = MAX2(1, tse_group->allocated / 2);
+ BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0);
+
+ tse_group->size--;
+ BLI_assert(tse_group->size >= 0);
+ for (int i = 0; i < tse_group->size; i++) {
+ if (tse_group->elems[i] == elem) {
+ memcpy(tse_group->elems[i], tse_group->elems[i + 1], (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *));
+ break;
+ }
+ }
+
+ if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) {
+ tse_group->allocated = min_allocated;
+ tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated);
+ }
+}
+
static void tse_group_free(TseGroup *tse_group)
{
MEM_freeN(tse_group->elems);
@@ -122,6 +145,16 @@ static void free_treehash_group(void *key)
tse_group_free(key);
}
+void BKE_outliner_treehash_clear_used(void *treehash)
+{
+ GHashIterator gh_iter;
+
+ GHASH_ITER(gh_iter, treehash) {
+ TseGroup *group = BLI_ghashIterator_getValue(&gh_iter);
+ group->lastused = 0;
+ }
+}
+
void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
{
BLI_assert(treehash);
@@ -140,7 +173,22 @@ void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem)
*val_p = tse_group_create();
}
group = *val_p;
- tse_group_add(group, elem);
+ group->lastused = 0;
+ tse_group_add_element(group, elem);
+}
+
+void BKE_outliner_treehash_remove_element(void *treehash, TreeStoreElem *elem)
+{
+ TseGroup *group = BLI_ghash_lookup(treehash, elem);
+
+ BLI_assert(group != NULL);
+ if (group->size <= 1) {
+ /* one element -> remove group completely */
+ BLI_ghash_remove(treehash, elem, NULL, free_treehash_group);
+ }
+ else {
+ tse_group_remove_element(group, elem);
+ }
}
static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
@@ -163,10 +211,19 @@ TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, s
group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
if (group) {
- int i;
- for (i = 0; i < group->size; i++) {
- if (!group->elems[i]->used) {
- return group->elems[i];
+ /* Find unused element, with optimization to start from previously
+ * found element assuming we do repeated lookups. */
+ int size = group->size;
+ int offset = group->lastused;
+
+ for (int i = 0; i < size; i++, offset++) {
+ if (offset >= size) {
+ offset = 0;
+ }
+
+ if (!group->elems[offset]->used) {
+ group->lastused = offset;
+ return group->elems[offset];
}
}
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 2c17fa44229..404a1a656d9 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -41,6 +41,7 @@
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "DNA_space_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
@@ -53,18 +54,21 @@
#include "BKE_main.h"
#include "BKE_context.h"
#include "BKE_crazyspace.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph.h"
+
#include "bmesh.h"
const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100};
@@ -74,9 +78,9 @@ const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255};
static eOverlayControlFlags overlay_flags = 0;
-void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
+void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, view_layer);
Brush *br = p->brush;
if (!br)
@@ -88,9 +92,9 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
overlay_flags |= PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY;
}
-void BKE_paint_invalidate_cursor_overlay(Scene *scene, CurveMapping *curve)
+void BKE_paint_invalidate_cursor_overlay(Scene *scene, ViewLayer *view_layer, CurveMapping *curve)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, view_layer);
Brush *br = p->brush;
if (br && br->curve == curve)
@@ -156,13 +160,13 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
return NULL;
}
-Paint *BKE_paint_get_active(Scene *sce)
+Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
{
- if (sce) {
+ if (sce && view_layer) {
ToolSettings *ts = sce->toolsettings;
- if (sce->basact && sce->basact->object) {
- switch (sce->basact->object->mode) {
+ if (view_layer->basact && view_layer->basact->object) {
+ switch (view_layer->basact->object->mode) {
case OB_MODE_SCULPT:
return &ts->sculpt->paint;
case OB_MODE_VERTEX_PAINT:
@@ -175,6 +179,8 @@ Paint *BKE_paint_get_active(Scene *sce)
if (ts->use_uv_sculpt)
return &ts->uvsculpt->paint;
return &ts->imapaint.paint;
+ default:
+ break;
}
}
@@ -188,14 +194,15 @@ Paint *BKE_paint_get_active(Scene *sce)
Paint *BKE_paint_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && view_layer) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (view_layer->basact && view_layer->basact->object)
+ obact = view_layer->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
@@ -209,7 +216,7 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
}
}
else {
- return BKE_paint_get_active(sce);
+ return BKE_paint_get_active(sce, view_layer);
}
}
@@ -219,14 +226,15 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
ePaintMode BKE_paintmode_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && view_layer) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (view_layer->basact && view_layer->basact->object)
+ obact = view_layer->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
@@ -332,8 +340,8 @@ void BKE_paint_palette_set(Paint *p, Palette *palette)
{
if (p) {
id_us_min((ID *)p->palette);
- id_us_plus((ID *)palette);
p->palette = palette;
+ id_us_plus((ID *)p->palette);
}
}
@@ -341,8 +349,8 @@ void BKE_paint_curve_set(Brush *br, PaintCurve *pc)
{
if (br) {
id_us_min((ID *)br->paint_curve);
- id_us_plus((ID *)pc);
br->paint_curve = pc;
+ id_us_plus((ID *)br->paint_curve);
}
}
@@ -375,9 +383,7 @@ void BKE_palette_clear(Palette *palette)
Palette *BKE_palette_add(Main *bmain, const char *name)
{
- Palette *palette;
-
- palette = BKE_libblock_alloc(bmain, ID_PAL, name, 0);
+ Palette *palette = BKE_id_new(bmain, ID_PAL, name);
/* enable fake user by default */
id_fake_user_set(&palette->id);
@@ -418,7 +424,7 @@ void BKE_palette_free(Palette *palette)
PaletteColor *BKE_palette_color_add(Palette *palette)
{
- PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color");
+ PaletteColor *color = MEM_callocN(sizeof(*color), "Palette Color");
BLI_addtail(&palette->colors, color);
return color;
}
@@ -713,8 +719,8 @@ void BKE_sculptsession_bm_to_me(Object *ob, bool reorder)
if (ob && ob->sculpt) {
sculptsession_bm_to_me_update_data_only(ob, reorder);
- /* ensure the objects DerivedMesh mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* ensure the objects evaluated mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
@@ -724,7 +730,7 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object)
if (object->sculpt->bm) {
/* Ensure no points to old arrays are stored in DM
*
- * Apparently, we could not use DAG_id_tag_update
+ * Apparently, we could not use DEG_id_tag_update
* here because this will lead to the while object
* surface to disappear, so we'll release DM in place.
*/
@@ -749,7 +755,6 @@ void BKE_sculptsession_free(Object *ob)
{
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
- DerivedMesh *dm = ob->derivedFinal;
if (ss->bm) {
BKE_sculptsession_bm_to_me(ob, true);
@@ -758,12 +763,11 @@ void BKE_sculptsession_free(Object *ob)
if (ss->pbvh)
BKE_pbvh_free(ss->pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
if (ss->bm_log)
BM_log_free(ss->bm_log);
- if (dm && dm->getPBVH)
- dm->getPBVH(NULL, dm); /* signal to clear */
-
if (ss->texcache)
MEM_freeN(ss->texcache);
@@ -853,14 +857,23 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
}
/**
- * \param need_mask So the DerivedMesh thats returned has mask data
+ * \param need_mask So taht the evaluated mesh that is returned has mask data.
*/
-void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
- bool need_pmap, bool need_mask)
+void BKE_sculpt_update_mesh_elements(
+ Depsgraph *depsgraph, Scene *scene, Sculpt *sd, Object *ob,
+ bool need_pmap, bool need_mask)
{
- DerivedMesh *dm;
+ if (depsgraph == NULL) {
+ /* Happens on file load.
+ *
+ * We do nothing in this case, it will be taken care about on depsgraph
+ * evaluation.
+ */
+ return;
+ }
+
SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
@@ -895,13 +908,14 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH);
+ Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
/* VWPaint require mesh info for loop lookup, so require sculpt mode here */
if (mmd && ob->mode & OB_MODE_SCULPT) {
ss->multires = mmd;
- ss->totvert = dm->getNumVerts(dm);
- ss->totpoly = dm->getNumPolys(dm);
+ ss->totvert = me_eval->totvert;
+ ss->totpoly = me_eval->totpoly;
ss->mvert = NULL;
ss->mpoly = NULL;
ss->mloop = NULL;
@@ -916,8 +930,17 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
}
- ss->pbvh = dm->getPBVH(ob, dm);
- ss->pmap = (need_pmap && dm->getPolyMap) ? dm->getPolyMap(ob, dm) : NULL;
+ PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(ob, me_eval_deform);
+ BLI_assert(pbvh == ss->pbvh);
+ UNUSED_VARS_NDEBUG(pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
+ if (need_pmap && ob->type == OB_MESH) {
+ BKE_mesh_vert_poly_map_create(
+ &ss->pmap, &ss->pmap_mem,
+ me->mpoly, me->mloop,
+ me->totvert, me->totpoly, me->totloop);
+ }
pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color);
pbvh_show_mask_set(ss->pbvh, ss->show_mask);
@@ -930,8 +953,8 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL);
- BKE_crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos);
- BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
+ BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos, me->totvert);
for (a = 0; a < me->totvert; ++a) {
invert_m3(ss->deform_imats[a]);
@@ -955,7 +978,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
if (vertCos) {
if (!pbvh_deformed) {
/* apply shape keys coordinates to PBVH */
- BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, me->totvert);
}
if (ss->deform_cos == NULL) {
ss->deform_cos = vertCos;
@@ -966,6 +989,9 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
}
}
}
+
+ /* 2.8x - avoid full mesh update! */
+ BKE_mesh_batch_cache_dirty(me, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS);
}
int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
@@ -1074,3 +1100,96 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
sd->paint.tile_offset[2] = 1.0f;
}
}
+
+static bool check_sculpt_object_deformed(Object *object, const bool for_construction)
+{
+ bool deformed = false;
+
+ /* Active modifiers means extra deformation, which can't be handled correct
+ * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
+ * stuff and show final evaluated mesh so user would see actual object shape.
+ */
+ deformed |= object->sculpt->modifiers_active;
+
+ if (for_construction) {
+ deformed |= object->sculpt->kb != NULL;
+ }
+ else {
+ /* As in case with modifiers, we can't synchronize deformation made against
+ * PBVH and non-locked keyblock, so also use PBVH only for brushes and
+ * final DM to give final result to user.
+ */
+ deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0;
+ }
+
+ return deformed;
+}
+
+PBVH *BKE_sculpt_object_pbvh_ensure(Object *ob, Mesh *me_eval_deform)
+{
+ if (!ob) {
+ return NULL;
+ }
+
+ if (!ob->sculpt) {
+ return NULL;
+ }
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH */
+ if (!pbvh && ob->sculpt->bm) {
+ pbvh = BKE_pbvh_new();
+
+ BKE_pbvh_build_bmesh(pbvh, ob->sculpt->bm,
+ ob->sculpt->bm_smooth_shading,
+ ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset,
+ ob->sculpt->cd_face_node_offset);
+
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+ }
+
+ /* always build pbvh from original mesh, and only use it for drawing if
+ * this evaluated mesh is just original mesh. it's the multires subsurf dm
+ * that this is actually for, to support a pbvh on a modified mesh */
+ if (!pbvh && ob->type == OB_MESH) {
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *looptri;
+ bool deformed;
+
+ pbvh = BKE_pbvh_new();
+
+ looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
+
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly,
+ me->mvert,
+ me->totloop, me->totpoly,
+ looptri);
+
+ BKE_pbvh_build_mesh(
+ pbvh,
+ me->mpoly, me->mloop,
+ me->mvert, me->totvert, &me->vdata,
+ looptri, looptris_num);
+
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+
+ deformed = check_sculpt_object_deformed(ob, true);
+
+ if (deformed && me_eval_deform) {
+ int totvert;
+ float (*v_cos)[3];
+
+ v_cos = BKE_mesh_vertexCos_get(me_eval_deform, &totvert);
+ BKE_pbvh_apply_vertCos(pbvh, v_cos, totvert);
+ MEM_freeN(v_cos);
+ }
+ }
+
+ ob->sculpt->pbvh = pbvh;
+ return pbvh;
+}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 50706a05dc0..278a8ab9720 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -51,6 +51,7 @@
#include "BLI_noise.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_kdopbvh.h"
#include "BLI_kdtree.h"
#include "BLI_rand.h"
#include "BLI_task.h"
@@ -64,10 +65,10 @@
#include "BKE_boids.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
#include "BKE_colortools.h"
#include "BKE_effect.h"
#include "BKE_global.h"
-#include "BKE_group.h"
#include "BKE_main.h"
#include "BKE_lattice.h"
@@ -78,14 +79,17 @@
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
-#include "BKE_depsgraph.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_cdderivedmesh.h" /* for weight_to_rgb() */
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_deform.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
#include "RE_render_ext.h"
#include "particle_private.h"
@@ -96,19 +100,19 @@ float PSYS_FRAND_BASE[PSYS_FRAND_COUNT];
void psys_init_rng(void)
{
- int i;
- BLI_srandom(5831); /* arbitrary */
- for (i = 0; i < PSYS_FRAND_COUNT; ++i) {
- PSYS_FRAND_BASE[i] = BLI_frand();
- PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rand();
- PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rand();
+ RNG *rng = BLI_rng_new_srandom(5831); /* arbitrary */
+ for (int i = 0; i < PSYS_FRAND_COUNT; ++i) {
+ PSYS_FRAND_BASE[i] = BLI_rng_get_float(rng);
+ PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rng_get_int(rng);
+ PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rng_get_int(rng);
}
+ BLI_rng_free(rng);
}
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
-static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
- int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
+static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
+ int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys)
@@ -249,10 +253,11 @@ struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData
{
struct LatticeDeformData *lattice_deform_data = NULL;
- if (psys_in_edit_mode(sim->scene, sim->psys) == 0) {
+ if (psys_in_edit_mode(sim->depsgraph, sim->psys) == 0) {
Object *lattice = NULL;
ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys);
- int mode = G.is_rendering ? eModifierMode_Render : eModifierMode_Realtime;
+ bool for_render = DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER;
+ int mode = for_render ? eModifierMode_Render : eModifierMode_Realtime;
for (; md; md = md->next) {
if (md->type == eModifierType_Lattice) {
@@ -285,10 +290,40 @@ void psys_enable_all(Object *ob)
for (; psys; psys = psys->next)
psys->flag &= ~PSYS_DISABLED;
}
-bool psys_in_edit_mode(Scene *scene, ParticleSystem *psys)
+
+ParticleSystem *psys_orig_get(ParticleSystem *psys)
+{
+ if (psys->orig_psys == NULL) {
+ return psys;
+ }
+ return psys->orig_psys;
+}
+
+static PTCacheEdit *psys_orig_edit_get(ParticleSystem *psys)
+{
+ if (psys->orig_psys == NULL) {
+ return psys->edit;
+ }
+ return psys->orig_psys->edit;
+}
+
+bool psys_in_edit_mode(Depsgraph *depsgraph, ParticleSystem *psys)
{
- return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit) && !psys->renderdata);
+ const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ if (view_layer->basact == NULL) {
+ /* TODO(sergey): Needs double-check with multi-object edit. */
+ return false;
+ }
+ const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const Object *object = view_layer->basact->object;
+ if (object->mode != OB_MODE_PARTICLE_EDIT) {
+ return false;
+ }
+ ParticleSystem *psys_orig = psys_orig_get(psys);
+ return (psys_orig->edit || psys->pointcache->edit) &&
+ (use_render_params == false);
}
+
bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSystemModifierData *psmd;
@@ -297,7 +332,7 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_
return 0;
psmd = psys_get_modifier(ob, psys);
- if (psys->renderdata || use_render_params) {
+ if (use_render_params) {
if (!(psmd->modifier.mode & eModifierMode_Render))
return 0;
}
@@ -318,18 +353,23 @@ bool psys_check_edited(ParticleSystem *psys)
void psys_check_group_weights(ParticleSettings *part)
{
ParticleDupliWeight *dw, *tdw;
- GroupObject *go;
int current = 0;
- if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) {
+ if (part->ren_as != PART_DRAW_GR || !part->dup_group) {
+ BLI_freelistN(&part->dupliweights);
+ return;
+ }
+
+ const ListBase dup_group_objects = BKE_collection_object_cache_get(part->dup_group);
+ if (dup_group_objects.first) {
/* First try to find NULL objects from their index,
* and remove all weights that don't have an object in the group. */
dw = part->dupliweights.first;
while (dw) {
- if (dw->ob == NULL || !BKE_group_object_exists(part->dup_group, dw->ob)) {
- go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
- if (go) {
- dw->ob = go->ob;
+ if (dw->ob == NULL || !BKE_collection_has_object_recursive(part->dup_group, dw->ob)) {
+ Base *base = BLI_findlink(&dup_group_objects, dw->index);
+ if (base != NULL) {
+ dw->ob = base->object;
}
else {
tdw = dw->next;
@@ -343,21 +383,21 @@ void psys_check_group_weights(ParticleSettings *part)
}
/* then add objects in the group to new list */
- go = part->dup_group->gobject.first;
- while (go) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object)
+ {
dw = part->dupliweights.first;
- while (dw && dw->ob != go->ob)
+ while (dw && dw->ob != object) {
dw = dw->next;
+ }
if (!dw) {
dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
- dw->ob = go->ob;
+ dw->ob = object;
dw->count = 1;
BLI_addtail(&part->dupliweights, dw);
}
-
- go = go->next;
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
dw = part->dupliweights.first;
for (; dw; dw = dw->next) {
@@ -447,13 +487,13 @@ void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics)
}
}
- if (psys->hair_in_dm)
- psys->hair_in_dm->release(psys->hair_in_dm);
- psys->hair_in_dm = NULL;
+ if (psys->hair_in_mesh)
+ BKE_id_free(NULL, psys->hair_in_mesh);
+ psys->hair_in_mesh = NULL;
- if (psys->hair_out_dm)
- psys->hair_out_dm->release(psys->hair_out_dm);
- psys->hair_out_dm = NULL;
+ if (psys->hair_out_mesh)
+ BKE_id_free(NULL, psys->hair_out_mesh);
+ psys->hair_out_mesh = NULL;
}
void free_keyed_keys(ParticleSystem *psys)
{
@@ -601,213 +641,62 @@ void psys_free(Object *ob, ParticleSystem *psys)
if (psys->fluid_springs)
MEM_freeN(psys->fluid_springs);
- pdEndEffectors(&psys->effectors);
+ BKE_effectors_free(psys->effectors);
if (psys->pdd) {
psys_free_pdd(psys);
MEM_freeN(psys->pdd);
}
- MEM_freeN(psys);
- }
-}
-
-/************************************************/
-/* Rendering */
-/************************************************/
-/* these functions move away particle data and bring it back after
- * rendering, to make different render settings possible without
- * removing the previous data. this should be solved properly once */
-
-void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset)
-{
- ParticleRenderData *data;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+ BKE_particle_batch_cache_free(psys);
- if (psys->renderdata)
- return;
-
- data = MEM_callocN(sizeof(ParticleRenderData), "ParticleRenderData");
-
- data->child = psys->child;
- data->totchild = psys->totchild;
- data->pathcache = psys->pathcache;
- data->pathcachebufs.first = psys->pathcachebufs.first;
- data->pathcachebufs.last = psys->pathcachebufs.last;
- data->totcached = psys->totcached;
- data->childcache = psys->childcache;
- data->childcachebufs.first = psys->childcachebufs.first;
- data->childcachebufs.last = psys->childcachebufs.last;
- data->totchildcache = psys->totchildcache;
-
- if (psmd->dm_final) {
- data->dm = CDDM_copy_with_tessface(psmd->dm_final);
- }
- data->totdmvert = psmd->totdmvert;
- data->totdmedge = psmd->totdmedge;
- data->totdmface = psmd->totdmface;
-
- psys->child = NULL;
- psys->pathcache = NULL;
- psys->childcache = NULL;
- psys->totchild = psys->totcached = psys->totchildcache = 0;
- BLI_listbase_clear(&psys->pathcachebufs);
- BLI_listbase_clear(&psys->childcachebufs);
-
- copy_m4_m4(data->winmat, winmat);
- mul_m4_m4m4(data->viewmat, viewmat, ob->obmat);
- mul_m4_m4m4(data->mat, winmat, data->viewmat);
- data->winx = winx;
- data->winy = winy;
-
- data->timeoffset = timeoffset;
-
- psys->renderdata = data;
-
- /* Hair can and has to be recalculated if everything isn't displayed. */
- if (psys->part->disp != 100 && ELEM(psys->part->type, PART_HAIR, PART_FLUID)) {
- psys->recalc |= PSYS_RECALC_RESET;
+ MEM_freeN(psys);
}
}
-void psys_render_restore(Object *ob, ParticleSystem *psys)
+void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src)
{
- ParticleRenderData *data;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- float render_disp = psys_get_current_display_percentage(psys);
- float disp;
-
- data = psys->renderdata;
- if (!data)
- return;
-
- if (data->elems)
- MEM_freeN(data->elems);
-
- if (psmd->dm_final) {
- psmd->dm_final->needsFree = 1;
- psmd->dm_final->release(psmd->dm_final);
- }
- if (psmd->dm_deformed) {
- psmd->dm_deformed->needsFree = 1;
- psmd->dm_deformed->release(psmd->dm_deformed);
- psmd->dm_deformed = NULL;
- }
-
- psys_free_path_cache(psys, NULL);
-
- if (psys->child) {
- MEM_freeN(psys->child);
- psys->child = 0;
- psys->totchild = 0;
- }
-
- psys->child = data->child;
- psys->totchild = data->totchild;
- psys->pathcache = data->pathcache;
- psys->pathcachebufs.first = data->pathcachebufs.first;
- psys->pathcachebufs.last = data->pathcachebufs.last;
- psys->totcached = data->totcached;
- psys->childcache = data->childcache;
- psys->childcachebufs.first = data->childcachebufs.first;
- psys->childcachebufs.last = data->childcachebufs.last;
- psys->totchildcache = data->totchildcache;
-
- psmd->dm_final = data->dm;
- psmd->totdmvert = data->totdmvert;
- psmd->totdmedge = data->totdmedge;
- psmd->totdmface = data->totdmface;
- psmd->flag &= ~eParticleSystemFlag_psys_updated;
-
- if (psmd->dm_final) {
- if (!psmd->dm_final->deformedOnly) {
- if (ob->derivedDeform) {
- psmd->dm_deformed = CDDM_copy(ob->derivedDeform);
- }
- else {
- psmd->dm_deformed = CDDM_from_mesh((Mesh *)ob->data);
- }
- DM_ensure_tessface(psmd->dm_deformed);
- }
- psys_calc_dmcache(ob, psmd->dm_final, psmd->dm_deformed, psys);
- }
-
- MEM_freeN(data);
- psys->renderdata = NULL;
-
- /* restore particle display percentage */
- disp = psys_get_current_display_percentage(psys);
-
- if (disp != render_disp) {
- /* Hair can and has to be recalculated if everything isn't displayed. */
- if (ELEM(psys->part->type, PART_HAIR, PART_FLUID)) {
- psys->recalc |= PSYS_RECALC_RESET;
- }
- else {
- PARTICLE_P;
-
- LOOP_PARTICLES {
- if (psys_frand(psys, p) > disp)
- pa->flag |= PARS_NO_DISP;
- else
- pa->flag &= ~PARS_NO_DISP;
- }
+ /* Free existing particles. */
+ if (psys_dst->particles != psys_src->particles) {
+ psys_free_particles(psys_dst);
+ }
+ if (psys_dst->child != psys_src->child) {
+ psys_free_children(psys_dst);
+ }
+ /* Restore counters. */
+ psys_dst->totpart = psys_src->totpart;
+ psys_dst->totchild = psys_src->totchild;
+ /* Copy particles and children. */
+ psys_dst->particles = MEM_dupallocN(psys_src->particles);
+ psys_dst->child = MEM_dupallocN(psys_src->child);
+ if (psys_dst->part->type == PART_HAIR) {
+ ParticleData *pa;
+ int p;
+ for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
+ pa->hair = MEM_dupallocN(pa->hair);
}
}
-}
-
-bool psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float *params)
-{
- ParticleRenderData *data;
- ParticleRenderElem *elem;
- float x, w, scale, alpha, lambda, t, scalemin, scalemax;
- int b;
-
- if (!(psys->renderdata && (psys->part->simplify_flag & PART_SIMPLIFY_ENABLE)))
- return false;
-
- data = psys->renderdata;
- if (!data->do_simplify)
- return false;
- b = (data->index_mf_to_mpoly) ? DM_origindex_mface_mpoly(data->index_mf_to_mpoly, data->index_mp_to_orig, cpa->num) : cpa->num;
- if (b == ORIGINDEX_NONE) {
- return false;
- }
-
- elem = &data->elems[b];
-
- lambda = elem->lambda;
- t = elem->t;
- scalemin = elem->scalemin;
- scalemax = elem->scalemax;
-
- if (!elem->reduce) {
- scale = scalemin;
- alpha = 1.0f;
- }
- else {
- x = (elem->curchild + 0.5f) / elem->totchild;
- if (x < lambda - t) {
- scale = scalemax;
- alpha = 1.0f;
+ if (psys_dst->particles && (psys_dst->particles->keys || psys_dst->particles->boid)) {
+ ParticleKey *key = psys_dst->particles->keys;
+ BoidParticle *boid = psys_dst->particles->boid;
+ ParticleData *pa;
+ int p;
+ if (key != NULL) {
+ key = MEM_dupallocN(key);
}
- else if (x >= lambda + t) {
- scale = scalemin;
- alpha = 0.0f;
+ if (boid != NULL) {
+ boid = MEM_dupallocN(boid);
}
- else {
- w = (lambda + t - x) / (2.0f * t);
- scale = scalemin + (scalemax - scalemin) * w;
- alpha = w;
+ for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
+ if (boid != NULL) {
+ pa->boid = boid++;
+ }
+ if (key != NULL) {
+ pa->keys = key;
+ key += pa->totkey;
+ }
}
}
-
- params[0] = scale;
- params[1] = alpha;
-
- elem->curchild++;
-
- return 1;
}
/************************************************/
@@ -859,7 +748,7 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic
typedef struct ParticleInterpolationData {
HairKey *hkey[2];
- DerivedMesh *dm;
+ Mesh *mesh;
MVert *mvert[2];
int keyed;
@@ -993,8 +882,8 @@ static void init_particle_interpolation(Object *ob, ParticleSystem *psys, Partic
pind->birthtime = key->time;
pind->dietime = (key + pa->totkey - 1)->time;
- if (pind->dm) {
- pind->mvert[0] = CDDM_get_vert(pind->dm, pa->hair_index);
+ if (pind->mesh) {
+ pind->mvert[0] = &pind->mesh->mvert[pa->hair_index];
pind->mvert[1] = pind->mvert[0] + 1;
}
}
@@ -1103,7 +992,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
edit_to_particle(keys + 1, pind->ekey[0]);
edit_to_particle(keys + 2, pind->ekey[1]);
}
- else if (pind->dm) {
+ else if (pind->mesh) {
pind->mvert[0] = pind->mvert[1] - 1;
mvert_to_particle(keys + 1, pind->mvert[0], pind->hkey[0]);
mvert_to_particle(keys + 2, pind->mvert[1], pind->hkey[1]);
@@ -1128,7 +1017,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
else
edit_to_particle(keys, pind->ekey[0]);
}
- else if (pind->dm) {
+ else if (pind->mesh) {
if (pind->hkey[0] != pa->hair)
mvert_to_particle(keys, pind->mvert[0] - 1, pind->hkey[0] - 1);
else
@@ -1147,7 +1036,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
else
edit_to_particle(keys + 3, pind->ekey[1]);
}
- else if (pind->dm) {
+ else if (pind->mesh) {
if (pind->hkey[1] != pa->hair + pa->totkey - 1)
mvert_to_particle(keys + 3, pind->mvert[1] + 1, pind->hkey[1] + 1);
else
@@ -1216,7 +1105,7 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
/* interpolate a location on a face based on face coordinates */
void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*orcodata)[3],
float w[4], float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
float *v1 = 0, *v2 = 0, *v3 = 0, *v4 = 0;
float e1[3], e2[3], s1, s2, t1, t2;
@@ -1314,21 +1203,13 @@ void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*or
o4 = orcodata[mface->v4];
interp_v3_v3v3v3v3(orco, o1, o2, o3, o4, w);
-
- if (ornor)
- normal_quad_v3(ornor, o1, o2, o3, o4);
}
else {
interp_v3_v3v3v3(orco, o1, o2, o3, w);
-
- if (ornor)
- normal_tri_v3(ornor, o1, o2, o3);
}
}
else {
copy_v3_v3(orco, vec);
- if (ornor && nor)
- copy_v3_v3(ornor, nor);
}
}
}
@@ -1381,7 +1262,7 @@ void psys_interpolate_mcol(const MCol *mcol, int quad, const float w[4], MCol *m
}
}
-static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, const float fw[4], const float *values)
+static float psys_interpolate_value_from_verts(Mesh *mesh, short from, int index, const float fw[4], const float *values)
{
if (values == 0 || index == -1)
return 0.0;
@@ -1392,7 +1273,7 @@ static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int
case PART_FROM_FACE:
case PART_FROM_VOLUME:
{
- MFace *mf = dm->getTessFaceData(dm, index, CD_MFACE);
+ MFace *mf = &mesh->mface[index];
return interpolate_particle_value(values[mf->v1], values[mf->v2], values[mf->v3], values[mf->v4], fw, mf->v4);
}
@@ -1442,7 +1323,7 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
* \return the DM tessface index.
*/
int psys_particle_dm_face_lookup(
- DerivedMesh *dm_final, DerivedMesh *dm_deformed,
+ Mesh *mesh_final, Mesh *mesh_original,
int findex_orig, const float fw[4], struct LinkNode **poly_nodes)
{
MFace *mtessface_final;
@@ -1454,36 +1335,36 @@ int psys_particle_dm_face_lookup(
const int *index_mf_to_mpoly = NULL;
const int *index_mp_to_orig = NULL;
- const int totface_final = dm_final->getNumTessFaces(dm_final);
- const int totface_deformed = dm_deformed ? dm_deformed->getNumTessFaces(dm_deformed) : totface_final;
+ const int totface_final = mesh_final->totface;
+ const int totface_deformed = mesh_original ? mesh_original->totface : totface_final;
if (ELEM(0, totface_final, totface_deformed)) {
return DMCACHE_NOTFOUND;
}
- index_mf_to_mpoly = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX);
- index_mp_to_orig = dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX);
+ index_mf_to_mpoly = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
+ index_mp_to_orig = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
BLI_assert(index_mf_to_mpoly);
- if (dm_deformed) {
- index_mf_to_mpoly_deformed = dm_deformed->getTessFaceDataArray(dm_deformed, CD_ORIGINDEX);
+ if (mesh_original) {
+ index_mf_to_mpoly_deformed = CustomData_get_layer(&mesh_original->fdata, CD_ORIGINDEX);
}
else {
- BLI_assert(dm_final->deformedOnly);
+ BLI_assert(mesh_final->runtime.deformed_only);
index_mf_to_mpoly_deformed = index_mf_to_mpoly;
}
BLI_assert(index_mf_to_mpoly_deformed);
pindex_orig = index_mf_to_mpoly_deformed[findex_orig];
- if (dm_deformed == NULL) {
- dm_deformed = dm_final;
+ if (mesh_original == NULL) {
+ mesh_original = mesh_final;
}
index_mf_to_mpoly_deformed = NULL;
- mtessface_final = dm_final->getTessFaceArray(dm_final);
- osface_final = dm_final->getTessFaceDataArray(dm_final, CD_ORIGSPACE);
+ mtessface_final = mesh_final->mface;
+ osface_final = CustomData_get_layer(&mesh_final->fdata, CD_ORIGSPACE);
if (osface_final == NULL) {
/* Assume we don't need osface_final data, and we get a direct 1-1 mapping... */
@@ -1496,7 +1377,7 @@ int psys_particle_dm_face_lookup(
return DMCACHE_NOTFOUND;
}
}
- else if (findex_orig >= dm_deformed->getNumTessFaces(dm_deformed)) {
+ else if (findex_orig >= mesh_original->totface) {
return DMCACHE_NOTFOUND; /* index not in the original mesh */
}
@@ -1525,7 +1406,7 @@ int psys_particle_dm_face_lookup(
else { /* if we have no node, try every face */
for (int findex_dst = 0; findex_dst < totface_final; findex_dst++) {
/* If current tessface from 'final' DM and orig tessface (given by index) map to the same orig poly... */
- if (DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) {
+ if (BKE_mesh_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) {
faceuv = osface_final[findex_dst].uv;
/* check that this intersects - Its possible this misses :/ -
@@ -1545,22 +1426,22 @@ int psys_particle_dm_face_lookup(
return DMCACHE_NOTFOUND;
}
-static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache, const float fw[4], float UNUSED(foffset), int *mapindex, float mapfw[4])
+static int psys_map_index_on_dm(Mesh *mesh, int from, int index, int index_dmcache, const float fw[4], float UNUSED(foffset), int *mapindex, float mapfw[4])
{
if (index < 0)
return 0;
- if (dm->deformedOnly || index_dmcache == DMCACHE_ISCHILD) {
+ if (mesh->runtime.deformed_only || index_dmcache == DMCACHE_ISCHILD) {
/* for meshes that are either only deformed or for child particles, the
* index and fw do not require any mapping, so we can directly use it */
if (from == PART_FROM_VERT) {
- if (index >= dm->getNumVerts(dm))
+ if (index >= mesh->totvert)
return 0;
*mapindex = index;
}
else { /* FROM_FACE/FROM_VOLUME */
- if (index >= dm->getNumTessFaces(dm))
+ if (index >= mesh->totface)
return 0;
*mapindex = index;
@@ -1572,7 +1453,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
* to their new location, which means a different index, and for faces
* also a new face interpolation weights */
if (from == PART_FROM_VERT) {
- if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > dm->getNumVerts(dm))
+ if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > mesh->totvert)
return 0;
*mapindex = index_dmcache;
@@ -1585,15 +1466,15 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
i = index_dmcache;
- if (i == DMCACHE_NOTFOUND || i >= dm->getNumTessFaces(dm))
+ if (i == DMCACHE_NOTFOUND || i >= mesh->totface)
return 0;
*mapindex = i;
/* modify the original weights to become
* weights for the derived mesh face */
- osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
- mface = dm->getTessFaceData(dm, i, CD_MFACE);
+ osface = CustomData_get_layer(&mesh->fdata, CD_ORIGSPACE);
+ mface = &mesh->mface[i];
if (osface == NULL)
mapfw[0] = mapfw[1] = mapfw[2] = mapfw[3] = 0.0f;
@@ -1606,32 +1487,31 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
}
/* interprets particle data to get a point on a mesh in object space */
-void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_dmcache,
+void psys_particle_on_dm(Mesh *mesh_final, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
float tmpnor[3], mapfw[4];
float (*orcodata)[3];
int mapindex;
- if (!psys_map_index_on_dm(dm_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
+ if (!psys_map_index_on_dm(mesh_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
if (vec) { vec[0] = vec[1] = vec[2] = 0.0; }
if (nor) { nor[0] = nor[1] = 0.0; nor[2] = 1.0; }
if (orco) { orco[0] = orco[1] = orco[2] = 0.0; }
- if (ornor) { ornor[0] = ornor[1] = 0.0; ornor[2] = 1.0; }
if (utan) { utan[0] = utan[1] = utan[2] = 0.0; }
if (vtan) { vtan[0] = vtan[1] = vtan[2] = 0.0; }
return;
}
- orcodata = dm_final->getVertDataArray(dm_final, CD_ORCO);
+ orcodata = CustomData_get_layer(&mesh_final->vdata, CD_ORCO);
if (from == PART_FROM_VERT) {
- dm_final->getVertCo(dm_final, mapindex, vec);
+ copy_v3_v3(vec, mesh_final->mvert[mapindex].co);
if (nor) {
- dm_final->getVertNo(dm_final, mapindex, nor);
+ normal_short_to_float_v3(nor, mesh_final->mvert[mapindex].no);
normalize_v3(nor);
}
@@ -1644,11 +1524,6 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d
}
}
- if (ornor) {
- dm_final->getVertNo(dm_final, mapindex, ornor);
- normalize_v3(ornor);
- }
-
if (utan && vtan) {
utan[0] = utan[1] = utan[2] = 0.0f;
vtan[0] = vtan[1] = vtan[2] = 0.0f;
@@ -1659,15 +1534,15 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d
MTFace *mtface;
MVert *mvert;
- mface = dm_final->getTessFaceData(dm_final, mapindex, CD_MFACE);
- mvert = dm_final->getVertDataArray(dm_final, CD_MVERT);
- mtface = CustomData_get_layer(&dm_final->faceData, CD_MTFACE);
+ mface = &mesh_final->mface[mapindex];
+ mvert = mesh_final->mvert;
+ mtface = mesh_final->mtface;
if (mtface)
mtface += mapindex;
if (from == PART_FROM_VOLUME) {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco, ornor);
+ psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
if (nor)
copy_v3_v3(nor, tmpnor);
@@ -1676,19 +1551,19 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d
add_v3_v3(vec, tmpnor);
}
else
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco, ornor);
+ psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
}
}
-float psys_particle_value_from_verts(DerivedMesh *dm, short from, ParticleData *pa, float *values)
+float psys_particle_value_from_verts(Mesh *mesh, short from, ParticleData *pa, float *values)
{
float mapfw[4];
int mapindex;
- if (!psys_map_index_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
+ if (!psys_map_index_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
return 0.0f;
- return psys_interpolate_value_from_verts(dm, from, mapindex, mapfw, values);
+ return psys_interpolate_value_from_verts(mesh, from, mapindex, mapfw, values);
}
ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
@@ -1712,7 +1587,7 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
/* ready for future use */
static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index),
float *UNUSED(fuv), float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
/* TODO */
float zerovec[3] = {0.0f, 0.0f, 0.0f};
@@ -1731,9 +1606,6 @@ static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index),
if (orco) {
copy_v3_v3(orco, zerovec);
}
- if (ornor) {
- copy_v3_v3(ornor, zerovec);
- }
}
/************************************************/
/* Particles on emitter */
@@ -1776,9 +1648,9 @@ CustomDataMask psys_emitter_customdata_mask(ParticleSystem *psys)
void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int index, int index_dmcache,
float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
- if (psmd && psmd->dm_final) {
+ if (psmd && psmd->mesh_final) {
if (psmd->psys->part->distr == PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT) {
if (vec)
copy_v3_v3(vec, fuv);
@@ -1788,10 +1660,10 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
return;
}
/* we cant use the num_dmcache */
- psys_particle_on_dm(psmd->dm_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco, ornor);
+ psys_particle_on_dm(psmd->mesh_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco);
}
else
- psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco, ornor);
+ psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco);
}
/************************************************/
@@ -1813,7 +1685,7 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
return;
LOOP_PARTICLES {
- psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0, 0);
+ psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0);
mul_m4_v3(sim->ob->obmat, state.co);
mul_mat3_m4_v3(sim->ob->obmat, state.vel);
@@ -1839,7 +1711,7 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
}
}
-int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time)
+int do_guides(Depsgraph *depsgraph, ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time)
{
CurveMapping *clumpcurve = (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) ? part->clumpcurve : NULL;
CurveMapping *roughcurve = (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) ? part->roughcurve : NULL;
@@ -1902,7 +1774,7 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i
/* curve taper */
if (cu->taperobj)
- mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
+ mul_v3_fl(vec_to_point, BKE_displist_calc_taper(depsgraph, eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
else { /* curve size*/
if (cu->flag & CU_PATH_RADIUS) {
@@ -1970,7 +1842,7 @@ static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheK
copy_qt_qt(eff_key.rot, (ca - 1)->rot);
pd_point_from_particle(sim, sim->psys->particles + i, &eff_key, &epoint);
- pdDoEffectors(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
+ BKE_effectors_apply(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
mul_v3_fl(force, effector * powf((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) / (float)steps);
@@ -2004,7 +1876,7 @@ static void offset_child(ChildParticle *cpa, ParticleKey *par, float *par_rot, P
add_v3_v3(child->co, par->co);
}
-float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
+float *psys_cache_vgroup(Mesh *mesh, ParticleSystem *psys, int vgroup)
{
float *vg = 0;
@@ -2013,9 +1885,9 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
}
else if (psys->vgroup[vgroup]) {
- MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ MDeformVert *dvert = mesh->dvert;
if (dvert) {
- int totvert = dm->getNumVerts(dm), i;
+ int totvert = mesh->totvert, i;
vg = MEM_callocN(sizeof(float) * totvert, "vg_cache");
if (psys->vg_neg & (1 << vgroup)) {
for (i = 0; i < totvert; i++)
@@ -2041,7 +1913,7 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
int from = PART_FROM_FACE;
totparent = (int)(totchild * part->parents * 0.3f);
- if ((sim->psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
+ if (use_render_params && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* hard limit, workaround for it being ignored above */
@@ -2052,10 +1924,10 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
tree = BLI_kdtree_new(totparent);
for (p = 0, cpa = sim->psys->child; p < totparent; p++, cpa++) {
- psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
/* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */
- get_cpa_texture(sim->psmd->dm_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+ get_cpa_texture(sim->psmd->mesh_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
if (ptex.exist >= psys_frand(psys, p + 24)) {
BLI_kdtree_insert(tree, p, orco);
@@ -2065,7 +1937,7 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
BLI_kdtree_balance(tree);
for (; p < totchild; p++, cpa++) {
- psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
cpa->parent = BLI_kdtree_find_nearest(tree, orco, NULL);
}
@@ -2085,10 +1957,10 @@ static bool psys_thread_context_init_path(
psys_thread_context_init(ctx, sim);
/*---start figuring out what is actually wanted---*/
- if (psys_in_edit_mode(scene, psys)) {
+ if (psys_in_edit_mode(sim->depsgraph, psys)) {
ParticleEditSettings *pset = &scene->toolsettings->particle;
- if ((psys->renderdata == 0 && use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if ((use_render_params == 0) && (psys_orig_edit_get(psys) == NULL || pset->flag & PE_DRAW_PART) == 0)
totchild = 0;
segments = 1 << pset->draw_step;
@@ -2097,14 +1969,14 @@ static bool psys_thread_context_init_path(
if (totchild && part->childtype == PART_CHILD_FACES) {
totparent = (int)(totchild * part->parents * 0.3f);
- if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
+ if (use_render_params && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* part->parents could still be 0 so we can't test with totparent */
between = 1;
}
- if (psys->renderdata || use_render_params)
+ if (use_render_params)
segments = 1 << part->ren_step;
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
@@ -2130,15 +2002,15 @@ static bool psys_thread_context_init_path(
psys->lattice_deform_data = psys_create_lattice_deform_data(&ctx->sim);
/* cache all relevant vertex groups if they exist */
- ctx->vg_length = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_LENGTH);
- ctx->vg_clump = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_CLUMP);
- ctx->vg_kink = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_KINK);
- ctx->vg_rough1 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH1);
- ctx->vg_rough2 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH2);
- ctx->vg_roughe = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGHE);
- ctx->vg_twist = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_TWIST);
+ ctx->vg_length = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_LENGTH);
+ ctx->vg_clump = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_CLUMP);
+ ctx->vg_kink = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_KINK);
+ ctx->vg_rough1 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH1);
+ ctx->vg_rough2 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH2);
+ ctx->vg_roughe = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGHE);
+ ctx->vg_twist = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_TWIST);
if (psys->part->flag & PART_CHILD_EFFECT)
- ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR);
+ ctx->vg_effector = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_EFFECTOR);
/* prepare curvemapping tables */
if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) {
@@ -2182,11 +2054,12 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
ParticleSystem *psys = ctx->sim.psys;
ParticleSettings *part = psys->part;
ParticleCacheKey **cache = psys->childcache;
- ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.scene, psys) && psys->edit ? psys->edit->pathcache : psys->pathcache;
+ PTCacheEdit *edit = psys_orig_edit_get(psys);
+ ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.depsgraph, psys) && edit ? edit->pathcache : psys->pathcache;
ParticleCacheKey *child, *key[4];
ParticleTexture ptex;
float *cpa_fuv = 0, *par_rot = 0, rot[4];
- float orco[3], ornor[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
+ float orco[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
float eff_length, eff_vec[3], weight[4];
int k, cpa_num;
short cpa_from;
@@ -2208,7 +2081,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
needupdate = 0;
w = 0;
while (w < 4 && cpa->pa[w] >= 0) {
- if (psys->edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) {
+ if (edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) {
needupdate = 1;
break;
}
@@ -2282,20 +2155,20 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
- psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, ornor, 0, 0, orco, 0);
+ psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
mul_m4_v3(ob->obmat, co);
for (w = 0; w < 4; w++)
sub_v3_v3v3(off1[w], co, key[w]->co);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
}
else {
ParticleData *pa = psys->particles + cpa->parent;
float co[3];
if (ctx->editupdate) {
- if (!(psys->edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
+ if (!(edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
return;
memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
@@ -2320,13 +2193,13 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
: pa->num_dmcache;
/* XXX hack to avoid messed up particle num and subsequent crash (#40733) */
- if (cpa_num > ctx->sim.psmd->dm_final->getNumTessFaces(ctx->sim.psmd->dm_final))
+ if (cpa_num > ctx->sim.psmd->mesh_final->totface)
cpa_num = 0;
cpa_fuv = pa->fuv;
- psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, ornor, 0, 0, orco, 0);
+ psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
}
child_keys->segments = ctx->segments;
@@ -2432,9 +2305,9 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
BLI_listbase_clear(&modifiers);
psys_particle_on_emitter(ctx->sim.psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset,
- par_co, NULL, NULL, NULL, par_orco, NULL);
+ par_co, NULL, NULL, NULL, par_orco);
- psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par, par_orco);
+ psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, hairmat, child_keys, par, par_orco);
}
else
zero_v3(par_orco);
@@ -2576,7 +2449,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
ParticleSettings *part = psys->part;
ParticleCacheKey *ca, **cache;
- DerivedMesh *hair_dm = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_dm : NULL;
+ Mesh *hair_mesh = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_mesh : NULL;
ParticleKey result;
@@ -2592,7 +2465,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
- int segments = (int)pow(2.0, (double)((psys->renderdata || use_render_params) ? part->ren_step : part->draw_step));
+ int segments = (int)pow(2.0, (double)((use_render_params) ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float length, vec[3];
float *vg_effector = NULL;
@@ -2603,8 +2476,8 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if ((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache) == 0)
return;
- if (psys_in_edit_mode(sim->scene, psys))
- if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if (psys_in_edit_mode(sim->depsgraph, psys))
+ if ((psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
return;
keyed = psys->flag & PSYS_KEYED;
@@ -2621,15 +2494,15 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if ((psys->flag & PSYS_GLOBAL_HAIR) == 0) {
if ((psys->part->flag & PART_CHILD_EFFECT) == 0)
- vg_effector = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_EFFECTOR);
+ vg_effector = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_EFFECTOR);
if (!psys->totchild)
- vg_length = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_LENGTH);
+ vg_length = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_LENGTH);
}
/* ensure we have tessfaces to be used for mapping */
if (part->from != PART_FROM_VERT) {
- DM_ensure_tessface(psmd->dm_final);
+ BKE_mesh_tessface_ensure(psmd->mesh_final);
}
/*---first main loop: create all actual particles' paths---*/
@@ -2638,14 +2511,14 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f);
pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p));
if (vg_length)
- pa_length *= psys_particle_value_from_verts(psmd->dm_final, part->from, pa, vg_length);
+ pa_length *= psys_particle_value_from_verts(psmd->mesh_final, part->from, pa, vg_length);
}
pind.keyed = keyed;
pind.cache = baked ? psys->pointcache : NULL;
pind.epoint = NULL;
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
- pind.dm = hair_dm;
+ pind.mesh = hair_mesh;
memset(cache[p], 0, sizeof(*cache[p]) * (segments + 1));
@@ -2655,7 +2528,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
init_particle_interpolation(sim->ob, sim->psys, pa, &pind);
/* hairmat is needed for for non-hair particle too so we get proper rotations */
- psys_mat_hair_to_global(sim->ob, psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, psmd->mesh_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -2687,7 +2560,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
/* dynamic hair is in object space */
/* keyed and baked are already in global space */
- if (hair_dm)
+ if (hair_mesh)
mul_m4_v3(sim->ob->obmat, ca->co);
else if (!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR))
mul_m4_v3(hairmat, ca->co);
@@ -2710,7 +2583,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if ((psys->part->flag & PART_CHILD_EFFECT) == 0) {
float effector = 1.0f;
if (vg_effector)
- effector *= psys_particle_value_from_verts(psmd->dm_final, psys->part->from, pa, vg_effector);
+ effector *= psys_particle_value_from_verts(psmd->mesh_final, psys->part->from, pa, vg_effector);
sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co);
length = len_v3(vec);
@@ -2723,7 +2596,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if (sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT) == 0) {
for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
/* ca is safe to cast, since only co and vel are used */
- do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments);
+ do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments);
}
/* lattices have to be calculated separately to avoid mixups between effector calculations */
@@ -2771,219 +2644,255 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if (vg_length)
MEM_freeN(vg_length);
}
-void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
-{
- ParticleCacheKey *ca, **cache = edit->pathcache;
- ParticleEditSettings *pset = &scene->toolsettings->particle;
- PTCacheEditPoint *point = NULL;
- PTCacheEditKey *ekey = NULL;
-
- ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleData *pa = psys ? psys->particles : NULL;
-
- ParticleInterpolationData pind;
- ParticleKey result;
-
- float birthtime = 0.0f, dietime = 0.0f;
- float t, time = 0.0f, keytime = 0.0f /*, frs_sec */;
- float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
- int k, i;
- int segments = 1 << pset->draw_step;
- int totpart = edit->totpoint, recalc_set = 0;
+typedef struct CacheEditrPathsIterData {
+ Object *object;
+ PTCacheEdit *edit;
+ ParticleSystemModifierData *psmd;
+ ParticleData *pa;
+ int segments;
+ bool use_weight;
float sel_col[3];
float nosel_col[3];
+} CacheEditrPathsIterData;
- segments = MAX2(segments, 4);
-
- if (!cache || edit->totpoint != edit->totcached) {
- /* clear out old and create new empty path cache */
- psys_free_path_cache(edit->psys, edit);
- cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
-
- /* set flag for update (child particles check this too) */
- for (i = 0, point = edit->points; i < totpart; i++, point++)
- point->flag |= PEP_EDIT_RECALC;
- recalc_set = 1;
+static void psys_cache_edit_paths_iter(
+ void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ CacheEditrPathsIterData *iter_data = (CacheEditrPathsIterData *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if (edit->totcached && !(point->flag & PEP_EDIT_RECALC)) {
+ return;
}
+ if (point->totkey == 0) {
+ return;
+ }
+ Object *ob = iter_data->object;
+ ParticleSystem *psys = edit->psys;
+ ParticleCacheKey **cache = edit->pathcache;
+ ParticleSystemModifierData *psmd = iter_data->psmd;
+ ParticleData *pa = iter_data->pa ? iter_data->pa + iter : NULL;
+ PTCacheEditKey *ekey = point->keys;
+ const int segments = iter_data->segments;
+ const bool use_weight = iter_data->use_weight;
- /* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */
+ float birthtime = 0.0f, dietime = 0.0f;
+ float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
- const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
+ ParticleInterpolationData pind;
+ pind.keyed = 0;
+ pind.cache = NULL;
+ pind.epoint = point;
+ pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0;
+ pind.mesh = NULL;
+ /* should init_particle_interpolation set this ? */
if (use_weight) {
- ; /* use weight painting colors now... */
- }
- else {
- sel_col[0] = (float)edit->sel_col[0] / 255.0f;
- sel_col[1] = (float)edit->sel_col[1] / 255.0f;
- sel_col[2] = (float)edit->sel_col[2] / 255.0f;
- nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
- nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
- nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
+ pind.hkey[0] = NULL;
+ /* pa != NULL since the weight brush is only available for hair */
+ pind.hkey[0] = pa->hair;
+ pind.hkey[1] = pa->hair + 1;
}
- /*---first main loop: create all actual particles' paths---*/
- for (i = 0, point = edit->points; i < totpart; i++, pa += pa ? 1 : 0, point++) {
- if (edit->totcached && !(point->flag & PEP_EDIT_RECALC))
- continue;
+ memset(cache[iter], 0, sizeof(*cache[iter]) * (segments + 1));
- if (point->totkey == 0)
- continue;
+ cache[iter]->segments = segments;
- ekey = point->keys;
+ /*--get the first data points--*/
+ init_particle_interpolation(ob, psys, pa, &pind);
- pind.keyed = 0;
- pind.cache = NULL;
- pind.epoint = point;
- pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0;
- pind.dm = NULL;
+ if (psys) {
+ psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat);
+ copy_v3_v3(rotmat[0], hairmat[2]);
+ copy_v3_v3(rotmat[1], hairmat[1]);
+ copy_v3_v3(rotmat[2], hairmat[0]);
+ }
+ birthtime = pind.birthtime;
+ dietime = pind.dietime;
- /* should init_particle_interpolation set this ? */
- if (use_weight) {
- pind.hkey[0] = NULL;
- /* pa != NULL since the weight brush is only available for hair */
- pind.hkey[0] = pa->hair;
- pind.hkey[1] = pa->hair + 1;
- }
+ if (birthtime >= dietime) {
+ cache[iter]->segments = -1;
+ return;
+ }
+ /*--interpolate actual path from data points--*/
+ ParticleCacheKey *ca;
+ int k;
+ float t, time = 0.0f, keytime = 0.0f;
+ for (k = 0, ca = cache[iter]; k <= segments; k++, ca++) {
+ time = (float)k / (float)segments;
+ t = birthtime + time * (dietime - birthtime);
+ ParticleKey result;
+ result.time = -t;
+ do_particle_interpolation(psys, iter, pa, t, &pind, &result);
+ copy_v3_v3(ca->co, result.co);
+
+ /* non-hair points are already in global space */
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ mul_m4_v3(hairmat, ca->co);
- memset(cache[i], 0, sizeof(*cache[i]) * (segments + 1));
+ if (k) {
+ cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
- cache[i]->segments = segments;
+ if (k == segments)
+ copy_qt_qt(ca->rot, (ca - 1)->rot);
- /*--get the first data points--*/
- init_particle_interpolation(ob, psys, pa, &pind);
+ /* set velocity */
+ sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
- if (psys) {
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
- copy_v3_v3(rotmat[0], hairmat[2]);
- copy_v3_v3(rotmat[1], hairmat[1]);
- copy_v3_v3(rotmat[2], hairmat[0]);
+ if (k == 1)
+ copy_v3_v3((ca - 1)->vel, ca->vel);
+ }
}
-
- birthtime = pind.birthtime;
- dietime = pind.dietime;
-
- if (birthtime >= dietime) {
- cache[i]->segments = -1;
- continue;
+ else {
+ ca->vel[0] = ca->vel[1] = 0.0f;
+ ca->vel[2] = 1.0f;
}
- /*--interpolate actual path from data points--*/
- for (k = 0, ca = cache[i]; k <= segments; k++, ca++) {
- time = (float)k / (float)segments;
- t = birthtime + time * (dietime - birthtime);
- result.time = -t;
- do_particle_interpolation(psys, i, pa, t, &pind, &result);
- copy_v3_v3(ca->co, result.co);
-
- /* non-hair points are already in global space */
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- mul_m4_v3(hairmat, ca->co);
-
- if (k) {
- cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
-
- if (k == segments)
- copy_qt_qt(ca->rot, (ca - 1)->rot);
-
- /* set velocity */
- sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
-
- if (k == 1)
- copy_v3_v3((ca - 1)->vel, ca->vel);
- }
+ /* selection coloring in edit mode */
+ if (use_weight) {
+ if (k == 0) {
+ weight_to_rgb(ca->col, pind.hkey[1]->weight);
}
else {
- ca->vel[0] = ca->vel[1] = 0.0f;
- ca->vel[2] = 1.0f;
- }
-
- /* selection coloring in edit mode */
- if (use_weight) {
- if (k == 0) {
- weight_to_rgb(ca->col, pind.hkey[1]->weight);
+ /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
+ float real_t;
+ if (result.time < 0.0f) {
+ real_t = -result.time;
}
else {
- /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
- float real_t;
- if (result.time < 0.0f) {
- real_t = -result.time;
- }
- else {
- real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time);
- }
+ real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time);
+ }
- while (pind.hkey[1]->time < real_t) {
- pind.hkey[1]++;
- }
- pind.hkey[0] = pind.hkey[1] - 1;
- /* end copy */
+ while (pind.hkey[1]->time < real_t) {
+ pind.hkey[1]++;
+ }
+ pind.hkey[0] = pind.hkey[1] - 1;
+ /* end copy */
- float w1[3], w2[3];
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ float w1[3], w2[3];
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- weight_to_rgb(w1, pind.hkey[0]->weight);
- weight_to_rgb(w2, pind.hkey[1]->weight);
+ weight_to_rgb(w1, pind.hkey[0]->weight);
+ weight_to_rgb(w2, pind.hkey[1]->weight);
- interp_v3_v3v3(ca->col, w1, w2, keytime);
+ interp_v3_v3v3(ca->col, w1, w2, keytime);
+ }
+ }
+ else {
+ if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
+ if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
+ copy_v3_v3(ca->col, iter_data->sel_col);
+ }
+ else {
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ interp_v3_v3v3(ca->col, iter_data->sel_col, iter_data->nosel_col, keytime);
}
}
else {
- if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
- if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
- copy_v3_v3(ca->col, sel_col);
- }
- else {
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, sel_col, nosel_col, keytime);
- }
+ if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ interp_v3_v3v3(ca->col, iter_data->nosel_col, iter_data->sel_col, keytime);
}
else {
- if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, nosel_col, sel_col, keytime);
- }
- else {
- copy_v3_v3(ca->col, nosel_col);
- }
+ copy_v3_v3(ca->col, iter_data->nosel_col);
}
}
-
- ca->time = t;
}
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- /* First rotation is based on emitting face orientation.
- * This is way better than having flipping rotations resulting
- * from using a global axis as a rotation pole (vec_to_quat()).
- * It's not an ideal solution though since it disregards the
- * initial tangent, but taking that in to account will allow
- * the possibility of flipping again. -jahka
- */
- mat3_to_quat_is_ok(cache[i]->rot, rotmat);
+
+ ca->time = t;
+ }
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ /* First rotation is based on emitting face orientation.
+ * This is way better than having flipping rotations resulting
+ * from using a global axis as a rotation pole (vec_to_quat()).
+ * It's not an ideal solution though since it disregards the
+ * initial tangent, but taking that in to account will allow
+ * the possibility of flipping again. -jahka
+ */
+ mat3_to_quat_is_ok(cache[iter]->rot, rotmat);
+ }
+}
+
+void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
+{
+ ParticleCacheKey **cache = edit->pathcache;
+ ParticleEditSettings *pset = &scene->toolsettings->particle;
+
+ ParticleSystem *psys = edit->psys;
+
+ ParticleData *pa = psys ? psys->particles : NULL;
+
+ int segments = 1 << pset->draw_step;
+ int totpart = edit->totpoint, recalc_set = 0;
+
+ segments = MAX2(segments, 4);
+
+ if (!cache || edit->totpoint != edit->totcached) {
+ /* Clear out old and create new empty path cache. */
+ psys_free_path_cache(edit->psys, edit);
+ cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
+ /* Set flag for update (child particles check this too). */
+ int i;
+ PTCacheEditPoint *point;
+ for (i = 0, point = edit->points; i < totpart; i++, point++) {
+ point->flag |= PEP_EDIT_RECALC;
}
+ recalc_set = 1;
+ }
+
+ const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
+
+ CacheEditrPathsIterData iter_data;
+ iter_data.object = ob;
+ iter_data.edit = edit;
+ iter_data.psmd = edit->psmd_eval;
+ iter_data.pa = pa;
+ iter_data.segments = segments;
+ iter_data.use_weight = use_weight;
+
+ if (use_weight) {
+ ; /* use weight painting colors now... */
+ }
+ else {
+ iter_data.sel_col[0] = (float)edit->sel_col[0] / 255.0f;
+ iter_data.sel_col[1] = (float)edit->sel_col[1] / 255.0f;
+ iter_data.sel_col[2] = (float)edit->sel_col[2] / 255.0f;
+ iter_data.nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
+ iter_data.nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
+ iter_data.nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
}
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings);
+
edit->totcached = totpart;
if (psys) {
ParticleSimulationData sim = {0};
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
- sim.psmd = psys_get_modifier(ob, psys);
+ sim.psmd = edit->psmd_eval;
psys_cache_child_paths(&sim, cfra, true, use_render_params);
}
/* clear recalc flag if set here */
if (recalc_set) {
- for (i = 0, point = edit->points; i < totpart; i++, point++)
+ PTCacheEditPoint *point;
+ int i;
+ for (i = 0, point = edit->points; i < totpart; i++, point++) {
point->flag &= ~PEP_EDIT_RECALC;
+ }
}
}
/************************************************/
@@ -3065,7 +2974,7 @@ static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat
cross_v3_v3v3(mat[0], mat[1], mat[2]);
}
-static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float mat[4][4], int orco)
+static void psys_face_mat(Object *ob, Mesh *mesh, ParticleData *pa, float mat[4][4], int orco)
{
float v[3][3];
MFace *mface;
@@ -3073,72 +2982,72 @@ static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float m
float (*orcodata)[3];
int i = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? pa->num : pa->num_dmcache;
- if (i == -1 || i >= dm->getNumTessFaces(dm)) { unit_m4(mat); return; }
+ if (i == -1 || i >= mesh->totface) { unit_m4(mat); return; }
- mface = dm->getTessFaceData(dm, i, CD_MFACE);
- osface = dm->getTessFaceData(dm, i, CD_ORIGSPACE);
+ mface = &mesh->mface[i];
+ osface = CustomData_get(&mesh->fdata, i, CD_ORIGSPACE);
- if (orco && (orcodata = dm->getVertDataArray(dm, CD_ORCO))) {
+ if (orco && (orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO))) {
copy_v3_v3(v[0], orcodata[mface->v1]);
copy_v3_v3(v[1], orcodata[mface->v2]);
copy_v3_v3(v[2], orcodata[mface->v3]);
/* ugly hack to use non-transformed orcos, since only those
* give symmetric results for mirroring in particle mode */
- if (DM_get_vert_data_layer(dm, CD_ORIGINDEX))
+ if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
BKE_mesh_orco_verts_transform(ob->data, v, 3, 1);
}
else {
- dm->getVertCo(dm, mface->v1, v[0]);
- dm->getVertCo(dm, mface->v2, v[1]);
- dm->getVertCo(dm, mface->v3, v[2]);
+ copy_v3_v3(v[0], mesh->mvert[mface->v1].co);
+ copy_v3_v3(v[1], mesh->mvert[mface->v2].co);
+ copy_v3_v3(v[2], mesh->mvert[mface->v3].co);
}
triatomat(v[0], v[1], v[2], (osface) ? osface->uv : NULL, mat);
}
-void psys_mat_hair_to_object(Object *UNUSED(ob), DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_object(Object *UNUSED(ob), Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
float vec[3];
/* can happen when called from a different object's modifier */
- if (!dm) {
+ if (!mesh) {
unit_m4(hairmat);
return;
}
- psys_face_mat(0, dm, pa, hairmat, 0);
- psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0, 0);
+ psys_face_mat(0, mesh, pa, hairmat, 0);
+ psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0);
copy_v3_v3(hairmat[3], vec);
}
-void psys_mat_hair_to_orco(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_orco(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
float vec[3], orco[3];
- psys_face_mat(ob, dm, pa, hairmat, 1);
- psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco, 0);
+ psys_face_mat(ob, mesh, pa, hairmat, 1);
+ psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco);
/* see psys_face_mat for why this function is called */
- if (DM_get_vert_data_layer(dm, CD_ORIGINDEX))
+ if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1);
copy_v3_v3(hairmat[3], orco);
}
-void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float vec[3])
+void psys_vec_rot_to_face(Mesh *mesh, ParticleData *pa, float vec[3])
{
float mat[4][4];
- psys_face_mat(0, dm, pa, mat, 0);
+ psys_face_mat(0, mesh, pa, mat, 0);
transpose_m4(mat); /* cheap inverse for rotation matrix */
mul_mat3_m4_v3(mat, vec);
}
-void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_global(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
float facemat[4][4];
- psys_mat_hair_to_object(ob, dm, from, pa, facemat);
+ psys_mat_hair_to_object(ob, mesh, from, pa, facemat);
mul_m4_m4m4(hairmat, ob->obmat, facemat);
}
@@ -3186,8 +3095,8 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob,
psys->flag = PSYS_CURRENT;
psys->cfra = BKE_scene_frame_get_from_ctime(scene, CFRA + 1);
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
return md;
}
@@ -3232,8 +3141,11 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
else
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
static void default_particle_settings(ParticleSettings *part)
@@ -3296,7 +3208,7 @@ static void default_particle_settings(ParticleSettings *part)
part->clength = 1.0f;
part->clength_thres = 0.0f;
- part->draw = PART_DRAW_EMITTER;
+ part->draw = 0;
part->draw_line[0] = 0.5;
part->path_start = 0.0f;
part->path_end = 1.0f;
@@ -3308,16 +3220,18 @@ static void default_particle_settings(ParticleSettings *part)
part->color_vec_max = 1.f;
part->draw_col = PART_DRAW_COL_MAT;
- part->simplify_refsize = 1920;
- part->simplify_rate = 1.0f;
- part->simplify_transition = 0.1f;
- part->simplify_viewport = 0.8;
-
if (!part->effector_weights)
part->effector_weights = BKE_add_effector_weights(NULL);
part->omat = 1;
part->use_modifier_stack = false;
+ part->draw_size = 0.1f;
+
+ part->shape_flag = PART_SHAPE_CLOSE_TIP;
+ part->shape = 0.0f;
+ part->rad_root = 1.0f;
+ part->rad_tip = 0.0f;
+ part->rad_scale = 0.01f;
}
@@ -3421,25 +3335,25 @@ void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const
/* Textures */
/************************************************/
-static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const float fuv[4],
+static int get_particle_uv(Mesh *mesh, ParticleData *pa, int index, const float fuv[4],
char *name, float *texco, bool from_vert)
{
MFace *mf;
MTFace *tf;
int i;
- tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, name);
+ tf = CustomData_get_layer_named(&mesh->fdata, CD_MTFACE, name);
if (tf == NULL)
- tf = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+ tf = mesh->mtface;
if (tf == NULL)
return 0;
if (pa) {
i = ELEM(pa->num_dmcache, DMCACHE_NOTFOUND, DMCACHE_ISCHILD) ? pa->num : pa->num_dmcache;
- if ((!from_vert && i >= dm->getNumTessFaces(dm)) ||
- (from_vert && i >= dm->getNumVerts(dm)))
+ if ((!from_vert && i >= mesh->totface) ||
+ (from_vert && i >= mesh->totvert))
{
i = -1;
}
@@ -3455,12 +3369,12 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f
}
else {
if (from_vert) {
- mf = dm->getTessFaceDataArray(dm, CD_MFACE);
+ mf = mesh->mface;
/* This finds the first face to contain the emitting vertex,
* this is not ideal, but is mostly fine as UV seams generally
* map to equal-colored parts of a texture */
- for (int j = 0; j < dm->getNumTessFaces(dm); j++, mf++) {
+ for (int j = 0; j < mesh->totface; j++, mf++) {
if (ELEM(i, mf->v1, mf->v2, mf->v3, mf->v4)) {
i = j;
break;
@@ -3468,7 +3382,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f
}
}
else {
- mf = dm->getTessFaceData(dm, i, CD_MFACE);
+ mf = &mesh->mface[i];
}
psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
@@ -3503,7 +3417,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f
CLAMP(pvalue, -1.0f, 1.0f); \
} (void)0
-static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra)
+static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra)
{
MTex *mtex, **mtexp = part->mtex;
int m;
@@ -3537,7 +3451,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (fw && get_particle_uv(dm, NULL, face_index, fw, mtex->uvname,
+ if (fw && get_particle_uv(mesh, NULL, face_index, fw, mtex->uvname,
texvec, (part->from == PART_FROM_VERT)))
{
break;
@@ -3615,7 +3529,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (get_particle_uv(sim->psmd->dm_final, pa, 0, pa->fuv, mtex->uvname,
+ if (get_particle_uv(sim->psmd->mesh_final, pa, 0, pa->fuv, mtex->uvname,
texvec, (part->from == PART_FROM_VERT)))
{
break;
@@ -3623,7 +3537,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
/* no break, failed to get uv's, so let's try orco's */
ATTR_FALLTHROUGH;
case TEXCO_ORCO:
- psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec, 0);
+ psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec);
if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
BKE_mesh_texspace_calc(me);
@@ -3745,28 +3659,28 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
ParticleSystem *psys = ctx->sim.psys;
int i = cpa - psys->child;
- get_cpa_texture(ctx->dm, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+ get_cpa_texture(ctx->mesh, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
if (ptex->exist < psys_frand(psys, i + 24))
return;
if (ctx->vg_length)
- ptex->length *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_length);
+ ptex->length *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_length);
if (ctx->vg_clump)
- ptex->clump *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump);
+ ptex->clump *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump);
if (ctx->vg_kink)
- ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
+ ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
if (ctx->vg_rough1)
- ptex->rough1 *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1);
+ ptex->rough1 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1);
if (ctx->vg_rough2)
- ptex->rough2 *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2);
+ ptex->rough2 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2);
if (ctx->vg_roughe)
- ptex->roughe *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe);
+ ptex->roughe *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe);
if (ctx->vg_effector)
- ptex->effector *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
+ ptex->effector *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
if (ctx->vg_twist)
- ptex->twist *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
+ ptex->twist *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
}
/* get's hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, const bool vel)
@@ -3819,22 +3733,22 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
/* pind.dm disabled in editmode means we don't get effectors taken into
* account when subdividing for instance */
- pind.dm = psys_in_edit_mode(sim->scene, psys) ? NULL : psys->hair_out_dm;
+ pind.mesh = psys_in_edit_mode(sim->depsgraph, psys) ? NULL : psys->hair_out_mesh; /* XXX Sybren EEK */
init_particle_interpolation(sim->ob, psys, pa, &pind);
do_particle_interpolation(psys, p, pa, t, &pind, state);
- if (pind.dm) {
+ if (pind.mesh) {
mul_m4_v3(sim->ob->obmat, state->co);
mul_mat3_m4_v3(sim->ob->obmat, state->vel);
}
else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) {
if ((pa->flag & PARS_REKEY) == 0) {
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, part->from, pa, hairmat);
mul_m4_v3(hairmat, state->co);
mul_mat3_m4_v3(hairmat, state->vel);
if (sim->psys->effectors && (part->flag & PART_CHILD_GUIDE) == 0) {
- do_guides(sim->psys->part, sim->psys->effectors, state, p, state->time);
+ do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, state, p, state->time);
/* TODO: proper velocity handling */
}
@@ -3885,7 +3799,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
- psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
/* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
//copy_v3_v3(cpa_1st, co);
@@ -3894,9 +3808,9 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
pa = psys->particles + cpa->parent;
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco);
if (part->type == PART_HAIR)
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
else
unit_m4(hairmat);
@@ -3914,10 +3828,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
cpa_num = pa->num;
cpa_fuv = pa->fuv;
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco);
if (part->type == PART_HAIR) {
- psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco, 0);
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
}
else {
copy_v3_v3(orco, cpa->fuv);
@@ -3936,7 +3850,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
/* get different child parameters from textures & vgroups */
memset(&ctx, 0, sizeof(ParticleThreadContext));
ctx.sim = *sim;
- ctx.dm = psmd->dm_final;
+ ctx.mesh = psmd->mesh_final;
ctx.ma = ma;
/* TODO: assign vertex groups */
get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
@@ -4020,7 +3934,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
float timestep = psys_get_timestep(sim);
/* negative time means "use current time" */
- cfra = state->time > 0 ? state->time : BKE_scene_frame_get(sim->scene);
+ cfra = state->time > 0 ? state->time : DEG_get_ctime(sim->depsgraph);
if (p >= totpart) {
if (!psys->totchild)
@@ -4190,18 +4104,18 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
bool is_grid = (part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT);
if (cpa) {
- if ((part->childtype == PART_CHILD_FACES) && (psmd->dm_final != NULL)) {
- CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
+ if ((part->childtype == PART_CHILD_FACES) && (psmd->mesh_final != NULL)) {
+ CustomData *mtf_data = &psmd->mesh_final->fdata;
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
if (mtface && !is_grid) {
- mface = psmd->dm_final->getTessFaceData(psmd->dm_final, cpa->num, CD_MFACE);
+ mface = CustomData_get(&psmd->mesh_final->fdata, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
}
- psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco);
return;
}
else {
@@ -4209,8 +4123,8 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
}
}
- if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL) && !is_grid) {
- CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
+ if ((part->from == PART_FROM_FACE) && (psmd->mesh_final != NULL) && !is_grid) {
+ CustomData *mtf_data = &psmd->mesh_final->fdata;
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
@@ -4219,20 +4133,20 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
if (num == DMCACHE_NOTFOUND)
num = pa->num;
- if (num >= psmd->dm_final->getNumTessFaces(psmd->dm_final)) {
+ if (num >= psmd->mesh_final->totface) {
/* happens when simplify is enabled
* gives invalid coords but would crash otherwise */
num = DMCACHE_NOTFOUND;
}
if (mtface && !ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
+ mface = CustomData_get(&psmd->mesh_final->fdata, num, CD_MFACE);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
}
}
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco);
}
void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[4][4], float *scale)
@@ -4250,9 +4164,9 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa
pa = psys->particles + cpa->pa[0];
if (pa)
- psys_particle_on_emitter(psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0, 0);
+ psys_particle_on_emitter(psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0);
else
- psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, nor, 0, 0, 0, 0);
+ psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, nor, 0, 0, 0);
if (psys->part->rotmode == PART_ROT_VEL) {
transpose_m3_m4(nmat, ob->imat);
@@ -4384,9 +4298,10 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
madd_v3_v3fl(center, yvec, bb->offset[1]);
}
-void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
+void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys)
{
ParticleSimulationData sim = {0};
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
@@ -4401,7 +4316,7 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
float hairmat[4][4], imat[4][4];
for (p = 0; p < psys->totpart; p++, pa++) {
- psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
hkey = pa->hair;
@@ -4419,3 +4334,22 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag |= PSYS_EDITED;
}
}
+
+
+
+/* Draw Engine */
+void (*BKE_particle_batch_cache_dirty_cb)(ParticleSystem *psys, int mode) = NULL;
+void (*BKE_particle_batch_cache_free_cb)(ParticleSystem *psys) = NULL;
+
+void BKE_particle_batch_cache_dirty(ParticleSystem *psys, int mode)
+{
+ if (psys->batch_cache) {
+ BKE_particle_batch_cache_dirty_cb(psys, mode);
+ }
+}
+void BKE_particle_batch_cache_free(ParticleSystem *psys)
+{
+ if (psys->batch_cache) {
+ BKE_particle_batch_cache_free_cb(psys);
+ }
+}
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index c921e1ea107..7cfad93224d 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -39,40 +39,6 @@
#include "particle_private.h"
-struct Material;
-
-static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3])
-{
- float cross[3], nstrand[3], vnor[3], blend;
-
- if (!((ma->mode & MA_STR_SURFDIFF) || (ma->strand_surfnor > 0.0f)))
- return;
-
- if (ma->mode & MA_STR_SURFDIFF) {
- cross_v3_v3v3(cross, surfnor, nor);
- cross_v3_v3v3(nstrand, nor, cross);
-
- blend = dot_v3v3(nstrand, surfnor);
- CLAMP(blend, 0.0f, 1.0f);
-
- interp_v3_v3v3(vnor, nstrand, surfnor, blend);
- normalize_v3(vnor);
- }
- else {
- copy_v3_v3(vnor, nor);
- }
-
- if (ma->strand_surfnor > 0.0f) {
- if (ma->strand_surfnor > surfdist) {
- blend = (ma->strand_surfnor - surfdist) / ma->strand_surfnor;
- interp_v3_v3v3(vnor, vnor, surfnor, blend);
- normalize_v3(vnor);
- }
- }
-
- copy_v3_v3(nor, vnor);
-}
-
/* ------------------------------------------------------------------------- */
typedef struct ParticlePathIterator {
@@ -320,7 +286,7 @@ static bool check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *k
}
void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *modifiers,
- ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
+ ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], float hairmat[4][4],
ParticleCacheKey *keys, ParticleCacheKey *parent_keys, const float parent_orco[3])
{
struct ParticleSettings *part = ctx->sim.psys->part;
@@ -389,9 +355,6 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
if (k >= 2) {
sub_v3_v3v3((key-1)->vel, key->co, (key-2)->co);
mul_v3_fl((key-1)->vel, 0.5);
-
- if (ma && draw_col_ma)
- get_strand_normal(ma, ornor, cur_length, (key-1)->vel);
}
if (use_length_check && k > 0) {
@@ -413,7 +376,6 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
if (ma && draw_col_ma) {
copy_v3_v3(key->col, &ma->r);
- get_strand_normal(ma, ornor, cur_length, key->vel);
}
}
}
@@ -816,7 +778,7 @@ void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
if (part->flag & PART_CHILD_EFFECT)
/* state is safe to cast, since only co and vel are used */
- guided = do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
+ guided = do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
if (guided == 0) {
float orco_offset[3];
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 8a3b1312590..2e056aa7a3f 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -50,14 +50,13 @@
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
-static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot);
+#include "DEG_depsgraph_query.h"
static void alloc_child_particles(ParticleSystem *psys, int tot)
{
@@ -80,12 +79,13 @@ static void alloc_child_particles(ParticleSystem *psys, int tot)
}
}
-static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, DerivedMesh *deformdm, ParticleSystem *psys)
+static void distribute_simple_children(Scene *scene, Object *ob, Mesh *final_mesh, Mesh *deform_mesh, ParticleSystem *psys, const bool use_render_params)
{
ChildParticle *cpa = NULL;
int i, p;
- int child_nbr= psys_get_child_number(scene, psys);
- int totpart= psys_get_tot_child(scene, psys);
+ int child_nbr= psys_get_child_number(scene, psys, use_render_params);
+ int totpart= psys_get_tot_child(scene, psys, use_render_params);
+ RNG *rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
alloc_child_particles(psys, totpart);
@@ -97,9 +97,9 @@ static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *fi
/* create even spherical distribution inside unit sphere */
while (length>=1.0f) {
- cpa->fuv[0]=2.0f*BLI_frand()-1.0f;
- cpa->fuv[1]=2.0f*BLI_frand()-1.0f;
- cpa->fuv[2]=2.0f*BLI_frand()-1.0f;
+ cpa->fuv[0]=2.0f*BLI_rng_get_float(rng)-1.0f;
+ cpa->fuv[1]=2.0f*BLI_rng_get_float(rng)-1.0f;
+ cpa->fuv[2]=2.0f*BLI_rng_get_float(rng)-1.0f;
length=len_v3(cpa->fuv);
}
@@ -107,14 +107,16 @@ static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *fi
}
}
/* dmcache must be updated for parent particles if children from faces is used */
- psys_calc_dmcache(ob, finaldm, deformdm, psys);
+ psys_calc_dmcache(ob, final_mesh, deform_mesh, psys);
+
+ BLI_rng_free(rng);
}
-static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
+static void distribute_grid(Mesh *mesh, ParticleSystem *psys)
{
ParticleData *pa=NULL;
float min[3], max[3], delta[3], d;
- MVert *mv, *mvert = dm->getVertDataArray(dm,0);
- int totvert=dm->getNumVerts(dm), from=psys->part->from;
+ MVert *mv, *mvert = mesh->mvert;
+ int totvert=mesh->totvert, from=psys->part->from;
int i, j, k, p, res=psys->part->grid_res, size[3], axis;
/* find bounding box of dm */
@@ -196,8 +198,8 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
int a, a1, a2, a0mul, a1mul, a2mul, totface;
int amax= from==PART_FROM_FACE ? 3 : 1;
- totface=dm->getNumTessFaces(dm);
- mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);
+ totface = mesh->totface;
+ mface = mface_array = mesh->mface;
for (a=0; a<amax; a++) {
if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; }
@@ -314,19 +316,16 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
static void hammersley_create(float *out, int n, int seed, float amount)
{
RNG *rng;
- double p, t, offs[2];
- int k, kk;
+
+ double offs[2], t;
rng = BLI_rng_new(31415926 + n + seed);
offs[0] = BLI_rng_get_double(rng) + (double)amount;
offs[1] = BLI_rng_get_double(rng) + (double)amount;
BLI_rng_free(rng);
- for (k = 0; k < n; k++) {
- t = 0;
- for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1)
- if (kk & 1) /* kk mod 2 = 1 */
- t += p;
+ for (int k = 0; k < n; k++) {
+ BLI_hammersley_1D(k, &t);
out[2*k + 0] = fmod((double)k/(double)n + offs[0], 1.0);
out[2*k + 1] = fmod(t + offs[1], 1.0);
@@ -434,7 +433,7 @@ static int distribute_binary_search(float *sum, int n, float value)
/* the max number if calls to rng_* funcs within psys_thread_distribute_particle
* be sure to keep up to date if this changes */
-#define PSYS_RND_DIST_SKIP 2
+#define PSYS_RND_DIST_SKIP 3
/* note: this function must be thread safe, for from == PART_FROM_CHILD */
#define ONLY_WORKING_WITH_PA_VERTS 0
@@ -443,7 +442,7 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
ParticleThreadContext *ctx= thread->ctx;
MFace *mface;
- mface = ctx->dm->getTessFaceDataArray(ctx->dm, CD_MFACE);
+ mface = ctx->mesh->mface;
int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
@@ -452,12 +451,12 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
zero_v4(pa->fuv);
- if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->dm->getNumVerts(ctx->dm)) {
+ if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->mesh->totvert) {
/* This finds the first face to contain the emitting vertex,
* this is not ideal, but is mostly fine as UV seams generally
* map to equal-colored parts of a texture */
- for (int i = 0; i < ctx->dm->getNumTessFaces(ctx->dm); i++, mface++) {
+ for (int i = 0; i < ctx->mesh->totface; i++, mface++) {
if (ELEM(pa->num, mface->v1, mface->v2, mface->v3, mface->v4)) {
unsigned int *vert = &mface->v1;
@@ -478,7 +477,7 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
KDTreeNearest ptn[3];
int w, maxw;
- psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
+ psys_particle_on_dm(ctx->mesh,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
@@ -488,13 +487,15 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
}
#endif
- if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_assert(rng_skip_tot > 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, int p) {
ParticleThreadContext *ctx= thread->ctx;
- DerivedMesh *dm= ctx->dm;
+ Mesh *mesh = ctx->mesh;
float randu, randv;
int distr= ctx->distr;
int i;
@@ -503,7 +504,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
MFace *mface;
pa->num = i = ctx->index[p];
- mface = dm->getTessFaceData(dm,i,CD_MFACE);
+ mface = &mesh->mface[i];
switch (distr) {
case PART_DISTR_JIT:
@@ -530,13 +531,15 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
}
pa->foffset= 0.0f;
- if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_assert(rng_skip_tot > 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
ParticleThreadContext *ctx= thread->ctx;
- DerivedMesh *dm= ctx->dm;
+ Mesh *mesh = ctx->mesh;
float *v1, *v2, *v3, *v4, nor[3], co[3];
float cur_d, min_d, randu, randv;
int distr= ctx->distr;
@@ -544,10 +547,10 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
MFace *mface;
- MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
+ MVert *mvert = mesh->mvert;
pa->num = i = ctx->index[p];
- mface = dm->getTessFaceData(dm,i,CD_MFACE);
+ mface = &mesh->mface[i];
switch (distr) {
case PART_DISTR_JIT:
@@ -575,9 +578,9 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
pa->foffset= 0.0f;
/* experimental */
- tot=dm->getNumTessFaces(dm);
+ tot = mesh->totface;
- psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0);
+ psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0);
normalize_v3(nor);
negate_v3(nor);
@@ -585,7 +588,7 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
min_d=FLT_MAX;
intersect=0;
- for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
+ for (i=0, mface=mesh->mface; i<tot; i++,mface++) {
if (i==pa->num) continue;
v1=mvert[mface->v1].co;
@@ -619,19 +622,22 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)];
break;
case PART_DISTR_RAND:
- pa->foffset *= BLI_frand();
+ pa->foffset *= BLI_rng_get_float(thread->rng);
+ rng_skip_tot--;
break;
}
}
- if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_assert(rng_skip_tot > 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, int p) {
ParticleThreadContext *ctx= thread->ctx;
Object *ob= ctx->sim.ob;
- DerivedMesh *dm= ctx->dm;
+ Mesh *mesh = ctx->mesh;
float orco1[3], co1[3], nor1[3];
float randu, randv;
int cfrom= ctx->cfrom;
@@ -647,7 +653,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
return;
}
- mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);
+ mf = &mesh->mface[ctx->index[p]];
randu= BLI_rng_get_float(thread->rng);
randv= BLI_rng_get_float(thread->rng);
@@ -664,7 +670,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
int parent[10];
float pweight[10];
- psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL);
+ psys_particle_on_dm(mesh,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1);
BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
@@ -743,16 +749,10 @@ static void exec_distribute_child(TaskPool * __restrict UNUSED(pool), void *task
/* RNG skipping at the beginning */
cpa = psys->child;
for (p = 0; p < task->begin; ++p, ++cpa) {
- if (task->ctx->skip) /* simplification skip */
- BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
-
BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP);
}
for (; p < task->end; ++p, ++cpa) {
- if (task->ctx->skip) /* simplification skip */
- BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
-
distribute_children_exec(task, cpa, p);
}
}
@@ -779,11 +779,15 @@ static int distribute_compare_orig_index(const void *p1, const void *p2, void *u
return 1;
}
-static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from)
+static void distribute_invalid(ParticleSimulationData *sim, int from)
{
+ Scene *scene = sim->scene;
+ ParticleSystem *psys = sim->psys;
+ const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
+
if (from == PART_FROM_CHILD) {
ChildParticle *cpa;
- int p, totchild = psys_get_tot_child(scene, psys);
+ int p, totchild = psys_get_tot_child(scene, psys, use_render_params);
if (psys->child && totchild) {
for (p=0,cpa=psys->child; p<totchild; p++,cpa++) {
@@ -805,19 +809,18 @@ static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from)
}
}
-/* Creates a distribution of coordinates on a DerivedMesh */
-/* This is to denote functionality that does not yet work with mesh - only derived mesh */
+/* Creates a distribution of coordinates on a Mesh */
static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, ParticleSimulationData *sim, int from)
{
Scene *scene = sim->scene;
- DerivedMesh *finaldm = sim->psmd->dm_final;
+ Mesh *final_mesh = sim->psmd->mesh_final;
Object *ob = sim->ob;
ParticleSystem *psys= sim->psys;
ParticleData *pa=0, *tpars= 0;
ParticleSettings *part;
ParticleSeam *seams= 0;
KDTree *tree=0;
- DerivedMesh *dm= NULL;
+ Mesh *mesh = NULL;
float *jit= NULL;
int i, p=0;
int cfrom=0;
@@ -825,6 +828,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
int jitlevel= 1, distr;
float *element_weight=NULL,*jitter_offset=NULL, *vweight=NULL;
float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3];
+ RNG *rng = NULL;
if (ELEM(NULL, ob, psys, psys->part))
return 0;
@@ -834,7 +838,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
if (totpart==0)
return 0;
- if (!finaldm->deformedOnly && !finaldm->getTessFaceDataArray(finaldm, CD_ORIGINDEX)) {
+ if (!final_mesh->runtime.deformed_only && !CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) {
printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
// XXX error("Can't paint with the current modifier stack, disable destructive modifiers");
return 0;
@@ -847,32 +851,37 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
psys_thread_context_init(ctx, sim);
+ const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
+
/* First handle special cases */
if (from == PART_FROM_CHILD) {
/* Simple children */
if (part->childtype != PART_CHILD_FACES) {
- BLI_srandom(31415926 + psys->seed + psys->child_seed);
- distribute_simple_children(scene, ob, finaldm, sim->psmd->dm_deformed, psys);
+ distribute_simple_children(scene, ob, final_mesh, sim->psmd->mesh_original, psys, use_render_params);
return 0;
}
}
else {
/* Grid distribution */
if (part->distr==PART_DISTR_GRID && from != PART_FROM_VERT) {
- BLI_srandom(31415926 + psys->seed);
-
if (psys->part->use_modifier_stack) {
- dm = finaldm;
+ mesh = final_mesh;
}
else {
- dm = CDDM_from_mesh((Mesh*)ob->data);
+ BKE_id_copy_ex(
+ NULL, ob->data, (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
}
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
- distribute_grid(dm,psys);
+ distribute_grid(mesh,psys);
- if (dm != finaldm) {
- dm->release(dm);
+ if (mesh != final_mesh) {
+ BKE_id_free(NULL, mesh);
}
return 0;
@@ -881,47 +890,54 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
/* Create trees and original coordinates if needed */
if (from == PART_FROM_CHILD) {
- distr=PART_DISTR_RAND;
- BLI_srandom(31415926 + psys->seed + psys->child_seed);
- dm= finaldm;
+ distr = PART_DISTR_RAND;
+ rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
+ mesh= final_mesh;
/* BMESH ONLY */
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
children=1;
tree=BLI_kdtree_new(totpart);
for (p=0,pa=psys->particles; p<totpart; p++,pa++) {
- psys_particle_on_dm(dm,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco,NULL);
+ psys_particle_on_dm(mesh,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco);
BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco, 1, 1);
BLI_kdtree_insert(tree, p, orco);
}
BLI_kdtree_balance(tree);
- totpart = psys_get_tot_child(scene, psys);
+ totpart = psys_get_tot_child(scene, psys, use_render_params);
cfrom = from = PART_FROM_FACE;
}
else {
distr = part->distr;
- BLI_srandom(31415926 + psys->seed);
+
+ rng = BLI_rng_new_srandom(31415926 + psys->seed);
if (psys->part->use_modifier_stack)
- dm = finaldm;
+ mesh = final_mesh;
else
- dm= CDDM_from_mesh((Mesh*)ob->data);
+ BKE_id_copy_ex(
+ NULL, ob->data, (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
/* we need orco for consistent distributions */
- if (!CustomData_has_layer(&dm->vertData, CD_ORCO))
- DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob));
+ if (!CustomData_has_layer(&mesh->vdata, CD_ORCO))
+ CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert);
if (from == PART_FROM_VERT) {
- MVert *mv= dm->getVertDataArray(dm, CD_MVERT);
- float (*orcodata)[3] = dm->getVertDataArray(dm, CD_ORCO);
- int totvert = dm->getNumVerts(dm);
+ MVert *mv = mesh->mvert;
+ float (*orcodata)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO);
+ int totvert = mesh->totvert;
tree=BLI_kdtree_new(totvert);
@@ -940,17 +956,18 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
/* Get total number of emission elements and allocate needed arrays */
- totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm);
+ totelem = (from == PART_FROM_VERT) ? mesh->totvert : mesh->totface;
if (totelem == 0) {
- distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0);
+ distribute_invalid(sim, children ? PART_FROM_CHILD : 0);
if (G.debug & G_DEBUG)
fprintf(stderr,"Particle distribution error: Nothing to emit from!\n");
- if (dm != finaldm) dm->release(dm);
+ if (mesh != final_mesh) BKE_id_free(NULL, mesh);
BLI_kdtree_free(tree);
+ BLI_rng_free(rng);
return 0;
}
@@ -965,10 +982,10 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
float totarea=0.f, co1[3], co2[3], co3[3], co4[3];
float (*orcodata)[3];
- orcodata= dm->getVertDataArray(dm, CD_ORCO);
+ orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
for (i=0; i<totelem; i++) {
- MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
+ MFace *mf = &mesh->mface[i];
if (orcodata) {
copy_v3_v3(co1, orcodata[mf->v1]);
@@ -983,14 +1000,14 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
}
else {
- v1= (MVert*)dm->getVertData(dm,mf->v1,CD_MVERT);
- v2= (MVert*)dm->getVertData(dm,mf->v2,CD_MVERT);
- v3= (MVert*)dm->getVertData(dm,mf->v3,CD_MVERT);
+ v1 = &mesh->mvert[mf->v1];
+ v2 = &mesh->mvert[mf->v2];
+ v3 = &mesh->mvert[mf->v3];
copy_v3_v3(co1, v1->co);
copy_v3_v3(co2, v2->co);
copy_v3_v3(co3, v3->co);
if (mf->v4) {
- v4= (MVert*)dm->getVertData(dm,mf->v4,CD_MVERT);
+ v4 = &mesh->mvert[mf->v4];
copy_v3_v3(co4, v4->co);
}
}
@@ -1017,7 +1034,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
/* Calculate weights from vgroup */
- vweight = psys_cache_vgroup(dm,psys,PSYS_VG_DENSITY);
+ vweight = psys_cache_vgroup(mesh,psys,PSYS_VG_DENSITY);
if (vweight) {
if (from==PART_FROM_VERT) {
@@ -1026,7 +1043,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
else { /* PART_FROM_FACE / PART_FROM_VOLUME */
for (i=0;i<totelem; i++) {
- MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
+ MFace *mf = &mesh->mface[i];
tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
if (mf->v4) {
@@ -1087,11 +1104,11 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
totmapped = i_mapped;
/* Finally assign elements to particles */
- if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) {
+ if (part->flag & PART_TRAND) {
for (p = 0; p < totpart; p++) {
/* In theory element_sum[totmapped - 1] should be 1.0,
* but due to float errors this is not necessarily always true, so scale pos accordingly. */
- const float pos = BLI_frand() * element_sum[totmapped - 1];
+ const float pos = BLI_rng_get_float(rng) * element_sum[totmapped - 1];
const int eidx = distribute_binary_search(element_sum, totmapped, pos);
particle_element[p] = element_map[eidx];
BLI_assert(pos <= element_sum[eidx]);
@@ -1129,12 +1146,12 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
int *orig_index = NULL;
if (from == PART_FROM_VERT) {
- if (dm->numVertData)
- orig_index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ if (mesh->totvert)
+ orig_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
}
else {
- if (dm->numTessFaceData)
- orig_index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ if (mesh->totface)
+ orig_index = CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX);
}
if (orig_index) {
@@ -1177,14 +1194,15 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
ctx->maxweight= maxweight;
ctx->cfrom= cfrom;
ctx->distr= distr;
- ctx->dm= dm;
+ ctx->mesh= mesh;
ctx->tpars= tpars;
if (children) {
- totpart= psys_render_simplify_distribution(ctx, totpart);
alloc_child_particles(psys, totpart);
}
+ BLI_rng_free(rng);
+
return 1;
}
@@ -1202,7 +1220,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
TaskPool *task_pool;
ParticleThreadContext ctx;
ParticleTask *tasks;
- DerivedMesh *finaldm = sim->psmd->dm_final;
+ Mesh *final_mesh = sim->psmd->mesh_final;
int i, totpart, numtasks;
/* create a task pool for distribution tasks */
@@ -1227,10 +1245,10 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
BLI_task_pool_free(task_pool);
- psys_calc_dmcache(sim->ob, finaldm, sim->psmd->dm_deformed, sim->psys);
+ psys_calc_dmcache(sim->ob, final_mesh, sim->psmd->mesh_original, sim->psys);
- if (ctx.dm != finaldm)
- ctx.dm->release(ctx.dm);
+ if (ctx.mesh != final_mesh)
+ BKE_id_free(NULL, ctx.mesh);
psys_tasks_free(tasks, numtasks);
@@ -1240,7 +1258,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
/* ready for future use, to emit particles without geometry */
static void distribute_particles_on_shape(ParticleSimulationData *sim, int UNUSED(from))
{
- distribute_invalid(sim->scene, sim->psys, 0);
+ distribute_invalid(sim, 0);
fprintf(stderr,"Shape emission not yet possible!\n");
}
@@ -1251,7 +1269,7 @@ void distribute_particles(ParticleSimulationData *sim, int from)
int distr_error=0;
if (psmd) {
- if (psmd->dm_final)
+ if (psmd->mesh_final)
distribute_particles_on_dm(sim, from);
else
distr_error=1;
@@ -1260,250 +1278,8 @@ void distribute_particles(ParticleSimulationData *sim, int from)
distribute_particles_on_shape(sim, from);
if (distr_error) {
- distribute_invalid(sim->scene, sim->psys, from);
+ distribute_invalid(sim, from);
fprintf(stderr,"Particle distribution error!\n");
}
}
-
-/* ======== Simplify ======== */
-
-static float psys_render_viewport_falloff(double rate, float dist, float width)
-{
- return pow(rate, dist / width);
-}
-
-static float psys_render_projected_area(ParticleSystem *psys, const float center[3], float area, double vprate, float *viewport)
-{
- ParticleRenderData *data = psys->renderdata;
- float co[4], view[3], ortho1[3], ortho2[3], w, dx, dy, radius;
-
- /* transform to view space */
- copy_v3_v3(co, center);
- co[3] = 1.0f;
- mul_m4_v4(data->viewmat, co);
-
- /* compute two vectors orthogonal to view vector */
- normalize_v3_v3(view, co);
- ortho_basis_v3v3_v3(ortho1, ortho2, view);
-
- /* compute on screen minification */
- w = co[2] * data->winmat[2][3] + data->winmat[3][3];
- dx = data->winx * ortho2[0] * data->winmat[0][0];
- dy = data->winy * ortho2[1] * data->winmat[1][1];
- w = sqrtf(dx * dx + dy * dy) / w;
-
- /* w squared because we are working with area */
- area = area * w * w;
-
- /* viewport of the screen test */
-
- /* project point on screen */
- mul_m4_v4(data->winmat, co);
- if (co[3] != 0.0f) {
- co[0] = 0.5f * data->winx * (1.0f + co[0] / co[3]);
- co[1] = 0.5f * data->winy * (1.0f + co[1] / co[3]);
- }
-
- /* screen space radius */
- radius = sqrtf(area / (float)M_PI);
-
- /* make smaller using fallof once over screen edge */
- *viewport = 1.0f;
-
- if (co[0] + radius < 0.0f)
- *viewport *= psys_render_viewport_falloff(vprate, -(co[0] + radius), data->winx);
- else if (co[0] - radius > data->winx)
- *viewport *= psys_render_viewport_falloff(vprate, (co[0] - radius) - data->winx, data->winx);
-
- if (co[1] + radius < 0.0f)
- *viewport *= psys_render_viewport_falloff(vprate, -(co[1] + radius), data->winy);
- else if (co[1] - radius > data->winy)
- *viewport *= psys_render_viewport_falloff(vprate, (co[1] - radius) - data->winy, data->winy);
-
- return area;
-}
-
-/* BMESH_TODO, for orig face data, we need to use MPoly */
-static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
-{
- DerivedMesh *dm = ctx->dm;
- Mesh *me = (Mesh *)(ctx->sim.ob->data);
- MFace *mf, *mface;
- MVert *mvert;
- ParticleRenderData *data;
- ParticleRenderElem *elems, *elem;
- ParticleSettings *part = ctx->sim.psys->part;
- float *facearea, (*facecenter)[3], size[3], fac, powrate, scaleclamp;
- float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport;
- double vprate;
- int *facetotvert;
- int a, b, totorigface, totface, newtot, skipped;
-
- /* double lookup */
- const int *index_mf_to_mpoly;
- const int *index_mp_to_orig;
-
- if (part->ren_as != PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND))
- return tot;
- if (!ctx->sim.psys->renderdata)
- return tot;
-
- data = ctx->sim.psys->renderdata;
- if (data->timeoffset)
- return 0;
- if (!(part->simplify_flag & PART_SIMPLIFY_ENABLE))
- return tot;
-
- mvert = dm->getVertArray(dm);
- mface = dm->getTessFaceArray(dm);
- totface = dm->getNumTessFaces(dm);
- totorigface = me->totpoly;
-
- if (totface == 0 || totorigface == 0)
- return tot;
-
- index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
-
- facearea = MEM_callocN(sizeof(float) * totorigface, "SimplifyFaceArea");
- facecenter = MEM_callocN(sizeof(float[3]) * totorigface, "SimplifyFaceCenter");
- facetotvert = MEM_callocN(sizeof(int) * totorigface, "SimplifyFaceArea");
- elems = MEM_callocN(sizeof(ParticleRenderElem) * totorigface, "SimplifyFaceElem");
-
- if (data->elems)
- MEM_freeN(data->elems);
-
- data->do_simplify = true;
- data->elems = elems;
- data->index_mf_to_mpoly = index_mf_to_mpoly;
- data->index_mp_to_orig = index_mp_to_orig;
-
- /* compute number of children per original face */
- for (a = 0; a < tot; a++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
- if (b != ORIGINDEX_NONE) {
- elems[b].totchild++;
- }
- }
-
- /* compute areas and centers of original faces */
- for (mf = mface, a = 0; a < totface; a++, mf++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
-
- if (b != ORIGINDEX_NONE) {
- copy_v3_v3(co1, mvert[mf->v1].co);
- copy_v3_v3(co2, mvert[mf->v2].co);
- copy_v3_v3(co3, mvert[mf->v3].co);
-
- add_v3_v3(facecenter[b], co1);
- add_v3_v3(facecenter[b], co2);
- add_v3_v3(facecenter[b], co3);
-
- if (mf->v4) {
- copy_v3_v3(co4, mvert[mf->v4].co);
- add_v3_v3(facecenter[b], co4);
- facearea[b] += area_quad_v3(co1, co2, co3, co4);
- facetotvert[b] += 4;
- }
- else {
- facearea[b] += area_tri_v3(co1, co2, co3);
- facetotvert[b] += 3;
- }
- }
- }
-
- for (a = 0; a < totorigface; a++)
- if (facetotvert[a] > 0)
- mul_v3_fl(facecenter[a], 1.0f / facetotvert[a]);
-
- /* for conversion from BU area / pixel area to reference screen size */
- BKE_mesh_texspace_get(me, 0, 0, size);
- fac = ((size[0] + size[1] + size[2]) / 3.0f) / part->simplify_refsize;
- fac = fac * fac;
-
- powrate = log(0.5f) / log(part->simplify_rate * 0.5f);
- if (part->simplify_flag & PART_SIMPLIFY_VIEWPORT)
- vprate = pow(1.0f - part->simplify_viewport, 5.0);
- else
- vprate = 1.0;
-
- /* set simplification parameters per original face */
- for (a = 0, elem = elems; a < totorigface; a++, elem++) {
- area = psys_render_projected_area(ctx->sim.psys, facecenter[a], facearea[a], vprate, &viewport);
- arearatio = fac * area / facearea[a];
-
- if ((arearatio < 1.0f || viewport < 1.0f) && elem->totchild) {
- /* lambda is percentage of elements to keep */
- lambda = (arearatio < 1.0f) ? powf(arearatio, powrate) : 1.0f;
- lambda *= viewport;
-
- lambda = MAX2(lambda, 1.0f / elem->totchild);
-
- /* compute transition region */
- t = part->simplify_transition;
- elem->t = (lambda - t < 0.0f) ? lambda : (lambda + t > 1.0f) ? 1.0f - lambda : t;
- elem->reduce = 1;
-
- /* scale at end and beginning of the transition region */
- elem->scalemax = (lambda + t < 1.0f) ? 1.0f / lambda : 1.0f / (1.0f - elem->t * elem->t / t);
- elem->scalemin = (lambda + t < 1.0f) ? 0.0f : elem->scalemax * (1.0f - elem->t / t);
-
- elem->scalemin = sqrtf(elem->scalemin);
- elem->scalemax = sqrtf(elem->scalemax);
-
- /* clamp scaling */
- scaleclamp = (float)min_ii(elem->totchild, 10);
- elem->scalemin = MIN2(scaleclamp, elem->scalemin);
- elem->scalemax = MIN2(scaleclamp, elem->scalemax);
-
- /* extend lambda to include transition */
- lambda = lambda + elem->t;
- if (lambda > 1.0f)
- lambda = 1.0f;
- }
- else {
- lambda = arearatio;
-
- elem->scalemax = 1.0f; //sqrt(lambda);
- elem->scalemin = 1.0f; //sqrt(lambda);
- elem->reduce = 0;
- }
-
- elem->lambda = lambda;
- elem->scalemin = sqrtf(elem->scalemin);
- elem->scalemax = sqrtf(elem->scalemax);
- elem->curchild = 0;
- }
-
- MEM_freeN(facearea);
- MEM_freeN(facecenter);
- MEM_freeN(facetotvert);
-
- /* move indices and set random number skipping */
- ctx->skip = MEM_callocN(sizeof(int) * tot, "SimplificationSkip");
-
- skipped = 0;
- for (a = 0, newtot = 0; a < tot; a++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
-
- if (b != ORIGINDEX_NONE) {
- if (elems[b].curchild++ < ceil(elems[b].lambda * elems[b].totchild)) {
- ctx->index[newtot] = ctx->index[a];
- ctx->skip[newtot] = skipped;
- skipped = 0;
- newtot++;
- }
- else skipped++;
- }
- else skipped++;
- }
-
- for (a = 0, elem = elems; a < totorigface; a++, elem++)
- elem->curchild = 0;
-
- return newtot;
-}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index fd63285ea85..d6a29531482 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -74,10 +74,13 @@
#include "BKE_collision.h"
#include "BKE_colortools.h"
#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_main.h"
#include "BKE_particle.h"
+#include "BKE_collection.h"
#include "BKE_DerivedMesh.h"
#include "BKE_object.h"
#include "BKE_material.h"
@@ -88,12 +91,14 @@
#include "BKE_modifier.h"
#include "BKE_scene.h"
#include "BKE_bvhutils.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "PIL_time.h"
#include "RE_shader_ext.h"
-#include "DEG_depsgraph.h"
/* fluid sim particle import */
#ifdef WITH_MOD_FLUID
@@ -121,11 +126,11 @@ static int particles_are_dynamic(ParticleSystem *psys)
return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID);
}
-float psys_get_current_display_percentage(ParticleSystem *psys)
+float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_render_params)
{
ParticleSettings *part=psys->part;
- if ((psys->renderdata && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
+ if ((use_render_params && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
(part->child_nbr && part->childtype) || /* display percentage applies to children */
(psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */
{
@@ -285,31 +290,31 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
}
}
-int psys_get_child_number(Scene *scene, ParticleSystem *psys)
+int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params)
{
int nbr;
if (!psys->part->childtype)
return 0;
- if (psys->renderdata)
+ if (use_render_params)
nbr= psys->part->ren_child_nbr;
else
nbr= psys->part->child_nbr;
- return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL);
+ return get_render_child_particle_number(&scene->r, nbr, use_render_params);
}
-int psys_get_tot_child(Scene *scene, ParticleSystem *psys)
+int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params)
{
- return psys->totpart*psys_get_child_number(scene, psys);
+ return psys->totpart*psys_get_child_number(scene, psys, use_render_params);
}
/************************************************/
/* Distribution */
/************************************************/
-void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deformed, ParticleSystem *psys)
+void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, ParticleSystem *psys)
{
/* use for building derived mesh mapping info:
*
@@ -322,13 +327,13 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
PARTICLE_P;
/* CACHE LOCATIONS */
- if (!dm_final->deformedOnly) {
+ if (!mesh_final->runtime.deformed_only) {
/* Will use later to speed up subsurf/derivedmesh */
LinkNode *node, *nodedmelem, **nodearray;
int totdmelem, totelem, i, *origindex, *origindex_poly = NULL;
if (psys->part->from == PART_FROM_VERT) {
- totdmelem= dm_final->getNumVerts(dm_final);
+ totdmelem = mesh_final->totvert;
if (use_modifier_stack) {
totelem= totdmelem;
@@ -336,11 +341,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
}
else {
totelem= me->totvert;
- origindex= dm_final->getVertDataArray(dm_final, CD_ORIGINDEX);
+ origindex = CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX);
}
}
else { /* FROM_FACE/FROM_VOLUME */
- totdmelem= dm_final->getNumTessFaces(dm_final);
+ totdmelem= mesh_final->totface;
if (use_modifier_stack) {
totelem= totdmelem;
@@ -348,11 +353,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
origindex_poly= NULL;
}
else {
- totelem = dm_deformed->getNumTessFaces(dm_deformed);
- origindex = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX);
+ totelem = mesh_original->totface;
+ origindex = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
/* for face lookups we need the poly origindex too */
- origindex_poly= dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX);
+ origindex_poly = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
if (origindex_poly == NULL) {
origindex= NULL;
}
@@ -412,7 +417,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
pa->num_dmcache = DMCACHE_NOTFOUND;
}
else { /* FROM_FACE/FROM_VOLUME */
- pa->num_dmcache = psys_particle_dm_face_lookup(dm_final, dm_deformed, pa->num, pa->fuv, nodearray);
+ pa->num_dmcache = psys_particle_dm_face_lookup(mesh_final, mesh_original, pa->num, pa->fuv, nodearray);
}
}
}
@@ -436,7 +441,7 @@ void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData
{
memset(ctx, 0, sizeof(ParticleThreadContext));
ctx->sim = *sim;
- ctx->dm = ctx->sim.psmd->dm_final;
+ ctx->mesh = ctx->sim.psmd->mesh_final;
ctx->ma = give_current_material(sim->ob, sim->psys->part->omat);
}
@@ -511,7 +516,6 @@ void psys_thread_context_free(ParticleThreadContext *ctx)
if (ctx->jitoff) MEM_freeN(ctx->jitoff);
if (ctx->weight) MEM_freeN(ctx->weight);
if (ctx->index) MEM_freeN(ctx->index);
- if (ctx->skip) MEM_freeN(ctx->skip);
if (ctx->seams) MEM_freeN(ctx->seams);
//if (ctx->vertpart) MEM_freeN(ctx->vertpart);
BLI_kdtree_free(ctx->tree);
@@ -702,9 +706,9 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic
/* get birth location from object */
if (use_tangents)
- psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0,0);
+ psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0);
else
- psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0,0);
+ psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0);
/* get possible textural influence */
psys_get_texture(sim, pa, &ptex, PAMAP_IVEL, cfra);
@@ -988,14 +992,14 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic
}
/* recursively evaluate emitter parent anim at cfra */
-static void evaluate_emitter_anim(Scene *scene, Object *ob, float cfra)
+static void evaluate_emitter_anim(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra)
{
if (ob->parent)
- evaluate_emitter_anim(scene, ob->parent, cfra);
+ evaluate_emitter_anim(depsgraph, scene, ob->parent, cfra);
/* we have to force RECALC_ANIM here since where_is_objec_time only does drivers */
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM);
- BKE_object_where_is_calc_time(scene, ob, cfra);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
}
/* sets particle to the emitter surface with initial velocity & rotation */
@@ -1009,7 +1013,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
/* get precise emitter matrix if particle is born */
if (part->type != PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
- evaluate_emitter_anim(sim->scene, sim->ob, pa->time);
+ evaluate_emitter_anim(sim->depsgraph, sim->scene, sim->ob, pa->time);
psys->flag |= PSYS_OB_ANIM_RESTORE;
}
@@ -1143,7 +1147,8 @@ static void set_keyed_keys(ParticleSimulationData *sim)
int totpart = psys->totpart, k, totkeys = psys->totkeyed;
int keyed_flag = 0;
- ksim.scene= sim->scene;
+ ksim.depsgraph = sim->depsgraph;
+ ksim.scene = sim->scene;
/* no proper targets so let's clear and bail out */
if (psys->totkeyed==0) {
@@ -1303,9 +1308,10 @@ void psys_update_particle_tree(ParticleSystem *psys, float cfra)
static void psys_update_effectors(ParticleSimulationData *sim)
{
- pdEndEffectors(&sim->psys->effectors);
- sim->psys->effectors = pdInitEffectors(sim->scene, sim->ob, sim->psys,
- sim->psys->part->effector_weights, true);
+ BKE_effectors_free(sim->psys->effectors);
+ sim->psys->effectors = BKE_effectors_create(sim->depsgraph,
+ sim->scene, sim->ob, sim->psys,
+ sim->psys->part->effector_weights);
precalc_guides(sim, sim->psys->effectors);
}
@@ -2057,11 +2063,12 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo
ParticleSettings *part = sim->psys->part;
ParticleData *pa = efdata->pa;
EffectedPoint epoint;
+ RNG *rng = sim->rng;
/* add effectors */
pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint);
if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR)
- pdDoEffectors(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
+ BKE_effectors_apply(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
mul_v3_fl(force, efdata->ptex.field);
mul_v3_fl(impulse, efdata->ptex.field);
@@ -2072,9 +2079,9 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo
/* brownian force */
if (part->brownfac != 0.0f) {
- force[0] += (BLI_frand()-0.5f) * part->brownfac;
- force[1] += (BLI_frand()-0.5f) * part->brownfac;
- force[2] += (BLI_frand()-0.5f) * part->brownfac;
+ force[0] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
+ force[1] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
+ force[2] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
}
if (part->flag & PART_ROT_DYN && epoint.ave)
@@ -2125,7 +2132,7 @@ static void basic_integrate(ParticleSimulationData *sim, int p, float dfra, floa
tkey.time=pa->state.time;
if (part->type != PART_HAIR) {
- if (do_guides(sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
+ if (do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
copy_v3_v3(pa->state.co,tkey.co);
/* guides don't produce valid velocity */
sub_v3_v3v3(pa->state.vel, tkey.co, pa->prev_state.co);
@@ -2645,16 +2652,17 @@ static int collision_detect(ParticleData *pa, ParticleCollision *col, BVHTreeRay
return hit->index >= 0;
}
-static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation)
+static int collision_response(ParticleSimulationData *sim, ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation)
{
ParticleCollisionElement *pce = &col->pce;
PartDeflect *pd = col->hit->pd;
+ RNG *rng = sim->rng;
float co[3]; /* point of collision */
float x = hit->dist/col->original_ray_length; /* location factor of collision between this iteration */
float f = col->f + x * (1.0f - col->f); /* time factor of collision between timestep */
float dt1 = (f - col->f) * col->total_time; /* time since previous collision (in seconds) */
float dt2 = (1.0f - f) * col->total_time; /* time left after collision (in seconds) */
- int through = (BLI_frand() < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */
+ int through = (BLI_rng_get_float(rng) < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */
/* calculate exact collision location */
interp_v3_v3v3(co, col->co1, col->co2, x);
@@ -2679,8 +2687,8 @@ static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeR
float v0_tan[3];/* tangential component of v0 */
float vc_tan[3];/* tangential component of collision surface velocity */
float v0_dot, vc_dot;
- float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_frand() - 0.5f);
- float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_frand() - 0.5f);
+ float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_rng_get_float(rng) - 0.5f);
+ float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_rng_get_float(rng) - 0.5f);
float distance, nor[3], dot;
CLAMP(damp,0.0f, 1.0f);
@@ -2890,7 +2898,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
if (collision_count == PARTICLE_COLLISION_MAX_COLLISIONS)
collision_fail(pa, &col);
- else if (collision_response(pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0)
+ else if (collision_response(sim, pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0)
return;
}
else
@@ -2906,10 +2914,9 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
- Base *base;
int distr=0, alloc=0, skip=0;
- if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET)
+ if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys, use_render_params)) || psys->recalc&PSYS_RECALC_RESET)
alloc=1;
if (alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT)))
@@ -2919,7 +2926,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
if (alloc)
realloc_particles(sim, sim->psys->totpart);
- if (psys_get_tot_child(sim->scene, psys)) {
+ if (psys_get_tot_child(sim->scene, psys, use_render_params)) {
/* don't generate children while computing the hair keys */
if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
distribute_particles(sim, PART_FROM_CHILD);
@@ -2936,12 +2943,13 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
skip = 1; /* only hair, keyed and baked stuff can have paths */
else if (part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)))
skip = 1; /* particle visualization must be set as path */
- else if (!psys->renderdata) {
+ else {
if (part->draw_as != PART_DRAW_REND)
skip = 1; /* draw visualization */
else if (psys->pointcache->flag & PTCACHE_BAKING)
skip = 1; /* no need to cache paths while baking dynamics */
- else if (psys_in_edit_mode(sim->scene, psys)) {
+
+ else if (psys_in_edit_mode(sim->depsgraph, psys)) {
if ((pset->flag & PE_DRAW_PART)==0)
skip = 1;
else if (part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0)
@@ -2951,15 +2959,19 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
/* particle instance modifier with "path" option need cached paths even if particle system doesn't */
- for (base = sim->scene->base.first; base; base= base->next) {
- ModifierData *md = modifiers_findByType(base->object, eModifierType_ParticleInstance);
- if (md) {
- ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
- if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) {
- skip = 0;
- break;
+ if (skip) {
+ FOREACH_SCENE_OBJECT_BEGIN(sim->scene, ob)
+ {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleInstance);
+ if (md) {
+ ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
+ if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) {
+ skip = 0;
+ break;
+ }
}
}
+ FOREACH_SCENE_OBJECT_END;
}
if (!skip) {
@@ -3019,11 +3031,11 @@ static MDeformVert *hair_set_pinning(MDeformVert *dvert, float weight)
return dvert;
}
-static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int totedge, DerivedMesh **r_dm, ClothHairData **r_hairdata)
+static void hair_create_input_mesh(ParticleSimulationData *sim, int totpoint, int totedge, Mesh **r_mesh, ClothHairData **r_hairdata)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
- DerivedMesh *dm;
+ Mesh *mesh;
ClothHairData *hairdata;
MVert *mvert;
MEdge *medge;
@@ -3035,14 +3047,15 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
float max_length;
float hair_radius;
- dm = *r_dm;
- if (!dm) {
- *r_dm = dm = CDDM_new(totpoint, totedge, 0, 0, 0);
- DM_add_vert_layer(dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
+ mesh = *r_mesh;
+ if (!mesh) {
+ *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0);
+ CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert);
+ BKE_mesh_update_customdata_pointers(mesh, false);
}
- mvert = CDDM_get_verts(dm);
- medge = CDDM_get_edges(dm);
- dvert = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
+ mvert = mesh->mvert;
+ medge = mesh->medge;
+ dvert = mesh->dvert;
hairdata = *r_hairdata;
if (!hairdata) {
@@ -3077,7 +3090,7 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
pa->hair_index = hair_index;
use_hair = psys_hair_use_simulation(pa, max_length);
- psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
normalize_m4(root_mat);
@@ -3174,26 +3187,26 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
}
realloc_roots = false; /* whether hair root info array has to be reallocated */
- if (psys->hair_in_dm) {
- DerivedMesh *dm = psys->hair_in_dm;
- if (totpoint != dm->getNumVerts(dm) || totedge != dm->getNumEdges(dm)) {
- dm->release(dm);
- psys->hair_in_dm = NULL;
+ if (psys->hair_in_mesh) {
+ Mesh *mesh = psys->hair_in_mesh;
+ if (totpoint != mesh->totvert || totedge != mesh->totedge) {
+ BKE_id_free(NULL, mesh);
+ psys->hair_in_mesh = NULL;
realloc_roots = true;
}
}
- if (!psys->hair_in_dm || !psys->clmd->hairdata || realloc_roots) {
+ if (!psys->hair_in_mesh || !psys->clmd->hairdata || realloc_roots) {
if (psys->clmd->hairdata) {
MEM_freeN(psys->clmd->hairdata);
psys->clmd->hairdata = NULL;
}
}
- hair_create_input_dm(sim, totpoint, totedge, &psys->hair_in_dm, &psys->clmd->hairdata);
+ hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh, &psys->clmd->hairdata);
- if (psys->hair_out_dm)
- psys->hair_out_dm->release(psys->hair_out_dm);
+ if (psys->hair_out_mesh)
+ BKE_id_free(NULL, psys->hair_out_mesh);
psys->clmd->point_cache = psys->pointcache;
/* for hair sim we replace the internal cloth effector weights temporarily
@@ -3202,13 +3215,16 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
clmd_effweights = psys->clmd->sim_parms->effector_weights;
psys->clmd->sim_parms->effector_weights = psys->part->effector_weights;
- deformedVerts = MEM_mallocN(sizeof(*deformedVerts) * psys->hair_in_dm->getNumVerts(psys->hair_in_dm), "do_hair_dynamics vertexCos");
- psys->hair_out_dm = CDDM_copy(psys->hair_in_dm);
- psys->hair_out_dm->getVertCos(psys->hair_out_dm, deformedVerts);
-
- clothModifier_do(psys->clmd, sim->scene, sim->ob, psys->hair_in_dm, deformedVerts);
-
- CDDM_apply_vert_coords(psys->hair_out_dm, deformedVerts);
+ BKE_id_copy_ex(
+ NULL, &psys->hair_in_mesh->id, (ID **)&psys->hair_out_mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ deformedVerts = BKE_mesh_vertexCos_get(psys->hair_out_mesh, NULL);
+ clothModifier_do(psys->clmd, sim->depsgraph, sim->scene, sim->ob, psys->hair_in_mesh, deformedVerts);
+ BKE_mesh_apply_vert_coords(psys->hair_out_mesh, deformedVerts);
MEM_freeN(deformedVerts);
@@ -3220,7 +3236,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_re
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys);
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
LOOP_PARTICLES {
pa->size = part->size;
@@ -3235,7 +3251,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_re
if (psys->recalc & PSYS_RECALC_RESET) {
/* need this for changing subsurf levels */
- psys_calc_dmcache(sim->ob, sim->psmd->dm_final, sim->psmd->dm_deformed, psys);
+ psys_calc_dmcache(sim->ob, sim->psmd->mesh_final, sim->psmd->mesh_original, psys);
if (psys->clmd)
cloth_free_modifier(psys->clmd);
@@ -3282,7 +3298,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra))
if (pa->totkey) {
sub_v3_v3(key->co, root->co);
- psys_vec_rot_to_face(sim->psmd->dm_final, pa, key->co);
+ psys_vec_rot_to_face(sim->psmd->mesh_final, pa, key->co);
}
key->time = pa->state.time;
@@ -3492,7 +3508,6 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part=psys->part;
- RNG *rng;
BoidBrainData bbd;
ParticleTexture ptex;
PARTICLE_P;
@@ -3519,9 +3534,8 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
return;
}
- BLI_srandom(31415926 + (int)cfra + psys->seed);
/* for now do both, boids us 'rng' */
- rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed);
+ sim->rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed);
psys_update_effectors(sim);
@@ -3538,7 +3552,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
bbd.cfra = cfra;
bbd.dfra = dfra;
bbd.timestep = timestep;
- bbd.rng = rng;
+ bbd.rng = sim->rng;
psys_update_particle_tree(psys, cfra);
@@ -3734,15 +3748,17 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
}
free_collider_cache(&sim->colliders);
- BLI_rng_free(rng);
+ BLI_rng_free(sim->rng);
+ sim->rng = NULL;
}
-static void update_children(ParticleSimulationData *sim)
+
+static void update_children(ParticleSimulationData *sim, const bool use_render_params)
{
if ((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE)==0)
/* don't generate children while growing hair - waste of time */
psys_free_children(sim->psys);
else if (sim->psys->part->childtype) {
- if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys))
+ if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys, use_render_params))
distribute_particles(sim, PART_FROM_CHILD);
else {
/* Children are up to date, nothing to do. */
@@ -3752,7 +3768,7 @@ static void update_children(ParticleSimulationData *sim)
psys_free_children(sim->psys);
}
/* updates cached particles' alive & other flags etc..*/
-static void cached_step(ParticleSimulationData *sim, float cfra)
+static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -3762,7 +3778,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
psys_update_effectors(sim);
- disp= psys_get_current_display_percentage(psys);
+ disp= psys_get_current_display_percentage(psys, use_render_params);
LOOP_PARTICLES {
psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
@@ -3985,8 +4001,8 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
int cache_result = BKE_ptcache_read(pid, cache_cfra, true);
if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) {
- cached_step(sim, cfra);
- update_children(sim);
+ cached_step(sim, cfra, use_render_params);
+ update_children(sim, use_render_params);
psys_update_path_cache(sim, cfra, use_render_params);
BKE_ptcache_validate(cache, (int)cache_cfra);
@@ -4003,7 +4019,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
}
else if (cache_result == PTCACHE_READ_OLD) {
psys->cfra = (float)cache->simframe;
- cached_step(sim, psys->cfra);
+ cached_step(sim, psys->cfra, use_render_params);
}
/* if on second frame, write cache for first frame */
@@ -4015,7 +4031,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
/* 3. do dynamics */
/* set particles to be not calculated TODO: can't work with pointcache */
- disp= psys_get_current_display_percentage(psys);
+ disp= psys_get_current_display_percentage(psys, use_render_params);
LOOP_PARTICLES {
if (psys_frand(psys, p) > disp)
@@ -4071,7 +4087,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
BKE_ptcache_write(pid, (int)cache_cfra);
}
- update_children(sim);
+ update_children(sim, use_render_params);
/* cleanup */
if (psys->lattice_deform_data) {
@@ -4195,11 +4211,13 @@ static int hair_needs_recalc(ParticleSystem *psys)
/* main particle update call, checks that things are ok on the large scale and
* then advances in to actual particle calculations depending on particle type */
-void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
+void particle_system_update(struct Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSimulationData sim= {0};
ParticleSettings *part = psys->part;
+ ParticleSystem *psys_orig = psys_orig_get(psys);
float cfra;
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
/* drawdata is outdated after ANY change */
if (psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
@@ -4207,12 +4225,13 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
if (!psys_check_enabled(ob, psys, use_render_params))
return;
- cfra= BKE_scene_frame_get(scene);
+ cfra = DEG_get_ctime(depsgraph);
- sim.scene= scene;
- sim.ob= ob;
- sim.psys= psys;
- sim.psmd= psys_get_modifier(ob, psys);
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = psmd;
/* system was already updated from modifier stack */
if (sim.psmd->flag & eParticleSystemFlag_psys_updated) {
@@ -4222,22 +4241,19 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
return;
}
- if (!sim.psmd->dm_final)
+ if (!sim.psmd->mesh_final)
return;
if (part->from != PART_FROM_VERT) {
- DM_ensure_tessface(sim.psmd->dm_final);
+ BKE_mesh_tessface_ensure(sim.psmd->mesh_final);
}
/* execute drivers only, as animation has already been done */
- BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, cfra, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &part->id, part->adt, cfra, ADT_RECALC_DRIVERS);
/* to verify if we need to restore object afterwards */
psys->flag &= ~PSYS_OB_ANIM_RESTORE;
- if (psys->recalc & PSYS_RECALC_TYPE)
- psys_changed_type(sim.ob, sim.psys);
-
if (psys->recalc & PSYS_RECALC_RESET)
psys->totunexist = 0;
@@ -4260,10 +4276,10 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
free_hair(ob, psys, 0);
- if (psys->edit && psys->free_edit) {
- psys->free_edit(psys->edit);
- psys->edit = NULL;
- psys->free_edit = NULL;
+ if (psys_orig->edit && psys_orig->free_edit) {
+ psys_orig->free_edit(psys_orig->edit);
+ psys_orig->edit = NULL;
+ psys_orig->free_edit = NULL;
}
/* first step is negative so particles get killed and reset */
@@ -4272,7 +4288,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
for (i=0; i<=part->hair_step; i++) {
hcfra=100.0f*(float)i/(float)psys->part->hair_step;
if ((part->flag & PART_HAIR_REGROW)==0)
- BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM);
system_step(&sim, hcfra, use_render_params);
psys->cfra = hcfra;
psys->recalc = 0;
@@ -4291,7 +4307,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
}
case PART_FLUID:
{
- particles_fluid_step(bmain, &sim, (int)cfra, use_render_params);
+ particles_fluid_step(G.main /* Yuck :/ */, &sim, (int)cfra, use_render_params);
break;
}
default:
@@ -4301,7 +4317,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
case PART_PHYS_KEYED:
{
PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys);
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
bool free_unexisting = false;
/* Particles without dynamics haven't been reset yet because they don't use pointcache */
@@ -4355,16 +4371,33 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
/* make sure emitter is left at correct time (particle emission can change this) */
if (psys->flag & PSYS_OB_ANIM_RESTORE) {
- evaluate_emitter_anim(scene, ob, cfra);
+ evaluate_emitter_anim(depsgraph, scene, ob, cfra);
psys->flag &= ~PSYS_OB_ANIM_RESTORE;
}
+ if (psys_orig->edit) {
+ psys_orig->edit->flags |= PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL;
+ }
+
+ if (DEG_is_active(depsgraph)) {
+ if (psys_orig != psys) {
+ if (psys_orig->edit != NULL &&
+ psys_orig->edit->psys == psys_orig)
+ {
+ psys_orig->edit->psys_eval = psys;
+ psys_orig->edit->psmd_eval = psmd;
+ }
+ psys_orig->flag = psys->flag;
+ }
+ }
+
psys->cfra = cfra;
psys->recalc = 0;
/* save matrix for duplicators, at rendertime the actual dupliobject's matrix is used so don't update! */
- if (psys->renderdata==0)
- invert_m4_m4(psys->imat, ob->obmat);
+ invert_m4_m4(psys->imat, ob->obmat);
+
+ BKE_particle_batch_cache_dirty(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
}
/* ID looper */
@@ -4395,10 +4428,16 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
/* **** Depsgraph evaluation **** */
-void BKE_particle_system_eval_init(EvaluationContext *UNUSED(eval_ctx),
+void BKE_particle_system_eval_init(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
+ for (ParticleSystem *psys = ob->particlesystem.first;
+ psys != NULL;
+ psys = psys->next)
+ {
+ psys->recalc |= (psys->part->id.recalc & DEG_TAG_PSYS_ALL);
+ }
BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 6d29646319f..0a4cd3ec3c1 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -41,6 +41,7 @@
#include "BKE_paint.h"
#include "GPU_buffers.h"
+#include "GPU_immediate.h"
#include "bmesh.h"
@@ -1185,19 +1186,6 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
}
}
-void BKE_pbvh_draw_BB(PBVH *bvh)
-{
- GPU_pbvh_BB_draw_init();
-
- for (int a = 0; a < bvh->totnode; a++) {
- PBVHNode *node = &bvh->nodes[a];
-
- GPU_pbvh_BB_draw(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
- }
-
- GPU_pbvh_BB_draw_end();
-}
-
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
{
int update = 0;
@@ -2006,42 +1994,6 @@ bool BKE_pbvh_node_find_nearest_to_ray(
return hit;
}
-typedef struct {
- DMSetMaterial setMaterial;
- bool wireframe;
- bool fast;
-} PBVHNodeDrawData;
-
-void BKE_pbvh_node_draw(PBVHNode *node, void *data_v)
-{
- PBVHNodeDrawData *data = data_v;
-
-#if 0
- /* XXX: Just some quick code to show leaf nodes in different colors */
- float col[3];
- float spec[3] = {0.0f, 0.0f, 0.0f};
-
- if (0) { //is_partial) {
- col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6;
- }
- else {
- srand((long long)node);
- for (int i = 0; i < 3; ++i)
- col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7;
- }
-
- GPU_basic_shader_colors(col, spec, 0, 1.0f);
- glColor3f(1, 0, 0);
-#endif
-
- if (!(node->flag & PBVH_FullyHidden)) {
- GPU_pbvh_buffers_draw(node->draw_buffers,
- data->setMaterial,
- data->wireframe,
- data->fast);
- }
-}
-
typedef enum {
ISECT_INSIDE,
ISECT_OUTSIDE,
@@ -2110,6 +2062,8 @@ static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node)
node->flag |= PBVH_UpdateDrawBuffers;
}
+/* TODO: not needed anymore in 2.8? */
+#if 0
static void pbvh_node_check_mask_changed(PBVH *bvh, PBVHNode *node)
{
if (!node->draw_buffers) {
@@ -2119,18 +2073,44 @@ static void pbvh_node_check_mask_changed(PBVH *bvh, PBVHNode *node)
node->flag |= PBVH_UpdateDrawBuffers;
}
}
+#endif
+
+struct PBVHNodeDrawCallbackData {
-void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
- DMSetMaterial setMaterial, bool wireframe, bool fast)
+ void (*draw_fn)(void *user_data, Gwn_Batch *batch);
+ void *user_data;
+ bool fast;
+};
+
+static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
{
- PBVHNodeDrawData draw_data = {setMaterial, wireframe, fast};
+ struct PBVHNodeDrawCallbackData *data = data_v;
+
+ if (!(node->flag & PBVH_FullyHidden)) {
+ Gwn_Batch *triangles = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast);
+ if (triangles != NULL) {
+ data->draw_fn(data->user_data, triangles);
+ }
+ }
+}
+
+/**
+ * Version of #BKE_pbvh_draw that runs a callback.
+ */
+void BKE_pbvh_draw_cb(
+ PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast,
+ void (*draw_fn)(void *user_data, Gwn_Batch *batch), void *user_data)
+{
+ struct PBVHNodeDrawCallbackData draw_data = {
+ .fast = fast,
+ .draw_fn = draw_fn,
+ .user_data = user_data,
+ };
PBVHNode **nodes;
int totnode;
- for (int a = 0; a < bvh->totnode; a++) {
+ for (int a = 0; a < bvh->totnode; a++)
pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]);
- pbvh_node_check_mask_changed(bvh, &bvh->nodes[a]);
- }
BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers),
&nodes, &totnode);
@@ -2141,15 +2121,19 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
if (nodes) MEM_freeN(nodes);
if (planes) {
- BKE_pbvh_search_callback(bvh, BKE_pbvh_node_planes_contain_AABB,
- planes, BKE_pbvh_node_draw, &draw_data);
+ BKE_pbvh_search_callback(
+ bvh, BKE_pbvh_node_planes_contain_AABB,
+ planes, pbvh_node_draw_cb, &draw_data);
}
else {
- BKE_pbvh_search_callback(bvh, NULL, NULL, BKE_pbvh_node_draw, &draw_data);
+ BKE_pbvh_search_callback(
+ bvh, NULL,
+ NULL, pbvh_node_draw_cb, &draw_data);
}
-
+#if 0
if (G.debug_value == 14)
- BKE_pbvh_draw_BB(bvh);
+ pbvh_draw_BB(bvh);
+#endif
}
void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
@@ -2205,8 +2189,13 @@ float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3]
return vertCos;
}
-void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
+void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3], const int totvert)
{
+ if (totvert != pbvh->totvert) {
+ BLI_assert(!"PBVH: Given deforming vcos number does not natch PBVH vertex number!");
+ return;
+ }
+
if (!pbvh->deformed) {
if (pbvh->verts) {
/* if pbvh is not already deformed, verts/faces points to the */
@@ -2361,24 +2350,24 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK);
}
-void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color)
+bool pbvh_has_mask(PBVH *bvh)
{
- bool has_mask = false;
-
switch (bvh->type) {
case PBVH_GRIDS:
- has_mask = (bvh->gridkey.has_mask != 0);
- break;
+ return (bvh->gridkey.has_mask != 0);
case PBVH_FACES:
- has_mask = (bvh->vdata && CustomData_get_layer(bvh->vdata,
- CD_PAINT_MASK));
- break;
+ return (bvh->vdata && CustomData_get_layer(bvh->vdata,
+ CD_PAINT_MASK));
case PBVH_BMESH:
- has_mask = (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
- break;
+ return (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
}
- bvh->show_diffuse_color = !has_mask || show_diffuse_color;
+ return false;
+}
+
+void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color)
+{
+ bvh->show_diffuse_color = !pbvh_has_mask(bvh) || show_diffuse_color;
}
void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 104f8482635..3e8e6a69dd8 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -38,6 +38,7 @@
#include "DNA_ID.h"
#include "DNA_dynamicpaint_types.h"
+#include "DNA_group_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
@@ -59,6 +60,7 @@
#include "BKE_appdir.h"
#include "BKE_anim.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
#include "BKE_dynamicpaint.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -72,6 +74,8 @@
#include "BIK_api.h"
+#include "DEG_depsgraph.h"
+
#ifdef WITH_BULLET
# include "RBI_api.h"
#endif
@@ -1648,7 +1652,26 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-void BKE_ptcache_ids_from_object(Main *bmain, ListBase *lb, Object *ob, Scene *scene, int duplis)
+PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
+{
+ PTCacheID result = {0};
+
+ ListBase pidlist;
+ BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
+
+ for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->cache == cache) {
+ result = *pid;
+ break;
+ }
+ }
+
+ BLI_freelistN(&pidlist);
+
+ return result;
+}
+
+void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
{
PTCacheID *pid;
ParticleSystem *psys;
@@ -1716,23 +1739,19 @@ void BKE_ptcache_ids_from_object(Main *bmain, ListBase *lb, Object *ob, Scene *s
BLI_addtail(lb, pid);
}
- if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) {
- ListBase *lb_dupli_ob;
- /* don't update the dupli groups, we only want their pid's */
- if ((lb_dupli_ob = object_duplilist_ex(bmain, bmain->eval_ctx, scene, ob, false))) {
- DupliObject *dob;
- for (dob= lb_dupli_ob->first; dob; dob= dob->next) {
- if (dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */
- ListBase lb_dupli_pid;
- BKE_ptcache_ids_from_object(bmain, &lb_dupli_pid, dob->ob, scene, duplis);
- BLI_movelisttolist(lb, &lb_dupli_pid);
- if (lb_dupli_pid.first)
- printf("Adding Dupli\n");
- }
+ /* Consider all object in dupli groups to be part of the same object,
+ * for baking with linking dupligroups. Once we have better overrides
+ * this can be revisited so users select the local objects directly. */
+ if (scene && (duplis-- > 0) && (ob->dup_group)) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(ob->dup_group, object)
+ {
+ if (object != ob) {
+ ListBase lb_dupli_pid;
+ BKE_ptcache_ids_from_object(&lb_dupli_pid, object, scene, duplis);
+ BLI_movelisttolist(lb, &lb_dupli_pid);
}
-
- free_object_duplilist(lb_dupli_ob); /* does restore */
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
}
@@ -3357,6 +3376,7 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
if (ob->type == OB_ARMATURE)
BIK_clear_cache(ob->pose);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
return reset;
}
@@ -3511,13 +3531,14 @@ PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcach
* every user action changing stuff, and then it runs a complete bake??? (ton) */
/* Baking */
-void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene)
+void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
PTCacheBaker baker;
memset(&baker, 0, sizeof(baker));
baker.bmain = bmain;
baker.scene = scene;
+ baker.view_layer = view_layer;
baker.bake = 0;
baker.render = 0;
baker.anim_init = 0;
@@ -3543,6 +3564,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
{
Main *bmain = baker->bmain;
Scene *scene = baker->scene;
+ ViewLayer *view_layer = baker->view_layer;
+ struct Depsgraph *depsgraph = baker->depsgraph;
Scene *sce_iter; /* SETLOOPER macro only */
Base *base;
ListBase pidlist;
@@ -3572,7 +3595,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
/* get all pids from the object and search for smoke low res */
ListBase pidlist2;
PTCacheID *pid2;
- BKE_ptcache_ids_from_object(bmain, &pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
+ BKE_ptcache_ids_from_object(&pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
for (pid2=pidlist2.first; pid2; pid2=pid2->next) {
if (pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
if (pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) {
@@ -3605,9 +3628,9 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
else {
- for (SETLOOPER(scene, sce_iter, base)) {
+ for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
/* cache/bake everything in the scene */
- BKE_ptcache_ids_from_object(bmain, &pidlist, base->object, scene, MAX_DUPLI_RECUR);
+ BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
for (pid=pidlist.first; pid; pid=pid->next) {
cache = pid->cache;
@@ -3661,7 +3684,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
stime = ptime = PIL_check_seconds_timer();
for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) {
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
if (baker->update_progress) {
float progress = ((float)(CFRA - startframe)/(float)(endframe - startframe));
@@ -3716,8 +3739,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
else {
- for (SETLOOPER(scene, sce_iter, base)) {
- BKE_ptcache_ids_from_object(bmain, &pidlist, base->object, scene, MAX_DUPLI_RECUR);
+ for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
+ BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
for (pid=pidlist.first; pid; pid=pid->next) {
/* skip hair particles */
@@ -3747,7 +3770,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
CFRA = cfrao;
if (bake) { /* already on cfra unless baking */
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
/* TODO: call redraw all windows somehow */
diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c
deleted file mode 100644
index cb297744ab8..00000000000
--- a/source/blender/blenkernel/intern/property.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * ***** 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) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): ton roosendaal
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/property.c
- * \ingroup bke
- *
- * This module deals with bProperty only,
- * they are used on blender objects in the game engine
- * (where they get converted into C++ classes - CValue and subclasses)
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_property_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_blenlib.h"
-
-#include "BKE_property.h"
-
-void BKE_bproperty_free(bProperty *prop)
-{
-
- if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
- MEM_freeN(prop);
-
-}
-
-void BKE_bproperty_free_list(ListBase *lb)
-{
- bProperty *prop;
-
- while ((prop = BLI_pophead(lb))) {
- BKE_bproperty_free(prop);
- }
-}
-
-bProperty *BKE_bproperty_copy(const bProperty *prop)
-{
- bProperty *propn;
-
- propn = MEM_dupallocN(prop);
- if (prop->poin && prop->poin != &prop->data) {
- propn->poin = MEM_dupallocN(prop->poin);
- }
- else {
- propn->poin = &propn->data;
- }
-
- return propn;
-}
-
-void BKE_bproperty_copy_list(ListBase *lbn, const ListBase *lbo)
-{
- bProperty *prop, *propn;
- BKE_bproperty_free_list(lbn); /* in case we are copying to an object with props */
- prop = lbo->first;
- while (prop) {
- propn = BKE_bproperty_copy(prop);
- BLI_addtail(lbn, propn);
- prop = prop->next;
- }
-
-
-}
-
-void BKE_bproperty_init(bProperty *prop)
-{
- /* also use when property changes type */
-
- if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
- prop->poin = NULL;
-
- prop->data = 0;
-
- switch (prop->type) {
- case GPROP_BOOL:
- case GPROP_INT:
- case GPROP_FLOAT:
- case GPROP_TIME:
- prop->poin = &prop->data;
- break;
- case GPROP_STRING:
- prop->poin = MEM_callocN(MAX_PROPSTRING, "property string");
- break;
- }
-}
-
-
-bProperty *BKE_bproperty_new(int type)
-{
- bProperty *prop;
-
- prop = MEM_callocN(sizeof(bProperty), "property");
- prop->type = type;
-
- BKE_bproperty_init(prop);
-
- strcpy(prop->name, "prop");
-
- return prop;
-}
-
-
-bProperty *BKE_bproperty_object_get(Object *ob, const char *name)
-{
- return BLI_findstring(&ob->prop, name, offsetof(bProperty, name));
-}
-
-void BKE_bproperty_object_set(Object *ob, bProperty *propc)
-{
- bProperty *prop;
- prop = BKE_bproperty_object_get(ob, propc->name);
- if (prop) {
- BLI_remlink(&ob->prop, prop);
- BKE_bproperty_free(prop);
- }
- BLI_addtail(&ob->prop, BKE_bproperty_copy(propc));
-}
-
-/* negative: prop is smaller
- * positive: prop is larger
- */
-#if 0 /* UNUSED */
-int BKE_bproperty_cmp(bProperty *prop, const char *str)
-{
-// extern int Gdfra; /* sector.c */
- float fvalue, ftest;
-
- switch (prop->type) {
- case GPROP_BOOL:
- if (BLI_strcasecmp(str, "true") == 0) {
- if (prop->data == 1) return 0;
- else return 1;
- }
- else if (BLI_strcasecmp(str, "false") == 0) {
- if (prop->data == 0) return 0;
- else return 1;
- }
- /* no break, do GPROP_int too! */
-
- case GPROP_INT:
- return prop->data - atoi(str);
-
- case GPROP_FLOAT:
- case GPROP_TIME:
- /* WARNING: untested for GPROP_TIME
- * function isn't used currently */
- fvalue = *((float *)&prop->data);
- ftest = (float)atof(str);
- if (fvalue > ftest) return 1;
- else if (fvalue < ftest) return -1;
- return 0;
-
- case GPROP_STRING:
- return strcmp(prop->poin, str);
- }
-
- return 0;
-}
-#endif
-
-void BKE_bproperty_set(bProperty *prop, const char *str)
-{
-// extern int Gdfra; /* sector.c */
-
- switch (prop->type) {
- case GPROP_BOOL:
- if (BLI_strcasecmp(str, "true") == 0) prop->data = 1;
- else if (BLI_strcasecmp(str, "false") == 0) prop->data = 0;
- else prop->data = (atoi(str) != 0);
- break;
- case GPROP_INT:
- prop->data = atoi(str);
- break;
- case GPROP_FLOAT:
- case GPROP_TIME:
- *((float *)&prop->data) = (float)atof(str);
- break;
- case GPROP_STRING:
- strcpy(prop->poin, str); /* TODO - check size? */
- break;
- }
-
-}
-
-void BKE_bproperty_add(bProperty *prop, const char *str)
-{
-// extern int Gdfra; /* sector.c */
-
- switch (prop->type) {
- case GPROP_BOOL:
- case GPROP_INT:
- prop->data += atoi(str);
- break;
- case GPROP_FLOAT:
- case GPROP_TIME:
- *((float *)&prop->data) += (float)atof(str);
- break;
- case GPROP_STRING:
- /* strcpy(prop->poin, str); */
- break;
- }
-}
-
-/* reads value of property, sets it in chars in str */
-void BKE_bproperty_set_valstr(bProperty *prop, char str[MAX_PROPSTRING])
-{
-// extern int Gdfra; /* sector.c */
-
- if (str == NULL) return;
-
- switch (prop->type) {
- case GPROP_BOOL:
- case GPROP_INT:
- sprintf(str, "%d", prop->data);
- break;
- case GPROP_FLOAT:
- case GPROP_TIME:
- sprintf(str, "%f", *((float *)&prop->data));
- break;
- case GPROP_STRING:
- BLI_strncpy(str, prop->poin, MAX_PROPSTRING);
- break;
- }
-}
-
-#if 0 /* UNUSED */
-void cp_property(bProperty *prop1, bProperty *prop2)
-{
- char str[128];
-
- BKE_bproperty_set_valstr(prop2, str);
-
- BKE_bproperty_set(prop1, str);
-}
-#endif
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 502b6a81c76..ab324726812 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -48,25 +48,28 @@
#include "DNA_ID.h"
#include "DNA_group_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_depsgraph.h"
+#include "BKE_collection.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
/* ************************************** */
/* Memory Management */
@@ -93,26 +96,30 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
if (rbw->physics_world) {
/* free physics references, we assume that all physics objects in will have been added to the world */
- GroupObject *go;
if (rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- if (go->ob && go->ob->rigidbody_constraint) {
- RigidBodyCon *rbc = go->ob->rigidbody_constraint;
-
- if (rbc->physics_constraint)
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object)
+ {
+ if (object->rigidbody_constraint) {
+ RigidBodyCon *rbc = object->rigidbody_constraint;
+ if (rbc->physics_constraint) {
RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ }
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
- if (rbw->group) {
- for (go = rbw->group->gobject.first; go; go = go->next) {
- if (go->ob && go->ob->rigidbody_object) {
- RigidBodyOb *rbo = go->ob->rigidbody_object;
- if (rbo->physics_object)
+ if (rbw->group) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ if (object->rigidbody_object) {
+ RigidBodyOb *rbo = object->rigidbody_object;
+ if (rbo->physics_object) {
RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
+ }
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
/* free dynamics world */
RB_dworld_delete(rbw->physics_world);
@@ -229,31 +236,38 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(f
/* Setup Utilities - Validate Sim Instances */
/* get the appropriate DerivedMesh based on rigid body mesh source */
-static DerivedMesh *rigidbody_get_mesh(Object *ob)
+static Mesh *rigidbody_get_mesh(Object *ob)
{
- if (ob->rigidbody_object->mesh_source == RBO_MESH_DEFORM) {
- return ob->derivedDeform;
- }
- else if (ob->rigidbody_object->mesh_source == RBO_MESH_FINAL) {
- return ob->derivedFinal;
- }
- else {
- return CDDM_from_mesh(ob->data);
- }
+ switch (ob->rigidbody_object->mesh_source) {
+ case RBO_MESH_DEFORM:
+ return ob->runtime.mesh_deform_eval;
+ case RBO_MESH_FINAL:
+ return ob->runtime.mesh_eval;
+ case RBO_MESH_BASE:
+ /* This mesh may be used for computing looptris, which should be done
+ * on the original; otherwise every time the CoW is recreated it will
+ * have to be recomputed. */
+ BLI_assert(ob->rigidbody_object->mesh_source == RBO_MESH_BASE);
+ return DEG_get_original_object(ob)->data;
+ }
+
+ /* Just return something sensible so that at least Blender won't crash. */
+ BLI_assert(!"Unknown mesh source");
+ return ob->runtime.mesh_eval;
}
/* create collision shape of mesh - convex hull */
static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, float margin, bool *can_embed)
{
rbCollisionShape *shape = NULL;
- DerivedMesh *dm = NULL;
+ Mesh *mesh = NULL;
MVert *mvert = NULL;
int totvert = 0;
if (ob->type == OB_MESH && ob->data) {
- dm = rigidbody_get_mesh(ob);
- mvert = (dm) ? dm->getVertArray(dm) : NULL;
- totvert = (dm) ? dm->getNumVerts(dm) : 0;
+ mesh = rigidbody_get_mesh(ob);
+ mvert = (mesh) ? mesh->mvert : NULL;
+ totvert = (mesh) ? mesh->totvert : 0;
}
else {
printf("ERROR: cannot make Convex Hull collision shape for non-Mesh object\n");
@@ -266,9 +280,6 @@ static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, fl
printf("ERROR: no vertices to define Convex Hull collision shape with\n");
}
- if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE)
- dm->release(dm);
-
return shape;
}
@@ -280,24 +291,24 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
rbCollisionShape *shape = NULL;
if (ob->type == OB_MESH) {
- DerivedMesh *dm = NULL;
+ Mesh *mesh = NULL;
MVert *mvert;
const MLoopTri *looptri;
int totvert;
int tottri;
const MLoop *mloop;
- dm = rigidbody_get_mesh(ob);
+ mesh = rigidbody_get_mesh(ob);
/* ensure mesh validity, then grab data */
- if (dm == NULL)
+ if (mesh == NULL)
return NULL;
- mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
- looptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
- mloop = dm->getLoopArray(dm);
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
/* sanity checking - potential case when no data will be present */
if ((totvert == 0) || (tottri == 0)) {
@@ -347,11 +358,6 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
shape = RB_shape_new_gimpact_mesh(mdata);
}
}
-
- /* cleanup temp data */
- if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
- dm->release(dm);
- }
}
else {
printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n");
@@ -514,30 +520,25 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
case RB_SHAPE_TRIMESH:
{
if (ob->type == OB_MESH) {
- DerivedMesh *dm = rigidbody_get_mesh(ob);
+ Mesh *mesh = rigidbody_get_mesh(ob);
MVert *mvert;
const MLoopTri *lt = NULL;
int totvert, tottri = 0;
const MLoop *mloop = NULL;
/* ensure mesh validity, then grab data */
- if (dm == NULL)
+ if (mesh == NULL)
return;
- mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
- lt = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
- mloop = dm->getLoopArray(dm);
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ lt = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
if (totvert > 0 && tottri > 0) {
BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL);
}
-
- /* cleanup temp data */
- if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
- dm->release(dm);
- }
}
else {
/* rough estimate from boundbox as fallback */
@@ -597,30 +598,25 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
case RB_SHAPE_TRIMESH:
{
if (ob->type == OB_MESH) {
- DerivedMesh *dm = rigidbody_get_mesh(ob);
+ Mesh *mesh = rigidbody_get_mesh(ob);
MVert *mvert;
const MLoopTri *looptri;
int totvert, tottri;
const MLoop *mloop;
/* ensure mesh validity, then grab data */
- if (dm == NULL)
+ if (mesh == NULL)
return;
- mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
- looptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
- mloop = dm->getLoopArray(dm);
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
if (totvert > 0 && tottri > 0) {
BKE_mesh_calc_volume(mvert, totvert, looptri, tottri, mloop, NULL, r_center);
}
-
- /* cleanup temp data */
- if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
- dm->release(dm);
- }
}
break;
}
@@ -700,7 +696,8 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
/* --------------------- */
-static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint*,int,float,float))
+static void rigidbody_constraint_set_limits(
+ RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float))
{
if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
@@ -1020,8 +1017,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */
rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */
- rbo->lin_damping = 0.04f; /* 0.04 is game engine default */
- rbo->ang_damping = 0.1f; /* 0.1 is game engine default */
+ rbo->lin_damping = 0.04f;
+ rbo->ang_damping = 0.1f;
rbo->col_groups = 1;
@@ -1128,12 +1125,11 @@ RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
return scene->rigidbody_world;
}
-void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
+void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
RigidBodyOb *rbo = ob->rigidbody_object;
RigidBodyCon *rbc;
- GroupObject *go;
int i;
if (rbw) {
@@ -1153,8 +1149,8 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
/* remove object from rigid body constraints */
if (rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *obt = go->ob;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, obt)
+ {
if (obt && obt->rigidbody_constraint) {
rbc = obt->rigidbody_constraint;
if (ELEM(ob, rbc->ob1, rbc->ob2)) {
@@ -1162,7 +1158,9 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
}
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
+ BKE_collection_object_remove(bmain, rbw->group, ob, false);
}
/* remove object's settings */
@@ -1195,20 +1193,26 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
/* Update object array and rigid body count so they're in sync with the rigid body group */
static void rigidbody_update_ob_array(RigidBodyWorld *rbw)
{
- GroupObject *go;
- int i, n;
-
- n = BLI_listbase_count(&rbw->group->gobject);
+ int n = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ (void)object;
+ n++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
if (rbw->numbodies != n) {
rbw->numbodies = n;
rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies);
}
- for (go = rbw->group->gobject.first, i = 0; go; go = go->next, i++) {
- Object *ob = go->ob;
- rbw->objects[i] = ob;
+ int i = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ rbw->objects[i] = object;
+ i++;
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
@@ -1231,7 +1235,7 @@ static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
rigidbody_update_ob_array(rbw);
}
-static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
+static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
{
float loc[3];
float rot[4];
@@ -1242,10 +1246,10 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
return;
if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
- DerivedMesh *dm = ob->derivedDeform;
- if (dm) {
- MVert *mvert = dm->getVertArray(dm);
- int totvert = dm->getNumVerts(dm);
+ Mesh *mesh = ob->runtime.mesh_deform_eval;
+ if (mesh) {
+ MVert *mvert = mesh->mvert;
+ int totvert = mesh->totvert;
BoundBox *bb = BKE_object_boundbox_get(ob);
RB_shape_trimesh_update(rbo->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
@@ -1279,7 +1283,7 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
ListBase *effectors;
/* get effectors present in the group specified by effector_weights */
- effectors = pdInitEffectors(scene, ob, NULL, effector_weights, true);
+ effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, effector_weights);
if (effectors) {
float eff_force[3] = {0.0f, 0.0f, 0.0f};
float eff_loc[3], eff_vel[3];
@@ -1294,7 +1298,7 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
/* calculate net force of effectors, and apply to sim object
* - we use 'central force' since apply force requires a "relative position" which we don't have...
*/
- pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
+ BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
if (G.f & G_DEBUG)
printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2);
/* activate object in case it is deactivated */
@@ -1306,7 +1310,7 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
/* cleanup */
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
}
/* NOTE: passive objects don't need to be updated since they don't move */
@@ -1320,10 +1324,8 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
*
* \param rebuild Rebuild entire simulation
*/
-static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
+static void rigidbody_update_simulation(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
- GroupObject *go;
-
/* update world */
if (rebuild)
BKE_rigidbody_validate_sim_world(scene, rbw, true);
@@ -1336,28 +1338,26 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
* Memory management needs redesign here, this is just a dirty workaround.
*/
if (rebuild && rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
- if (ob) {
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- if (rbc && rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
- RB_constraint_delete(rbc->physics_constraint);
- rbc->physics_constraint = NULL;
- }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob)
+ {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
/* update objects */
- for (go = rbw->group->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
-
- if (ob && ob->type == OB_MESH) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob)
+ {
+ if (ob->type == OB_MESH) {
/* validate that we've got valid object set up here... */
RigidBodyOb *rbo = ob->rigidbody_object;
/* update transformation matrix of the object so we don't get a frame of lag for simple animations */
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob);
if (rbo == NULL) {
/* Since this object is included in the sim group but doesn't have
@@ -1391,65 +1391,64 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
}
/* update simulation object... */
- rigidbody_update_sim_ob(scene, rbw, ob, rbo);
+ rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo);
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
/* update constraints */
if (rbw->constraints == NULL) /* no constraints, move on */
return;
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
- if (ob) {
- /* validate that we've got valid object set up here... */
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
- BKE_object_where_is_calc(scene, ob);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob)
+ {
+ /* validate that we've got valid object set up here... */
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
+ BKE_object_where_is_calc(depsgraph, scene, ob);
- if (rbc == NULL) {
- /* Since this object is included in the group but doesn't have
- * constraint settings (perhaps it was added manually), add!
- */
- ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
- rigidbody_validate_sim_constraint(rbw, ob, true);
+ if (rbc == NULL) {
+ /* Since this object is included in the group but doesn't have
+ * constraint settings (perhaps it was added manually), add!
+ */
+ ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
+ rigidbody_validate_sim_constraint(rbw, ob, true);
- rbc = ob->rigidbody_constraint;
+ rbc = ob->rigidbody_constraint;
+ }
+ else {
+ /* perform simulation data updates as tagged */
+ if (rebuild) {
+ /* World has been rebuilt so rebuild constraint */
+ rigidbody_validate_sim_constraint(rbw, ob, true);
}
- else {
- /* perform simulation data updates as tagged */
- if (rebuild) {
- /* World has been rebuilt so rebuild constraint */
- rigidbody_validate_sim_constraint(rbw, ob, true);
- }
- else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
- rigidbody_validate_sim_constraint(rbw, ob, false);
- }
- rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
+ else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
+ rigidbody_validate_sim_constraint(rbw, ob, false);
}
+ rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
-static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw)
+static void rigidbody_update_simulation_post_step(Depsgraph *depsgraph, RigidBodyWorld *rbw)
{
- GroupObject *go;
-
- for (go = rbw->group->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
-
- if (ob) {
- RigidBodyOb *rbo = ob->rigidbody_object;
- /* reset kinematic state for transformed objects */
- if (rbo && (ob->flag & SELECT) && (G.moving & G_TRANSFORM_OBJ)) {
- RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
- RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
- /* deactivate passive objects so they don't interfere with deactivation of active objects */
- if (rbo->type == RBO_TYPE_PASSIVE)
- RB_body_deactivate(rbo->physics_object);
- }
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob)
+ {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* Reset kinematic state for transformed objects. */
+ if (rbo && base && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) {
+ RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
+ RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
+ /* Deactivate passive objects so they don't interfere with deactivation of active objects. */
+ if (rbo->type == RBO_TYPE_PASSIVE)
+ RB_body_deactivate(rbo->physics_object);
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime)
@@ -1564,7 +1563,7 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
/* Rebuild rigid body world */
/* NOTE: this needs to be called before frame update to work correctly */
-void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
+void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
PointCache *cache;
@@ -1576,14 +1575,22 @@ void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
cache = rbw->pointcache;
/* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */
- if (rbw->physics_world == NULL || rbw->numbodies != BLI_listbase_count(&rbw->group->gobject)) {
+ int n = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ (void)object;
+ n++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ if (rbw->physics_world == NULL || rbw->numbodies != n) {
cache->flag |= PTCACHE_OUTDATED;
}
if (ctime == startframe + 1 && rbw->ltime == startframe) {
if (cache->flag & PTCACHE_OUTDATED) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- rigidbody_update_simulation(scene, rbw, true);
+ rigidbody_update_simulation(depsgraph, scene, rbw, true);
BKE_ptcache_validate(cache, (int)ctime);
cache->last_exact = 0;
cache->flag &= ~PTCACHE_REDO_NEEDED;
@@ -1592,7 +1599,7 @@ void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
}
/* Run RigidBody simulation for the specified physics world */
-void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
+void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime)
{
float timestep;
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -1630,21 +1637,21 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
}
/* advance simulation, we can only step one frame forward */
- if (can_simulate) {
+ if (compare_ff_relative(ctime, rbw->ltime + 1, FLT_EPSILON, 64)) {
/* write cache for first frame when on second frame */
if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
BKE_ptcache_write(&pid, startframe);
}
/* update and validate simulation */
- rigidbody_update_simulation(scene, rbw, false);
+ rigidbody_update_simulation(depsgraph, scene, rbw, false);
/* calculate how much time elapsed since last step in seconds */
timestep = 1.0f / (float)FPS * (ctime - rbw->ltime) * rbw->time_scale;
/* step simulation by the requested timestep, steps per second are adjusted to take time scale into account */
RB_dworld_step_simulation(rbw->physics_world, timestep, INT_MAX, 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f));
- rigidbody_update_simulation_post_step(rbw);
+ rigidbody_update_simulation_post_step(depsgraph, rbw);
/* write cache for current frame */
BKE_ptcache_validate(cache, (int)ctime);
@@ -1675,14 +1682,14 @@ void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFun
struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; }
struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) { return NULL; }
struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { return NULL; }
-void BKE_rigidbody_remove_object(Scene *scene, Object *ob) {}
+void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob) {}
void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) {}
void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) {}
void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle) {}
bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) { return false; }
void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) {}
-void BKE_rigidbody_rebuild_world(Scene *scene, float ctime) {}
-void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
+void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime) {}
+void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime) {}
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic pop
@@ -1690,38 +1697,67 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
#endif /* WITH_BULLET */
+
+/* Copy the pointcache from the evaluated to the original scene.
+ * This allows the re-evaluation of the original scene to use the
+ * physics cache.
+ */
+static void rigidbody_copy_cache_to_orig(Scene *scene_eval)
+{
+ if ((scene_eval->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
+ /* Scene is already an original, this function is a no-op. */
+ return;
+ }
+
+ Scene *scene_orig = (Scene *)DEG_get_original_id(&scene_eval->id);
+ RigidBodyWorld *rbw_orig = scene_orig->rigidbody_world;
+ RigidBodyWorld *rbw_eval = scene_eval->rigidbody_world;
+
+ BKE_ptcache_free_list(&rbw_orig->ptcaches);
+ rbw_orig->pointcache = BKE_ptcache_copy_list(&rbw_orig->ptcaches, &rbw_eval->ptcaches, LIB_ID_COPY_CACHES);
+}
+
+
/* -------------------- */
/* Depsgraph evaluation */
-void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_rebuild_sim(Depsgraph *depsgraph,
Scene *scene)
{
- float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, 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);
+ BKE_rigidbody_rebuild_world(depsgraph, scene, ctime);
}
}
-void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_eval_simulation(Depsgraph *depsgraph,
Scene *scene)
{
- float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime);
+
/* evaluate rigidbody sim */
- if (BKE_scene_check_rigidbody_active(scene)) {
- BKE_rigidbody_do_simulation(scene, ctime);
+ if (!BKE_scene_check_rigidbody_active(scene)) {
+ return;
+ }
+ BKE_rigidbody_do_simulation(depsgraph, scene, ctime);
+
+ /* Make sure re-evaluation can use the cache from this simulation */
+ if (!DEG_is_active(depsgraph)) {
+ return;
}
+ rigidbody_copy_cache_to_orig(scene);
}
-void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_object_sync_transforms(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
- float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval_time(__func__, ob->id.name, ob, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, ob->id.name, ob, ctime);
/* read values pushed into RBO from sim/cache... */
BKE_rigidbody_sync_transforms(rbw, ob, ctime);
}
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
deleted file mode 100644
index 6f288258a00..00000000000
--- a/source/blender/blenkernel/intern/sca.c
+++ /dev/null
@@ -1,1179 +0,0 @@
-/*
- * ***** 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) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- * these all are linked to objects (listbase)
- * all data is 'direct data', not Blender lib data.
- */
-
-/** \file blender/blenkernel/intern/sca.c
- * \ingroup bke
- */
-
-
-#include <stdio.h>
-#include <string.h>
-#include <float.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_controller_types.h"
-#include "DNA_sensor_types.h"
-#include "DNA_actuator_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
-#include "BLI_math.h"
-
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_library.h"
-#include "BKE_library_query.h"
-#include "BKE_sca.h"
-
-/* ******************* SENSORS ************************ */
-
-void free_sensor(bSensor *sens)
-{
- if (sens->links) MEM_freeN(sens->links);
- if (sens->data) MEM_freeN(sens->data);
- MEM_freeN(sens);
-
-}
-
-void free_sensors(ListBase *lb)
-{
- bSensor *sens;
-
- while ((sens = BLI_pophead(lb))) {
- free_sensor(sens);
- }
-}
-
-bSensor *copy_sensor(bSensor *sens, const int UNUSED(flag))
-{
- bSensor *sensn;
-
- sensn= MEM_dupallocN(sens);
- sensn->flag |= SENS_NEW;
- if (sens->data) {
- sensn->data= MEM_dupallocN(sens->data);
- }
-
- if (sens->links) sensn->links= MEM_dupallocN(sens->links);
-
- return sensn;
-}
-
-void copy_sensors(ListBase *lbn, const ListBase *lbo, const int flag)
-{
- bSensor *sens, *sensn;
-
- lbn->first= lbn->last= NULL;
- sens= lbo->first;
- while (sens) {
- sensn= copy_sensor(sens, flag);
- BLI_addtail(lbn, sensn);
- sens= sens->next;
- }
-}
-
-void init_sensor(bSensor *sens)
-{
- /* also use when sensor changes type */
- bNearSensor *ns;
- bMouseSensor *ms;
- bJoystickSensor *js;
- bRaySensor *rs;
-
- if (sens->data) MEM_freeN(sens->data);
- sens->data= NULL;
- sens->pulse = 0;
-
- switch (sens->type) {
- case SENS_ALWAYS:
- sens->pulse = 0;
- break;
- case SENS_NEAR:
- ns=sens->data= MEM_callocN(sizeof(bNearSensor), "nearsens");
- ns->dist= 1.0;
- ns->resetdist= 2.0;
- break;
- case SENS_KEYBOARD:
- sens->data= MEM_callocN(sizeof(bKeyboardSensor), "keysens");
- break;
- case SENS_PROPERTY:
- sens->data= MEM_callocN(sizeof(bPropertySensor), "propsens");
- break;
- case SENS_ARMATURE:
- sens->data= MEM_callocN(sizeof(bArmatureSensor), "armsens");
- break;
- case SENS_ACTUATOR:
- sens->data= MEM_callocN(sizeof(bActuatorSensor), "actsens");
- break;
- case SENS_DELAY:
- sens->data= MEM_callocN(sizeof(bDelaySensor), "delaysens");
- break;
- case SENS_MOUSE:
- ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens");
- ms->type= 1; // LEFTMOUSE workaround because Mouse Sensor types enum starts in 1
- break;
- case SENS_COLLISION:
- sens->data= MEM_callocN(sizeof(bCollisionSensor), "colsens");
- break;
- case SENS_RADAR:
- sens->data= MEM_callocN(sizeof(bRadarSensor), "radarsens");
- break;
- case SENS_RANDOM:
- sens->data= MEM_callocN(sizeof(bRandomSensor), "randomsens");
- break;
- case SENS_RAY:
- sens->data= MEM_callocN(sizeof(bRaySensor), "raysens");
- rs = sens->data;
- rs->range = 0.01f;
- break;
- case SENS_MESSAGE:
- sens->data= MEM_callocN(sizeof(bMessageSensor), "messagesens");
- break;
- case SENS_JOYSTICK:
- sens->data= MEM_callocN(sizeof(bJoystickSensor), "joysticksens");
- js= sens->data;
- js->hatf = SENS_JOY_HAT_UP;
- js->axis = 1;
- js->hat = 1;
- break;
- default:
- ; /* this is very severe... I cannot make any memory for this */
- /* logic brick... */
- }
-}
-
-bSensor *new_sensor(int type)
-{
- bSensor *sens;
-
- sens= MEM_callocN(sizeof(bSensor), "Sensor");
- sens->type= type;
- sens->flag= SENS_SHOW;
-
- init_sensor(sens);
-
- strcpy(sens->name, "sensor");
-// XXX make_unique_prop_names(sens->name);
-
- return sens;
-}
-
-/* ******************* CONTROLLERS ************************ */
-
-void unlink_controller(bController *cont)
-{
- bSensor *sens;
- Object *ob;
-
- /* check for controller pointers in sensors */
- ob= G.main->object.first;
- while (ob) {
- sens= ob->sensors.first;
- while (sens) {
- unlink_logicbricks((void **)&cont, (void ***)&(sens->links), &sens->totlinks);
- sens= sens->next;
- }
- ob= ob->id.next;
- }
-}
-
-void unlink_controllers(ListBase *lb)
-{
- bController *cont;
-
- for (cont= lb->first; cont; cont= cont->next)
- unlink_controller(cont);
-}
-
-void free_controller(bController *cont)
-{
- if (cont->links) MEM_freeN(cont->links);
-
- /* the controller itself */
- if (cont->data) MEM_freeN(cont->data);
- MEM_freeN(cont);
-
-}
-
-void free_controllers(ListBase *lb)
-{
- bController *cont;
-
- while ((cont = BLI_pophead(lb))) {
- if (cont->slinks)
- MEM_freeN(cont->slinks);
- free_controller(cont);
- }
-}
-
-bController *copy_controller(bController *cont, const int UNUSED(flag))
-{
- bController *contn;
-
- cont->mynew=contn= MEM_dupallocN(cont);
- contn->flag |= CONT_NEW;
- if (cont->data) {
- contn->data= MEM_dupallocN(cont->data);
- }
-
- if (cont->links) contn->links= MEM_dupallocN(cont->links);
- contn->slinks= NULL;
- contn->totslinks= 0;
-
- return contn;
-}
-
-void copy_controllers(ListBase *lbn, const ListBase *lbo, const int flag)
-{
- bController *cont, *contn;
-
- lbn->first= lbn->last= NULL;
- cont= lbo->first;
- while (cont) {
- contn= copy_controller(cont, flag);
- BLI_addtail(lbn, contn);
- cont= cont->next;
- }
-}
-
-void init_controller(bController *cont)
-{
- /* also use when controller changes type, leave actuators... */
-
- if (cont->data) MEM_freeN(cont->data);
- cont->data= NULL;
-
- switch (cont->type) {
- case CONT_EXPRESSION:
- cont->data= MEM_callocN(sizeof(bExpressionCont), "expcont");
- break;
- case CONT_PYTHON:
- cont->data= MEM_callocN(sizeof(bPythonCont), "pycont");
- break;
- }
-}
-
-bController *new_controller(int type)
-{
- bController *cont;
-
- cont= MEM_callocN(sizeof(bController), "Controller");
- cont->type= type;
- cont->flag= CONT_SHOW;
-
- init_controller(cont);
-
- strcpy(cont->name, "cont");
-// XXX make_unique_prop_names(cont->name);
-
- return cont;
-}
-
-/* ******************* ACTUATORS ************************ */
-
-void unlink_actuator(bActuator *act)
-{
- bController *cont;
- Object *ob;
-
- /* check for actuator pointers in controllers */
- ob= G.main->object.first;
- while (ob) {
- cont= ob->controllers.first;
- while (cont) {
- unlink_logicbricks((void **)&act, (void ***)&(cont->links), &cont->totlinks);
- cont= cont->next;
- }
- ob= ob->id.next;
- }
-}
-
-void unlink_actuators(ListBase *lb)
-{
- bActuator *act;
-
- for (act= lb->first; act; act= act->next)
- unlink_actuator(act);
-}
-
-void free_actuator(bActuator *act)
-{
- if (act->data) {
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- {
- bActionActuator *aa = (bActionActuator *)act->data;
- if (aa->act)
- id_us_min((ID *)aa->act);
- break;
- }
- case ACT_SOUND:
- {
- bSoundActuator *sa = (bSoundActuator *) act->data;
- if (sa->sound)
- id_us_min((ID *)sa->sound);
- break;
- }
- }
-
- MEM_freeN(act->data);
- }
- MEM_freeN(act);
-}
-
-void free_actuators(ListBase *lb)
-{
- bActuator *act;
-
- while ((act = BLI_pophead(lb))) {
- free_actuator(act);
- }
-}
-
-bActuator *copy_actuator(bActuator *act, const int flag)
-{
- bActuator *actn;
-
- act->mynew=actn= MEM_dupallocN(act);
- actn->flag |= ACT_NEW;
- if (act->data) {
- actn->data= MEM_dupallocN(act->data);
- }
-
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- {
- bActionActuator *aa = (bActionActuator *)act->data;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)aa->act);
- }
- break;
- }
- case ACT_SOUND:
- {
- bSoundActuator *sa = (bSoundActuator *)act->data;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)sa->sound);
- }
- break;
- }
- }
- return actn;
-}
-
-void copy_actuators(ListBase *lbn, const ListBase *lbo, const int flag)
-{
- bActuator *act, *actn;
-
- lbn->first= lbn->last= NULL;
- act= lbo->first;
- while (act) {
- actn= copy_actuator(act, flag);
- BLI_addtail(lbn, actn);
- act= act->next;
- }
-}
-
-void init_actuator(bActuator *act)
-{
- /* also use when actuator changes type */
- bCameraActuator *ca;
- bObjectActuator *oa;
- bRandomActuator *ra;
- bSoundActuator *sa;
- bSteeringActuator *sta;
- bArmatureActuator *arma;
- bMouseActuator *ma;
- bEditObjectActuator *eoa;
-
- if (act->data) MEM_freeN(act->data);
- act->data= NULL;
-
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- act->data= MEM_callocN(sizeof(bActionActuator), "actionact");
- break;
- case ACT_SOUND:
- sa = act->data= MEM_callocN(sizeof(bSoundActuator), "soundact");
- sa->volume = 1.0f;
- sa->sound3D.rolloff_factor = 1.0f;
- sa->sound3D.reference_distance = 1.0f;
- sa->sound3D.max_gain = 1.0f;
- sa->sound3D.cone_inner_angle = DEG2RADF(360.0f);
- sa->sound3D.cone_outer_angle = DEG2RADF(360.0f);
- sa->sound3D.max_distance = FLT_MAX;
- break;
- case ACT_OBJECT:
- act->data= MEM_callocN(sizeof(bObjectActuator), "objectact");
- oa= act->data;
- oa->flag= 15;
- break;
- case ACT_PROPERTY:
- act->data= MEM_callocN(sizeof(bPropertyActuator), "propact");
- break;
- case ACT_CAMERA:
- act->data= MEM_callocN(sizeof(bCameraActuator), "camact");
- ca = act->data;
- ca->axis = OB_POSX;
- ca->damping = 1.0/32.0;
- break;
- case ACT_EDIT_OBJECT:
- act->data= MEM_callocN(sizeof(bEditObjectActuator), "editobact");
- eoa = act->data;
- eoa->upflag= ACT_TRACK_UP_Z;
- eoa->trackflag= ACT_TRACK_TRAXIS_Y;
- break;
- case ACT_CONSTRAINT:
- act->data= MEM_callocN(sizeof(bConstraintActuator), "cons act");
- break;
- case ACT_SCENE:
- act->data= MEM_callocN(sizeof(bSceneActuator), "scene act");
- break;
- case ACT_GROUP:
- act->data= MEM_callocN(sizeof(bGroupActuator), "group act");
- break;
- case ACT_RANDOM:
- act->data= MEM_callocN(sizeof(bRandomActuator), "random act");
- ra=act->data;
- ra->float_arg_1 = 0.1f;
- break;
- case ACT_MESSAGE:
- act->data= MEM_callocN(sizeof(bMessageActuator), "message act");
- break;
- case ACT_GAME:
- act->data= MEM_callocN(sizeof(bGameActuator), "game act");
- break;
- case ACT_VISIBILITY:
- act->data= MEM_callocN(sizeof(bVisibilityActuator), "visibility act");
- break;
- case ACT_2DFILTER:
- act->data = MEM_callocN(sizeof( bTwoDFilterActuator ), "2d filter act");
- break;
- case ACT_PARENT:
- act->data = MEM_callocN(sizeof( bParentActuator ), "parent act");
- break;
- case ACT_STATE:
- act->data = MEM_callocN(sizeof( bStateActuator ), "state act");
- break;
- case ACT_ARMATURE:
- act->data = MEM_callocN(sizeof( bArmatureActuator ), "armature act");
- arma = act->data;
- arma->influence = 1.f;
- break;
- case ACT_STEERING:
- act->data = MEM_callocN(sizeof( bSteeringActuator), "steering act");
- sta = act->data;
- sta->acceleration = 3.f;
- sta->turnspeed = 120.f;
- sta->dist = 1.f;
- sta->velocity= 3.f;
- sta->flag = ACT_STEERING_AUTOMATICFACING | ACT_STEERING_LOCKZVEL;
- sta->facingaxis = 1;
- break;
- case ACT_MOUSE:
- ma = act->data = MEM_callocN(sizeof( bMouseActuator ), "mouse act");
- ma->flag = ACT_MOUSE_VISIBLE|ACT_MOUSE_USE_AXIS_X|ACT_MOUSE_USE_AXIS_Y|ACT_MOUSE_RESET_X|ACT_MOUSE_RESET_Y|ACT_MOUSE_LOCAL_Y;
- ma->sensitivity[0] = ma->sensitivity[1] = 2.f;
- ma->object_axis[0] = ACT_MOUSE_OBJECT_AXIS_Z;
- ma->object_axis[1] = ACT_MOUSE_OBJECT_AXIS_X;
- ma->limit_y[0] = DEG2RADF(-90.0f);
- ma->limit_y[1] = DEG2RADF(90.0f);
- break;
- default:
- ; /* this is very severe... I cannot make any memory for this */
- /* logic brick... */
- }
-}
-
-bActuator *new_actuator(int type)
-{
- bActuator *act;
-
- act= MEM_callocN(sizeof(bActuator), "Actuator");
- act->type= type;
- act->flag= ACT_SHOW;
-
- init_actuator(act);
-
- strcpy(act->name, "act");
-// XXX make_unique_prop_names(act->name);
-
- return act;
-}
-
-/* ******************** GENERAL ******************* */
-void clear_sca_new_poins_ob(Object *ob)
-{
- bSensor *sens;
- bController *cont;
- bActuator *act;
-
- sens= ob->sensors.first;
- while (sens) {
- sens->flag &= ~SENS_NEW;
- sens= sens->next;
- }
- cont= ob->controllers.first;
- while (cont) {
- cont->mynew= NULL;
- cont->flag &= ~CONT_NEW;
- cont= cont->next;
- }
- act= ob->actuators.first;
- while (act) {
- act->mynew= NULL;
- act->flag &= ~ACT_NEW;
- act= act->next;
- }
-}
-
-void clear_sca_new_poins(void)
-{
- Object *ob;
-
- ob= G.main->object.first;
- while (ob) {
- clear_sca_new_poins_ob(ob);
- ob= ob->id.next;
- }
-}
-
-void set_sca_new_poins_ob(Object *ob)
-{
- bSensor *sens;
- bController *cont;
- bActuator *act;
- int a;
-
- sens= ob->sensors.first;
- while (sens) {
- if (sens->flag & SENS_NEW) {
- for (a=0; a<sens->totlinks; a++) {
- if (sens->links[a] && sens->links[a]->mynew)
- sens->links[a] = sens->links[a]->mynew;
- }
- }
- sens= sens->next;
- }
-
- cont= ob->controllers.first;
- while (cont) {
- if (cont->flag & CONT_NEW) {
- for (a=0; a<cont->totlinks; a++) {
- if ( cont->links[a] && cont->links[a]->mynew)
- cont->links[a] = cont->links[a]->mynew;
- }
- }
- cont= cont->next;
- }
-
-
- act= ob->actuators.first;
- while (act) {
- if (act->flag & ACT_NEW) {
- if (act->type==ACT_EDIT_OBJECT) {
- bEditObjectActuator *eoa= act->data;
- ID_NEW_REMAP(eoa->ob);
- }
- else if (act->type==ACT_SCENE) {
- bSceneActuator *sca= act->data;
- ID_NEW_REMAP(sca->camera);
- }
- else if (act->type==ACT_CAMERA) {
- bCameraActuator *ca= act->data;
- ID_NEW_REMAP(ca->ob);
- }
- else if (act->type==ACT_OBJECT) {
- bObjectActuator *oa= act->data;
- ID_NEW_REMAP(oa->reference);
- }
- else if (act->type==ACT_MESSAGE) {
- bMessageActuator *ma= act->data;
- ID_NEW_REMAP(ma->toObject);
- }
- else if (act->type==ACT_PARENT) {
- bParentActuator *para = act->data;
- ID_NEW_REMAP(para->ob);
- }
- else if (act->type==ACT_ARMATURE) {
- bArmatureActuator *aa = act->data;
- ID_NEW_REMAP(aa->target);
- ID_NEW_REMAP(aa->subtarget);
- }
- else if (act->type==ACT_PROPERTY) {
- bPropertyActuator *pa= act->data;
- ID_NEW_REMAP(pa->ob);
- }
- else if (act->type==ACT_STEERING) {
- bSteeringActuator *sta = act->data;
- ID_NEW_REMAP(sta->navmesh);
- ID_NEW_REMAP(sta->target);
- }
- }
- act= act->next;
- }
-}
-
-
-void set_sca_new_poins(void)
-{
- Object *ob;
-
- ob= G.main->object.first;
- while (ob) {
- set_sca_new_poins_ob(ob);
- ob= ob->id.next;
- }
-}
-
-/**
- * Try to remap logic links to new object... Very, *very* weak.
- */
-/* XXX Logick bricks... I don't have words to say what I think about this behavior.
- * They have silent hidden ugly inter-objects dependencies (a sensor can link into any other
- * object's controllers, and same between controllers and actuators, without *any* explicit reference
- * to data-block involved).
- * This is bad, bad, bad!!!
- * ...and forces us to add yet another very ugly hack to get remapping with logic bricks working. */
-void BKE_sca_logic_links_remap(Main *bmain, Object *ob_old, Object *ob_new)
-{
- if (ob_new == NULL || (ob_old->controllers.first == NULL && ob_old->actuators.first == NULL)) {
- /* Nothing to do here... */
- return;
- }
-
- GHash *controllers_map = ob_old->controllers.first ?
- BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->controllers)) : NULL;
- GHash *actuators_map = ob_old->actuators.first ?
- BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->actuators)) : NULL;
-
- /* We try to remap old controllers/actuators to new ones - in a very basic way. */
- for (bController *cont_old = ob_old->controllers.first, *cont_new = ob_new->controllers.first;
- cont_old;
- cont_old = cont_old->next)
- {
- bController *cont_new2 = cont_new;
-
- if (cont_old->mynew != NULL) {
- cont_new2 = cont_old->mynew;
- if (!(cont_new2 == cont_new || BLI_findindex(&ob_new->controllers, cont_new2) >= 0)) {
- cont_new2 = NULL;
- }
- }
- else if (cont_new && cont_old->type != cont_new->type) {
- cont_new2 = NULL;
- }
-
- BLI_ghash_insert(controllers_map, cont_old, cont_new2);
-
- if (cont_new) {
- cont_new = cont_new->next;
- }
- }
-
- for (bActuator *act_old = ob_old->actuators.first, *act_new = ob_new->actuators.first;
- act_old;
- act_old = act_old->next)
- {
- bActuator *act_new2 = act_new;
-
- if (act_old->mynew != NULL) {
- act_new2 = act_old->mynew;
- if (!(act_new2 == act_new || BLI_findindex(&ob_new->actuators, act_new2) >= 0)) {
- act_new2 = NULL;
- }
- }
- else if (act_new && act_old->type != act_new->type) {
- act_new2 = NULL;
- }
-
- BLI_ghash_insert(actuators_map, act_old, act_new2);
-
- if (act_new) {
- act_new = act_new->next;
- }
- }
-
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
- if (controllers_map != NULL) {
- for (bSensor *sens = ob->sensors.first; sens; sens = sens->next) {
- for (int a = 0; a < sens->totlinks; a++) {
- if (sens->links[a]) {
- bController *old_link = sens->links[a];
- bController **new_link_p = (bController **)BLI_ghash_lookup_p(controllers_map, old_link);
-
- if (new_link_p == NULL) {
- /* old_link is *not* in map's keys (i.e. not to any ob_old->controllers),
- * which means we ignore it totally here. */
- }
- else if (*new_link_p == NULL) {
- unlink_logicbricks((void **)&old_link, (void ***)&(sens->links), &sens->totlinks);
- a--;
- }
- else {
- sens->links[a] = *new_link_p;
- }
- }
- }
- }
- }
-
- if (actuators_map != NULL) {
- for (bController *cont = ob->controllers.first; cont; cont = cont->next) {
- for (int a = 0; a < cont->totlinks; a++) {
- if (cont->links[a]) {
- bActuator *old_link = cont->links[a];
- bActuator **new_link_p = (bActuator **)BLI_ghash_lookup_p(actuators_map, old_link);
-
- if (new_link_p == NULL) {
- /* old_link is *not* in map's keys (i.e. not to any ob_old->actuators),
- * which means we ignore it totally here. */
- }
- else if (*new_link_p == NULL) {
- unlink_logicbricks((void **)&old_link, (void ***)&(cont->links), &cont->totlinks);
- a--;
- }
- else {
- cont->links[a] = *new_link_p;
- }
- }
- }
- }
- }
- }
-
- if (controllers_map) {
- BLI_ghash_free(controllers_map, NULL, NULL);
- }
- if (actuators_map) {
- BLI_ghash_free(actuators_map, NULL, NULL);
- }
-}
-
-/**
- * Handle the copying of logic data into a new object, including internal logic links update.
- * External links (links between logic bricks of different objects) must be handled separately.
- */
-void BKE_sca_logic_copy(Object *ob_new, const Object *ob, const int flag)
-{
- copy_sensors(&ob_new->sensors, &ob->sensors, flag);
- copy_controllers(&ob_new->controllers, &ob->controllers, flag);
- copy_actuators(&ob_new->actuators, &ob->actuators, flag);
-
- for (bSensor *sens = ob_new->sensors.first; sens; sens = sens->next) {
- if (sens->flag & SENS_NEW) {
- for (int a = 0; a < sens->totlinks; a++) {
- if (sens->links[a] && sens->links[a]->mynew) {
- sens->links[a] = sens->links[a]->mynew;
- }
- }
- }
- }
-
- for (bController *cont = ob_new->controllers.first; cont; cont = cont->next) {
- if (cont->flag & CONT_NEW) {
- for (int a = 0; a < cont->totlinks; a++) {
- if (cont->links[a] && cont->links[a]->mynew) {
- cont->links[a] = cont->links[a]->mynew;
- }
- }
- }
- }
-}
-
-/* ******************** INTERFACE ******************* */
-void sca_move_sensor(bSensor *sens_to_move, Object *ob, int move_up)
-{
- bSensor *sens, *tmp;
-
- int val;
- val = move_up ? 1 : 2;
-
- /* make sure this sensor belongs to this object */
- sens= ob->sensors.first;
- while (sens) {
- if (sens == sens_to_move) break;
- sens= sens->next;
- }
- if (!sens) return;
-
- /* move up */
- if (val == 1 && sens->prev) {
- for (tmp=sens->prev; tmp; tmp=tmp->prev) {
- if (tmp->flag & SENS_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->sensors, sens);
- BLI_insertlinkbefore(&ob->sensors, tmp, sens);
- }
- }
- /* move down */
- else if (val == 2 && sens->next) {
- for (tmp=sens->next; tmp; tmp=tmp->next) {
- if (tmp->flag & SENS_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->sensors, sens);
- BLI_insertlinkafter(&ob->sensors, tmp, sens);
- }
- }
-}
-
-void sca_move_controller(bController *cont_to_move, Object *ob, int move_up)
-{
- bController *cont, *tmp;
-
- int val;
- val = move_up ? 1 : 2;
-
- /* make sure this controller belongs to this object */
- cont= ob->controllers.first;
- while (cont) {
- if (cont == cont_to_move) break;
- cont= cont->next;
- }
- if (!cont) return;
-
- /* move up */
- if (val == 1 && cont->prev) {
- /* locate the controller that has the same state mask but is earlier in the list */
- tmp = cont->prev;
- while (tmp) {
- if (tmp->state_mask & cont->state_mask)
- break;
- tmp = tmp->prev;
- }
- if (tmp) {
- BLI_remlink(&ob->controllers, cont);
- BLI_insertlinkbefore(&ob->controllers, tmp, cont);
- }
- }
-
- /* move down */
- else if (val == 2 && cont->next) {
- tmp = cont->next;
- while (tmp) {
- if (tmp->state_mask & cont->state_mask)
- break;
- tmp = tmp->next;
- }
- BLI_remlink(&ob->controllers, cont);
- BLI_insertlinkafter(&ob->controllers, tmp, cont);
- }
-}
-
-void sca_move_actuator(bActuator *act_to_move, Object *ob, int move_up)
-{
- bActuator *act, *tmp;
- int val;
-
- val = move_up ? 1 : 2;
-
- /* make sure this actuator belongs to this object */
- act= ob->actuators.first;
- while (act) {
- if (act == act_to_move) break;
- act= act->next;
- }
- if (!act) return;
-
- /* move up */
- if (val == 1 && act->prev) {
- /* locate the first visible actuators before this one */
- for (tmp = act->prev; tmp; tmp=tmp->prev) {
- if (tmp->flag & ACT_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->actuators, act);
- BLI_insertlinkbefore(&ob->actuators, tmp, act);
- }
- }
- /* move down */
- else if (val == 2 && act->next) {
- /* locate the first visible actuators after this one */
- for (tmp=act->next; tmp; tmp=tmp->next) {
- if (tmp->flag & ACT_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->actuators, act);
- BLI_insertlinkafter(&ob->actuators, tmp, act);
- }
- }
-}
-
-void link_logicbricks(void **poin, void ***ppoin, short *tot, short size)
-{
- void **old_links= NULL;
-
- int ibrick;
-
- /* check if the bricks are already linked */
- for (ibrick=0; ibrick < *tot; ibrick++) {
- if ((*ppoin)[ibrick] == *poin)
- return;
- }
-
- if (*ppoin) {
- old_links= *ppoin;
-
- (*tot) ++;
- *ppoin = MEM_callocN((*tot)*size, "new link");
-
- for (ibrick=0; ibrick < *(tot) - 1; ibrick++) {
- (*ppoin)[ibrick] = old_links[ibrick];
- }
- (*ppoin)[ibrick] = *poin;
-
- if (old_links) MEM_freeN(old_links);
- }
- else {
- (*tot) = 1;
- *ppoin = MEM_callocN((*tot)*size, "new link");
- (*ppoin)[0] = *poin;
- }
-}
-
-void unlink_logicbricks(void **poin, void ***ppoin, short *tot)
-{
- int ibrick, removed;
-
- removed= 0;
- for (ibrick=0; ibrick < *tot; ibrick++) {
- if (removed) (*ppoin)[ibrick - removed] = (*ppoin)[ibrick];
- else if ((*ppoin)[ibrick] == *poin) removed = 1;
- }
-
- if (removed) {
- (*tot) --;
-
- if (*tot == 0) {
- MEM_freeN(*ppoin);
- (*ppoin)= NULL;
- }
- return;
- }
-}
-
-void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *userdata)
-{
- bSensor *sensor;
-
- for (sensor = senslist->first; sensor; sensor = sensor->next) {
- func(sensor, (ID **)&sensor->ob, userdata, IDWALK_CB_NOP);
-
- switch (sensor->type) {
- case SENS_TOUCH: /* DEPRECATED */
- {
- bTouchSensor *ts = sensor->data;
- func(sensor, (ID **)&ts->ma, userdata, IDWALK_CB_NOP);
- break;
- }
- case SENS_MESSAGE:
- {
- bMessageSensor *ms = sensor->data;
- func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_CB_NOP);
- break;
- }
- case SENS_ALWAYS:
- case SENS_NEAR:
- case SENS_KEYBOARD:
- case SENS_PROPERTY:
- case SENS_MOUSE:
- case SENS_COLLISION:
- case SENS_RADAR:
- case SENS_RANDOM:
- case SENS_RAY:
- case SENS_JOYSTICK:
- case SENS_ACTUATOR:
- case SENS_DELAY:
- case SENS_ARMATURE:
- default:
- break;
- }
- }
-}
-
-void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, void *userdata)
-{
- bController *controller;
-
- for (controller = contlist->first; controller; controller = controller->next) {
- switch (controller->type) {
- case CONT_PYTHON:
- {
- bPythonCont *pc = controller->data;
- func(controller, (ID **)&pc->text, userdata, IDWALK_CB_NOP);
- break;
- }
- case CONT_LOGIC_AND:
- case CONT_LOGIC_OR:
- case CONT_EXPRESSION:
- case CONT_LOGIC_NAND:
- case CONT_LOGIC_NOR:
- case CONT_LOGIC_XOR:
- case CONT_LOGIC_XNOR:
- default:
- break;
- }
- }
-}
-
-void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void *userdata)
-{
- bActuator *actuator;
-
- for (actuator = actlist->first; actuator; actuator = actuator->next) {
- func(actuator, (ID **)&actuator->ob, userdata, IDWALK_CB_NOP);
-
- switch (actuator->type) {
- case ACT_ADD_OBJECT: /* DEPRECATED */
- {
- bAddObjectActuator *aoa = actuator->data;
- func(actuator, (ID **)&aoa->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_ACTION:
- {
- bActionActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->act, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_SOUND:
- {
- bSoundActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->sound, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_EDIT_OBJECT:
- {
- bEditObjectActuator *eoa = actuator->data;
- func(actuator, (ID **)&eoa->ob, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&eoa->me, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_SCENE:
- {
- bSceneActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->scene, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&sa->camera, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_PROPERTY:
- {
- bPropertyActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_OBJECT:
- {
- bObjectActuator *oa = actuator->data;
- func(actuator, (ID **)&oa->reference, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_CAMERA:
- {
- bCameraActuator *ca = actuator->data;
- func(actuator, (ID **)&ca->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_MESSAGE:
- {
- bMessageActuator *ma = actuator->data;
- func(actuator, (ID **)&ma->toObject, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_2DFILTER:
- {
- bTwoDFilterActuator *tdfa = actuator->data;
- func(actuator, (ID **)&tdfa->text, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_PARENT:
- {
- bParentActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_ARMATURE:
- {
- bArmatureActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->target, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_STEERING:
- {
- bSteeringActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->target, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_CB_NOP);
- break;
- }
- /* Note: some types seems to be non-implemented? ACT_LAMP, ACT_MATERIAL... */
- case ACT_LAMP:
- case ACT_MATERIAL:
- case ACT_END_OBJECT: /* DEPRECATED */
- case ACT_CONSTRAINT:
- case ACT_GROUP:
- case ACT_RANDOM:
- case ACT_GAME:
- case ACT_VISIBILITY:
- case ACT_SHAPEACTION:
- case ACT_STATE:
- case ACT_MOUSE:
- default:
- break;
- }
- }
-}
-
-const char *sca_state_name_get(Object *ob, short bit)
-{
- bController *cont;
- unsigned int mask;
-
- mask = (1<<bit);
- cont = ob->controllers.first;
- while (cont) {
- if (cont->state_mask & mask) {
- return cont->name;
- }
- cont = cont->next;
- }
- return NULL;
-}
-
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index a1003910ca3..ba13a8eca2a 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -49,6 +49,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_gpencil_types.h"
#include "BLI_math.h"
@@ -67,17 +68,17 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_cachefile.h"
+#include "BKE_collection.h"
#include "BKE_colortools.h"
-#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_group.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -92,9 +93,13 @@
#include "BKE_sequencer.h"
#include "BKE_sound.h"
#include "BKE_unit.h"
+#include "BKE_workspace.h"
#include "BKE_world.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
#include "RE_engine.h"
@@ -105,8 +110,8 @@
#include "bmesh.h"
-const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER";
-const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME";
+const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
+const char *RE_engine_id_BLENDER_WORKBENCH = "BLENDER_WORKBENCH";
const char *RE_engine_id_CYCLES = "CYCLES";
void free_avicodecdata(AviCodecData *acd)
@@ -234,25 +239,25 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
sce_dst->ed = NULL;
- sce_dst->theDag = NULL;
- sce_dst->depsgraph = NULL;
- sce_dst->obedit = NULL;
- sce_dst->stats = NULL;
+ sce_dst->depsgraph_hash = NULL;
sce_dst->fps_info = NULL;
- BLI_duplicatelist(&(sce_dst->base), &(sce_src->base));
- for (Base *base_dst = sce_dst->base.first, *base_src = sce_src->base.first;
- base_dst;
- base_dst = base_dst->next, base_src = base_src->next)
+ /* Master Collection */
+ if (sce_src->master_collection) {
+ sce_dst->master_collection = BKE_collection_copy_master(bmain, sce_src->master_collection, flag);
+ }
+
+ /* View Layers */
+ BLI_duplicatelist(&sce_dst->view_layers, &sce_src->view_layers);
+ for (ViewLayer *view_layer_src = sce_src->view_layers.first, *view_layer_dst = sce_dst->view_layers.first;
+ view_layer_src;
+ view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next)
{
- if (base_src == sce_src->basact) {
- sce_dst->basact = base_dst;
- }
+ BKE_view_layer_copy_data(sce_dst, sce_src, view_layer_dst, view_layer_src, flag_subdata);
}
BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers));
BLI_duplicatelist(&(sce_dst->transform_spaces), &(sce_src->transform_spaces));
- BLI_duplicatelist(&(sce_dst->r.layers), &(sce_src->r.layers));
BLI_duplicatelist(&(sce_dst->r.views), &(sce_src->r.views));
BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets));
@@ -267,17 +272,6 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
sce_dst->rigidbody_world = BKE_rigidbody_world_copy(sce_src->rigidbody_world, flag_subdata);
}
- /* copy Freestyle settings */
- for (SceneRenderLayer *srl_dst = sce_dst->r.layers.first, *srl_src = sce_src->r.layers.first;
- srl_src;
- srl_dst = srl_dst->next, srl_src = srl_src->next)
- {
- if (srl_dst->prop != NULL) {
- srl_dst->prop = IDP_CopyProperty_ex(srl_dst->prop, flag_subdata);
- }
- BKE_freestyle_config_copy(&srl_dst->freestyleConfig, &srl_src->freestyleConfig, flag_subdata);
- }
-
/* copy color management settings */
BKE_color_managed_display_settings_copy(&sce_dst->display_settings, &sce_src->display_settings);
BKE_color_managed_view_settings_copy(&sce_dst->view_settings, &sce_src->view_settings);
@@ -331,20 +325,16 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* TODO this should/could most likely be replaced by call to more generic code at some point...
* But for now, let's keep it well isolated here. */
if (type == SCE_COPY_EMPTY) {
- ListBase rl, rv;
+ ListBase rv;
sce_copy = BKE_scene_add(bmain, sce->id.name + 2);
- rl = sce_copy->r.layers;
rv = sce_copy->r.views;
curvemapping_free_data(&sce_copy->r.mblur_shutter_curve);
sce_copy->r = sce->r;
- sce_copy->r.layers = rl;
- sce_copy->r.actlay = 0;
sce_copy->r.views = rv;
sce_copy->unit = sce->unit;
sce_copy->physics_settings = sce->physics_settings;
- sce_copy->gm = sce->gm;
sce_copy->audio = sce->audio;
if (sce->id.properties)
@@ -399,8 +389,8 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (type == SCE_COPY_FULL) {
/* Copy Freestyle LineStyle datablocks. */
- for (SceneRenderLayer *srl_dst = sce_copy->r.layers.first; srl_dst; srl_dst = srl_dst->next) {
- for (FreestyleLineSet *lineset = srl_dst->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ for (ViewLayer *view_layer_dst = sce_copy->view_layers.first; view_layer_dst; view_layer_dst = view_layer_dst->next) {
+ for (FreestyleLineSet *lineset = view_layer_dst->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
if (lineset->linestyle) {
/* XXX Not copying anim/actions here? */
BKE_id_copy_ex(bmain, (ID *)lineset->linestyle, (ID **)&lineset->linestyle, 0, false);
@@ -413,6 +403,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS, false);
}
+ /* Collections */
+ BKE_collection_copy_full(bmain, sce_copy->master_collection);
+
/* Full copy of GreasePencil. */
/* XXX Not copying anim/actions here? */
if (sce_copy->gpd) {
@@ -452,15 +445,11 @@ void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local)
}
/** Free (or release) any data used by this scene (does not free the scene itself). */
-void BKE_scene_free(Scene *sce)
+void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
{
- SceneRenderLayer *srl;
-
BKE_animdata_free((ID *)sce, false);
- sce->basact = NULL;
- BLI_freelistN(&sce->base);
- BKE_sequencer_editing_free(sce, false);
+ BKE_sequencer_editing_free(sce, do_id_user);
BKE_keyingsets_free(&sce->keyingsets);
@@ -487,27 +476,15 @@ void BKE_scene_free(Scene *sce)
sce->r.ffcodecdata.properties = NULL;
}
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- if (srl->prop != NULL) {
- IDP_FreeProperty(srl->prop);
- MEM_freeN(srl->prop);
- }
- BKE_freestyle_config_free(&srl->freestyleConfig);
- }
-
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->transform_spaces);
- BLI_freelistN(&sce->r.layers);
BLI_freelistN(&sce->r.views);
BKE_toolsettings_free(sce->toolsettings);
sce->toolsettings = NULL;
- DAG_scene_free(sce);
- if (sce->depsgraph)
- DEG_graph_free(sce->depsgraph);
+ BKE_scene_free_depsgraph_hash(sce);
- MEM_SAFE_FREE(sce->stats);
MEM_SAFE_FREE(sce->fps_info);
BKE_sound_destroy_scene(sce);
@@ -516,6 +493,32 @@ void BKE_scene_free(Scene *sce)
BKE_previewimg_free(&sce->preview);
curvemapping_free_data(&sce->r.mblur_shutter_curve);
+
+ for (ViewLayer *view_layer = sce->view_layers.first, *view_layer_next; view_layer; view_layer = view_layer_next) {
+ view_layer_next = view_layer->next;
+
+ BLI_remlink(&sce->view_layers, view_layer);
+ BKE_view_layer_free_ex(view_layer, do_id_user);
+ }
+
+ /* Master Collection */
+ // TODO: what to do with do_id_user? it's also true when just
+ // closing the file which seems wrong? should decrement users
+ // for objects directly in the master collection? then other
+ // collections in the scene need to do it too?
+ if (sce->master_collection) {
+ BKE_collection_free(sce->master_collection);
+ MEM_freeN(sce->master_collection);
+ sce->master_collection = NULL;
+ }
+
+ /* These are freed on doversion. */
+ BLI_assert(sce->layer_properties == NULL);
+}
+
+void BKE_scene_free(Scene *sce)
+{
+ BKE_scene_free_ex(sce, true);
}
void BKE_scene_init(Scene *sce)
@@ -530,7 +533,7 @@ void BKE_scene_init(Scene *sce)
sce->lay = sce->layact = 1;
- sce->r.mode = R_GAMMA | R_OSA | R_SHADOW | R_SSS | R_ENVMAP | R_RAYTRACE;
+ sce->r.mode = R_OSA;
sce->r.cfra = 1;
sce->r.sfra = 1;
sce->r.efra = 250;
@@ -541,9 +544,7 @@ void BKE_scene_init(Scene *sce)
sce->r.yasp = 1;
sce->r.tilex = 256;
sce->r.tiley = 256;
- sce->r.mblur_samples = 1;
- sce->r.filtertype = R_FILTER_MITCH;
- sce->r.size = 50;
+ sce->r.size = 100;
sce->r.im_format.planes = R_IMF_PLANES_RGBA;
sce->r.im_format.imtype = R_IMF_IMTYPE_PNG;
@@ -551,15 +552,13 @@ void BKE_scene_init(Scene *sce)
sce->r.im_format.quality = 90;
sce->r.im_format.compress = 15;
- sce->r.displaymode = R_OUTPUT_AREA;
+ sce->r.displaymode = R_OUTPUT_WINDOW;
sce->r.framapto = 100;
sce->r.images = 100;
sce->r.framelen = 1.0;
sce->r.blurfac = 0.5;
sce->r.frs_sec = 24;
sce->r.frs_sec_base = 1;
- sce->r.edgeint = 10;
- sce->r.ocres = 128;
/* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used,
* images would look in the same way as in current blender
@@ -568,18 +567,11 @@ void BKE_scene_init(Scene *sce)
*/
sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT;
- sce->r.gauss = 1.0;
-
- /* deprecated but keep for upwards compat */
- sce->r.postgamma = 1.0;
- sce->r.posthue = 0.0;
- sce->r.postsat = 1.0;
+ sce->r.dither_intensity = 1.0f;
- sce->r.bake_mode = 1; /* prevent to include render stuff here */
+ sce->r.bake_mode = 0;
sce->r.bake_filter = 16;
- sce->r.bake_osa = 5;
sce->r.bake_flag = R_BAKE_CLEAR;
- sce->r.bake_normal_space = R_BAKE_SPACE_TANGENT;
sce->r.bake_samples = 256;
sce->r.bake_biasdist = 0.001;
@@ -607,7 +599,6 @@ void BKE_scene_init(Scene *sce)
sce->r.fg_stamp[3] = 1.0f;
sce->r.bg_stamp[0] = sce->r.bg_stamp[1] = sce->r.bg_stamp[2] = 0.0f;
sce->r.bg_stamp[3] = 0.25f;
- sce->r.raytrace_options = R_RAYTRACE_USE_INSTANCES;
sce->r.seq_prev_type = OB_SOLID;
sce->r.seq_rend_type = OB_SOLID;
@@ -617,8 +608,6 @@ void BKE_scene_init(Scene *sce)
sce->r.simplify_subsurf = 6;
sce->r.simplify_particles = 1.0f;
- sce->r.simplify_shadowsamples = 16;
- sce->r.simplify_aosss = 1.0f;
sce->r.border.xmin = 0.0f;
sce->r.border.ymin = 0.0f;
@@ -639,33 +628,25 @@ void BKE_scene_init(Scene *sce)
CURVEMAP_SLOPE_POS_NEG);
sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct");
+
+ sce->toolsettings->object_flag |= SCE_OBJECT_MODE_LOCK;
sce->toolsettings->doublimit = 0.001;
sce->toolsettings->vgroup_weight = 1.0f;
sce->toolsettings->uvcalc_margin = 0.001f;
+ sce->toolsettings->uvcalc_flag = UVCALC_TRANSFORM_CORRECT;
sce->toolsettings->unwrapper = 1;
sce->toolsettings->select_thresh = 0.01f;
+ sce->toolsettings->manipulator_flag = SCE_MANIP_TRANSLATE | SCE_MANIP_ROTATE | SCE_MANIP_SCALE;
sce->toolsettings->selectmode = SCE_SELECT_VERTEX;
sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX;
- sce->toolsettings->normalsize = 0.1;
sce->toolsettings->autokey_mode = U.autokey_mode;
- sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
- sce->toolsettings->skgen_resolution = 100;
- sce->toolsettings->skgen_threshold_internal = 0.01f;
- sce->toolsettings->skgen_threshold_external = 0.01f;
- sce->toolsettings->skgen_angle_limit = 45.0f;
- sce->toolsettings->skgen_length_ratio = 1.3f;
- sce->toolsettings->skgen_length_limit = 1.5f;
- sce->toolsettings->skgen_correlation_limit = 0.98f;
- sce->toolsettings->skgen_symmetry_limit = 0.1f;
- sce->toolsettings->skgen_postpro = SKGEN_SMOOTH;
- sce->toolsettings->skgen_postpro_passes = 1;
- sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL | SKGEN_FILTER_EXTERNAL | SKGEN_FILTER_SMART | SKGEN_HARMONIC | SKGEN_SUB_CORRELATION | SKGEN_STICK_TO_EMBEDDING;
- sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
- sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
- sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
+ sce->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEAN;
+ sce->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT;
+ sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
+ sce->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT;
sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
@@ -695,6 +676,7 @@ void BKE_scene_init(Scene *sce)
sce->physics_settings.gravity[2] = -9.81f;
sce->physics_settings.flag = PHYS_GLOBAL_GRAVITY;
+ sce->unit.system = USER_UNIT_METRIC;
sce->unit.scale_length = 1.0f;
pset = &sce->toolsettings->particle;
@@ -720,12 +702,13 @@ void BKE_scene_init(Scene *sce)
sce->r.ffcodecdata.audio_bitrate = 192;
sce->r.ffcodecdata.audio_channels = 2;
- BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_RENDER, sizeof(sce->r.engine));
+ BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
sce->audio.distance_model = 2.0f;
sce->audio.doppler_factor = 1.0f;
sce->audio.speed_of_sound = 343.3f;
sce->audio.volume = 1.0f;
+ sce->audio.flag = AUDIO_SYNC;
BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic));
@@ -733,7 +716,6 @@ void BKE_scene_init(Scene *sce)
sce->r.osa = 8;
/* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
- BKE_scene_add_render_layer(sce, NULL);
/* multiview - stereo */
BKE_scene_add_render_view(sce, STEREO_LEFT_NAME);
@@ -744,59 +726,6 @@ void BKE_scene_init(Scene *sce)
srv = sce->r.views.last;
BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
- /* game data */
- sce->gm.stereoflag = STEREO_NOSTEREO;
- sce->gm.stereomode = STEREO_ANAGLYPH;
- sce->gm.eyeseparation = 0.10;
-
- sce->gm.dome.angle = 180;
- sce->gm.dome.mode = DOME_FISHEYE;
- sce->gm.dome.res = 4;
- sce->gm.dome.resbuf = 1.0f;
- sce->gm.dome.tilt = 0;
-
- sce->gm.xplay = 640;
- sce->gm.yplay = 480;
- sce->gm.freqplay = 60;
- sce->gm.depth = 32;
-
- sce->gm.gravity = 9.8f;
- sce->gm.physicsEngine = WOPHY_BULLET;
- sce->gm.mode = 32; //XXX ugly harcoding, still not sure we should drop mode. 32 == 1 << 5 == use_occlusion_culling
- sce->gm.occlusionRes = 128;
- sce->gm.ticrate = 60;
- sce->gm.maxlogicstep = 5;
- sce->gm.physubstep = 1;
- sce->gm.maxphystep = 5;
- sce->gm.lineardeactthreshold = 0.8f;
- sce->gm.angulardeactthreshold = 1.0f;
- sce->gm.deactivationtime = 0.0f;
-
- sce->gm.flag = GAME_DISPLAY_LISTS;
- sce->gm.matmode = GAME_MAT_MULTITEX;
-
- sce->gm.obstacleSimulation = OBSTSIMULATION_NONE;
- sce->gm.levelHeight = 2.f;
-
- sce->gm.recastData.cellsize = 0.3f;
- sce->gm.recastData.cellheight = 0.2f;
- 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;
- sce->gm.recastData.edgemaxlen = 12.0f;
- sce->gm.recastData.edgemaxerror = 1.3f;
- sce->gm.recastData.regionminsize = 8.f;
- sce->gm.recastData.regionmergesize = 20.f;
- sce->gm.recastData.vertsperpoly = 6;
- sce->gm.recastData.detailsampledist = 6.0f;
- sce->gm.recastData.detailsamplemaxerror = 1.0f;
-
- sce->gm.lodflag = SCE_LOD_USE_HYST;
- sce->gm.scehysteresis = 10;
-
- sce->gm.exitkey = 218; // Blender key code for ESC
-
BKE_sound_create_scene(sce);
/* color management */
@@ -866,6 +795,75 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+
+ sce->orientation_index_custom = -1;
+
+ /* Master Collection */
+ sce->master_collection = BKE_collection_master_add();
+
+ BKE_view_layer_add(sce, "View Layer");
+
+ /* SceneDisplay */
+ copy_v3_v3(sce->display.light_direction, (float[3]){-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3});
+ sce->display.shadow_shift = 0.1;
+
+ sce->display.matcap_ssao_distance = 0.2f;
+ sce->display.matcap_ssao_attenuation = 1.0f;
+ sce->display.matcap_ssao_samples = 16;
+
+ /* SceneEEVEE */
+ sce->eevee.gi_diffuse_bounces = 3;
+ sce->eevee.gi_cubemap_resolution = 512;
+ sce->eevee.gi_visibility_resolution = 32;
+
+ sce->eevee.taa_samples = 16;
+ sce->eevee.taa_render_samples = 64;
+
+ sce->eevee.sss_samples = 7;
+ sce->eevee.sss_jitter_threshold = 0.3f;
+
+ sce->eevee.ssr_quality = 0.25f;
+ sce->eevee.ssr_max_roughness = 0.5f;
+ sce->eevee.ssr_thickness = 0.2f;
+ sce->eevee.ssr_border_fade = 0.075f;
+ sce->eevee.ssr_firefly_fac = 10.0f;
+
+ sce->eevee.volumetric_start = 0.1f;
+ sce->eevee.volumetric_end = 100.0f;
+ sce->eevee.volumetric_tile_size = 8;
+ sce->eevee.volumetric_samples = 64;
+ sce->eevee.volumetric_sample_distribution = 0.8f;
+ sce->eevee.volumetric_light_clamp = 0.0f;
+ sce->eevee.volumetric_shadow_samples = 16;
+
+ sce->eevee.gtao_distance = 0.2f;
+ sce->eevee.gtao_factor = 1.0f;
+ sce->eevee.gtao_quality = 0.25f;
+
+ sce->eevee.bokeh_max_size = 100.0f;
+ sce->eevee.bokeh_threshold = 1.0f;
+
+ copy_v3_fl(sce->eevee.bloom_color, 1.0f);
+ sce->eevee.bloom_threshold = 0.8f;
+ sce->eevee.bloom_knee = 0.5f;
+ sce->eevee.bloom_intensity = 0.8f;
+ sce->eevee.bloom_radius = 6.5f;
+ sce->eevee.bloom_clamp = 1.0f;
+
+ sce->eevee.motion_blur_samples = 8;
+ sce->eevee.motion_blur_shutter = 1.0f;
+
+ sce->eevee.shadow_method = SHADOW_ESM;
+ sce->eevee.shadow_cube_size = 512;
+ sce->eevee.shadow_cascade_size = 1024;
+
+ sce->eevee.flag =
+ SCE_EEVEE_VOLUMETRIC_LIGHTS |
+ SCE_EEVEE_VOLUMETRIC_COLORED |
+ SCE_EEVEE_GTAO_BENT_NORMALS |
+ SCE_EEVEE_GTAO_BOUNCE |
+ SCE_EEVEE_TAA_REPROJECTION |
+ SCE_EEVEE_SSR_HALF_RESOLUTION;
}
Scene *BKE_scene_add(Main *bmain, const char *name)
@@ -881,75 +879,54 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
-Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
+/**
+ * Check if there is any intance of the object in the scene
+ */
+bool BKE_scene_object_find(Scene *scene, Object *ob)
{
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- if (STREQ(base->object->id.name + 2, name)) {
- break;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object))) {
+ return true;
}
}
-
- return base;
+ return false;
}
-Base *BKE_scene_base_find(Scene *scene, Object *ob)
+Object *BKE_scene_object_find_by_name(Scene *scene, const char *name)
{
- return BLI_findptr(&scene->base, ob, offsetof(Base, object));
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (STREQ(base->object->id.name + 2, name)) {
+ return base->object;
+ }
+ }
+ }
+ return NULL;
}
/**
* Sets the active scene, mainly used when running in background mode (``--scene`` command line argument).
* This is also called to set the scene directly, bypassing windowing code.
- * Otherwise #ED_screen_set_scene is used when changing scenes by the user.
+ * Otherwise #WM_window_change_active_scene is used when changing scenes by the user.
*/
void BKE_scene_set_background(Main *bmain, Scene *scene)
{
- Scene *sce;
- Base *base;
Object *ob;
- Group *group;
- GroupObject *go;
- int flag;
/* check for cyclic sets, for reading old files but also for definite security (py?) */
BKE_scene_validate_setscene(bmain, scene);
- /* can happen when switching modes in other scenes */
- if (scene->obedit && !(scene->obedit->mode & OB_MODE_EDIT))
- scene->obedit = NULL;
-
/* deselect objects (for dataselect) */
for (ob = bmain->object.first; ob; ob = ob->id.next)
- ob->flag &= ~(SELECT | OB_FROMGROUP);
-
- /* group flags again */
- for (group = bmain->group.first; group; group = group->id.next) {
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob) {
- go->ob->flag |= OB_FROMGROUP;
- }
- }
- }
-
- /* sort baselist for scene and sets */
- for (sce = scene; sce; sce = sce->set)
- DAG_scene_relations_rebuild(bmain, sce);
+ ob->flag &= ~SELECT;
/* copy layers and flags from bases to objects */
- for (base = scene->base.first; base; base = base->next) {
- ob = base->object;
- ob->lay = base->lay;
-
- /* group patch... */
- base->flag &= ~(OB_FROMGROUP);
- flag = ob->flag & (OB_FROMGROUP);
- base->flag |= flag;
-
- /* not too nice... for recovering objects with lost data */
- //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE;
- ob->flag = base->flag;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ ob = base->object;
+ /* collection patch... */
+ BKE_scene_object_base_flag_sync_from_base(base);
+ }
}
/* no full animation update, this to enable render code to work (render code calls own animation updates) */
}
@@ -969,8 +946,8 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
}
/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
-int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBaseIter *iter,
- Scene **scene, int val, Base **base, Object **ob)
+int BKE_scene_base_iter_next(Depsgraph *depsgraph, SceneBaseIter *iter,
+ Scene **scene, int val, Base **base, Object **ob)
{
bool run_again = true;
@@ -988,17 +965,21 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
/* the first base */
if (iter->phase == F_START) {
- *base = (*scene)->base.first;
+ ViewLayer *view_layer = (depsgraph) ?
+ DEG_get_evaluated_view_layer(depsgraph) :
+ BKE_view_layer_context_active_PLACEHOLDER(*scene);
+ *base = view_layer->object_bases.first;
if (*base) {
*ob = (*base)->object;
iter->phase = F_SCENE;
}
else {
- /* exception: empty scene */
+ /* exception: empty scene layer */
while ((*scene)->set) {
(*scene) = (*scene)->set;
- if ((*scene)->base.first) {
- *base = (*scene)->base.first;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
+ if (view_layer_set->object_bases.first) {
+ *base = view_layer_set->object_bases.first;
*ob = (*base)->object;
iter->phase = F_SCENE;
break;
@@ -1017,8 +998,9 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
/* (*scene) is finished, now do the set */
while ((*scene)->set) {
(*scene) = (*scene)->set;
- if ((*scene)->base.first) {
- *base = (*scene)->base.first;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
+ if (view_layer_set->object_bases.first) {
+ *base = view_layer_set->object_bases.first;
*ob = (*base)->object;
break;
}
@@ -1033,12 +1015,12 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
else {
if (iter->phase != F_DUPLI) {
- if ( (*base)->object->transflag & OB_DUPLI) {
- /* groups cannot be duplicated for mballs yet,
+ if (depsgraph && (*base)->object->transflag & OB_DUPLI) {
+ /* collections cannot be duplicated for mballs yet,
* this enters eternal loop because of
- * makeDispListMBall getting called inside of group_duplilist */
+ * makeDispListMBall getting called inside of collection_duplilist */
if ((*base)->object->dup_group == NULL) {
- iter->duplilist = object_duplilist_ex(bmain, eval_ctx, (*scene), (*base)->object, false);
+ iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object);
iter->dupob = iter->duplilist->first;
@@ -1052,7 +1034,7 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
/* handle dupli's */
if (iter->dupob) {
- (*base)->flag |= OB_FROMDUPLI;
+ (*base)->flag_legacy |= OB_FROMDUPLI;
*ob = iter->dupob->ob;
iter->phase = F_DUPLI;
@@ -1071,7 +1053,7 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
else if (iter->phase == F_DUPLI) {
iter->phase = F_SCENE;
- (*base)->flag &= ~OB_FROMDUPLI;
+ (*base)->flag_legacy &= ~OB_FROMDUPLI;
if (iter->dupli_refob) {
/* Restore last object's real matrix. */
@@ -1096,13 +1078,15 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
return iter->phase;
}
-Object *BKE_scene_camera_find(Scene *sc)
+Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection)
{
- Base *base;
-
- for (base = sc->base.first; base; base = base->next)
- if (base->object->type == OB_CAMERA)
- return base->object;
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (ViewLayer *layer = scene->view_layers.first; layer; layer = layer->next) {
+ if (BKE_view_layer_has_collection(layer, collection)) {
+ return scene;
+ }
+ }
+ }
return NULL;
}
@@ -1204,49 +1188,14 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame)
return best_marker ? best_marker->name : NULL;
}
-
-Base *BKE_scene_base_add(Scene *sce, Object *ob)
-{
- Base *b = MEM_callocN(sizeof(*b), __func__);
- BLI_addhead(&sce->base, b);
-
- b->object = ob;
- b->flag = ob->flag;
- b->lay = ob->lay;
-
- return b;
-}
-
-void BKE_scene_base_unlink(Scene *sce, Base *base)
+void BKE_scene_remove_rigidbody_object(struct Main *bmain, Scene *scene, Object *ob)
{
/* remove rigid body constraint from world before removing object */
- if (base->object->rigidbody_constraint)
- BKE_rigidbody_remove_constraint(sce, base->object);
+ if (ob->rigidbody_constraint)
+ BKE_rigidbody_remove_constraint(scene, ob);
/* remove rigid body object from world before removing object */
- if (base->object->rigidbody_object)
- BKE_rigidbody_remove_object(sce, base->object);
-
- BLI_remlink(&sce->base, base);
- if (sce->basact == base)
- sce->basact = NULL;
-}
-
-void BKE_scene_base_deselect_all(Scene *sce)
-{
- Base *b;
-
- for (b = sce->base.first; b; b = b->next) {
- b->flag &= ~SELECT;
- b->object->flag = b->flag;
- }
-}
-
-void BKE_scene_base_select(Scene *sce, Base *selbase)
-{
- selbase->flag |= SELECT;
- selbase->object->flag = selbase->flag;
-
- sce->basact = selbase;
+ if (ob->rigidbody_object)
+ BKE_rigidbody_remove_object(bmain, scene, ob);
}
/* checks for cycle, returns 1 if it's all OK */
@@ -1298,109 +1247,6 @@ 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
- * - these happen after objects are all done so that we can read in their final transform values,
- * though this means that objects can't refer to scene info for guidance...
- */
-static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene)
-{
- SceneRenderLayer *srl;
- float ctime = BKE_scene_frame_get(scene);
-
- /* scene itself */
- if (scene->adt && scene->adt->drivers.first) {
- BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* world */
- /* TODO: what about world textures? but then those have nodes too... */
- if (scene->world) {
- ID *wid = (ID *)scene->world;
- AnimData *adt = BKE_animdata_from_id(wid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* nodes */
- if (scene->nodetree) {
- ID *nid = (ID *)scene->nodetree;
- AnimData *adt = BKE_animdata_from_id(nid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* world nodes */
- if (scene->world && scene->world->nodetree) {
- ID *nid = (ID *)scene->world->nodetree;
- AnimData *adt = BKE_animdata_from_id(nid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* freestyle */
- for (srl = scene->r.layers.first; srl; srl = srl->next) {
- FreestyleConfig *config = &srl->freestyleConfig;
- FreestyleLineSet *lineset;
-
- for (lineset = config->linesets.first; lineset; lineset = lineset->next) {
- if (lineset->linestyle) {
- ID *lid = &lineset->linestyle->id;
- AnimData *adt = BKE_animdata_from_id(lid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, lid, adt, ctime, ADT_RECALC_DRIVERS);
- }
- }
- }
-}
-
-/* deps hack - do extra recalcs at end */
-static void scene_depsgraph_hack(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent)
-{
- Base *base;
-
- scene->customdata_mask = scene_parent->customdata_mask;
-
- /* sets first, we allow per definition current scene to have
- * dependencies on sets, but not the other way around. */
- if (scene->set)
- scene_depsgraph_hack(bmain, eval_ctx, scene->set, scene_parent);
-
- for (base = scene->base.first; base; base = base->next) {
- Object *ob = base->object;
-
- if (ob->depsflag) {
- int recalc = 0;
- // printf("depshack %s\n", ob->id.name + 2);
-
- if (ob->depsflag & OB_DEPS_EXTRA_OB_RECALC)
- recalc |= OB_RECALC_OB;
- if (ob->depsflag & OB_DEPS_EXTRA_DATA_RECALC)
- recalc |= OB_RECALC_DATA;
-
- ob->recalc |= recalc;
- BKE_object_handle_update(bmain, eval_ctx, scene_parent, ob);
-
- if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) {
- GroupObject *go;
-
- for (go = ob->dup_group->gobject.first; go; go = go->next) {
- if (go->ob)
- go->ob->recalc |= recalc;
- }
- BKE_group_handle_recalc_and_update(bmain, eval_ctx, scene_parent, ob, ob->dup_group);
- }
- }
- }
-}
-#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.
* This happens when changing visible layers, which leads to situations when
@@ -1413,10 +1259,10 @@ static void scene_depsgraph_hack(Main *bmain, EvaluationContext *eval_ctx, Scene
#define POSE_ANIMATION_WORKAROUND
#ifdef POSE_ANIMATION_WORKAROUND
-static void scene_armature_depsgraph_workaround(Main *bmain)
+static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgraph)
{
Object *ob;
- if (BLI_listbase_is_empty(&bmain->armature) || !DAG_id_type_tagged(bmain, ID_OB)) {
+ if (BLI_listbase_is_empty(&bmain->armature) || !DEG_id_type_updated(depsgraph, ID_OB)) {
return;
}
for (ob = bmain->object.first; ob; ob = ob->id.next) {
@@ -1429,371 +1275,20 @@ 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)
- scene_rebuild_rbw_recursive(scene->set, ctime);
-
- if (BKE_scene_check_rigidbody_active(scene))
- BKE_rigidbody_rebuild_world(scene, ctime);
-}
-
-static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
-{
- if (scene->set)
- scene_do_rb_simulation_recursive(scene->set, 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.
- */
-#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
- * accessing and writing same data from multiple threads.
- *
- * Ideally Mballs shouldn't do such an iteration and use DAG
- * queries instead. For the time being we've got new DAG
- * let's keep it simple and update mballs in a single thread.
- */
-#define MBALL_SINGLETHREAD_HACK
-
-#ifdef WITH_LEGACY_DEPSGRAPH
-typedef struct StatisicsEntry {
- struct StatisicsEntry *next, *prev;
- Object *object;
- double start_time;
- double duration;
-} StatisicsEntry;
-
-typedef struct ThreadedObjectUpdateState {
- /* TODO(sergey): We might want this to be per-thread object. */
- EvaluationContext *eval_ctx;
- Main *bmain;
- Scene *scene;
- Scene *scene_parent;
- double base_time;
-
-#ifdef MBALL_SINGLETHREAD_HACK
- bool has_mballs;
-#endif
-
- int num_threads;
-
- /* Execution statistics */
- bool has_updated_objects;
- ListBase *statistics;
-} ThreadedObjectUpdateState;
-
-static void scene_update_object_add_task(void *node, void *user_data);
-
-static void scene_update_all_bases(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent)
-{
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- Object *object = base->object;
-
- BKE_object_handle_update_ex(bmain, eval_ctx, scene_parent, object, scene->rigidbody_world, true);
-
- if (object->dup_group && (object->transflag & OB_DUPLIGROUP))
- BKE_group_handle_recalc_and_update(bmain, eval_ctx, scene_parent, object, object->dup_group);
-
- /* always update layer, so that animating layers works (joshua july 2010) */
- /* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes
- * (on scene-set, the base-lay is copied to ob-lay (ton nov 2012) */
- // base->lay = ob->lay;
- }
-}
-
-static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata, int threadid)
-{
-/* Disable print for now in favor of summary statistics at the end of update. */
-#define PRINT if (false) printf
-
- ThreadedObjectUpdateState *state = (ThreadedObjectUpdateState *) BLI_task_pool_userdata(pool);
- void *node = taskdata;
- Object *object = DAG_get_node_object(node);
- EvaluationContext *eval_ctx = state->eval_ctx;
- Main *bmain = state->bmain;
- Scene *scene = state->scene;
- Scene *scene_parent = state->scene_parent;
-
-#ifdef MBALL_SINGLETHREAD_HACK
- if (object && object->type == OB_MBALL) {
- state->has_mballs = true;
- }
- else
-#endif
- if (object) {
- double start_time = 0.0;
- bool add_to_stats = false;
-
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- if (object->recalc & OB_RECALC_ALL) {
- printf("Thread %d: update object %s\n", threadid, object->id.name);
- }
-
- start_time = PIL_check_seconds_timer();
-
- if (object->recalc & OB_RECALC_ALL) {
- state->has_updated_objects = true;
- add_to_stats = true;
- }
- }
-
- /* We only update object itself here, dupli-group will be updated
- * separately from main thread because of we've got no idea about
- * dependencies inside the group.
- */
- BKE_object_handle_update_ex(bmain, eval_ctx, scene_parent, object, scene->rigidbody_world, false);
-
- /* Calculate statistics. */
- if (add_to_stats) {
- StatisicsEntry *entry;
-
- entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics");
- entry->object = object;
- entry->start_time = start_time;
- entry->duration = PIL_check_seconds_timer() - start_time;
-
- BLI_addtail(&state->statistics[threadid], entry);
- }
- }
- else {
- PRINT("Threda %d: update node %s\n", threadid,
- DAG_get_node_name(scene, node));
- }
-
- /* Update will decrease child's valency and schedule child with zero valency. */
- DAG_threaded_update_handle_node_updated(node, scene_update_object_add_task, pool);
-
-#undef PRINT
-}
-
-static void scene_update_object_add_task(void *node, void *user_data)
-{
- TaskPool *task_pool = user_data;
-
- BLI_task_pool_push(task_pool, scene_update_object_func, node, false, TASK_PRIORITY_LOW);
-}
-
-static void print_threads_statistics(ThreadedObjectUpdateState *state)
-{
- double finish_time;
-
- if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
- return;
- }
-
-#ifdef DETAILED_ANALYSIS_OUTPUT
- if (state->has_updated_objects) {
- tot_thread = BLI_system_thread_count();
-
- fprintf(stderr, "objects update base time %f\n", state->base_time);
-
- for (i = 0; i < tot_thread; i++) {
- StatisicsEntry *entry;
- for (entry = state->statistics[i].first;
- entry;
- entry = entry->next)
- {
- fprintf(stderr, "thread %d object %s start_time %f duration %f\n",
- i, entry->object->id.name + 2,
- entry->start_time, entry->duration);
- }
- BLI_freelistN(&state->statistics[i]);
- }
- }
-#else
- finish_time = PIL_check_seconds_timer();
- int total_objects = 0;
-
- for (int i = 0; i < state->num_threads; i++) {
- int thread_total_objects = 0;
- double thread_total_time = 0.0;
- StatisicsEntry *entry;
-
- if (state->has_updated_objects) {
- /* Don't pollute output if no objects were updated. */
- for (entry = state->statistics[i].first;
- entry;
- entry = entry->next)
- {
- thread_total_objects++;
- thread_total_time += entry->duration;
- }
-
- printf("Thread %d: total %d objects in %f sec.\n",
- i,
- thread_total_objects,
- thread_total_time);
-
- for (entry = state->statistics[i].first;
- entry;
- entry = entry->next)
- {
- printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration);
- }
-
- total_objects += thread_total_objects;
- }
-
- BLI_freelistN(&state->statistics[i]);
- }
- if (state->has_updated_objects) {
- printf("Scene updated %d objects in %f sec\n",
- total_objects,
- finish_time - state->base_time);
- }
-#endif
-}
-
-static bool scene_need_update_objects(Main *bmain)
-{
- return
- /* Object datablocks themselves (for OB_RECALC_OB) */
- DAG_id_type_tagged(bmain, ID_OB) ||
-
- /* Objects data datablocks (for OB_RECALC_DATA) */
- DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */
- DAG_id_type_tagged(bmain, ID_CU) || /* Curve */
- DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */
- DAG_id_type_tagged(bmain, ID_LA) || /* Lamp */
- DAG_id_type_tagged(bmain, ID_LT) || /* Lattice */
- DAG_id_type_tagged(bmain, ID_CA) || /* Camera */
- DAG_id_type_tagged(bmain, ID_KE) || /* KE */
- DAG_id_type_tagged(bmain, ID_SPK) || /* Speaker */
- DAG_id_type_tagged(bmain, ID_AR); /* Armature */
-}
-
-static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
-{
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
- ThreadedObjectUpdateState state;
- bool need_singlethread_pass;
- bool need_free_scheduler;
-
- /* Early check for whether we need to invoke all the task-based
- * things (spawn new ppol, traverse dependency graph and so on).
- *
- * Basically if there's no ID datablocks tagged for update which
- * corresponds to object->recalc flags (which are checked in
- * BKE_object_handle_update() then we do nothing here.
- */
- if (!scene_need_update_objects(bmain)) {
- return;
- }
-
- state.eval_ctx = eval_ctx;
- state.bmain = bmain;
- state.scene = scene;
- state.scene_parent = scene_parent;
-
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- task_scheduler = BLI_task_scheduler_create(1);
- need_free_scheduler = true;
- }
- else {
- task_scheduler = BLI_task_scheduler_get();
- need_free_scheduler = false;
- }
-
- /* Those are only needed when blender is run with --debug argument. */
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
- state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics),
- "scene update objects stats");
- state.has_updated_objects = false;
- state.base_time = PIL_check_seconds_timer();
- state.num_threads = tot_thread;
- }
-
-#ifdef MBALL_SINGLETHREAD_HACK
- state.has_mballs = false;
-#endif
-
- task_pool = BLI_task_pool_create(task_scheduler, &state);
-
- DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- print_threads_statistics(&state);
- MEM_freeN(state.statistics);
- }
-
- /* We do single thread pass to update all the objects which are in cyclic dependency.
- * Such objects can not be handled by a generic DAG traverse and it's really tricky
- * to detect whether cycle could be solved or not.
- *
- * In this situation we simply update all remaining objects in a single thread and
- * it'll happen in the same exact order as it was in single-threaded DAG.
- *
- * We couldn't use threaded update for objects which are in cycle because they might
- * access data of each other which is being re-evaluated.
- *
- * Also, as was explained above, for now we also update all the mballs in single thread.
- *
- * - sergey -
- */
- need_singlethread_pass = DAG_is_acyclic(scene) == false;
-#ifdef MBALL_SINGLETHREAD_HACK
- need_singlethread_pass |= state.has_mballs;
-#endif
-
- if (need_singlethread_pass) {
- scene_update_all_bases(bmain, eval_ctx, scene, scene_parent);
- }
-
- if (need_free_scheduler) {
- BLI_task_scheduler_free(task_scheduler);
- }
-}
-
-static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
-{
- scene->customdata_mask = scene_parent->customdata_mask;
-
- /* sets first, we allow per definition current scene to have
- * dependencies on sets, but not the other way around. */
- if (scene->set)
- scene_update_tagged_recursive(eval_ctx, bmain, scene->set, scene_parent);
-
- /* scene objects */
- scene_update_objects(eval_ctx, bmain, scene, scene_parent);
-
- /* scene drivers... */
- scene_update_drivers(bmain, scene);
-
- /* update masking curves */
- BKE_mask_update_scene(bmain, scene);
-
-}
-#endif /* WITH_LEGACY_DEPSGRAPH */
-
static bool check_rendered_viewport_visible(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
wmWindow *window;
for (window = wm->windows.first; window != NULL; window = window->next) {
- bScreen *screen = window->screen;
- ScrArea *area;
- for (area = screen->areabase.first; area != NULL; area = area->next) {
+ const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ Scene *scene = window->scene;
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+
+ if (type->draw_engine || !type->render) {
+ continue;
+ }
+
+ for (ScrArea *area = screen->areabase.first; area != NULL; area = area->next) {
View3D *v3d = area->spacedata.first;
if (area->spacetype != SPACE_VIEW3D) {
continue;
@@ -1806,7 +1301,10 @@ static bool check_rendered_viewport_visible(Main *bmain)
return false;
}
-static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
+/* TODO(campbell): shouldn't we be able to use 'DEG_get_view_layer' here?
+ * Currently this is NULL on load, so don't. */
+static void prepare_mesh_for_viewport_render(
+ Main *bmain, const ViewLayer *view_layer)
{
/* This is needed to prepare mesh to be used by the render
* engine from the viewport rendering. We do loading here
@@ -1817,7 +1315,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
* call loading of the edit data for the mesh objects.
*/
- Object *obedit = scene->obedit;
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (obedit) {
Mesh *mesh = obedit->data;
if ((obedit->type == OB_MESH) &&
@@ -1831,318 +1329,84 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
(&(struct BMeshToMeshParams){
.calc_object_remap = true,
}));
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
}
}
}
}
-void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
+/* TODO(sergey): This actually should become view_layer_graph or so.
+ * Same applies to update_for_newframe.
+ */
+void BKE_scene_graph_update_tagged(Depsgraph *depsgraph,
+ Main *bmain)
{
- Scene *sce_iter;
-#ifdef WITH_LEGACY_DEPSGRAPH
- bool use_new_eval = !DEG_depsgraph_use_legacy();
-#endif
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- /* 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) {
- DAG_scene_relations_update(bmain, sce_iter);
- /* Uncomment this to check if dependency 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);
-
- /* flush recalc flags to dependencies */
- DAG_ids_flush_tagged(bmain);
-
- /* removed calls to quick_cache, see pointcache.c */
-
- /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later
- * when trying to find materials with drivers that need evaluating [#32017]
+ /* TODO(sergey): Some functions here are changing global state,
+ * for example, clearing update tags from bmain.
*/
- BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
-
- /* update all objects: drivers, matrices, displists, etc. flags set
- * by depgraph or manual, no layer check here, gets correct flushed
- *
- * in the future this should handle updates for all datablocks, not
- * only objects and scenes. - brecht */
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
- }
- else
-#endif
- {
- DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
- }
-
- /* update sound system animation (TODO, move to depsgraph) */
- BKE_sound_update_scene(bmain, scene);
-
- /* extra call here to recalc scene animation (for sequencer) */
- {
- AnimData *adt = BKE_animdata_from_id(&scene->id);
- float ctime = BKE_scene_frame_get(scene);
-
- if (adt && (adt->recalc & ADT_RECALC_ANIM))
- BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0);
- }
-
- /* Extra call here to recalc material animation.
- *
- * Need to do this so changing material settings from the graph/dopesheet
- * will update stuff in the viewport.
+ /* (Re-)build dependency graph if needed. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Uncomment this to check if graph was properly tagged for update. */
+ // DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
+ /* Flush editing data if needed. */
+ prepare_mesh_for_viewport_render(bmain, view_layer);
+ /* Flush recalc flags to dependencies. */
+ DEG_graph_flush_update(bmain, depsgraph);
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
*/
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) {
- Material *material;
- float ctime = BKE_scene_frame_get(scene);
-
- for (material = bmain->mat.first;
- material;
- material = material->id.next)
- {
- AnimData *adt = BKE_animdata_from_id(&material->id);
- if (adt && (adt->recalc & ADT_RECALC_ANIM))
- BKE_animsys_evaluate_animdata(scene, &material->id, adt, ctime, 0);
- }
- }
-
- /* Also do the same for node trees. */
- if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) {
- float ctime = BKE_scene_frame_get(scene);
-
- FOREACH_NODETREE(bmain, ntree, id)
- {
- AnimData *adt = BKE_animdata_from_id(&ntree->id);
- if (adt && (adt->recalc & ADT_RECALC_ANIM))
- BKE_animsys_evaluate_animdata(scene, &ntree->id, adt, ctime, 0);
- }
- FOREACH_NODETREE_END
- }
-#endif
-
- /* notify editors and python about recalc */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST);
-
+ DEG_evaluate_on_refresh(depsgraph);
+ /* Update sound system animation (TODO, move to depsgraph). */
+ BKE_sound_update_scene(bmain, scene);
/* Inform editors about possible changes. */
- DAG_ids_check_recalc(bmain, scene, false);
-
- /* clear recalc flags */
- DAG_ids_clear_recalc(bmain);
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
+ /* Clear recalc flags. */
+ DEG_ids_clear_recalc(bmain, depsgraph);
}
/* applies changes right away, does all sets too */
-void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay)
+void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph,
+ Main *bmain)
{
- BKE_scene_update_for_newframe_ex(eval_ctx, bmain, sce, lay, false);
-}
-
-void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay, bool do_invisible_flush)
-{
- float ctime = BKE_scene_frame_get(sce);
- Scene *sce_iter;
-#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 dependency graph? */
- (void) do_invisible_flush;
-#endif
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- DAG_editors_update_pre(bmain, sce, true);
-
- /* keep this first */
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
-
- /* update animated image textures for particles, modifiers, gpu, etc,
- * 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
+ /* TODO(sergey): Some functions here are changing global state,
+ * for example, clearing update tags from bmain.
*/
- if (!use_new_eval) {
- scene_rebuild_rbw_recursive(sce, ctime);
- }
-#endif
-
- BKE_sound_set_cfra(sce->r.cfra);
-
- /* clear animation overrides */
- /* XXX TODO... */
-
- for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
- DAG_scene_relations_update(bmain, sce_iter);
-
-#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
- BKE_mask_evaluate_all_masks(bmain, ctime, true);
- }
-#endif
-
- /* Update animated cache files for modifiers. */
- BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base));
-
-#ifdef POSE_ANIMATION_WORKAROUND
- scene_armature_depsgraph_workaround(bmain);
-#endif
-
- /* All 'standard' (i.e. without any dependencies) animation is handled here,
- * with an 'local' to 'macro' order of evaluation. This should ensure that
- * settings stored nestled within a hierarchy (i.e. settings in a Texture block
- * 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.
+ const float ctime = BKE_scene_frame_get(scene);
+ /* Keep this first. */
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
+ /* Update animated image textures for particles, modifiers, gpu, etc,
+ * call this at the start so modifiers with textures don't lag 1 frame.
*/
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
- /*...done with recursive funcs */
- }
-#endif
-
- /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later
- * when trying to find materials with drivers that need evaluating [#32017]
+ BKE_image_update_frame(bmain, scene->r.cfra);
+ BKE_sound_set_cfra(scene->r.cfra);
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Update animated cache files for modifiers.
+ *
+ * TODO(sergey): Make this a depsgraph node?
*/
- BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
-
- /* run rigidbody sim */
- /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
-#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 */
-#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);
-
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- scene_depsgraph_hack(bmain, eval_ctx, sce, sce);
- }
+ BKE_cachefile_update_frame(bmain, depsgraph, scene, ctime,
+ (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base));
+#ifdef POSE_ANIMATION_WORKAROUND
+ scene_armature_depsgraph_workaround(bmain, depsgraph);
#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);
-
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
+ */
+ DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
+ /* Update sound system animation (TODO, move to depsgraph). */
+ BKE_sound_update_scene(bmain, scene);
+ /* Notify editors and python about recalc. */
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
/* Inform editors about possible changes. */
- DAG_ids_check_recalc(bmain, sce, true);
-
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
/* clear recalc flags */
- DAG_ids_clear_recalc(bmain);
-
-#ifdef DETAILED_ANALYSIS_OUTPUT
- fprintf(stderr, "frame update start_time %f duration %f\n", start_time, PIL_check_seconds_timer() - start_time);
-#endif
-}
-
-/* return default layer, also used to patch old files */
-SceneRenderLayer *BKE_scene_add_render_layer(Scene *sce, const char *name)
-{
- SceneRenderLayer *srl;
-
- if (!name)
- name = DATA_("RenderLayer");
-
- srl = MEM_callocN(sizeof(SceneRenderLayer), "new render layer");
- BLI_strncpy(srl->name, name, sizeof(srl->name));
- BLI_uniquename(&sce->r.layers, srl, DATA_("RenderLayer"), '.', offsetof(SceneRenderLayer, name), sizeof(srl->name));
- BLI_addtail(&sce->r.layers, srl);
-
- /* note, this is also in render, pipeline.c, to make layer when scenedata doesnt have it */
- srl->lay = (1 << 20) - 1;
- srl->layflag = 0x7FFF; /* solid ztra halo edge strand */
- srl->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
- srl->pass_alpha_threshold = 0.5f;
- BKE_freestyle_config_init(&srl->freestyleConfig);
-
- return srl;
-}
-
-bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *srl)
-{
- const int act = BLI_findindex(&scene->r.layers, srl);
- Scene *sce;
-
- if (act == -1) {
- return false;
- }
- else if ( (scene->r.layers.first == scene->r.layers.last) &&
- (scene->r.layers.first == srl))
- {
- /* ensure 1 layer is kept */
- return false;
- }
-
- BKE_freestyle_config_free(&srl->freestyleConfig);
-
- if (srl->prop) {
- IDP_FreeProperty(srl->prop);
- MEM_freeN(srl->prop);
- }
-
- BLI_remlink(&scene->r.layers, srl);
- MEM_freeN(srl);
-
- scene->r.actlay = 0;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->nodetree) {
- bNode *node;
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
- if (node->custom1 == act)
- node->custom1 = 0;
- else if (node->custom1 > act)
- node->custom1--;
- }
- }
- }
- }
-
- return true;
+ DEG_ids_clear_recalc(bmain, depsgraph);
}
/* return default view */
@@ -2209,37 +1473,34 @@ int get_render_child_particle_number(const RenderData *r, int num, bool for_rend
}
}
-int get_render_shadow_samples(const RenderData *r, int samples)
-{
- if ((r->mode & R_SIMPLIFY) && samples > 0)
- return min_ii(r->simplify_shadowsamples, samples);
- else
- return samples;
-}
-
-float get_render_aosss_error(const RenderData *r, float error)
-{
- if (r->mode & R_SIMPLIFY)
- return ((1.0f - r->simplify_aosss) * 10.0f + 1.0f) * error;
- else
- return error;
-}
-
-/* helper function for the SETLOOPER macro */
-Base *_setlooper_base_step(Scene **sce_iter, Base *base)
+/**
+ * Helper function for the SETLOOPER and SETLOOPER_VIEW_LAYER macros
+ *
+ * It iterates over the bases of the active layer and then the bases
+ * of the active layer of the background (set) scenes recursively.
+ */
+Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base)
{
if (base && base->next) {
- /* common case, step to the next */
+ /* Common case, step to the next. */
return base->next;
}
- else if (base == NULL && (*sce_iter)->base.first) {
- /* first time looping, return the scenes first base */
- return (Base *)(*sce_iter)->base.first;
+ else if ((base == NULL) && (view_layer != NULL)) {
+ /* First time looping, return the scenes first base. */
+ /* For the first loop we should get the layer from workspace when available. */
+ if (view_layer->object_bases.first) {
+ return (Base *)view_layer->object_bases.first;
+ }
+ /* No base on this scene layer. */
+ goto next_set;
}
else {
- /* reached the end, get the next base in the set */
+next_set:
+ /* Reached the end, get the next base in the set. */
while ((*sce_iter = (*sce_iter)->set)) {
- base = (Base *)(*sce_iter)->base.first;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*sce_iter));
+ base = (Base *)view_layer_set->object_bases.first;
+
if (base) {
return base;
}
@@ -2249,58 +1510,63 @@ Base *_setlooper_base_step(Scene **sce_iter, Base *base)
return NULL;
}
-bool BKE_scene_use_new_shading_nodes(const Scene *scene)
-{
- const RenderEngineType *type = RE_engines_find(scene->r.engine);
- 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_use_world_space_shading(Scene *scene)
-{
- const RenderEngineType *type = RE_engines_find(scene->r.engine);
- return ((scene->r.mode & R_USE_WS_SHADING) ||
- (type && (type->flag & RE_USE_SHADING_NODES)));
-}
-
bool BKE_scene_use_spherical_stereo(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
return (type && type->flag & RE_USE_SPHERICAL_STEREO);
}
-bool BKE_scene_uses_blender_internal(const Scene *scene)
+bool BKE_scene_uses_blender_eevee(const Scene *scene)
{
- return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER);
+ return STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE);
}
-bool BKE_scene_uses_blender_game(const Scene *scene)
+bool BKE_scene_uses_cycles(const Scene *scene)
{
- return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME);
+ return STREQ(scene->r.engine, RE_engine_id_CYCLES);
}
-void BKE_scene_base_flag_to_objects(struct Scene *scene)
+void BKE_scene_base_flag_to_objects(ViewLayer *view_layer)
{
- Base *base = scene->base.first;
+ Base *base = view_layer->object_bases.first;
while (base) {
- base->object->flag = base->flag;
+ BKE_scene_object_base_flag_sync_from_base(base);
base = base->next;
}
}
-void BKE_scene_base_flag_from_objects(struct Scene *scene)
+void BKE_scene_object_base_flag_sync_from_base(Base *base)
{
- Base *base = scene->base.first;
+ Object *ob = base->object;
- while (base) {
- base->flag = base->object->flag;
- base = base->next;
+ ob->flag = base->flag;
+
+ if ((base->flag & BASE_SELECTED) != 0) {
+ ob->flag |= SELECT;
+ }
+ else {
+ ob->flag &= ~SELECT;
+ }
+}
+
+void BKE_scene_object_base_flag_sync_from_object(Base *base)
+{
+ Object *ob = base->object;
+ base->flag = ob->flag;
+
+ if ((ob->flag & SELECT) != 0) {
+ base->flag |= BASE_SELECTED;
+ BLI_assert((base->flag & BASE_SELECTABLED) != 0);
+ }
+ else {
+ base->flag &= ~BASE_SELECTED;
}
}
@@ -2669,3 +1935,146 @@ int BKE_scene_multiview_num_videos_get(const RenderData *rd)
return BKE_scene_multiview_num_views_get(rd);
}
}
+
+/* Manipulation of depsgraph storage. */
+
+/* This is a key which identifies depsgraph. */
+typedef struct DepsgraphKey {
+ ViewLayer *view_layer;
+ /* TODO(sergey): Need to include window somehow (same layer might be in a
+ * different states in different windows).
+ */
+} DepsgraphKey;
+
+static unsigned int depsgraph_key_hash(const void *key_v)
+{
+ const DepsgraphKey *key = key_v;
+ unsigned int hash = BLI_ghashutil_ptrhash(key->view_layer);
+ /* TODO(sergey): Include hash from other fields in the key. */
+ return hash;
+}
+
+static bool depsgraph_key_compare(const void *key_a_v, const void *key_b_v)
+{
+ const DepsgraphKey *key_a = key_a_v;
+ const DepsgraphKey *key_b = key_b_v;
+ /* TODO(sergey): Compare rest of */
+ return !(key_a->view_layer == key_b->view_layer);
+}
+
+static void depsgraph_key_free(void *key_v)
+{
+ DepsgraphKey *key = key_v;
+ MEM_freeN(key);
+}
+
+static void depsgraph_key_value_free(void *value)
+{
+ Depsgraph *depsgraph = value;
+ DEG_graph_free(depsgraph);
+}
+
+void BKE_scene_allocate_depsgraph_hash(Scene *scene)
+{
+ scene->depsgraph_hash = BLI_ghash_new(depsgraph_key_hash,
+ depsgraph_key_compare,
+ "Scene Depsgraph Hash");
+}
+
+void BKE_scene_ensure_depsgraph_hash(Scene *scene)
+{
+ if (scene->depsgraph_hash == NULL) {
+ BKE_scene_allocate_depsgraph_hash(scene);
+ }
+}
+
+void BKE_scene_free_depsgraph_hash(Scene *scene)
+{
+ if (scene->depsgraph_hash == NULL) {
+ return;
+ }
+ BLI_ghash_free(scene->depsgraph_hash,
+ depsgraph_key_free,
+ depsgraph_key_value_free);
+}
+
+/* Query depsgraph for a specific contexts. */
+
+Depsgraph *BKE_scene_get_depsgraph(Scene *scene,
+ ViewLayer *view_layer,
+ bool allocate)
+{
+ BLI_assert(scene != NULL);
+ BLI_assert(view_layer != NULL);
+ /* Make sure hash itself exists. */
+ if (allocate) {
+ BKE_scene_ensure_depsgraph_hash(scene);
+ }
+ if (scene->depsgraph_hash == NULL) {
+ return NULL;
+ }
+ /* Either ensure item is in the hash or simply return NULL if it's not,
+ * depending on whether caller wants us to create depsgraph or not.
+ */
+ DepsgraphKey key;
+ key.view_layer = view_layer;
+ Depsgraph *depsgraph;
+ if (allocate) {
+ DepsgraphKey **key_ptr;
+ Depsgraph **depsgraph_ptr;
+ if (!BLI_ghash_ensure_p_ex(scene->depsgraph_hash,
+ &key,
+ (void ***)&key_ptr,
+ (void ***)&depsgraph_ptr))
+ {
+ *key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__);
+ **key_ptr = key;
+ *depsgraph_ptr = DEG_graph_new(scene, view_layer, DAG_EVAL_VIEWPORT);
+ /* TODO(sergey): Would be cool to avoid string format print,
+ * but is a bit tricky because we can't know in advance whether
+ * we will ever enable debug messages for this depsgraph.
+ */
+ char name[1024];
+ BLI_snprintf(name, sizeof(name), "%s :: %s", scene->id.name, view_layer->name);
+ DEG_debug_name_set(*depsgraph_ptr, name);
+ }
+ depsgraph = *depsgraph_ptr;
+ }
+ else {
+ depsgraph = BLI_ghash_lookup(scene->depsgraph_hash, &key);
+ }
+ return depsgraph;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Scene Orientation
+ * \{ */
+
+void BKE_scene_transform_orientation_remove(
+ Scene *scene, TransformOrientation *orientation)
+{
+ const int orientation_index = BKE_scene_transform_orientation_get_index(scene, orientation);
+ if (scene->orientation_index_custom == orientation_index) {
+ /* could also use orientation_index-- */
+ scene->orientation_type = V3D_MANIP_GLOBAL;
+ scene->orientation_index_custom = -1;
+ }
+ BLI_freelinkN(&scene->transform_spaces, orientation);
+}
+
+TransformOrientation *BKE_scene_transform_orientation_find(
+ const Scene *scene, const int index)
+{
+ return BLI_findlink(&scene->transform_spaces, index);
+}
+
+/**
+ * \return the index that \a orientation has within \a scene's transform-orientation list or -1 if not found.
+ */
+int BKE_scene_transform_orientation_get_index(
+ const Scene *scene, const TransformOrientation *orientation)
+{
+ return BLI_findindex(&scene->transform_spaces, orientation);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 3c615221564..4a840b5ffbe 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -39,19 +39,20 @@
#include "MEM_guardedalloc.h"
-#include "GPU_compositing.h"
-
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_rect.h"
+#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
/* ************ Spacetype/regiontype handling ************** */
@@ -72,6 +73,8 @@ static void spacetype_free(SpaceType *st)
if (pt->ext.free) {
pt->ext.free(pt->ext.data);
}
+
+ BLI_freelistN(&pt->children);
}
for (ht = art->headertypes.first; ht; ht = ht->next) {
@@ -85,8 +88,6 @@ static void spacetype_free(SpaceType *st)
}
BLI_freelistN(&st->regiontypes);
- BLI_freelistN(&st->toolshelf);
-
}
void BKE_spacetypes_free(void)
@@ -184,10 +185,35 @@ void BKE_spacedata_freelist(ListBase *lb)
BLI_freelistN(lb);
}
+static void panel_list_copy(ListBase *newlb, const ListBase *lb)
+{
+ BLI_listbase_clear(newlb);
+ BLI_duplicatelist(newlb, lb);
+
+ /* copy panel pointers */
+ Panel *newpa = newlb->first;
+ Panel *pa = lb->first;
+ for (; newpa; newpa = newpa->next, pa = pa->next) {
+ newpa->activedata = NULL;
+
+ Panel *newpatab = newlb->first;
+ Panel *patab = lb->first;
+ while (newpatab) {
+ if (newpa->paneltab == patab) {
+ newpa->paneltab = newpatab;
+ break;
+ }
+ newpatab = newpatab->next;
+ patab = patab->next;
+ }
+
+ panel_list_copy(&newpa->children, &pa->children);
+ }
+}
+
ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
{
ARegion *newar = MEM_dupallocN(ar);
- Panel *pa, *newpa, *patab;
newar->prev = newar->next = NULL;
BLI_listbase_clear(&newar->handlers);
@@ -195,9 +221,11 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
BLI_listbase_clear(&newar->panels_category);
BLI_listbase_clear(&newar->panels_category_active);
BLI_listbase_clear(&newar->ui_lists);
- newar->swinid = 0;
+ newar->visible = 0;
+ newar->manipulator_map = NULL;
newar->regiontimer = NULL;
newar->headerstr = NULL;
+ newar->draw_buffer = NULL;
/* use optional regiondata callback */
if (ar->regiondata) {
@@ -217,26 +245,11 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
if (ar->v2d.tab_offset)
newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset);
- BLI_listbase_clear(&newar->panels);
- BLI_duplicatelist(&newar->panels, &ar->panels);
+ panel_list_copy(&newar->panels, &ar->panels);
BLI_listbase_clear(&newar->ui_previews);
BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews);
- /* copy panel pointers */
- for (newpa = newar->panels.first; newpa; newpa = newpa->next) {
- patab = newar->panels.first;
- pa = ar->panels.first;
- while (patab) {
- if (newpa->paneltab == pa) {
- newpa->paneltab = patab;
- break;
- }
- patab = patab->next;
- pa = pa->next;
- }
- }
-
return newar;
}
@@ -310,6 +323,56 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID
}
}
+/**
+ * Avoid bad-level calls to #WM_manipulatormap_tag_refresh.
+ */
+static void (*region_refresh_tag_manipulatormap_callback)(struct wmManipulatorMap *) = NULL;
+
+void BKE_region_callback_refresh_tag_manipulatormap_set(void (*callback)(struct wmManipulatorMap *))
+{
+ region_refresh_tag_manipulatormap_callback = callback;
+}
+
+void BKE_screen_manipulator_tag_refresh(struct bScreen *sc)
+{
+ if (region_refresh_tag_manipulatormap_callback == NULL) {
+ return;
+ }
+
+ ScrArea *sa;
+ ARegion *ar;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->manipulator_map != NULL) {
+ region_refresh_tag_manipulatormap_callback(ar->manipulator_map);
+ }
+ }
+ }
+}
+
+/**
+ * Avoid bad-level calls to #WM_manipulatormap_delete.
+ */
+static void (*region_free_manipulatormap_callback)(struct wmManipulatorMap *) = NULL;
+
+void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *))
+{
+ region_free_manipulatormap_callback = callback;
+}
+
+static void panel_list_free(ListBase *lb)
+{
+ Panel *pa, *pa_next;
+ for (pa = lb->first; pa; pa = pa_next) {
+ pa_next = pa->next;
+ if (pa->activedata) {
+ MEM_freeN(pa->activedata);
+ }
+ panel_list_free(&pa->children);
+ MEM_freeN(pa);
+ }
+}
+
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
{
@@ -332,16 +395,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
ar->v2d.tab_offset = NULL;
}
- if (!BLI_listbase_is_empty(&ar->panels)) {
- Panel *pa, *pa_next;
- for (pa = ar->panels.first; pa; pa = pa_next) {
- pa_next = pa->next;
- if (pa->activedata) {
- MEM_freeN(pa->activedata);
- }
- MEM_freeN(pa);
- }
- }
+ panel_list_free(&ar->panels);
for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) {
if (uilst->dyn_data) {
@@ -359,6 +413,11 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
MEM_freeN(uilst->properties);
}
}
+
+ if (ar->manipulator_map != NULL) {
+ region_free_manipulatormap_callback(ar->manipulator_map);
+ }
+
BLI_freelistN(&ar->ui_lists);
BLI_freelistN(&ar->ui_previews);
BLI_freelistN(&ar->panels_category);
@@ -374,6 +433,7 @@ void BKE_screen_area_free(ScrArea *sa)
for (ar = sa->regionbase.first; ar; ar = ar->next)
BKE_area_region_free(st, ar);
+ MEM_SAFE_FREE(sa->global);
BLI_freelistN(&sa->regionbase);
BKE_spacedata_freelist(&sa->spacedata);
@@ -381,10 +441,21 @@ void BKE_screen_area_free(ScrArea *sa)
BLI_freelistN(&sa->actionzones);
}
+void BKE_screen_area_map_free(ScrAreaMap *area_map)
+{
+ for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) {
+ area_next = area->next;
+ BKE_screen_area_free(area);
+ }
+
+ BLI_freelistN(&area_map->vertbase);
+ BLI_freelistN(&area_map->edgebase);
+ BLI_freelistN(&area_map->areabase);
+}
+
/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free(bScreen *sc)
{
- ScrArea *sa, *san;
ARegion *ar;
/* No animdata here. */
@@ -394,14 +465,9 @@ void BKE_screen_free(bScreen *sc)
BLI_freelistN(&sc->regionbase);
- for (sa = sc->areabase.first; sa; sa = san) {
- san = sa->next;
- BKE_screen_area_free(sa);
- }
+ BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(sc));
- BLI_freelistN(&sc->vertbase);
- BLI_freelistN(&sc->edgebase);
- BLI_freelistN(&sc->areabase);
+ BKE_previewimg_free(&sc->preview);
/* Region and timer are freed by the window manager. */
MEM_SAFE_FREE(sc->tool_tip);
@@ -426,6 +492,174 @@ unsigned int BKE_screen_visible_layers(bScreen *screen, Scene *scene)
return layer;
}
+
+/* ***************** Screen edges & verts ***************** */
+
+ScrEdge *BKE_screen_find_edge(bScreen *sc, ScrVert *v1, ScrVert *v2)
+{
+ ScrEdge *se;
+
+ BKE_screen_sort_scrvert(&v1, &v2);
+ for (se = sc->edgebase.first; se; se = se->next) {
+ if (se->v1 == v1 && se->v2 == v2) {
+ return se;
+ }
+ }
+
+ return NULL;
+}
+
+void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
+{
+ ScrVert *tmp;
+
+ if (*v1 > *v2) {
+ tmp = *v1;
+ *v1 = *v2;
+ *v2 = tmp;
+ }
+}
+
+void BKE_screen_remove_double_scrverts(bScreen *sc)
+{
+ ScrVert *v1, *verg;
+ ScrEdge *se;
+ ScrArea *sa;
+
+ verg = sc->vertbase.first;
+ while (verg) {
+ if (verg->newv == NULL) { /* !!! */
+ v1 = verg->next;
+ while (v1) {
+ if (v1->newv == NULL) { /* !?! */
+ if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
+ /* printf("doublevert\n"); */
+ v1->newv = verg;
+ }
+ }
+ v1 = v1->next;
+ }
+ }
+ verg = verg->next;
+ }
+
+ /* replace pointers in edges and faces */
+ se = sc->edgebase.first;
+ while (se) {
+ if (se->v1->newv) se->v1 = se->v1->newv;
+ if (se->v2->newv) se->v2 = se->v2->newv;
+ /* edges changed: so.... */
+ BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
+ se = se->next;
+ }
+ sa = sc->areabase.first;
+ while (sa) {
+ if (sa->v1->newv) sa->v1 = sa->v1->newv;
+ if (sa->v2->newv) sa->v2 = sa->v2->newv;
+ if (sa->v3->newv) sa->v3 = sa->v3->newv;
+ if (sa->v4->newv) sa->v4 = sa->v4->newv;
+ sa = sa->next;
+ }
+
+ /* remove */
+ verg = sc->vertbase.first;
+ while (verg) {
+ v1 = verg->next;
+ if (verg->newv) {
+ BLI_remlink(&sc->vertbase, verg);
+ MEM_freeN(verg);
+ }
+ verg = v1;
+ }
+
+}
+
+void BKE_screen_remove_double_scredges(bScreen *sc)
+{
+ ScrEdge *verg, *se, *sn;
+
+ /* compare */
+ verg = sc->edgebase.first;
+ while (verg) {
+ se = verg->next;
+ while (se) {
+ sn = se->next;
+ if (verg->v1 == se->v1 && verg->v2 == se->v2) {
+ BLI_remlink(&sc->edgebase, se);
+ MEM_freeN(se);
+ }
+ se = sn;
+ }
+ verg = verg->next;
+ }
+}
+
+void BKE_screen_remove_unused_scredges(bScreen *sc)
+{
+ ScrEdge *se, *sen;
+ ScrArea *sa;
+ int a = 0;
+
+ /* sets flags when edge is used in area */
+ sa = sc->areabase.first;
+ while (sa) {
+ se = BKE_screen_find_edge(sc, sa->v1, sa->v2);
+ if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a);
+ else se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
+ if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a);
+ else se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v3, sa->v4);
+ if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a);
+ else se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
+ if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a);
+ else se->flag = 1;
+ sa = sa->next;
+ a++;
+ }
+ se = sc->edgebase.first;
+ while (se) {
+ sen = se->next;
+ if (se->flag == 0) {
+ BLI_remlink(&sc->edgebase, se);
+ MEM_freeN(se);
+ }
+ else {
+ se->flag = 0;
+ }
+ se = sen;
+ }
+}
+
+void BKE_screen_remove_unused_scrverts(bScreen *sc)
+{
+ ScrVert *sv, *svn;
+ ScrEdge *se;
+
+ /* we assume edges are ok */
+
+ se = sc->edgebase.first;
+ while (se) {
+ se->v1->flag = 1;
+ se->v2->flag = 1;
+ se = se->next;
+ }
+
+ sv = sc->vertbase.first;
+ while (sv) {
+ svn = sv->next;
+ if (sv->flag == 0) {
+ BLI_remlink(&sc->vertbase, sv);
+ MEM_freeN(sv);
+ }
+ else {
+ sv->flag = 0;
+ }
+ sv = svn;
+ }
+}
+
/* ***************** Utilities ********************** */
/* Find a region of the specified type from the given area */
@@ -604,7 +838,7 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
}
}
-void BKE_screen_view3d_scene_sync(bScreen *sc)
+void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
{
/* are there cameras in the views that are not in the scene? */
ScrArea *sa;
@@ -613,56 +847,7 @@ void BKE_screen_view3d_scene_sync(bScreen *sc)
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *) sl;
- BKE_screen_view3d_sync(v3d, sc->scene);
- }
- }
- }
-}
-
-void BKE_screen_view3d_main_sync(ListBase *screen_lb, Scene *scene)
-{
- bScreen *sc;
- ScrArea *sa;
- SpaceLink *sl;
-
- /* from scene copy to the other views */
- for (sc = screen_lb->first; sc; sc = sc->id.next) {
- if (sc->scene != scene)
- continue;
-
- for (sa = sc->areabase.first; sa; sa = sa->next)
- for (sl = sa->spacedata.first; sl; sl = sl->next)
- if (sl->spacetype == SPACE_VIEW3D)
- BKE_screen_view3d_sync((View3D *)sl, scene);
- }
-}
-
-void BKE_screen_view3d_twmode_remove(View3D *v3d, const int i)
-{
- const int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
- if (selected_index == i) {
- v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
- }
- else if (selected_index > i) {
- v3d->twmode--;
- }
-}
-
-void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, Scene *scene, const int i)
-{
- bScreen *sc;
-
- for (sc = screen_lb->first; sc; sc = sc->id.next) {
- if (sc->scene == scene) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- BKE_screen_view3d_twmode_remove(v3d, i);
- }
- }
+ BKE_screen_view3d_sync(v3d, scene);
}
}
}
@@ -686,25 +871,12 @@ float BKE_screen_view3d_zoom_from_fac(float zoomfac)
return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
}
-void BKE_screen_gpu_fx_validate(GPUFXSettings *fx_settings)
+bool BKE_screen_is_fullscreen_area(const bScreen *screen)
{
- /* currently we use DOF from the camera _only_,
- * so we never allocate this, only copy from the Camera */
-#if 0
- if ((fx_settings->dof == NULL) &&
- (fx_settings->fx_flag & GPU_FX_FLAG_DOF))
- {
- GPUDOFSettings *fx_dof;
- fx_dof = fx_settings->dof = MEM_callocN(sizeof(GPUDOFSettings), __func__);
- }
-#endif
-
- if ((fx_settings->ssao == NULL) &&
- (fx_settings->fx_flag & GPU_FX_FLAG_SSAO))
- {
- GPUSSAOSettings *fx_ssao;
- fx_ssao = fx_settings->ssao = MEM_callocN(sizeof(GPUSSAOSettings), __func__);
+ return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
+}
- GPU_fx_compositor_init_ssao_settings(fx_ssao);
- }
+bool BKE_screen_is_used(const bScreen *screen)
+{
+ return (screen->winid != 0);
}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 64c59bd7f2b..9105961a3ae 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -1767,13 +1767,13 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
if (output != output) output = 1;
if (wipe->forward) output = 1 - output;
break;
- /* BOX WIPE IS NOT WORKING YET */
+ /* BOX WIPE IS NOT WORKING YET */
/* case DO_CROSS_WIPE: */
/* BOX WIPE IS NOT WORKING YET */
#if 0
case DO_BOX_WIPE:
- if (!wipe->forward)
- facf0 = 1.0f - facf0; /* Go the other direction */
+ if (!wipe->forward)
+ facf0 = 1.0f - facf0; /* Go the other direction */
width = (int)(wipe->edgeWidth * ((xo + yo) / 2.0));
hwidth = (float)width / 2.0;
@@ -1806,8 +1806,9 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
}
- if (!wipe->forward)
- facf0 = 1.0f - facf0; /* Go the other direction */
+ if (!wipe->forward) {
+ facf0 = 1.0f - facf0; /* Go the other direction */
+ }
angle = -1 / angle;
b1 = posy / 2 - (-angle) * posx / 2;
b3 = (yo - posy / 2) - (-angle) * (xo - posx / 2);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 14119998519..d857db7e276 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -63,9 +63,9 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "BKE_movieclip.h"
@@ -75,6 +75,9 @@
#include "BKE_library.h"
#include "BKE_idprop.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#include "RE_pipeline.h"
@@ -89,8 +92,10 @@
#include "BKE_context.h"
#include "BKE_sound.h"
+#include "RE_engine.h"
+
#ifdef WITH_AUDASPACE
-# include AUD_SPECIAL_H
+# include <AUD_Special.h>
#endif
/* mutable state for sequencer */
@@ -588,17 +593,17 @@ void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixe
/*********************** sequencer pipeline functions *************************/
void BKE_sequencer_new_render_data(
- EvaluationContext *eval_ctx,
- Main *bmain, Scene *scene, int rectx, int recty,
- int preview_render_size,
+ Main *bmain, struct Depsgraph *depsgraph, Scene *scene, int rectx, int recty,
+ int preview_render_size, int for_render,
SeqRenderData *r_context)
{
- r_context->eval_ctx = eval_ctx;
r_context->bmain = bmain;
+ r_context->depsgraph = depsgraph;
r_context->scene = scene;
r_context->rectx = rectx;
r_context->recty = recty;
r_context->preview_render_size = preview_render_size;
+ r_context->for_render = for_render;
r_context->motion_blur_samples = 0;
r_context->motion_blur_shutter = 0;
r_context->skip_cache = false;
@@ -1458,6 +1463,7 @@ typedef struct SeqIndexBuildContext {
int view_id;
Main *bmain;
+ Depsgraph *depsgraph;
Scene *scene;
Sequence *seq, *orig_seq;
} SeqIndexBuildContext;
@@ -1946,7 +1952,9 @@ static int seq_proxy_context_count(Sequence *seq, Scene *scene)
return num_views;
}
-void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list, ListBase *queue)
+void BKE_sequencer_proxy_rebuild_context(
+ Main *bmain, Depsgraph *depsgraph, Scene *scene,
+ Sequence *seq, struct GSet *file_list, ListBase *queue)
{
SeqIndexBuildContext *context;
Sequence *nseq;
@@ -1978,6 +1986,7 @@ void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *se
context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
context->bmain = bmain;
+ context->depsgraph = depsgraph;
context->scene = scene;
context->orig_seq = seq;
context->seq = nseq;
@@ -2031,9 +2040,10 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
/* fail safe code */
BKE_sequencer_new_render_data(
- bmain->eval_ctx, bmain, context->scene,
+ bmain, context->depsgraph, context->scene,
(scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f,
(scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, 100,
+ false,
&render_context);
render_context.skip_cache = true;
@@ -2753,17 +2763,12 @@ static ImBuf *seq_render_effect_strip_impl(
if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
sh.get_default_fac(seq, cfra, &fac, &facf);
-
- if ((scene->r.mode & R_FIELDS) == 0)
- facf = fac;
+ facf = fac;
}
else {
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
if (fcu) {
fac = facf = evaluate_fcurve(fcu, cfra);
- if (scene->r.mode & R_FIELDS) {
- facf = evaluate_fcurve(fcu, cfra + 0.5f);
- }
}
else {
fac = facf = seq->effect_fader;
@@ -3131,7 +3136,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
/* anim-data */
adt = BKE_animdata_from_id(&mask->id);
- BKE_animsys_evaluate_animdata(context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(context->depsgraph, context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM);
maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
@@ -3268,6 +3273,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
// have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first); /* UNUSED */
have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree;
+ /* Get view layer for the strip. */
+ ViewLayer *view_layer = BKE_view_layer_default_render(scene);
+ /* Depsgraph will be NULL when doing rendering. */
+ Depsgraph *depsgraph = NULL;
+
orig_data.scemode = scene->r.scemode;
orig_data.cfra = scene->r.cfra;
orig_data.subframe = scene->r.subframe;
@@ -3323,12 +3333,16 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
context->scene->r.seq_prev_type = 3 /* == OB_SOLID */;
/* opengl offscreen render */
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
+ depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
ibuf = sequencer_view3d_cb(
/* set for OpenGL render (NULL when scrubbing) */
- context->bmain, scene, camera, width, height, IB_rect, draw_flags, context->scene->r.seq_prev_type,
+ depsgraph, scene,
+ context->scene->r.seq_prev_type,
+ camera, width, height, IB_rect,
+ draw_flags,
scene->r.alphamode, context->gpu_samples, viewname,
- context->gpu_fx, context->gpu_offscreen, err_out);
+ context->gpu_offscreen, err_out);
if (ibuf == NULL) {
fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
}
@@ -3349,12 +3363,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
* When rendering from command line renderer is called from main thread, in this
* case it's always safe to render scene here
*/
- if (!is_thread_main || is_rendering == false || is_background || context->eval_ctx->mode == DAG_EVAL_RENDER) {
+ if (!is_thread_main || is_rendering == false || is_background || context->for_render) {
if (re == NULL)
re = RE_NewSceneRender(scene);
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
- RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false);
+ RE_BlenderFrame(re, context->bmain, scene, view_layer, camera, scene->lay, frame, false);
/* restore previous state after it was toggled on & off by RE_BlenderFrame */
G.is_rendering = is_rendering;
@@ -3412,8 +3425,8 @@ finally:
scene->r.cfra = orig_data.cfra;
scene->r.subframe = orig_data.subframe;
- if (is_frame_update) {
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
+ if (is_frame_update && (depsgraph != NULL)) {
+ BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
}
#ifdef DURIAN_CAMERA_SWITCH
@@ -3503,7 +3516,7 @@ static ImBuf *do_render_strip_uncached(
ibuf = seq_render_scene_strip(context, seq, nr, cfra);
/* Scene strips update all animation, so we need to restore original state.*/
- BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra);
+ BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, context->scene, cfra);
copy_to_ibuf_still(context, seq, nr, ibuf);
}
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index e28b4ccc23d..9fa104dc04d 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -47,8 +47,11 @@
#include "BLI_task.h"
#include "BKE_shrinkwrap.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_DerivedMesh.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
@@ -154,11 +157,11 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
- if (calc->target != NULL && calc->target->getNumVerts(calc->target) == 0) {
+ if (calc->target != NULL && calc->target->totvert == 0) {
return;
}
- TIMEIT_BENCH(bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_VERTS, 2), bvhtree_verts);
+ TIMEIT_BENCH(BKE_bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_VERTS, 2), bvhtree_verts);
if (treeData.tree == NULL) {
OUT_OF_MEMORY();
return;
@@ -297,7 +300,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
}
if (calc->vert) {
- /* calc->vert contains verts from derivedMesh */
+ /* calc->vert contains verts from evaluated mesh. */
/* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
/* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
@@ -354,7 +357,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
/* don't set the initial dist (which is more efficient),
* because its calculated in the targets space, we want the dist in our own space */
if (proj_limit_squared != 0.0f) {
- if (len_squared_v3v3(hit->co, co) > proj_limit_squared) {
+ if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) {
hit->index = -1;
}
}
@@ -365,7 +368,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
}
}
-static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render)
+static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
{
/* Options about projection direction */
float proj_axis[3] = {0.0f, 0.0f, 0.0f};
@@ -379,7 +382,8 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
void *treeData = NULL;
/* auxiliary target */
- DerivedMesh *auxMesh = NULL;
+ Mesh *auxMesh = NULL;
+ bool auxMesh_free;
void *auxData = NULL;
SpaceTransform local2aux;
@@ -388,7 +392,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
return;
- if (calc->target != NULL && calc->target->getNumPolys(calc->target) == 0) {
+ if (calc->target != NULL && calc->target->totpoly == 0) {
return;
}
@@ -412,7 +416,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
if (calc->smd->auxTarget) {
- auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render);
+ auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->smd->auxTarget, &auxMesh_free);
if (!auxMesh)
return;
BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget);
@@ -427,47 +431,24 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
BVHTree *targ_tree;
void *targ_callback;
- if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) {
- emtarget = BKE_editmesh_from_object(calc->smd->target);
- if ((targ_tree = bvhtree_from_editmesh_looptri(
- &treedata_stack.emtreedata, emtarget, 0.0, 4, 6, &calc->target->bvhCache)))
- {
- targ_callback = treedata_stack.emtreedata.raycast_callback;
- treeData = &treedata_stack.emtreedata;
- }
- }
- else {
- if ((targ_tree = bvhtree_from_mesh_get(
- &treedata_stack.dmtreedata, calc->target, BVHTREE_FROM_LOOPTRI, 4)))
- {
- targ_callback = treedata_stack.dmtreedata.raycast_callback;
- treeData = &treedata_stack.dmtreedata;
- }
- }
- if (targ_tree) {
+ if ((targ_tree = BKE_bvhtree_from_mesh_get(
+ &treedata_stack.dmtreedata, calc->target, BVHTREE_FROM_LOOPTRI, 4)))
+ {
+ targ_callback = treedata_stack.dmtreedata.raycast_callback;
+ treeData = &treedata_stack.dmtreedata;
+
BVHTree *aux_tree = NULL;
void *aux_callback = NULL;
- if (auxMesh != NULL && auxMesh->getNumPolys(auxMesh) != 0) {
+ if (auxMesh != NULL && auxMesh->totpoly != 0) {
/* use editmesh to avoid array allocation */
- if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
- emaux = BKE_editmesh_from_object(calc->smd->auxTarget);
- if ((aux_tree = bvhtree_from_editmesh_looptri(
- &auxdata_stack.emtreedata, emaux, 0.0, 4, 6, &auxMesh->bvhCache)))
- {
- aux_callback = auxdata_stack.emtreedata.raycast_callback;
- auxData = &auxdata_stack.emtreedata;
- }
- }
- else {
- if ((aux_tree = bvhtree_from_mesh_get(
- &auxdata_stack.dmtreedata, auxMesh, BVHTREE_FROM_LOOPTRI, 4)) != NULL)
- {
- aux_callback = auxdata_stack.dmtreedata.raycast_callback;
- auxData = &auxdata_stack.dmtreedata;
- }
+ if ((aux_tree = BKE_bvhtree_from_mesh_get(
+ &auxdata_stack.dmtreedata, auxMesh, BVHTREE_FROM_LOOPTRI, 4)) != NULL)
+ {
+ aux_callback = auxdata_stack.dmtreedata.raycast_callback;
+ auxData = &auxdata_stack.dmtreedata;
}
}
- /* After sucessufuly build the trees, start projection vertexs */
+ /* After successfully build the trees, start projection vertices. */
ShrinkwrapCalcCBData data = {
.calc = calc,
.treeData = treeData, .targ_tree = targ_tree, .targ_callback = targ_callback,
@@ -503,6 +484,9 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
free_bvhtree_from_mesh(auxData);
}
}
+ if (auxMesh != NULL && auxMesh_free) {
+ BKE_id_free(NULL, auxMesh);
+ }
}
/*
@@ -585,12 +569,12 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
- if (calc->target->getNumPolys(calc->target) == 0) {
+ if (calc->target->totpoly == 0) {
return;
}
/* Create a bvh-tree of the given target */
- bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_LOOPTRI, 2);
if (treeData.tree == NULL) {
OUT_OF_MEMORY();
return;
@@ -616,12 +600,13 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
}
/* Main shrinkwrap function */
-void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts, bool for_render)
+void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, struct Scene *scene, Object *ob, Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
{
DerivedMesh *ss_mesh = NULL;
ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+ bool target_free;
/* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */
if (smd->target == ob) smd->target = NULL;
@@ -637,8 +622,8 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
/* DeformVertex */
calc.vgroup = defgroup_name_index(calc.ob, calc.smd->vgroup_name);
- if (dm) {
- calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ if (mesh) {
+ calc.dvert = mesh->dvert;
}
else if (calc.ob->type == OB_LATTICE) {
calc.dvert = BKE_lattice_deform_verts_get(calc.ob);
@@ -646,7 +631,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
if (smd->target) {
- calc.target = object_get_derived_final(smd->target, for_render);
+ calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(smd->target, &target_free);
/* TODO there might be several "bugs" on non-uniform scales matrixs
* because it will no longer be nearest surface, not sphere projection
@@ -661,10 +646,10 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
calc.vgroup = defgroup_name_index(calc.ob, smd->vgroup_name);
- if (dm != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
+ if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
/* Setup arrays to get vertexs positions, normals and deform weights */
- calc.vert = dm->getVertDataArray(dm, CD_MVERT);
- calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ calc.vert = mesh->mvert;
+ calc.dvert = mesh->dvert;
/* Using vertexs positions/normals as if a subsurface was applied */
if (smd->subsurfLevels) {
@@ -672,7 +657,10 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */
ssmd.levels = smd->subsurfLevels; /* levels */
- ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0);
+ /* TODO to be moved to Mesh once we are done with changes in subsurf code. */
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+
+ ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, scene, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0);
if (ss_mesh) {
calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT);
@@ -684,8 +672,10 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
}
/* Just to make sure we are not leaving any memory behind */
- assert(ssmd.emCache == NULL);
- assert(ssmd.mCache == NULL);
+ BLI_assert(ssmd.emCache == NULL);
+ BLI_assert(ssmd.mCache == NULL);
+
+ dm->release(dm);
}
}
@@ -697,7 +687,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
break;
case MOD_SHRINKWRAP_PROJECT:
- TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc, for_render), deform_project);
+ TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project);
break;
case MOD_SHRINKWRAP_NEAREST_VERTEX:
@@ -709,4 +699,8 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
/* free memory */
if (ss_mesh)
ss_mesh->release(ss_mesh);
+
+ if (target_free && calc.target) {
+ BKE_id_free(NULL, calc.target);
+ }
}
diff --git a/source/blender/blenkernel/intern/sketch.c b/source/blender/blenkernel/intern/sketch.c
deleted file mode 100644
index 0bf7a9f278e..00000000000
--- a/source/blender/blenkernel/intern/sketch.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/sketch.c
- * \ingroup bke
- */
-
-
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_sketch.h"
-
-
-#include "DNA_userdef_types.h"
-
-void freeSketch(SK_Sketch *sketch)
-{
- SK_Stroke *stk, *next;
-
- for (stk = sketch->strokes.first; stk; stk = next) {
- next = stk->next;
-
- sk_freeStroke(stk);
- }
-
- MEM_freeN(sketch);
-}
-
-SK_Sketch *createSketch(void)
-{
- SK_Sketch *sketch;
-
- sketch = MEM_callocN(sizeof(SK_Sketch), "SK_Sketch");
-
- sketch->active_stroke = NULL;
- sketch->gesture = NULL;
-
- BLI_listbase_clear(&sketch->strokes);
-
- return sketch;
-}
-
-void sk_initPoint(SK_Point *pt, SK_DrawData *dd, const float no[3])
-{
- if (no) {
- normalize_v3_v3(pt->no, no);
- }
- else {
- pt->no[0] = 0.0f;
- pt->no[1] = 0.0f;
- pt->no[2] = 1.0f;
- }
- pt->p2d[0] = dd->mval[0];
- pt->p2d[1] = dd->mval[1];
-
- pt->size = 0.0f;
- pt->type = PT_CONTINUOUS;
- pt->mode = PT_SNAP;
- /* more init code here */
-}
-
-void sk_copyPoint(SK_Point *dst, SK_Point *src)
-{
- memcpy(dst, src, sizeof(SK_Point));
-}
-
-void sk_allocStrokeBuffer(SK_Stroke *stk)
-{
- stk->points = MEM_callocN(sizeof(SK_Point) * stk->buf_size, "SK_Point buffer");
-}
-
-void sk_freeStroke(SK_Stroke *stk)
-{
- MEM_freeN(stk->points);
- MEM_freeN(stk);
-}
-
-SK_Stroke *sk_createStroke(void)
-{
- SK_Stroke *stk;
-
- stk = MEM_callocN(sizeof(SK_Stroke), "SK_Stroke");
-
- stk->selected = 0;
- stk->nb_points = 0;
- stk->buf_size = SK_Stroke_BUFFER_INIT_SIZE;
-
- sk_allocStrokeBuffer(stk);
-
- return stk;
-}
-
-void sk_shrinkStrokeBuffer(SK_Stroke *stk)
-{
- if (stk->nb_points < stk->buf_size) {
- SK_Point *old_points = stk->points;
-
- stk->buf_size = stk->nb_points;
-
- sk_allocStrokeBuffer(stk);
-
- memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
-
- MEM_freeN(old_points);
- }
-}
-
-void sk_growStrokeBuffer(SK_Stroke *stk)
-{
- if (stk->nb_points == stk->buf_size) {
- SK_Point *old_points = stk->points;
-
- stk->buf_size *= 2;
-
- sk_allocStrokeBuffer(stk);
-
- memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
-
- MEM_freeN(old_points);
- }
-}
-
-void sk_growStrokeBufferN(SK_Stroke *stk, int n)
-{
- if (stk->nb_points + n > stk->buf_size) {
- SK_Point *old_points = stk->points;
-
- while (stk->nb_points + n > stk->buf_size) {
- stk->buf_size *= 2;
- }
-
- sk_allocStrokeBuffer(stk);
-
- memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
-
- MEM_freeN(old_points);
- }
-}
-
-
-void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
-{
- memcpy(stk->points + n, pt, sizeof(SK_Point));
-}
-
-void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
-{
- int size = stk->nb_points - n;
-
- sk_growStrokeBuffer(stk);
-
- memmove(stk->points + n + 1, stk->points + n, size * sizeof(SK_Point));
-
- memcpy(stk->points + n, pt, sizeof(SK_Point));
-
- stk->nb_points++;
-}
-
-void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt)
-{
- sk_growStrokeBuffer(stk);
-
- memcpy(stk->points + stk->nb_points, pt, sizeof(SK_Point));
-
- stk->nb_points++;
-}
-
-void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end)
-{
- int size = end - start;
-
- sk_growStrokeBufferN(stk, len - size);
-
- if (len != size) {
- int tail_size = stk->nb_points - end;
-
- memmove(stk->points + start + len, stk->points + end, tail_size * sizeof(SK_Point));
- }
-
- memcpy(stk->points + start, pts, len * sizeof(SK_Point));
-
- stk->nb_points += len - size;
-}
-
-void sk_trimStroke(SK_Stroke *stk, int start, int end)
-{
- int size = end - start + 1;
-
- if (start > 0) {
- memmove(stk->points, stk->points + start, size * sizeof(SK_Point));
- }
-
- stk->nb_points = size;
-}
-
-void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3])
-{
- SK_Point pt1, pt2;
- SK_Point *prev, *next;
- float delta_p[3];
- int i, total;
-
- total = end - start;
-
- sub_v3_v3v3(delta_p, p_end, p_start);
-
- prev = stk->points + start;
- next = stk->points + end;
-
- copy_v3_v3(pt1.p, p_start);
- copy_v3_v3(pt1.no, prev->no);
- pt1.mode = prev->mode;
- pt1.type = prev->type;
-
- copy_v3_v3(pt2.p, p_end);
- copy_v3_v3(pt2.no, next->no);
- pt2.mode = next->mode;
- pt2.type = next->type;
-
- sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */
- sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */
-
- for (i = 1; i < total; i++) {
- float delta = (float)i / (float)total;
- float *p = stk->points[start + 1 + i].p;
-
- mul_v3_v3fl(p, delta_p, delta);
- add_v3_v3(p, p_start);
- }
-}
-
-void sk_polygonizeStroke(SK_Stroke *stk, int start, int end)
-{
- int offset;
- int i;
-
- /* find first exact points outside of range */
- for (; start > 0; start--) {
- if (stk->points[start].type == PT_EXACT) {
- break;
- }
- }
-
- for (; end < stk->nb_points - 1; end++) {
- if (stk->points[end].type == PT_EXACT) {
- break;
- }
- }
-
- offset = start + 1;
-
- for (i = start + 1; i < end; i++) {
- if (stk->points[i].type == PT_EXACT) {
- if (offset != i) {
- memcpy(stk->points + offset, stk->points + i, sizeof(SK_Point));
- }
-
- offset++;
- }
- }
-
- /* some points were removes, move end of array */
- if (offset < end) {
- int size = stk->nb_points - end;
- memmove(stk->points + offset, stk->points + end, size * sizeof(SK_Point));
- stk->nb_points = offset + size;
- }
-}
-
-void sk_flattenStroke(SK_Stroke *stk, int start, int end)
-{
- float normal[3], distance[3];
- float limit;
- int i, total;
-
- total = end - start + 1;
-
- copy_v3_v3(normal, stk->points[start].no);
-
- sub_v3_v3v3(distance, stk->points[end].p, stk->points[start].p);
- project_v3_v3v3(normal, distance, normal);
- limit = normalize_v3(normal);
-
- for (i = 1; i < total - 1; i++) {
- float d = limit * i / total;
- float offset[3];
- float *p = stk->points[start + i].p;
-
- sub_v3_v3v3(distance, p, stk->points[start].p);
- project_v3_v3v3(distance, distance, normal);
-
- copy_v3_v3(offset, normal);
- mul_v3_fl(offset, d);
-
- sub_v3_v3(p, distance);
- add_v3_v3(p, offset);
- }
-}
-
-void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk)
-{
- if (sketch->active_stroke == stk) {
- sketch->active_stroke = NULL;
- }
-
- BLI_remlink(&sketch->strokes, stk);
- sk_freeStroke(stk);
-}
-
-void sk_reverseStroke(SK_Stroke *stk)
-{
- SK_Point *old_points = stk->points;
- int i = 0;
-
- sk_allocStrokeBuffer(stk);
-
- for (i = 0; i < stk->nb_points; i++) {
- sk_copyPoint(stk->points + i, old_points + stk->nb_points - 1 - i);
- }
-
- MEM_freeN(old_points);
-}
-
-
-/* Ramer-Douglas-Peucker algorithm for line simplification */
-void sk_filterStroke(SK_Stroke *stk, int start, int end)
-{
- SK_Point *old_points = stk->points;
- int nb_points = stk->nb_points;
- char *marked = NULL;
- char work;
- int i;
-
- if (start == -1) {
- start = 0;
- end = stk->nb_points - 1;
- }
-
- sk_allocStrokeBuffer(stk);
- stk->nb_points = 0;
-
- /* adding points before range */
- for (i = 0; i < start; i++) {
- sk_appendStrokePoint(stk, old_points + i);
- }
-
- marked = MEM_callocN(nb_points, "marked array");
- marked[start] = 1;
- marked[end] = 1;
-
- work = 1;
-
- /* while still reducing */
- while (work) {
- int ls, le;
- work = 0;
-
- ls = start;
- le = start + 1;
-
- /* while not over interval */
- while (ls < end) {
- int max_i = 0;
- short v1[2];
- float max_dist = 16; /* more than 4 pixels */
-
- /* find the next marked point */
- while (marked[le] == 0) {
- le++;
- }
-
- /* perpendicular vector to ls-le */
- v1[1] = old_points[le].p2d[0] - old_points[ls].p2d[0];
- v1[0] = old_points[ls].p2d[1] - old_points[le].p2d[1];
-
-
- for (i = ls + 1; i < le; i++) {
- float mul;
- float dist;
- short v2[2];
-
- v2[0] = old_points[i].p2d[0] - old_points[ls].p2d[0];
- v2[1] = old_points[i].p2d[1] - old_points[ls].p2d[1];
-
- if (v2[0] == 0 && v2[1] == 0) {
- continue;
- }
-
- mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
-
- dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
-
- if (dist > max_dist) {
- max_dist = dist;
- max_i = i;
- }
- }
-
- if (max_i != 0) {
- work = 1;
- marked[max_i] = 1;
- }
-
- ls = le;
- le = ls + 1;
- }
- }
-
-
- /* adding points after range */
- for (i = start; i <= end; i++) {
- if (marked[i]) {
- sk_appendStrokePoint(stk, old_points + i);
- }
- }
-
- MEM_freeN(marked);
-
- /* adding points after range */
- for (i = end + 1; i < nb_points; i++) {
- sk_appendStrokePoint(stk, old_points + i);
- }
-
- MEM_freeN(old_points);
-
- sk_shrinkStrokeBuffer(stk);
-}
-
-
-void sk_filterLastContinuousStroke(SK_Stroke *stk)
-{
- int start, end;
-
- end = stk->nb_points - 1;
-
- for (start = end - 1; start > 0 && stk->points[start].type == PT_CONTINUOUS; start--) {
- /* nothing to do here*/
- }
-
- if (end - start > 1) {
- sk_filterStroke(stk, start, end);
- }
-}
-
-SK_Point *sk_lastStrokePoint(SK_Stroke *stk)
-{
- SK_Point *pt = NULL;
-
- if (stk->nb_points > 0) {
- pt = stk->points + (stk->nb_points - 1);
- }
-
- return pt;
-}
-
-void sk_endContinuousStroke(SK_Stroke *stk)
-{
- stk->points[stk->nb_points - 1].type = PT_EXACT;
-}
-
-void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk)
-{
- if (stk) {
- memcpy(&(sketch->next_point), &(stk->points[stk->nb_points - 1]), sizeof(SK_Point));
- }
-}
-
-int sk_stroke_filtermval(SK_DrawData *dd)
-{
- int retval = 0;
- if (ABS(dd->mval[0] - dd->previous_mval[0]) + ABS(dd->mval[1] - dd->previous_mval[1]) > U.gp_manhattendist) {
- retval = 1;
- }
-
- return retval;
-}
-
-void sk_initDrawData(SK_DrawData *dd, const int mval[2])
-{
- dd->mval[0] = mval[0];
- dd->mval[1] = mval[1];
- dd->previous_mval[0] = -1;
- dd->previous_mval[1] = -1;
- dd->type = PT_EXACT;
-}
-
-
-void sk_deleteSelectedStrokes(SK_Sketch *sketch)
-{
- SK_Stroke *stk, *next;
-
- for (stk = sketch->strokes.first; stk; stk = next) {
- next = stk->next;
-
- if (stk->selected == 1) {
- sk_removeStroke(sketch, stk);
- }
- }
-}
-
-void sk_selectAllSketch(SK_Sketch *sketch, int mode)
-{
- SK_Stroke *stk = NULL;
-
- if (mode == -1) {
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- stk->selected = 0;
- }
- }
- else if (mode == 0) {
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- stk->selected = 1;
- }
- }
- else if (mode == 1) {
- int selected = 1;
-
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- selected &= stk->selected;
- }
-
- selected ^= 1;
-
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- stk->selected = selected;
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index c1a085a3b15..5ba9b7ce4dc 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -71,7 +71,6 @@
#include "BKE_constraint.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
@@ -84,6 +83,9 @@
#include "BKE_smoke.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RE_shader_ext.h"
#include "GPU_glew.h"
@@ -127,7 +129,7 @@ void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(s
void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity),
int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color),
float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {}
-struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; }
+struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), struct Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; }
float smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; }
#endif /* WITH_SMOKE */
@@ -696,16 +698,16 @@ void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifie
#ifdef WITH_SMOKE
// forward decleration
-static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene);
+static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer);
static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-static int get_lamp(Scene *scene, float *light)
+static int get_lamp(ViewLayer *view_layer, float *light)
{
Base *base_tmp = NULL;
int found_lamp = 0;
// try to find a lamp, preferably local
- for (base_tmp = scene->base.first; base_tmp; base_tmp = base_tmp->next) {
+ for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
if (base_tmp->object->type == OB_LAMP) {
Lamp *la = base_tmp->object->data;
@@ -2107,7 +2109,7 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value
}
static void update_flowsfluids(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
{
Object **flowobjs = NULL;
EmissionMap *emaps = NULL;
@@ -2214,9 +2216,7 @@ static void update_flowsfluids(
else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
/* update flow object frame */
BLI_mutex_lock(&object_update_lock);
- BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, collob,
- true, 5, BKE_scene_frame_get(scene), eModifierType_Smoke);
+ BKE_object_modifier_update_subframe(depsgraph, scene, collob, true, 5, BKE_scene_frame_get(scene), eModifierType_Smoke);
BLI_mutex_unlock(&object_update_lock);
/* apply flow */
@@ -2512,7 +2512,7 @@ static void update_effectors_task_cb(
mul_m4_v3(sds->obmat, voxelCenter);
pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
- pdDoEffectors(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
+ BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
/* convert retvel to local space */
mag = len_v3(retvel);
@@ -2528,12 +2528,12 @@ static void update_effectors_task_cb(
}
}
-static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
+static void update_effectors(struct Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
{
ListBase *effectors;
/* make sure smoke flow influence is 0.0f */
sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
- effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights, true);
+ effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, sds->effector_weights);
if (effectors) {
// precalculate wind forces
@@ -2560,11 +2560,11 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds,
&settings);
}
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
}
static void step(
- Main *bmain, EvaluationContext *eval_ctx,
+ Depsgraph *depsgraph,
Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps)
{
SmokeDomainSettings *sds = smd->domain;
@@ -2635,11 +2635,11 @@ static void step(
for (substep = 0; substep < totalSubsteps; substep++)
{
// calc animated obstacle velocities
- update_flowsfluids(bmain, eval_ctx, scene, ob, sds, dtSubdiv);
+ update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv);
update_obstacles(scene, ob, sds, dtSubdiv, substep, totalSubsteps);
if (sds->total_cells > 1) {
- update_effectors(scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
+ update_effectors(depsgraph, scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
smoke_step(sds->fluid, gravity, dtSubdiv);
}
}
@@ -2733,7 +2733,7 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
}
static void smokeModifier_process(
- Main *bmain, EvaluationContext *eval_ctx, SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+ SmokeModifierData *smd, struct Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm)
{
if ((smd->type & MOD_SMOKE_TYPE_FLOW))
{
@@ -2854,11 +2854,11 @@ static void smokeModifier_process(
}
- step(bmain, eval_ctx, scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base);
+ step(depsgraph, scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base);
}
// create shadows before writing cache so they get stored
- smoke_calc_transparency(sds, scene);
+ smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph));
if (sds->wt && sds->total_cells > 1) {
smoke_turbulence_step(sds->wt, sds->fluid);
@@ -2875,14 +2875,14 @@ static void smokeModifier_process(
}
}
-struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+struct DerivedMesh *smokeModifier_do(
+ SmokeModifierData *smd, struct Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm)
{
/* lock so preview render does not read smoke data while it gets modified */
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
- /* Ugly G.main, hopefully won't be needed anymore in 2.8 */
- smokeModifier_process(G.main, G.main->eval_ctx , smd, scene, ob, dm);
+ smokeModifier_process(smd, depsgraph, scene, ob, dm);
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
@@ -2997,7 +2997,7 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f
cb(result, input, res, pixel, tRay, correct);
}
-static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene)
+static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer)
{
float bv[6] = {0};
float light[3];
@@ -3005,7 +3005,7 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene)
float *density = smoke_get_density(sds->fluid);
float correct = -7.0f * sds->dx;
- if (!get_lamp(scene, light)) return;
+ if (!get_lamp(view_layer, light)) return;
/* convert light pos to sim cell space */
mul_m4_v3(sds->imat, light);
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index cf5ce374e4c..c552bfeb0dc 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -71,9 +71,11 @@ variables on the UI for now
#include "BLI_ghash.h"
#include "BLI_threads.h"
+#include "BKE_collection.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_modifier.h"
#include "BKE_softbody.h"
#include "BKE_pointcache.h"
@@ -81,6 +83,9 @@ variables on the UI for now
#include "BKE_mesh.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "PIL_time.h"
/* callbacks for errors and interrupts and some goo */
@@ -134,7 +139,7 @@ typedef struct SB_thread_context {
float timenow;
int ifirst;
int ilast;
- ListBase *do_effector;
+ ListBase *effectors;
int do_deflector;
float fieldfactor;
float windfactor;
@@ -510,37 +515,24 @@ static void ccd_build_deflector_hash_single(GHash *hash, Object *ob)
}
/**
- * \note group overrides scene when not NULL.
+ * \note collection overrides scene when not NULL.
*/
-static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
+static void ccd_build_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash)
{
- Object *ob;
-
if (!hash) return;
- if (group) {
- /* Explicit collision group */
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- ob = go->ob;
+ /* Explicit collision collection. */
+ Base *base = BKE_collection_or_layer_objects(depsgraph, NULL, NULL, collection);
- if (ob == vertexowner || ob->type != OB_MESH)
+ for (; base; base = base->next) {
+ /* Only proceed for mesh object in same layer. */
+ if (base->object->type == OB_MESH) {
+ Object *ob = base->object;
+ if (ob == vertexowner) {
+ /* If vertexowner is given we don't want to check collision with owner object. */
continue;
-
- ccd_build_deflector_hash_single(hash, ob);
- }
- }
- else {
- for (Base *base = scene->base.first; base; base = base->next) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) {
- ob= base->object;
- if ((vertexowner) && (ob == vertexowner)) {
- /* if vertexowner is given we don't want to check collision with owner object */
- continue;
- }
-
- ccd_build_deflector_hash_single(hash, ob);
}
+ ccd_build_deflector_hash_single(hash, ob);
}
}
}
@@ -556,39 +548,27 @@ static void ccd_update_deflector_hash_single(GHash *hash, Object *ob)
}
/**
- * \note group overrides scene when not NULL.
+ * \note collection overrides scene when not NULL.
*/
-static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
+static void ccd_update_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash)
{
- Object *ob;
-
if ((!hash) || (!vertexowner)) return;
- if (group) {
- /* Explicit collision group */
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- ob = go->ob;
+ /* Explicit collision collection. */
+ Base *base = BKE_collection_or_layer_objects(depsgraph, NULL, NULL, collection);
- if (ob == vertexowner || ob->type != OB_MESH)
+ for (; base; base = base->next) {
+ /* Only proceed for mesh object in same layer. */
+ if (base->object->type == OB_MESH) {
+ Object *ob = base->object;
+ if (ob == vertexowner) {
+ /* If vertexowner is given we don't want to check collision with owner object. */
continue;
+ }
ccd_update_deflector_hash_single(hash, ob);
}
}
- else {
- for (Base *base = scene->base.first; base; base = base->next) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) {
- ob= base->object;
- if (ob == vertexowner) {
- /* if vertexowner is given we don't want to check collision with owner object */
- continue;
- }
-
- ccd_update_deflector_hash_single(hash, ob);
- }
- }
- }
}
@@ -977,31 +957,23 @@ static void free_softbody_intern(SoftBody *sb)
/* +++ dependency information functions*/
/**
- * \note group overrides scene when not NULL.
+ * \note collection overrides scene when not NULL.
*/
-static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer)
+static bool are_there_deflectors(Base *first_base)
{
- if (group) {
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- if (go->ob->pd && go->ob->pd->deflect)
+ for (Base *base = first_base; base; base = base->next) {
+ if (base->object->pd) {
+ if (base->object->pd->deflect)
return 1;
}
}
- else {
- for (Base *base = scene->base.first; base; base= base->next) {
- if ( (base->lay & layer) && base->object->pd) {
- if (base->object->pd->deflect)
- return 1;
- }
- }
- }
return 0;
}
-static int query_external_colliders(Scene *scene, Group *group, Object *me)
+static int query_external_colliders(Depsgraph *depsgraph, Collection *collection)
{
- return(are_there_deflectors(scene, group, me->lay));
+ return(are_there_deflectors(BKE_collection_or_layer_objects(depsgraph, NULL, NULL, collection)));
}
/* --- dependency information functions*/
@@ -1472,7 +1444,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
return deflected;
}
-static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *do_effector)
+static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *effectors)
{
SoftBody *sb = ob->soft;
int a;
@@ -1506,14 +1478,14 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
float vel[3], sp[3], pr[3], force[3];
float f, windfactor = 0.25f;
/*see if we have wind*/
- if (do_effector) {
+ if (effectors) {
EffectedPoint epoint;
float speed[3] = {0.0f, 0.0f, 0.0f};
float pos[3];
mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos);
mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec);
pd_point_from_soft(scene, pos, vel, -1, &epoint);
- pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
mul_v3_fl(speed, windfactor);
add_v3_v3(vel, speed);
@@ -1546,32 +1518,30 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
}
-static void scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow)
+static void scan_for_ext_spring_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float timenow)
{
SoftBody *sb = ob->soft;
- ListBase *do_effector = NULL;
- do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
- _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector);
- pdEndEffectors(&do_effector);
+ ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, sb->effector_weights);
+ _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, effectors);
+ BKE_effectors_free(effectors);
}
static void *exec_scan_for_ext_spring_forces(void *data)
{
SB_thread_context *pctx = (SB_thread_context*)data;
- _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->do_effector);
+ _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->effectors);
return NULL;
}
-static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void)))
+static void sb_sfesf_threads_run(struct Depsgraph *depsgraph, Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void)))
{
- ListBase *do_effector = NULL;
ListBase threads;
SB_thread_context *sb_threads;
int i, totthread, left, dec;
int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
- do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, ob->soft->effector_weights);
/* figure the number of threads while preventing pretty pointless threading overhead */
totthread= BKE_scene_num_threads(scene);
@@ -1596,7 +1566,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,
}
else
sb_threads[i].ifirst = 0;
- sb_threads[i].do_effector = do_effector;
+ sb_threads[i].effectors = effectors;
sb_threads[i].do_deflector = false;// not used here
sb_threads[i].fieldfactor = 0.0f;// not used here
sb_threads[i].windfactor = 0.0f;// not used here
@@ -1616,7 +1586,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,
/* clean up */
MEM_freeN(sb_threads);
- pdEndEffectors(&do_effector);
+ BKE_effectors_free(effectors);
}
@@ -1969,7 +1939,7 @@ static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, floa
/* since this is definitely the most CPU consuming task here .. try to spread it */
/* core function _softbody_calc_forces_slice_in_a_thread */
/* result is int to be able to flag user break */
-static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor)
+static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
{
float iks;
int bb, do_selfcollision, do_springcollision, do_aero;
@@ -2088,14 +2058,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
}
/* particle field & vortex */
- if (do_effector) {
+ if (effectors) {
EffectedPoint epoint;
float kd;
float force[3] = {0.0f, 0.0f, 0.0f};
float speed[3] = {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
- pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale);
@@ -2170,11 +2140,11 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
static void *exec_softbody_calc_forces(void *data)
{
SB_thread_context *pctx = (SB_thread_context*)data;
- _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->do_effector, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor);
+ _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->effectors, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor);
return NULL;
}
-static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor)
+static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
{
ListBase threads;
SB_thread_context *sb_threads;
@@ -2206,7 +2176,7 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
}
else
sb_threads[i].ifirst = 0;
- sb_threads[i].do_effector = do_effector;
+ sb_threads[i].effectors = effectors;
sb_threads[i].do_deflector = do_deflector;
sb_threads[i].fieldfactor = fieldfactor;
sb_threads[i].windfactor = windfactor;
@@ -2229,14 +2199,13 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
MEM_freeN(sb_threads);
}
-static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow)
+static void softbody_calc_forcesEx(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow)
{
/* rule we never alter free variables :bp->vec bp->pos in here !
* this will ruin adaptive stepsize AKA heun! (BM)
*/
SoftBody *sb= ob->soft; /* is supposed to be there */
/*BodyPoint *bproot;*/ /* UNUSED */
- ListBase *do_effector = NULL;
/* float gravity; */ /* UNUSED */
/* float iks; */
float fieldfactor = -1.0f, windfactor = 0.25;
@@ -2245,7 +2214,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
/* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */
/* check conditions for various options */
- do_deflector= query_external_colliders(scene, sb->collision_group, ob);
+ do_deflector= query_external_colliders(depsgraph, sb->collision_group);
/* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */
do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
@@ -2254,31 +2223,31 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
/* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */
if (do_springcollision || do_aero)
- sb_sfesf_threads_run(scene, ob, timenow, sb->totspring, NULL);
+ sb_sfesf_threads_run(depsgraph, scene, ob, timenow, sb->totspring, NULL);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, sb->effector_weights);
if (do_deflector) {
float defforce[3];
do_deflector = sb_detect_aabb_collisionCached(defforce, ob->lay, ob, timenow);
}
- sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, do_effector, do_deflector, fieldfactor, windfactor);
+ sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, effectors, do_deflector, fieldfactor, windfactor);
/* finally add forces caused by face collision */
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
/* finish matrix and solve */
- pdEndEffectors(&do_effector);
+ BKE_effectors_free(effectors);
}
-static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow)
+static void softbody_calc_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow)
{
/* redirection to the new threaded Version */
if (!(G.debug_value & 0x10)) { // 16
- softbody_calc_forcesEx(scene, ob, forcetime, timenow);
+ softbody_calc_forcesEx(depsgraph, scene, ob, forcetime, timenow);
return;
}
else {
@@ -2297,7 +2266,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
BodyPoint *bp;
/* BodyPoint *bproot; */ /* UNUSED */
BodySpring *bs;
- ListBase *do_effector = NULL;
float iks, ks, kd, gravity[3] = {0.0f, 0.0f, 0.0f};
float fieldfactor = -1.0f, windfactor = 0.25f;
float tune = sb->ballstiff;
@@ -2309,7 +2277,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
}
/* check conditions for various options */
- do_deflector= query_external_colliders(scene, sb->collision_group, ob);
+ do_deflector= query_external_colliders(depsgraph, sb->collision_group);
do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF));
do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
@@ -2317,9 +2285,9 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */
/* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */
- if (do_springcollision || do_aero) scan_for_ext_spring_forces(scene, ob, timenow);
+ if (do_springcollision || do_aero) scan_for_ext_spring_forces(depsgraph, scene, ob, timenow);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, scene, ob, NULL, ob->soft->effector_weights);
if (do_deflector) {
float defforce[3];
@@ -2422,13 +2390,13 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* particle field & vortex */
- if (do_effector) {
+ if (effectors) {
EffectedPoint epoint;
float force[3] = {0.0f, 0.0f, 0.0f};
float speed[3] = {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
- pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale);
@@ -2520,7 +2488,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* finally add forces caused by face collision */
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
- pdEndEffectors(&do_effector);
+ BKE_effectors_free(effectors);
}
}
@@ -3506,7 +3474,7 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int
}
}
-static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
+static void softbody_step(struct Depsgraph *depsgraph, Scene *scene, Object *ob, SoftBody *sb, float dtime)
{
/* the simulator */
float forcetime;
@@ -3520,11 +3488,11 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
*/
if (dtime < 0 || dtime > 10.5f) return;
- ccd_update_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
+ ccd_update_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
if (sb->scratch->needstobuildcollider) {
- if (query_external_colliders(scene, sb->collision_group, ob)) {
- ccd_build_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
+ if (query_external_colliders(depsgraph, sb->collision_group)) {
+ ccd_build_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
}
sb->scratch->needstobuildcollider=0;
}
@@ -3554,12 +3522,12 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
sb->scratch->flag &= ~SBF_DOFUZZY;
/* do predictive euler step */
- softbody_calc_forces(scene, ob, forcetime, timedone/dtime);
+ softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime);
softbody_apply_forces(ob, forcetime, 1, NULL, mid_flags);
/* crop new slope values to do averaged slope step */
- softbody_calc_forces(scene, ob, forcetime, timedone/dtime);
+ softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime);
softbody_apply_forces(ob, forcetime, 2, &err, mid_flags);
softbody_apply_goalsnap(ob);
@@ -3640,7 +3608,7 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
}
/* simulates one step. framenr is in frames */
-void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
+void sbObjectStep(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
{
SoftBody *sb= ob->soft;
PointCache *cache;
@@ -3648,7 +3616,6 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
float dtime, timescale;
int framedelta, framenr, startframe, endframe;
int cache_result;
-
cache= sb->pointcache;
framenr= (int)cfra;
@@ -3717,7 +3684,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
}
/* try to read from cache */
- bool can_simulate = (framenr == sb->last_frame+1) && !(cache->flag & PTCACHE_BAKED);
+ bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED);
cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate);
@@ -3757,7 +3724,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
dtime = framedelta*timescale;
/* do simulation */
- softbody_step(scene, ob, sb, dtime);
+ softbody_step(depsgraph, scene, ob, sb, dtime);
softbody_to_object(ob, vertexCos, numVerts, 0);
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 6aa44cde0e0..ebb23f8d5c6 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -48,13 +48,11 @@
#include "DNA_speaker_types.h"
#ifdef WITH_AUDASPACE
-# include AUD_SOUND_H
-# include AUD_SEQUENCE_H
-# include AUD_HANDLE_H
-# include AUD_SPECIAL_H
-# ifdef WITH_SYSTEM_AUDASPACE
-# include "../../../intern/audaspace/intern/AUD_Set.h"
-# endif
+# include <AUD_Sound.h>
+# include <AUD_Sequence.h>
+# include <AUD_Handle.h>
+# include <AUD_Special.h>
+# include "../../../intern/audaspace/intern/AUD_Set.h"
#endif
#include "BKE_global.h"
@@ -228,7 +226,7 @@ void BKE_sound_init_once(void)
atexit(BKE_sound_exit_once);
}
-static AUD_Device *sound_device;
+static AUD_Device *sound_device = NULL;
void *BKE_sound_get_device(void)
{
@@ -237,6 +235,9 @@ void *BKE_sound_get_device(void)
void BKE_sound_init(struct Main *bmain)
{
+ /* Make sure no instance of the sound system is running, otherwise we get leaks. */
+ BKE_sound_exit();
+
AUD_DeviceSpecs specs;
int device, buffersize;
const char *device_name;
@@ -302,7 +303,6 @@ void BKE_sound_exit_once(void)
sound_device = NULL;
AUD_exitOnce();
-#ifdef WITH_SYSTEM_AUDASPACE
if (audio_device_names != NULL) {
int i;
for (i = 0; audio_device_names[i]; i++) {
@@ -311,7 +311,6 @@ void BKE_sound_exit_once(void)
free(audio_device_names);
audio_device_names = NULL;
}
-#endif
}
/* XXX unused currently */
@@ -807,13 +806,76 @@ void BKE_sound_read_waveform(bSound *sound, short *stop)
BLI_spin_unlock(sound->spinlock);
}
-void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
+static void sound_update_base(Scene *scene, Base *base, void *new_set)
{
- Object *ob;
- Base *base;
+ Object *ob = base->object;
NlaTrack *track;
NlaStrip *strip;
Speaker *speaker;
+ float quat[4];
+
+ if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
+ return;
+ }
+
+ ob->id.tag &= ~LIB_TAG_DOIT;
+
+ if ((ob->type != OB_SPEAKER) || !ob->adt) {
+ return;
+ }
+
+ for (track = ob->adt->nla_tracks.first; track; track = track->next) {
+ for (strip = track->strips.first; strip; strip = strip->next) {
+ if (strip->type != NLASTRIP_TYPE_SOUND) {
+ continue;
+ }
+ speaker = (Speaker *)ob->data;
+
+ if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
+ if (speaker->sound) {
+ AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
+ }
+ else {
+ AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
+ strip->speaker_handle = NULL;
+ }
+ }
+ else {
+ if (speaker->sound) {
+ strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
+ speaker->sound->playback_handle,
+ (double)strip->start / FPS, FLT_MAX, 0);
+ AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
+ }
+ }
+
+ if (strip->speaker_handle) {
+ const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
+ AUD_addSet(new_set, strip->speaker_handle);
+ AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
+ AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
+ AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
+ AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
+ AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
+ AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
+ AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
+ AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
+
+ mat4_to_quat(quat, ob->obmat);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
+ AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
+ AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
+ }
+ }
+ }
+}
+
+void BKE_sound_update_scene(Main *bmain, Scene *scene)
+{
+ Base *base;
Scene *sce_it;
void *new_set = AUD_createSet();
@@ -822,59 +884,18 @@ void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
/* cheap test to skip looping over all objects (no speakers is a common case) */
if (!BLI_listbase_is_empty(&bmain->speaker)) {
- for (SETLOOPER(scene, sce_it, base)) {
- ob = base->object;
- if ((ob->type != OB_SPEAKER) || !ob->adt) {
- continue;
- }
- for (track = ob->adt->nla_tracks.first; track; track = track->next) {
- for (strip = track->strips.first; strip; strip = strip->next) {
- if (strip->type != NLASTRIP_TYPE_SOUND) {
- continue;
- }
- speaker = (Speaker *)ob->data;
-
- if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
- if (speaker->sound) {
- AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
- }
- else {
- AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
- strip->speaker_handle = NULL;
- }
- }
- else {
- if (speaker->sound) {
- strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
- speaker->sound->playback_handle,
- (double)strip->start / FPS, FLT_MAX, 0);
- AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
- }
- }
-
- if (strip->speaker_handle) {
- const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
- AUD_addSet(new_set, strip->speaker_handle);
- AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
- AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
- AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
- AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
- AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
- AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
- AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
- AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
-
- mat4_to_quat(quat, ob->obmat);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
- AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
- AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
- }
- }
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
+
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ sound_update_base(scene, base, new_set);
}
}
+
+ for (SETLOOPER_SET_ONLY(scene, sce_it, base)) {
+ sound_update_base(scene, base, new_set);
+ }
+
}
while ((handle = AUD_getSet(scene->speaker_handles))) {
@@ -907,28 +928,12 @@ float BKE_sound_get_length(bSound *sound)
char **BKE_sound_get_device_names(void)
{
if (audio_device_names == NULL) {
-#ifdef WITH_SYSTEM_AUDASPACE
audio_device_names = AUD_getDeviceNames();
-#else
- static const char *names[] = {
- "Null", "SDL", "OpenAL", "JACK", NULL
- };
- audio_device_names = (char **)names;
-#endif
}
return audio_device_names;
}
-bool BKE_sound_is_jack_supported(void)
-{
-#ifdef WITH_SYSTEM_AUDASPACE
- return 1;
-#else
- return (bool)AUD_isJackSupported();
-#endif
-}
-
#else /* WITH_AUDASPACE */
#include "BLI_utildefines.h"
@@ -975,5 +980,6 @@ void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char
void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {}
void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {}
float BKE_sound_get_length(struct bSound *UNUSED(sound)) { return 0; }
-bool BKE_sound_is_jack_supported(void) { return false; }
+char **BKE_sound_get_device_names(void) { static char *names[1] = {NULL}; return names; }
+
#endif /* WITH_AUDASPACE */
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
new file mode 100644
index 00000000000..b2a1785542c
--- /dev/null
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -0,0 +1,1200 @@
+/*
+ * ***** 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) 2006-2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenkernel/intern/studiolight.c
+ * \ingroup bke
+ */
+
+#include "BKE_studiolight.h"
+
+#include "BKE_appdir.h"
+#include "BKE_icons.h"
+
+#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+#include "BLI_path_util.h"
+#include "BLI_rand.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "DNA_listBase.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "GPU_texture.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* Statics */
+static ListBase studiolights;
+static int last_studiolight_id = 0;
+#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 128
+#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT 32
+#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * 2)
+
+#define STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE 0
+#define STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS 1
+/*
+ * The method to calculate the irradiance buffers
+ * The irradiance buffer is only shown in the background when in LookDev.
+ *
+ * STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE is very slow, but very accurate
+ * STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS is faster but has artifacts
+ */
+// #define STUDIOLIGHT_IRRADIANCE_METHOD STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+#define STUDIOLIGHT_IRRADIANCE_METHOD STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 2
+# define STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING
+#endif
+
+/*
+ * Disable this option so caches are not loaded from disk
+ * Do not checkin with this commented out
+ */
+#define STUDIOLIGHT_LOAD_CACHED_FILES
+
+static const char *STUDIOLIGHT_CAMERA_FOLDER = "studiolights/camera/";
+static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/";
+static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/";
+
+/* FUNCTIONS */
+#define IMB_SAFE_FREE(p) do { \
+if (p) { \
+ IMB_freeImBuf(p); \
+ p = NULL; \
+} \
+} while (0)
+
+#define GPU_TEXTURE_SAFE_FREE(p) do { \
+if (p) { \
+ GPU_texture_free(p); \
+ p = NULL; \
+} \
+} while (0)
+
+static void studiolight_free(struct StudioLight *sl)
+{
+#define STUDIOLIGHT_DELETE_ICON(s) { \
+ if (s != 0) { \
+ BKE_icon_delete(s); \
+ s = 0; \
+ } \
+}
+ if (sl->free_function) {
+ sl->free_function(sl, sl->free_function_data);
+ }
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_radiance);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_irradiance);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap_flipped);
+#undef STUDIOLIGHT_DELETE_ICON
+
+ for (int index = 0 ; index < 6 ; index ++) {
+ IMB_SAFE_FREE(sl->radiance_cubemap_buffers[index]);
+ }
+ GPU_TEXTURE_SAFE_FREE(sl->equirectangular_radiance_gputexture);
+ GPU_TEXTURE_SAFE_FREE(sl->equirectangular_irradiance_gputexture);
+ IMB_SAFE_FREE(sl->equirectangular_radiance_buffer);
+ IMB_SAFE_FREE(sl->equirectangular_irradiance_buffer);
+ MEM_SAFE_FREE(sl->path_irr_cache);
+ MEM_SAFE_FREE(sl->path_sh_cache);
+ MEM_SAFE_FREE(sl->gpu_matcap_3components);
+ MEM_SAFE_FREE(sl);
+}
+
+static struct StudioLight *studiolight_create(int flag)
+{
+ struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__);
+ sl->path[0] = 0x00;
+ sl->name[0] = 0x00;
+ sl->path_irr_cache = NULL;
+ sl->path_sh_cache = NULL;
+ sl->free_function = NULL;
+ sl->flag = flag;
+ sl->index = ++last_studiolight_id;
+ if (flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) {
+ sl->icon_id_matcap = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP);
+ sl->icon_id_matcap_flipped = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED);
+ }
+ else {
+ sl->icon_id_radiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE);
+ sl->icon_id_irradiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE);
+ }
+
+ for (int index = 0 ; index < 6 ; index ++) {
+ sl->radiance_cubemap_buffers[index] = NULL;
+ }
+
+ return sl;
+}
+
+static void direction_to_equirectangular(float r[2], const float dir[3])
+{
+ r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2);
+ r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI;
+}
+
+static void equirectangular_to_direction(float r[3], float u, float v)
+{
+ float phi = (-(M_PI * 2)) * u + M_PI;
+ float theta = -M_PI * v + M_PI;
+ float sin_theta = sinf(theta);
+ r[0] = sin_theta * cosf(phi);
+ r[1] = sin_theta * sinf(phi);
+ r[2] = cosf(theta);
+}
+
+static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
+{
+ float uv[2];
+ direction_to_equirectangular(uv, direction);
+ nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
+}
+
+static void studiolight_calculate_radiance_buffer(
+ ImBuf *ibuf, float *colbuf,
+ const float start_x, const float add_x,
+ const float start_y, const float add_y, const float z,
+ const int index_x, const int index_y, const int index_z)
+{
+ float direction[3];
+ float yf = start_y;
+ float xf;
+ float *color = colbuf;
+
+ for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y ++, yf += add_y) {
+ xf = start_x;
+ for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x ++, xf += add_x) {
+ direction[index_x] = xf;
+ direction[index_y] = yf;
+ direction[index_z] = z;
+ normalize_v3(direction);
+ studiolight_calculate_radiance(ibuf, color, direction);
+ color += 4;
+ }
+ }
+}
+
+static void studiolight_load_equirectangular_image(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ ImBuf *ibuf = NULL;
+ ibuf = IMB_loadiffname(sl->path, 0, NULL);
+ if (ibuf == NULL) {
+ float *colbuf = MEM_mallocN(sizeof(float[4]), __func__);
+ copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f);
+ ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1);
+ }
+ IMB_float_from_rect(ibuf);
+ sl->equirectangular_radiance_buffer = ibuf;
+ }
+ sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
+}
+
+static void studiolight_create_equirectangular_radiance_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ char error[256];
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ ImBuf *ibuf = sl->equirectangular_radiance_buffer;
+
+ if (sl->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) {
+ sl->gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
+
+ float *offset4 = ibuf->rect_float;
+ float *offset3 = sl->gpu_matcap_3components;
+ for (int i = 0 ; i < ibuf->x * ibuf->y; i++) {
+ copy_v3_v3(offset3, offset4);
+ offset3 += 3;
+ offset4 += 4;
+ }
+ sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(
+ ibuf->x, ibuf->y, GPU_R11F_G11F_B10F, sl->gpu_matcap_3components, error);
+ }
+ else {
+ sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ GPUTexture *tex = sl->equirectangular_radiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE;
+}
+
+static void studiolight_create_equirectangular_irradiance_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ char error[256];
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
+ ImBuf *ibuf = sl->equirectangular_irradiance_buffer;
+ sl->equirectangular_irradiance_gputexture = GPU_texture_create_2D(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ GPUTexture *tex = sl->equirectangular_irradiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE;
+}
+
+static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ ImBuf *ibuf = sl->equirectangular_radiance_buffer;
+ if (ibuf) {
+ float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__);
+ const float add = 1.0f / (STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE + 1);
+ const float start = ((1.0f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * 0.5f) - 0.5f;
+
+ /* front */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, 0.5f, 0, 2, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* back */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, -0.5f, 0, 2, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* left */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, 0.5f, 1, 2, 0);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* right */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 1, 2, 0);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* top */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 0, 1, 2);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* bottom */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, -start, -add, 0.5f, 0, 1, 2);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+#if 0
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], "/tmp/studiolight_radiance_left.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], "/tmp/studiolight_radiance_right.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], "/tmp/studiolight_radiance_front.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], "/tmp/studiolight_radiance_back.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], "/tmp/studiolight_radiance_bottom.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], "/tmp/studiolight_radiance_top.png", IB_rectfloat);
+#endif
+ MEM_freeN(colbuf);
+ }
+ }
+ sl->flag |= STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED;
+}
+
+BLI_INLINE void studiolight_evaluate_radiance_buffer(
+ ImBuf *radiance_buffer, const float normal[3], float color[3], int *hits,
+ int xoffset, int yoffset, int zoffset, float zvalue)
+{
+ if (radiance_buffer == NULL) {
+ return;
+ }
+ float angle;
+ float *radiance_color = radiance_buffer->rect_float;
+ float direction[3];
+ for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y ++) {
+ for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x ++) {
+ // calculate light direction;
+ direction[zoffset] = zvalue;
+ direction[xoffset] = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
+ direction[yoffset] = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
+ normalize_v3(direction);
+ angle = fmax(0.0f, dot_v3v3(direction, normal));
+ madd_v3_v3fl(color, radiance_color, angle);
+ (*hits) ++;
+ radiance_color += 4;
+ }
+ }
+
+}
+
+/*
+ * Spherical Harmonics
+ */
+BLI_INLINE float studiolight_area_element(float x, float y)
+{
+ return atan2(x * y, sqrtf(x * x + y * y + 1));
+}
+
+BLI_INLINE float studiolight_texel_solid_angle(float x, float y, float halfpix)
+{
+ float v1x = (x - halfpix) * 2.0f - 1.0f;
+ float v1y = (y - halfpix) * 2.0f - 1.0f;
+ float v2x = (x + halfpix) * 2.0f - 1.0f;
+ float v2y = (y + halfpix) * 2.0f - 1.0f;
+
+ return studiolight_area_element(v1x, v1y) - studiolight_area_element(v1x, v2y) - studiolight_area_element(v2x, v1y) + studiolight_area_element(v2x, v2y);
+}
+
+static void studiolight_calculate_cubemap_vector_weight(float normal[3], float *weight, int face, float x, float y)
+{
+ copy_v3_fl3(normal, x * 2.0f - 1.0f, y * 2.0f - 1.0f, 1.0f);
+ const float conversion_matrices[6][3][3] = {
+ {
+ {0.0f, 0.0f, 1.0f},
+ {0.0f, -1.0f, 0.0f},
+ {1.0f, 0.0f, 0.0f},
+ },
+ {
+ {0.0f, 0.0f, -1.0f},
+ {0.0f, -1.0f, 0.0f},
+ {-1.0f, 0.0f, 0.0f},
+ },
+ {
+ {1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, -1.0f},
+ {0.0f, 1.0f, 0.0f},
+ },
+ {
+ {1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 1.0f},
+ {0.0f, -1.0f, 0.0f},
+ },
+ {
+ {1.0f, 0.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f},
+ {0.0f, 0.0f, -1.0f},
+ },
+ {
+ {-1.0f, 0.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f},
+ {0.0f, 0.0f, 1.0f},
+ }
+ };
+
+ mul_m3_v3(conversion_matrices[face], normal);
+ normalize_v3(normal);
+ const float halfpix = 1.0f / (2.0f * STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ *weight = studiolight_texel_solid_angle(x + halfpix, y + halfpix, halfpix);
+}
+
+static void studiolight_calculate_spherical_harmonics_coefficient(StudioLight *sl, int sh_component)
+{
+ const float M_4PI = M_PI * 4.0f;
+
+ float weight_accum = 0.0f;
+ float sh[3] = {0.0f, 0.0f, 0.0f};
+ for (int face = 0; face < 6; face++) {
+ float *color;
+ color = sl->radiance_cubemap_buffers[face]->rect_float;
+ for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++) {
+ float yf = y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE;
+ for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++) {
+ float xf = x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE;
+ float weight, coef;
+ float cubevec[3];
+ studiolight_calculate_cubemap_vector_weight(cubevec, &weight, face, xf, yf);
+
+ switch (sh_component) {
+ case 0:
+ {
+ coef = 0.2822095f;
+ break;
+ }
+
+ case 1:
+ {
+ coef = -0.488603f * cubevec[2] * 2.0f / 3.0f;
+ break;
+ }
+ case 2:
+ {
+ coef = 0.488603f * cubevec[1] * 2.0f / 3.0f;
+ break;
+ }
+ case 3:
+ {
+ coef = -0.488603f * cubevec[0] * 2.0f / 3.0f;
+ break;
+ }
+
+ case 4:
+ {
+ coef = 1.092548f * cubevec[0] * cubevec[2] * 1.0f / 4.0f;
+ break;
+ }
+ case 5:
+ {
+ coef = -1.092548f * cubevec[2] * cubevec[1] * 1.0f / 4.0f;
+ break;
+ }
+ case 6:
+ {
+ coef = 0.315392f * (3.0f * cubevec[2] * cubevec[2] - 1.0f) * 1.0f / 4.0f;
+ break;
+ }
+ case 7:
+ {
+ coef = 1.092548f * cubevec[0] * cubevec[1] * 1.0f / 4.0f;
+ break;
+ }
+ case 8:
+ {
+ coef = 0.546274f * (cubevec[0] * cubevec[0] - cubevec[2] * cubevec[2]) * 1.0f / 4.0f;
+ break;
+ }
+
+ default:
+ {
+ coef = 0.0f;
+ }
+ }
+
+ madd_v3_v3fl(sh, color, coef * weight);
+ weight_accum += weight;
+ color += 4;
+ }
+ }
+ }
+
+ mul_v3_fl(sh, M_4PI / weight_accum);
+ copy_v3_v3(sl->spherical_harmonics_coefs[sh_component], sh);
+}
+
+#ifdef STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING
+static void studiolight_calculate_spherical_harmonics_luminance(StudioLight *sl, float luminance[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS])
+{
+ for (int index = 0; index < STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS; index++) {
+ luminance[index] = rgb_to_grayscale(sl->spherical_harmonics_coefs[index]);
+ }
+}
+
+static void studiolight_apply_spherical_harmonics_windowing(StudioLight *sl, float max_lamplacian)
+{
+ /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf */
+ float table_l[STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL + 1];
+ float table_b[STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL + 1];
+
+ table_l[0] = 0.0f;
+ table_b[0] = 0.0f;
+
+ /* convert to luminance */
+ float luminance[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS];
+ studiolight_calculate_spherical_harmonics_luminance(sl, luminance);
+
+ int index = 1;
+ for (int level = 1; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; level++) {
+ table_l[level] = (float)(SQUARE(level) * SQUARE(level + 1));
+
+ float b = 0.0f;
+ for (int m = -1; m <= level; m++) {
+ b += SQUARE(luminance[index++]);
+ }
+ table_b[level] = b;
+ }
+
+ float squared_lamplacian = 0.0f;
+ for (int level = 1; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; level++) {
+ squared_lamplacian += table_l[level] * table_b[level];
+ }
+
+ const float target_squared_laplacian = max_lamplacian * max_lamplacian;
+ if (squared_lamplacian <= target_squared_laplacian) {
+ return;
+ }
+
+ float lambda = 0.0f;
+
+ const int no_iterations = 10000000;
+ for (int i = 0; i < no_iterations; ++i) {
+ float f = 0.0f;
+ float fd = 0.0f;
+
+ for (int level = 1; level <= (int)STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; ++level) {
+ f += table_l[level] * table_b[level] / SQUARE(1.0f + lambda * table_l[level]);
+ fd += (2.0f * SQUARE(table_l[level]) * table_b[level]) / CUBE(1.0f + lambda * table_l[level]);
+ }
+
+ f = target_squared_laplacian - f;
+
+ float delta = -f / fd;
+ lambda += delta;
+
+ if (ABS(delta) < 1e-6f) {
+ break;
+ }
+ }
+
+ /* Apply windowing lambda */
+ index = 0;
+ for (int level = 0; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; level ++) {
+ float s = 1.0f / (1.0f + lambda * SQUARE(level) * SQUARE(level + 1.0f));
+
+ for (int m = -1; m <= level; m++) {
+ mul_v3_fl(sl->spherical_harmonics_coefs[index++], s);
+ }
+ }
+}
+#endif
+
+BLI_INLINE void studiolight_sample_spherical_harmonics(StudioLight *sl, float color[3], float normal[3])
+{
+ copy_v3_fl(color, 0.0f);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f);
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 0
+ /* Spherical Harmonics L1 */
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[1], -0.488603f * normal[2]);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[2], 0.488603f * normal[1]);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[3], -0.488603f * normal[0]);
+#endif
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 1
+ /* Spherical Harmonics L1 */
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[4], 1.092548f * normal[0] * normal[2]);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[5], -1.092548f * normal[2] * normal[1]);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[6], 0.315392f * (3.0f * normal[1] * normal[1] - 1.0f));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[7], -1.092548 * normal[0] * normal[1]);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[8], 0.546274 * (normal[0] * normal[0] - normal[2] * normal[2]));
+#endif
+}
+
+static void studiolight_calculate_diffuse_light(StudioLight *sl)
+{
+ /* init light to black */
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
+
+ for (int comp = 0; comp < STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS; comp ++) {
+ studiolight_calculate_spherical_harmonics_coefficient(sl, comp);
+ }
+
+#ifdef STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING
+ studiolight_apply_spherical_harmonics_windowing(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING_TARGET_LAMPLACIAN);
+#endif
+
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ FILE *fp = BLI_fopen(sl->path_sh_cache, "wb");
+ if (fp) {
+ fwrite(sl->spherical_harmonics_coefs, sizeof(sl->spherical_harmonics_coefs), 1, fp);
+ fclose(fp);
+ }
+ }
+ }
+ sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
+}
+
+static float texel_coord_solid_angle(float a_U, float a_V, int a_Size)
+{
+ //scale up to [-1, 1] range (inclusive), offset by 0.5 to point to texel center.
+ float u = (2.0f * ((float)a_U + 0.5f) / (float)a_Size ) - 1.0f;
+ float v = (2.0f * ((float)a_V + 0.5f) / (float)a_Size ) - 1.0f;
+
+ float resolution_inv = 1.0f / a_Size;
+
+ // U and V are the -1..1 texture coordinate on the current face.
+ // Get projected area for this texel
+ float x0 = u - resolution_inv;
+ float y0 = v - resolution_inv;
+ float x1 = u + resolution_inv;
+ float y1 = v + resolution_inv;
+ return studiolight_area_element(x0, y0) - studiolight_area_element(x0, y1) - studiolight_area_element(x1, y0) + studiolight_area_element(x1, y1);
+}
+
+BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(
+ ImBuf *radiance_buffer, const float normal[3], float color[3],
+ int xoffset, int yoffset, int zoffset, float zvalue)
+{
+ if (radiance_buffer == NULL) {
+ return;
+ }
+ float angle;
+ float *radiance_color = radiance_buffer->rect_float;
+ float direction[3];
+ for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y ++) {
+ for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x ++) {
+ // calculate light direction;
+ float u = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
+ float v = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
+ direction[zoffset] = zvalue;
+ direction[xoffset] = u;
+ direction[yoffset] = v;
+ normalize_v3(direction);
+ angle = fmax(0.0f, dot_v3v3(direction, normal)) * texel_coord_solid_angle(x, y, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ madd_v3_v3fl(color, radiance_color, angle);
+ radiance_color += 4;
+ }
+ }
+
+}
+
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+static void studiolight_calculate_specular_irradiance(StudioLight *sl, float color[3], const float normal[3])
+{
+ copy_v3_fl(color, 0.0f);
+
+ /* back */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, 0, 2, 1, 0.5);
+ /* front */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, 0, 2, 1, -0.5);
+
+ /* left */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, 1, 2, 0, 0.5);
+ /* right */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, 1, 2, 0, -0.5);
+
+ /* top */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, 0, 1, 2, 0.5);
+ /* bottom */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, 0, 1, 2, -0.5);
+
+ mul_v3_fl(color, 1.0 / M_PI);
+}
+#endif
+
+static bool studiolight_load_irradiance_equirectangular_image(StudioLight *sl)
+{
+#ifdef STUDIOLIGHT_LOAD_CACHED_FILES
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ ImBuf *ibuf = NULL;
+ ibuf = IMB_loadiffname(sl->path_irr_cache, 0, NULL);
+ if (ibuf) {
+ IMB_float_from_rect(ibuf);
+ sl->equirectangular_irradiance_buffer = ibuf;
+ sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED;
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+static bool studiolight_load_spherical_harmonics_coefficients(StudioLight *sl)
+{
+#ifdef STUDIOLIGHT_LOAD_CACHED_FILES
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ FILE *fp = BLI_fopen(sl->path_sh_cache, "rb");
+ if (fp) {
+ if (fread((void *)(sl->spherical_harmonics_coefs), sizeof(sl->spherical_harmonics_coefs), 1, fp)) {
+ sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
+ fclose(fp);
+ return true;
+ }
+ fclose(fp);
+ }
+ }
+#endif
+ return false;
+}
+
+static void studiolight_calculate_irradiance_equirectangular_image(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
+#endif
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED);
+#endif
+
+ float *colbuf = MEM_mallocN(STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH * STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * sizeof(float[4]), __func__);
+ float *color = colbuf;
+ for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT ; y ++) {
+ float yf = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT;
+
+ for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH ; x ++) {
+ float xf = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH;
+ float dir[3];
+ equirectangular_to_direction(dir, xf, yf);
+
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ studiolight_calculate_specular_irradiance(sl, color, dir);
+#endif
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS
+ studiolight_sample_spherical_harmonics(sl, color, dir);
+#endif
+
+ color[3] = 1.0f;
+ color += 4;
+ }
+ }
+
+ sl->equirectangular_irradiance_buffer = IMB_allocFromBuffer(
+ NULL, colbuf,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT);
+ MEM_freeN(colbuf);
+
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ /*
+ * Only store cached files when using STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ */
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ IMB_saveiff(sl->equirectangular_irradiance_buffer, sl->path_irr_cache, IB_rectfloat);
+ }
+#endif
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED;
+}
+
+static void studiolight_calculate_light_direction(StudioLight *sl)
+{
+ float best_light = 0.0;
+ sl->light_direction[0] = 0.0f;
+ sl->light_direction[1] = 0.0f;
+ sl->light_direction[2] = -1.0f;
+
+ if ((sl->flag & STUDIOLIGHT_EXTERNAL_FILE) && (sl->flag & STUDIOLIGHT_ORIENTATION_WORLD)) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
+ ImBuf *ibuf = sl->equirectangular_irradiance_buffer;
+ if (ibuf) {
+ /* go over every pixel, determine light, if higher calc direction off the light */
+ float new_light;
+ float *color = ibuf->rect_float;
+ for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT; y ++) {
+ for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH; x ++) {
+ new_light = color[0] + color[1] + color[2];
+ if (new_light > best_light) {
+ float u = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH;
+ float v = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT;
+ equirectangular_to_direction(sl->light_direction, u, v);
+ SWAP(float, sl->light_direction[0], sl->light_direction[1]);
+ normalize_v3(sl->light_direction);
+ negate_v3(sl->light_direction);
+ best_light = new_light;
+ }
+ color += 4;
+ }
+ }
+ }
+ }
+ sl->flag |= STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED;
+}
+
+static StudioLight *studiolight_add_file(const char *path, int flag)
+{
+ char filename[FILE_MAXFILE];
+ BLI_split_file_part(path, filename, FILE_MAXFILE);
+ if (BLI_path_extension_check_array(filename, imb_ext_image)) {
+ StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | flag);
+ BLI_strncpy(sl->name, filename, FILE_MAXFILE);
+ BLI_strncpy(sl->path, path, FILE_MAXFILE);
+ sl->path_irr_cache = BLI_string_joinN(path, ".irr");
+ sl->path_sh_cache = BLI_string_joinN(path, ".sh2");
+ BLI_addtail(&studiolights, sl);
+ return sl;
+ }
+ return NULL;
+}
+
+static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag)
+{
+ struct direntry *dir;
+ const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
+ if (folder) {
+ uint totfile = BLI_filelist_dir_contents(folder, &dir);
+ int i;
+ for (i = 0; i < totfile; i++) {
+ if ((dir[i].type & S_IFREG)) {
+ studiolight_add_file(dir[i].path, flag);
+ }
+ }
+ BLI_filelist_free(dir, totfile);
+ dir = NULL;
+ }
+}
+
+static int studiolight_flag_cmp_order(const StudioLight *sl)
+{
+ /* Internal studiolights before external studio lights */
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ return 1;
+ }
+ return 0;
+}
+
+static int studiolight_cmp(const void *a, const void *b)
+{
+ const StudioLight *sl1 = a;
+ const StudioLight *sl2 = b;
+
+ const int flagorder1 = studiolight_flag_cmp_order(sl1);
+ const int flagorder2 = studiolight_flag_cmp_order(sl2);
+
+ if (flagorder1 < flagorder2) {
+ return -1;
+ }
+ else if (flagorder1 > flagorder2) {
+ return 1;
+ }
+ else {
+ return BLI_strcasecmp(sl1->name, sl2->name);
+ }
+}
+
+/* icons */
+
+/* Takes normalized uvs as parameter (range from 0 to 1).
+ * inner_edge and outer_edge are distances (from the center)
+ * in uv space for the alpha mask falloff. */
+static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge)
+{
+ /* Coords from center. */
+ float co[2] = {u - 0.5f, v - 0.5f};
+ float dist = len_v2(co);
+ float alpha = 1.0f + (inner_edge - dist) / (outer_edge - inner_edge);
+ uint mask = (uint)floorf(255.0f * min_ff(max_ff(alpha, 0.0f), 1.0f));
+ return mask << 24;
+}
+
+#define STUDIOLIGHT_DIAMETER 0.95f
+
+static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
+{
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+
+ float pixel_size = 1.0f / (float)STUDIOLIGHT_ICON_SIZE;
+
+ int offset = 0;
+ for (int y = 0; y < STUDIOLIGHT_ICON_SIZE; y++) {
+ float dy = (y + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+ for (int x = 0; x < STUDIOLIGHT_ICON_SIZE; x++) {
+ float dx = (x + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+
+ uint pixelresult = 0x0;
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f);
+ if (alphamask != 0) {
+ float incoming[3] = {0.0f, 0.0f, -1.0f};
+
+ float normal[3];
+ normal[0] = dx * 2.0f - 1.0f;
+ normal[1] = dy * 2.0f - 1.0f;
+ float dist = len_v2(normal);
+ normal[2] = sqrtf(1.0f - SQUARE(dist));
+
+ float direction[3];
+ reflect_v3_v3v3(direction, incoming, normal);
+
+ /* We want to see horizon not poles. */
+ SWAP(float, direction[1], direction[2]);
+ direction[1] = -direction[1];
+
+ float color[4];
+ studiolight_calculate_radiance(sl->equirectangular_radiance_buffer, color, direction);
+
+ pixelresult = rgb_to_cpack(
+ linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ icon_buffer[offset++] = pixelresult;
+ }
+ }
+}
+
+static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped)
+{
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+
+ float color[4];
+ float fx, fy;
+ float pixel_size = 1.0f / (float)STUDIOLIGHT_ICON_SIZE;
+ int offset = 0;
+ ImBuf *ibuf = sl->equirectangular_radiance_buffer;
+
+ for (int y = 0; y < STUDIOLIGHT_ICON_SIZE; y++) {
+ fy = (y + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ fy = fy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+ for (int x = 0; x < STUDIOLIGHT_ICON_SIZE; x++) {
+ fx = (x + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ fx = fx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+ if (flipped) {
+ fx = 1.0f - fx;
+ }
+ nearest_interpolation_color(ibuf, NULL, color, fx * ibuf->x, fy * ibuf->y);
+
+ uint alphamask = alpha_circle_mask(fx, fy, 0.5f - pixel_size, 0.5f);
+
+ icon_buffer[offset++] = rgb_to_cpack(
+ linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ }
+}
+
+static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl)
+{
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED);
+
+ float pixel_size = 1.0f / (float)STUDIOLIGHT_ICON_SIZE;
+
+ int offset = 0;
+ for (int y = 0; y < STUDIOLIGHT_ICON_SIZE; y++) {
+ float dy = (y + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+ for (int x = 0; x < STUDIOLIGHT_ICON_SIZE; x++) {
+ float dx = (x + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+
+ uint pixelresult = 0x0;
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f);
+ if (alphamask != 0) {
+ /* calculate normal */
+ float normal[3];
+ normal[0] = dx * 2.0f - 1.0f;
+ normal[1] = -(dy * 2.0f - 1.0f);
+ float dist = len_v2(normal);
+ normal[2] = -sqrtf(1.0f - SQUARE(dist));
+ SWAP(float, normal[1], normal[2]);
+
+ float color[3];
+ studiolight_sample_spherical_harmonics(sl, color, normal);
+ pixelresult = rgb_to_cpack(
+ linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ icon_buffer[offset++] = pixelresult;
+ }
+ }
+}
+
+/* API */
+void BKE_studiolight_init(void)
+{
+ StudioLight *sl;
+ /* go over the preset folder and add a studiolight for every image with its path */
+ /* order studio lights by name */
+ /* Also reserve icon space for it. */
+ /* Add default studio light */
+ sl = studiolight_create(STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA);
+ BLI_strncpy(sl->name, "Default", FILE_MAXFILE);
+
+
+ copy_v3_fl3(sl->spherical_harmonics_coefs[0], 1.03271556f, 1.07163882f, 1.11193657f);
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 0
+ copy_v3_fl3(sl->spherical_harmonics_coefs[1], -0.00480952f, 0.05290511f, 0.16394117f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[2], -0.29686999f, -0.27378261f, -0.24797194f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[3], 0.47932500f, 0.48242140f, 0.47190312f);
+#endif
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 1
+ copy_v3_fl3(sl->spherical_harmonics_coefs[4], -0.00576984f, 0.00504886f, 0.01640534f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[5], 0.15500379f, 0.15415503f, 0.16244425f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[6], -0.02483751f, -0.02245096f, -0.00536885f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[7], 0.11155496f, 0.11005443f, 0.10839636f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[8], 0.01363425f, 0.01278363f, -0.00159006f);
+#endif
+
+ BLI_addtail(&studiolights, sl);
+
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_USER_DEFINED);
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_USER_DEFINED);
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_USER_DEFINED);
+
+ /* sort studio lights on filename. */
+ BLI_listbase_sort(&studiolights, studiolight_cmp);
+}
+
+void BKE_studiolight_free(void)
+{
+ struct StudioLight *sl;
+ while ((sl = BLI_pophead(&studiolights))) {
+ studiolight_free(sl);
+ }
+}
+
+struct StudioLight *BKE_studiolight_find_first(int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if ((sl->flag & flag)) {
+ return sl;
+ }
+ }
+ return NULL;
+}
+
+struct StudioLight *BKE_studiolight_find(const char *name, int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
+ if ((sl->flag & flag)) {
+ return sl;
+ }
+ else {
+ /* flags do not match, so use default */
+ return BKE_studiolight_find_first(flag);
+ }
+ }
+ }
+ /* When not found, use the default studio light */
+ return BKE_studiolight_find_first(flag);
+}
+
+struct StudioLight *BKE_studiolight_findindex(int index, int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if (sl->index == index) {
+ return sl;
+ }
+ }
+ /* When not found, use the default studio light */
+ return BKE_studiolight_find_first(flag);
+}
+
+struct ListBase *BKE_studiolight_listbase(void)
+{
+ return &studiolights;
+}
+
+void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type)
+{
+ switch (icon_id_type) {
+ case STUDIOLIGHT_ICON_ID_TYPE_RADIANCE:
+ default:
+ {
+ studiolight_radiance_preview(icon_buffer, sl);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE:
+ {
+ studiolight_irradiance_preview(icon_buffer, sl);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_MATCAP:
+ {
+ studiolight_matcap_preview(icon_buffer, sl, false);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED:
+ {
+ studiolight_matcap_preview(icon_buffer, sl, true);
+ break;
+ }
+ }
+}
+
+/* Ensure state of Studiolights */
+void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
+{
+ if ((sl->flag & flag) == flag) {
+ return;
+ }
+
+ if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) {
+ studiolight_load_equirectangular_image(sl);
+ }
+ if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) {
+ studiolight_calculate_radiance_cubemap_buffers(sl);
+ }
+ if ((flag & STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED)) {
+ if (!studiolight_load_spherical_harmonics_coefficients(sl)) {
+ studiolight_calculate_diffuse_light(sl);
+ }
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE)) {
+ studiolight_create_equirectangular_radiance_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED)) {
+ studiolight_calculate_light_direction(sl);
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE)) {
+ studiolight_create_equirectangular_irradiance_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED)) {
+ if (!studiolight_load_irradiance_equirectangular_image(sl)) {
+ studiolight_calculate_irradiance_equirectangular_image(sl);
+ }
+ }
+}
+
+/*
+ * Python API Functions
+ */
+void BKE_studiolight_remove(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ BLI_remlink(&studiolights, sl);
+ studiolight_free(sl);
+ }
+}
+
+StudioLight *BKE_studiolight_new(const char *path, int orientation)
+{
+ StudioLight *sl = studiolight_add_file(path, orientation | STUDIOLIGHT_USER_DEFINED);
+ return sl;
+}
+
+void BKE_studiolight_refresh(void)
+{
+ BKE_studiolight_free();
+ BKE_studiolight_init();
+}
+
+void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data)
+{
+ sl->free_function = free_function;
+ sl->free_function_data = data;
+}
+
+void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id)
+{
+ BLI_assert(sl != NULL);
+ if (sl->icon_id_radiance == icon_id) {
+ sl->icon_id_radiance = 0;
+ }
+ if (sl->icon_id_irradiance == icon_id) {
+ sl->icon_id_irradiance = 0;
+ }
+ if (sl->icon_id_matcap == icon_id) {
+ sl->icon_id_matcap = 0;
+ }
+ if (sl->icon_id_matcap_flipped == icon_id) {
+ sl->icon_id_matcap_flipped = 0;
+ }
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 1f1270b85b6..9ea6ef62e4e 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -69,6 +69,7 @@
#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
@@ -77,12 +78,6 @@
# include "BLI_array.h"
#endif
-#include "GPU_draw.h"
-#include "GPU_glew.h"
-#include "GPU_buffers.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
#include "CCGSubSurf.h"
#ifdef WITH_OPENSUBDIV
@@ -1775,47 +1770,7 @@ static void ccgDM_foreachMappedLoop(
}
}
-static void ccgDM_drawVerts(DerivedMesh *dm)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- CCGVertIterator vi;
- CCGEdgeIterator ei;
- CCGFaceIterator fi;
-
- glBegin(GL_POINTS);
- for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
- CCGVert *v = ccgVertIterator_getCurrent(&vi);
- glVertex3fv(ccgSubSurf_getVertData(ss, v));
- }
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- int x;
-
- for (x = 1; x < edgeSize - 1; x++)
- glVertex3fv(ccgSubSurf_getEdgeData(ss, e, x));
- }
-
- for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- glVertex3fv(ccgSubSurf_getFaceCenterData(f));
- for (S = 0; S < numVerts; S++)
- for (x = 1; x < gridSize - 1; x++)
- glVertex3fv(ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
- for (S = 0; S < numVerts; S++)
- for (y = 1; y < gridSize - 1; y++)
- for (x = 1; x < gridSize - 1; x++)
- glVertex3fv(ccgSubSurf_getFaceGridData(ss, f, S, x, y));
- }
- glEnd();
-}
-
-static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
+static void UNUSED_FUNCTION(ccgdm_pbvh_update)(CCGDerivedMesh *ccgdm)
{
if (ccgdm->pbvh && ccgDM_use_grid_pbvh(ccgdm)) {
CCGFace **faces;
@@ -1830,2179 +1785,6 @@ static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
}
}
-static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
-{
- GPUDrawObject *gdo;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- /* TODO(sergey): We currently only support all edges drawing. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
- ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
- }
- return;
- }
-#endif
-
- ccgdm_pbvh_update(ccgdm);
-
-/* old debug feature for edges, unsupported for now */
-#if 0
- int useAging = 0;
-
- if (!(G.f & G_BACKBUFSEL)) {
- CCGSubSurf *ss = ccgdm->ss;
- ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
- /* it needs some way to upload this to VBO now */
- if (useAging) {
- int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
- glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
- }
- }
-#endif
-
- GPU_edge_setup(dm);
- gdo = dm->drawObject;
- if (gdo->edges && gdo->points) {
- if (drawAllEdges && drawLooseEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, (gdo->totedge - gdo->totinterior) * 2);
- }
- else if (drawAllEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2);
- }
- else {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2);
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, gdo->tot_loose_edge_drawn * 2);
- }
- }
-
- if (gdo->edges && ccgdm->drawInteriorEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->interior_offset * 2, gdo->totinterior * 2);
- }
- GPU_buffers_unbind();
-}
-
-static void ccgDM_drawLooseEdges(DerivedMesh *dm)
-{
- int start;
- int count;
-
-#ifdef WITH_OPENSUBDIV
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- if (ccgdm->useGpuBackend) {
- /* TODO(sergey): Needs implementation. */
- return;
- }
-#endif
-
- GPU_edge_setup(dm);
-
- start = (dm->drawObject->loose_edge_offset * 2);
- count = (dm->drawObject->interior_offset - dm->drawObject->loose_edge_offset) * 2;
-
- if (count) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count);
- }
-
- GPU_buffers_unbind();
-}
-
-static void ccgDM_NormalFast(float *a, float *b, float *c, float *d, float no[3])
-{
- float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
- float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
-
- no[0] = b_dY * a_cZ - b_dZ * a_cY;
- no[1] = b_dZ * a_cX - b_dX * a_cZ;
- no[2] = b_dX * a_cY - b_dY * a_cX;
-
- normalize_v3(no);
-}
-
-
-static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
-{
- float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
- float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
- float no[3];
-
- no[0] = b_dY * a_cZ - b_dZ * a_cY;
- no[1] = b_dZ * a_cX - b_dX * a_cZ;
- no[2] = b_dX * a_cY - b_dY * a_cX;
-
- /* don't normalize, GL_NORMALIZE is enabled */
- glNormal3fv(no);
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_normal(
- DerivedMesh *dm, short *varray)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int shademodel;
- int start = 0;
-
- /* we are in sculpt mode, disable loop normals (since they won't get updated) */
- if (ccgdm->pbvh)
- lnors = NULL;
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- const float (*ln)[3] = NULL;
-
- if (faceFlags) {
- shademodel = (lnors || (faceFlags[index].flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT;
- }
- else {
- shademodel = GL_SMOOTH;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += gridFaces * gridFaces * numVerts * 4;
- }
-
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
-
- if (ln) {
- /* Can't use quad strips here... */
- for (y = 0; y < gridFaces; y ++) {
- for (x = 0; x < gridFaces; x ++) {
- normal_float_to_short_v3(&varray[start + 0], ln[0]);
- normal_float_to_short_v3(&varray[start + 4], ln[3]);
- normal_float_to_short_v3(&varray[start + 8], ln[2]);
- normal_float_to_short_v3(&varray[start + 12], ln[1]);
-
- start += 16;
- ln += 4;
- }
- }
- }
- else if (shademodel == GL_SMOOTH) {
- for (y = 0; y < gridFaces; y ++) {
- for (x = 0; x < gridFaces; x ++) {
- float *a = CCG_grid_elem_no(&key, faceGridData, x, y );
- float *b = CCG_grid_elem_no(&key, faceGridData, x + 1, y);
- float *c = CCG_grid_elem_no(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_no(&key, faceGridData, x, y + 1);
-
- normal_float_to_short_v3(&varray[start], a);
- normal_float_to_short_v3(&varray[start + 4], b);
- normal_float_to_short_v3(&varray[start + 8], c);
- normal_float_to_short_v3(&varray[start + 12], d);
-
- start += 16;
- }
- }
- }
- else {
- for (y = 0; y < gridFaces; y ++) {
- for (x = 0; x < gridFaces; x ++) {
- float f_no[3];
- short f_no_s[3];
-
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y );
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y );
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_NormalFast(a, b, c, d, f_no);
- normal_float_to_short_v3(f_no_s, f_no);
-
- copy_v3_v3_short(&varray[start], f_no_s);
- copy_v3_v3_short(&varray[start + 4], f_no_s);
- copy_v3_v3_short(&varray[start + 8], f_no_s);
- copy_v3_v3_short(&varray[start + 12], f_no_s);
-
- start += 16;
- }
- }
- }
- }
- }
-}
-
-typedef struct FaceCount {
- unsigned int i_visible;
- unsigned int i_hidden;
- unsigned int i_tri_visible;
- unsigned int i_tri_hidden;
-} FaceCount;
-
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_triangles(
- DerivedMesh *dm, unsigned int *varray,
- const int *mat_orig_to_new)
-{
- GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials;
- const int gpu_totmat = dm->drawObject->totmaterial;
- const short dm_totmat = dm->totmat;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- short mat_nr = -1;
- int start;
- int totloops = 0;
- FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount");
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < gpu_totmat; i++) {
- fc[i].i_visible = 0;
- fc[i].i_tri_visible = 0;
- fc[i].i_hidden = gpumaterials[i].totpolys - 1;
- fc[i].i_tri_hidden = gpumaterials[i].totelements - 1;
- }
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- bool is_hidden;
- int mati;
-
- if (faceFlags) {
- mat_nr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat);
- is_hidden = (faceFlags[index].flag & ME_HIDE) != 0;
- }
- else {
- mat_nr = 0;
- is_hidden = false;
- }
- mati = mat_orig_to_new[mat_nr];
- gpumat = dm->drawObject->materials + mati;
-
- if (is_hidden) {
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- start = gpumat->start + fc[mati].i_tri_hidden;
-
- varray[start--] = totloops;
- varray[start--] = totloops + 2;
- varray[start--] = totloops + 3;
-
- varray[start--] = totloops;
- varray[start--] = totloops + 1;
- varray[start--] = totloops + 2;
-
- fc[mati].i_tri_hidden -= 6;
-
- totloops += 4;
- }
- }
- }
- gpumat->polys[fc[mati].i_hidden--] = i;
- }
- else {
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- start = gpumat->start + fc[mati].i_tri_visible;
-
- varray[start++] = totloops + 3;
- varray[start++] = totloops + 2;
- varray[start++] = totloops;
-
- varray[start++] = totloops + 2;
- varray[start++] = totloops + 1;
- varray[start++] = totloops;
-
- fc[mati].i_tri_visible += 6;
-
- totloops += 4;
- }
- }
- }
- gpumat->polys[fc[mati].i_visible++] = i;
- }
- }
-
- /* set the visible polygons */
- for (i = 0; i < gpu_totmat; i++) {
- gpumaterials[i].totvisiblepolys = fc[i].i_visible;
- }
-
- MEM_freeN(fc);
-}
-
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_vertex(
- DerivedMesh *dm, void *varray_p)
-{
- float *varray = varray_p;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int totedge = ccgSubSurf_getNumEdges(ss);
- int start = 0;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- copy_v3_v3(&varray[start], a);
- copy_v3_v3(&varray[start + 3], b);
- copy_v3_v3(&varray[start + 6], c);
- copy_v3_v3(&varray[start + 9], d);
-
- start += 12;
- }
- }
- }
- }
-
- /* upload loose points */
- for (i = 0; i < totedge; i++) {
- CCGEdge *e = ccgdm->edgeMap[i].edge;
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
-
- if (!ccgSubSurf_getEdgeNumFaces(e)) {
- int j = 0;
- for (j = 0; j < edgeSize; j++) {
- copy_v3_v3(&varray[start], CCG_elem_offset_co(&key, edgeData, j));
- start += 3;
- }
- }
- }
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_color(
- DerivedMesh *dm, unsigned char *varray,
- const void *user_data)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- const unsigned char *mloopcol = user_data;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int start = 0;
- int iface = 0;
-
- CCG_key_top_level(&key, ss);
-
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- copy_v4_v4_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]);
- copy_v4_v4_uchar(&varray[start + 4], &mloopcol[iface * 16 + 12]);
- copy_v4_v4_uchar(&varray[start + 8], &mloopcol[iface * 16 + 8]);
- copy_v4_v4_uchar(&varray[start + 12], &mloopcol[iface * 16 + 4]);
-
- start += 16;
- iface++;
- }
- }
- }
- }
-}
-
-static void ccgDM_buffer_copy_uv(
- DerivedMesh *dm, void *varray_p)
-{
- float *varray = varray_p;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- MLoopUV *mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int start = 0;
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- copy_v2_v2(&varray[start + 0], mloopuv[0].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[3].uv);
- copy_v2_v2(&varray[start + 4], mloopuv[2].uv);
- copy_v2_v2(&varray[start + 6], mloopuv[1].uv);
-
- mloopuv += 4;
- start += 8;
- }
- }
- }
- }
-}
-
-static void ccgDM_buffer_copy_uv_texpaint(
- DerivedMesh *dm, float *varray)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int start = 0;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int dm_totmat = dm->totmat;
- MLoopUV **mloopuv_base;
- MLoopUV *stencil_base;
- int stencil;
-
- CCG_key_top_level(&key, ss);
-
- /* should have been checked for before, reassert */
- BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV));
- mloopuv_base = MEM_mallocN(dm_totmat * sizeof(*mloopuv_base), "texslots");
-
- for (i = 0; i < dm_totmat; i++) {
- mloopuv_base[i] = DM_paint_uvlayer_active_get(dm, i);
- }
-
- stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV);
- stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil);
-
- start = 0;
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- int matnr;
-
- if (faceFlags) {
- matnr = faceFlags[index].mat_nr;
- }
- else {
- matnr = 0;
- }
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- /* divide by 4, gives us current loop-index */
- unsigned int i_ml = start / 4;
- copy_v2_v2(&varray[start + 0], mloopuv_base[matnr][i_ml + 0].uv);
- copy_v2_v2(&varray[start + 2], stencil_base[i_ml + 0].uv);
- copy_v2_v2(&varray[start + 4], mloopuv_base[matnr][i_ml + 3].uv);
- copy_v2_v2(&varray[start + 6], stencil_base[i_ml + 3].uv);
- copy_v2_v2(&varray[start + 8], mloopuv_base[matnr][i_ml + 2].uv);
- copy_v2_v2(&varray[start + 10], stencil_base[i_ml + 2].uv);
- copy_v2_v2(&varray[start + 12], mloopuv_base[matnr][i_ml + 1].uv);
- copy_v2_v2(&varray[start + 14], stencil_base[i_ml + 1].uv);
- start += 16;
- }
- }
- }
- }
-
- MEM_freeN(mloopuv_base);
-}
-
-static void ccgDM_buffer_copy_uvedge(
- DerivedMesh *dm, float *varray)
-{
- int i, totpoly;
- int start;
- const MLoopUV *mloopuv;
-#ifndef USE_LOOP_LAYOUT_FAST
- const MPoly *mpoly = dm->getPolyArray(dm);
-#endif
-
- if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
- return;
- }
-
- totpoly = dm->getNumPolys(dm);
- start = 0;
-
-#ifndef USE_LOOP_LAYOUT_FAST
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv);
- start += 4;
- }
- }
-#else
- for (i = 0; i < totpoly; i++) {
- copy_v2_v2(&varray[start + 0], mloopuv[(i * 4) + 0].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[(i * 4) + 1].uv);
-
- copy_v2_v2(&varray[start + 4], mloopuv[(i * 4) + 1].uv);
- copy_v2_v2(&varray[start + 6], mloopuv[(i * 4) + 2].uv);
-
- copy_v2_v2(&varray[start + 8], mloopuv[(i * 4) + 2].uv);
- copy_v2_v2(&varray[start + 10], mloopuv[(i * 4) + 3].uv);
-
- copy_v2_v2(&varray[start + 12], mloopuv[(i * 4) + 3].uv);
- copy_v2_v2(&varray[start + 14], mloopuv[(i * 4) + 0].uv);
-
- start += 16;
- }
-#endif
-}
-
-static void ccgDM_buffer_copy_edge(
- DerivedMesh *dm, unsigned int *varray)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- /* getEdgeSuze returns num of verts, edges is one less */
- int i, j, edgeSize = ccgSubSurf_getEdgeSize(ss) - 1;
- int totedge = ccgSubSurf_getNumEdges(ss);
- int grid_face_side = ccgSubSurf_getGridSize(ss) - 1;
- int totface = ccgSubSurf_getNumFaces(ss);
- unsigned int index_start;
- unsigned int tot_interior = 0;
- unsigned int grid_tot_face = grid_face_side * grid_face_side;
-
- unsigned int iloose, inorm, iloosehidden, inormhidden;
- unsigned int tot_loose_hidden = 0, tot_loose = 0;
- unsigned int tot_hidden = 0, tot = 0;
- unsigned int iloosevert;
- /* int tot_interior = 0; */
-
- /* first, handle hidden/loose existing edges, then interior edges */
- for (j = 0; j < totedge; j++) {
- CCGEdge *e = ccgdm->edgeMap[j].edge;
-
- if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) {
- if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose_hidden++;
- else tot_hidden++;
- }
- else {
- if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose++;
- else tot++;
- }
- }
-
- inorm = 0;
- inormhidden = tot * edgeSize;
- iloose = (tot + tot_hidden) * edgeSize;
- iloosehidden = (tot + tot_hidden + tot_loose) * edgeSize;
- iloosevert = dm->drawObject->tot_loop_verts;
-
- /* part one, handle all normal edges */
- for (j = 0; j < totedge; j++) {
- CCGFace *f;
- int fhandle = 0;
- int totvert = 0;
- unsigned int S = 0;
- CCGEdge *e = ccgdm->edgeMap[j].edge;
- bool isloose = !ccgSubSurf_getEdgeNumFaces(e);
-
- if (!isloose) {
- CCGVert *v1, *v2;
- CCGVert *ev1 = ccgSubSurf_getEdgeVert0(e);
- CCGVert *ev2 = ccgSubSurf_getEdgeVert1(e);
-
- f = ccgSubSurf_getEdgeFace(e, 0);
- fhandle = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- totvert = ccgSubSurf_getFaceNumVerts(f);
-
- /* find the index of vertices in the face */
- for (i = 0; i < totvert; i++) {
- v1 = ccgSubSurf_getFaceVert(f, i);
- v2 = ccgSubSurf_getFaceVert(f, (i + 1) % totvert);
-
- if ((ev1 == v1 && ev2 == v2) || (ev1 == v2 && ev2 == v1)) {
- S = i;
- break;
- }
- }
- }
-
- if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) {
- if (isloose) {
- for (i = 0; i < edgeSize; i++) {
- varray[iloosehidden * 2] = iloosevert;
- varray[iloosehidden * 2 + 1] = iloosevert + 1;
- iloosehidden++;
- iloosevert++;
- }
- /* we are through with this loose edge and moving to the next, so increase by one */
- iloosevert++;
- }
- else {
- index_start = ccgdm->faceMap[fhandle].startFace;
-
- for (i = 0; i < grid_face_side; i++) {
- varray[inormhidden * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1;
- varray[inormhidden * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2;
- varray[inormhidden * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2;
- varray[inormhidden * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3;
- inormhidden += 2;
- }
- }
- }
- else {
- if (isloose) {
- for (i = 0; i < edgeSize; i++) {
- varray[iloose * 2] = iloosevert;
- varray[iloose * 2 + 1] = iloosevert + 1;
- iloose++;
- iloosevert++;
- }
- /* we are through with this loose edge and moving to the next, so increase by one */
- iloosevert++;
- }
- else {
- index_start = ccgdm->faceMap[fhandle].startFace;
-
- for (i = 0; i < grid_face_side; i++) {
- varray[inorm * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1;
- varray[inorm * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2;
- varray[inorm * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2;
- varray[inorm * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3;
- inorm += 2;
- }
- }
- }
- }
-
- /* part two, handle interior edges */
- inorm = totedge * grid_face_side * 2;
-
- index_start = 0;
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- unsigned int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (x = 1; x < grid_face_side; x++) {
- for (y = 0; y < grid_face_side; y++) {
- unsigned int tmp = (index_start + x * grid_face_side + y) * 4;
- varray[inorm * 2] = tmp;
- varray[inorm * 2 + 1] = tmp + 1;
- inorm++;
- }
- }
- for (x = 0; x < grid_face_side; x++) {
- for (y = 0; y < grid_face_side; y++) {
- unsigned int tmp = (index_start + x * grid_face_side + y) * 4;
- varray[inorm * 2] = tmp + 3;
- varray[inorm * 2 + 1] = tmp;
- inorm++;
- }
- }
-
- tot_interior += grid_face_side * (2 * grid_face_side - 1);
- index_start += grid_tot_face;
- }
- }
-
- dm->drawObject->tot_loose_edge_drawn = tot_loose * edgeSize;
- dm->drawObject->loose_edge_offset = (tot + tot_hidden) * edgeSize;
- dm->drawObject->tot_edge_drawn = tot * edgeSize;
-
- dm->drawObject->interior_offset = totedge * edgeSize;
- dm->drawObject->totinterior = tot_interior;
-}
-
-static void ccgDM_copy_gpu_data(
- DerivedMesh *dm, int type, void *varray_p,
- const int *mat_orig_to_new, const void *user_data)
-{
- /* 'varray_p' cast is redundant but include for self-documentation */
- switch (type) {
- case GPU_BUFFER_VERTEX:
- ccgDM_buffer_copy_vertex(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_NORMAL:
- ccgDM_buffer_copy_normal(dm, (short *)varray_p);
- break;
- case GPU_BUFFER_UV:
- ccgDM_buffer_copy_uv(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_UV_TEXPAINT:
- ccgDM_buffer_copy_uv_texpaint(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_COLOR:
- ccgDM_buffer_copy_color(dm, (unsigned char *)varray_p, user_data);
- break;
- case GPU_BUFFER_UVEDGE:
- ccgDM_buffer_copy_uvedge(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_EDGE:
- ccgDM_buffer_copy_edge(dm, (unsigned int *)varray_p);
- break;
- case GPU_BUFFER_TRIANGLES:
- ccgDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new);
- break;
- default:
- break;
- }
-}
-
-static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- GPUDrawObject *gdo;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
- const short dm_totmat = (faceFlags) ? dm->totmat : 1;
- GPUBufferMaterial *matinfo;
- int i;
- unsigned int tot_internal_edges = 0;
- int edgeVerts = ccgSubSurf_getEdgeSize(ss);
- int edgeSize = edgeVerts - 1;
-
- int totedge = ccgSubSurf_getNumEdges(ss);
- int totface = ccgSubSurf_getNumFaces(ss);
-
- /* object contains at least one material (default included) so zero means uninitialized dm */
- BLI_assert(dm_totmat != 0);
-
- matinfo = MEM_callocN(sizeof(*matinfo) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new");
-
- if (faceFlags) {
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- const short new_matnr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat);
- matinfo[new_matnr].totelements += numVerts * gridFaces * gridFaces * 6;
- matinfo[new_matnr].totloops += numVerts * gridFaces * gridFaces * 4;
- matinfo[new_matnr].totpolys++;
- tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1);
- }
- }
- else {
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- matinfo[0].totelements += numVerts * gridFaces * gridFaces * 6;
- matinfo[0].totloops += numVerts * gridFaces * gridFaces * 4;
- matinfo[0].totpolys++;
- tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1);
- }
- }
-
- /* create the GPUDrawObject */
- gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
- gdo->totvert = 0; /* used to count indices, doesn't really matter for ccgsubsurf */
- gdo->totedge = (totedge * edgeSize + tot_internal_edges);
-
- GPU_buffer_material_finalize(gdo, matinfo, dm_totmat);
-
- /* store total number of points used for triangles */
- gdo->tot_triangle_point = ccgSubSurf_getNumFinalFaces(ss) * 6;
- gdo->tot_loop_verts = ccgSubSurf_getNumFinalFaces(ss) * 4;
-
- /* finally, count loose points */
- for (i = 0; i < totedge; i++) {
- CCGEdge *e = ccgdm->edgeMap[i].edge;
-
- if (!ccgSubSurf_getEdgeNumFaces(e))
- gdo->tot_loose_point += edgeVerts;
- }
-
- return gdo;
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], bool fast, DMSetMaterial setMaterial)
-{
- int a;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-
- ccgdm_pbvh_update(ccgdm);
-
- if (ccgdm->pbvh && ccgdm->multires.mmd) {
- if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
- BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
- setMaterial, false, fast);
- }
-
- return;
- }
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- CCGSubSurf *ss = ccgdm->ss;
- const DMFlagMat *faceFlags = ccgdm->faceFlags;
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int i, current_patch = 0;
- int mat_nr = -1;
- bool draw_smooth = false;
- int start_draw_patch = -1, num_draw_patches = 0;
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) {
- return;
- }
- if (setMaterial == NULL) {
- ccgSubSurf_drawGLMesh(ss,
- true,
- -1,
- -1);
- return;
- }
- for (i = 0; i < num_base_faces; ++i) {
- const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
- const int num_patches = (num_face_verts == 4) ? face_patches
- : num_face_verts * grid_patches;
- int new_matnr;
- bool new_draw_smooth;
- if (faceFlags) {
- new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- new_matnr = (faceFlags[i].mat_nr + 1);
- }
- else {
- new_draw_smooth = true;
- new_matnr = 1;
- }
- if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, NULL);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- start_draw_patch = current_patch;
- num_draw_patches = num_patches;
- mat_nr = new_matnr;
- draw_smooth = new_draw_smooth;
- }
- else {
- num_draw_patches += num_patches;
- }
- current_patch += num_patches;
- }
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, NULL);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- for (a = 0; a < dm->drawObject->totmaterial; a++) {
- if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start,
- dm->drawObject->materials[a].totelements);
- }
- }
- GPU_buffers_unbind();
-}
-
-typedef struct {
- DMVertexAttribs attribs;
- int numdata;
-
- GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/
-} GPUMaterialConv;
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- GPUVertexAttribs gattribs;
- int a, b;
- const DMFlagMat *faceFlags = ccgdm->faceFlags;
- unsigned char *varray;
- size_t max_element_size = 0;
- int tot_loops = 0;
- int totpoly = ccgSubSurf_getNumFaces(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int i, current_patch = 0;
- int mat_nr = -1;
- bool draw_smooth = false;
- int start_draw_patch = -1, num_draw_patches = 0;
- GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) {
- return;
- }
- for (i = 0; i < num_base_faces; ++i) {
- const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
- const int num_patches = (num_face_verts == 4) ? face_patches
- : num_face_verts * grid_patches;
- int new_matnr;
- bool new_draw_smooth;
-
- if (faceFlags) {
- new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- new_matnr = (faceFlags[i].mat_nr + 1);
- }
- else {
- new_draw_smooth = true;
- new_matnr = 1;
- }
- if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, &gattribs);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- start_draw_patch = current_patch;
- num_draw_patches = num_patches;
- mat_nr = new_matnr;
- draw_smooth = new_draw_smooth;
- }
- else {
- num_draw_patches += num_patches;
- }
- current_patch += num_patches;
- }
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, &gattribs);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
- if (setDrawOptions != NULL) {
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- DMVertexAttribs attribs = {{{NULL}}};
- int i;
- int matnr = -1;
- int do_draw = 0;
-
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
- DM_draw_attrib_vertex_uniforms(&attribs); \
-} (void)0
-
- totpoly = ccgSubSurf_getNumFaces(ss);
- for (a = 0, i = 0; i < totpoly; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- const float (*ln)[3] = NULL;
- int S, x, y, drawSmooth;
- int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- int origIndex = ccgDM_getFaceMapIndex(ss, f);
-
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int new_matnr;
-
- if (faceFlags) {
- drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
- new_matnr = faceFlags[index].mat_nr + 1;
- }
- else {
- drawSmooth = 1;
- new_matnr = 1;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
-
- if (new_matnr != matnr) {
- do_draw = setMaterial(matnr = new_matnr, &gattribs);
- if (do_draw)
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- }
-
- if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) &&
- (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP)))
- {
- a += gridFaces * gridFaces * numVerts;
- continue;
- }
-
- glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- CCGElem *vda, *vdb;
-
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(ln[1]);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glNormal3fv(ln[2]);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glNormal3fv(ln[3]);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glNormal3fv(ln[0]);
- glVertex3fv(aco);
-
- ln += 4;
- a++;
- }
- }
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 0);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- if (x != gridFaces - 1)
- a++;
- }
-
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 3);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 2);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- glEnd();
-
- a++;
- }
- }
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_glNormalFast(aco, bco, cco, dco);
-
- PASSATTRIB(0, 1, 1);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glVertex3fv(aco);
-
- a++;
- }
- }
- glEnd();
- }
- }
- }
-
- glShadeModel(GL_SMOOTH);
-#undef PASSATTRIB
- }
- else {
- GPUMaterialConv *matconv;
- size_t offset;
- int *mat_orig_to_new;
- int tot_active_mat;
- GPUBuffer *buffer = NULL;
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
-
- tot_active_mat = dm->drawObject->totmaterial;
-
- matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat,
- "cdDM_drawMappedFacesGLSL.matconv");
- mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
- "cdDM_drawMappedFacesGLSL.mat_orig_to_new");
-
- /* part one, check what attributes are needed per material */
- for (a = 0; a < tot_active_mat; a++) {
- int new_matnr;
- int do_draw;
-
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- /* map from original material index to new
- * GPUBufferMaterial index */
- mat_orig_to_new[new_matnr] = a;
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- int numdata = 0;
- DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs);
-
- if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
- matconv[a].datatypes[numdata].size = 3;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- for (b = 0; b < matconv[a].attribs.tottface; b++) {
- if (matconv[a].attribs.tface[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 2;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.totmcol; b++) {
- if (matconv[a].attribs.mcol[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.tottang; b++) {
- if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- if (numdata != 0) {
- matconv[a].numdata = numdata;
- max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size);
- }
- }
- }
-
- /* part two, generate and fill the arrays with the data */
- if (max_element_size > 0) {
- buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts);
-
- varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY);
- if (varray == NULL) {
- GPU_buffers_unbind();
- GPU_buffer_free(buffer);
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- fprintf(stderr, "Out of memory, can't draw object\n");
- return;
- }
-
- for (a = 0; a < totpoly; a++) {
- CCGFace *f = ccgdm->faceMap[a].face;
- int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int i;
-
- if (faceFlags) {
- i = mat_orig_to_new[faceFlags[orig_index].mat_nr];
- }
- else {
- i = mat_orig_to_new[0];
- }
-
- if (matconv[i].numdata != 0) {
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
-
- offset = tot_loops * max_element_size;
-
- if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) {
- int index;
-
- index = getFaceIndex(ss, f, S, x, y, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset],
- (float *)matconv[i].attribs.orco.array[index]);
- index = getFaceIndex(ss, f, S, x + 1, y, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset + max_element_size],
- (float *)matconv[i].attribs.orco.array[index]);
- index = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset + 2 * max_element_size],
- (float *)matconv[i].attribs.orco.array[index]);
- index = getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset + 3 * max_element_size],
- (float *)matconv[i].attribs.orco.array[index]);
-
- offset += sizeof(float) * 3;
- }
- for (b = 0; b < matconv[i].attribs.tottface; b++) {
- if (matconv[i].attribs.tface[b].array) {
- const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array + tot_loops;
-
- copy_v2_v2((float *)&varray[offset], mloopuv[0].uv);
- copy_v2_v2((float *)&varray[offset + max_element_size], mloopuv[3].uv);
- copy_v2_v2((float *)&varray[offset + 2 * max_element_size], mloopuv[2].uv);
- copy_v2_v2((float *)&varray[offset + 3 * max_element_size], mloopuv[1].uv);
-
- offset += sizeof(float) * 2;
- }
- }
- for (b = 0; b < matconv[i].attribs.totmcol; b++) {
- if (matconv[i].attribs.mcol[b].array) {
- const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array + tot_loops;
-
- copy_v4_v4_uchar(&varray[offset], &mloopcol[0].r);
- copy_v4_v4_uchar(&varray[offset + max_element_size], &mloopcol[3].r);
- copy_v4_v4_uchar(&varray[offset + 2 * max_element_size], &mloopcol[2].r);
- copy_v4_v4_uchar(&varray[offset + 3 * max_element_size], &mloopcol[1].r);
-
- offset += sizeof(unsigned char) * 4;
- }
- }
- for (b = 0; b < matconv[i].attribs.tottang; b++) {
- if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
- const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array + tot_loops;
-
- copy_v4_v4((float *)&varray[offset], looptang[0]);
- copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
- copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
- copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
-
- offset += sizeof(float) * 4;
- }
- }
-
- tot_loops += 4;
- }
- }
- }
- }
- else {
- tot_loops += 4 * numVerts * gridFaces * gridFaces;
- }
- }
- GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY);
- }
-
- for (a = 0; a < tot_active_mat; a++) {
- int new_matnr;
- int do_draw;
-
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size);
- }
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES,
- dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_unbind();
- }
- }
- }
-
- GPU_buffers_unbind();
- if (buffer)
- GPU_buffer_free(buffer);
-
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- }
-}
-
-static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- GPUVertexAttribs gattribs;
- DMVertexAttribs attribs = {{{NULL}}};
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int a, i, numVerts, matnr, totface;
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int current_patch = 0;
- int mat_nr = -1;
- bool draw_smooth = false;
- int start_draw_patch = -1, num_draw_patches = 0;
- GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
- return;
- }
- for (i = 0; i < num_base_faces; ++i) {
- const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
- const int num_patches = (num_face_verts == 4) ? face_patches
- : num_face_verts * grid_patches;
- int new_matnr;
- bool new_draw_smooth;
-
- if (faceFlags) {
- new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- new_matnr = (faceFlags[i].mat_nr + 1);
- }
- else {
- new_draw_smooth = true;
- new_matnr = 1;
- }
- if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
- if (num_draw_patches != 0) {
- setMaterial(userData, mat_nr, &gattribs);
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- start_draw_patch = current_patch;
- num_draw_patches = num_patches;
- mat_nr = new_matnr;
- draw_smooth = new_draw_smooth;
- }
- else {
- num_draw_patches += num_patches;
- }
- current_patch += num_patches;
- }
- if (num_draw_patches != 0) {
- setMaterial(userData, mat_nr, &gattribs);
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
- matnr = -1;
-
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
- DM_draw_attrib_vertex_uniforms(&attribs); \
-} (void)0
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (a = 0, i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- const float (*ln)[3] = NULL;
- int S, x, y, drawSmooth;
- int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- int origIndex = ccgDM_getFaceMapIndex(ss, f);
- int new_matnr;
-
- numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- /* get flags */
- if (faceFlags) {
- drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
- new_matnr = faceFlags[index].mat_nr + 1;
- }
- else {
- drawSmooth = 1;
- new_matnr = 1;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
-
- /* material */
- if (new_matnr != matnr) {
- setMaterial(userData, matnr = new_matnr, &gattribs);
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- }
-
- /* face hiding */
- if ((setFace && (origIndex != ORIGINDEX_NONE) && !setFace(userData, origIndex))) {
- a += gridFaces * gridFaces * numVerts;
- continue;
- }
-
- /* draw face*/
- glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- CCGElem *vda, *vdb;
-
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(ln[1]);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glNormal3fv(ln[2]);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glNormal3fv(ln[3]);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glNormal3fv(ln[0]);
- glVertex3fv(aco);
-
- ln += 4;
- a++;
- }
- }
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
- vda = CCG_grid_elem(&key, faceGridData, x, y);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 0);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- if (x != gridFaces - 1)
- a++;
- }
-
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 3);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 2);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- glEnd();
-
- a++;
- }
- }
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_glNormalFast(aco, bco, cco, dco);
-
- PASSATTRIB(0, 1, 1);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glVertex3fv(aco);
-
- a++;
- }
- }
- glEnd();
- }
- }
- }
-
- glShadeModel(GL_SMOOTH);
-#undef PASSATTRIB
-}
-
-static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
- DMSetDrawOptionsTex drawParams,
- DMSetDrawOptionsMappedTex drawParamsMapped,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int colType;
- const MLoopCol *mloopcol = NULL;
- MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- DMDrawOption draw_option;
- int i, totpoly;
- bool flush;
- const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
- const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
- unsigned int next_actualFace;
- unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
- int mat_index;
- int tot_element, start_element, tot_drawn;
-
- if (use_colors) {
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- }
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) {
- return;
- }
- if (drawParams == NULL) {
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
- return;
- }
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int current_patch = 0;
- int mat_nr = -1;
- int start_draw_patch = 0, num_draw_patches = 0;
- bool draw_smooth = false;
- for (i = 0; i < num_base_faces; ++i) {
- const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
- const int num_patches = (num_face_verts == 4) ? face_patches
- : num_face_verts * grid_patches;
- if (faceFlags) {
- mat_nr = faceFlags[i].mat_nr;
- draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- }
- else {
- mat_nr = 0;
- draw_smooth = false;
- }
-
- if (drawParams != NULL) {
- MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL;
- draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
- }
- else {
- draw_option = (drawParamsMapped)
- ? drawParamsMapped(userData, i, mat_nr)
- : DM_DRAW_OPTION_NORMAL;
- }
-
- flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1);
-
- const int next_face = min_ii(i + 1, num_base_faces - 1);
- if (!flush && compareDrawOptions) {
- flush |= compareDrawOptions(userData, i, next_face) == 0;
- }
- if (!flush && faceFlags) {
- bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH);
- flush |= (new_draw_smooth != draw_smooth);
- }
-
- current_patch += num_patches;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- num_draw_patches += num_patches;
- }
- if (num_draw_patches != 0) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- start_draw_patch = current_patch;
- num_draw_patches = 0;
- }
- else {
- num_draw_patches += num_patches;
- }
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- if (flag & DM_DRAW_USE_TEXPAINT_UV)
- GPU_texpaint_uv_setup(dm);
- else
- GPU_uv_setup(dm);
- if (mloopcol) {
- GPU_color_setup(dm, colType);
- }
-
- next_actualFace = 0;
-
- /* lastFlag = 0; */ /* UNUSED */
- for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
- GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
- next_actualFace = bufmat->polys[0];
- totpoly = bufmat->totpolys;
-
- tot_element = 0;
- tot_drawn = 0;
- start_element = 0;
-
- for (i = 0; i < totpoly; i++) {
- int polyindex = bufmat->polys[i];
- CCGFace *f = ccgdm->faceMap[polyindex].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = ccgDM_getFaceMapIndex(ss, f);
- int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- int mat_nr;
- int facequads = numVerts * gridFaces * gridFaces;
- int actualFace = ccgdm->faceMap[polyindex].startFace;
-
- if (i != totpoly - 1) {
- polyindex = bufmat->polys[i + 1];
- next_actualFace = ccgdm->faceMap[polyindex].startFace;
- }
-
- if (faceFlags) {
- mat_nr = faceFlags[orig_index].mat_nr;
- }
- else {
- mat_nr = 0;
- }
-
- if (drawParams) {
- MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[actualFace] : NULL;
- draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
- }
- else if (index != ORIGINDEX_NONE)
- draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL;
- else
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- /* flush buffer if current triangle isn't drawable or it's last triangle */
- flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1);
-
- if (!flush && compareDrawOptions) {
- /* also compare draw options and flush buffer if they're different
- * need for face selection highlight in edit mode */
- flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
- }
-
- tot_element += facequads * 6;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP)
- tot_drawn += facequads * 6;
-
- if (tot_drawn) {
- if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL)
- GPU_color_switch(1);
- else
- GPU_color_switch(0);
-
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
- tot_drawn = 0;
- }
-
- start_element = tot_element;
- }
- else {
- tot_drawn += facequads * 6;
- }
- }
- }
-
-
- GPU_buffers_unbind();
-}
-
-static void ccgDM_drawFacesTex(DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
-}
-
-static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
-}
-
-/* same as cdDM_drawUVEdges */
-static void ccgDM_drawUVEdges(DerivedMesh *dm)
-{
- MPoly *mpoly = dm->getPolyArray(dm);
- int totpoly = dm->getNumPolys(dm);
- int prevstart = 0;
- bool prevdraw = true;
- int curpos = 0;
- int i;
-
- GPU_uvedge_setup(dm);
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool draw = (mpoly->flag & ME_HIDE) == 0;
-
- if (prevdraw != draw) {
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- prevstart = curpos;
- }
-
- curpos += 2 * mpoly->totloop;
- prevdraw = draw;
- }
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- GPU_buffers_unbind();
-}
-
-static void ccgDM_drawMappedFaces(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- MLoopCol *mloopcol = NULL;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int i, gridSize = ccgSubSurf_getGridSize(ss);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int useColors = flag & DM_DRAW_USE_COLORS;
- int gridFaces = gridSize - 1, totface;
- int prev_mat_nr = -1;
-
- if (ccgdm->pbvh) {
- if (G.debug_value == 14)
- BKE_pbvh_draw_BB(ccgdm->pbvh);
- }
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- int new_matnr;
- bool draw_smooth, do_draw = true;
- if (setDrawOptions == NULL) {
- /* TODO(sergey): This is for cases when vertex colors or weights
- * are visualising. Currently we don't have CD layers for this data
- * and here we only make it so there's no garbage displayed.
- *
- * In the future we'll either need to have CD for this data or pass
- * this data as face-varying or vertex-varying data in OSD mesh.
- */
- glColor3f(0.8f, 0.8f, 0.8f);
- }
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
- return;
- }
- if (faceFlags) {
- draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
- new_matnr = (faceFlags[0].mat_nr + 1);
- }
- else {
- draw_smooth = true;
- new_matnr = 1;
- }
- if (setMaterial) {
- setMaterial(new_matnr, NULL);
- }
- if (setDrawOptions) {
- if (setDrawOptions(userData, 0) == DM_DRAW_OPTION_SKIP) {
- do_draw = false;
- }
- }
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
- glShadeModel(GL_SMOOTH);
- }
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
-
- /* currently unused -- each original face is handled separately */
- (void)compareDrawOptions;
-
- if (useColors) {
- mloopcol = dm->getLoopDataArray(dm, CD_PREVIEW_MLOOPCOL);
- if (!mloopcol)
- mloopcol = dm->getLoopDataArray(dm, CD_MLOOPCOL);
- }
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
- int origIndex;
- unsigned char *cp = NULL;
- const float (*ln)[3] = NULL;
-
- origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-
- if (flag & DM_DRAW_ALWAYS_SMOOTH) drawSmooth = 1;
- else if (faceFlags) drawSmooth = (lnors || (faceFlags[origIndex].flag & ME_SMOOTH));
- else drawSmooth = 1;
-
- if (mloopcol) {
- cp = (unsigned char *)mloopcol;
- mloopcol += gridFaces * gridFaces * numVerts * 4;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
-
- {
- DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (setMaterial) {
- int mat_nr = faceFlags ? faceFlags[origIndex].mat_nr + 1 : 1;
-
- if (mat_nr != prev_mat_nr) {
- setMaterial(mat_nr, NULL); /* XXX, no faceFlags no material */
- prev_mat_nr = mat_nr;
- }
- }
-
- if (setDrawOptions && (index != ORIGINDEX_NONE))
- draw_option = setDrawOptions(userData, index);
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- if (draw_option == DM_DRAW_OPTION_STIPPLE) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
-
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- if (cp) glColor4ubv(&cp[4]);
- glNormal3fv(ln[1]);
- glVertex3fv(d);
- if (cp) glColor4ubv(&cp[8]);
- glNormal3fv(ln[2]);
- glVertex3fv(c);
- if (cp) glColor4ubv(&cp[12]);
- glNormal3fv(ln[3]);
- glVertex3fv(b);
- if (cp) glColor4ubv(&cp[0]);
- glNormal3fv(ln[0]);
- glVertex3fv(a);
-
- if (cp) cp += 16;
- ln += 4;
- }
- }
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- CCGElem *a, *b;
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
- a = CCG_grid_elem(&key, faceGridData, x, y + 0);
- b = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- if (cp) glColor4ubv(&cp[0]);
- glNormal3fv(CCG_elem_no(&key, a));
- glVertex3fv(CCG_elem_co(&key, a));
- if (cp) glColor4ubv(&cp[4]);
- glNormal3fv(CCG_elem_no(&key, b));
- glVertex3fv(CCG_elem_co(&key, b));
-
- if (x != gridFaces - 1) {
- if (cp) cp += 16;
- }
- }
-
- a = CCG_grid_elem(&key, faceGridData, x, y + 0);
- b = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- if (cp) glColor4ubv(&cp[12]);
- glNormal3fv(CCG_elem_no(&key, a));
- glVertex3fv(CCG_elem_co(&key, a));
- if (cp) glColor4ubv(&cp[8]);
- glNormal3fv(CCG_elem_no(&key, b));
- glVertex3fv(CCG_elem_co(&key, b));
-
- if (cp) cp += 16;
-
- glEnd();
- }
- }
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_glNormalFast(a, b, c, d);
-
- if (cp) glColor4ubv(&cp[4]);
- glVertex3fv(d);
- if (cp) glColor4ubv(&cp[8]);
- glVertex3fv(c);
- if (cp) glColor4ubv(&cp[12]);
- glVertex3fv(b);
- if (cp) glColor4ubv(&cp[0]);
- glVertex3fv(a);
-
- if (cp) cp += 16;
- }
- }
- glEnd();
- }
- }
- if (draw_option == DM_DRAW_OPTION_STIPPLE)
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- }
- }
-}
-
-static void ccgDM_drawMappedEdges(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGEdgeIterator ei;
- CCGKey key;
- int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- /* TODO(sergey): Only draw edges from base mesh. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
- if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) {
- ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
- }
- }
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
- int index = ccgDM_getEdgeMapIndex(ss, e);
-
- glBegin(GL_LINE_STRIP);
- if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) {
- if (useAging && !(G.f & G_BACKBUFSEL)) {
- int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
- glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
- }
-
- for (i = 0; i < edgeSize - 1; i++) {
- glVertex3fv(CCG_elem_offset_co(&key, edgeData, i));
- glVertex3fv(CCG_elem_offset_co(&key, edgeData, i + 1));
- }
- }
- glEnd();
- }
-}
-
-static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetDrawInterpOptions setDrawInterpOptions,
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- CCGEdgeIterator ei;
- int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- BLI_assert(!"Not currently supported");
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
- int index = ccgDM_getEdgeMapIndex(ss, e);
-
- glBegin(GL_LINE_STRIP);
- if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) {
- for (i = 0; i < edgeSize; i++) {
- setDrawInterpOptions(userData, index, (float) i / (edgeSize - 1));
-
- if (useAging && !(G.f & G_BACKBUFSEL)) {
- int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
- glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
- }
-
- glVertex3fv(CCG_elem_offset_co(&key, edgeData, i));
- }
- }
- glEnd();
- }
-}
-
static void ccgDM_foreachMappedFaceCenter(
DerivedMesh *dm,
void (*func)(void *userData, int index, const float co[3], const float no[3]),
@@ -4045,7 +1827,7 @@ static void ccgDM_release(DerivedMesh *dm)
if (ccgdm->multires.mmd) {
if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED)
- multires_modifier_update_mdisps(dm);
+ multires_modifier_update_mdisps(dm, NULL);
if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED)
multires_modifier_update_hidden(dm);
}
@@ -4546,7 +2328,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden);
}
else if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
MLoopTri *looptri;
@@ -4570,7 +2352,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
totvert = deformdm->getNumVerts(deformdm);
vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos");
deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos, totvert);
MEM_freeN(vertCos);
}
}
@@ -4687,23 +2469,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
ccgdm->dm.foreachMappedLoop = ccgDM_foreachMappedLoop;
ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
- ccgdm->dm.drawVerts = ccgDM_drawVerts;
- ccgdm->dm.drawEdges = ccgDM_drawEdges;
- ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
- ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
- ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
- ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL;
- ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
- ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
- ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL;
- ccgdm->dm.drawMappedFacesMat = ccgDM_drawMappedFacesMat;
- ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
-
- ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
- ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
- ccgdm->dm.gpuObjectNew = ccgDM_GPUObjectNew;
- ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data;
-
ccgdm->dm.release = ccgDM_release;
}
@@ -5155,8 +2920,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
*/
return
(flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
- (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE) &&
- (openSubdiv_supportGPUDisplay());
+ (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE);
#else
(void)flags;
return false;
@@ -5166,6 +2930,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
+ struct Scene *scene,
float (*vertCos)[3],
SubsurfFlags flags)
{
@@ -5179,7 +2944,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, false) : smd->levels;
+ int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels;
/* TODO(sergey): Same as emCache below. */
if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) {
@@ -5200,7 +2965,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, true) : smd->renderLevels;
+ int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->renderLevels, true) : smd->renderLevels;
if (levels == 0)
return dm;
@@ -5216,7 +2981,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, false) : smd->levels;
+ int levels = (scene != NULL) ? get_render_subsurf_level(&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 76df163ee3a..f876592c0a8 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -47,8 +47,6 @@
#include "BLI_fileops.h"
#include "DNA_constraint_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_actuator_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -58,7 +56,6 @@
#include "DNA_node_types.h"
#include "DNA_material_types.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index a0399c74be1..ad60e81fe19 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -44,9 +44,7 @@
#include "DNA_key_types.h"
#include "DNA_object_types.h"
-#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
-#include "DNA_world_types.h"
#include "DNA_brush_types.h"
#include "DNA_node_types.h"
#include "DNA_color_types.h"
@@ -213,22 +211,6 @@ void BKE_texture_free(Tex *tex)
}
MEM_SAFE_FREE(tex->coba);
- if (tex->env) {
- BKE_texture_envmap_free(tex->env);
- tex->env = NULL;
- }
- if (tex->pd) {
- BKE_texture_pointdensity_free(tex->pd);
- tex->pd = NULL;
- }
- if (tex->vd) {
- BKE_texture_voxeldata_free(tex->vd);
- tex->vd = NULL;
- }
- if (tex->ot) {
- BKE_texture_ocean_free(tex->ot);
- tex->ot = NULL;
- }
BKE_icon_id_delete((ID *)tex);
BKE_previewimg_free(&tex->preview);
@@ -285,30 +267,6 @@ void BKE_texture_default(Tex *tex)
tex->vn_distm = 0;
tex->vn_coltype = 0;
- if (tex->env) {
- tex->env->stype = ENV_ANIM;
- tex->env->clipsta = 0.1;
- tex->env->clipend = 100;
- tex->env->cuberes = 512;
- tex->env->depth = 0;
- }
-
- if (tex->pd) {
- tex->pd->radius = 0.3f;
- tex->pd->falloff_type = TEX_PD_FALLOFF_STD;
- }
-
- if (tex->vd) {
- tex->vd->resol[0] = tex->vd->resol[1] = tex->vd->resol[2] = 0;
- tex->vd->interp_type = TEX_VD_LINEAR;
- tex->vd->file_format = TEX_VD_SMOKE;
- }
-
- if (tex->ot) {
- tex->ot->output = TEX_OCN_DISPLACEMENT;
- tex->ot->object = NULL;
- }
-
tex->iuser.fie_ima = 2;
tex->iuser.ok = 1;
tex->iuser.frames = 100;
@@ -319,26 +277,6 @@ void BKE_texture_default(Tex *tex)
void BKE_texture_type_set(Tex *tex, int type)
{
- switch (type) {
-
- case TEX_VOXELDATA:
- if (tex->vd == NULL)
- tex->vd = BKE_texture_voxeldata_add();
- break;
- case TEX_POINTDENSITY:
- if (tex->pd == NULL)
- tex->pd = BKE_texture_pointdensity_add();
- break;
- case TEX_ENVMAP:
- if (tex->env == NULL)
- tex->env = BKE_texture_envmap_add();
- break;
- case TEX_OCEAN:
- if (tex->ot == NULL)
- tex->ot = BKE_texture_ocean_add();
- break;
- }
-
tex->type = type;
}
@@ -476,10 +414,6 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
MEM_freeN(mtex_ar[slot]);
mtex_ar[slot] = NULL;
}
- else if (GS(id->name) == ID_MA) {
- /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
- ((Material *)id)->septex &= ~(1 << slot);
- }
mtex_ar[slot] = BKE_texture_mtex_add();
@@ -498,9 +432,6 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
*/
void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag)
{
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
-
if (!BKE_texture_is_image_user(tex_src)) {
tex_dst->ima = NULL;
}
@@ -508,19 +439,6 @@ void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const
if (tex_dst->coba) {
tex_dst->coba = MEM_dupallocN(tex_dst->coba);
}
- if (tex_dst->env) {
- tex_dst->env = BKE_texture_envmap_copy(tex_dst->env, flag_subdata);
- }
- if (tex_dst->pd) {
- tex_dst->pd = BKE_texture_pointdensity_copy(tex_dst->pd, flag_subdata);
- }
- if (tex_dst->vd) {
- tex_dst->vd = MEM_dupallocN(tex_dst->vd);
- }
- if (tex_dst->ot) {
- tex_dst->ot = BKE_texture_ocean_copy(tex_dst->ot, flag_subdata);
- }
-
if (tex_src->nodetree) {
if (tex_src->nodetree->execdata) {
ntreeTexEndExecTree(tex_src->nodetree->execdata);
@@ -562,19 +480,6 @@ Tex *BKE_texture_localize(Tex *tex)
/* image texture: BKE_texture_free also doesn't decrease */
if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
- if (texn->env) {
- texn->env = BKE_texture_envmap_copy(texn->env, LIB_ID_CREATE_NO_USER_REFCOUNT);
- id_us_min(&texn->env->ima->id);
- }
- if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd, LIB_ID_CREATE_NO_USER_REFCOUNT);
- if (texn->vd) {
- texn->vd = MEM_dupallocN(texn->vd);
- if (texn->vd->dataset)
- texn->vd->dataset = MEM_dupallocN(texn->vd->dataset);
- }
- if (texn->ot) {
- texn->ot = BKE_texture_ocean_copy(tex->ot, LIB_ID_CREATE_NO_USER_REFCOUNT);
- }
texn->preview = NULL;
@@ -593,64 +498,6 @@ void BKE_texture_make_local(Main *bmain, Tex *tex, const bool lib_local)
BKE_id_make_local_generic(bmain, &tex->id, true, lib_local);
}
-Tex *give_current_object_texture(Object *ob)
-{
- Material *ma, *node_ma;
- Tex *tex = NULL;
-
- if (ob == NULL) return NULL;
- if (ob->totcol == 0 && !(ob->type == OB_LAMP)) return NULL;
-
- if (ob->type == OB_LAMP) {
- tex = give_current_lamp_texture(ob->data);
- }
- else {
- ma = give_current_material(ob, ob->actcol);
-
- if ((node_ma = give_node_material(ma)))
- ma = node_ma;
-
- tex = give_current_material_texture(ma);
- }
-
- return tex;
-}
-
-Tex *give_current_lamp_texture(Lamp *la)
-{
- MTex *mtex = NULL;
- Tex *tex = NULL;
-
- if (la) {
- mtex = la->mtex[(int)(la->texact)];
- if (mtex) tex = mtex->tex;
- }
-
- return tex;
-}
-
-void set_current_lamp_texture(Lamp *la, Tex *newtex)
-{
- int act = la->texact;
-
- if (la->mtex[act] && la->mtex[act]->tex)
- id_us_min(&la->mtex[act]->tex->id);
-
- if (newtex) {
- if (!la->mtex[act]) {
- la->mtex[act] = BKE_texture_mtex_add();
- la->mtex[act]->texco = TEXCO_GLOB;
- }
-
- la->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (la->mtex[act]) {
- MEM_freeN(la->mtex[act]);
- la->mtex[act] = NULL;
- }
-}
-
Tex *give_current_linestyle_texture(FreestyleLineStyle *linestyle)
{
MTex *mtex = NULL;
@@ -686,55 +533,9 @@ void set_current_linestyle_texture(FreestyleLineStyle *linestyle, Tex *newtex)
}
}
-bNode *give_current_material_texture_node(Material *ma)
-{
- if (ma && ma->use_nodes && ma->nodetree)
- return nodeGetActiveID(ma->nodetree, ID_TE);
-
- return NULL;
-}
-
-Tex *give_current_material_texture(Material *ma)
-{
- MTex *mtex = NULL;
- Tex *tex = NULL;
- bNode *node;
-
- if (ma && ma->use_nodes && ma->nodetree) {
- /* first check texture, then material, this works together
- * with a hack that clears the active ID flag for textures on
- * making a material node active */
- node = nodeGetActiveID(ma->nodetree, ID_TE);
-
- if (node) {
- tex = (Tex *)node->id;
- ma = NULL;
- }
- }
-
- if (ma) {
- mtex = ma->mtex[(int)(ma->texact)];
- if (mtex) tex = mtex->tex;
- }
-
- return tex;
-}
-
bool give_active_mtex(ID *id, MTex ***mtex_ar, short *act)
{
switch (GS(id->name)) {
- case ID_MA:
- *mtex_ar = ((Material *)id)->mtex;
- if (act) *act = (((Material *)id)->texact);
- break;
- case ID_WO:
- *mtex_ar = ((World *)id)->mtex;
- if (act) *act = (((World *)id)->texact);
- break;
- case ID_LA:
- *mtex_ar = ((Lamp *)id)->mtex;
- if (act) *act = (((Lamp *)id)->texact);
- break;
case ID_LS:
*mtex_ar = ((FreestyleLineStyle *)id)->mtex;
if (act) *act = (((FreestyleLineStyle *)id)->texact);
@@ -758,15 +559,6 @@ void set_active_mtex(ID *id, short act)
else if (act >= MAX_MTEX) act = MAX_MTEX - 1;
switch (GS(id->name)) {
- case ID_MA:
- ((Material *)id)->texact = act;
- break;
- case ID_WO:
- ((World *)id)->texact = act;
- break;
- case ID_LA:
- ((Lamp *)id)->texact = act;
- break;
case ID_LS:
((FreestyleLineStyle *)id)->texact = act;
break;
@@ -778,100 +570,6 @@ void set_active_mtex(ID *id, short act)
}
}
-void set_current_material_texture(Material *ma, Tex *newtex)
-{
- Tex *tex = NULL;
- bNode *node;
-
- if ((ma->use_nodes && ma->nodetree) &&
- (node = nodeGetActiveID(ma->nodetree, ID_TE)))
- {
- tex = (Tex *)node->id;
- id_us_min(&tex->id);
- if (newtex) {
- node->id = &newtex->id;
- id_us_plus(&newtex->id);
- }
- else {
- node->id = NULL;
- }
- }
- else {
- int act = (int)ma->texact;
-
- tex = (ma->mtex[act]) ? ma->mtex[act]->tex : NULL;
- id_us_min(&tex->id);
-
- if (newtex) {
- if (!ma->mtex[act]) {
- ma->mtex[act] = BKE_texture_mtex_add();
- /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
- ma->septex &= ~(1 << act);
- /* For volumes the default UV texture coordinates are not available. */
- if (ma->material_type == MA_TYPE_VOLUME) {
- ma->mtex[act]->texco = TEXCO_ORCO;
- }
- }
-
- ma->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (ma->mtex[act]) {
- MEM_freeN(ma->mtex[act]);
- ma->mtex[act] = NULL;
- }
- }
-}
-
-bool has_current_material_texture(Material *ma)
-{
- bNode *node;
-
- if (ma && ma->use_nodes && ma->nodetree) {
- node = nodeGetActiveID(ma->nodetree, ID_TE);
-
- if (node)
- return true;
- }
-
- return (ma != NULL);
-}
-
-Tex *give_current_world_texture(World *world)
-{
- MTex *mtex = NULL;
- Tex *tex = NULL;
-
- if (!world) return NULL;
-
- mtex = world->mtex[(int)(world->texact)];
- if (mtex) tex = mtex->tex;
-
- return tex;
-}
-
-void set_current_world_texture(World *wo, Tex *newtex)
-{
- int act = wo->texact;
-
- if (wo->mtex[act] && wo->mtex[act]->tex)
- id_us_min(&wo->mtex[act]->tex->id);
-
- if (newtex) {
- if (!wo->mtex[act]) {
- wo->mtex[act] = BKE_texture_mtex_add();
- wo->mtex[act]->texco = TEXCO_VIEW;
- }
-
- wo->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (wo->mtex[act]) {
- MEM_freeN(wo->mtex[act]);
- wo->mtex[act] = NULL;
- }
-}
-
Tex *give_current_brush_texture(Brush *br)
{
return br->mtex.tex;
@@ -926,65 +624,6 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex)
/* ------------------------------------------------------------------------- */
-EnvMap *BKE_texture_envmap_add(void)
-{
- EnvMap *env;
-
- env = MEM_callocN(sizeof(EnvMap), "envmap");
- env->type = ENV_CUBE;
- env->stype = ENV_ANIM;
- env->clipsta = 0.1;
- env->clipend = 100.0;
- env->cuberes = 512;
- env->viewscale = 0.5;
-
- return env;
-}
-
-/* ------------------------------------------------------------------------- */
-
-EnvMap *BKE_texture_envmap_copy(const EnvMap *env, const int flag)
-{
- EnvMap *envn;
- int a;
-
- envn = MEM_dupallocN(env);
- envn->ok = 0;
- for (a = 0; a < 6; a++) {
- envn->cube[a] = NULL;
- }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)envn->ima);
- }
-
- return envn;
-}
-
-/* ------------------------------------------------------------------------- */
-
-void BKE_texture_envmap_free_data(EnvMap *env)
-{
- unsigned int part;
-
- for (part = 0; part < 6; part++) {
- if (env->cube[part])
- IMB_freeImBuf(env->cube[part]);
- env->cube[part] = NULL;
- }
- env->ok = 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-void BKE_texture_envmap_free(EnvMap *env)
-{
-
- BKE_texture_envmap_free_data(env);
- MEM_freeN(env);
-
-}
-
-/* ------------------------------------------------------------------------- */
void BKE_texture_pointdensity_init_data(PointDensity *pd)
{
@@ -1057,77 +696,8 @@ void BKE_texture_pointdensity_free(PointDensity *pd)
BKE_texture_pointdensity_free_data(pd);
MEM_freeN(pd);
}
-
-/* ------------------------------------------------------------------------- */
-
-void BKE_texture_voxeldata_free_data(VoxelData *vd)
-{
- if (vd->dataset) {
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- }
-
-}
-
-void BKE_texture_voxeldata_free(VoxelData *vd)
-{
- BKE_texture_voxeldata_free_data(vd);
- MEM_freeN(vd);
-}
-
-VoxelData *BKE_texture_voxeldata_add(void)
-{
- VoxelData *vd;
-
- vd = MEM_callocN(sizeof(VoxelData), "voxeldata");
- vd->dataset = NULL;
- vd->resol[0] = vd->resol[1] = vd->resol[2] = 1;
- vd->interp_type = TEX_VD_LINEAR;
- vd->file_format = TEX_VD_SMOKE;
- vd->int_multiplier = 1.0;
- vd->extend = TEX_CLIP;
- vd->object = NULL;
- vd->cachedframe = -1;
- vd->ok = 0;
-
- return vd;
-}
-
-VoxelData *BKE_texture_voxeldata_copy(VoxelData *vd)
-{
- VoxelData *vdn;
-
- vdn = MEM_dupallocN(vd);
- vdn->dataset = NULL;
-
- return vdn;
-}
-
/* ------------------------------------------------------------------------- */
-OceanTex *BKE_texture_ocean_add(void)
-{
- OceanTex *ot;
-
- ot = MEM_callocN(sizeof(struct OceanTex), "ocean texture");
- ot->output = TEX_OCN_DISPLACEMENT;
- ot->object = NULL;
-
- return ot;
-}
-
-OceanTex *BKE_texture_ocean_copy(const OceanTex *ot, const int UNUSED(flag))
-{
- OceanTex *otn = MEM_dupallocN(ot);
-
- return otn;
-}
-
-void BKE_texture_ocean_free(struct OceanTex *ot)
-{
- MEM_freeN(ot);
-}
-
/**
* \returns true if this texture can use its #Texture.ima (even if its NULL)
*/
@@ -1138,15 +708,6 @@ bool BKE_texture_is_image_user(const struct Tex *tex)
{
return true;
}
- case TEX_ENVMAP:
- {
- if (tex->env) {
- if (tex->env->stype == ENV_LOAD) {
- return true;
- }
- }
- break;
- }
}
return false;
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index f9d34534a45..fe9cf1e9609 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -61,6 +61,7 @@
#include "BKE_movieclip.h"
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BKE_layer.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -394,17 +395,17 @@ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTrackin
/* Get transformation matrix for a given object which is used
* for parenting motion tracker reconstruction to 3D world.
*/
-void BKE_tracking_get_camera_object_matrix(Scene *scene, Object *ob, float mat[4][4])
+void BKE_tracking_get_camera_object_matrix(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float mat[4][4])
{
if (!ob) {
if (scene->camera)
ob = scene->camera;
else
- ob = BKE_scene_camera_find(scene);
+ ob = BKE_view_layer_camera_find(BKE_view_layer_context_active_PLACEHOLDER(scene));
}
if (ob)
- BKE_object_where_is_calc_mat4(scene, ob, mat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, ob, mat);
else
unit_m4(mat);
}
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index ba7d432fab3..173b459f442 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -39,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library_override.h"
#include "BKE_main.h"
#include "BKE_undo_system.h"
@@ -412,12 +413,19 @@ UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char
return BKE_undosys_step_push_init_with_type(ustack, C, name, ut);
}
+/**
+ * \param C: Can be NULL from some callers if their encoding function doesn't need it
+ */
bool BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
{
UNDO_NESTED_ASSERT(false);
undosys_stack_validate(ustack, false);
bool is_not_empty = ustack->step_active != NULL;
+ /* Might not be final place for this to be called - probably only want to call it from some
+ * undo handlers, not all of them? */
+ BKE_main_override_static_operations_create(G.main, false);
+
/* Remove all undos after (also when 'ustack->step_active == NULL'). */
while (ustack->steps.last != ustack->step_active) {
UndoStep *us_iter = ustack->steps.last;
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
new file mode 100644
index 00000000000..3a9a392da4a
--- /dev/null
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -0,0 +1,536 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/workspace.c
+ * \ingroup bke
+ */
+
+/* allow accessing private members of DNA_workspace_types.h */
+#define DNA_PRIVATE_WORKSPACE_ALLOW
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLI_listbase.h"
+
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_object.h"
+#include "BKE_workspace.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Internal utils */
+
+static void workspace_layout_name_set(
+ WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+{
+ BLI_strncpy(layout->name, new_name, sizeof(layout->name));
+ BLI_uniquename(&workspace->layouts, layout, "Layout", '.', offsetof(WorkSpaceLayout, name), sizeof(layout->name));
+}
+
+/**
+ * This should only be used directly when it is to be expected that there isn't
+ * a layout within \a workspace that wraps \a screen. Usually - especially outside
+ * of BKE_workspace - #BKE_workspace_layout_find should be used!
+ */
+static WorkSpaceLayout *workspace_layout_find_exec(
+ const WorkSpace *workspace, const bScreen *screen)
+{
+ return BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen));
+}
+
+static void workspace_relation_add(
+ ListBase *relation_list, void *parent, void *data)
+{
+ WorkSpaceDataRelation *relation = MEM_callocN(sizeof(*relation), __func__);
+ relation->parent = parent;
+ relation->value = data;
+ /* add to head, if we switch back to it soon we find it faster. */
+ BLI_addhead(relation_list, relation);
+}
+static void workspace_relation_remove(
+ ListBase *relation_list, WorkSpaceDataRelation *relation)
+{
+ BLI_remlink(relation_list, relation);
+ MEM_freeN(relation);
+}
+
+static void workspace_relation_ensure_updated(
+ ListBase *relation_list, void *parent, void *data)
+{
+ WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ relation->value = data;
+ /* reinsert at the head of the list, so that more commonly used relations are found faster. */
+ BLI_remlink(relation_list, relation);
+ BLI_addhead(relation_list, relation);
+ }
+ else {
+ /* no matching relation found, add new one */
+ workspace_relation_add(relation_list, parent, data);
+ }
+}
+
+static void *workspace_relation_get_data_matching_parent(
+ const ListBase *relation_list, const void *parent)
+{
+ WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ return relation->value;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/**
+ * Checks if \a screen is already used within any workspace. A screen should never be assigned to multiple
+ * WorkSpaceLayouts, but that should be ensured outside of the BKE_workspace module and without such checks.
+ * Hence, this should only be used as assert check before assigining a screen to a workspace.
+ */
+#ifndef NDEBUG
+static bool workspaces_is_screen_used
+#else
+static bool UNUSED_FUNCTION(workspaces_is_screen_used)
+#endif
+ (const Main *bmain, bScreen *screen)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if (workspace_layout_find_exec(workspace, screen)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* -------------------------------------------------------------------- */
+/* Create, delete, init */
+
+WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
+{
+ WorkSpace *new_workspace = BKE_libblock_alloc(bmain, ID_WS, name, 0);
+ return new_workspace;
+}
+
+/**
+ * The function that actually frees the workspace data (not workspace itself). It shouldn't be called
+ * directly, instead #BKE_workspace_remove should be, which calls this through #BKE_libblock_free then.
+ *
+ * Should something like a bke_internal.h be added, this should go there!
+ */
+void BKE_workspace_free(WorkSpace *workspace)
+{
+ BKE_workspace_relations_free(&workspace->hook_layout_relations);
+ BLI_freelistN(&workspace->scene_layer_relations);
+
+ BLI_freelistN(&workspace->owner_ids);
+ BLI_freelistN(&workspace->layouts);
+
+ for (bToolRef *tref = workspace->tools.first, *tref_next; tref; tref = tref_next) {
+ tref_next = tref->next;
+ if (tref->runtime) {
+ MEM_freeN(tref->runtime);
+ if (tref->properties) {
+ IDP_FreeProperty(tref->properties);
+ MEM_freeN(tref->properties);
+ }
+ }
+ }
+ BLI_freelistN(&workspace->tools);
+}
+
+/**
+ * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that
+ * calls #BKE_workspace_free (through #BKE_libblock_free) to free the workspace data, and frees
+ * other data-blocks owned by \a workspace and its layouts (currently that is screens only).
+ *
+ * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here.
+ */
+void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
+{
+ for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout; layout = layout_next) {
+ layout_next = layout->next;
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
+ BKE_libblock_free(bmain, workspace);
+}
+
+WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain)
+{
+ WorkSpaceInstanceHook *hook = MEM_callocN(sizeof(WorkSpaceInstanceHook), __func__);
+
+ /* set an active screen-layout for each possible window/workspace combination */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first);
+ }
+
+ return hook;
+}
+void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *hook)
+{
+ /* workspaces should never be freed before wm (during which we call this function) */
+ BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces));
+
+ /* Free relations for this hook */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
+ relation;
+ relation = relation_next)
+ {
+ relation_next = relation->next;
+ if (relation->parent == hook) {
+ workspace_relation_remove(&workspace->hook_layout_relations, relation);
+ }
+ }
+ }
+
+ MEM_freeN(hook);
+}
+
+/**
+ * Add a new layout to \a workspace for \a screen.
+ */
+WorkSpaceLayout *BKE_workspace_layout_add(
+ Main *bmain,
+ WorkSpace *workspace,
+ bScreen *screen,
+ const char *name)
+{
+ WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__);
+
+ BLI_assert(!workspaces_is_screen_used(bmain, screen));
+#ifndef DEBUG
+ UNUSED_VARS(bmain);
+#endif
+ layout->screen = screen;
+ workspace_layout_name_set(workspace, layout, name);
+ BLI_addtail(&workspace->layouts, layout);
+
+ return layout;
+}
+
+void BKE_workspace_layout_remove(
+ Main *bmain,
+ WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ BKE_libblock_free(bmain, BKE_workspace_layout_screen_get(layout));
+ BLI_freelinkN(&workspace->layouts, layout);
+}
+
+void BKE_workspace_relations_free(
+ ListBase *relation_list)
+{
+ for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation; relation = relation_next) {
+ relation_next = relation->next;
+ workspace_relation_remove(relation_list, relation);
+ }
+}
+
+void BKE_workspace_scene_relations_free_invalid(
+ WorkSpace *workspace)
+{
+ for (WorkSpaceSceneRelation *relation = workspace->scene_layer_relations.first, *relation_next; relation; relation = relation_next) {
+ relation_next = relation->next;
+
+ if (relation->scene == NULL) {
+ BLI_freelinkN(&workspace->scene_layer_relations, relation);
+ }
+ else if (!BLI_findstring(&relation->scene->view_layers, relation->view_layer, offsetof(ViewLayer, name))) {
+ BLI_freelinkN(&workspace->scene_layer_relations, relation);
+ }
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* General Utils */
+
+void BKE_workspace_view_layer_rename(
+ const Main *bmain,
+ const Scene *scene,
+ const char *old_name,
+ const char *new_name)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ for (WorkSpaceSceneRelation *relation = workspace->scene_layer_relations.first; relation; relation = relation->next) {
+ if (relation->scene == scene && STREQ(relation->view_layer, old_name)) {
+ STRNCPY(relation->view_layer, new_name);
+ }
+ }
+ }
+}
+
+void BKE_workspace_view_layer_remove(
+ const Main *bmain,
+ const ViewLayer *UNUSED(view_layer))
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_workspace_scene_relations_free_invalid(workspace);
+ }
+}
+
+WorkSpaceLayout *BKE_workspace_layout_find(
+ const WorkSpace *workspace, const bScreen *screen)
+{
+ WorkSpaceLayout *layout = workspace_layout_find_exec(workspace, screen);
+ if (layout) {
+ return layout;
+ }
+
+ printf("%s: Couldn't find layout in this workspace: '%s' screen: '%s'. "
+ "This should not happen!\n",
+ __func__, workspace->id.name + 2, screen->id.name + 2);
+
+ return NULL;
+}
+
+/**
+ * Find the layout for \a screen without knowing which workspace to look in.
+ * Can also be used to find the workspace that contains \a screen.
+ *
+ * \param r_workspace: Optionally return the workspace that contains the looked up layout (if found).
+ */
+WorkSpaceLayout *BKE_workspace_layout_find_global(
+ const Main *bmain, const bScreen *screen,
+ WorkSpace **r_workspace)
+{
+ WorkSpaceLayout *layout;
+
+ if (r_workspace) {
+ *r_workspace = NULL;
+ }
+
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if ((layout = workspace_layout_find_exec(workspace, screen))) {
+ if (r_workspace) {
+ *r_workspace = workspace;
+ }
+
+ return layout;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Circular workspace layout iterator.
+ *
+ * \param callback: Custom function which gets executed for each layout. Can return false to stop iterating.
+ * \param arg: Custom data passed to each \a callback call.
+ *
+ * \return the layout at which \a callback returned false.
+ */
+WorkSpaceLayout *BKE_workspace_layout_iter_circular(
+ const WorkSpace *workspace, WorkSpaceLayout *start,
+ bool (*callback)(const WorkSpaceLayout *layout, void *arg),
+ void *arg, const bool iter_backward)
+{
+ WorkSpaceLayout *iter_layout;
+
+ if (iter_backward) {
+ LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start);
+ }
+ else {
+ LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start)
+ }
+
+ return NULL;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Getters/Setters */
+
+WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook)
+{
+ return hook->active;
+}
+void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
+{
+ hook->active = workspace;
+ if (workspace) {
+ WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+ if (layout) {
+ hook->act_layout = layout;
+ }
+ }
+}
+
+WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
+{
+ return hook->act_layout;
+}
+void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout)
+{
+ hook->act_layout = layout;
+}
+
+bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook)
+{
+ return hook->act_layout->screen;
+}
+void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace, bScreen *screen)
+{
+ /* we need to find the WorkspaceLayout that wraps this screen */
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen);
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout);
+}
+
+Base *BKE_workspace_active_base_get(const WorkSpace *workspace, const Scene *scene)
+{
+ ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
+ return view_layer->basact;
+}
+
+ViewLayer *BKE_workspace_view_layer_exists(const WorkSpace *workspace, const Scene *scene)
+{
+ WorkSpaceSceneRelation *relation = BLI_findptr(&workspace->scene_layer_relations, scene, offsetof(WorkSpaceSceneRelation, scene));
+ return (relation) ? BLI_findstring(&scene->view_layers, relation->view_layer, offsetof(ViewLayer, name)) : NULL;
+}
+
+ViewLayer *BKE_workspace_view_layer_get(const WorkSpace *workspace, const Scene *scene)
+{
+ ViewLayer *layer = BKE_workspace_view_layer_exists(workspace, scene);
+
+ if (layer == NULL) {
+ BKE_workspace_view_layer_set((WorkSpace *)workspace, scene->view_layers.first, (Scene *)scene);
+ layer = scene->view_layers.first;
+ }
+
+ return layer;
+}
+
+void BKE_workspace_view_layer_set(WorkSpace *workspace, ViewLayer *layer, Scene *scene)
+{
+ WorkSpaceSceneRelation *relation = BLI_findptr(&workspace->scene_layer_relations, scene, offsetof(WorkSpaceSceneRelation, scene));
+ if (relation == NULL) {
+ relation = MEM_callocN(sizeof(*relation), __func__);
+ }
+ else {
+ BLI_remlink(&workspace->scene_layer_relations, relation);
+ }
+
+ /* (Re)insert at the head of the list, for faster lookups. */
+ relation->scene = scene;
+ STRNCPY(relation->view_layer, layer->name);
+ BLI_addhead(&workspace->scene_layer_relations, relation);
+}
+
+ListBase *BKE_workspace_layouts_get(WorkSpace *workspace)
+{
+ return &workspace->layouts;
+}
+
+const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout)
+{
+ return layout->name;
+}
+void BKE_workspace_layout_name_set(WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+{
+ workspace_layout_name_set(workspace, layout, new_name);
+}
+
+bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout)
+{
+ return layout->screen;
+}
+void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen)
+{
+ layout->screen = screen;
+}
+
+WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
+ const WorkSpaceInstanceHook *hook, const WorkSpace *workspace)
+{
+ return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+}
+void BKE_workspace_hook_layout_for_workspace_set(
+ WorkSpaceInstanceHook *hook, WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ hook->act_layout = layout;
+ workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
+}
+
+/* Update / evaluate */
+
+void BKE_workspace_update_tagged(Main *bmain,
+ WorkSpace *workspace,
+ Scene *scene)
+{
+ ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
+ struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene,
+ view_layer,
+ true);
+ /* TODO(sergey): For now all dependency graphs which are evaluated from
+ * workspace are considered active. This will work all fine with "locked"
+ * view layer and time across windows. This is to be granted separately,
+ * and for until then we have to accept ambiguities when object is shared
+ * across visible view layers and has overrides on it.
+ */
+ DEG_make_active(depsgraph);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+}
+
+
+bool BKE_workspace_owner_id_check(
+ const WorkSpace *workspace, const char *owner_id)
+{
+ if ((*owner_id == '\0') ||
+ ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0))
+ {
+ return true;
+ }
+ else {
+ /* we could use hash lookup, for now this list is highly under < ~16 items. */
+ return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL;
+ }
+}
+
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 545ca41c9c0..69096ad7a08 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_world_types.h"
@@ -43,6 +44,7 @@
#include "BLI_listbase.h"
#include "BKE_animsys.h"
+#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -51,19 +53,15 @@
#include "BKE_node.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_material.h"
/** Free (or release) any data used by this world (does not free the world itself). */
void BKE_world_free(World *wrld)
{
- int a;
-
BKE_animdata_free((ID *)wrld, false);
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(wrld->mtex[a]);
- }
-
/* is no lib link block, but world extension */
if (wrld->nodetree) {
ntreeFreeTree(wrld->nodetree);
@@ -84,23 +82,9 @@ void BKE_world_init(World *wrld)
wrld->horr = 0.05f;
wrld->horg = 0.05f;
wrld->horb = 0.05f;
- wrld->zenr = 0.01f;
- wrld->zeng = 0.01f;
- wrld->zenb = 0.01f;
- wrld->skytype = 0;
-
- wrld->exp = 0.0f;
- wrld->exposure = wrld->range = 1.0f;
wrld->aodist = 10.0f;
- wrld->aosamp = 5;
wrld->aoenergy = 1.0f;
- wrld->ao_env_energy = 1.0f;
- wrld->ao_indirect_energy = 1.0f;
- wrld->ao_indirect_bounces = 1;
- wrld->aobias = 0.05f;
- wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY;
- wrld->ao_approx_error = 0.25f;
wrld->preview = NULL;
wrld->miststa = 5.0f;
@@ -128,12 +112,6 @@ World *BKE_world_add(Main *bmain, const char *name)
*/
void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag)
{
- for (int a = 0; a < MAX_MTEX; a++) {
- if (wrld_src->mtex[a]) {
- wrld_dst->mtex[a] = MEM_dupallocN(wrld_src->mtex[a]);
- }
- }
-
if (wrld_src->nodetree) {
/* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
* (see BKE_libblock_copy_ex()). */
@@ -167,17 +145,9 @@ World *BKE_world_localize(World *wrld)
* ... Once f*** nodes are fully converted to that too :( */
World *wrldn;
- int a;
wrldn = BKE_libblock_copy_nolib(&wrld->id, false);
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a]) {
- wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), __func__);
- memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex));
- }
- }
-
if (wrld->nodetree)
wrldn->nodetree = ntreeLocalize(wrld->nodetree);
@@ -192,3 +162,11 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
}
+
+void BKE_world_eval(struct Depsgraph *depsgraph, World *world)
+{
+ DEG_debug_print_eval(depsgraph, __func__, world->id.name, world);
+ if (!BLI_listbase_is_empty(&world->gpumaterial)) {
+ world->update_flag = 1;
+ }
+}
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 7e989b6588f..994592ec307 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -84,10 +84,6 @@ static void context_free_avi(void *context_v);
# include "BKE_writeffmpeg.h"
#endif
-#ifdef WITH_FRAMESERVER
-# include "BKE_writeframeserver.h"
-#endif
-
bMovieHandle *BKE_movie_handle_get(const char imtype)
{
static bMovieHandle mh = {NULL};
@@ -121,16 +117,6 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.context_free = BKE_ffmpeg_context_free;
}
#endif
-#ifdef WITH_FRAMESERVER
- if (imtype == R_IMF_IMTYPE_FRAMESERVER) {
- mh.start_movie = BKE_frameserver_start;
- mh.append_movie = BKE_frameserver_append;
- mh.end_movie = BKE_frameserver_end;
- mh.get_next_frame = BKE_frameserver_loop;
- mh.context_create = BKE_frameserver_context_create;
- mh.context_free = BKE_frameserver_context_free;
- }
-#endif
/* in case all above are disabled */
(void)imtype;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 2bee16a30c8..394f4cc1122 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -45,8 +45,8 @@
#include "BLI_blenlib.h"
#ifdef WITH_AUDASPACE
-# include AUD_DEVICE_H
-# include AUD_SPECIAL_H
+# include <AUD_Device.h>
+# include <AUD_Special.h>
#endif
#include "BLI_utildefines.h"
@@ -326,10 +326,6 @@ static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, A
frame->pts = cfra;
- if (rd->mode & R_FIELDS) {
- frame->top_field_first = ((rd->mode & R_ODDFIELD) != 0);
- }
-
ret = avcodec_encode_video2(c, &packet, frame, &got_output);
if (ret >= 0 && got_output) {
@@ -686,13 +682,6 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
- /* Determine whether we are encoding interlaced material or not */
- if (rd->mode & R_FIELDS) {
- PRINT("Encoding interlaced video\n");
- c->flags |= CODEC_FLAG_INTERLACED_DCT;
- c->flags |= CODEC_FLAG_INTERLACED_ME;
- }
-
/* xasp & yasp got float lately... */
st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255);
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
deleted file mode 100644
index ebd6de6009e..00000000000
--- a/source/blender/blenkernel/intern/writeframeserver.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * ***** 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.
- *
- * Copyright (c) 2006 Peter Schlaile
- *
- * Contributor(s):
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/writeframeserver.c
- * \ingroup bke
- *
- * Frameserver
- * Makes Blender accessible from TMPGenc directly using VFAPI (you can
- * use firefox too ;-)
- */
-
-#ifdef WITH_FRAMESERVER
-
-#include <string.h>
-#include <stdio.h>
-
-#if defined(_WIN32)
-#include <winsock2.h>
-#include <windows.h>
-#include <winbase.h>
-#include <direct.h>
-#else
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netdb.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#endif
-
-#include <stdlib.h>
-
-#include "DNA_userdef_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_writeframeserver.h"
-#include "BKE_global.h"
-#include "BKE_report.h"
-
-#include "DNA_scene_types.h"
-#include "MEM_guardedalloc.h"
-
-typedef struct FrameserverContext {
- int sock;
- int connsock;
- int write_ppm;
- int render_width;
- int render_height;
-} FrameserverContext;
-
-
-#if defined(_WIN32)
-static int startup_socket_system(void)
-{
- WSADATA wsa;
- return (WSAStartup(MAKEWORD(2, 0), &wsa) == 0);
-}
-
-static void shutdown_socket_system(void)
-{
- WSACleanup();
-}
-static int select_was_interrupted_by_signal(void)
-{
- return (WSAGetLastError() == WSAEINTR);
-}
-#else
-static int startup_socket_system(void)
-{
- return 1;
-}
-
-static void shutdown_socket_system(void)
-{
-}
-
-static int select_was_interrupted_by_signal(void)
-{
- return (errno == EINTR);
-}
-
-static int closesocket(int fd)
-{
- return close(fd);
-}
-#endif
-
-int BKE_frameserver_start(void *context_v, struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview), const char *UNUSED(suffix))
-{
- struct sockaddr_in addr;
- int arg = 1;
- FrameserverContext *context = context_v;
-
- (void)scene; /* unused */
-
- if (!startup_socket_system()) {
- BKE_report(reports, RPT_ERROR, "Cannot startup socket system");
- return 0;
- }
-
- if ((context->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- shutdown_socket_system();
- BKE_report(reports, RPT_ERROR, "Cannot open socket");
- return 0;
- }
-
- setsockopt(context->sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(U.frameserverport);
- addr.sin_addr.s_addr = INADDR_ANY;
-
- if (bind(context->sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- shutdown_socket_system();
- BKE_report(reports, RPT_ERROR, "Cannot bind to socket");
- return 0;
- }
-
- if (listen(context->sock, SOMAXCONN) < 0) {
- shutdown_socket_system();
- BKE_report(reports, RPT_ERROR, "Cannot establish listen backlog");
- return 0;
- }
- context->connsock = -1;
-
- context->render_width = rectx;
- context->render_height = recty;
-
- return 1;
-}
-
-static char index_page[] =
-"HTTP/1.1 200 OK\r\n"
-"Content-Type: text/html\r\n"
-"\r\n"
-"<html><head><title>Blender Frameserver</title></head>\n"
-"<body><pre>\n"
-"<H2>Blender Frameserver</H2>\n"
-"<A HREF=info.txt>Render Info</A><br>\n"
-"<A HREF=close.txt>Stop Rendering</A><br>\n"
-"\n"
-"Images can be found here\n"
-"\n"
-"images/ppm/%d.ppm\n"
-"\n"
-"</pre></body></html>\n";
-
-static char good_bye[] =
-"HTTP/1.1 200 OK\r\n"
-"Content-Type: text/html\r\n"
-"\r\n"
-"<html><head><title>Blender Frameserver</title></head>\n"
-"<body><pre>\n"
-"Render stopped. Goodbye</pre></body></html>";
-
-static int safe_write(const int connsock, char *s, int tosend)
-{
- int total = tosend;
- do {
- int got = send(connsock, s, tosend, 0);
- if (got < 0) {
- return got;
- }
- tosend -= got;
- s += got;
- } while (tosend > 0);
-
- return total;
-}
-
-static int safe_puts(const int connsock, char *s)
-{
- return safe_write(connsock, s, strlen(s));
-}
-
-static int handle_request(FrameserverContext *context, RenderData *rd, char *req)
-{
- char *p;
- char *path;
- int pathlen;
-
- if (memcmp(req, "GET ", 4) != 0) {
- return -1;
- }
-
- p = req + 4;
- path = p;
-
- while (*p != ' ' && *p) p++;
-
- *p = 0;
-
- if (STREQ(path, "/index.html") || STREQ(path, "/")) {
- safe_puts(context->connsock, index_page);
- return -1;
- }
-
- context->write_ppm = 0;
- pathlen = strlen(path);
-
- if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
- context->write_ppm = 1;
- return atoi(path + 12);
- }
- if (STREQ(path, "/info.txt")) {
- char buf[4096];
-
- sprintf(buf,
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html\r\n"
- "\r\n"
- "start %d\n"
- "end %d\n"
- "width %d\n"
- "height %d\n"
- "rate %d\n"
- "ratescale %d\n",
- rd->sfra,
- rd->efra,
- context->render_width,
- context->render_height,
- rd->frs_sec,
- 1
- );
-
- safe_puts(context->connsock, buf);
- return -1;
- }
- if (STREQ(path, "/close.txt")) {
- safe_puts(context->connsock, good_bye);
- G.is_break = true; /* Abort render */
- return -1;
- }
- return -1;
-}
-
-int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(reports))
-{
- fd_set readfds;
- struct timeval tv;
- struct sockaddr_in addr;
- int len, rval;
- unsigned int socklen;
- char buf[4096];
-
- FrameserverContext *context = context_v;
-
- if (context->connsock != -1) {
- closesocket(context->connsock);
- context->connsock = -1;
- }
-
- tv.tv_sec = 1;
- tv.tv_usec = 0;
-
- FD_ZERO(&readfds);
- FD_SET(context->sock, &readfds);
-
- rval = select(context->sock + 1, &readfds, NULL, NULL, &tv);
- if (rval < 0) {
- return -1;
- }
-
- if (rval == 0) { /* nothing to be done */
- return -1;
- }
-
- socklen = sizeof(addr);
-
- if ((context->connsock = accept(context->sock, (struct sockaddr *)&addr, &socklen)) < 0) {
- return -1;
- }
-
- FD_ZERO(&readfds);
- FD_SET(context->connsock, &readfds);
-
- for (;;) {
- /* give 10 seconds for telnet testing... */
- tv.tv_sec = 10;
- tv.tv_usec = 0;
-
- rval = select(context->connsock + 1, &readfds, NULL, NULL, &tv);
- if (rval > 0) {
- break;
- }
- else if (rval == 0) {
- return -1;
- }
- else if (rval < 0) {
- if (!select_was_interrupted_by_signal()) {
- return -1;
- }
- }
- }
-
- len = recv(context->connsock, buf, sizeof(buf) - 1, 0);
-
- if (len < 0) {
- return -1;
- }
-
- buf[len] = 0;
-
- return handle_request(context, rd, buf);
-}
-
-static void serve_ppm(FrameserverContext *context, int *pixels, int rectx, int recty)
-{
- unsigned char *rendered_frame;
- unsigned char *row = (unsigned char *) malloc(context->render_width * 3);
- int y;
- char header[1024];
-
- sprintf(header,
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: image/ppm\r\n"
- "Connection: close\r\n"
- "\r\n"
- "P6\n"
- "# Creator: blender frameserver v0.0.1\n"
- "%d %d\n"
- "255\n",
- rectx, recty);
-
- safe_puts(context->connsock, header);
-
- rendered_frame = (unsigned char *)pixels;
-
- for (y = recty - 1; y >= 0; y--) {
- unsigned char *target = row;
- unsigned char *src = rendered_frame + rectx * 4 * y;
- unsigned char *end = src + rectx * 4;
- while (src != end) {
- target[2] = src[2];
- target[1] = src[1];
- target[0] = src[0];
-
- target += 3;
- src += 4;
- }
- safe_write(context->connsock, (char *)row, 3 * rectx);
- }
- free(row);
- closesocket(context->connsock);
- context->connsock = -1;
-}
-
-int BKE_frameserver_append(void *context_v, RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
- int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
-{
- FrameserverContext *context = context_v;
-
- fprintf(stderr, "Serving frame: %d\n", frame);
- if (context->write_ppm) {
- serve_ppm(context, pixels, rectx, recty);
- }
- if (context->connsock != -1) {
- closesocket(context->connsock);
- context->connsock = -1;
- }
-
- return 1;
-}
-
-void BKE_frameserver_end(void *context_v)
-{
- FrameserverContext *context = context_v;
-
- if (context->connsock != -1) {
- closesocket(context->connsock);
- context->connsock = -1;
- }
- closesocket(context->sock);
- shutdown_socket_system();
-}
-
-void *BKE_frameserver_context_create(void)
-{
- FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context");
- return context;
-}
-
-void BKE_frameserver_context_free(void *context_v)
-{
- FrameserverContext *context = context_v;
- if (context) {
- MEM_freeN(context);
- }
-}
-
-#endif /* WITH_FRAMESERVER */