485 lines
13 KiB
C
485 lines
13 KiB
C
#if 0
|
|
|
|
/**
|
|
* BME_conversions.c August 2008
|
|
*
|
|
* BM to Derived Mesh conversion functions.
|
|
*
|
|
* ***** 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.
|
|
* about this.
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2007 Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): Geoffrey Bantle, Levi Schooley.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#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 "BKE_utildefines.h"
|
|
#include "BKE_mesh.h"
|
|
#include "bmesh.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_DerivedMesh.h"
|
|
#include "BKE_cdderivedmesh.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_editVert.h"
|
|
#include "BLI_edgehash.h"
|
|
#include "bmesh_private.h"
|
|
|
|
|
|
|
|
/*
|
|
* BMESH DERIVED MESH CONVERSION FUNCTIONS
|
|
*
|
|
* The functions in this file provides
|
|
* methods for converting to and from
|
|
* a bmesh.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* DMCORNERS TO LOOPS
|
|
*
|
|
* Function to convert derived mesh per-face
|
|
* corner data (uvs, vertex colors), to n-gon
|
|
* per-loop data.
|
|
*
|
|
*/
|
|
|
|
static void DMcorners_to_loops(BMMesh *bm, CustomData *facedata, int index, BMFace *f, int numCol, int numTex)
|
|
{
|
|
int i, j;
|
|
BMLoop *l;
|
|
MTFace *texface;
|
|
MTexPoly *texpoly;
|
|
MCol *mcol;
|
|
MLoopCol *mloopcol;
|
|
MLoopUV *mloopuv;
|
|
|
|
for(i=0; i< numTex; i++){
|
|
texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
|
|
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
|
|
|
|
texpoly->tpage = texface[index].tpage;
|
|
texpoly->flag = texface[index].flag;
|
|
texpoly->transp = texface[index].transp;
|
|
texpoly->mode = texface[index].mode;
|
|
texpoly->tile = texface[index].tile;
|
|
texpoly->unwrap = texface[index].unwrap;
|
|
|
|
j = 0;
|
|
l = f->loopbase;
|
|
do{
|
|
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
|
|
mloopuv->uv[0] = texface[index].uv[j][0];
|
|
mloopuv->uv[1] = texface[index].uv[j][1];
|
|
j++;
|
|
l = l->next;
|
|
}while(l!=f->loopbase);
|
|
}
|
|
|
|
for(i=0; i < numCol; i++){
|
|
mcol = CustomData_get_layer_n(facedata, CD_MCOL, i);
|
|
j = 0;
|
|
l = f->loopbase;
|
|
do{
|
|
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
|
|
mloopcol->r = mcol[(index*4)+j].r;
|
|
mloopcol->g = mcol[(index*4)+j].g;
|
|
mloopcol->b = mcol[(index*4)+j].b;
|
|
mloopcol->a = mcol[(index*4)+j].a;
|
|
j++;
|
|
l = l->next;
|
|
}while(l!=f->loopbase);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* LOOPS TO DMCORNERS
|
|
*
|
|
* Function to convert n-gon per-loop data
|
|
* (uvs, vertex colors, ect)to derived mesh
|
|
* face corner data.
|
|
*
|
|
*/
|
|
|
|
static void loops_to_DMcorners(BMMesh *bm, CustomData *facedata, int index, BMFace *f,int numCol, int numTex)
|
|
{
|
|
int i, j;
|
|
BMLoop *l;
|
|
MTFace *texface;
|
|
MTexPoly *texpoly;
|
|
MCol *mcol;
|
|
MLoopCol *mloopcol;
|
|
MLoopUV *mloopuv;
|
|
|
|
for(i=0; i < numTex; i++){
|
|
texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
|
|
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
|
|
|
|
texface[index].tpage = texpoly->tpage;
|
|
texface[index].flag = texpoly->flag;
|
|
texface[index].transp = texpoly->transp;
|
|
texface[index].mode = texpoly->mode;
|
|
texface[index].tile = texpoly->tile;
|
|
texface[index].unwrap = texpoly->unwrap;
|
|
|
|
j = 0;
|
|
l = f->loopbase;
|
|
do{
|
|
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
|
|
texface[index].uv[j][0] = mloopuv->uv[0];
|
|
texface[index].uv[j][1] = mloopuv->uv[1];
|
|
j++;
|
|
l = l->next;
|
|
}while(l!=f->loopbase);
|
|
|
|
}
|
|
for(i=0; i < numCol; i++){
|
|
mcol = CustomData_get_layer_n(facedata,CD_MCOL, i);
|
|
j = 0;
|
|
l = f->loopbase;
|
|
do{
|
|
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
|
|
mcol[(index*4) + j].r = mloopcol->r;
|
|
mcol[(index*4) + j].g = mloopcol->g;
|
|
mcol[(index*4) + j].b = mloopcol->b;
|
|
mcol[(index*4) + j].a = mloopcol->a;
|
|
j++;
|
|
l = l->next;
|
|
}while(l!=f->loopbase);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* MVERT TO BMESHVERT
|
|
*
|
|
* Converts a MVert to a BMVert
|
|
*
|
|
*/
|
|
static BMVert *mvert_to_bmeshvert(BMMesh *bm, BMVert **vert_array, int index, MVert *mv, CustomData *data)
|
|
{
|
|
BMVert *v = NULL;
|
|
|
|
v = bmesh_make_vert(bm, mv->co, NULL);
|
|
vert_array[index] = v;
|
|
if(mv->flag & SELECT) bmesh_set_flag(v, BMESH_SELECT);
|
|
v->bweight = mv->bweight/255.0f;
|
|
CustomData_to_bmesh_block(data, &bm->vdata, index, &v->data);
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
* MEDGE TO BMESHEDGE
|
|
*
|
|
* Converts a MEdge to a BMEdge
|
|
*
|
|
*/
|
|
|
|
static BMEdge *medge_to_bmeshedge(BMMesh *bm, BMVert **vert_array, int index, MEdge *me, CustomData *data, Edge_Hash *edge_hash)
|
|
{
|
|
BMVert *v1, *v2;
|
|
BMEdge *e = NULL;
|
|
|
|
v1 = vert_array[me->v1];
|
|
v2 = vert_array[me->v2];
|
|
e = bmesh_make_edge(bm, v1, v2, NULL, 0);
|
|
e->crease = me->crease/255.0f;
|
|
e->bweight = me->bweight/255.0f;
|
|
if(me->flag & 1) bmesh_set_flag(e, BMESH_SELECT);
|
|
if(me->flag & ME_SEAM) bmesh_set_flag(e, BMESH_SEAM);
|
|
BLI_edgehash_insert(edge_hash,me->v1,me->v2,e);
|
|
CustomData_to_bmesh_block(data, &bm->edata, index, &e->data);
|
|
|
|
return e;
|
|
}
|
|
|
|
/*
|
|
* MFACE TO BMESHFACE
|
|
*
|
|
* Converts a MFace to a BMFace.
|
|
* Note that this will fail on eekadoodle
|
|
* faces.
|
|
*
|
|
*/
|
|
|
|
static BMFace *mface_to_bmeshface(BMMesh *bm, BMVert **vert_array, int index, MFace *mf, CustomData *data, Edge_Hash *edge_hash)
|
|
{
|
|
BMVert *v1, *v2;
|
|
BMEdge *edar[4];
|
|
BMFace *f = NULL;
|
|
int len;
|
|
|
|
if(mf->v4) len = 4;
|
|
else len = 3;
|
|
|
|
edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2);
|
|
edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3);
|
|
if(len == 4){
|
|
edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4);
|
|
edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1);
|
|
}
|
|
else
|
|
edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1);
|
|
|
|
/*find v1 and v2*/
|
|
v1 = vert_array[mf->v1];
|
|
v2 = vert_array[mf->v2];
|
|
|
|
f = bmesh_make_ngon(bm, v1, v2, edar, len, 0);
|
|
f->mat_nr = mf->mat_nr;
|
|
if(mf->flag & 1) bmesh_set_flag(f, BMESH_SELECT);
|
|
if(mf->flag & ME_HIDE) bmesh_set_flag(f, BMESH_HIDDEN);
|
|
CustomData_to_bmesh_block(data, &bm->pdata, index, &f->data);
|
|
|
|
return f;
|
|
}
|
|
|
|
/*
|
|
* DERIVEDMESH TO BMESH
|
|
*
|
|
* Converts a derived mesh to a bmesh.
|
|
*
|
|
*/
|
|
|
|
BMMesh *derivedmesh_to_bmesh(DerivedMesh *dm)
|
|
{
|
|
|
|
BMMesh *bm;
|
|
BMVert **vert_array;
|
|
BMFace *f=NULL;
|
|
|
|
MVert *mvert, *mv;
|
|
MEdge *medge, *me;
|
|
MFace *mface, *mf;
|
|
|
|
int totface,totedge,totvert,i,len, numTex, numCol;
|
|
int allocsize[4] = {512,512,2048,512};
|
|
|
|
EdgeHash *edge_hash = BLI_edgehash_new();
|
|
|
|
/*allocate a new bmesh*/
|
|
bm = bmesh_make_mesh(allocsize);
|
|
|
|
/*copy custom data layout*/
|
|
CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
|
|
CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
|
|
CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
|
|
|
|
/*copy face corner data*/
|
|
CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata);
|
|
/*initialize memory pools*/
|
|
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);
|
|
|
|
totvert = dm->getNumVerts(dm);
|
|
totedge = dm->getNumEdges(dm);
|
|
totface = dm->getNumTessFaces(dm);
|
|
mvert = dm->getVertArray(dm);
|
|
medge = dm->getEdgeArray(dm);
|
|
mface = dm->getTessFaceArray(dm);
|
|
|
|
vert_array = MEM_mallocN(sizeof(BMVert *)* totvert,"derivedmesh to bmesh vertex pointer array");
|
|
|
|
bmesh_begin_edit(bm);
|
|
/*add verts*/
|
|
for(i=0, mv = mvert; i < totvert; i++, mv++)
|
|
mvert_to_bmeshvert(bm, vert_array, i, mv, &dm->vertData);
|
|
|
|
/*add edges*/
|
|
for(i=0, me = medge; i < totedge; i++, me++)
|
|
medge_to_bmeshedge(bm, vert_array, i, me, &dm->edgeData, edge_hash);
|
|
|
|
/*add faces.*/
|
|
for(i=0, mf = mface; i < totface; i++, mf++){
|
|
f = mface_to_bmeshface(bm, vert_array, mf, &dm->faceData, edge_hash);
|
|
if(f) DMcorners_to_loops(bm, &dm->faceData, i, f, numCol, numTex);
|
|
}
|
|
|
|
bmesh_end__edit(bm);
|
|
BLI_edgehash_free(edge_hash, NULL);
|
|
MEM_freeN(vert_array);
|
|
return bm;
|
|
}
|
|
|
|
static void bmeshvert_to_mvert(BMMesh *bm, BMVert *v, MVert *mv, int index, CustomData *data)
|
|
{
|
|
copy_v3_v3(mv->co, v->co);
|
|
if(bmesh_test_flag(v, BMESH_SELECT)) mv->flag |= 1;
|
|
if(bmesh_test_flag(v, BMESH_HIDDEN)) mv->flag |= ME_HIDE;
|
|
mv->bweight = (char)(255.0*v1->bweight);
|
|
CustomData_from_bmesh_block(&bm->vdata, data, &v1->data, index);
|
|
}
|
|
|
|
static int bmeshedge_to_medge(BMMesh *bm, BMEdge *e, MEdge *me, int index, CustomData *data)
|
|
{
|
|
if(e->head.eflag2){
|
|
if(e->v1->head.eflag1 < e->v2->head.eflag1){
|
|
me->v1 = e->v1->head.eflag1;
|
|
me->v2 = e->v2->head.eflag1;
|
|
}
|
|
else{
|
|
me->v1 = e->v2->head.eflag1;
|
|
me->v2 = e->v1->eflag1;
|
|
}
|
|
|
|
me->crease = (char)(255.0*e->crease);
|
|
me->bweight = (char)(255.0*e->bweight);
|
|
if(bmesh_test_flag(e, BMESH_SELECT)) me->flag |= 1;
|
|
if(bmesh_test_flag(e, BMESH_HIDDEN)) me->flag |= ME_HIDE;
|
|
CustomData_from_bmesh_block(&bm->edata, data, &e->data, index);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int bmeshface_to_mface(BMMesh *bm, BMFace *f, MFace *mf, int index, CustomData *data)
|
|
{
|
|
if(f->len==3 || f->len==4){
|
|
mf->v1 = f->loopbase->v->head.eflag1;
|
|
mf->v2 = f->loopbase->next->v->head.eflag1;
|
|
mf->v3 = f->loopbase->next->next->v->head.eflag1;
|
|
if(len == 4){
|
|
mf->v4 = f->loopbase->prev->v->head.eflag1;
|
|
}
|
|
/* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */
|
|
if(mf->v3 == 0 || (f->len == 4 && mf->v4 == 0)){
|
|
test_index_face(mf, NULL, index, f->len);
|
|
}
|
|
mf->mat_nr = (unsigned char)f->mat_nr;
|
|
if(bmesh_test_flag(f, BMESH_SELECT)) mf->flag |= 1;
|
|
if(bmesh_test_flag(f, BMESH_HIDDEN)) mf->flag |= ME_HIDE;
|
|
CustomData_from_bmesh_block(&bm->pdata, data, &f->data, index);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* BMESH TO DERIVEDMESH
|
|
*
|
|
* Converts a bmesh to a derived mesh.
|
|
*
|
|
*/
|
|
|
|
DerivedMesh *bmesh_to_derivedmesh(BMMesh *bm, DerivedMesh *dm)
|
|
{
|
|
MFace *mface = NULL, *mf = NULL;
|
|
MEdge *medge = NULL, *me = NULL;
|
|
MVert *mvert = NULL, *mv = NULL;
|
|
DerivedMesh *result = NULL;
|
|
|
|
BMVert *v=NULL;
|
|
BMEdge *e=NULL, *oe=NULL;
|
|
BMFace *f=NULL;
|
|
|
|
BMIter verts;
|
|
BMIter edges;
|
|
BMIter faces;
|
|
|
|
int totface = 0,totedge = 0,totvert = 0,i = 0, numTex, numCol;
|
|
|
|
EdgeHash *edge_hash = BLI_edgehash_new();
|
|
|
|
/*get element counts*/
|
|
totvert = bmesh_count_element(bm, BMESH_VERT);
|
|
|
|
/*store element indices. Note that the abuse of eflag here should NOT be duplicated!*/
|
|
for(i=0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++)
|
|
v->head.eflag1 = i;
|
|
|
|
/*we cannot have double edges in a derived mesh!*/
|
|
for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){
|
|
oe = BLI_edgehash_lookup(edge_hash,e->v1->head.eflag1, e->v2->head.eflag1);
|
|
if(!oe){
|
|
totedge++;
|
|
BLI_edgehash_insert(edge_hash,e->v1->head.eflag1,e->v2->head.eflag1,e);
|
|
e->head.eflag2 = 1;
|
|
}
|
|
else{
|
|
e->head.eflag2 = 0;
|
|
}
|
|
}
|
|
|
|
/*count quads and tris*/
|
|
for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){
|
|
if(f->len == 3 || f->len == 4) totface++;
|
|
}
|
|
|
|
/*Allocate derivedmesh and copy custom data*/
|
|
result = CDDM_from_template(dm,totvert,totedge,totface);
|
|
CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
|
|
CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
|
|
CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
|
|
CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface);
|
|
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
|
|
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
|
|
|
|
/*Make Verts*/
|
|
mvert = CDDM_get_verts(result);
|
|
for(i = 0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++, mv++){
|
|
bmeshvert_to_mvert(bm,v,mv,i,&result->vertData);
|
|
}
|
|
|
|
/*Make Edges*/
|
|
medge = CDDM_get_edges(result);
|
|
i=0;
|
|
for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){
|
|
me = &medge[i];
|
|
if(bmeshedge_to_medge(bm, e, me, i, &result->edgeData){
|
|
me++;
|
|
i++;
|
|
}
|
|
}
|
|
/*Make Faces*/
|
|
if(totface){
|
|
mface = CDDM_get_faces(result);
|
|
i=0;
|
|
for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){
|
|
mf = &mface[i];
|
|
if(bmeshface_to_mface(bm, f, mf, i, &result->faceData)){
|
|
loops_to_DMcorners(bm, &result->faceData, i, f, numCol, numTex);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
BLI_edgehash_free(edge_hash, NULL);
|
|
return result;
|
|
}
|
|
|
|
#endif
|