looptri + bvhtree support for Mesh
authorSybren A. Stüvel <sybren@stuvel.eu>
Tue, 8 May 2018 08:07:21 +0000 (10:07 +0200)
committerSybren A. Stüvel <sybren@stuvel.eu>
Tue, 8 May 2018 09:36:48 +0000 (11:36 +0200)
source/blender/blenkernel/BKE_bvhutils.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/bvhutils.c
source/blender/blenkernel/intern/mesh_runtime.c [new file with mode: 0644]
source/blender/makesdna/DNA_mesh_types.h

index 1b4bb08756bb028cda97350d019b9eeec1595273..1157e20d6ac3270852c290f788918e764f485fc7 100644 (file)
@@ -40,6 +40,7 @@
 
 struct DerivedMesh;
 struct BMEditMesh;
+struct Mesh;
 struct MVert;
 struct MFace;
 
@@ -142,6 +143,8 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(
         const BLI_bitmap *mask, int looptri_num_active,
         float epsilon, int tree_type, int axis, BVHCache **bvhCache);
 
+BVHTree *BKE_bvhtree_from_mesh_looptri(
+        struct BVHTreeFromMesh *data, struct Mesh *mesh, float epsilon, int tree_type, int axis);
 BVHTree *bvhtree_from_mesh_looptri_ex(
         struct BVHTreeFromMesh *data,
         const struct MVert *vert, const bool vert_allocated,
index 485132bfa6d8f2d6be3f50e88df56affb58a3924..2adc1dbb6e377e9f090ab6904dfec3ca252bd8c2 100644 (file)
@@ -182,7 +182,11 @@ int  BKE_mesh_mselect_find(struct Mesh *me, int index, int type);
 int  BKE_mesh_mselect_active_get(struct Mesh *me, int type);
 void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type);
 
+/* *** mesh_runtime.c *** */
 
+void BKE_mesh_runtime_recalc_looptri(struct Mesh *mesh);
+int BKE_mesh_get_looptri_num(struct Mesh *mesh);
+const struct MLoopTri *BKE_mesh_get_looptri_array(struct Mesh *mesh);
 
 /* *** mesh_evaluate.c *** */
 
index 9e241b7fa81bfdb7e4bdce72f2d15836e0d42817..83241d3c4c7fd25e1b79a26c62c1ee66ac9d8342 100644 (file)
@@ -143,6 +143,7 @@ set(SRC
        intern/mesh_mapping.c
        intern/mesh_merge.c
        intern/mesh_remap.c
+       intern/mesh_runtime.c
        intern/mesh_tangent.c
        intern/mesh_validate.c
        intern/modifier.c
index 0240bb4b62415ed4be3b3b22cf45d61208fa3faf..00aa89b3776676ecdeafa9e9636651e33b2490d5 100644 (file)
@@ -34,6 +34,7 @@
 #include <math.h>
 #include <assert.h>
 
+#include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 
 #include "BLI_utildefines.h"
@@ -43,6 +44,7 @@
 
 #include "BKE_DerivedMesh.h"
 #include "BKE_editmesh.h"
+#include "BKE_mesh.h"
 
 #include "MEM_guardedalloc.h"
 
@@ -1161,6 +1163,70 @@ BVHTree *bvhtree_from_mesh_get(
        return tree;
 }
 
+/* This is a Mesh-specific copy of bvhtree_from_mesh_looptri() */
+/**
+ * Builds a bvh tree where nodes are the looptri faces of the given mesh.
+ *
+ * \note for editmesh this is currently a duplicate of bvhtree_from_mesh_faces
+ */
+BVHTree *BKE_bvhtree_from_mesh_looptri(
+        BVHTreeFromMesh *data, Mesh *mesh,
+        float epsilon, int tree_type, int axis)
+{
+       BVHTree *tree;
+       MVert *mvert = NULL;
+       MLoop *mloop = NULL;
+       const MLoopTri *looptri = NULL;
+
+       BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+       tree = bvhcache_find(mesh->runtime.bvh_cache, BVHTREE_FROM_LOOPTRI);
+       BLI_rw_mutex_unlock(&cache_rwlock);
+
+       mvert = mesh->mvert;
+       mloop = mesh->mloop;
+       looptri = BKE_mesh_get_looptri_array(mesh);
+
+       /* Not in cache */
+       if (tree == NULL) {
+               BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+               tree = bvhcache_find(mesh->runtime.bvh_cache, BVHTREE_FROM_LOOPTRI);
+               if (tree == NULL) {
+                       int looptri_num = BKE_mesh_get_looptri_num(mesh);
+
+                       /* this assert checks we have looptris,
+                        * if not caller should use DM_ensure_looptri() */
+                       BLI_assert(!(looptri_num == 0 && mesh->totpoly != 0));
+
+                       tree = bvhtree_from_mesh_looptri_create_tree(
+                               epsilon, tree_type, axis,
+                               mvert, mloop, looptri, looptri_num, NULL, -1);
+                       if (tree) {
+                               /* Save on cache for later use */
+                               /* printf("BVHTree built and saved on cache\n"); */
+                               bvhcache_insert(&mesh->runtime.bvh_cache, tree, BVHTREE_FROM_LOOPTRI);
+                       }
+               }
+               BLI_rw_mutex_unlock(&cache_rwlock);
+       }
+       else {
+               /* printf("BVHTree is already build, using cached tree\n"); */
+       }
+
+       if (tree) {
+               /* Setup BVHTreeFromMesh */
+               bvhtree_from_mesh_looptri_setup_data(
+                       data, tree, true,
+                       mvert, false,
+                       mloop, false,
+                       looptri, false);
+       }
+       else {
+               memset(data, 0, sizeof(*data));
+       }
+
+       return tree;
+}
+
 /** \} */
 
 
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
new file mode 100644 (file)
index 0000000..02caf45
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_runtime.c
+ *  \ingroup bke
+ */
+
+#include "atomic_ops.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_math_geom.h"
+#include "BLI_threads.h"
+
+#include "BKE_mesh.h"
+
+
+static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+
+/* This is a ported copy of DM_ensure_looptri_data(dm) */
+/**
+ * Ensure the array is large enough
+ *
+ * /note This function must always be thread-protected by caller. It should only be used by internal code.
+ */
+static void mesh_ensure_looptri_data(Mesh *mesh)
+{
+       const unsigned int totpoly = mesh->totpoly;
+       const int looptris_num = poly_to_tri_count(totpoly, mesh->totloop);
+
+       BLI_assert(mesh->runtime.looptris.array_wip == NULL);
+
+       SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+
+       if ((looptris_num > mesh->runtime.looptris.num_alloc) ||
+           (looptris_num < mesh->runtime.looptris.num_alloc * 2) ||
+           (totpoly == 0))
+       {
+               MEM_SAFE_FREE(mesh->runtime.looptris.array_wip);
+               mesh->runtime.looptris.num_alloc = 0;
+               mesh->runtime.looptris.num = 0;
+       }
+
+       if (totpoly) {
+               if (mesh->runtime.looptris.array_wip == NULL) {
+                       mesh->runtime.looptris.array_wip = MEM_malloc_arrayN(looptris_num, sizeof(*mesh->runtime.looptris.array_wip), __func__);
+                       mesh->runtime.looptris.num_alloc = looptris_num;
+               }
+
+               mesh->runtime.looptris.num = looptris_num;
+       }
+}
+
+/* This is a ported copy of CDDM_recalc_looptri(dm). */
+void BKE_mesh_runtime_recalc_looptri(Mesh *mesh)
+{
+       mesh_ensure_looptri_data(mesh);
+       BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != NULL);
+
+       BKE_mesh_recalc_looptri(
+               mesh->mloop, mesh->mpoly,
+               mesh->mvert,
+               mesh->totloop, mesh->totpoly,
+               mesh->runtime.looptris.array_wip);
+
+       BLI_assert(mesh->runtime.looptris.array == NULL);
+       atomic_cas_ptr((void **)&mesh->runtime.looptris.array, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+       mesh->runtime.looptris.array_wip = NULL;
+}
+
+/* This is a ported copy of dm_getNumLoopTri(dm). */
+int BKE_mesh_get_looptri_num(Mesh *mesh)
+{
+       const int numlooptris = poly_to_tri_count(mesh->totpoly, mesh->totloop);
+       BLI_assert(ELEM(mesh->runtime.looptris.num, 0, numlooptris));
+       return numlooptris;
+}
+
+/* This is a ported copy of dm_getLoopTriArray(dm). */
+const MLoopTri *BKE_mesh_get_looptri_array(Mesh *mesh)
+{
+       MLoopTri *looptri;
+
+       BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ);
+       looptri = mesh->runtime.looptris.array;
+       BLI_rw_mutex_unlock(&loops_cache_lock);
+
+       if (looptri != NULL) {
+               BLI_assert(BKE_mesh_get_looptri_num(mesh) == mesh->runtime.looptris.num);
+       }
+       else {
+               BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
+               /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already
+                * recomputed those looptris. */
+               if (mesh->runtime.looptris.array == NULL) {
+                       BKE_mesh_runtime_recalc_looptri(mesh);
+               }
+               looptri = mesh->runtime.looptris.array;
+               BLI_rw_mutex_unlock(&loops_cache_lock);
+       }
+       return looptri;
+}
index d951f67a7c475c1601d1dabaf616a8c060c9c0f0..af81ac8423b4b3c267faa61f0284915cd42c91bb 100644 (file)
 struct AnimData;
 struct Ipo;
 struct Key;
+struct LinkNode;
 struct MCol;
 struct MEdge;
 struct MFace;
 struct MLoop;
 struct MLoopCol;
+struct MLoopTri;
 struct MLoopUV;
 struct MPoly;
 struct MTexPoly;
@@ -65,6 +67,18 @@ typedef struct EditMeshData {
        const float (*polyCos)[3];
 } EditMeshData;
 
+
+/**
+ * \warning Typical access is done via #BKE_mesh_get_looptri_array, #BKE_mesh_get_looptri_num.
+ */
+struct LooptrisData {
+       /* WARNING! swapping between array (ready-to-be-used data) and array_wip (where data is actually computed)
+        *          shall always be protected by same lock as one used for looptris computing. */
+       struct MLoopTri *array, *array_wip;
+       int num;
+       int num_alloc;
+};
+
 /* not saved in file! */
 typedef struct MeshRuntime {
        struct EditMeshData *edit_data;
@@ -74,6 +88,11 @@ typedef struct MeshRuntime {
        int64_t cd_dirty_edge;
        int64_t cd_dirty_loop;
        int64_t cd_dirty_poly;
+
+       struct LooptrisData looptris;
+
+       /** 'BVHCache', for 'BKE_bvhutil.c' */
+       struct LinkNode *bvh_cache;
 } MeshRuntime;
 
 typedef struct Mesh {