BKE_mesh: add polygon flipping tools.

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
This commit is contained in:
Bastien Montagne 2016-02-28 15:29:56 +01:00
parent ea76ec2866
commit 877f441628
6 changed files with 114 additions and 1 deletions

View 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
*/

View 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,

View 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;

View 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);
}
}
/* -------------------------------------------------------------------- */

View 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 */

View 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");