diff options
-rw-r--r-- | source/blender/blenkernel/BKE_customdata.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_mesh.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/customdata.c | 29 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_evaluate.c | 51 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_mesh.c | 14 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_mesh_api.c | 16 |
6 files changed, 114 insertions, 1 deletions
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 0b248be9780..17ad51a7a16 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -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 */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index f35613f8bf7..b85c605f231 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -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, diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index c120509b769..1ed7c989075 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -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; diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index e3b9b21f341..9fdd541813a 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -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); + } +} /* -------------------------------------------------------------------- */ diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 686f8331ac4..1d734864833 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -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 */ diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 1459157112e..a3bc21b0170 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -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"); |