2008-12-30 13:16:14 +00:00
|
|
|
/**
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): Blender Foundation, full recode 2002-2008
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "PIL_time.h"
|
|
|
|
|
|
|
|
#include "DNA_customdata_types.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_object_force.h"
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
#include "DNA_key_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_view3d_types.h"
|
|
|
|
#include "DNA_material_types.h"
|
|
|
|
#include "DNA_modifier_types.h"
|
|
|
|
#include "DNA_texture_types.h"
|
|
|
|
#include "DNA_userdef_types.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "BLI_editVert.h"
|
|
|
|
#include "BLI_dynstr.h"
|
|
|
|
#include "BLI_rand.h"
|
|
|
|
|
|
|
|
#include "BKE_cloth.h"
|
|
|
|
#include "BKE_context.h"
|
2008-12-30 16:03:29 +00:00
|
|
|
#include "BKE_customdata.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "BKE_depsgraph.h"
|
2008-12-30 16:03:29 +00:00
|
|
|
#include "BKE_DerivedMesh.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_key.h"
|
|
|
|
#include "BKE_library.h"
|
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_material.h"
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_modifier.h"
|
|
|
|
#include "BKE_object.h"
|
2009-08-15 19:48:50 +00:00
|
|
|
#include "BKE_paint.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "BKE_pointcache.h"
|
|
|
|
#include "BKE_softbody.h"
|
|
|
|
#include "BKE_texture.h"
|
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
|
|
|
|
#include "LBM_fluidsim.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "ED_mesh.h"
|
2009-01-29 18:54:22 +00:00
|
|
|
#include "ED_object.h"
|
2009-07-08 16:17:47 +00:00
|
|
|
#include "ED_retopo.h"
|
2009-01-30 15:01:14 +00:00
|
|
|
#include "ED_screen.h"
|
2009-07-08 16:17:47 +00:00
|
|
|
#include "ED_util.h"
|
2009-01-05 15:19:31 +00:00
|
|
|
#include "ED_view3d.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* own include */
|
2009-01-01 13:15:35 +00:00
|
|
|
#include "mesh_intern.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
editmesh.c:
|
|
|
|
- add/alloc/free data
|
|
|
|
- hashtables
|
|
|
|
- enter/exit editmode
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* XXX */
|
|
|
|
static void BIF_undo_push() {}
|
|
|
|
static void error() {}
|
|
|
|
|
|
|
|
|
|
|
|
/* ***************** HASH ********************* */
|
|
|
|
|
|
|
|
|
|
|
|
#define EDHASHSIZE (512*512)
|
|
|
|
#define EDHASH(a, b) (a % EDHASHSIZE)
|
|
|
|
|
|
|
|
|
|
|
|
/* ************ ADD / REMOVE / FIND ****************** */
|
|
|
|
|
|
|
|
static void *calloc_em(EditMesh *em, size_t size, size_t nr)
|
|
|
|
{
|
|
|
|
return calloc(size, nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* used to bypass normal calloc with fast one */
|
|
|
|
static void *(*callocvert)(EditMesh *, size_t, size_t) = calloc_em;
|
|
|
|
static void *(*callocedge)(EditMesh *, size_t, size_t) = calloc_em;
|
|
|
|
static void *(*callocface)(EditMesh *, size_t, size_t) = calloc_em;
|
|
|
|
|
|
|
|
EditVert *addvertlist(EditMesh *em, float *vec, EditVert *example)
|
|
|
|
{
|
|
|
|
EditVert *eve;
|
|
|
|
static int hashnr= 0;
|
|
|
|
|
|
|
|
eve= callocvert(em, sizeof(EditVert), 1);
|
|
|
|
BLI_addtail(&em->verts, eve);
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totvert++;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
if(vec) VECCOPY(eve->co, vec);
|
|
|
|
|
|
|
|
eve->hash= hashnr++;
|
|
|
|
if( hashnr>=EDHASHSIZE) hashnr= 0;
|
|
|
|
|
|
|
|
/* new verts get keyindex of -1 since they did not
|
|
|
|
* have a pre-editmode vertex order
|
|
|
|
*/
|
|
|
|
eve->keyindex = -1;
|
|
|
|
|
|
|
|
if(example) {
|
|
|
|
CustomData_em_copy_data(&em->vdata, &em->vdata, example->data, &eve->data);
|
|
|
|
eve->bweight = example->bweight;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
CustomData_em_set_default(&em->vdata, &eve->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return eve;
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_editvert (EditMesh *em, EditVert *eve)
|
|
|
|
{
|
|
|
|
|
|
|
|
EM_remove_selection(em, eve, EDITVERT);
|
|
|
|
CustomData_em_free_block(&em->vdata, &eve->data);
|
|
|
|
if(eve->fast==0)
|
|
|
|
free(eve);
|
2009-01-15 15:01:39 +00:00
|
|
|
|
|
|
|
em->totvert--;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EditEdge *findedgelist(EditMesh *em, EditVert *v1, EditVert *v2)
|
|
|
|
{
|
|
|
|
EditVert *v3;
|
|
|
|
struct HashEdge *he;
|
|
|
|
|
|
|
|
/* swap ? */
|
|
|
|
if( v1 > v2) {
|
|
|
|
v3= v2;
|
|
|
|
v2= v1;
|
|
|
|
v1= v3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(em->hashedgetab==NULL)
|
|
|
|
em->hashedgetab= MEM_callocN(EDHASHSIZE*sizeof(struct HashEdge), "hashedgetab");
|
|
|
|
|
|
|
|
he= em->hashedgetab + EDHASH(v1->hash, v2->hash);
|
|
|
|
|
|
|
|
while(he) {
|
|
|
|
|
|
|
|
if(he->eed && he->eed->v1==v1 && he->eed->v2==v2) return he->eed;
|
|
|
|
|
|
|
|
he= he->next;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void insert_hashedge(EditMesh *em, EditEdge *eed)
|
|
|
|
{
|
|
|
|
/* assuming that eed is not in the list yet, and that a find has been done before */
|
|
|
|
|
|
|
|
struct HashEdge *first, *he;
|
|
|
|
|
|
|
|
first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
|
|
|
|
|
|
|
|
if( first->eed==0 ) {
|
|
|
|
first->eed= eed;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
he= &eed->hash;
|
|
|
|
he->eed= eed;
|
|
|
|
he->next= first->next;
|
|
|
|
first->next= he;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_hashedge(EditMesh *em, EditEdge *eed)
|
|
|
|
{
|
|
|
|
/* assuming eed is in the list */
|
|
|
|
|
|
|
|
struct HashEdge *first, *he, *prev=NULL;
|
|
|
|
|
|
|
|
he=first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
|
|
|
|
|
|
|
|
while(he) {
|
|
|
|
if(he->eed == eed) {
|
|
|
|
/* remove from list */
|
|
|
|
if(he==first) {
|
|
|
|
if(first->next) {
|
|
|
|
he= first->next;
|
|
|
|
first->eed= he->eed;
|
|
|
|
first->next= he->next;
|
|
|
|
}
|
|
|
|
else he->eed= 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
prev->next= he->next;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
prev= he;
|
|
|
|
he= he->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EditEdge *addedgelist(EditMesh *em, EditVert *v1, EditVert *v2, EditEdge *example)
|
|
|
|
{
|
|
|
|
EditVert *v3;
|
|
|
|
EditEdge *eed;
|
|
|
|
int swap= 0;
|
|
|
|
|
|
|
|
if(v1==v2) return NULL;
|
|
|
|
if(v1==NULL || v2==NULL) return NULL;
|
|
|
|
|
|
|
|
/* swap ? */
|
|
|
|
if(v1>v2) {
|
|
|
|
v3= v2;
|
|
|
|
v2= v1;
|
|
|
|
v1= v3;
|
|
|
|
swap= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find in hashlist */
|
|
|
|
eed= findedgelist(em, v1, v2);
|
|
|
|
|
|
|
|
if(eed==NULL) {
|
|
|
|
|
|
|
|
eed= (EditEdge *)callocedge(em, sizeof(EditEdge), 1);
|
|
|
|
eed->v1= v1;
|
|
|
|
eed->v2= v2;
|
|
|
|
BLI_addtail(&em->edges, eed);
|
|
|
|
eed->dir= swap;
|
|
|
|
insert_hashedge(em, eed);
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totedge++;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* copy edge data:
|
|
|
|
rule is to do this with addedgelist call, before addfacelist */
|
|
|
|
if(example) {
|
|
|
|
eed->crease= example->crease;
|
|
|
|
eed->bweight= example->bweight;
|
|
|
|
eed->sharp = example->sharp;
|
|
|
|
eed->seam = example->seam;
|
|
|
|
eed->h |= (example->h & EM_FGON);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return eed;
|
|
|
|
}
|
|
|
|
|
|
|
|
void remedge(EditMesh *em, EditEdge *eed)
|
|
|
|
{
|
|
|
|
BLI_remlink(&em->edges, eed);
|
|
|
|
remove_hashedge(em, eed);
|
2009-01-15 15:01:39 +00:00
|
|
|
|
|
|
|
em->totedge--;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void free_editedge(EditMesh *em, EditEdge *eed)
|
|
|
|
{
|
|
|
|
EM_remove_selection(em, eed, EDITEDGE);
|
|
|
|
if(eed->fast==0){
|
|
|
|
free(eed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_editface(EditMesh *em, EditFace *efa)
|
|
|
|
{
|
|
|
|
EM_remove_selection(em, efa, EDITFACE);
|
|
|
|
|
|
|
|
if (em->act_face==efa) {
|
|
|
|
EM_set_actFace(em, em->faces.first == efa ? NULL : em->faces.first);
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomData_em_free_block(&em->fdata, &efa->data);
|
|
|
|
if(efa->fast==0)
|
|
|
|
free(efa);
|
2009-01-15 15:01:39 +00:00
|
|
|
|
|
|
|
em->totface--;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void free_vertlist(EditMesh *em, ListBase *edve)
|
|
|
|
{
|
|
|
|
EditVert *eve, *next;
|
|
|
|
|
|
|
|
if (!edve) return;
|
|
|
|
|
|
|
|
eve= edve->first;
|
|
|
|
while(eve) {
|
|
|
|
next= eve->next;
|
|
|
|
free_editvert(em, eve);
|
|
|
|
eve= next;
|
|
|
|
}
|
|
|
|
edve->first= edve->last= NULL;
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totvert= em->totvertsel= 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void free_edgelist(EditMesh *em, ListBase *lb)
|
|
|
|
{
|
|
|
|
EditEdge *eed, *next;
|
|
|
|
|
|
|
|
eed= lb->first;
|
|
|
|
while(eed) {
|
|
|
|
next= eed->next;
|
|
|
|
free_editedge(em, eed);
|
|
|
|
eed= next;
|
|
|
|
}
|
|
|
|
lb->first= lb->last= NULL;
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totedge= em->totedgesel= 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void free_facelist(EditMesh *em, ListBase *lb)
|
|
|
|
{
|
|
|
|
EditFace *efa, *next;
|
|
|
|
|
|
|
|
efa= lb->first;
|
|
|
|
while(efa) {
|
|
|
|
next= efa->next;
|
|
|
|
free_editface(em, efa);
|
|
|
|
efa= next;
|
|
|
|
}
|
|
|
|
lb->first= lb->last= NULL;
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totface= em->totfacesel= 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EditFace *addfacelist(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, EditFace *example, EditFace *exampleEdges)
|
|
|
|
{
|
|
|
|
EditFace *efa;
|
|
|
|
EditEdge *e1, *e2=0, *e3=0, *e4=0;
|
|
|
|
|
|
|
|
/* added sanity check... seems to happen for some tools, or for enter editmode for corrupted meshes */
|
|
|
|
if(v1==v4 || v2==v4 || v3==v4) v4= NULL;
|
|
|
|
|
|
|
|
/* add face to list and do the edges */
|
|
|
|
if(exampleEdges) {
|
|
|
|
e1= addedgelist(em, v1, v2, exampleEdges->e1);
|
|
|
|
e2= addedgelist(em, v2, v3, exampleEdges->e2);
|
|
|
|
if(v4) e3= addedgelist(em, v3, v4, exampleEdges->e3);
|
|
|
|
else e3= addedgelist(em, v3, v1, exampleEdges->e3);
|
|
|
|
if(v4) e4= addedgelist(em, v4, v1, exampleEdges->e4);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
e1= addedgelist(em, v1, v2, NULL);
|
|
|
|
e2= addedgelist(em, v2, v3, NULL);
|
|
|
|
if(v4) e3= addedgelist(em, v3, v4, NULL);
|
|
|
|
else e3= addedgelist(em, v3, v1, NULL);
|
|
|
|
if(v4) e4= addedgelist(em, v4, v1, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(v1==v2 || v2==v3 || v1==v3) return NULL;
|
|
|
|
if(e2==0) return NULL;
|
|
|
|
|
|
|
|
efa= (EditFace *)callocface(em, sizeof(EditFace), 1);
|
|
|
|
efa->v1= v1;
|
|
|
|
efa->v2= v2;
|
|
|
|
efa->v3= v3;
|
|
|
|
efa->v4= v4;
|
|
|
|
|
|
|
|
efa->e1= e1;
|
|
|
|
efa->e2= e2;
|
|
|
|
efa->e3= e3;
|
|
|
|
efa->e4= e4;
|
|
|
|
|
|
|
|
if(example) {
|
|
|
|
efa->mat_nr= example->mat_nr;
|
|
|
|
efa->flag= example->flag;
|
|
|
|
CustomData_em_copy_data(&em->fdata, &em->fdata, example->data, &efa->data);
|
|
|
|
}
|
|
|
|
else {
|
2009-01-02 19:10:35 +00:00
|
|
|
efa->mat_nr= em->mat_nr;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
CustomData_em_set_default(&em->fdata, &efa->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_addtail(&em->faces, efa);
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totface++;
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
if(efa->v4) {
|
2009-11-10 20:43:45 +00:00
|
|
|
normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
|
|
|
|
cent_quad_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-11-10 20:43:45 +00:00
|
|
|
normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
|
|
|
|
cent_tri_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return efa;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************ end add/new/find ************ */
|
|
|
|
|
|
|
|
/* ************************ Edit{Vert,Edge,Face} utilss ***************************** */
|
|
|
|
|
|
|
|
/* some nice utility functions */
|
|
|
|
|
|
|
|
EditVert *editedge_getOtherVert(EditEdge *eed, EditVert *eve)
|
|
|
|
{
|
|
|
|
if (eve==eed->v1) {
|
|
|
|
return eed->v2;
|
|
|
|
} else if (eve==eed->v2) {
|
|
|
|
return eed->v1;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EditVert *editedge_getSharedVert(EditEdge *eed, EditEdge *eed2)
|
|
|
|
{
|
|
|
|
if (eed->v1==eed2->v1 || eed->v1==eed2->v2) {
|
|
|
|
return eed->v1;
|
|
|
|
} else if (eed->v2==eed2->v1 || eed->v2==eed2->v2) {
|
|
|
|
return eed->v2;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int editedge_containsVert(EditEdge *eed, EditVert *eve)
|
|
|
|
{
|
|
|
|
return (eed->v1==eve || eed->v2==eve);
|
|
|
|
}
|
|
|
|
|
|
|
|
int editface_containsVert(EditFace *efa, EditVert *eve)
|
|
|
|
{
|
|
|
|
return (efa->v1==eve || efa->v2==eve || efa->v3==eve || (efa->v4 && efa->v4==eve));
|
|
|
|
}
|
|
|
|
|
|
|
|
int editface_containsEdge(EditFace *efa, EditEdge *eed)
|
|
|
|
{
|
|
|
|
return (efa->e1==eed || efa->e2==eed || efa->e3==eed || (efa->e4 && efa->e4==eed));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ************************ stuct EditMesh manipulation ***************************** */
|
|
|
|
|
|
|
|
/* fake callocs for fastmalloc below */
|
|
|
|
static void *calloc_fastvert(EditMesh *em, size_t size, size_t nr)
|
|
|
|
{
|
|
|
|
EditVert *eve= em->curvert++;
|
|
|
|
eve->fast= 1;
|
|
|
|
return eve;
|
|
|
|
}
|
|
|
|
static void *calloc_fastedge(EditMesh *em, size_t size, size_t nr)
|
|
|
|
{
|
|
|
|
EditEdge *eed= em->curedge++;
|
|
|
|
eed->fast= 1;
|
|
|
|
return eed;
|
|
|
|
}
|
|
|
|
static void *calloc_fastface(EditMesh *em, size_t size, size_t nr)
|
|
|
|
{
|
|
|
|
EditFace *efa= em->curface++;
|
|
|
|
efa->fast= 1;
|
|
|
|
return efa;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate 1 chunk for all vertices, edges, faces. These get tagged to
|
|
|
|
prevent it from being freed
|
|
|
|
*/
|
|
|
|
static void init_editmesh_fastmalloc(EditMesh *em, int totvert, int totedge, int totface)
|
|
|
|
{
|
|
|
|
if(totvert) em->allverts= MEM_callocN(totvert*sizeof(EditVert), "allverts");
|
|
|
|
else em->allverts= NULL;
|
|
|
|
em->curvert= em->allverts;
|
|
|
|
|
|
|
|
if(totedge==0) totedge= 4*totface; // max possible
|
|
|
|
|
|
|
|
if(totedge) em->alledges= MEM_callocN(totedge*sizeof(EditEdge), "alledges");
|
|
|
|
else em->alledges= NULL;
|
|
|
|
em->curedge= em->alledges;
|
|
|
|
|
|
|
|
if(totface) em->allfaces= MEM_callocN(totface*sizeof(EditFace), "allfaces");
|
|
|
|
else em->allfaces= NULL;
|
|
|
|
em->curface= em->allfaces;
|
|
|
|
|
|
|
|
callocvert= calloc_fastvert;
|
|
|
|
callocedge= calloc_fastedge;
|
|
|
|
callocface= calloc_fastface;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void end_editmesh_fastmalloc(void)
|
|
|
|
{
|
|
|
|
callocvert= calloc_em;
|
|
|
|
callocedge= calloc_em;
|
|
|
|
callocface= calloc_em;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do not free editmesh itself here */
|
|
|
|
void free_editMesh(EditMesh *em)
|
|
|
|
{
|
|
|
|
if(em==NULL) return;
|
|
|
|
|
|
|
|
if(em->verts.first) free_vertlist(em, &em->verts);
|
|
|
|
if(em->edges.first) free_edgelist(em, &em->edges);
|
|
|
|
if(em->faces.first) free_facelist(em, &em->faces);
|
|
|
|
if(em->selected.first) BLI_freelistN(&(em->selected));
|
|
|
|
|
|
|
|
CustomData_free(&em->vdata, 0);
|
|
|
|
CustomData_free(&em->fdata, 0);
|
|
|
|
|
|
|
|
if(em->derivedFinal) {
|
|
|
|
if (em->derivedFinal!=em->derivedCage) {
|
|
|
|
em->derivedFinal->needsFree= 1;
|
|
|
|
em->derivedFinal->release(em->derivedFinal);
|
|
|
|
}
|
|
|
|
em->derivedFinal= NULL;
|
|
|
|
}
|
|
|
|
if(em->derivedCage) {
|
|
|
|
em->derivedCage->needsFree= 1;
|
|
|
|
em->derivedCage->release(em->derivedCage);
|
|
|
|
em->derivedCage= NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* DEBUG: hashtabs are slowest part of enter/exit editmode. here a testprint */
|
|
|
|
#if 0
|
|
|
|
if(em->hashedgetab) {
|
|
|
|
HashEdge *he, *hen;
|
|
|
|
int a, used=0, max=0, nr;
|
|
|
|
he= em->hashedgetab;
|
|
|
|
for(a=0; a<EDHASHSIZE; a++, he++) {
|
|
|
|
if(he->eed) used++;
|
|
|
|
hen= he->next;
|
|
|
|
nr= 0;
|
|
|
|
while(hen) {
|
|
|
|
nr++;
|
|
|
|
hen= hen->next;
|
|
|
|
}
|
|
|
|
if(max<nr) max= nr;
|
|
|
|
}
|
|
|
|
printf("hastab used %d max %d\n", used, max);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if(em->hashedgetab) MEM_freeN(em->hashedgetab);
|
|
|
|
em->hashedgetab= NULL;
|
|
|
|
|
|
|
|
if(em->allverts) MEM_freeN(em->allverts);
|
|
|
|
if(em->alledges) MEM_freeN(em->alledges);
|
|
|
|
if(em->allfaces) MEM_freeN(em->allfaces);
|
|
|
|
|
|
|
|
em->allverts= em->curvert= NULL;
|
|
|
|
em->alledges= em->curedge= NULL;
|
|
|
|
em->allfaces= em->curface= NULL;
|
|
|
|
|
|
|
|
mesh_octree_table(NULL, NULL, NULL, 'e');
|
|
|
|
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totvert= em->totedge= em->totface= 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
// XXX if(em->retopo_paint_data) retopo_free_paint_data(em->retopo_paint_data);
|
|
|
|
em->retopo_paint_data= NULL;
|
|
|
|
em->act_face = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void editMesh_set_hash(EditMesh *em)
|
|
|
|
{
|
|
|
|
EditEdge *eed;
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
if(em->hashedgetab) MEM_freeN(em->hashedgetab);
|
2008-12-30 13:16:14 +00:00
|
|
|
em->hashedgetab= NULL;
|
|
|
|
|
|
|
|
for(eed=em->edges.first; eed; eed= eed->next) {
|
|
|
|
if( findedgelist(em, eed->v1, eed->v2)==NULL )
|
|
|
|
insert_hashedge(em, eed);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ************************ IN & OUT EDITMODE ***************************** */
|
|
|
|
|
|
|
|
|
|
|
|
static void edge_normal_compare(EditEdge *eed, EditFace *efa1)
|
|
|
|
{
|
|
|
|
EditFace *efa2;
|
|
|
|
float cent1[3], cent2[3];
|
|
|
|
float inp;
|
|
|
|
|
|
|
|
efa2 = eed->tmp.f;
|
|
|
|
if(efa1==efa2) return;
|
|
|
|
|
|
|
|
inp= efa1->n[0]*efa2->n[0] + efa1->n[1]*efa2->n[1] + efa1->n[2]*efa2->n[2];
|
|
|
|
if(inp<0.999 && inp >-0.999) eed->f2= 1;
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
if(efa1->v4) cent_quad_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co, efa1->v4->co);
|
|
|
|
else cent_tri_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co);
|
|
|
|
if(efa2->v4) cent_quad_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co, efa2->v4->co);
|
|
|
|
else cent_tri_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(cent1, cent2, cent1);
|
|
|
|
normalize_v3(cent1);
|
2008-12-30 13:16:14 +00:00
|
|
|
inp= cent1[0]*efa1->n[0] + cent1[1]*efa1->n[1] + cent1[2]*efa1->n[2];
|
|
|
|
|
|
|
|
if(inp < -0.001 ) eed->f1= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
typedef struct {
|
|
|
|
EditEdge *eed;
|
|
|
|
float noLen,no[3];
|
|
|
|
int adjCount;
|
|
|
|
} EdgeDrawFlagInfo;
|
|
|
|
|
|
|
|
static int edgeDrawFlagInfo_cmp(const void *av, const void *bv)
|
|
|
|
{
|
|
|
|
const EdgeDrawFlagInfo *a = av;
|
|
|
|
const EdgeDrawFlagInfo *b = bv;
|
|
|
|
|
|
|
|
if (a->noLen<b->noLen) return -1;
|
|
|
|
else if (a->noLen>b->noLen) return 1;
|
|
|
|
else return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-01-31 13:30:56 +00:00
|
|
|
static void edge_drawflags(Mesh *me, EditMesh *em)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
EditVert *eve;
|
|
|
|
EditEdge *eed, *e1, *e2, *e3, *e4;
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
/* - count number of times edges are used in faces: 0 en 1 time means draw edge
|
|
|
|
* - edges more than 1 time used: in *tmp.f is pointer to first face
|
|
|
|
* - check all faces, when normal differs to much: draw (flag becomes 1)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* later on: added flags for 'cylinder' and 'sphere' intersection tests in old
|
|
|
|
game engine (2.04)
|
|
|
|
*/
|
|
|
|
|
|
|
|
recalc_editnormals(em);
|
|
|
|
|
|
|
|
/* init */
|
|
|
|
eve= em->verts.first;
|
|
|
|
while(eve) {
|
|
|
|
eve->f1= 1; /* during test it's set at zero */
|
|
|
|
eve= eve->next;
|
|
|
|
}
|
|
|
|
eed= em->edges.first;
|
|
|
|
while(eed) {
|
|
|
|
eed->f2= eed->f1= 0;
|
|
|
|
eed->tmp.f = 0;
|
|
|
|
eed= eed->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
efa= em->faces.first;
|
|
|
|
while(efa) {
|
|
|
|
e1= efa->e1;
|
|
|
|
e2= efa->e2;
|
|
|
|
e3= efa->e3;
|
|
|
|
e4= efa->e4;
|
|
|
|
if(e1->f2<4) e1->f2+= 1;
|
|
|
|
if(e2->f2<4) e2->f2+= 1;
|
|
|
|
if(e3->f2<4) e3->f2+= 1;
|
|
|
|
if(e4 && e4->f2<4) e4->f2+= 1;
|
|
|
|
|
|
|
|
if(e1->tmp.f == 0) e1->tmp.f = (void *) efa;
|
|
|
|
if(e2->tmp.f == 0) e2->tmp.f = (void *) efa;
|
|
|
|
if(e3->tmp.f ==0) e3->tmp.f = (void *) efa;
|
|
|
|
if(e4 && (e4->tmp.f == 0)) e4->tmp.f = (void *) efa;
|
|
|
|
|
|
|
|
efa= efa->next;
|
|
|
|
}
|
|
|
|
|
2009-01-31 13:30:56 +00:00
|
|
|
if(me->drawflag & ME_ALLEDGES) {
|
2008-12-30 13:16:14 +00:00
|
|
|
efa= em->faces.first;
|
|
|
|
while(efa) {
|
|
|
|
if(efa->e1->f2>=2) efa->e1->f2= 1;
|
|
|
|
if(efa->e2->f2>=2) efa->e2->f2= 1;
|
|
|
|
if(efa->e3->f2>=2) efa->e3->f2= 1;
|
|
|
|
if(efa->e4 && efa->e4->f2>=2) efa->e4->f2= 1;
|
|
|
|
|
|
|
|
efa= efa->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
/* handle single-edges for 'test cylinder flag' (old engine) */
|
|
|
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
while(eed) {
|
|
|
|
if(eed->f2==1) eed->f1= 1;
|
|
|
|
eed= eed->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* all faces, all edges with flag==2: compare normal */
|
|
|
|
efa= em->faces.first;
|
|
|
|
while(efa) {
|
|
|
|
if(efa->e1->f2==2) edge_normal_compare(efa->e1, efa);
|
|
|
|
else efa->e1->f2= 1;
|
|
|
|
if(efa->e2->f2==2) edge_normal_compare(efa->e2, efa);
|
|
|
|
else efa->e2->f2= 1;
|
|
|
|
if(efa->e3->f2==2) edge_normal_compare(efa->e3, efa);
|
|
|
|
else efa->e3->f2= 1;
|
|
|
|
if(efa->e4) {
|
|
|
|
if(efa->e4->f2==2) edge_normal_compare(efa->e4, efa);
|
|
|
|
else efa->e4->f2= 1;
|
|
|
|
}
|
|
|
|
efa= efa->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sphere collision flag */
|
|
|
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
while(eed) {
|
|
|
|
if(eed->f1!=1) {
|
|
|
|
eed->v1->f1= eed->v2->f1= 0;
|
|
|
|
}
|
|
|
|
eed= eed->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* turns Mesh into editmesh */
|
2008-12-31 17:11:42 +00:00
|
|
|
void make_editMesh(Scene *scene, Object *ob)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2008-12-31 17:11:42 +00:00
|
|
|
Mesh *me= ob->data;
|
2008-12-30 13:16:14 +00:00
|
|
|
MFace *mface;
|
|
|
|
MVert *mvert;
|
|
|
|
MSelect *mselect;
|
|
|
|
KeyBlock *actkey;
|
2008-12-31 17:11:42 +00:00
|
|
|
EditMesh *em;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4;
|
2010-01-19 12:24:28 +00:00
|
|
|
EditFace *efa, *efa_last_sel= NULL;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditEdge *eed;
|
|
|
|
EditSelection *ese;
|
2009-10-22 09:31:07 +00:00
|
|
|
float *co, (*keyco)[3]= NULL;
|
2009-08-29 15:20:36 +00:00
|
|
|
int tot, a, eekadoodle= 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2008-12-31 17:11:42 +00:00
|
|
|
if(me->edit_mesh==NULL)
|
|
|
|
me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh");
|
|
|
|
else
|
|
|
|
/* because of reload */
|
|
|
|
free_editMesh(me->edit_mesh);
|
|
|
|
|
|
|
|
em= me->edit_mesh;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-06-23 00:41:55 +00:00
|
|
|
em->selectmode= scene->toolsettings->selectmode; // warning needs to be synced
|
2008-12-30 13:16:14 +00:00
|
|
|
em->act_face = NULL;
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totvert= tot= me->totvert;
|
|
|
|
em->totedge= me->totedge;
|
|
|
|
em->totface= me->totface;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
if(tot==0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-11-05 14:54:02 +00:00
|
|
|
if(ob->actcol > 0)
|
|
|
|
em->mat_nr= ob->actcol-1;
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* initialize fastmalloc for editmesh */
|
|
|
|
init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface);
|
|
|
|
|
2008-12-31 17:11:42 +00:00
|
|
|
actkey = ob_get_keyblock(ob);
|
2008-12-30 13:16:14 +00:00
|
|
|
if(actkey) {
|
|
|
|
/* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */
|
|
|
|
undo_editmode_clear();
|
2009-10-22 09:31:07 +00:00
|
|
|
keyco= actkey->data;
|
2009-10-22 17:12:28 +00:00
|
|
|
em->shapenr= ob->shapenr;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* make editverts */
|
|
|
|
CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
|
|
|
|
mvert= me->mvert;
|
|
|
|
|
|
|
|
evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist");
|
|
|
|
for(a=0; a<tot; a++, mvert++) {
|
|
|
|
|
2009-08-29 15:20:36 +00:00
|
|
|
co= mvert->co;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-10-15 13:33:56 +00:00
|
|
|
/* edit the shape key coordinate if available */
|
2009-10-22 09:31:07 +00:00
|
|
|
if(keyco && a < actkey->totelem)
|
|
|
|
co= keyco[a];
|
2009-10-15 13:33:56 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
eve= addvertlist(em, co, NULL);
|
|
|
|
evlist[a]= eve;
|
|
|
|
|
2009-10-15 13:33:56 +00:00
|
|
|
/* face select sets selection in next loop */
|
2009-08-15 19:48:50 +00:00
|
|
|
if(!paint_facesel_test(ob))
|
2008-12-30 13:16:14 +00:00
|
|
|
eve->f |= (mvert->flag & 1);
|
|
|
|
|
|
|
|
if (mvert->flag & ME_HIDE) eve->h= 1;
|
|
|
|
eve->no[0]= mvert->no[0]/32767.0;
|
|
|
|
eve->no[1]= mvert->no[1]/32767.0;
|
|
|
|
eve->no[2]= mvert->no[2]/32767.0;
|
|
|
|
|
|
|
|
eve->bweight= ((float)mvert->bweight)/255.0f;
|
|
|
|
|
|
|
|
/* lets overwrite the keyindex of the editvert
|
|
|
|
* with the order it used to be in before
|
|
|
|
* editmode
|
|
|
|
*/
|
|
|
|
eve->keyindex = a;
|
|
|
|
|
|
|
|
CustomData_to_em_block(&me->vdata, &em->vdata, a, &eve->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(actkey && actkey->totelem!=me->totvert);
|
|
|
|
else {
|
|
|
|
MEdge *medge= me->medge;
|
|
|
|
|
|
|
|
CustomData_copy(&me->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
|
|
|
|
/* make edges */
|
|
|
|
for(a=0; a<me->totedge; a++, medge++) {
|
|
|
|
eed= addedgelist(em, evlist[medge->v1], evlist[medge->v2], NULL);
|
|
|
|
/* eed can be zero when v1 and v2 are identical, dxf import does this... */
|
|
|
|
if(eed) {
|
|
|
|
eed->crease= ((float)medge->crease)/255.0f;
|
|
|
|
eed->bweight= ((float)medge->bweight)/255.0f;
|
|
|
|
|
|
|
|
if(medge->flag & ME_SEAM) eed->seam= 1;
|
|
|
|
if(medge->flag & ME_SHARP) eed->sharp = 1;
|
|
|
|
if(medge->flag & SELECT) eed->f |= SELECT;
|
|
|
|
if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
|
|
|
|
if(medge->flag & ME_HIDE) eed->h |= 1;
|
|
|
|
if(em->selectmode==SCE_SELECT_EDGE)
|
|
|
|
EM_select_edge(eed, eed->f & SELECT); // force edge selection to vertices, seems to be needed ...
|
|
|
|
CustomData_to_em_block(&me->edata,&em->edata, a, &eed->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomData_copy(&me->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
|
|
|
|
|
|
|
|
/* make faces */
|
|
|
|
mface= me->mface;
|
|
|
|
|
|
|
|
for(a=0; a<me->totface; a++, mface++) {
|
|
|
|
eve1= evlist[mface->v1];
|
|
|
|
eve2= evlist[mface->v2];
|
|
|
|
if(!mface->v3) eekadoodle= 1;
|
|
|
|
eve3= evlist[mface->v3];
|
|
|
|
if(mface->v4) eve4= evlist[mface->v4]; else eve4= NULL;
|
|
|
|
|
|
|
|
efa= addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL);
|
|
|
|
|
|
|
|
if(efa) {
|
|
|
|
CustomData_to_em_block(&me->fdata, &em->fdata, a, &efa->data);
|
|
|
|
|
|
|
|
efa->mat_nr= mface->mat_nr;
|
|
|
|
efa->flag= mface->flag & ~ME_HIDE;
|
|
|
|
|
|
|
|
/* select and hide face flag */
|
|
|
|
if(mface->flag & ME_HIDE) {
|
|
|
|
efa->h= 1;
|
|
|
|
} else {
|
|
|
|
if (a==me->act_face) {
|
|
|
|
EM_set_actFace(em, efa);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* dont allow hidden and selected */
|
|
|
|
if(mface->flag & ME_FACE_SEL) {
|
|
|
|
efa->f |= SELECT;
|
|
|
|
|
2009-08-15 19:48:50 +00:00
|
|
|
if(paint_facesel_test(ob)) {
|
2008-12-30 13:16:14 +00:00
|
|
|
EM_select_face(efa, 1); /* flush down */
|
|
|
|
}
|
2010-01-19 12:24:28 +00:00
|
|
|
|
|
|
|
efa_last_sel= efa;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-19 12:24:28 +00:00
|
|
|
if(EM_get_actFace(em, 0) && efa_last_sel) {
|
|
|
|
EM_set_actFace(em, efa_last_sel);
|
|
|
|
}
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
if(eekadoodle)
|
|
|
|
error("This Mesh has old style edgecodes, please put it in the bugtracker!");
|
|
|
|
|
|
|
|
MEM_freeN(evlist);
|
|
|
|
|
|
|
|
end_editmesh_fastmalloc(); // resets global function pointers
|
|
|
|
|
|
|
|
if(me->mselect){
|
|
|
|
//restore editselections
|
|
|
|
EM_init_index_arrays(em, 1,1,1);
|
|
|
|
mselect = me->mselect;
|
|
|
|
|
|
|
|
for(a=0; a<me->totselect; a++, mselect++){
|
|
|
|
/*check if recorded selection is still valid, if so copy into editmesh*/
|
|
|
|
if( (mselect->type == EDITVERT && me->mvert[mselect->index].flag & SELECT) || (mselect->type == EDITEDGE && me->medge[mselect->index].flag & SELECT) || (mselect->type == EDITFACE && me->mface[mselect->index].flag & ME_FACE_SEL) ){
|
|
|
|
ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
|
|
|
|
ese->type = mselect->type;
|
|
|
|
if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(mselect->index); else
|
|
|
|
if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(mselect->index); else
|
|
|
|
if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(mselect->index);
|
|
|
|
BLI_addtail(&(em->selected),ese);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EM_free_index_arrays();
|
|
|
|
}
|
|
|
|
/* this creates coherent selections. also needed for older files */
|
|
|
|
EM_selectmode_set(em);
|
|
|
|
/* paranoia check to enforce hide rules */
|
|
|
|
EM_hide_reset(em);
|
|
|
|
/* sets helper flags which arent saved */
|
|
|
|
EM_fgon_flags(em);
|
|
|
|
|
|
|
|
if (EM_get_actFace(em, 0)==NULL) {
|
|
|
|
EM_set_actFace(em, em->faces.first ); /* will use the first face, this is so we alwats have an active face */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* makes Mesh out of editmesh */
|
2008-12-31 17:11:42 +00:00
|
|
|
void load_editMesh(Scene *scene, Object *ob)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2008-12-31 17:11:42 +00:00
|
|
|
Mesh *me= ob->data;
|
2008-12-30 13:16:14 +00:00
|
|
|
MVert *mvert, *oldverts;
|
|
|
|
MEdge *medge;
|
|
|
|
MFace *mface;
|
|
|
|
MSelect *mselect;
|
2008-12-31 17:11:42 +00:00
|
|
|
EditMesh *em= me->edit_mesh;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditVert *eve;
|
|
|
|
EditFace *efa, *efa_act;
|
|
|
|
EditEdge *eed;
|
|
|
|
EditSelection *ese;
|
2009-08-29 15:20:36 +00:00
|
|
|
float *fp, *newkey, *oldkey, nor[3];
|
|
|
|
int i, a, ototvert;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* this one also tests of edges are not in faces: */
|
|
|
|
/* eed->f2==0: not in face, f2==1: draw it */
|
|
|
|
/* eed->f1 : flag for dynaface (cylindertest, old engine) */
|
|
|
|
/* eve->f1 : flag for dynaface (sphere test, old engine) */
|
|
|
|
/* eve->f2 : being used in vertexnormals */
|
2009-01-31 13:30:56 +00:00
|
|
|
edge_drawflags(me, em);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-15 15:01:39 +00:00
|
|
|
EM_stats_update(em);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* new Vertex block */
|
2009-01-15 15:01:39 +00:00
|
|
|
if(em->totvert==0) mvert= NULL;
|
|
|
|
else mvert= MEM_callocN(em->totvert*sizeof(MVert), "loadeditMesh vert");
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* new Edge block */
|
2009-01-15 15:01:39 +00:00
|
|
|
if(em->totedge==0) medge= NULL;
|
|
|
|
else medge= MEM_callocN(em->totedge*sizeof(MEdge), "loadeditMesh edge");
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* new Face block */
|
2009-01-15 15:01:39 +00:00
|
|
|
if(em->totface==0) mface= NULL;
|
|
|
|
else mface= MEM_callocN(em->totface*sizeof(MFace), "loadeditMesh face");
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* lets save the old verts just in case we are actually working on
|
|
|
|
* a key ... we now do processing of the keys at the end */
|
|
|
|
oldverts= me->mvert;
|
|
|
|
ototvert= me->totvert;
|
|
|
|
|
|
|
|
/* don't free this yet */
|
|
|
|
CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
|
|
|
|
|
|
|
|
/* free custom data */
|
|
|
|
CustomData_free(&me->vdata, me->totvert);
|
|
|
|
CustomData_free(&me->edata, me->totedge);
|
|
|
|
CustomData_free(&me->fdata, me->totface);
|
|
|
|
|
|
|
|
/* add new custom data */
|
2009-01-15 15:01:39 +00:00
|
|
|
me->totvert= em->totvert;
|
|
|
|
me->totedge= em->totedge;
|
|
|
|
me->totface= em->totface;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
CustomData_copy(&em->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
|
|
|
|
CustomData_copy(&em->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
|
|
|
|
CustomData_copy(&em->fdata, &me->fdata, CD_MASK_MESH, CD_CALLOC, me->totface);
|
|
|
|
|
|
|
|
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
|
|
|
|
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
|
|
|
|
CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface);
|
|
|
|
mesh_update_customdata_pointers(me);
|
|
|
|
|
|
|
|
/* the vertices, use ->tmp.l as counter */
|
|
|
|
eve= em->verts.first;
|
|
|
|
a= 0;
|
|
|
|
|
|
|
|
while(eve) {
|
2009-08-29 15:20:36 +00:00
|
|
|
VECCOPY(mvert->co, eve->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-07-13 00:40:20 +00:00
|
|
|
mvert->mat_nr= 32767; /* what was this for, halos? */
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* vertex normal */
|
|
|
|
VECCOPY(nor, eve->no);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(nor, 32767.0);
|
2008-12-30 13:16:14 +00:00
|
|
|
VECCOPY(mvert->no, nor);
|
|
|
|
|
|
|
|
/* note: it used to remove me->dvert when it was not in use, cancelled
|
|
|
|
that... annoying when you have a fresh vgroup */
|
|
|
|
CustomData_from_em_block(&em->vdata, &me->vdata, eve->data, a);
|
|
|
|
|
|
|
|
eve->tmp.l = a++; /* counter */
|
|
|
|
|
|
|
|
mvert->flag= 0;
|
|
|
|
mvert->flag |= (eve->f & SELECT);
|
|
|
|
if (eve->h) mvert->flag |= ME_HIDE;
|
2009-01-31 13:30:56 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
mvert->bweight= (char)(255.0*eve->bweight);
|
|
|
|
|
|
|
|
eve= eve->next;
|
|
|
|
mvert++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the edges */
|
|
|
|
a= 0;
|
|
|
|
eed= em->edges.first;
|
|
|
|
while(eed) {
|
|
|
|
medge->v1= (unsigned int) eed->v1->tmp.l;
|
|
|
|
medge->v2= (unsigned int) eed->v2->tmp.l;
|
|
|
|
|
|
|
|
medge->flag= (eed->f & SELECT) | ME_EDGERENDER;
|
|
|
|
if(eed->f2<2) medge->flag |= ME_EDGEDRAW;
|
|
|
|
if(eed->f2==0) medge->flag |= ME_LOOSEEDGE;
|
|
|
|
if(eed->sharp) medge->flag |= ME_SHARP;
|
|
|
|
if(eed->seam) medge->flag |= ME_SEAM;
|
|
|
|
if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes
|
|
|
|
if(eed->h & 1) medge->flag |= ME_HIDE;
|
|
|
|
|
|
|
|
medge->crease= (char)(255.0*eed->crease);
|
|
|
|
medge->bweight= (char)(255.0*eed->bweight);
|
|
|
|
CustomData_from_em_block(&em->edata, &me->edata, eed->data, a);
|
|
|
|
|
|
|
|
eed->tmp.l = a++;
|
|
|
|
|
|
|
|
medge++;
|
|
|
|
eed= eed->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the faces */
|
|
|
|
a = 0;
|
|
|
|
efa= em->faces.first;
|
|
|
|
efa_act= EM_get_actFace(em, 0);
|
|
|
|
i = 0;
|
|
|
|
me->act_face = -1;
|
|
|
|
while(efa) {
|
|
|
|
mface= &((MFace *) me->mface)[i];
|
|
|
|
|
|
|
|
mface->v1= (unsigned int) efa->v1->tmp.l;
|
|
|
|
mface->v2= (unsigned int) efa->v2->tmp.l;
|
|
|
|
mface->v3= (unsigned int) efa->v3->tmp.l;
|
|
|
|
if (efa->v4) mface->v4 = (unsigned int) efa->v4->tmp.l;
|
|
|
|
|
|
|
|
mface->mat_nr= efa->mat_nr;
|
|
|
|
|
|
|
|
mface->flag= efa->flag;
|
|
|
|
/* bit 0 of flag is already taken for smooth... */
|
|
|
|
|
|
|
|
if(efa->h) {
|
|
|
|
mface->flag |= ME_HIDE;
|
|
|
|
mface->flag &= ~ME_FACE_SEL;
|
|
|
|
} else {
|
|
|
|
if(efa->f & 1) mface->flag |= ME_FACE_SEL;
|
|
|
|
else mface->flag &= ~ME_FACE_SEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* mat_nr in vertex */
|
|
|
|
if(me->totcol>1) {
|
|
|
|
mvert= me->mvert+mface->v1;
|
2009-07-13 00:40:20 +00:00
|
|
|
if(mvert->mat_nr == (char)32767) mvert->mat_nr= mface->mat_nr;
|
2008-12-30 13:16:14 +00:00
|
|
|
mvert= me->mvert+mface->v2;
|
2009-07-13 00:40:20 +00:00
|
|
|
if(mvert->mat_nr == (char)32767) mvert->mat_nr= mface->mat_nr;
|
2008-12-30 13:16:14 +00:00
|
|
|
mvert= me->mvert+mface->v3;
|
2009-07-13 00:40:20 +00:00
|
|
|
if(mvert->mat_nr == (char)32767) mvert->mat_nr= mface->mat_nr;
|
2008-12-30 13:16:14 +00:00
|
|
|
if(mface->v4) {
|
|
|
|
mvert= me->mvert+mface->v4;
|
2009-07-13 00:40:20 +00:00
|
|
|
if(mvert->mat_nr == (char)32767) mvert->mat_nr= mface->mat_nr;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* watch: efa->e1->f2==0 means loose edge */
|
|
|
|
|
|
|
|
if(efa->e1->f2==1) {
|
|
|
|
efa->e1->f2= 2;
|
|
|
|
}
|
|
|
|
if(efa->e2->f2==1) {
|
|
|
|
efa->e2->f2= 2;
|
|
|
|
}
|
|
|
|
if(efa->e3->f2==1) {
|
|
|
|
efa->e3->f2= 2;
|
|
|
|
}
|
|
|
|
if(efa->e4 && efa->e4->f2==1) {
|
|
|
|
efa->e4->f2= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomData_from_em_block(&em->fdata, &me->fdata, efa->data, i);
|
|
|
|
|
|
|
|
/* no index '0' at location 3 or 4 */
|
|
|
|
test_index_face(mface, &me->fdata, i, efa->v4?4:3);
|
|
|
|
|
|
|
|
if (efa_act == efa)
|
|
|
|
me->act_face = a;
|
|
|
|
|
|
|
|
efa->tmp.l = a++;
|
|
|
|
i++;
|
|
|
|
efa= efa->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* patch hook indices and vertex parents */
|
|
|
|
{
|
|
|
|
Object *ob;
|
|
|
|
ModifierData *md;
|
|
|
|
EditVert **vertMap = NULL;
|
|
|
|
int i,j;
|
|
|
|
|
|
|
|
for (ob=G.main->object.first; ob; ob=ob->id.next) {
|
2008-12-31 17:11:42 +00:00
|
|
|
if (ob->parent==ob && ELEM(ob->partype, PARVERT1,PARVERT3)) {
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* duplicate code from below, make it function later...? */
|
|
|
|
if (!vertMap) {
|
|
|
|
vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
|
|
|
|
|
|
|
|
for (eve=em->verts.first; eve; eve=eve->next) {
|
|
|
|
if (eve->keyindex!=-1)
|
|
|
|
vertMap[eve->keyindex] = eve;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(ob->par1 < ototvert) {
|
|
|
|
eve = vertMap[ob->par1];
|
|
|
|
if(eve) ob->par1= eve->tmp.l;
|
|
|
|
}
|
|
|
|
if(ob->par2 < ototvert) {
|
|
|
|
eve = vertMap[ob->par2];
|
|
|
|
if(eve) ob->par2= eve->tmp.l;
|
|
|
|
}
|
|
|
|
if(ob->par3 < ototvert) {
|
|
|
|
eve = vertMap[ob->par3];
|
|
|
|
if(eve) ob->par3= eve->tmp.l;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if (ob->data==me) {
|
|
|
|
for (md=ob->modifiers.first; md; md=md->next) {
|
|
|
|
if (md->type==eModifierType_Hook) {
|
|
|
|
HookModifierData *hmd = (HookModifierData*) md;
|
|
|
|
|
|
|
|
if (!vertMap) {
|
|
|
|
vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
|
|
|
|
|
|
|
|
for (eve=em->verts.first; eve; eve=eve->next) {
|
|
|
|
if (eve->keyindex!=-1)
|
|
|
|
vertMap[eve->keyindex] = eve;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=j=0; i<hmd->totindex; i++) {
|
|
|
|
if(hmd->indexar[i] < ototvert) {
|
|
|
|
eve = vertMap[hmd->indexar[i]];
|
|
|
|
|
|
|
|
if (eve) {
|
|
|
|
hmd->indexar[j++] = eve->tmp.l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
hmd->totindex = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vertMap) MEM_freeN(vertMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* are there keys? */
|
|
|
|
if(me->key) {
|
2009-10-22 17:12:28 +00:00
|
|
|
KeyBlock *currkey;
|
|
|
|
KeyBlock *actkey= BLI_findlink(&me->key->block, em->shapenr-1);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* Lets reorder the key data so that things line up roughly
|
|
|
|
* with the way things were before editmode */
|
|
|
|
currkey = me->key->block.first;
|
|
|
|
while(currkey) {
|
|
|
|
|
2009-01-15 15:01:39 +00:00
|
|
|
fp= newkey= MEM_callocN(me->key->elemsize*em->totvert, "currkey->data");
|
2008-12-30 13:16:14 +00:00
|
|
|
oldkey = currkey->data;
|
|
|
|
|
|
|
|
eve= em->verts.first;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
mvert = me->mvert;
|
|
|
|
while(eve) {
|
|
|
|
if (eve->keyindex >= 0 && eve->keyindex < currkey->totelem) { // valid old vertex
|
|
|
|
if(currkey == actkey) {
|
2009-10-22 09:31:07 +00:00
|
|
|
if(actkey == me->key->refkey) {
|
2008-12-30 13:16:14 +00:00
|
|
|
VECCOPY(fp, mvert->co);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VECCOPY(fp, mvert->co);
|
|
|
|
if(oldverts) {
|
|
|
|
VECCOPY(mvert->co, oldverts[eve->keyindex].co);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(oldkey) {
|
|
|
|
VECCOPY(fp, oldkey + 3 * eve->keyindex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VECCOPY(fp, mvert->co);
|
|
|
|
}
|
|
|
|
fp+= 3;
|
|
|
|
++i;
|
|
|
|
++mvert;
|
|
|
|
eve= eve->next;
|
|
|
|
}
|
2009-01-15 15:01:39 +00:00
|
|
|
currkey->totelem= em->totvert;
|
2008-12-30 13:16:14 +00:00
|
|
|
if(currkey->data) MEM_freeN(currkey->data);
|
|
|
|
currkey->data = newkey;
|
|
|
|
|
|
|
|
currkey= currkey->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(oldverts) MEM_freeN(oldverts);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
for(ese=em->selected.first; ese; ese=ese->next) i++;
|
|
|
|
me->totselect = i;
|
|
|
|
if(i==0) mselect= NULL;
|
|
|
|
else mselect= MEM_callocN(i*sizeof(MSelect), "loadeditMesh selections");
|
|
|
|
|
|
|
|
if(me->mselect) MEM_freeN(me->mselect);
|
|
|
|
me->mselect= mselect;
|
|
|
|
|
|
|
|
for(ese=em->selected.first; ese; ese=ese->next){
|
|
|
|
mselect->type = ese->type;
|
|
|
|
if(ese->type == EDITVERT) mselect->index = ((EditVert*)ese->data)->tmp.l;
|
|
|
|
else if(ese->type == EDITEDGE) mselect->index = ((EditEdge*)ese->data)->tmp.l;
|
|
|
|
else if(ese->type == EDITFACE) mselect->index = ((EditFace*)ese->data)->tmp.l;
|
|
|
|
mselect++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* to be sure: clear ->tmp.l pointers */
|
|
|
|
eve= em->verts.first;
|
|
|
|
while(eve) {
|
|
|
|
eve->tmp.l = 0;
|
|
|
|
eve= eve->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
while(eed) {
|
|
|
|
eed->tmp.l = 0;
|
|
|
|
eed= eed->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
efa= em->faces.first;
|
|
|
|
while(efa) {
|
|
|
|
efa->tmp.l = 0;
|
|
|
|
efa= efa->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remake softbody of all users */
|
|
|
|
if(me->id.us>1) {
|
|
|
|
Base *base;
|
|
|
|
for(base= scene->base.first; base; base= base->next)
|
|
|
|
if(base->object->data==me)
|
|
|
|
base->object->recalc |= OB_RECALC_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
|
|
|
|
}
|
|
|
|
|
2008-12-31 17:11:42 +00:00
|
|
|
void remake_editMesh(Scene *scene, Object *ob)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2008-12-31 17:11:42 +00:00
|
|
|
make_editMesh(scene, ob);
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
2008-12-30 13:16:14 +00:00
|
|
|
BIF_undo_push("Undo all changes");
|
|
|
|
}
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* *************** Operator: separate parts *************/
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
static EnumPropertyItem prop_separate_types[] = {
|
2009-06-16 00:52:21 +00:00
|
|
|
{0, "SELECTED", 0, "Selection", ""},
|
|
|
|
{1, "MATERIAL", 0, "By Material", ""},
|
|
|
|
{2, "LOOSE", 0, "By loose parts", ""},
|
|
|
|
{0, NULL, 0, NULL, NULL}
|
2009-01-30 15:01:14 +00:00
|
|
|
};
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* return 1: success */
|
|
|
|
static int mesh_separate_selected(Scene *scene, Base *editbase)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-30 15:01:14 +00:00
|
|
|
EditMesh *em, *emnew;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditVert *eve, *v1;
|
|
|
|
EditEdge *eed, *e1;
|
2009-01-30 15:01:14 +00:00
|
|
|
EditFace *efa, *f1;
|
|
|
|
Object *obedit;
|
|
|
|
Mesh *me, *menew;
|
|
|
|
Base *basenew;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
if(editbase==NULL) return 0;
|
|
|
|
|
|
|
|
obedit= editbase->object;
|
2009-01-02 19:10:35 +00:00
|
|
|
me= obedit->data;
|
2009-04-11 08:26:51 +00:00
|
|
|
em= BKE_mesh_get_editmesh(me);
|
2008-12-30 13:16:14 +00:00
|
|
|
if(me->key) {
|
|
|
|
error("Can't separate with vertex keys");
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-30 15:01:14 +00:00
|
|
|
return 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
if(em->selected.first)
|
|
|
|
BLI_freelistN(&(em->selected)); /* clear the selection order */
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-04-15 15:40:31 +00:00
|
|
|
EM_selectmode_set(em); // enforce full consistent selection flags
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
EM_stats_update(em);
|
|
|
|
|
2009-03-30 07:28:37 +00:00
|
|
|
if(em->totvertsel==0) {
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-03-30 07:28:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2009-01-30 15:01:14 +00:00
|
|
|
|
|
|
|
/* we are going to work as follows:
|
|
|
|
* 1. add a linked duplicate object: this will be the new one, we remember old pointer
|
|
|
|
* 2. give new object empty mesh and put in editmode
|
|
|
|
* 3: do a split if needed on current editmesh.
|
|
|
|
* 4. copy over: all NOT selected verts, edges, faces
|
|
|
|
* 5. call load_editMesh() on the new object
|
2008-12-30 13:16:14 +00:00
|
|
|
*/
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* 1 */
|
|
|
|
basenew= ED_object_add_duplicate(scene, editbase, 0); /* 0 = fully linked */
|
|
|
|
ED_base_object_select(basenew, BA_DESELECT);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* 2 */
|
2009-10-09 21:45:14 +00:00
|
|
|
basenew->object->data= menew= add_mesh(me->id.name+2); /* empty */
|
2009-10-08 09:22:39 +00:00
|
|
|
assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
|
2009-01-30 15:01:14 +00:00
|
|
|
me->id.us--;
|
|
|
|
make_editMesh(scene, basenew->object);
|
|
|
|
emnew= menew->edit_mesh;
|
2009-10-09 21:45:14 +00:00
|
|
|
CustomData_copy(&em->vdata, &emnew->vdata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
|
|
|
|
CustomData_copy(&em->edata, &emnew->edata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
|
|
|
|
CustomData_copy(&em->fdata, &emnew->fdata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
|
2009-01-30 15:01:14 +00:00
|
|
|
|
|
|
|
/* 3 */
|
2008-12-30 13:16:14 +00:00
|
|
|
/* SPLIT: first make duplicate */
|
|
|
|
adduplicateflag(em, SELECT);
|
|
|
|
/* SPLIT: old faces have 3x flag 128 set, delete these ones */
|
|
|
|
delfaceflag(em, 128);
|
|
|
|
/* since we do tricky things with verts/edges/faces, this makes sure all is selected coherent */
|
|
|
|
EM_selectmode_set(em);
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* 4 */
|
|
|
|
/* move over: everything that is selected */
|
|
|
|
for(eve= em->verts.first; eve; eve= v1) {
|
2008-12-30 13:16:14 +00:00
|
|
|
v1= eve->next;
|
2009-01-30 15:01:14 +00:00
|
|
|
if(eve->f & SELECT) {
|
2008-12-30 13:16:14 +00:00
|
|
|
BLI_remlink(&em->verts, eve);
|
2009-01-30 15:01:14 +00:00
|
|
|
BLI_addtail(&emnew->verts, eve);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-30 15:01:14 +00:00
|
|
|
|
|
|
|
for(eed= em->edges.first; eed; eed= e1) {
|
2008-12-30 13:16:14 +00:00
|
|
|
e1= eed->next;
|
2009-01-30 15:01:14 +00:00
|
|
|
if(eed->f & SELECT) {
|
2008-12-30 13:16:14 +00:00
|
|
|
BLI_remlink(&em->edges, eed);
|
2009-01-30 15:01:14 +00:00
|
|
|
BLI_addtail(&emnew->edges, eed);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-30 15:01:14 +00:00
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= f1) {
|
|
|
|
f1= efa->next;
|
2008-12-30 13:16:14 +00:00
|
|
|
if (efa == em->act_face && (efa->f & SELECT)) {
|
|
|
|
EM_set_actFace(em, NULL);
|
|
|
|
}
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
if(efa->f & SELECT) {
|
2008-12-30 13:16:14 +00:00
|
|
|
BLI_remlink(&em->faces, efa);
|
2009-01-30 15:01:14 +00:00
|
|
|
BLI_addtail(&emnew->faces, efa);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-30 15:01:14 +00:00
|
|
|
|
|
|
|
/* 5 */
|
|
|
|
load_editMesh(scene, basenew->object);
|
|
|
|
free_editMesh(emnew);
|
2009-10-09 21:45:14 +00:00
|
|
|
MEM_freeN(menew->edit_mesh);
|
|
|
|
menew->edit_mesh= NULL;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* hashedges are invalid now, make new! */
|
2008-12-30 13:16:14 +00:00
|
|
|
editMesh_set_hash(em);
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(&obedit->id, OB_RECALC_DATA);
|
|
|
|
DAG_id_flush_update(&basenew->object->id, OB_RECALC_DATA);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
return 1;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* return 1: success */
|
|
|
|
static int mesh_separate_material(Scene *scene, Base *editbase)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-30 15:01:14 +00:00
|
|
|
Mesh *me= editbase->object->data;
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(me);
|
2008-12-31 17:11:42 +00:00
|
|
|
unsigned char curr_mat;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
for (curr_mat = 1; curr_mat < editbase->object->totcol; ++curr_mat) {
|
|
|
|
/* clear selection, we're going to use that to select material group */
|
|
|
|
EM_clear_flag_all(em, SELECT);
|
|
|
|
/* select the material */
|
2009-06-24 14:07:48 +00:00
|
|
|
EM_select_by_material(em, curr_mat);
|
2009-01-30 15:01:14 +00:00
|
|
|
/* and now separate */
|
2009-03-30 07:28:37 +00:00
|
|
|
if(0==mesh_separate_selected(scene, editbase)) {
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-30 15:01:14 +00:00
|
|
|
return 0;
|
2009-03-30 07:28:37 +00:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-30 15:01:14 +00:00
|
|
|
return 1;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* return 1: success */
|
|
|
|
static int mesh_separate_loose(Scene *scene, Base *editbase)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-30 15:01:14 +00:00
|
|
|
Mesh *me;
|
|
|
|
EditMesh *em;
|
|
|
|
int doit= 1;
|
|
|
|
|
|
|
|
me= editbase->object->data;
|
2009-04-11 08:26:51 +00:00
|
|
|
em= BKE_mesh_get_editmesh(me);
|
2009-01-30 15:01:14 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
if(me->key) {
|
2009-01-30 15:01:14 +00:00
|
|
|
error("Can't separate with vertex keys");
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-30 15:01:14 +00:00
|
|
|
return 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-01-30 15:01:14 +00:00
|
|
|
|
|
|
|
EM_clear_flag_all(em, SELECT);
|
|
|
|
|
|
|
|
while(doit && em->verts.first) {
|
2008-12-30 13:16:14 +00:00
|
|
|
/* Select a random vert to start with */
|
2009-01-30 15:01:14 +00:00
|
|
|
EditVert *eve= em->verts.first;
|
2008-12-30 13:16:14 +00:00
|
|
|
eve->f |= SELECT;
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
selectconnected_mesh_all(em);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2010-01-30 19:42:03 +00:00
|
|
|
/* don't separate the very last part */
|
|
|
|
for(eve=em->verts.first; eve; eve= eve->next)
|
|
|
|
if((eve->f & SELECT)==0) break;
|
|
|
|
if(eve==NULL) break;
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* and now separate */
|
|
|
|
doit= mesh_separate_selected(scene, editbase);
|
|
|
|
}
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-30 15:01:14 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
static int mesh_separate_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
Base *base= CTX_data_active_base(C);
|
RNA
* Enums can now be dynamically created in the _itemf callback,
using RNA_enum_item(s)_add, RNA_enum_item_end. All places asking
for enum items now need to potentially free the items.
* This callback now also gets context, this was added specifically
for operators. This doesn't fit design well at all, needed to do
some ugly hacks, but can't find a good solution at the moment.
* All enums must have a default list of items too, even with an
_itemf callback, for docs and fallback in case there is no context.
* Used by MESH_OT_merge, MESH_OT_select_similar, TFM_OT_select_orientation.
* Also changes some operator properties that were enums to booleas
(unselected, deselect), to make them consistent with other ops.
2009-07-10 19:56:13 +00:00
|
|
|
int retval= 0, type= RNA_enum_get(op->ptr, "type");
|
2009-01-30 15:01:14 +00:00
|
|
|
|
RNA
* Enums can now be dynamically created in the _itemf callback,
using RNA_enum_item(s)_add, RNA_enum_item_end. All places asking
for enum items now need to potentially free the items.
* This callback now also gets context, this was added specifically
for operators. This doesn't fit design well at all, needed to do
some ugly hacks, but can't find a good solution at the moment.
* All enums must have a default list of items too, even with an
_itemf callback, for docs and fallback in case there is no context.
* Used by MESH_OT_merge, MESH_OT_select_similar, TFM_OT_select_orientation.
* Also changes some operator properties that were enums to booleas
(unselected, deselect), to make them consistent with other ops.
2009-07-10 19:56:13 +00:00
|
|
|
if(type == 0)
|
2009-01-30 15:01:14 +00:00
|
|
|
retval= mesh_separate_selected(scene, base);
|
RNA
* Enums can now be dynamically created in the _itemf callback,
using RNA_enum_item(s)_add, RNA_enum_item_end. All places asking
for enum items now need to potentially free the items.
* This callback now also gets context, this was added specifically
for operators. This doesn't fit design well at all, needed to do
some ugly hacks, but can't find a good solution at the moment.
* All enums must have a default list of items too, even with an
_itemf callback, for docs and fallback in case there is no context.
* Used by MESH_OT_merge, MESH_OT_select_similar, TFM_OT_select_orientation.
* Also changes some operator properties that were enums to booleas
(unselected, deselect), to make them consistent with other ops.
2009-07-10 19:56:13 +00:00
|
|
|
else if(type == 1)
|
2009-01-30 15:01:14 +00:00
|
|
|
retval= mesh_separate_material (scene, base);
|
RNA
* Enums can now be dynamically created in the _itemf callback,
using RNA_enum_item(s)_add, RNA_enum_item_end. All places asking
for enum items now need to potentially free the items.
* This callback now also gets context, this was added specifically
for operators. This doesn't fit design well at all, needed to do
some ugly hacks, but can't find a good solution at the moment.
* All enums must have a default list of items too, even with an
_itemf callback, for docs and fallback in case there is no context.
* Used by MESH_OT_merge, MESH_OT_select_similar, TFM_OT_select_orientation.
* Also changes some operator properties that were enums to booleas
(unselected, deselect), to make them consistent with other ops.
2009-07-10 19:56:13 +00:00
|
|
|
else if(type == 2)
|
2009-01-30 15:01:14 +00:00
|
|
|
retval= mesh_separate_loose(scene, base);
|
|
|
|
|
|
|
|
if(retval) {
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
|
2009-01-30 15:01:14 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-01-30 15:01:14 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
void MESH_OT_separate(wmOperatorType *ot)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-30 15:01:14 +00:00
|
|
|
/* identifiers */
|
2009-07-08 21:31:28 +00:00
|
|
|
ot->name= "Separate";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Separate selected geometry into a new mesh.";
|
2009-01-30 15:01:14 +00:00
|
|
|
ot->idname= "MESH_OT_separate";
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-30 15:01:14 +00:00
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke= WM_menu_invoke;
|
|
|
|
ot->exec= mesh_separate_exec;
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
/* flags */
|
2009-01-31 19:40:40 +00:00
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-30 15:01:14 +00:00
|
|
|
|
2010-01-15 22:40:33 +00:00
|
|
|
ot->prop= RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ******************************************** */
|
|
|
|
|
|
|
|
/* *************** UNDO ***************************** */
|
|
|
|
/* new mesh undo, based on pushing editmesh data itself */
|
|
|
|
/* reuses same code as for global and curve undo... unify that (ton) */
|
|
|
|
|
|
|
|
/* only one 'hack', to save memory it doesn't store the first push, but does a remake editmesh */
|
|
|
|
|
|
|
|
/* a compressed version of editmesh data */
|
|
|
|
|
|
|
|
typedef struct EditVertC
|
|
|
|
{
|
|
|
|
float no[3];
|
|
|
|
float co[3];
|
|
|
|
unsigned char f, h;
|
|
|
|
short bweight;
|
|
|
|
int keyindex;
|
|
|
|
} EditVertC;
|
|
|
|
|
|
|
|
typedef struct EditEdgeC
|
|
|
|
{
|
|
|
|
int v1, v2;
|
|
|
|
unsigned char f, h, seam, sharp, pad;
|
|
|
|
short crease, bweight, fgoni;
|
|
|
|
} EditEdgeC;
|
|
|
|
|
|
|
|
typedef struct EditFaceC
|
|
|
|
{
|
|
|
|
int v1, v2, v3, v4;
|
2009-07-13 00:40:20 +00:00
|
|
|
unsigned char flag, f, h, fgonf, pad1;
|
|
|
|
short mat_nr;
|
2008-12-30 13:16:14 +00:00
|
|
|
} EditFaceC;
|
|
|
|
|
|
|
|
typedef struct EditSelectionC{
|
|
|
|
short type;
|
|
|
|
int index;
|
|
|
|
}EditSelectionC;
|
|
|
|
|
|
|
|
typedef struct UndoMesh {
|
|
|
|
EditVertC *verts;
|
|
|
|
EditEdgeC *edges;
|
|
|
|
EditFaceC *faces;
|
|
|
|
EditSelectionC *selected;
|
|
|
|
int totvert, totedge, totface, totsel;
|
2010-01-26 17:39:45 +00:00
|
|
|
int selectmode, shapenr;
|
2008-12-30 13:16:14 +00:00
|
|
|
RetopoPaintData *retopo_paint_data;
|
|
|
|
char retopo_mode;
|
|
|
|
CustomData vdata, edata, fdata;
|
|
|
|
} UndoMesh;
|
|
|
|
|
|
|
|
/* for callbacks */
|
|
|
|
|
|
|
|
static void free_undoMesh(void *umv)
|
|
|
|
{
|
|
|
|
UndoMesh *um= umv;
|
|
|
|
|
|
|
|
if(um->verts) MEM_freeN(um->verts);
|
|
|
|
if(um->edges) MEM_freeN(um->edges);
|
|
|
|
if(um->faces) MEM_freeN(um->faces);
|
|
|
|
if(um->selected) MEM_freeN(um->selected);
|
|
|
|
// XXX if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data);
|
|
|
|
CustomData_free(&um->vdata, um->totvert);
|
|
|
|
CustomData_free(&um->edata, um->totedge);
|
|
|
|
CustomData_free(&um->fdata, um->totface);
|
|
|
|
MEM_freeN(um);
|
|
|
|
}
|
|
|
|
|
2009-01-01 13:15:35 +00:00
|
|
|
static void *editMesh_to_undoMesh(void *emv)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-01 13:15:35 +00:00
|
|
|
EditMesh *em= (EditMesh *)emv;
|
2008-12-30 13:16:14 +00:00
|
|
|
UndoMesh *um;
|
|
|
|
EditVert *eve;
|
|
|
|
EditEdge *eed;
|
|
|
|
EditFace *efa;
|
|
|
|
EditSelection *ese;
|
|
|
|
EditVertC *evec=NULL;
|
|
|
|
EditEdgeC *eedc=NULL;
|
|
|
|
EditFaceC *efac=NULL;
|
|
|
|
EditSelectionC *esec=NULL;
|
|
|
|
int a;
|
2009-01-01 13:15:35 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
um= MEM_callocN(sizeof(UndoMesh), "undomesh");
|
|
|
|
|
2008-12-31 17:11:42 +00:00
|
|
|
um->selectmode = em->selectmode;
|
2010-01-26 17:39:45 +00:00
|
|
|
um->shapenr = em->shapenr;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
for(eve=em->verts.first; eve; eve= eve->next) um->totvert++;
|
|
|
|
for(eed=em->edges.first; eed; eed= eed->next) um->totedge++;
|
|
|
|
for(efa=em->faces.first; efa; efa= efa->next) um->totface++;
|
|
|
|
for(ese=em->selected.first; ese; ese=ese->next) um->totsel++;
|
|
|
|
/* malloc blocks */
|
|
|
|
|
|
|
|
if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC");
|
|
|
|
if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC");
|
|
|
|
if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC");
|
|
|
|
if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections");
|
|
|
|
|
|
|
|
if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert);
|
|
|
|
if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge);
|
|
|
|
if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface);
|
|
|
|
|
|
|
|
/* now copy vertices */
|
|
|
|
a = 0;
|
|
|
|
for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) {
|
|
|
|
VECCOPY(evec->co, eve->co);
|
|
|
|
VECCOPY(evec->no, eve->no);
|
|
|
|
|
|
|
|
evec->f= eve->f;
|
|
|
|
evec->h= eve->h;
|
|
|
|
evec->keyindex= eve->keyindex;
|
|
|
|
eve->tmp.l = a; /*store index*/
|
|
|
|
evec->bweight= (short)(eve->bweight*255.0);
|
|
|
|
|
|
|
|
CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy edges */
|
|
|
|
a = 0;
|
|
|
|
for(eed=em->edges.first; eed; eed= eed->next, eedc++, a++) {
|
|
|
|
eedc->v1= (int)eed->v1->tmp.l;
|
|
|
|
eedc->v2= (int)eed->v2->tmp.l;
|
|
|
|
eedc->f= eed->f;
|
|
|
|
eedc->h= eed->h;
|
|
|
|
eedc->seam= eed->seam;
|
|
|
|
eedc->sharp= eed->sharp;
|
|
|
|
eedc->crease= (short)(eed->crease*255.0);
|
|
|
|
eedc->bweight= (short)(eed->bweight*255.0);
|
|
|
|
eedc->fgoni= eed->fgoni;
|
|
|
|
eed->tmp.l = a; /*store index*/
|
|
|
|
CustomData_from_em_block(&em->edata, &um->edata, eed->data, a);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy faces */
|
|
|
|
a = 0;
|
|
|
|
for(efa=em->faces.first; efa; efa= efa->next, efac++, a++) {
|
|
|
|
efac->v1= (int)efa->v1->tmp.l;
|
|
|
|
efac->v2= (int)efa->v2->tmp.l;
|
|
|
|
efac->v3= (int)efa->v3->tmp.l;
|
|
|
|
if(efa->v4) efac->v4= (int)efa->v4->tmp.l;
|
|
|
|
else efac->v4= -1;
|
|
|
|
|
|
|
|
efac->mat_nr= efa->mat_nr;
|
|
|
|
efac->flag= efa->flag;
|
|
|
|
efac->f= efa->f;
|
|
|
|
efac->h= efa->h;
|
|
|
|
efac->fgonf= efa->fgonf;
|
|
|
|
|
|
|
|
efa->tmp.l = a; /*store index*/
|
|
|
|
|
|
|
|
CustomData_from_em_block(&em->fdata, &um->fdata, efa->data, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
a = 0;
|
|
|
|
for(ese=em->selected.first; ese; ese=ese->next, esec++){
|
|
|
|
esec->type = ese->type;
|
|
|
|
if(ese->type == EDITVERT) a = esec->index = ((EditVert*)ese->data)->tmp.l;
|
|
|
|
else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l;
|
|
|
|
else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data);
|
2009-01-01 13:15:35 +00:00
|
|
|
// um->retopo_mode= scene->toolsettings->retopo_mode;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
return um;
|
|
|
|
}
|
|
|
|
|
2009-01-01 13:15:35 +00:00
|
|
|
static void undoMesh_to_editMesh(void *umv, void *emv)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-01 13:15:35 +00:00
|
|
|
EditMesh *em= (EditMesh *)emv;
|
|
|
|
UndoMesh *um= (UndoMesh *)umv;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditVert *eve, **evar=NULL;
|
|
|
|
EditEdge *eed;
|
|
|
|
EditFace *efa;
|
|
|
|
EditSelection *ese;
|
|
|
|
EditVertC *evec;
|
|
|
|
EditEdgeC *eedc;
|
|
|
|
EditFaceC *efac;
|
|
|
|
EditSelectionC *esec;
|
|
|
|
int a=0;
|
2009-01-01 13:15:35 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
free_editMesh(em);
|
|
|
|
|
|
|
|
/* malloc blocks */
|
|
|
|
memset(em, 0, sizeof(EditMesh));
|
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
em->selectmode = um->selectmode;
|
2010-01-26 17:39:45 +00:00
|
|
|
em->shapenr = um->shapenr;
|
2009-01-31 19:40:40 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface);
|
|
|
|
|
|
|
|
CustomData_free(&em->vdata, 0);
|
|
|
|
CustomData_free(&em->edata, 0);
|
|
|
|
CustomData_free(&em->fdata, 0);
|
|
|
|
|
|
|
|
CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
|
|
|
|
CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
|
|
|
|
CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
|
|
|
|
|
|
|
|
/* now copy vertices */
|
|
|
|
|
|
|
|
if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar");
|
|
|
|
for(a=0, evec= um->verts; a<um->totvert; a++, evec++) {
|
|
|
|
eve= addvertlist(em, evec->co, NULL);
|
|
|
|
evar[a]= eve;
|
|
|
|
|
|
|
|
VECCOPY(eve->no, evec->no);
|
|
|
|
eve->f= evec->f;
|
|
|
|
eve->h= evec->h;
|
|
|
|
eve->keyindex= evec->keyindex;
|
|
|
|
eve->bweight= ((float)evec->bweight)/255.0f;
|
|
|
|
|
|
|
|
CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy edges */
|
|
|
|
for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) {
|
|
|
|
eed= addedgelist(em, evar[eedc->v1], evar[eedc->v2], NULL);
|
|
|
|
|
|
|
|
eed->f= eedc->f;
|
|
|
|
eed->h= eedc->h;
|
|
|
|
eed->seam= eedc->seam;
|
|
|
|
eed->sharp= eedc->sharp;
|
|
|
|
eed->fgoni= eedc->fgoni;
|
|
|
|
eed->crease= ((float)eedc->crease)/255.0f;
|
|
|
|
eed->bweight= ((float)eedc->bweight)/255.0f;
|
|
|
|
CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy faces */
|
|
|
|
for(a=0, efac= um->faces; a<um->totface; a++, efac++) {
|
|
|
|
if(efac->v4 != -1)
|
|
|
|
efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL);
|
|
|
|
else
|
|
|
|
efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL);
|
|
|
|
|
|
|
|
efa->mat_nr= efac->mat_nr;
|
|
|
|
efa->flag= efac->flag;
|
|
|
|
efa->f= efac->f;
|
|
|
|
efa->h= efac->h;
|
|
|
|
efa->fgonf= efac->fgonf;
|
|
|
|
|
|
|
|
CustomData_to_em_block(&um->fdata, &em->fdata, a, &efa->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
end_editmesh_fastmalloc();
|
|
|
|
if(evar) MEM_freeN(evar);
|
|
|
|
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totvert = um->totvert;
|
|
|
|
em->totedge = um->totedge;
|
|
|
|
em->totface = um->totface;
|
2008-12-30 13:16:14 +00:00
|
|
|
/*restore stored editselections*/
|
|
|
|
if(um->totsel){
|
|
|
|
EM_init_index_arrays(em, 1,1,1);
|
|
|
|
for(a=0, esec= um->selected; a<um->totsel; a++, esec++){
|
|
|
|
ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
|
|
|
|
ese->type = esec->type;
|
|
|
|
if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(esec->index); else
|
|
|
|
if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(esec->index); else
|
|
|
|
if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(esec->index);
|
|
|
|
BLI_addtail(&(em->selected),ese);
|
|
|
|
}
|
|
|
|
EM_free_index_arrays();
|
|
|
|
}
|
|
|
|
|
2009-11-25 22:38:07 +00:00
|
|
|
/* restore total selections */
|
|
|
|
EM_nvertices_selected(em);
|
|
|
|
EM_nedges_selected(em);
|
|
|
|
EM_nfaces_selected(em);
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
// XXX retopo_free_paint();
|
|
|
|
// em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data);
|
|
|
|
// scene->toolsettings->retopo_mode= um->retopo_mode;
|
|
|
|
// if(scene->toolsettings->retopo_mode) {
|
|
|
|
// XXX if(G.vd->depths) G.vd->depths->damaged= 1;
|
|
|
|
// retopo_queue_updates(G.vd);
|
|
|
|
// retopo_paint_view_update(G.vd);
|
|
|
|
// }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-01-01 13:15:35 +00:00
|
|
|
static void *getEditMesh(bContext *C)
|
|
|
|
{
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-01-23 14:43:25 +00:00
|
|
|
if(obedit && obedit->type==OB_MESH) {
|
2009-01-01 13:15:35 +00:00
|
|
|
Mesh *me= obedit->data;
|
|
|
|
return me->edit_mesh;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
/* and this is all the undo system needs to know */
|
2009-01-01 13:15:35 +00:00
|
|
|
void undo_push_mesh(bContext *C, char *name)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-01 13:15:35 +00:00
|
|
|
undo_editmode_push(C, name, getEditMesh, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh, NULL);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* *************** END UNDO *************/
|
|
|
|
|
|
|
|
static EditVert **g_em_vert_array = NULL;
|
|
|
|
static EditEdge **g_em_edge_array = NULL;
|
|
|
|
static EditFace **g_em_face_array = NULL;
|
|
|
|
|
|
|
|
void EM_init_index_arrays(EditMesh *em, int forVert, int forEdge, int forFace)
|
|
|
|
{
|
|
|
|
EditVert *eve;
|
|
|
|
EditEdge *eed;
|
|
|
|
EditFace *efa;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (forVert) {
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totvert= BLI_countlist(&em->verts);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
if(em->totvert) {
|
|
|
|
g_em_vert_array = MEM_mallocN(sizeof(*g_em_vert_array)*em->totvert, "em_v_arr");
|
|
|
|
|
|
|
|
for (i=0,eve=em->verts.first; eve; i++,eve=eve->next)
|
|
|
|
g_em_vert_array[i] = eve;
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (forEdge) {
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totedge= BLI_countlist(&em->edges);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
if(em->totedge) {
|
|
|
|
g_em_edge_array = MEM_mallocN(sizeof(*g_em_edge_array)*em->totedge, "em_e_arr");
|
|
|
|
|
|
|
|
for (i=0,eed=em->edges.first; eed; i++,eed=eed->next)
|
|
|
|
g_em_edge_array[i] = eed;
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (forFace) {
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totface= BLI_countlist(&em->faces);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
if(em->totface) {
|
|
|
|
g_em_face_array = MEM_mallocN(sizeof(*g_em_face_array)*em->totface, "em_f_arr");
|
|
|
|
|
|
|
|
for (i=0,efa=em->faces.first; efa; i++,efa=efa->next)
|
|
|
|
g_em_face_array[i] = efa;
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EM_free_index_arrays(void)
|
|
|
|
{
|
|
|
|
if (g_em_vert_array) MEM_freeN(g_em_vert_array);
|
|
|
|
if (g_em_edge_array) MEM_freeN(g_em_edge_array);
|
|
|
|
if (g_em_face_array) MEM_freeN(g_em_face_array);
|
|
|
|
g_em_vert_array = NULL;
|
|
|
|
g_em_edge_array = NULL;
|
|
|
|
g_em_face_array = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EditVert *EM_get_vert_for_index(int index)
|
|
|
|
{
|
|
|
|
return g_em_vert_array?g_em_vert_array[index]:NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EditEdge *EM_get_edge_for_index(int index)
|
|
|
|
{
|
|
|
|
return g_em_edge_array?g_em_edge_array[index]:NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EditFace *EM_get_face_for_index(int index)
|
|
|
|
{
|
|
|
|
return g_em_face_array?g_em_face_array[index]:NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* can we edit UV's for this mesh?*/
|
|
|
|
int EM_texFaceCheck(EditMesh *em)
|
|
|
|
{
|
|
|
|
/* some of these checks could be a touch overkill */
|
2009-01-02 19:10:35 +00:00
|
|
|
if ( (em) &&
|
2008-12-30 13:16:14 +00:00
|
|
|
(em->faces.first) &&
|
|
|
|
(CustomData_has_layer(&em->fdata, CD_MTFACE)))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* can we edit colors for this mesh?*/
|
|
|
|
int EM_vertColorCheck(EditMesh *em)
|
|
|
|
{
|
|
|
|
/* some of these checks could be a touch overkill */
|
2009-01-02 19:10:35 +00:00
|
|
|
if ( (em) &&
|
2008-12-30 13:16:14 +00:00
|
|
|
(em->faces.first) &&
|
|
|
|
(CustomData_has_layer(&em->fdata, CD_MCOL)))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
|
|
|
|
void em_setup_viewcontext(bContext *C, ViewContext *vc)
|
|
|
|
{
|
2009-01-13 15:18:41 +00:00
|
|
|
view3d_set_viewcontext(C, vc);
|
|
|
|
|
2008-12-31 17:11:42 +00:00
|
|
|
if(vc->obedit) {
|
|
|
|
Mesh *me= vc->obedit->data;
|
|
|
|
vc->em= me->edit_mesh;
|
|
|
|
}
|
2008-12-30 16:03:29 +00:00
|
|
|
}
|