Subdiv: Add ptex offsets to a subdiv structure
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 6 Sep 2018 13:39:27 +0000 (15:39 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Fri, 7 Sep 2018 09:54:20 +0000 (11:54 +0200)
This is something what we need to know quite often from various places.
Added it as a cached value in Subdiv itself, so it can be queried easily
from any area.

Shouldn't be a problem from memory usage point of view, it's 4MB per
1M faces coarse mesh. This is very low percentage of mesh itself, and
even lower percentage of highres subdivided mesh.

source/blender/blenkernel/BKE_subdiv.h
source/blender/blenkernel/intern/subdiv.c
source/blender/blenkernel/intern/subdiv_foreach.c

index 28b2942a70f224ffc857814845ebc9111ee468e8..4ebb5d1ac666bdab2d7b1df6f87fbdac80928a46 100644 (file)
@@ -144,6 +144,14 @@ typedef struct Subdiv {
        struct SubdivDisplacement *displacement_evaluator;
        /* Statistics for debugging. */
        SubdivStats stats;
+
+       /* Cached values, are not supposed to be accessed directly. */
+       struct {
+               /* Indexed by base face index, element indicates total number of ptex
+                *faces created for preceding base faces.
+                */
+               int *face_ptex_offset;
+       } cache_;
 } Subdiv;
 
 /* ================================ HELPERS ================================= */
@@ -180,4 +188,8 @@ void BKE_subdiv_displacement_attach_from_multires(
 
 void BKE_subdiv_displacement_detach(Subdiv *subdiv);
 
+/* ============================ TOPOLOGY HELPERS ============================ */
+
+int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv);
+
 #endif  /* __BKE_SUBDIV_H__ */
index f847d62018af80d0e71637cd1b9aee5f576472ba..82275b7305ff32b7f5304a3919484ce19ebef7f4 100644 (file)
@@ -118,5 +118,28 @@ void BKE_subdiv_free(Subdiv *subdiv)
                openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
        }
        BKE_subdiv_displacement_detach(subdiv);
+       if (subdiv->cache_.face_ptex_offset != NULL) {
+               MEM_freeN(subdiv->cache_.face_ptex_offset);
+       }
        MEM_freeN(subdiv);
 }
+
+int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
+{
+       if (subdiv->cache_.face_ptex_offset != NULL) {
+               return subdiv->cache_.face_ptex_offset;
+       }
+       const int num_coarse_faces =
+               subdiv->topology_refiner->getNumFaces(subdiv->topology_refiner);
+       subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
+               num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
+       int ptex_offset = 0;
+       for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
+               const int num_ptex_faces =
+                       subdiv->topology_refiner->getNumFacePtexFaces(
+                               subdiv->topology_refiner, face_index);
+               subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
+               ptex_offset += num_ptex_faces;
+       }
+       return subdiv->cache_.face_ptex_offset;
+}
index 8fa060f2931f05a1dc1fa8de8864572aec458d6d..5c53a0e41264e77a6b5002ec9a5fb1f3e424447b 100644 (file)
@@ -229,16 +229,13 @@ static void subdiv_foreach_ctx_init_offsets(SubdivForeachTaskContext *ctx)
        int vertex_offset = 0;
        int edge_offset = 0;
        int polygon_offset = 0;
-       int face_ptex_offset = 0;
        for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
                const MPoly *coarse_poly = &coarse_mpoly[poly_index];
                const int num_ptex_faces_per_poly =
                        num_ptex_faces_per_poly_get(coarse_poly);
-               ctx->face_ptex_offset[poly_index] = face_ptex_offset;
                ctx->subdiv_vertex_offset[poly_index] = vertex_offset;
                ctx->subdiv_edge_offset[poly_index] = edge_offset;
                ctx->subdiv_polygon_offset[poly_index] = polygon_offset;
-               face_ptex_offset += num_ptex_faces_per_poly;
                if (num_ptex_faces_per_poly == 1) {
                        vertex_offset += resolution_2_squared;
                        edge_offset += num_edges_per_ptex_face_get(resolution - 2) +
@@ -265,7 +262,8 @@ static void subdiv_foreach_ctx_init_offsets(SubdivForeachTaskContext *ctx)
        }
 }
 
-static void subdiv_foreach_ctx_init(SubdivForeachTaskContext *ctx)
+static void subdiv_foreach_ctx_init(Subdiv *subdiv,
+                                    SubdivForeachTaskContext *ctx)
 {
        const Mesh *coarse_mesh = ctx->coarse_mesh;
        /* Allocate maps and offsets. */
@@ -285,15 +283,13 @@ static void subdiv_foreach_ctx_init(SubdivForeachTaskContext *ctx)
                coarse_mesh->totpoly,
                sizeof(*ctx->subdiv_polygon_offset),
                "subdiv_edge_offset");
-       ctx->face_ptex_offset = MEM_malloc_arrayN(coarse_mesh->totpoly,
-                                                 sizeof(*ctx->face_ptex_offset),
-                                                 "face_ptex_offset");
        /* Initialize all offsets. */
        subdiv_foreach_ctx_init_offsets(ctx);
        /* Calculate number of geometry in the result subdivision mesh. */
        subdiv_foreach_ctx_count(ctx);
        /* Re-set maps which were used at this step. */
        BLI_BITMAP_SET_ALL(ctx->coarse_edges_used_map, false, coarse_mesh->totedge);
+       ctx->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
 }
 
 static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
@@ -303,7 +299,6 @@ static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
        MEM_freeN(ctx->subdiv_vertex_offset);
        MEM_freeN(ctx->subdiv_edge_offset);
        MEM_freeN(ctx->subdiv_polygon_offset);
-       MEM_freeN(ctx->face_ptex_offset);
 }
 
 /* =============================================================================
@@ -1982,16 +1977,16 @@ static void subdiv_foreach_finalize(void *__restrict userdata,
 }
 
 bool BKE_subdiv_foreach_subdiv_geometry(
-        struct Subdiv *UNUSED(subdiv),
+        Subdiv *subdiv,
         const SubdivForeachContext *context,
         const SubdivToMeshSettings *mesh_settings,
-        const struct Mesh *coarse_mesh)
+        const Mesh *coarse_mesh)
 {
        SubdivForeachTaskContext ctx = {0};
        ctx.coarse_mesh = coarse_mesh;
        ctx.settings = mesh_settings;
        ctx.foreach_context = context;
-       subdiv_foreach_ctx_init(&ctx);
+       subdiv_foreach_ctx_init(subdiv, &ctx);
        if (context->topology_info != NULL) {
                if (!context->topology_info(context,
                                            ctx.num_subdiv_vertices,