diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
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, ¶ms, &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(¶ms, &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, ¶ms, &data_cb); + camera_frame_fit_data_init(scene_eval, camera_ob_eval, ¶ms, &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, ×cale); 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(¶ms); - BKE_camera_params_from_object(¶ms, camob); + BKE_camera_params_from_object(¶ms, 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, ¤t_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(<Ob->curve_cache->disp); + if (ltOb->curve_cache) { + /* prevent using deformed locations */ + BKE_displist_free(<Ob->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, <_src->key->id, (ID **)<_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, <->id, (ID **)<_copy, 0, false); + BKE_id_copy_ex(bmain, <->id, (ID **)<_copy, LIB_ID_COPY_SHAPEKEY, false); return lt_copy; } @@ -313,6 +311,8 @@ void BKE_lattice_free(Lattice *lt) { BKE_animdata_free(<->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 **)©cu, 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 **)<ree, - 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 **)<ree, + (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(<ree->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 */ |