BKE_mesh: add polygon flipping tools.
authorBastien Montagne <montagne29@wanadoo.fr>
Sun, 28 Feb 2016 14:29:56 +0000 (15:29 +0100)
committerBastien Montagne <montagne29@wanadoo.fr>
Sun, 28 Feb 2016 14:29:56 +0000 (15:29 +0100)
Those new functions invert the winding of polygons, effectively inverting their normals.

A helper was also added to allow swapping two items in customdata layers.

Being able to invert normals outside of BMesh area is very important in several places,
like IO scripts or customnormals modifiers...

Reviewers: campbellbarton

Differential Revision: https://developer.blender.org/D1814

source/blender/blenkernel/BKE_customdata.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/mesh_evaluate.c
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_mesh_api.c

index 0b248be9780ac873b8cedc9e1ef17317bff8846b..17ad51a7a16abaa484a9bd04fb1a50a93608b1b5 100644 (file)
@@ -260,6 +260,8 @@ void CustomData_bmesh_interp(
  * faces an array of length 4 */
 void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices);
 
+void CustomData_swap(struct CustomData *data, const int index_a, const int index_b);
+
 /* gets a pointer to the data element at index from the first layer of type
  * returns NULL if there is no layer of type
  */
index f35613f8bf7c84fae05bcb79d5af3cf76f8a2380..b85c605f231d31cc01c5173854ab5b5fa183e3ab 100644 (file)
@@ -317,6 +317,9 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(
         int *r_totloop, int *r_totpoly,
         struct MLoop **r_mloop, struct MPoly **r_mpoly);
 
+void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
+void BKE_mesh_polygons_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, int totpoly);
+
 /* flush flags */
 void BKE_mesh_flush_hidden_from_verts_ex(
         const struct MVert *mvert,
index c120509b76986baf1243700af7c96436ba08a1d4..1ed7c9890752afd8cc90f4a7e6029f53bc9a0d58 100644 (file)
@@ -2356,6 +2356,35 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
        }
 }
 
+/**
+ * Swap two items of given custom data, in all available layers.
+ */
+void CustomData_swap(struct CustomData *data, const int index_a, const int index_b)
+{
+       int i;
+       char buff_static[256];
+
+       if (index_a == index_b) {
+               return;
+       }
+
+       for (i = 0; i < data->totlayer; ++i) {
+               const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
+               const size_t size = typeInfo->size;
+               const size_t offset_a = size * index_a;
+               const size_t offset_b = size * index_b;
+
+               void *buff = size <= sizeof(buff_static) ? buff_static : MEM_mallocN(size, __func__);
+               memcpy(buff, POINTER_OFFSET(data->layers[i].data, offset_a), size);
+               memcpy(POINTER_OFFSET(data->layers[i].data, offset_a), POINTER_OFFSET(data->layers[i].data, offset_b), size);
+               memcpy(POINTER_OFFSET(data->layers[i].data, offset_b), buff, size);
+
+               if (buff != buff_static) {
+                       MEM_freeN(buff);
+               }
+       }
+}
+
 void *CustomData_get(const CustomData *data, int index, int type)
 {
        int offset;
index e3b9b21f341214f84532df5c478f9d39124084f0..9fdd541813ae79521072d01b1f01d203b66a9c14 100644 (file)
@@ -3200,6 +3200,57 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData
 }
 /** \} */
 
+/**
+ * Flip (invert winding of) the given \a mpoly, i.e. reverse order of its loops
+ * (keeping the same vertex as 'start point').
+ *
+ * \param mpoly the polygon to flip.
+ * \param mloop the full loops array.
+ * \param ldata the loops custom data.
+ */
+void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
+{
+       int loopstart = mpoly->loopstart;
+       int loopend = loopstart + mpoly->totloop - 1;
+       const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop);
+
+       /* Note that we keep same start vertex for flipped face. */
+
+       /* We also have to update loops' edge
+        * (they ell get ther original 'other edge', that is, the original edge of their original previous loop)... */
+       unsigned int prev_edge_index = mloop[loopstart].e;
+       mloop[loopstart].e = mloop[loopend].e;
+
+       for (loopstart++; loopend > loopstart; loopstart++, loopend--) {
+               mloop[loopend].e = mloop[loopend - 1].e;
+               SWAP(unsigned int, mloop[loopstart].e, prev_edge_index);
+
+               if (!loops_in_ldata) {
+                       SWAP(MLoop, mloop[loopstart], mloop[loopend]);
+               }
+               CustomData_swap(ldata, loopstart, loopend);
+       }
+       /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */
+       if (loopstart == loopend) {
+               mloop[loopstart].e = prev_edge_index;
+       }
+}
+
+/**
+ * Flip (invert winding of) all polygons (used to inverse their normals).
+ *
+ * \note Invalidates tessalation, caller must handle that.
+ */
+void BKE_mesh_polygons_flip(
+        MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly)
+{
+       MPoly *mp;
+       int i;
+
+       for (mp = mpoly, i = 0; i < totpoly; mp++, i++) {
+               BKE_mesh_polygon_flip(mp, mloop, ldata);
+       }
+}
 
 /* -------------------------------------------------------------------- */
 
index 686f8331ac42501ade1b1dcb9059086e16bf35c6..1d7348648332d5810e47085eebfdd9647a24d423 100644 (file)
@@ -418,6 +418,14 @@ static float rna_MeshPolygon_area_get(PointerRNA *ptr)
        return BKE_mesh_calc_poly_area(mp, me->mloop + mp->loopstart, me->mvert);
 }
 
+static void rna_MeshPolygon_flip(ID *id, MPoly *mp)
+{
+       Mesh *me = (Mesh *)id;
+
+       BKE_mesh_polygon_flip(mp, me->mloop, &me->ldata);
+       BKE_mesh_tessface_clear(me);
+}
+
 static void rna_MeshTessFace_normal_get(PointerRNA *ptr, float *values)
 {
        Mesh *me = rna_mesh(ptr);
@@ -2138,6 +2146,7 @@ static void rna_def_mpolygon(BlenderRNA *brna)
 {
        StructRNA *srna;
        PropertyRNA *prop;
+       FunctionRNA *func;
 
        srna = RNA_def_struct(brna, "MeshPolygon", NULL);
        RNA_def_struct_sdna(srna, "MPoly");
@@ -2216,6 +2225,11 @@ static void rna_def_mpolygon(BlenderRNA *brna)
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
        RNA_def_property_int_funcs(prop, "rna_MeshPolygon_index_get", NULL, NULL);
        RNA_def_property_ui_text(prop, "Index", "Index of this polygon");
+
+       func = RNA_def_function(srna, "flip", "rna_MeshPolygon_flip");
+       RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+       RNA_def_function_ui_description(func, "Invert winding of this polygon (flip its normal)");
+
 }
 
 /* mesh.loop_uvs */
index 1459157112e9b4534f824b936a1cab0b238a7294..a3bc21b017072a2dd48d20d4208ff332fbee9844 100644 (file)
@@ -200,6 +200,15 @@ static void rna_Mesh_transform(Mesh *mesh, float *mat, int shape_keys)
        DAG_id_tag_update(&mesh->id, 0);
 }
 
+static void rna_Mesh_flip_normals(Mesh *mesh)
+{
+       BKE_mesh_polygons_flip(mesh->mpoly, mesh->mloop, &mesh->ldata, mesh->totpoly);
+       BKE_mesh_tessface_clear(mesh);
+       BKE_mesh_calc_normals(mesh);
+
+       DAG_id_tag_update(&mesh->id, 0);
+}
+
 #else
 
 void RNA_api_mesh(StructRNA *srna)
@@ -209,11 +218,16 @@ void RNA_api_mesh(StructRNA *srna)
        const int normals_array_dim[] = {1, 3};
 
        func = RNA_def_function(srna, "transform", "rna_Mesh_transform");
-       RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix");
+       RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix "
+                                             "(Warning: inverts normals if matrix is negative)");
        parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
        RNA_def_property_flag(parm, PROP_REQUIRED);
        RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
 
+       func = RNA_def_function(srna, "flip_normals", "rna_Mesh_flip_normals");
+       RNA_def_function_ui_description(func, "Invert winding of all polygons "
+                                             "(clears tessellation, does not handle custom normals)");
+
        func = RNA_def_function(srna, "calc_normals", "BKE_mesh_calc_normals");
        RNA_def_function_ui_description(func, "Calculate vertex normals");