Commit: 6647a3517e7865c6936d81d084630ffb9811612f
Author: Campbell Barton
Date:   Thu Jul 3 16:54:27 2014 +1000
https://developer.blender.org/rB6647a3517e7865c6936d81d084630ffb9811612f

Patch D443: A new implementation of the Array Modifier

By PatB

Committing to temp branch to do testing and finalize before going into master

===================================================================

M       source/blender/blenkernel/BKE_cdderivedmesh.h
M       source/blender/blenkernel/intern/cdderivedmesh.c
M       source/blender/modifiers/intern/MOD_array.c
M       source/blender/modifiers/intern/MOD_mirror.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h 
b/source/blender/blenkernel/BKE_cdderivedmesh.h
index dffc2b6..02aa7f5 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -58,7 +58,10 @@ struct DerivedMesh *CDDM_from_bmesh(struct BMesh *bm, const 
bool use_mdisps);
 DerivedMesh *CDDM_from_editbmesh(struct BMEditMesh *em, const bool use_mdisps, 
const bool use_tessface);
 
 /* merge verts  */
-DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const 
int tot_vtargetmap);
+/* Constants for merge_mode of CDDM_merge_verts.   Refer to cdderivedmesh.c 
for details.  */
+#define CDDM_MERGE_VERTS_DUMP_IF_MAPPED  1
+#define CDDM_MERGE_VERTS_DUMP_IF_EQUAL   2
+DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const 
int tot_vtargetmap, const int merge_mode);
 
 /* creates a CDDerivedMesh from the given curve object */
 struct DerivedMesh *CDDM_from_curve(struct Object *ob);
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c 
b/source/blender/blenkernel/intern/cdderivedmesh.c
index 3f8edbc..21168af 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -2540,6 +2540,169 @@ void CDDM_calc_normals_tessface(DerivedMesh *dm)
 }
 
 #if 1
+/**
+ *  Poly compare with vtargetmap
+ *  Function used by #CDDM_merge_verts.
+ *  The function compares poly_source after applying vtargetmap, with 
poly_target. 
+ *  The two polys are identical if they share the same vertices in the same 
order, or in reverse order,
+ *  but starting position loopstart may be different.
+ *  The function is called with direct_reverse=1 for same order (i.e. same 
normal), 
+ *  and may be called again with direct_reverse=-1 for reverse order.
+ *  \return 1 if polys are identical,  0 if polys are different.
+ */
+
+static int cddm_poly_compare(MLoop *mloop_array, MPoly *mpoly_source, MPoly 
*mpoly_target, const int *vtargetmap, const int direct_reverse)
+{
+       int vert_source, first_vert_source, vert_target;
+       int i_loop_source;
+       int i_loop_target, i_loop_target_start, i_loop_target_offset, 
i_loop_target_adjusted;
+       bool compare_completed = false;
+       bool same_loops = false;
+
+       MLoop * mloop_source, *mloop_target;
+
+       BLI_assert(direct_reverse == 1 || direct_reverse == -1);
+
+       i_loop_source = 0;
+       mloop_source = mloop_array + mpoly_source->loopstart;
+       vert_source = mloop_source->v;
+
+       if (vtargetmap[vert_source] != -1)
+               vert_source = vtargetmap[vert_source];
+       else {
+               /* All source loop vertices should be mapped */
+               BLI_assert(false);
+       }
+
+       /* Find same vertex within mpoly_target's loops */
+       mloop_target = mloop_array + mpoly_target->loopstart;
+       for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; 
i_loop_target++, mloop_target++) {
+               if (mloop_target->v == vert_source)
+                       break;
+       }
+
+       /* If same vertex not found, then polys cannot be equal */
+       if (i_loop_target >= mpoly_target->totloop) {
+               return false;
+       }
+
+       /* Now mloop_source and m_loop_target have one identical vertex */
+       /* mloop_source is at position 0, while m_loop_target has advanced to 
find identical vertex */
+       /* Go around the loop and check that all vertices match in same order */
+       /* Skipping source loops when consecutive source vertices are mapped to 
same target vertex */
+
+       i_loop_target_start = i_loop_target;
+       i_loop_target_offset = 0;
+       first_vert_source = vert_source;
+
+       compare_completed = false;
+       same_loops = false;
+
+       while (!compare_completed) {
+
+               vert_target = mloop_target->v;
+
+               /* First advance i_loop_source, until it points to different 
vertex, after mapping applied */
+               do {
+                       i_loop_source++;
+
+                       if (i_loop_source == mpoly_source->totloop) {
+                               /* End of loops for source, must match end of 
loop for target.  */
+                               if (i_loop_target_offset == 
mpoly_target->totloop - 1) {
+                                       compare_completed = true;
+                                       same_loops = true;
+                                       break;  /* Polys are identical */
+                               }
+                               else {
+                                       compare_completed = true;
+                                       same_loops = false;
+                                       break;  /* Polys are different */
+                               }
+                       }
+
+                       mloop_source++;
+                       vert_source = mloop_source->v;
+
+                       if (vtargetmap[vert_source] != -1) {
+                               vert_source = vtargetmap[vert_source];
+                       }
+                       else {
+                               /* All source loop vertices should be mapped */
+                               BLI_assert(false);
+                       }
+
+               } while (vert_source == vert_target);
+
+               if (compare_completed)
+                       break;
+
+               /* Now advance i_loop_target as well */
+               i_loop_target_offset++;
+
+               if (i_loop_target_offset == mpoly_target->totloop) {
+                       /* End of loops for target only, that means no match */
+                       /* except if all remaining source vertices are mapped 
to first target */
+                       for (; i_loop_source < mpoly_source->totloop; 
i_loop_source++, mloop_source++) {
+                               vert_source = vtargetmap[mloop_source->v];
+                               if (vert_source != first_vert_source) {
+                                       compare_completed = true;
+                                       same_loops = false;
+                                       break;
+                               }
+                       }
+                       if (!compare_completed) {
+                               same_loops = true;
+                       }
+                       break;
+               }
+
+               /* Adjust i_loop_target for cycling around and for 
direct/reverse order defined by delta = +1 or -1 */
+               i_loop_target_adjusted = (i_loop_target_start + direct_reverse 
* i_loop_target_offset) % mpoly_target->totloop;
+               if (i_loop_target_adjusted < 0) 
+                       i_loop_target_adjusted += mpoly_target->totloop;
+               mloop_target = mloop_array + mpoly_target->loopstart + 
i_loop_target_adjusted;
+               vert_target = mloop_target->v;
+
+               if (vert_target != vert_source) {
+                       same_loops = false;   /* Polys are different */
+                       break;
+               }
+       }
+       return same_loops;
+}
+
+/* Utility stuff for using GHash with polys */
+
+typedef struct PolyKey {
+       int poly_index;   /* index of the MPoly within the derived mesh */
+       int totloops;     /* number of loops in the poly */
+       unsigned int hash_sum;  /* Sum of all vertices indices */
+       unsigned int hash_xor;  /* Xor of all vertices indices */
+} PolyKey;
+
+
+static unsigned int poly_ghash_hash_fn(const void *key) 
+{
+       PolyKey *pk = (PolyKey*)key;
+       return pk->hash_sum;
+}
+
+static int poly_ghash_compare_fn(const void *k1, const void *k2) 
+{
+       PolyKey *pk1 = (PolyKey*)k1;
+       PolyKey *pk2 = (PolyKey*)k2;
+       if (pk1->hash_sum == pk2->hash_sum &&
+               pk1->hash_xor == pk2->hash_xor &&
+               pk1->totloops == pk2->totloops)
+       {
+               /* Equality - note that this does not mean equality of polys */
+               return 0;
+       }
+       else {
+               return 1;
+       }
+}
+
 
 /**
  * Merge Verts
@@ -2555,12 +2718,19 @@ void CDDM_calc_normals_tessface(DerivedMesh *dm)
  *
  * note, CDDM_recalc_tessellation has to run on the returned DM if you want to 
access tessfaces.
  *
- * Note: This function is currently only used by the Mirror modifier, so it
- *       skips any faces that have all vertices merged (to avoid creating pairs
- *       of faces sharing the same set of vertices). If used elsewhere, it may
- *       be necessary to make this functionality optional.
+ * Note: This function has two modes. 
+ *       When called by the Mirror Modifier, it uses merge_mode= 
..._DUMP_IF_MAPPED (=1).
+ *       In this mode it skips any faces that have all vertices merged (to 
avoid creating pairs
+ *       of faces sharing the same set of vertices)
+ *       When called by the Array Modifier, it uses merge_mode= 
..._DUMP_IF_EQUAL (=2).
+ *       In this mode, faces where all vertices are merged are double-checked, 
to see whether
+ *       all target vertices actually make up a poly already.   Indeed it 
could be that all of a poly's
+ *       vertices are merged, but merged to vertices that do not make up a 
single poly, in which case
+ *       the original poly should not be dumped.
+ *       Actually this later behaviour could apply to the Mirror Modifier as 
well, but the additionnal checks are
+ *       costly and not necessary in the case of mirror, because each vertex 
is only merged to its own mirror.
  */
-DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const 
int tot_vtargetmap)
+DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const 
int tot_vtargetmap, const int merge_mode)
 {
 // #define USE_LOOPS
        CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
@@ -2601,7 +2771,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int 
*vtargetmap, const int
        EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge);
 
        int i, j, c;
-       
+
+       PolyKey *poly_keys;
+       GHash *poly_ghash = NULL;
+
        STACK_INIT(oldv, totvert_final);
        STACK_INIT(olde, totedge);
        STACK_INIT(oldl, totloop);
@@ -2643,10 +2816,9 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int 
*vtargetmap, const int
        med = cddm->medge;
        c = 0;
        for (i = 0; i < totedge; i++, med++) {
-               
-               if (LIKELY(med->v1 != med->v2)) {
-                       const unsigned int v1 = (vtargetmap[med->v1] != -1) ? 
vtargetmap[med->v1] : med->v1;
-                       const unsigned int v2 = (vtargetmap[med->v2] != -1) ? 
vtargetmap[med->v2] : med->v2;
+               const unsigned int v1 = (vtargetmap[med->v1] != -1) ? 
vtargetmap[med->v1] : med->v1;
+               const unsigned int v2 = (vtargetmap[med->v2] != -1) ? 
vtargetmap[med->v2] : med->v2;
+               if (LIKELY(v1 != v2)) {
                        void **eh_p = BLI_edgehash_lookup_p(ehash, v1, v2);
 
                        if (eh_p) {
@@ -2665,13 +2837,48 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const 
int *vtargetmap, const int
                }
        }
        
+       if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) {
+               /* In this mode, we need to determine,  whenever a poly' 
vertices are all mapped */
+               /* if the targets already make up a poly, in which case the new 
poly is dropped */
+               /* This poly equality check is rather complex.   We use a 
BLI_ghash to speed it up with a first level check */
+               PolyKey *mpgh;
+               poly_keys = MEM_mallocN(sizeof(PolyKey)* totpoly, 
"CDDM_merge_verts poly keys");
+               poly_ghash = BLI_ghash_new_ex(poly_ghash_hash_fn, 
poly_ghash_compare_fn, "CDDM_merge_verts poly hash", totpoly);
+               BLI_ghash_flag_set(poly_ghash, GHASH_FLAG_ALLOW_DUPES);  /* 
Duplicates allowed because our compare function is not pure equality */
+
+               mp = cddm->mpoly;
+               mpgh = poly_keys;
+               for (i = 0; i < totpoly; i++, mp++, mpgh++) {
+                       mpgh->poly_index = i;
+                       mpgh->totloops = mp->totloop;
+                       ml = cddm->mloop + mp->loopstart;
+                       mpgh->hash_sum = mpgh->hash_xor = 0;
+                       for (j = 0; j

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to