Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/editmesh.cc')
-rw-r--r--source/blender/blenkernel/intern/editmesh.cc307
1 files changed, 307 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/editmesh.cc b/source/blender/blenkernel/intern/editmesh.cc
new file mode 100644
index 00000000000..b586b4110f2
--- /dev/null
+++ b/source/blender/blenkernel/intern/editmesh.cc
@@ -0,0 +1,307 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2005 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_math.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
+#include "BKE_mesh_wrapper.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+BMEditMesh *BKE_editmesh_create(BMesh *bm)
+{
+ BMEditMesh *em = MEM_cnew<BMEditMesh>(__func__);
+ em->bm = bm;
+ return em;
+}
+
+BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
+{
+ BMEditMesh *em_copy = MEM_cnew<BMEditMesh>(__func__);
+ *em_copy = *em;
+
+ em_copy->bm = BM_mesh_copy(em->bm);
+
+ /* The tessellation is NOT calculated on the copy here,
+ * because currently all the callers of this function use
+ * it to make a backup copy of the #BMEditMesh to restore
+ * it in the case of errors in an operation. For performance reasons,
+ * in that case it makes more sense to do the
+ * tessellation only when/if that copy ends up getting used. */
+ em_copy->looptris = nullptr;
+
+ /* Copy various settings. */
+ em_copy->selectmode = em->selectmode;
+ em_copy->mat_nr = em->mat_nr;
+
+ return em_copy;
+}
+
+BMEditMesh *BKE_editmesh_from_object(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+ /* sanity check */
+#if 0 /* disable in multi-object edit. */
+# ifndef NDEBUG
+ if (((Mesh *)ob->data)->edit_mesh) {
+ BLI_assert(((Mesh *)ob->data)->edit_mesh->ob == ob);
+ }
+# endif
+#endif
+ return ((Mesh *)ob->data)->edit_mesh;
+}
+
+static void editmesh_tessface_calc_intern(BMEditMesh *em,
+ const BMeshCalcTessellation_Params *params)
+{
+ /* allocating space before calculating the tessellation */
+
+ BMesh *bm = em->bm;
+
+ /* This assumes all faces can be scan-filled, which isn't always true,
+ * worst case we over allocate a little which is acceptable. */
+ const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+ const int looptris_tot_prev_alloc = em->looptris ?
+ (MEM_allocN_len(em->looptris) / sizeof(*em->looptris)) :
+ 0;
+
+ BMLoop *(*looptris)[3];
+
+ /* This means no reallocations for quad dominant models. */
+ if ((em->looptris != nullptr) &&
+ // (*em->tottri >= looptris_tot))
+ /* Check against allocated size in case we over allocated a little. */
+ ((looptris_tot_prev_alloc >= looptris_tot) &&
+ (looptris_tot_prev_alloc <= looptris_tot * 2))) {
+ looptris = em->looptris;
+ }
+ else {
+ if (em->looptris) {
+ MEM_freeN(em->looptris);
+ }
+ looptris = static_cast<BMLoop *(*)[3]>(
+ MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__));
+ }
+
+ em->looptris = looptris;
+ em->tottri = looptris_tot;
+
+ /* after allocating the em->looptris, we're ready to tessellate */
+ BM_mesh_calc_tessellation_ex(em->bm, em->looptris, params);
+}
+
+void BKE_editmesh_looptri_calc_ex(BMEditMesh *em, const BMeshCalcTessellation_Params *params)
+{
+ editmesh_tessface_calc_intern(em, params);
+
+ /* commented because editbmesh_build_data() ensures we get tessfaces */
+#if 0
+ if (em->mesh_eval_final && em->mesh_eval_final == em->mesh_eval_cage) {
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
+ }
+ else if (em->mesh_eval_final) {
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_cage);
+ }
+#endif
+}
+
+void BKE_editmesh_looptri_calc(BMEditMesh *em)
+{
+ BMeshCalcTessellation_Params params{};
+ params.face_normals = false;
+ BKE_editmesh_looptri_calc_ex(em, &params);
+}
+
+void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em)
+{
+ BMeshCalcTessellation_Params looptri_params{};
+ looptri_params.face_normals = true;
+ BKE_editmesh_looptri_calc_ex(em, &looptri_params);
+ BMeshNormalsUpdate_Params normals_params{};
+ normals_params.face_normals = false;
+ BM_mesh_normals_update_ex(em->bm, &normals_params);
+}
+
+void BKE_editmesh_looptri_calc_with_partial_ex(BMEditMesh *em,
+ BMPartialUpdate *bmpinfo,
+ const BMeshCalcTessellation_Params *params)
+{
+ BLI_assert(em->tottri == poly_to_tri_count(em->bm->totface, em->bm->totloop));
+ BLI_assert(em->looptris != nullptr);
+
+ BM_mesh_calc_tessellation_with_partial_ex(em->bm, em->looptris, bmpinfo, params);
+}
+
+void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, BMPartialUpdate *bmpinfo)
+{
+ BMeshCalcTessellation_Params looptri_params{};
+ looptri_params.face_normals = false;
+ BKE_editmesh_looptri_calc_with_partial_ex(em, bmpinfo, &looptri_params);
+}
+
+void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em, BMPartialUpdate *bmpinfo)
+{
+ BMeshCalcTessellation_Params looptri_params{};
+ looptri_params.face_normals = true;
+ BKE_editmesh_looptri_calc_with_partial_ex(em, bmpinfo, &looptri_params);
+ BMeshNormalsUpdate_Params normals_params{};
+ normals_params.face_normals = false;
+ BM_mesh_normals_update_with_partial_ex(em->bm, bmpinfo, &normals_params);
+}
+
+void BKE_editmesh_free_data(BMEditMesh *em)
+{
+
+ if (em->looptris) {
+ MEM_freeN(em->looptris);
+ }
+
+ if (em->bm) {
+ BM_mesh_free(em->bm);
+ }
+}
+
+struct CageUserData {
+ int totvert;
+ float (*cos_cage)[3];
+ BLI_bitmap *visit_bitmap;
+};
+
+static void cage_mapped_verts_callback(void *userData,
+ int index,
+ const float co[3],
+ const float /*no*/[3])
+{
+ CageUserData *data = static_cast<CageUserData *>(userData);
+
+ if ((index >= 0 && index < data->totvert) && !BLI_BITMAP_TEST(data->visit_bitmap, index)) {
+ BLI_BITMAP_ENABLE(data->visit_bitmap, index);
+ copy_v3_v3(data->cos_cage[index], co);
+ }
+}
+
+float (*BKE_editmesh_vert_coords_alloc(
+ Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, Object *ob, int *r_vert_len))[3]
+{
+ Mesh *cage = editbmesh_get_eval_cage(depsgraph, scene, ob, em, &CD_MASK_BAREMESH);
+ float(*cos_cage)[3] = static_cast<float(*)[3]>(
+ MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, __func__));
+
+ /* When initializing cage verts, we only want the first cage coordinate for each vertex,
+ * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate. */
+ BLI_bitmap *visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+
+ CageUserData data;
+ data.totvert = em->bm->totvert;
+ data.cos_cage = cos_cage;
+ data.visit_bitmap = visit_bitmap;
+
+ BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
+
+ MEM_freeN(visit_bitmap);
+
+ if (r_vert_len) {
+ *r_vert_len = em->bm->totvert;
+ }
+
+ return cos_cage;
+}
+
+const float (*BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph,
+ BMEditMesh *em,
+ Scene *scene,
+ Object *ob,
+ int *r_vert_len,
+ bool *r_is_alloc))[3]
+{
+ const float(*coords)[3] = nullptr;
+ *r_is_alloc = false;
+
+ Mesh *me = static_cast<Mesh *>(ob->data);
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval);
+
+ if ((me->runtime->edit_data != nullptr) && (me->runtime->edit_data->vertexCos != nullptr)) {
+ /* Deformed, and we have deformed coords already. */
+ coords = me->runtime->edit_data->vertexCos;
+ }
+ else if ((editmesh_eval_final != nullptr) &&
+ (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
+ /* If this is an edit-mesh type, leave nullptr as we can use the vertex coords. */
+ }
+ else {
+ /* Constructive modifiers have been used, we need to allocate coordinates. */
+ *r_is_alloc = true;
+ coords = BKE_editmesh_vert_coords_alloc(depsgraph, em, scene, ob, r_vert_len);
+ }
+ return coords;
+}
+
+float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]
+{
+ return BM_mesh_vert_coords_alloc(em->bm, r_vert_len);
+}
+
+void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me)
+{
+ BMesh *bm = em->bm;
+
+ /* We need to create custom-loop-normals (CLNORS) data if none exist yet,
+ * otherwise there is no way to edit them.
+ * Similar code to #MESH_OT_customdata_custom_splitnormals_add operator,
+ * we want to keep same shading in case we were using auto-smooth so far.
+ * NOTE: there is a problem here, which is that if someone starts a normal editing operation on
+ * previously auto-smooth-ed mesh, and cancel that operation, generated CLNORS data remain,
+ * with related sharp edges (and hence auto-smooth is 'lost').
+ * Not sure how critical this is, and how to fix that issue? */
+ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ if (me->flag & ME_AUTOSMOOTH) {
+ BM_edges_sharp_from_angle_set(bm, me->smoothresh);
+ }
+ }
+
+ BM_lnorspace_update(bm);
+}
+
+void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
+{
+ if (!(me->flag & ME_AUTOSMOOTH)) {
+ me->flag |= ME_AUTOSMOOTH;
+ BKE_editmesh_lnorspace_update(em, me);
+ }
+}
+
+BoundBox *BKE_editmesh_cage_boundbox_get(Object *object, BMEditMesh * /*em*/)
+{
+ if (object->runtime.editmesh_bb_cage == nullptr) {
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ if (object->runtime.editmesh_eval_cage) {
+ BKE_mesh_wrapper_minmax(object->runtime.editmesh_eval_cage, min, max);
+ }
+
+ object->runtime.editmesh_bb_cage = MEM_cnew<BoundBox>("BMEditMesh.bb_cage");
+ BKE_boundbox_init_from_minmax(object->runtime.editmesh_bb_cage, min, max);
+ }
+
+ return object->runtime.editmesh_bb_cage;
+}