diff options
Diffstat (limited to 'source/blender/blenkernel/intern/mesh.c')
-rw-r--r-- | source/blender/blenkernel/intern/mesh.c | 1090 |
1 files changed, 1029 insertions, 61 deletions
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index ec9d4873057..e106ebae63d 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -41,16 +41,19 @@ #include "DNA_key_types.h" #include "DNA_meshdata_types.h" #include "DNA_ipo_types.h" +#include "DNA_customdata_types.h" +#include "BLI_utildefines.h" #include "BLI_blenlib.h" #include "BLI_bpath.h" #include "BLI_editVert.h" #include "BLI_math.h" #include "BLI_edgehash.h" -#include "BLI_utildefines.h" +#include "BLI_scanfill.h" #include "BKE_animsys.h" #include "BKE_main.h" +#include "BKE_customdata.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" @@ -64,20 +67,316 @@ #include "BKE_curve.h" /* -- */ #include "BKE_object.h" +#include "BKE_tessmesh.h" +#include "BLI_edgehash.h" + +#include "BLI_blenlib.h" +#include "BLI_editVert.h" +#include "BLI_math.h" +#include "BLI_cellalloc.h" +#include "BLI_array.h" +#include "BLI_edgehash.h" +#include "bmesh.h" + +enum { + MESHCMP_DVERT_WEIGHTMISMATCH = 1, + MESHCMP_DVERT_GROUPMISMATCH, + MESHCMP_DVERT_TOTGROUPMISMATCH, + MESHCMP_LOOPCOLMISMATCH, + MESHCMP_LOOPUVMISMATCH, + MESHCMP_LOOPMISMATCH, + MESHCMP_POLYVERTMISMATCH, + MESHCMP_POLYMISMATCH, + MESHCMP_EDGEUNKNOWN, + MESHCMP_VERTCOMISMATCH, + MESHCMP_CDLAYERS_MISMATCH, +}; -EditMesh *BKE_mesh_get_editmesh(Mesh *me) +static const char *cmpcode_to_str(int code) { - return me->edit_mesh; + switch (code) { + case MESHCMP_DVERT_WEIGHTMISMATCH: + return "Vertex Weight Mismatch"; + case MESHCMP_DVERT_GROUPMISMATCH: + return "Vertex Group Mismatch"; + case MESHCMP_DVERT_TOTGROUPMISMATCH: + return "Vertex Doesn't Belong To Same Number Of Groups"; + case MESHCMP_LOOPCOLMISMATCH: + return "Vertex Color Mismatch"; + case MESHCMP_LOOPUVMISMATCH: + return "UV Mismatch"; + case MESHCMP_LOOPMISMATCH: + return "Loop Mismatch"; + case MESHCMP_POLYVERTMISMATCH: + return "Loop Vert Mismatch In Poly Test"; + case MESHCMP_POLYMISMATCH: + return "Loop Vert Mismatch"; + case MESHCMP_EDGEUNKNOWN: + return "Edge Mismatch"; + case MESHCMP_VERTCOMISMATCH: + return "Vertex Coordinate Mismatch"; + case MESHCMP_CDLAYERS_MISMATCH: + "CustomData Layer Count Mismatch"; + default: + return "Mesh Comparison Code Unknown"; + } } -void BKE_mesh_end_editmesh(Mesh *UNUSED(me), EditMesh *UNUSED(em)) +/*thresh is threshold for comparing vertices, uvs, vertex colors, + weights, etc.*/ +static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2, float thresh) { + CustomDataLayer *l1, *l2; + int i, i1=0, i2=0, tot, j; + + for (i=0; i<c1->totlayer; i++) { + if (ELEM7(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + i1++; + } + + for (i=0; i<c2->totlayer; i++) { + if (ELEM7(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + i2++; + } + + if (i1 != i2) + return MESHCMP_CDLAYERS_MISMATCH; + + l1 = c1->layers; l2 = c2->layers; + tot = i1; + i1 = 0; i2 = 0; + for (i=0; i < tot; i++) { + while (i1 < c1->totlayer && !ELEM7(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + i1++, l1++; + + while (i2 < c2->totlayer && !ELEM7(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + i2++, l2++; + + if (l1->type == CD_MVERT) { + MVert *v1 = l1->data; + MVert *v2 = l2->data; + int vtot = m1->totvert; + + for (j=0; j<vtot; j++, v1++, v2++) { + if (len_v3v3(v1->co, v2->co) > thresh) + return MESHCMP_VERTCOMISMATCH; + /*I don't care about normals, let's just do coodinates*/ + } + } + + /*we're order-agnostic for edges here*/ + if (l1->type == CD_MEDGE) { + MEdge *e1 = l1->data; + MEdge *e2 = l2->data; + EdgeHash *eh = BLI_edgehash_new(); + int etot = m1->totedge; + + for (j=0; j<etot; j++, e1++) { + BLI_edgehash_insert(eh, e1->v1, e1->v2, e1); + } + + for (j=0; j<etot; j++, e2++) { + if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2)) + return MESHCMP_EDGEUNKNOWN; + } + BLI_edgehash_free(eh, NULL); + } + + if (l1->type == CD_MPOLY) { + MPoly *p1 = l1->data; + MPoly *p2 = l2->data; + int ptot = m1->totpoly; + + for (j=0; j<ptot; j++, p1++, p2++) { + MLoop *lp1, *lp2; + int k; + + if (p1->totloop != p2->totloop) + return MESHCMP_POLYMISMATCH; + + lp1 = m1->mloop + p1->loopstart; + lp2 = m2->mloop + p2->loopstart; + + for (k=0; k<p1->totloop; k++, lp1++, lp2++) { + if (lp1->v != lp2->v) + return MESHCMP_POLYVERTMISMATCH; + } + } + } + if (l1->type == CD_MLOOP) { + MLoop *lp1 = l1->data; + MLoop *lp2 = l2->data; + int ltot = m1->totloop; + + for (j=0; j<ltot; j++, lp1++, lp2++) { + if (lp1->v != lp2->v) + return MESHCMP_LOOPMISMATCH; + } + } + if (l1->type == CD_MLOOPUV) { + MLoopUV *lp1 = l1->data; + MLoopUV *lp2 = l2->data; + int ltot = m1->totloop; + + for (j=0; j<ltot; j++, lp1++, lp2++) { + if (len_v2v2(lp1->uv, lp2->uv) > thresh) + return MESHCMP_LOOPUVMISMATCH; + } + } + + if (l1->type == CD_MLOOPCOL) { + MLoopCol *lp1 = l1->data; + MLoopCol *lp2 = l2->data; + int ltot = m1->totloop; + + for (j=0; j<ltot; j++, lp1++, lp2++) { + if (ABS(lp1->r - lp2->r) > thresh || + ABS(lp1->g - lp2->g) > thresh || + ABS(lp1->b - lp2->b) > thresh || + ABS(lp1->a - lp2->a) > thresh) + { + return MESHCMP_LOOPCOLMISMATCH; + } + } + } + + if (l1->type == CD_MDEFORMVERT) { + MDeformVert *dv1 = l1->data; + MDeformVert *dv2 = l2->data; + int dvtot = m1->totvert; + + for (j=0; j<dvtot; j++, dv1++, dv2++) { + int k; + MDeformWeight *dw1 = dv1->dw, *dw2=dv2->dw; + + if (dv1->totweight != dv2->totweight) + return MESHCMP_DVERT_TOTGROUPMISMATCH; + + for (k=0; k<dv1->totweight; k++, dw1++, dw2++) { + if (dw1->def_nr != dw2->def_nr) + return MESHCMP_DVERT_GROUPMISMATCH; + if (ABS(dw1->weight - dw2->weight) > thresh) + return MESHCMP_DVERT_WEIGHTMISMATCH; + } + } + } + } + + return 0; +} + +/*used for testing. returns an error string the two meshes don't match*/ +const char *mesh_cmp(Mesh *me1, Mesh *me2, float thresh) +{ + int c; + + if (!me1 || !me2) + return "Requires two input meshes"; + + if (me1->totvert != me2->totvert) + return "Number of verts don't match"; + + if (me1->totedge != me2->totedge) + return "Number of edges don't match"; + + if (me1->totpoly != me2->totpoly) + return "Number of faces don't match"; + + if (me1->totloop !=me2->totloop) + return "Number of loops don't match"; + + if ((c = customdata_compare(&me1->vdata, &me2->vdata, me1, me2, thresh))) + return cmpcode_to_str(c); + + if ((c = customdata_compare(&me1->edata, &me2->edata, me1, me2, thresh))) + return cmpcode_to_str(c); + + if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1, me2, thresh))) + return cmpcode_to_str(c); + + if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1, me2, thresh))) + return cmpcode_to_str(c); + + return NULL; } +static void mesh_ensure_tesselation_customdata(Mesh *me) +{ + int tottex, totcol; + + tottex = CustomData_number_of_layers(&me->fdata, CD_MTFACE); + totcol = CustomData_number_of_layers(&me->fdata, CD_MCOL); + + if (tottex != CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY) || + totcol != CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL)) + { + CustomData_free(&me->fdata, me->totface); + + me->mface = NULL; + me->mtface = NULL; + me->mcol = NULL; + me->totface = 0; + + memset(&me->fdata, 0, sizeof(&me->fdata)); + + CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface); + printf("Warning! Tesselation uvs or vcol data got out of sync, had to reset!\n"); + } +} + +/*this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or + mloopcol and mcol) have the same relative active/render/clone/mask indices.*/ +static void mesh_update_linked_customdata(Mesh *me) +{ + int act; + + if (me->edit_btmesh) + BMEdit_UpdateLinkedCustomData(me->edit_btmesh); + + mesh_ensure_tesselation_customdata(me); + + if (CustomData_has_layer(&me->pdata, CD_MTEXPOLY)) { + act = CustomData_get_active_layer(&me->pdata, CD_MTEXPOLY); + CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, act); + CustomData_set_layer_active(&me->fdata, CD_MTFACE, act); + + act = CustomData_get_render_layer(&me->pdata, CD_MTEXPOLY); + CustomData_set_layer_render(&me->ldata, CD_MLOOPUV, act); + CustomData_set_layer_render(&me->fdata, CD_MTFACE, act); + + act = CustomData_get_clone_layer(&me->pdata, CD_MTEXPOLY); + CustomData_set_layer_clone(&me->ldata, CD_MLOOPUV, act); + CustomData_set_layer_clone(&me->fdata, CD_MTFACE, act); + + act = CustomData_get_stencil_layer(&me->pdata, CD_MTEXPOLY); + CustomData_set_layer_stencil(&me->ldata, CD_MLOOPUV, act); + CustomData_set_layer_stencil(&me->fdata, CD_MTFACE, act); + } + + if (CustomData_has_layer(&me->ldata, CD_MLOOPCOL)) { + act = CustomData_get_active_layer(&me->ldata, CD_MLOOPCOL); + CustomData_set_layer_active(&me->fdata, CD_MCOL, act); + + act = CustomData_get_render_layer(&me->ldata, CD_MLOOPCOL); + CustomData_set_layer_render(&me->fdata, CD_MCOL, act); + + act = CustomData_get_clone_layer(&me->ldata, CD_MLOOPCOL); + CustomData_set_layer_clone(&me->fdata, CD_MCOL, act); + + act = CustomData_get_stencil_layer(&me->ldata, CD_MLOOPCOL); + CustomData_set_layer_stencil(&me->fdata, CD_MCOL, act); + } +} void mesh_update_customdata_pointers(Mesh *me) { + mesh_update_linked_customdata(me); + me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); me->msticky = CustomData_get_layer(&me->vdata, CD_MSTICKY); @@ -87,6 +386,13 @@ void mesh_update_customdata_pointers(Mesh *me) me->mface = CustomData_get_layer(&me->fdata, CD_MFACE); me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL); me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); + + me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); + me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); + + me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY); + me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); + me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); } /* Note: unlinking is called when me->id.us is 0, question remains how @@ -117,9 +423,10 @@ void unlink_mesh(Mesh *me) /* do not free mesh itself */ -void free_mesh(Mesh *me) +void free_mesh(Mesh *me, int unlink) { - unlink_mesh(me); + if (unlink) + unlink_mesh(me); if(me->pv) { if(me->pv->vert_map) MEM_freeN(me->pv->vert_map); @@ -135,7 +442,9 @@ void free_mesh(Mesh *me) CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); - + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); + if(me->adt) { BKE_free_animdata(&me->id); me->adt= NULL; @@ -145,7 +454,7 @@ void free_mesh(Mesh *me) if(me->bb) MEM_freeN(me->bb); if(me->mselect) MEM_freeN(me->mselect); - if(me->edit_mesh) MEM_freeN(me->edit_mesh); + if(me->edit_btmesh) MEM_freeN(me->edit_btmesh); } void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount) @@ -160,7 +469,7 @@ void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount) for (i=0; i<copycount; i++){ if (src[i].dw){ - dst[i].dw = MEM_callocN (sizeof(MDeformWeight)*src[i].totweight, "copy_deformWeight"); + dst[i].dw = BLI_cellalloc_calloc (sizeof(MDeformWeight)*src[i].totweight, "copy_deformWeight"); memcpy (dst[i].dw, src[i].dw, sizeof (MDeformWeight)*src[i].totweight); } } @@ -179,7 +488,7 @@ void free_dverts(MDeformVert *dvert, int totvert) /* Free any special data from the verts */ for (i=0; i<totvert; i++){ - if (dvert[i].dw) MEM_freeN (dvert[i].dw); + if (dvert[i].dw) BLI_cellalloc_free (dvert[i].dw); } MEM_freeN (dvert); } @@ -204,6 +513,7 @@ Mesh *copy_mesh(Mesh *me) { Mesh *men; MTFace *tface; + MTexPoly *txface; int a, i; men= copy_libblock(&me->id); @@ -217,6 +527,8 @@ Mesh *copy_mesh(Mesh *me) CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert); CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge); CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface); + CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop); + CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly); mesh_update_customdata_pointers(men); /* ensure indirect linked data becomes lib-extern */ @@ -230,8 +542,18 @@ Mesh *copy_mesh(Mesh *me) } } + for(i=0; i<me->pdata.totlayer; i++) { + if(me->pdata.layers[i].type == CD_MTEXPOLY) { + txface= (MTexPoly*)me->pdata.layers[i].data; + + for(a=0; a<me->totpoly; a++, txface++) + if(txface->tpage) + id_lib_extern((ID*)txface->tpage); + } + } + men->mselect= NULL; - men->edit_mesh= NULL; + men->edit_btmesh= NULL; men->pv= NULL; /* looks like this is no-longer supported but NULL just incase */ men->bb= MEM_dupallocN(men->bb); @@ -242,21 +564,50 @@ Mesh *copy_mesh(Mesh *me) return men; } +BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob) +{ + BMesh *bm; + int allocsize[4] = {512,512,2048,512}; + + bm = BM_Make_Mesh(ob, allocsize); + + BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", me, ob, 1); + + return bm; +} + static void expand_local_mesh(Mesh *me) { id_lib_extern((ID *)me->texcomesh); if(me->mtface) { - MTFace *tface; int a, i; + for(i=0; i<me->pdata.totlayer; i++) { + if(me->pdata.layers[i].type == CD_MTEXPOLY) { + MTexPoly *txface= (MTexPoly*)me->fdata.layers[i].data; + + for(a=0; a<me->totpoly; a++, txface++) { + /* special case: ima always local immediately */ + if(txface->tpage) { + if(txface->tpage) { + id_lib_extern((ID *)txface->tpage); + } + } + } + } + } + for(i=0; i<me->fdata.totlayer; i++) { if(me->fdata.layers[i].type == CD_MTFACE) { - tface= (MTFace*)me->fdata.layers[i].data; + MTFace *tface= (MTFace*)me->fdata.layers[i].data; for(a=0; a<me->totface; a++, tface++) { + /* special case: ima always local immediately */ if(tface->tpage) { - id_lib_extern((ID *)tface->tpage); + if(tface->tpage) { + id_lib_extern((ID *)tface->tpage); + } } } } @@ -272,7 +623,7 @@ void make_local_mesh(Mesh *me) { Main *bmain= G.main; Object *ob; - int is_local= FALSE, is_lib= FALSE; + int local=0, lib=0; /* - only lib users: do nothing * - only local users: set flag @@ -281,28 +632,32 @@ void make_local_mesh(Mesh *me) if(me->id.lib==NULL) return; if(me->id.us==1) { - id_clear_lib_data(bmain, &me->id); + me->id.lib= NULL; + me->id.flag= LIB_LOCAL; + + new_id(&bmain->mesh, (ID *)me, NULL); expand_local_mesh(me); return; } - for(ob= bmain->object.first; ob && ELEM(0, is_lib, is_local); ob= ob->id.next) { + for(ob= bmain->object.first; ob && ELEM(0, lib, local); ob= ob->id.next) { if(me == ob->data) { - if(ob->id.lib) is_lib= TRUE; - else is_local= TRUE; + if(ob->id.lib) lib= 1; + else local= 1; } } - if(is_local && is_lib == FALSE) { - id_clear_lib_data(bmain, &me->id); + if(local && lib==0) { + me->id.lib= NULL; + me->id.flag= LIB_LOCAL; + + new_id(&bmain->mesh, (ID *)me, NULL); expand_local_mesh(me); } - else if(is_local && is_lib) { + else if(local && lib) { Mesh *men= copy_mesh(me); men->id.us= 0; - - /* Remap paths of new ID using old library as base. */ BKE_id_lib_local_paths(bmain, &men->id); for(ob= bmain->object.first; ob; ob= ob->id.next) { @@ -581,13 +936,17 @@ static void mfaces_strip_loose(MFace *mface, int *totface) } /* Create edges based on known verts and faces */ -static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, int UNUSED(totvert), int totface, +static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *allloop, + MPoly *allpoly, int UNUSED(totvert), int totface, int UNUSED(totloop), int totpoly, int old, MEdge **alledge, int *_totedge) { + MPoly *mpoly; + MLoop *mloop; MFace *mface; MEdge *medge; + EdgeHash *hash = BLI_edgehash_new(); struct edgesort *edsort, *ed; - int a, totedge=0, final=0; + int a, b, totedge=0, final=0; /* we put all edges in array, sort them, and detect doubles that way */ @@ -659,6 +1018,26 @@ static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, int UNUSED( medge->flag |= ME_EDGERENDER; MEM_freeN(edsort); + + /*set edge members of mloops*/ + medge= *alledge; + for (a=0; a<*_totedge; a++, medge++) { + BLI_edgehash_insert(hash, medge->v1, medge->v2, SET_INT_IN_POINTER(a)); + } + + mpoly = allpoly; + for (a=0; a<totpoly; a++, mpoly++) { + mloop = allloop + mpoly->loopstart; + for (b=0; b<mpoly->totloop; b++) { + int v1, v2; + + v1 = mloop[b].v; + v2 = mloop[(b+1)%mpoly->totloop].v; + mloop[b].e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(hash, v1, v2)); + } + } + + BLI_edgehash_free(hash, NULL); } void make_edges(Mesh *me, int old) @@ -666,7 +1045,7 @@ void make_edges(Mesh *me, int old) MEdge *medge; int totedge=0; - make_edges_mdata(me->mvert, me->mface, me->totvert, me->totface, old, &medge, &totedge); + make_edges_mdata(me->mvert, me->mface, me->mloop, me->mpoly, me->totvert, me->totface, me->totloop, me->totpoly, old, &medge, &totedge); if(totedge==0) { /* flag that mesh has edges */ me->medge = medge; @@ -762,31 +1141,43 @@ void mball_to_mesh(ListBase *lb, Mesh *me) } make_edges(me, 0); // all edges - } + convert_mfaces_to_mpolys(me); + + me->totface = mesh_recalcTesselation( + &me->fdata, &me->ldata, &me->pdata, + me->mvert, me->totface, me->totloop, me->totpoly); + + mesh_update_customdata_pointers(me); + } } /* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */ /* return non-zero on error */ int nurbs_to_mdata(Object *ob, MVert **allvert, int *totvert, - MEdge **alledge, int *totedge, MFace **allface, int *totface) + MEdge **alledge, int *totedge, MFace **allface, MLoop **allloop, MPoly **allpoly, + int *totface, int *totloop, int *totpoly) { return nurbs_to_mdata_customdb(ob, &ob->disp, - allvert, totvert, alledge, totedge, allface, totface); + allvert, totvert, alledge, totedge, allface, allloop, allpoly, totface, totloop, totpoly); } /* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */ /* use specified dispbase */ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int *_totvert, - MEdge **alledge, int *_totedge, MFace **allface, int *_totface) + MEdge **alledge, int *_totedge, MFace **allface, MLoop **allloop, MPoly **allpoly, + int *_totface, int *_totloop, int *_totpoly) { DispList *dl; Curve *cu; MVert *mvert; MFace *mface; + MPoly *mpoly; + MLoop *mloop; float *data; int a, b, ofs, vertcount, startvert, totvert=0, totvlak=0; int p1, p2, p3, p4, *index; int conv_polys= 0; + int i, j; cu= ob->data; @@ -825,7 +1216,9 @@ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int *allvert= mvert= MEM_callocN(sizeof (MVert) * totvert, "nurbs_init mvert"); *allface= mface= MEM_callocN(sizeof (MFace) * totvlak, "nurbs_init mface"); - + *allloop = mloop = MEM_callocN(sizeof(MLoop) * totvlak * 4, "nurbs_init mloop"); + *allpoly = mpoly = MEM_callocN(sizeof(MPoly) * totvlak * 4, "nurbs_init mloop"); + /* verts and faces */ vertcount= 0; @@ -963,11 +1356,35 @@ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int dl= dl->next; } - + + mface= *allface; + j = 0; + for (i=0; i<totvert; i++, mpoly++, mface++) { + int k; + + if (!mface->v3) { + mpoly--; + i--; + continue; + } + + if (mface >= *allface + totvlak) + break; + + mpoly->flag |= mface->flag & ME_SMOOTH; + mpoly->loopstart= j; + mpoly->totloop= mface->v4 ? 4 : 3; + for (k=0; k<mpoly->totloop; k++, mloop++, j++) { + mloop->v = (&mface->v1)[k]; + } + } + + *_totpoly= i; + *_totloop= j; *_totvert= totvert; *_totface= totvlak; - make_edges_mdata(*allvert, *allface, totvert, totvlak, 0, alledge, _totedge); + make_edges_mdata(*allvert, *allface, *allloop, *allpoly, totvert, totvlak, *_totloop, *_totpoly, 0, alledge, _totedge); mfaces_strip_loose(*allface, _totface); return 0; @@ -984,12 +1401,14 @@ void nurbs_to_mesh(Object *ob) MVert *allvert= NULL; MEdge *alledge= NULL; MFace *allface= NULL; - int totvert, totedge, totface; + MLoop *allloop = NULL; + MPoly *allpoly = NULL; + int totvert, totedge, totface, totloop, totpoly; cu= ob->data; if (dm == NULL) { - if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allface, &totface) != 0) { + if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allface, &allloop, &allpoly, &totface, &totloop, &totpoly) != 0) { /* Error initializing */ return; } @@ -999,15 +1418,19 @@ void nurbs_to_mesh(Object *ob) me->totvert= totvert; me->totface= totface; me->totedge= totedge; + me->totloop = totloop; + me->totpoly = totpoly; me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert); - me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, allface, me->totface); me->medge= CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge); + me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, allface, me->totface); + me->mloop= CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop); + me->mpoly= CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly); - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } else { me= add_mesh("Mesh"); - DM_to_mesh(dm, me); + DM_to_mesh(dm, me, ob); } me->totcol= cu->totcol; @@ -1068,10 +1491,10 @@ void mesh_to_curve(Scene *scene, Object *ob) MVert *mverts= dm->getVertArray(dm); MEdge *med, *medge= dm->getEdgeArray(dm); - MFace *mf, *mface= dm->getFaceArray(dm); + MFace *mf, *mface= dm->getTessFaceArray(dm); int totedge = dm->getNumEdges(dm); - int totface = dm->getNumFaces(dm); + int totface = dm->getNumTessFaces(dm); int totedges = 0; int i, needsFree = 0; @@ -1234,10 +1657,16 @@ void mesh_to_curve(Scene *scene, Object *ob) void mesh_delete_material_index(Mesh *me, short index) { - MFace *mf; int i; - for (i=0, mf=me->mface; i<me->totface; i++, mf++) { + for (i=0; i<me->totpoly; i++) { + MPoly *mp = &((MPoly*) me->mpoly)[i]; + if (mp->mat_nr && mp->mat_nr>=index) + mp->mat_nr--; + } + + for (i=0; i<me->totface; i++) { + MFace *mf = &((MFace*) me->mface)[i]; if (mf->mat_nr && mf->mat_nr>=index) mf->mat_nr--; } @@ -1248,6 +1677,16 @@ void mesh_set_smooth_flag(Object *meshOb, int enableSmooth) Mesh *me = meshOb->data; int i; + for (i=0; i<me->totpoly; i++) { + MPoly *mp = &((MPoly*) me->mpoly)[i]; + + if (enableSmooth) { + mp->flag |= ME_SMOOTH; + } else { + mp->flag &= ~ME_SMOOTH; + } + } + for (i=0; i<me->totface; i++) { MFace *mf = &((MFace*) me->mface)[i]; @@ -1258,10 +1697,98 @@ void mesh_set_smooth_flag(Object *meshOb, int enableSmooth) } } - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, + me->totpoly, NULL, NULL, 0, NULL, NULL); } -void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3]) +void mesh_calc_normals(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpolys, + int UNUSED(numLoops), int numPolys, float (*polyNors_r)[3], MFace *mfaces, int numFaces, + int *origIndexFace, float (*faceNors_r)[3]) +{ + float (*pnors)[3] = polyNors_r, (*fnors)[3] = faceNors_r; + float (*tnorms)[3], (*edgevecbuf)[3]; + float **vertcos = NULL, **vertnos = NULL; + BLI_array_declare(vertcos); + BLI_array_declare(vertnos); + int i, j, maxPolyVerts = 0; + MFace *mf; + MPoly *mp; + MLoop *ml; + + if (numPolys == 0) { + return; + } + + mp = mpolys; + for (i=0; i<numPolys; i++, mp++) { + maxPolyVerts = MAX2(mp->totloop, maxPolyVerts); + } + + if (maxPolyVerts == 0) { + return; + } + + /*first go through and calculate normals for all the polys*/ + edgevecbuf = MEM_callocN(sizeof(float)*3*maxPolyVerts, "edgevecbuf mesh.c"); + tnorms = MEM_callocN(sizeof(float)*3*numVerts, "tnorms mesh.c"); + if (!pnors) + pnors = MEM_callocN(sizeof(float)*3*numPolys, "poly_nors mesh.c"); + if (!fnors) + fnors = MEM_callocN(sizeof(float)*3*numFaces, "face nors mesh.c"); + + mp = mpolys; + for (i=0; i<numPolys; i++, mp++) { + mesh_calc_poly_normal(mp, mloop+mp->loopstart, mverts, pnors[i]); + ml = mloop + mp->loopstart; + + BLI_array_empty(vertcos); + BLI_array_empty(vertnos); + for (j=0; j<mp->totloop; j++) { + int vindex = ml[j].v; + BLI_array_append(vertcos, mverts[vindex].co); + BLI_array_append(vertnos, tnorms[vindex]); + } + + accumulate_vertex_normals_poly(vertnos, pnors[i], vertcos, edgevecbuf, mp->totloop); + } + + /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + for(i=0; i<numVerts; i++) { + MVert *mv= &mverts[i]; + float *no= tnorms[i]; + + if(normalize_v3(no) == 0.0f) + normalize_v3_v3(no, mv->co); + + normal_float_to_short_v3(mv->no, no); + } + + if (origIndexFace && fnors==faceNors_r && numFaces) { + mf = mfaces; + for (i=0; i<numFaces; i++, mf++, origIndexFace++) { + if (*origIndexFace < numPolys) { + VECCOPY(fnors[i], pnors[*origIndexFace]); + } else { + /*eek, we're not corrusponding to polys*/ + printf("error in mesh_calc_normals; tesselation face indices are incorrect. normals may look bad.\n"); + } + } + } + + BLI_array_free(vertcos); + BLI_array_free(vertnos); + MEM_freeN(edgevecbuf); + MEM_freeN(tnorms); + if (fnors != faceNors_r) + MEM_freeN(fnors); + if (pnors != polyNors_r) + MEM_freeN(pnors); + + fnors = pnors = NULL; + +} + +void mesh_calc_tessface_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3]) { float (*tnorms)[3]= MEM_callocN(numVerts*sizeof(*tnorms), "tnorms"); float (*fnors)[3]= (faceNors_r)? faceNors_r: MEM_callocN(sizeof(*fnors)*numFaces, "meshnormals"); @@ -1299,6 +1826,159 @@ void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, MEM_freeN(fnors); } + +static void bmesh_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, int numCol) +{ + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + MFace *mf; + int i; + + mf = me->mface + findex; + + for(i=0; i < numTex; i++){ + texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i); + texpoly = CustomData_get_n(&me->pdata, CD_MTEXPOLY, findex, i); + + texpoly->tpage = texface->tpage; + texpoly->flag = texface->flag; + texpoly->transp = texface->transp; + texpoly->mode = texface->mode; + texpoly->tile = texface->tile; + texpoly->unwrap = texface->unwrap; + + mloopuv = CustomData_get_n(&me->ldata, CD_MLOOPUV, loopstart, i); + mloopuv->uv[0] = texface->uv[0][0]; mloopuv->uv[1] = texface->uv[0][1]; mloopuv++; + mloopuv->uv[0] = texface->uv[1][0]; mloopuv->uv[1] = texface->uv[1][1]; mloopuv++; + mloopuv->uv[0] = texface->uv[2][0]; mloopuv->uv[1] = texface->uv[2][1]; mloopuv++; + + if (mf->v4) { + mloopuv->uv[0] = texface->uv[3][0]; mloopuv->uv[1] = texface->uv[3][1]; mloopuv++; + } + } + + for(i=0; i < numCol; i++){ + mloopcol = CustomData_get_n(&me->ldata, CD_MLOOPCOL, loopstart, i); + mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i); + + mloopcol->r = mcol[0].r; mloopcol->g = mcol[0].g; mloopcol->b = mcol[0].b; mloopcol->a = mcol[0].a; mloopcol++; + mloopcol->r = mcol[1].r; mloopcol->g = mcol[1].g; mloopcol->b = mcol[1].b; mloopcol->a = mcol[1].a; mloopcol++; + mloopcol->r = mcol[2].r; mloopcol->g = mcol[2].g; mloopcol->b = mcol[2].b; mloopcol->a = mcol[2].a; mloopcol++; + if (mf->v4) { + mloopcol->r = mcol[3].r; mloopcol->g = mcol[3].g; mloopcol->b = mcol[3].b; mloopcol->a = mcol[3].a; mloopcol++; + } + } + + if (CustomData_has_layer(&me->fdata, CD_MDISPS)) { + MDisps *ld = CustomData_get(&me->ldata, loopstart, CD_MDISPS); + MDisps *fd = CustomData_get(&me->fdata, findex, CD_MDISPS); + float (*disps)[3] = fd->disps; + int i, tot = mf->v4 ? 4 : 3; + int side, corners; + + corners = multires_mdisp_corners(fd); + + if (corners == 0) { + /* Empty MDisp layers appear in at least one of the sintel.blend files. + Not sure why this happens, but it seems fine to just ignore them here. + If corners==0 for a non-empty layer though, something went wrong. */ + BLI_assert(fd->totdisp == 0); + } + else { + side = sqrt(fd->totdisp / corners); + + for (i=0; i<tot; i++, disps += side*side, ld++) { + ld->totdisp = side*side; + + if (ld->disps) + BLI_cellalloc_free(ld->disps); + + ld->disps = BLI_cellalloc_calloc(sizeof(float)*3*side*side, "converted loop mdisps"); + if (fd->disps) { + memcpy(ld->disps, disps, sizeof(float)*3*side*side); + } + } + } + } +} + +void convert_mfaces_to_mpolys(Mesh *mesh) +{ + MFace *mf; + MLoop *ml; + MPoly *mp; + MEdge *me; + EdgeHash *eh; + int numTex, numCol; + int i, j, totloop; + + mesh->totpoly = mesh->totface; + mesh->mpoly = MEM_callocN(sizeof(MPoly)*mesh->totpoly, "mpoly converted"); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_ASSIGN, mesh->mpoly, mesh->totpoly); + + numTex = CustomData_number_of_layers(&mesh->fdata, CD_MTFACE); + numCol = CustomData_number_of_layers(&mesh->fdata, CD_MCOL); + + totloop = 0; + mf = mesh->mface; + for (i=0; i<mesh->totface; i++, mf++) { + totloop += mf->v4 ? 4 : 3; + } + + mesh->totloop = totloop; + mesh->mloop = MEM_callocN(sizeof(MLoop)*mesh->totloop, "mloop converted"); + + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_ASSIGN, mesh->mloop, totloop); + CustomData_to_bmeshpoly(&mesh->fdata, &mesh->pdata, &mesh->ldata, + mesh->totloop, mesh->totpoly); + + eh = BLI_edgehash_new(); + + /*build edge hash*/ + me = mesh->medge; + for (i=0; i<mesh->totedge; i++, me++) { + BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i)); + } + + j = 0; /*current loop index*/ + ml = mesh->mloop; + mf = mesh->mface; + mp = mesh->mpoly; + for (i=0; i<mesh->totface; i++, mf++, mp++) { + mp->loopstart = j; + + mp->totloop = mf->v4 ? 4 : 3; + + mp->mat_nr = mf->mat_nr; + mp->flag = mf->flag; + + #define ML(v1, v2) {ml->v = mf->v1; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); ml++; j++;} + + ML(v1, v2); + ML(v2, v3); + if (mf->v4) { + ML(v3, v4); + ML(v4, v1); + } else { + ML(v3, v1); + } + + #undef ML + + bmesh_corners_to_loops(mesh, i, mp->loopstart, numTex, numCol); + } + + /* note, we dont convert FGons at all, these are not even real ngons, + * they have their own UV's, colors etc - its more an editing feature. */ + + mesh_update_customdata_pointers(mesh); + + BLI_edgehash_free(eh, NULL); +} + float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3] { int i, numVerts = me->totvert; @@ -1306,27 +1986,32 @@ float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3] if (numVerts_r) *numVerts_r = numVerts; for (i=0; i<numVerts; i++) - VECCOPY(cos[i], me->mvert[i].co); + copy_v3_v3(cos[i], me->mvert[i].co); return cos; } -UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit) + +/* ngon version wip, based on EDBM_make_uv_vert_map */ +/* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could + * but for now this replaces it because its unused. */ + +UvVertMap *make_uv_vert_map(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, unsigned int totpoly, unsigned int totvert, int selected, float *limit) { UvVertMap *vmap; UvMapVert *buf; - MFace *mf; + MPoly *mp; unsigned int a; int i, totuv, nverts; totuv = 0; /* generate UvMapVert array */ - mf= mface; - for(a=0; a<totface; a++, mf++) - if(!selected || (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))) - totuv += (mf->v4)? 4: 3; - + mp= mpoly; + for(a=0; a<totpoly; a++, mp++) + if(!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) + totuv += mp->totloop; + if(totuv==0) return NULL; @@ -1342,17 +2027,17 @@ UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned return NULL; } - mf= mface; - for(a=0; a<totface; a++, mf++) { - if(!selected || (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))) { - nverts= (mf->v4)? 4: 3; + mp= mpoly; + for(a=0; a<totpoly; a++, mp++) { + if(!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) { + nverts= mp->totloop; for(i=0; i<nverts; i++) { buf->tfindex= i; buf->f= a; buf->separate = 0; - buf->next= vmap->vert[*(&mf->v1 + i)]; - vmap->vert[*(&mf->v1 + i)]= buf; + buf->next= vmap->vert[mloop[mp->loopstart + i].v]; + vmap->vert[mloop[mp->loopstart + i].v]= buf; buf++; } } @@ -1370,14 +2055,14 @@ UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned v->next= newvlist; newvlist= v; - uv= tface[v->f].uv[v->tfindex]; + uv= mloopuv[mpoly[v->f].loopstart + v->tfindex].uv; lastv= NULL; iterv= vlist; while(iterv) { next= iterv->next; - uv2= tface[iterv->f].uv[iterv->tfindex]; + uv2= mloopuv[mpoly[iterv->f].loopstart + iterv->tfindex].uv; sub_v2_v2v2(uvdiff, uv2, uv); @@ -1524,6 +2209,289 @@ void mesh_pmv_off(Mesh *me) } } +void mesh_loops_to_tri_corners(CustomData *fdata, CustomData *ldata, + CustomData *pdata, int lindex[3], int findex, + int polyindex) +{ + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + int i, j, hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL); + int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + + for(i=0; i < numTex; i++){ + texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); + texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i); + + texface->tpage = texpoly->tpage; + texface->flag = texpoly->flag; + texface->transp = texpoly->transp; + texface->mode = texpoly->mode; + texface->tile = texpoly->tile; + texface->unwrap = texpoly->unwrap; + + for (j=0; j<3; j++) { + mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, lindex[j], i); + texface->uv[j][0] = mloopuv->uv[0]; + texface->uv[j][1] = mloopuv->uv[1]; + } + } + + for(i=0; i < numCol; i++){ + mcol = CustomData_get_n(fdata, CD_MCOL, findex, i); + + for (j=0; j<3; j++) { + mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, lindex[j], i); + mcol[j].r = mloopcol->r; + mcol[j].g = mloopcol->g; + mcol[j].b = mloopcol->b; + mcol[j].a = mloopcol->a; + } + } + + if (hasWCol) { + mcol = CustomData_get(fdata, findex, CD_WEIGHT_MCOL); + + for (j=0; j<3; j++) { + mloopcol = CustomData_get(ldata, lindex[j], CD_WEIGHT_MLOOPCOL); + mcol[j].r = mloopcol->r; + mcol[j].g = mloopcol->g; + mcol[j].b = mloopcol->b; + mcol[j].a = mloopcol->a; + } + } +} + +/* + this function recreates a tesselation. + returns number of tesselation faces. + */ +int mesh_recalcTesselation(CustomData *fdata, + CustomData *ldata, CustomData *pdata, + MVert *mvert, int totface, int UNUSED(totloop), + int totpoly) +{ + MPoly *mp, *mpoly; + MLoop *ml, *mloop; + MFace *mf = NULL, *mface; + BLI_array_declare(mf); + EditVert *v, *lastv, *firstv; + EditFace *f; + int *origIndex = NULL; + BLI_array_declare(origIndex); + int *polyIndex = NULL; + BLI_array_declare(polyIndex); + int i, j, k, lindex[4], *polyorigIndex; + int numTex, numCol; + + mpoly = CustomData_get_layer(pdata, CD_MPOLY); + mloop = CustomData_get_layer(ldata, CD_MLOOP); + + numTex = CustomData_number_of_layers(ldata, CD_MLOOPUV); + numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + + k = 0; + mp = mpoly; + polyorigIndex = CustomData_get_layer(pdata, CD_ORIGINDEX); + for (i=0; i<totpoly; i++, mp++) { + if (mp->totloop > 2) { + ml = mloop + mp->loopstart; + + BLI_begin_edgefill(); + firstv = NULL; + lastv = NULL; + for (j=0; j<mp->totloop; j++, ml++) { + v = BLI_addfillvert(mvert[ml->v].co); + + v->keyindex = mp->loopstart + j; + + if (lastv) + BLI_addfilledge(lastv, v); + + if (!firstv) + firstv = v; + lastv = v; + } + BLI_addfilledge(lastv, firstv); + + BLI_edgefill(2); + for (f=fillfacebase.first; f; f=f->next) { + BLI_array_growone(mf); + BLI_array_append(polyIndex, i); + + /*these are loop indices, they'll be transformed + into vert indices later.*/ + mf[k].v1 = f->v1->keyindex; + mf[k].v2 = f->v2->keyindex; + mf[k].v3 = f->v3->keyindex; + mf[k].v4 = 0; + + mf[k].mat_nr = mp->mat_nr; + mf[k].flag = mp->flag; + + if (polyorigIndex) { + BLI_array_append(origIndex, polyorigIndex[polyIndex[k]]); + } + + k++; + } + + BLI_end_edgefill(); + } + } + + CustomData_free(fdata, totface); + memset(fdata, 0, sizeof(CustomData)); + totface = k; + + CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mf, totface); + CustomData_add_layer(fdata, CD_POLYINDEX, CD_ASSIGN, polyIndex, totface); + if (origIndex) { + CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, origIndex, totface); + } + + CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); + + /* If polys have a normals layer, copying that to faces can help + avoid the need to recalculate normals later */ + if (CustomData_has_layer(pdata, CD_NORMAL)) { + float *pnors = CustomData_get_layer(pdata, CD_NORMAL); + float *fnors = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface); + for (i=0; i<totface; i++, fnors++) { + copy_v3_v3(fnors, &pnors[polyIndex[i]]); + } + } + + mface = mf; + for (i=0; i<totface; i++, mf++) { + /*sort loop indices to ensure winding is correct*/ + if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2); + if (mf->v2 > mf->v3) SWAP(int, mf->v2, mf->v3); + if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2); + + if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2); + if (mf->v2 > mf->v3) SWAP(int, mf->v2, mf->v3); + if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2); + + lindex[0] = mf->v1; + lindex[1] = mf->v2; + lindex[2] = mf->v3; + + /*transform loop indices to vert indices*/ + mf->v1 = mloop[mf->v1].v; + mf->v2 = mloop[mf->v2].v; + mf->v3 = mloop[mf->v3].v; + + mesh_loops_to_tri_corners(fdata, ldata, pdata, + lindex, i, polyIndex[i]); + } + + return totface; +} + +/* + * COMPUTE POLY NORMAL + * + * Computes the normal of a planar + * polygon See Graphics Gems for + * computing newell normal. + * +*/ +static void mesh_calc_ngon_normal(MPoly *mpoly, MLoop *loopstart, + MVert *mvert, float *normal) +{ + + MVert *v1, *v2, *v3; + double u[3], v[3], w[3]; + double n[3] = {0.0, 0.0, 0.0}, l; + int i; + + for(i = 0; i < mpoly->totloop; i++){ + v1 = mvert + loopstart[i].v; + v2 = mvert + loopstart[(i+1)%mpoly->totloop].v; + v3 = mvert + loopstart[(i+2)%mpoly->totloop].v; + + VECCOPY(u, v1->co); + VECCOPY(v, v2->co); + VECCOPY(w, v3->co); + + /*this fixes some weird numerical error*/ + if (i==0) { + u[0] += 0.0001f; + u[1] += 0.0001f; + u[2] += 0.0001f; + } + + /* newell's method + + so thats?: + (a[1] - b[1]) * (a[2] + b[2]); + a[1]*b[2] - b[1]*a[2] - b[1]*b[2] + a[1]*a[2] + + odd. half of that is the cross product. . .what's the + other half? + + also could be like a[1]*(b[2] + a[2]) - b[1]*(a[2] - b[2]) + */ + + n[0] += (u[1] - v[1]) * (u[2] + v[2]); + n[1] += (u[2] - v[2]) * (u[0] + v[0]); + n[2] += (u[0] - v[0]) * (u[1] + v[1]); + } + + l = n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; + l = sqrt(l); + + if (l == 0.0) { + normal[0] = 0.0f; + normal[1] = 0.0f; + normal[2] = 1.0f; + + return; + } else l = 1.0f / l; + + n[0] *= l; + n[1] *= l; + n[2] *= l; + + normal[0] = (float) n[0]; + normal[1] = (float) n[1]; + normal[2] = (float) n[2]; +} + +void mesh_calc_poly_normal(MPoly *mpoly, MLoop *loopstart, + MVert *mvarray, float *no) +{ + if(mpoly->totloop > 4) { + mesh_calc_ngon_normal(mpoly, loopstart, mvarray, no); + } + else if(mpoly->totloop == 3){ + MVert *v1, *v2, *v3; + + v1 = mvarray + (loopstart++)->v; + v2 = mvarray + (loopstart++)->v; + v3 = mvarray + loopstart->v; + normal_tri_v3( no,v1->co, v2->co, v3->co); + } + else if(mpoly->totloop == 4){ + MVert *v1, *v2, *v3, *v4; + + v1 = mvarray + (loopstart++)->v; + v2 = mvarray + (loopstart++)->v; + v3 = mvarray + (loopstart++)->v; + v4 = mvarray + loopstart->v; + normal_quad_v3( no,v1->co, v2->co, v3->co, v4->co); + } + else{ /*horrible, two sided face!*/ + no[0] = 0.0; + no[1] = 0.0; + no[2] = 1.0; + } +} + /* basic vertex data functions */ int minmax_mesh(Mesh *me, float min[3], float max[3]) { |