509 lines
12 KiB
C
509 lines
12 KiB
C
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/bmesh/intern/editmesh_to_bmesh.c
|
|
* \ingroup bmesh
|
|
*
|
|
* Unused
|
|
*/
|
|
|
|
#if 0
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
#include "BKE_customdata.h"
|
|
#include "DNA_listBase.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include <string.h>
|
|
#include "BKE_utildefines.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_DerivedMesh.h"
|
|
#include "BKE_cdderivedmesh.h"
|
|
|
|
#include "BLI_editVert.h"
|
|
#include "mesh_intern.h"
|
|
#include "ED_mesh.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_edgehash.h"
|
|
#include "BLI_array.h"
|
|
|
|
#include "bmesh.h"
|
|
|
|
/*
|
|
* EDITMESH TO BMESH.C
|
|
*
|
|
* This file contains functions
|
|
* for converting an editmesh
|
|
* into a Bmesh
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* EDITMESH CORNERS TO LOOPS
|
|
*
|
|
* Converts editmesh face corner data
|
|
* (UVs, Vert colors, ect) to N-Gon
|
|
* face-edge ('loop') data.
|
|
*
|
|
*/
|
|
|
|
static void editmesh_corners_to_loops(BMesh *bm, CustomData *facedata, void *face_block, BMFace *f,int numCol, int numTex)
|
|
{
|
|
int i, j;
|
|
BMLoop *l;
|
|
MTFace *texface;
|
|
MTexPoly *texpoly;
|
|
MCol *mcol;
|
|
MLoopCol *mloopcol;
|
|
MLoopUV *mloopuv;
|
|
BMIter iter;
|
|
|
|
for(i=0; i < numTex; i++) {
|
|
texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
|
|
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, 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;
|
|
|
|
for (j=0, l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); l; j++, l=BMIter_Step(&iter)) {
|
|
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
|
|
mloopuv->uv[0] = texface->uv[j][0];
|
|
mloopuv->uv[1] = texface->uv[j][1];
|
|
}
|
|
|
|
}
|
|
for(i=0; i < numCol; i++) {
|
|
mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
|
|
for (j=0, l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); l; j++, l=BMIter_Step(&iter)) {
|
|
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
|
|
mloopcol->r = mcol[j].r;
|
|
mloopcol->g = mcol[j].g;
|
|
mloopcol->b = mcol[j].b;
|
|
mloopcol->a = mcol[j].a;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* EDITVERT TO BMVert
|
|
*
|
|
* Converts an editvert to
|
|
* a BMVert.
|
|
*
|
|
*/
|
|
|
|
static BMVert *editvert_to_BMVert(BMesh *bm, BMOperator *op, EditMesh *em, EditVert *eve)
|
|
{
|
|
BMVert *v = NULL;
|
|
|
|
v = BM_Make_Vert(bm, eve->co, NULL);
|
|
VECCOPY(v->no, eve->no);
|
|
|
|
/*transfer flags*/
|
|
v->head.flag = eve->h ? BM_HIDDEN : 0;
|
|
if(eve->f & SELECT) BM_Select_Vert(bm, v, TRUE);
|
|
v->bweight = eve->bweight;
|
|
|
|
BMO_Insert_MapPointer(bm, op, "map", eve, v);
|
|
|
|
/*Copy Custom Data*/
|
|
CustomData_bmesh_copy_data(&em->vdata, &bm->vdata, eve->data, &v->head.data);
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
* EDITEDGE TO BMEdge
|
|
*
|
|
* Converts an editedge to
|
|
* a BMEdge
|
|
*
|
|
*/
|
|
|
|
static void editedge_to_BMEdge_internal(BMesh *bm, BMOperator *op, EditMesh *em, BMEdge *e, EditEdge *eed)
|
|
{
|
|
e->crease = eed->crease;
|
|
e->bweight = eed->bweight;
|
|
|
|
BM_Select(bm, e, eed->f & SELECT);
|
|
e->head.flag |= eed->seam ? BM_SEAM : 0;
|
|
e->head.flag |= eed->h & 1 ? BM_HIDDEN : 0;
|
|
e->head.flag |= eed->h & EM_FGON ? BM_FGON : 0;
|
|
e->head.flag |= eed->sharp ? BM_SHARP : 0;
|
|
|
|
CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->head.data);
|
|
|
|
BMO_Insert_MapPointer(bm, op, "map", eed, e);
|
|
}
|
|
|
|
static BMEdge *editedge_to_BMEdge(BMesh *bm, BMOperator *op, EditMesh *em, EditEdge *eed)
|
|
{
|
|
BMVert *v1 = NULL, *v2 = NULL;
|
|
BMEdge *e = NULL;
|
|
|
|
v1 = eed->v1->tmp.p;
|
|
v2 = eed->v2->tmp.p;
|
|
|
|
e = BM_Make_Edge(bm, v1, v2,NULL, 0);
|
|
|
|
editedge_to_BMEdge_internal(bm, op, em, e, eed);
|
|
|
|
return e;
|
|
}
|
|
/*
|
|
* EDITFACE TO BMFace
|
|
*
|
|
* Converts an editface to a BMFace.
|
|
* Note that this also convert per-face
|
|
* corner data as well.
|
|
*
|
|
*/
|
|
|
|
static BMFace *editface_to_BMFace(BMesh *bm, BMOperator *op, EditMesh *em, EditFace *efa, int numCol, int numTex)
|
|
{
|
|
BMVert *v1 = NULL, *v2 = NULL;
|
|
BMFace *f = NULL;
|
|
BMEdge *edar[4];
|
|
int len;
|
|
|
|
edar[0] = BM_Make_Edge(bm, efa->v1->tmp.p, efa->v2->tmp.p, NULL, 1);
|
|
edar[1] = BM_Make_Edge(bm, efa->v2->tmp.p, efa->v3->tmp.p, NULL, 1);
|
|
if(efa->v4) {
|
|
edar[2] = BM_Make_Edge(bm, efa->v3->tmp.p, efa->v4->tmp.p, NULL, 1);
|
|
edar[3] = BM_Make_Edge(bm, efa->v4->tmp.p, efa->v1->tmp.p, NULL, 1);
|
|
}
|
|
else {
|
|
edar[2] = BM_Make_Edge(bm, efa->v3->tmp.p, efa->v1->tmp.p, NULL, 1);
|
|
}
|
|
|
|
editedge_to_BMEdge_internal(bm, op, em, edar[0], efa->e1);
|
|
editedge_to_BMEdge_internal(bm, op, em, edar[1], efa->e2);
|
|
editedge_to_BMEdge_internal(bm, op, em, edar[2], efa->e3);
|
|
if(efa->v4)
|
|
editedge_to_BMEdge_internal(bm, op, em, edar[3], efa->e4);
|
|
|
|
|
|
if(efa->e1->fgoni) edar[0]->head.flag |= BM_FGON;
|
|
if(efa->e2->fgoni) edar[1]->head.flag |= BM_FGON;
|
|
if(efa->e3->fgoni) edar[2]->head.flag |= BM_FGON;
|
|
if(efa->v4 && efa->e4->fgoni) edar[3]->head.flag |= BM_FGON;
|
|
|
|
if(efa->v4) len = 4;
|
|
else len = 3;
|
|
|
|
/*find v1 and v2*/
|
|
v1 = efa->v1->tmp.p;
|
|
v2 = efa->v2->tmp.p;
|
|
|
|
f = BM_Make_Ngon(bm, v1, v2, edar, len, 0);
|
|
|
|
VECCOPY(f->no, efa->n);
|
|
|
|
BMO_Insert_MapPointer(bm, op, "map", efa, f);
|
|
|
|
f->head.flag = 0;
|
|
f->mat_nr = efa->mat_nr;
|
|
if(efa->f & SELECT) BM_Select_Face(bm, f, TRUE);
|
|
if (efa->flag & ME_SMOOTH) f->head.flag |= BM_SMOOTH;
|
|
if(efa->h) f->head.flag |= BM_HIDDEN;
|
|
|
|
if (efa == em->act_face) f->head.flag |= BM_ACTIVE;
|
|
|
|
CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->head.data);
|
|
editmesh_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex);
|
|
|
|
return f;
|
|
}
|
|
|
|
/*
|
|
* BMESH FGONCONVERT
|
|
*
|
|
* This function and its associated structures
|
|
* /helpers (fgonsort, sortfgon, fuse_fgon) are
|
|
* used to convert f-gons to bmesh n-gons. This
|
|
* is accomplished by sorting a list of fgon faces
|
|
* such that faces that are part of the same fgon
|
|
* are next to each other. These faces are then
|
|
* converted as is into bmesh faces and
|
|
* fused togather.
|
|
*
|
|
* Note that currently, there is no support for
|
|
* holes in faces in the bmesh structure, so
|
|
* f-gons with holes will only partially convert.
|
|
*
|
|
*/
|
|
|
|
typedef struct fgonsort {
|
|
unsigned long x;
|
|
struct EditFace *efa;
|
|
struct BMFace *f;
|
|
int done;
|
|
}fgonsort;
|
|
|
|
static int sortfgon(const void *v1, const void *v2)
|
|
{
|
|
const struct fgonsort *x1=v1, *x2=v2;
|
|
|
|
if( x1->x > x2->x ) return 1;
|
|
else if( x1->x < x2->x) return -1;
|
|
return 0;
|
|
}
|
|
|
|
static void fuse_fgon(BMesh *bm, BMFace *f)
|
|
{
|
|
BMFace *sf;
|
|
BMLoop *l;
|
|
int done, act=0;
|
|
|
|
sf = f;
|
|
done = 0;
|
|
while(!done) {
|
|
done = 1;
|
|
l = sf->loopbase;
|
|
do{
|
|
if(l->e->head.flag & BM_FGON) {
|
|
if (l->f->head.flag & BM_ACTIVE) act = BM_ACTIVE;
|
|
if (l->radial.next->data->f->head.flag & BM_ACTIVE) act = BM_ACTIVE;
|
|
|
|
sf = BM_Join_TwoFaces(bm,l->f, l->radial.next->data->f, l->e);
|
|
if (!sf) {
|
|
//tesselation error
|
|
break;
|
|
}
|
|
|
|
sf->head.flag |= act;
|
|
if(sf) {
|
|
done = 0;
|
|
break;
|
|
} else { /*we have to get out of here...*/
|
|
return;
|
|
}
|
|
}
|
|
l = l->next;
|
|
} while(l != sf->loopbase);
|
|
}
|
|
}
|
|
|
|
static BM_fgonconvert(BMesh *bm, BMOperator *op, EditMesh *em, int numCol, int numTex)
|
|
{
|
|
EditFace *efa;
|
|
BMFace *f;
|
|
BMIter iter;
|
|
struct fgonsort *sortblock, *sb, *sb1;
|
|
int a, b, amount=0;
|
|
|
|
/*
|
|
for (efa=em->faces.first; efa; efa=efa->next) {
|
|
f = editface_to_BMFace(bm, em, efa, numCol, numTex);
|
|
}
|
|
|
|
for (f=bm->polys.first; f; f=f->next) {
|
|
fuse_fgon(bm, f);
|
|
}
|
|
|
|
return;*/
|
|
|
|
EM_fgon_flags(em);
|
|
|
|
/*zero out efa->tmp, we store fgon index here*/
|
|
for(efa = em->faces.first; efa; efa = efa->next) {
|
|
efa->tmp.l = 0;
|
|
amount++;
|
|
}
|
|
/*go through and give each editface an fgon index*/
|
|
for(efa = em->faces.first; efa; efa = efa->next) {
|
|
if(efa->e1->fgoni) efa->tmp.l = efa->e1->fgoni;
|
|
else if(efa->e2->fgoni) efa->tmp.l = efa->e2->fgoni;
|
|
else if(efa->e3->fgoni) efa->tmp.l = efa->e3->fgoni;
|
|
else if(efa->e4 && efa->e4->fgoni) efa->tmp.l = efa->e4->fgoni;
|
|
}
|
|
|
|
sb= sortblock= MEM_mallocN(sizeof(fgonsort)* amount,"fgon sort block");
|
|
|
|
for(efa = em->faces.first; efa; efa=efa->next) {
|
|
sb->x = efa->tmp.l;
|
|
sb->efa = efa;
|
|
sb->done = 0;
|
|
sb++;
|
|
}
|
|
|
|
qsort(sortblock, amount, sizeof(fgonsort), sortfgon);
|
|
|
|
sb = sortblock;
|
|
for(a=0; a<amount; a++, sb++) {
|
|
if(sb->x && sb->done == 0) {
|
|
/*first pass: add in faces for this fgon*/
|
|
for(b=a, sb1 = sb; b<amount && sb1->x == sb->x; b++, sb1++) {
|
|
efa = sb1->efa;
|
|
sb1->f = editface_to_BMFace(bm, op, em, efa, numCol, numTex);
|
|
sb1->done = 1;
|
|
}
|
|
/*fuse fgon*/
|
|
fuse_fgon(bm, sb->f);
|
|
}
|
|
}
|
|
MEM_freeN(sortblock);
|
|
}
|
|
|
|
/*
|
|
* TAG WIRE EDGES
|
|
*
|
|
* Flags editedges 'f1' member
|
|
* if the edge has no faces.
|
|
*
|
|
*/
|
|
|
|
static void tag_wire_edges(EditMesh *em)
|
|
{
|
|
EditFace *efa;
|
|
EditEdge *eed;
|
|
for(eed = em->edges.first; eed; eed = eed->next) eed->f1 = 1;
|
|
for(efa = em->faces.first; efa; efa = efa->next) {
|
|
efa->e1->f1 = 0;
|
|
efa->e2->f1 = 0;
|
|
efa->e3->f1 = 0;
|
|
if(efa->e4) efa->e4->f1 = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* EDITMESH TO BMESH
|
|
*
|
|
* Function to convert an editmesh to a bmesh
|
|
* Currently all custom data as well as
|
|
* f-gons should be converted correctly.
|
|
*
|
|
*/
|
|
|
|
BMesh *editmesh_to_bmesh_intern(EditMesh *em, BMesh *bm, BMOperator *op)
|
|
{
|
|
BMVert *v;
|
|
EditVert *eve;
|
|
EditEdge *eed;
|
|
EditFace *efa;
|
|
BMEdge *e;
|
|
BMIter iter;
|
|
int allocsize[4] = {512,512,2048,512}, numTex, numCol;
|
|
|
|
/*make sure to update FGon flags*/
|
|
EM_fgon_flags(em);
|
|
|
|
/*copy custom data layout*/
|
|
CustomData_copy(&em->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
|
|
CustomData_copy(&em->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
|
|
CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
|
|
|
|
/*copy face corner data*/
|
|
CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata, 0, 0);
|
|
|
|
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
|
|
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
|
|
CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
|
|
CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
|
|
|
|
/*needed later*/
|
|
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
|
|
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
|
|
|
|
/*copy over selection mode*/
|
|
bm->selectmode = 0;
|
|
if(em->selectmode & SCE_SELECT_VERTEX) bm->selectmode |= SCE_SELECT_VERTEX;
|
|
if(em->selectmode & SCE_SELECT_EDGE) bm->selectmode |= SCE_SELECT_EDGE;
|
|
if(em->selectmode & SCE_SELECT_FACE) bm->selectmode |= SCE_SELECT_FACE;
|
|
|
|
|
|
/*begin editloop*/
|
|
//BM_Begin_Edit(bm);
|
|
|
|
/*tag wire edges*/
|
|
tag_wire_edges(em);
|
|
|
|
/*add verts*/
|
|
for(eve = em->verts.first; eve; eve = eve->next) {
|
|
v = editvert_to_BMVert(bm, op, em, eve);
|
|
eve->tmp.p = v;
|
|
}
|
|
/*convert f-gons*/
|
|
BM_fgonconvert(bm, op, em, numCol, numTex);
|
|
|
|
/*clean up any dangling fgon flags*/
|
|
for (e=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e=BMIter_Step(&iter)) {
|
|
e->head.flag &= ~BM_FGON;
|
|
}
|
|
|
|
/*do quads + triangles*/
|
|
for(efa = em->faces.first; efa; efa = efa->next) {
|
|
if(!efa->tmp.l) editface_to_BMFace(bm, op, em, efa, numCol, numTex);
|
|
}
|
|
|
|
/*add wire edges*/
|
|
for(eed = em->edges.first; eed; eed = eed->next) {
|
|
if(eed->f1) editedge_to_BMEdge(bm, op, em, eed);
|
|
}
|
|
//BM_end_edit(bm, BM_CALC_NORM);
|
|
return bm;
|
|
}
|
|
|
|
void edit2bmesh_exec(BMesh *bmesh, BMOperator *op)
|
|
{
|
|
editmesh_to_bmesh_intern(BMO_Get_Pnt(op, "em"), bmesh, op);
|
|
}
|
|
|
|
BMesh *editmesh_to_bmesh(EditMesh *em)
|
|
{
|
|
BMOperator conv;
|
|
BMesh *bm;
|
|
int allocsize[4] = {512,512,2048,512};
|
|
|
|
/*allocate a bmesh*/
|
|
bm = BM_Make_Mesh(allocsize);
|
|
|
|
BMO_Init_Op(&conv, "editmesh_to_bmesh");
|
|
BMO_Set_Pnt(&conv, "em", em);
|
|
BMO_Exec_Op(bm, &conv);
|
|
BMO_Finish_Op(bm, &conv);
|
|
|
|
return bm;
|
|
}
|
|
|
|
BMesh *init_editmesh_to_bmesh(EditMesh *em, BMOperator *op)
|
|
{
|
|
BMesh *bm;
|
|
int allocsize[4] = {512,512,2048,512}, numTex, numCol;
|
|
|
|
/*allocate a bmesh*/
|
|
bm = BM_Make_Mesh(allocsize);
|
|
|
|
BMO_Init_Op(op, "editmesh_to_bmesh");
|
|
BMO_Set_Pnt(op, "em", em);
|
|
|
|
return bm;
|
|
}
|
|
#endif
|