diff options
Diffstat (limited to 'source/blender/blenkernel/intern/DerivedMesh.c')
-rw-r--r-- | source/blender/blenkernel/intern/DerivedMesh.c | 2055 |
1 files changed, 728 insertions, 1327 deletions
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 */ |