forked from bartvdbraak/blender
part 1 of vkey rip tool. still needs more work. ugh, doing this tool correctly is a nightmare.
This commit is contained in:
parent
c75e1598dd
commit
d4a9660b99
@ -882,32 +882,50 @@ static void bmDM_drawFacesTex_common(DerivedMesh *dm,
|
||||
|
||||
bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
|
||||
|
||||
glTexCoord2fv(luv[0]->uv);
|
||||
glColor3ub(lcol[0]->r, lcol[0]->g, lcol[0]->b);
|
||||
if (luv[0])
|
||||
glTexCoord2fv(luv[0]->uv);
|
||||
if (lcol[0])
|
||||
glColor3ub(lcol[0]->r, lcol[0]->g, lcol[0]->b);
|
||||
else glColor3ub(0, 0, 0);
|
||||
glVertex3fv(ls[0]->v->co);
|
||||
|
||||
glTexCoord2fv(luv[1]->uv);
|
||||
glColor3ub(lcol[1]->r, lcol[1]->g, lcol[1]->b);
|
||||
if (luv[1])
|
||||
glTexCoord2fv(luv[1]->uv);
|
||||
if (lcol[1])
|
||||
glColor3ub(lcol[1]->r, lcol[1]->g, lcol[1]->b);
|
||||
else glColor3ub(0, 0, 0);
|
||||
glVertex3fv(ls[1]->v->co);
|
||||
|
||||
glTexCoord2fv(luv[2]->uv);
|
||||
glColor3ub(lcol[2]->r, lcol[2]->g, lcol[2]->b);
|
||||
if (luv[2])
|
||||
glTexCoord2fv(luv[2]->uv);
|
||||
if (lcol[2])
|
||||
glColor3ub(lcol[2]->r, lcol[2]->g, lcol[2]->b);
|
||||
else glColor3ub(0, 0, 0);
|
||||
glVertex3fv(ls[2]->v->co);
|
||||
} else {
|
||||
bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
|
||||
|
||||
glTexCoord2fv(luv[0]->uv);
|
||||
glColor3ub(lcol[0]->r, lcol[0]->g, lcol[0]->b);
|
||||
if (luv[0])
|
||||
glTexCoord2fv(luv[0]->uv);
|
||||
if (lcol[0])
|
||||
glColor3ub(lcol[0]->r, lcol[0]->g, lcol[0]->b);
|
||||
else glColor3ub(0, 0, 0);
|
||||
glNormal3fv(ls[0]->v->no);
|
||||
glVertex3fv(ls[0]->v->co);
|
||||
|
||||
glTexCoord2fv(luv[1]->uv);
|
||||
glColor3ub(lcol[1]->r, lcol[1]->g, lcol[1]->b);
|
||||
if (luv[1])
|
||||
glTexCoord2fv(luv[1]->uv);
|
||||
if (lcol[1])
|
||||
glColor3ub(lcol[1]->r, lcol[1]->g, lcol[1]->b);
|
||||
else glColor3ub(0, 0, 0);
|
||||
glNormal3fv(ls[1]->v->no);
|
||||
glVertex3fv(ls[1]->v->co);
|
||||
|
||||
glTexCoord2fv(luv[2]->uv);
|
||||
glColor3ub(lcol[2]->r, lcol[2]->g, lcol[2]->b);
|
||||
if (luv[2])
|
||||
glTexCoord2fv(luv[2]->uv);
|
||||
if (lcol[2])
|
||||
glColor3ub(lcol[2]->r, lcol[2]->g, lcol[2]->b);
|
||||
else glColor3ub(0, 0, 0);
|
||||
glNormal3fv(ls[2]->v->no);
|
||||
glVertex3fv(ls[2]->v->co);
|
||||
}
|
||||
|
@ -30,9 +30,15 @@
|
||||
|
||||
/*
|
||||
this library needs to be changed to not use macros quite so heavily,
|
||||
and to be more of a complete vector array API. The way arrays are
|
||||
and to be more of a complete array API. The way arrays are
|
||||
exposed to client code as normal C arrays is very useful though, imho.
|
||||
it does require some use of macros, however.
|
||||
it does require some use of macros, however.
|
||||
|
||||
anyway, it's used a bit too heavily to simply rewrite as a
|
||||
more "correct" solution without macros entirely. I originally wrote this
|
||||
to be very easy to use, without the normal pain of most array libraries.
|
||||
This was especially helpful when it came to the massive refactors necessary for
|
||||
bmesh, and really helped to speed the process up. - joeedh
|
||||
|
||||
little array macro library. example of usage:
|
||||
|
||||
@ -51,28 +57,35 @@ the array size is doubled). supposedly this should give good Big Oh
|
||||
behaviour, though it may not be the best in practice.
|
||||
*/
|
||||
|
||||
#define BLI_array_declare(vec) int _##vec##_count=0; void *_##vec##_tmp
|
||||
#define BLI_array_declare(arr) int _##arr##_count=0; void *_##arr##_tmp
|
||||
|
||||
/*this returns the entire size of the array, including any buffering.*/
|
||||
#define BLI_array_totalsize(vec) ((signed int)((vec)==NULL ? 0 : MEM_allocN_len(vec) / sizeof(*vec)))
|
||||
#define BLI_array_totalsize(arr) ((signed int)((arr)==NULL ? 0 : MEM_allocN_len(arr) / sizeof(*arr)))
|
||||
|
||||
/*this returns the logical size of the array, not including buffering.*/
|
||||
#define BLI_array_count(vec) _##vec##_count
|
||||
#define BLI_array_count(arr) _##arr##_count
|
||||
|
||||
/*grow the array by one. zeroes the new elements.*/
|
||||
#define BLI_array_growone(vec) \
|
||||
BLI_array_totalsize(vec) > _##vec##_count ? _##vec##_count++ : \
|
||||
((_##vec##_tmp = MEM_callocN(sizeof(*vec)*(_##vec##_count*2+2), #vec " " __FILE__ " ")),\
|
||||
(vec && memcpy(_##vec##_tmp, vec, sizeof(*vec) * _##vec##_count)),\
|
||||
(vec && (MEM_freeN(vec),1)),\
|
||||
(vec = _##vec##_tmp),\
|
||||
_##vec##_count++)
|
||||
#define BLI_array_growone(arr) \
|
||||
BLI_array_totalsize(arr) > _##arr##_count ? _##arr##_count++ : \
|
||||
((_##arr##_tmp = MEM_callocN(sizeof(*arr)*(_##arr##_count*2+2), #arr " " __FILE__ " ")),\
|
||||
(arr && memcpy(_##arr##_tmp, arr, sizeof(*arr) * _##arr##_count)),\
|
||||
(arr && (MEM_freeN(arr),1)),\
|
||||
(arr = _##arr##_tmp),\
|
||||
_##arr##_count++)
|
||||
|
||||
#define BLI_array_free(vec) if (vec) MEM_freeN(vec);
|
||||
/*appends an item to the array and returns a pointer to the item in the array.
|
||||
item is not a pointer, but actual data value.*/
|
||||
#define BLI_array_append(arr, item) (BLI_array_growone(arr), arr[_##arr##_count] = item, (arr+_##arr##_count))
|
||||
|
||||
/*grow an array by a specified number of items.*/
|
||||
#define BLI_array_growitems(arr, num) {int _i; for (_i=0; _i<(num); _i++) {BLI_array_growone(arr);}}
|
||||
#define BLI_array_free(arr) if (arr) MEM_freeN(arr)
|
||||
|
||||
/*resets the logical size of an array to zero, but doesn't
|
||||
free the memory.*/
|
||||
#define BLI_array_empty(vec) _##vec##_count=0
|
||||
#define BLI_array_empty(arr) _##arr##_count=0
|
||||
|
||||
/*set the count of the array*/
|
||||
#define BLI_array_set_length(vec, count) _##vec##_count = (count)
|
||||
/*set the count of the array, doesn't actually increase the allocated array
|
||||
size. don't use this unless you know what your doing.*/
|
||||
#define BLI_array_set_length(arr, count) _##arr##_count = (count)
|
||||
|
@ -13,7 +13,7 @@ int BM_Count_Element(struct BMesh *bm, int type);
|
||||
/*returns true if v is in f*/
|
||||
int BM_Vert_In_Face(struct BMFace *f, struct BMVert *v);
|
||||
|
||||
// int BM_VERTS_OF_MESH_In_Face(struct BMFace *f, struct BMVert **varr, int len);
|
||||
// int BM_Verts_In_Face(struct BMFace *f, struct BMVert **varr, int len);
|
||||
int BM_Verts_In_Face(struct BMesh *bm, struct BMFace *f, struct BMVert **varr, int len);
|
||||
|
||||
int BM_Edge_In_Face(struct BMFace *f, struct BMEdge *e);
|
||||
|
@ -154,12 +154,13 @@ BMOpDefine def_reversefaces = {
|
||||
};
|
||||
|
||||
/*
|
||||
Edge Split
|
||||
Edge Bisect
|
||||
|
||||
Splits input edges (but doesn't do anything else).
|
||||
This creates a 2-valence vert.
|
||||
*/
|
||||
BMOpDefine def_edgesplit = {
|
||||
"edgesplit",
|
||||
BMOpDefine def_edgebisect = {
|
||||
"edgebisect",
|
||||
{{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, //input edges
|
||||
{BMOP_OPSLOT_INT, "numcuts"}, //number of cuts
|
||||
{BMOP_OPSLOT_ELEMENT_BUF, "outsplit"}, //newly created vertices and edges
|
||||
@ -802,6 +803,21 @@ BMOpDefine def_vertexshortestpath = {
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
Edge Split
|
||||
|
||||
Disconnects faces along input edges.
|
||||
*/
|
||||
BMOpDefine def_edgesplit = {
|
||||
"edgesplit",
|
||||
{{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, /* input edges */
|
||||
{BMOP_OPSLOT_ELEMENT_BUF, "edgeout1"}, /* old output disconnected edges */
|
||||
{BMOP_OPSLOT_ELEMENT_BUF, "edgeout2"}, /* new output disconnected edges */
|
||||
{0} /*null-terminating sentinel*/},
|
||||
bmesh_edgesplitop_exec,
|
||||
0
|
||||
};
|
||||
|
||||
BMOpDefine *opdefines[] = {
|
||||
&def_splitop,
|
||||
&def_dupeop,
|
||||
@ -831,7 +847,7 @@ BMOpDefine *opdefines[] = {
|
||||
&def_removedoubles,
|
||||
&def_finddoubles,
|
||||
&def_mirror,
|
||||
&def_edgesplit,
|
||||
&def_edgebisect,
|
||||
&def_reversefaces,
|
||||
&def_edgerotate,
|
||||
&def_regionextend,
|
||||
@ -855,6 +871,7 @@ BMOpDefine *opdefines[] = {
|
||||
&def_meshreversecolors,
|
||||
&def_vertexshortestpath,
|
||||
&def_scale,
|
||||
&def_edgesplit,
|
||||
};
|
||||
|
||||
int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*));
|
||||
|
@ -59,4 +59,5 @@ void bmesh_rotatecolors_exec(BMesh *bm, BMOperator *op);
|
||||
void bmesh_reversecolors_exec(BMesh *bm, BMOperator *op);
|
||||
void bmesh_vertexshortestpath_exec(BMesh *bm, BMOperator *op);
|
||||
void bmesh_scale_exec(BMesh *bm, BMOperator *op);
|
||||
void bmesh_edgesplitop_exec(BMesh *bm, BMOperator *op);
|
||||
#endif
|
||||
|
@ -184,6 +184,9 @@ BMEdge *BM_Edge_Exist(BMVert *v1, BMVert *v2)
|
||||
BMEdge *curedge;
|
||||
int i, len=0;
|
||||
|
||||
if (!v1 || !v2 || v1 == v2)
|
||||
return NULL;
|
||||
|
||||
if(v1->edge){
|
||||
diskbase = bmesh_disk_getpointer(v1->edge,v1);
|
||||
len = bmesh_cycle_length(diskbase);
|
||||
|
357
source/blender/bmesh/operators/edgesplitop.c
Normal file
357
source/blender/bmesh/operators/edgesplitop.c
Normal file
@ -0,0 +1,357 @@
|
||||
/**
|
||||
* $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. The Blender
|
||||
* Foundation also sells licenses for use in proprietary software under
|
||||
* the Blender License. See http://www.blender.org/BL/ for information
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Joseph Eagar
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_array.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "ED_mesh.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
#include "mesh_intern.h"
|
||||
#include "subdivideop.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
typedef struct EdgeTag {
|
||||
BMVert *newv1, *newv2;
|
||||
BMEdge *newe1, *newe2;
|
||||
int tag;
|
||||
} EdgeTag;
|
||||
|
||||
#define EDGE_SEAM 1
|
||||
#define EDGE_DEL 2
|
||||
#define EDGE_MARK 4
|
||||
#define EDGE_RET1 8
|
||||
#define EDGE_RET2 16
|
||||
|
||||
#define FACE_DEL 1
|
||||
#define FACE_NEW 2
|
||||
|
||||
static BMFace *remake_face(BMesh *bm, EdgeTag *etags, BMFace *f, BMVert **verts)
|
||||
{
|
||||
BMIter liter1, liter2;
|
||||
EdgeTag *et;
|
||||
BMFace *f2;
|
||||
BMLoop *l, *l2;
|
||||
BMEdge **edges = (BMEdge**) verts; /*he he, can reuse this, sneaky! ;)*/
|
||||
BMVert *lastv1, *lastv2, *v1, *v2;
|
||||
int i;
|
||||
|
||||
/*we do final edge last*/
|
||||
lastv1 = verts[f->len-1];
|
||||
lastv2 = verts[0];
|
||||
v1 = verts[0];
|
||||
v2 = verts[1];
|
||||
for (i=0; i<f->len-1; i++) {
|
||||
edges[i] = BM_Make_Edge(bm, verts[i], verts[i+1], NULL, 1);
|
||||
|
||||
if (!edges[i])
|
||||
return NULL;
|
||||
}
|
||||
|
||||
edges[i] = BM_Make_Edge(bm, lastv1, lastv2, NULL, 1);
|
||||
|
||||
f2 = BM_Make_Ngon(bm, v1, v2, edges, f->len, 0);
|
||||
if (!f2)
|
||||
return NULL;
|
||||
|
||||
BM_Copy_Attributes(bm, bm, f, f2);
|
||||
|
||||
l = BMIter_New(&liter1, bm, BM_LOOPS_OF_FACE, f);
|
||||
l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
|
||||
for (; l && l2; l=BMIter_Step(&liter1), l2=BMIter_Step(&liter2)) {
|
||||
BM_Copy_Attributes(bm, bm, l, l2);
|
||||
if (l->e != l2->e) {
|
||||
/*set up data for figuring out the two sides of
|
||||
the splits*/
|
||||
BMINDEX_SET(l2->e, BMINDEX_GET(l->e));
|
||||
et = etags + BMINDEX_GET(l->e);
|
||||
|
||||
if (!et->newe1) et->newe1 = l2->e;
|
||||
else et->newe2 = l2->e;
|
||||
|
||||
if (BMO_TestFlag(bm, l->e, EDGE_SEAM))
|
||||
BMO_SetFlag(bm, l2->e, EDGE_SEAM);
|
||||
|
||||
BM_Copy_Attributes(bm, bm, l->e, l2->e);
|
||||
}
|
||||
|
||||
BMO_SetFlag(bm, l->e, EDGE_MARK);
|
||||
BMO_SetFlag(bm, l2->e, EDGE_MARK);
|
||||
}
|
||||
|
||||
return f2;
|
||||
}
|
||||
|
||||
void tag_out_edges(BMesh *bm, EdgeTag *etags, BMOperator *op)
|
||||
{
|
||||
EdgeTag *et;
|
||||
BMIter iter;
|
||||
BMLoop *l, *startl;
|
||||
BMEdge *e;
|
||||
BMVert *v;
|
||||
int i;
|
||||
|
||||
while (1) {
|
||||
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
|
||||
if (!BMO_TestFlag(bm, e, EDGE_SEAM))
|
||||
continue;
|
||||
|
||||
et = etags + BMINDEX_GET(e);
|
||||
if (!et->tag && e->loop) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!e)
|
||||
break;
|
||||
|
||||
/*ok we found an edge, part of a region of splits we need
|
||||
to identify. now walk along it.*/
|
||||
for (i=0; i<2; i++) {
|
||||
l = e->loop;
|
||||
|
||||
v = i ? ((BMLoop*)l->head.next)->v : l->v;
|
||||
|
||||
while (1) {
|
||||
et = etags + BMINDEX_GET(l->e);
|
||||
if (et->newe1 == l->e) {
|
||||
if (et->newe1) {
|
||||
BMO_SetFlag(bm, et->newe1, EDGE_RET1);
|
||||
BMO_ClearFlag(bm, et->newe1, EDGE_SEAM);
|
||||
}
|
||||
if (et->newe2) {
|
||||
BMO_SetFlag(bm, et->newe2, EDGE_RET2);
|
||||
BMO_ClearFlag(bm, et->newe2, EDGE_SEAM);
|
||||
}
|
||||
} else {
|
||||
if (et->newe1) {
|
||||
BMO_SetFlag(bm, et->newe1, EDGE_RET2);
|
||||
BMO_ClearFlag(bm, et->newe1, EDGE_SEAM);
|
||||
}
|
||||
if (et->newe2) {
|
||||
BMO_SetFlag(bm, et->newe2, EDGE_RET1);
|
||||
BMO_ClearFlag(bm, et->newe2, EDGE_SEAM);
|
||||
}
|
||||
}
|
||||
|
||||
startl = l;
|
||||
do {
|
||||
l = BM_OtherFaceLoop(l->e, l->f, v);
|
||||
if (BM_Edge_FaceCount(l->e) != 2)
|
||||
break;
|
||||
l = (BMLoop*) l->radial.next->data;
|
||||
} while (l != startl && !BMO_TestFlag(bm, l->e, EDGE_SEAM));
|
||||
|
||||
if (l == startl || !BMO_TestFlag(bm, l->e, EDGE_SEAM))
|
||||
break;
|
||||
|
||||
if (l->v == v) {
|
||||
v = ((BMLoop*)l->head.next)->v;
|
||||
} else v = l->v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bmesh_edgesplitop_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
EdgeTag *etags, *et;
|
||||
BMIter iter, liter;
|
||||
BMOIter siter;
|
||||
BMFace *f, *f2;
|
||||
BMLoop *l, *nextl, *prevl, *l2, *l3;
|
||||
BMEdge *e, *e2;
|
||||
BLI_array_declare(verts);
|
||||
BMVert *v, *v2, **verts = NULL;
|
||||
int i, j;
|
||||
|
||||
BMO_Flag_Buffer(bm, op, "edges", EDGE_SEAM, BM_EDGE);
|
||||
|
||||
/*single marked edges unconnected to any other marked edges
|
||||
are illegal, go through and unmark them*/
|
||||
BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
|
||||
for (i=0; i<2; i++) {
|
||||
BM_ITER(e2, &iter, bm, BM_EDGES_OF_VERT, i ? e->v2 : e->v1) {
|
||||
if (e != e2 && BMO_TestFlag(bm, e2, EDGE_SEAM))
|
||||
break;
|
||||
}
|
||||
if (e2)
|
||||
break;
|
||||
}
|
||||
if (!e2)
|
||||
BMO_ClearFlag(bm, e, EDGE_SEAM);
|
||||
}
|
||||
|
||||
etags = MEM_callocN(sizeof(EdgeTag)*bm->totedge, "EdgeTag");
|
||||
|
||||
i = 0;
|
||||
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
|
||||
BMINDEX_SET(e, i);
|
||||
i++;
|
||||
}
|
||||
|
||||
#ifdef ETV
|
||||
#undef ETV
|
||||
#endif
|
||||
#ifdef SETETV
|
||||
#undef SETETV
|
||||
#endif
|
||||
|
||||
#define ETV(et, v, l) (l->e->v1 == v ? et->newv1 : et->newv2)
|
||||
#define SETETV(et, v, l, vs) l->e->v1 == v ? (et->newv1 = vs) : (et->newv2 = vs)
|
||||
|
||||
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
|
||||
if (BMO_TestFlag(bm, f, FACE_NEW))
|
||||
continue;
|
||||
|
||||
BLI_array_empty(verts);
|
||||
BLI_array_growitems(verts, f->len);
|
||||
memset(verts, 0, sizeof(BMVert*)*f->len);
|
||||
|
||||
i = 0;
|
||||
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
|
||||
if (!BMO_TestFlag(bm, l->e, EDGE_SEAM)) {
|
||||
if (!verts[i]) {
|
||||
et = etags + BMINDEX_GET(l->e);
|
||||
if (ETV(et, l->v, l))
|
||||
verts[i] = ETV(et, l->v, l);
|
||||
else verts[i] = l->v;
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
BMO_SetFlag(bm, l->e, EDGE_DEL);
|
||||
|
||||
nextl = (BMLoop*) l->head.next;
|
||||
prevl = (BMLoop*) l->head.prev;
|
||||
|
||||
for (j=0; j<2; j++) {
|
||||
l2 = j ? nextl : prevl;
|
||||
v = j ? l2->v : l->v;
|
||||
|
||||
if (BMO_TestFlag(bm, l2->e, EDGE_SEAM)) {
|
||||
if (!verts[j ? (i+1) % f->len : i]) {
|
||||
/*make unique vert here for this face only*/
|
||||
v2 = BM_Make_Vert(bm, v->co, NULL);
|
||||
VECCOPY(v2->no, v->no);
|
||||
BM_Copy_Attributes(bm, bm, v, v2);
|
||||
|
||||
verts[j ? (i+1) % f->len : i] = v2;
|
||||
} else v2 = verts[j ? (i+1) % f->len : i];
|
||||
} else {
|
||||
/*generate unique vert for non-seam edge(s)
|
||||
around the manifold vert fan if necassary*/
|
||||
|
||||
/*first check that we have two seam edges
|
||||
somewhere within this fan*/
|
||||
l3 = l2;
|
||||
do {
|
||||
if (BM_Edge_FaceCount(l3->e) != 2) {
|
||||
/*if we hit a boundary edge, tag
|
||||
l3 as null so we know to disconnect
|
||||
it*/
|
||||
if (BM_Edge_FaceCount(l3->e) == 1)
|
||||
l3 = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
l3 = (BMLoop*)l3->radial.next->data;
|
||||
l3 = BM_OtherFaceLoop(l3->e, l3->f, v);
|
||||
} while (l3 != l2 && !BMO_TestFlag(bm, l3->e, EDGE_SEAM));
|
||||
|
||||
if (l3 == NULL || (BMO_TestFlag(bm, l3->e, EDGE_SEAM) && l3->e != l->e)) {
|
||||
et = etags + BMINDEX_GET(l2->e);
|
||||
if (ETV(et, v, l2) == NULL) {
|
||||
v2 = BM_Make_Vert(bm, v->co, NULL);
|
||||
VECCOPY(v2->no, v->no);
|
||||
BM_Copy_Attributes(bm, bm, v, v2);
|
||||
|
||||
l3 = l2;
|
||||
do {
|
||||
SETETV(et, v, l3, v2);
|
||||
if (BM_Edge_FaceCount(l3->e) != 2)
|
||||
break;
|
||||
|
||||
l3 = (BMLoop*)l3->radial.next->data;
|
||||
l3 = BM_OtherFaceLoop(l3->e, l3->f, v);
|
||||
|
||||
et = etags + BMINDEX_GET(l3->e);
|
||||
} while (l3 != l2 && !BMO_TestFlag(bm, l3->e, EDGE_SEAM));
|
||||
} else v2 = ETV(et, v, l2);
|
||||
|
||||
verts[j ? (i+1) % f->len : i] = v2;
|
||||
} else verts[j ? (i+1) % f->len : i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
f2 = remake_face(bm, etags, f, verts);
|
||||
if (!f2)
|
||||
continue;
|
||||
|
||||
BMO_SetFlag(bm, f, FACE_DEL);
|
||||
BMO_SetFlag(bm, f2, FACE_NEW);
|
||||
}
|
||||
|
||||
BMO_CallOpf(bm, "del geom=%ff context=%i", FACE_DEL, DEL_ONLYFACES);
|
||||
|
||||
/*test EDGE_MARK'd edges if we need to delete them, EDGE_MARK
|
||||
is set in remake_face*/
|
||||
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
|
||||
if (BMO_TestFlag(bm, e, EDGE_MARK)) {
|
||||
if (!e->loop)
|
||||
BMO_SetFlag(bm, e, EDGE_DEL);
|
||||
}
|
||||
}
|
||||
|
||||
BMO_CallOpf(bm, "del geom=%fe context=%i", EDGE_DEL, DEL_EDGES);
|
||||
|
||||
tag_out_edges(bm, etags, op);
|
||||
BMO_Flag_To_Slot(bm, op, "edgeout1", EDGE_RET1, BM_EDGE);
|
||||
BMO_Flag_To_Slot(bm, op, "edgeout2", EDGE_RET2, BM_EDGE);
|
||||
|
||||
BLI_array_free(verts);
|
||||
if (etags) MEM_freeN(etags);
|
||||
}
|
||||
|
||||
#undef ETV
|
||||
#undef SETETV
|
@ -1,3 +1,30 @@
|
||||
/**
|
||||
* $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. The Blender
|
||||
* Foundation also sells licenses for use in proprietary software under
|
||||
* the Blender License. See http://www.blender.org/BL/ for information
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Joseph Eagar.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BKE_utildefines.h"
|
||||
@ -20,15 +47,6 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
/*subdivide future development notes:
|
||||
each pattern should be able to be disabled
|
||||
by the client code, and the client code
|
||||
should be able to pass in custom patterns.
|
||||
|
||||
so you can configure it anywhere from a simple
|
||||
edge connect tool, to what's in 2.49a.
|
||||
*/
|
||||
|
||||
/*flags for all elements share a common bitfield space*/
|
||||
#define SUBD_SPLIT 1
|
||||
|
||||
|
@ -89,6 +89,8 @@
|
||||
#include "mesh_intern.h"
|
||||
#include "bmesh.h"
|
||||
|
||||
#include "editbmesh_bvh.h"
|
||||
|
||||
static void add_normal_aligned(float *nor, float *add)
|
||||
{
|
||||
if( INPR(nor, add) < -0.9999f)
|
||||
@ -2047,12 +2049,24 @@ static int bm_test_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
RegionView3D *r3d = CTX_wm_region_view3d(C);
|
||||
BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
|
||||
#if 1
|
||||
if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT))
|
||||
return OPERATOR_CANCELLED;
|
||||
BMBVHTree *tree = BMBVH_NewBVH(em);
|
||||
BMIter iter;
|
||||
BMEdge *e;
|
||||
|
||||
#else //uv island walker test
|
||||
/*hide all back edges*/
|
||||
BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
|
||||
if (!BM_TestHFlag(e, BM_SELECT))
|
||||
continue;
|
||||
|
||||
if (!BMBVH_EdgeVisible(tree, e, r3d, obedit))
|
||||
BM_Select(em->bm, e, 0);
|
||||
}
|
||||
|
||||
BMBVH_FreeBVH(tree);
|
||||
|
||||
#if 0 //uv island walker test
|
||||
BMIter iter, liter;
|
||||
BMFace *f;
|
||||
BMLoop *l, *l2;
|
||||
@ -2908,3 +2922,396 @@ void MESH_OT_select_vertex_path(wmOperatorType *ot)
|
||||
/* properties */
|
||||
RNA_def_enum(ot->srna, "type", type_items, VPATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance.");
|
||||
}
|
||||
/********************** Rip Operator *************************/
|
||||
|
||||
#if 0
|
||||
/* helper for below */
|
||||
static void mesh_rip_setface(EditMesh *em, EditFace *sefa)
|
||||
{
|
||||
/* put new vertices & edges in best face */
|
||||
if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v;
|
||||
if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v;
|
||||
if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v;
|
||||
if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v;
|
||||
|
||||
sefa->e1= addedgelist(em, sefa->v1, sefa->v2, sefa->e1);
|
||||
sefa->e2= addedgelist(em, sefa->v2, sefa->v3, sefa->e2);
|
||||
if(sefa->v4) {
|
||||
sefa->e3= addedgelist(em, sefa->v3, sefa->v4, sefa->e3);
|
||||
sefa->e4= addedgelist(em, sefa->v4, sefa->v1, sefa->e4);
|
||||
}
|
||||
else
|
||||
sefa->e3= addedgelist(em, sefa->v3, sefa->v1, sefa->e3);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* helper to find edge for edge_rip */
|
||||
static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, short *mval)
|
||||
{
|
||||
float vec1[3], vec2[3], mvalf[2];
|
||||
|
||||
view3d_project_float(ar, co1, vec1, mat);
|
||||
view3d_project_float(ar, co2, vec2, mat);
|
||||
mvalf[0]= (float)mval[0];
|
||||
mvalf[1]= (float)mval[1];
|
||||
|
||||
return PdistVL2Dfl(mvalf, vec1, vec2);
|
||||
}
|
||||
|
||||
/* based on mouse cursor position, it defines how is being ripped */
|
||||
static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
{
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
ARegion *ar= CTX_wm_region(C);
|
||||
RegionView3D *rv3d= CTX_wm_region_view3d(C);
|
||||
BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
|
||||
BMOperator bmop;
|
||||
BMBVHTree *bvhtree;
|
||||
BMOIter siter;
|
||||
BMIter iter, eiter, liter;
|
||||
BMLoop *l;
|
||||
BMEdge *e, *e2, *closest = NULL;
|
||||
BMVert *v;
|
||||
int side = 0, i;
|
||||
float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1], 0.0f};
|
||||
float dist = FLT_MAX, d;
|
||||
|
||||
view3d_get_object_project_mat(rv3d, obedit, projectMat);
|
||||
|
||||
BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
|
||||
if (BM_TestHFlag(e, BM_SELECT))
|
||||
BMINDEX_SET(e, 1);
|
||||
else BMINDEX_SET(e, 0);
|
||||
}
|
||||
|
||||
/*expand edge selection*/
|
||||
BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
|
||||
e2 = NULL;
|
||||
i = 0;
|
||||
BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
|
||||
if (BMINDEX_GET(e)) {
|
||||
e2 = e;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 1 && e2->loop) {
|
||||
l = BM_OtherFaceLoop(e2, e2->loop->f, v);
|
||||
l = (BMLoop*)l->radial.next->data;
|
||||
l = BM_OtherFaceLoop(l->e, l->f, v);
|
||||
|
||||
if (l)
|
||||
BM_Select(em->bm, l->e, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he", BM_SELECT)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BMO_Exec_Op(em->bm, &bmop);
|
||||
|
||||
/*build bvh tree for edge visibility tests*/
|
||||
bvhtree = BMBVH_NewBVH(em);
|
||||
|
||||
for (i=0; i<2; i++) {
|
||||
BMO_ITER(e, &siter, em->bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) {
|
||||
float cent[3] = {0, 0, 0}, mid[4], vec[3];
|
||||
|
||||
if (!BMBVH_EdgeVisible(bvhtree, e, rv3d, obedit))
|
||||
continue;
|
||||
|
||||
/*method for calculating distance:
|
||||
|
||||
for each edge: calculate face center, then made a vector
|
||||
from edge midpoint to face center. offset edge midpoint
|
||||
by a small amount along this vector.*/
|
||||
BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, e->loop->f) {
|
||||
VecAddf(cent, cent, l->v->co);
|
||||
}
|
||||
VecMulf(cent, 1.0f/(float)e->loop->f->len);
|
||||
|
||||
VecAddf(mid, e->v1->co, e->v2->co);
|
||||
VecMulf(mid, 0.5f);
|
||||
VecSubf(vec, cent, mid);
|
||||
Normalize(vec);
|
||||
VecMulf(vec, 0.01f);
|
||||
VecAddf(mid, mid, vec);
|
||||
|
||||
/*yay we have our comparison point, now project it*/
|
||||
view3d_project_float(ar, mid, mid, projectMat);
|
||||
|
||||
vec[0] = fmval[0] - mid[0];
|
||||
vec[1] = fmval[1] - mid[1];
|
||||
d = vec[0]*vec[0] + vec[1]*vec[1];
|
||||
|
||||
if (d < dist) {
|
||||
side = i;
|
||||
closest = e;
|
||||
dist = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EDBM_clear_flag_all(em, BM_SELECT);
|
||||
BMO_HeaderFlag_Buffer(em->bm, &bmop, side?"edgeout2":"edgeout1", BM_SELECT, BM_EDGE);
|
||||
|
||||
BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
|
||||
if (BM_TestHFlag(e, BM_SELECT))
|
||||
BMINDEX_SET(e, 1);
|
||||
else BMINDEX_SET(e, 0);
|
||||
}
|
||||
|
||||
/*constrict edge selection again*/
|
||||
BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
|
||||
e2 = NULL;
|
||||
i = 0;
|
||||
BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
|
||||
if (BMINDEX_GET(e)) {
|
||||
e2 = e;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 1)
|
||||
BM_Select(em->bm, e2, 0);
|
||||
}
|
||||
|
||||
EDBM_selectmode_flush(em);
|
||||
|
||||
if (!EDBM_FinishOp(em, &bmop, op, 1)) {
|
||||
BMBVH_FreeBVH(bvhtree);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BMBVH_FreeBVH(bvhtree);
|
||||
|
||||
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
#if 0 //BMESH_TODO
|
||||
ARegion *ar= CTX_wm_region(C);
|
||||
RegionView3D *rv3d= ar->regiondata;
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
|
||||
EditVert *eve, *nextve;
|
||||
EditEdge *eed, *seed= NULL;
|
||||
EditFace *efa, *sefa= NULL;
|
||||
float projectMat[4][4], vec[3], dist, mindist;
|
||||
short doit= 1, *mval= event->mval;
|
||||
|
||||
/* select flush... vertices are important */
|
||||
EM_selectmode_set(em);
|
||||
|
||||
view3d_get_object_project_mat(rv3d, obedit, projectMat);
|
||||
|
||||
/* find best face, exclude triangles and break on face select or faces with 2 edges select */
|
||||
mindist= 1000000.0f;
|
||||
for(efa= em->faces.first; efa; efa=efa->next) {
|
||||
if( efa->f & 1)
|
||||
break;
|
||||
if(efa->v4 && faceselectedOR(efa, SELECT) ) {
|
||||
int totsel=0;
|
||||
|
||||
if(efa->e1->f & SELECT) totsel++;
|
||||
if(efa->e2->f & SELECT) totsel++;
|
||||
if(efa->e3->f & SELECT) totsel++;
|
||||
if(efa->e4->f & SELECT) totsel++;
|
||||
|
||||
if(totsel>1)
|
||||
break;
|
||||
view3d_project_float(ar, efa->cent, vec, projectMat);
|
||||
dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
|
||||
if(dist<mindist) {
|
||||
mindist= dist;
|
||||
sefa= efa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(efa) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't perform ripping with faces selected this way");
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if(sefa==NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No proper selection or faces included");
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
||||
/* duplicate vertices, new vertices get selected */
|
||||
for(eve = em->verts.last; eve; eve= eve->prev) {
|
||||
eve->tmp.v = NULL;
|
||||
if(eve->f & SELECT) {
|
||||
eve->tmp.v = addvertlist(em, eve->co, eve);
|
||||
eve->f &= ~SELECT;
|
||||
eve->tmp.v->f |= SELECT;
|
||||
}
|
||||
}
|
||||
|
||||
/* find the best candidate edge */
|
||||
/* or one of sefa edges is selected... */
|
||||
if(sefa->e1->f & SELECT) seed= sefa->e2;
|
||||
if(sefa->e2->f & SELECT) seed= sefa->e1;
|
||||
if(sefa->e3->f & SELECT) seed= sefa->e2;
|
||||
if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3;
|
||||
|
||||
/* or we do the distance trick */
|
||||
if(seed==NULL) {
|
||||
mindist= 1000000.0f;
|
||||
if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) {
|
||||
dist = mesh_rip_edgedist(ar, projectMat,
|
||||
sefa->e1->v1->co,
|
||||
sefa->e1->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e1;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) {
|
||||
dist = mesh_rip_edgedist(ar, projectMat,
|
||||
sefa->e2->v1->co,
|
||||
sefa->e2->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e2;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) {
|
||||
dist= mesh_rip_edgedist(ar, projectMat,
|
||||
sefa->e3->v1->co,
|
||||
sefa->e3->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e3;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) {
|
||||
dist= mesh_rip_edgedist(ar, projectMat,
|
||||
sefa->e4->v1->co,
|
||||
sefa->e4->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e4;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(seed==NULL) { // never happens?
|
||||
BKE_report(op->reports, RPT_ERROR, "No proper edge found to start");
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
faceloop_select(em, seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
|
||||
|
||||
/* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
|
||||
for(eed = em->edges.last; eed; eed= eed->prev) {
|
||||
eed->tmp.v = NULL;
|
||||
if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
|
||||
EditEdge *newed;
|
||||
|
||||
newed= addedgelist(em, eed->v1->tmp.v?eed->v1->tmp.v:eed->v1,
|
||||
eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed);
|
||||
if(eed->f & SELECT) {
|
||||
EM_select_edge(eed, 0);
|
||||
EM_remove_selection(em, eed, EDITEDGE);
|
||||
EM_select_edge(newed, 1);
|
||||
}
|
||||
eed->tmp.v = (EditVert *)newed;
|
||||
}
|
||||
}
|
||||
|
||||
/* first clear edges to help finding neighbours */
|
||||
for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
|
||||
|
||||
/* put new vertices & edges && flag in best face */
|
||||
mesh_rip_setface(em, sefa);
|
||||
|
||||
/* starting with neighbours of best face, we loop over the seam */
|
||||
sefa->f1= 2;
|
||||
doit= 1;
|
||||
while(doit) {
|
||||
doit= 0;
|
||||
|
||||
for(efa= em->faces.first; efa; efa=efa->next) {
|
||||
/* new vert in face */
|
||||
if (efa->v1->tmp.v || efa->v2->tmp.v ||
|
||||
efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) {
|
||||
/* face is tagged with loop */
|
||||
if(efa->f1==1) {
|
||||
mesh_rip_setface(em, efa);
|
||||
efa->f1= 2;
|
||||
doit= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* remove loose edges, that were part of a ripped face */
|
||||
for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0;
|
||||
for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
|
||||
for(efa= em->faces.first; efa; efa=efa->next) {
|
||||
efa->e1->f1= 1;
|
||||
efa->e2->f1= 1;
|
||||
efa->e3->f1= 1;
|
||||
if(efa->e4) efa->e4->f1= 1;
|
||||
}
|
||||
|
||||
for(eed = em->edges.last; eed; eed= seed) {
|
||||
seed= eed->prev;
|
||||
if(eed->f1==0) {
|
||||
if(eed->v1->tmp.v || eed->v2->tmp.v ||
|
||||
(eed->v1->f & SELECT) || (eed->v2->f & SELECT)) {
|
||||
remedge(em, eed);
|
||||
free_editedge(em, eed);
|
||||
eed= NULL;
|
||||
}
|
||||
}
|
||||
if(eed) {
|
||||
eed->v1->f1= 1;
|
||||
eed->v2->f1= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* and remove loose selected vertices, that got duplicated accidentally */
|
||||
for(eve = em->verts.first; eve; eve= nextve) {
|
||||
nextve= eve->next;
|
||||
if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) {
|
||||
BLI_remlink(&em->verts,eve);
|
||||
free_editvert(em, eve);
|
||||
}
|
||||
}
|
||||
|
||||
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
||||
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
|
||||
// RNA_enum_set(op->ptr, "proportional", 0);
|
||||
// RNA_boolean_set(op->ptr, "mirror", 0);
|
||||
// WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MESH_OT_rip(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Rip";
|
||||
ot->idname= "MESH_OT_rip";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke= mesh_rip_invoke;
|
||||
ot->poll= EM_view3d_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* to give to transform */
|
||||
Properties_Proportional(ot);
|
||||
RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
|
||||
}
|
288
source/blender/editors/mesh/editbmesh_bvh.c
Normal file
288
source/blender/editors/mesh/editbmesh_bvh.c
Normal file
@ -0,0 +1,288 @@
|
||||
/* $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) 2004 by Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Joseph Eagar
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
#include "PIL_time.h"
|
||||
|
||||
#include "BLO_sys_types.h" // for intptr_t support
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#include "RNA_types.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_editVert.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_heap.h"
|
||||
#include "BLI_array.h"
|
||||
#include "BLI_kdopbvh.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BKE_bmesh.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_tessmesh.h"
|
||||
|
||||
#include "BIF_gl.h"
|
||||
#include "BIF_glutil.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_view3d.h"
|
||||
#include "ED_util.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_transform.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "mesh_intern.h"
|
||||
#include "bmesh.h"
|
||||
|
||||
#include "editbmesh_bvh.h"
|
||||
|
||||
typedef struct BMBVHTree {
|
||||
BMEditMesh *em;
|
||||
BMesh *bm;
|
||||
BVHTree *tree;
|
||||
float epsilon;
|
||||
} BMBVHTree;
|
||||
|
||||
BMBVHTree *BMBVH_NewBVH(BMEditMesh *em)
|
||||
{
|
||||
BMBVHTree *tree = MEM_callocN(sizeof(*tree), "BMBVHTree");
|
||||
float cos[3][3];
|
||||
int i;
|
||||
|
||||
BMEdit_RecalcTesselation(em);
|
||||
|
||||
tree->em = em;
|
||||
tree->bm = em->bm;
|
||||
tree->epsilon = FLT_EPSILON*2.0f;
|
||||
|
||||
tree->tree = BLI_bvhtree_new(em->tottri, tree->epsilon, 8, 8);
|
||||
|
||||
for (i=0; i<em->tottri; i++) {
|
||||
VECCOPY(cos[0], em->looptris[i][0]->v->co);
|
||||
VECCOPY(cos[1], em->looptris[i][1]->v->co);
|
||||
VECCOPY(cos[2], em->looptris[i][2]->v->co);
|
||||
|
||||
BLI_bvhtree_insert(tree->tree, i, (float*)cos, 3);
|
||||
}
|
||||
|
||||
BLI_bvhtree_balance(tree->tree);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void BMBVH_FreeBVH(BMBVHTree *tree)
|
||||
{
|
||||
BLI_bvhtree_free(tree->tree);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
|
||||
/*taken from bvhutils.c*/
|
||||
static float ray_tri_intersection(const BVHTreeRay *ray, const float m_dist, float *v0,
|
||||
float *v1, float *v2, float *uv, float e)
|
||||
{
|
||||
float dist;
|
||||
#if 0
|
||||
float vv1[3], vv2[3], vv3[3], cent[3];
|
||||
|
||||
/*expand triangle by an epsilon. this is probably a really stupid
|
||||
way of doing it, but I'm too tired to do better work.*/
|
||||
VECCOPY(vv1, v0);
|
||||
VECCOPY(vv2, v1);
|
||||
VECCOPY(vv3, v2);
|
||||
|
||||
VecAddf(cent, vv1, vv2);
|
||||
VecAddf(cent, cent, vv3);
|
||||
VecMulf(cent, 1.0f/3.0f);
|
||||
|
||||
VecSubf(vv1, vv1, cent);
|
||||
VecSubf(vv2, vv2, cent);
|
||||
VecSubf(vv3, vv3, cent);
|
||||
|
||||
VecMulf(vv1, 1.0f + e);
|
||||
VecMulf(vv2, 1.0f + e);
|
||||
VecMulf(vv3, 1.0f + e);
|
||||
|
||||
VecAddf(vv1, vv1, cent);
|
||||
VecAddf(vv2, vv2, cent);
|
||||
VecAddf(vv3, vv3, cent);
|
||||
|
||||
if(RayIntersectsTriangle((float*)ray->origin, (float*)ray->direction, vv1, vv2, vv3, &dist, uv))
|
||||
return dist;
|
||||
#else
|
||||
if(RayIntersectsTriangle((float*)ray->origin, (float*)ray->direction, v0, v1, v2, &dist, uv))
|
||||
return dist;
|
||||
#endif
|
||||
|
||||
return FLT_MAX;
|
||||
}
|
||||
|
||||
static void raycallback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
|
||||
{
|
||||
BMBVHTree *tree = userdata;
|
||||
BMLoop **ls = tree->em->looptris[index];
|
||||
float dist, uv[2], co1[3], co2[3], co3[3];
|
||||
|
||||
dist = ray_tri_intersection(ray, hit->dist, ls[0]->v->co, ls[1]->v->co,
|
||||
ls[2]->v->co, uv, tree->epsilon);
|
||||
if (dist < hit->dist) {
|
||||
hit->dist = dist;
|
||||
hit->index = index;
|
||||
|
||||
VECCOPY(hit->no, ls[0]->v->no);
|
||||
|
||||
VECCOPY(co1, ls[0]->v->co);
|
||||
VECCOPY(co2, ls[1]->v->co);
|
||||
VECCOPY(co3, ls[2]->v->co);
|
||||
|
||||
VecMulf(co1, uv[0]);
|
||||
VecMulf(co2, uv[1]);
|
||||
VecMulf(co3, 1.0f-uv[0]-uv[1]);
|
||||
|
||||
VecAddf(hit->co, co1, co2);
|
||||
VecAddf(hit->co, hit->co, co3);
|
||||
}
|
||||
}
|
||||
|
||||
BMFace *BMBVH_RayCast(BMBVHTree *tree, float *co, float *dir, float *hitout)
|
||||
{
|
||||
BVHTreeRayHit hit;
|
||||
|
||||
hit.dist = FLT_MAX;
|
||||
hit.index = -1;
|
||||
|
||||
BLI_bvhtree_ray_cast(tree->tree, co, dir, FLT_MAX, &hit, raycallback, tree);
|
||||
if (hit.dist != FLT_MAX && hit.index != -1) {
|
||||
if (hitout) {
|
||||
VECCOPY(hitout, hit.co);
|
||||
}
|
||||
|
||||
return tree->em->looptris[hit.index][0]->f;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0 //BMESH_TODO: not implemented yet
|
||||
int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static BMFace *edge_ray_cast(BMBVHTree *tree, float *co, float *dir, float *hitout, BMEdge *e)
|
||||
{
|
||||
BMFace *f = BMBVH_RayCast(tree, co, dir, hitout);
|
||||
|
||||
if (f && BM_Edge_In_Face(f, e))
|
||||
return NULL;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
int BMBVH_EdgeVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d, Object *obedit)
|
||||
{
|
||||
BMFace *f;
|
||||
float co1[3], co2[3], co3[3], dir1[4], dir2[4], dir3[4];
|
||||
float origin[3], invmat[4][4];
|
||||
float epsilon = 0.01f;
|
||||
|
||||
VECCOPY(origin, r3d->viewinv[3]);
|
||||
Mat4Invert(invmat, obedit->obmat);
|
||||
Mat4MulVecfl(invmat, origin);
|
||||
|
||||
VECCOPY(co1, e->v1->co);
|
||||
VecAddf(co2, e->v1->co, e->v2->co);
|
||||
VecMulf(co2, 0.5f);
|
||||
VECCOPY(co3, e->v2->co);
|
||||
|
||||
/*ok, idea is to generate rays going from the camera origin to the
|
||||
three points on the edge (v1, mid, v2)*/
|
||||
VecSubf(dir1, origin, co1);
|
||||
VecSubf(dir2, origin, co2);
|
||||
VecSubf(dir3, origin, co3);
|
||||
|
||||
Normalize(dir1);
|
||||
Normalize(dir2);
|
||||
Normalize(dir3);
|
||||
|
||||
VecMulf(dir1, epsilon);
|
||||
VecMulf(dir2, epsilon);
|
||||
VecMulf(dir3, epsilon);
|
||||
|
||||
/*offset coordinates slightly along view vectors, to avoid
|
||||
hitting the faces that own the edge.*/
|
||||
VecAddf(co1, co1, dir1);
|
||||
VecAddf(co2, co2, dir2);
|
||||
VecAddf(co3, co3, dir3);
|
||||
|
||||
Normalize(dir1);
|
||||
Normalize(dir2);
|
||||
Normalize(dir3);
|
||||
|
||||
/*do three samplings: left, middle, right*/
|
||||
f = edge_ray_cast(tree, co1, dir1, NULL, e);
|
||||
if (f && !edge_ray_cast(tree, co2, dir2, NULL, e))
|
||||
return 1;
|
||||
else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e))
|
||||
return 1;
|
||||
else if (!f)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
15
source/blender/editors/mesh/editbmesh_bvh.h
Normal file
15
source/blender/editors/mesh/editbmesh_bvh.h
Normal file
@ -0,0 +1,15 @@
|
||||
struct BMEditMesh;
|
||||
struct BMFace;
|
||||
struct BMEdge;
|
||||
struct BMVert;
|
||||
struct RegionView3D;
|
||||
|
||||
struct BMBVHTree;
|
||||
typedef struct BMBVHTree BMBVHTree;
|
||||
|
||||
BMBVHTree *BMBVH_NewBVH(struct BMEditMesh *em);
|
||||
void BMBVH_FreeBVH(BMBVHTree *tree);
|
||||
|
||||
struct BMFace *BMBVH_RayCast(BMBVHTree *tree, float *co, float *dir, float *hitout);
|
||||
int BMBVH_EdgeVisible(BMBVHTree *tree, struct BMEdge *e,
|
||||
struct RegionView3D *r3d, struct Object *obedit);
|
@ -4243,272 +4243,6 @@ void mesh_set_face_flags(EditMesh *em, short mode)
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************** Rip Operator *************************/
|
||||
|
||||
/* helper to find edge for edge_rip */
|
||||
static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, short *mval)
|
||||
{
|
||||
float vec1[3], vec2[3], mvalf[2];
|
||||
|
||||
view3d_project_float(ar, co1, vec1, mat);
|
||||
view3d_project_float(ar, co2, vec2, mat);
|
||||
mvalf[0]= (float)mval[0];
|
||||
mvalf[1]= (float)mval[1];
|
||||
|
||||
return PdistVL2Dfl(mvalf, vec1, vec2);
|
||||
}
|
||||
|
||||
/* helper for below */
|
||||
static void mesh_rip_setface(EditMesh *em, EditFace *sefa)
|
||||
{
|
||||
/* put new vertices & edges in best face */
|
||||
if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v;
|
||||
if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v;
|
||||
if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v;
|
||||
if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v;
|
||||
|
||||
sefa->e1= addedgelist(em, sefa->v1, sefa->v2, sefa->e1);
|
||||
sefa->e2= addedgelist(em, sefa->v2, sefa->v3, sefa->e2);
|
||||
if(sefa->v4) {
|
||||
sefa->e3= addedgelist(em, sefa->v3, sefa->v4, sefa->e3);
|
||||
sefa->e4= addedgelist(em, sefa->v4, sefa->v1, sefa->e4);
|
||||
}
|
||||
else
|
||||
sefa->e3= addedgelist(em, sefa->v3, sefa->v1, sefa->e3);
|
||||
|
||||
}
|
||||
|
||||
/* based on mouse cursor position, it defines how is being ripped */
|
||||
static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
{
|
||||
#if 0 //BMESH_TODO
|
||||
ARegion *ar= CTX_wm_region(C);
|
||||
RegionView3D *rv3d= ar->regiondata;
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
|
||||
EditVert *eve, *nextve;
|
||||
EditEdge *eed, *seed= NULL;
|
||||
EditFace *efa, *sefa= NULL;
|
||||
float projectMat[4][4], vec[3], dist, mindist;
|
||||
short doit= 1, *mval= event->mval;
|
||||
|
||||
/* select flush... vertices are important */
|
||||
EM_selectmode_set(em);
|
||||
|
||||
view3d_get_object_project_mat(rv3d, obedit, projectMat);
|
||||
|
||||
/* find best face, exclude triangles and break on face select or faces with 2 edges select */
|
||||
mindist= 1000000.0f;
|
||||
for(efa= em->faces.first; efa; efa=efa->next) {
|
||||
if( efa->f & 1)
|
||||
break;
|
||||
if(efa->v4 && faceselectedOR(efa, SELECT) ) {
|
||||
int totsel=0;
|
||||
|
||||
if(efa->e1->f & SELECT) totsel++;
|
||||
if(efa->e2->f & SELECT) totsel++;
|
||||
if(efa->e3->f & SELECT) totsel++;
|
||||
if(efa->e4->f & SELECT) totsel++;
|
||||
|
||||
if(totsel>1)
|
||||
break;
|
||||
view3d_project_float(ar, efa->cent, vec, projectMat);
|
||||
dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
|
||||
if(dist<mindist) {
|
||||
mindist= dist;
|
||||
sefa= efa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(efa) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't perform ripping with faces selected this way");
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if(sefa==NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No proper selection or faces included");
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
||||
/* duplicate vertices, new vertices get selected */
|
||||
for(eve = em->verts.last; eve; eve= eve->prev) {
|
||||
eve->tmp.v = NULL;
|
||||
if(eve->f & SELECT) {
|
||||
eve->tmp.v = addvertlist(em, eve->co, eve);
|
||||
eve->f &= ~SELECT;
|
||||
eve->tmp.v->f |= SELECT;
|
||||
}
|
||||
}
|
||||
|
||||
/* find the best candidate edge */
|
||||
/* or one of sefa edges is selected... */
|
||||
if(sefa->e1->f & SELECT) seed= sefa->e2;
|
||||
if(sefa->e2->f & SELECT) seed= sefa->e1;
|
||||
if(sefa->e3->f & SELECT) seed= sefa->e2;
|
||||
if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3;
|
||||
|
||||
/* or we do the distance trick */
|
||||
if(seed==NULL) {
|
||||
mindist= 1000000.0f;
|
||||
if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) {
|
||||
dist = mesh_rip_edgedist(ar, projectMat,
|
||||
sefa->e1->v1->co,
|
||||
sefa->e1->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e1;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) {
|
||||
dist = mesh_rip_edgedist(ar, projectMat,
|
||||
sefa->e2->v1->co,
|
||||
sefa->e2->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e2;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) {
|
||||
dist= mesh_rip_edgedist(ar, projectMat,
|
||||
sefa->e3->v1->co,
|
||||
sefa->e3->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e3;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) {
|
||||
dist= mesh_rip_edgedist(ar, projectMat,
|
||||
sefa->e4->v1->co,
|
||||
sefa->e4->v2->co, mval);
|
||||
if(dist<mindist) {
|
||||
seed= sefa->e4;
|
||||
mindist= dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(seed==NULL) { // never happens?
|
||||
BKE_report(op->reports, RPT_ERROR, "No proper edge found to start");
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
faceloop_select(em, seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
|
||||
|
||||
/* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
|
||||
for(eed = em->edges.last; eed; eed= eed->prev) {
|
||||
eed->tmp.v = NULL;
|
||||
if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
|
||||
EditEdge *newed;
|
||||
|
||||
newed= addedgelist(em, eed->v1->tmp.v?eed->v1->tmp.v:eed->v1,
|
||||
eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed);
|
||||
if(eed->f & SELECT) {
|
||||
EM_select_edge(eed, 0);
|
||||
EM_remove_selection(em, eed, EDITEDGE);
|
||||
EM_select_edge(newed, 1);
|
||||
}
|
||||
eed->tmp.v = (EditVert *)newed;
|
||||
}
|
||||
}
|
||||
|
||||
/* first clear edges to help finding neighbours */
|
||||
for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
|
||||
|
||||
/* put new vertices & edges && flag in best face */
|
||||
mesh_rip_setface(em, sefa);
|
||||
|
||||
/* starting with neighbours of best face, we loop over the seam */
|
||||
sefa->f1= 2;
|
||||
doit= 1;
|
||||
while(doit) {
|
||||
doit= 0;
|
||||
|
||||
for(efa= em->faces.first; efa; efa=efa->next) {
|
||||
/* new vert in face */
|
||||
if (efa->v1->tmp.v || efa->v2->tmp.v ||
|
||||
efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) {
|
||||
/* face is tagged with loop */
|
||||
if(efa->f1==1) {
|
||||
mesh_rip_setface(em, efa);
|
||||
efa->f1= 2;
|
||||
doit= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* remove loose edges, that were part of a ripped face */
|
||||
for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0;
|
||||
for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
|
||||
for(efa= em->faces.first; efa; efa=efa->next) {
|
||||
efa->e1->f1= 1;
|
||||
efa->e2->f1= 1;
|
||||
efa->e3->f1= 1;
|
||||
if(efa->e4) efa->e4->f1= 1;
|
||||
}
|
||||
|
||||
for(eed = em->edges.last; eed; eed= seed) {
|
||||
seed= eed->prev;
|
||||
if(eed->f1==0) {
|
||||
if(eed->v1->tmp.v || eed->v2->tmp.v ||
|
||||
(eed->v1->f & SELECT) || (eed->v2->f & SELECT)) {
|
||||
remedge(em, eed);
|
||||
free_editedge(em, eed);
|
||||
eed= NULL;
|
||||
}
|
||||
}
|
||||
if(eed) {
|
||||
eed->v1->f1= 1;
|
||||
eed->v2->f1= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* and remove loose selected vertices, that got duplicated accidentally */
|
||||
for(eve = em->verts.first; eve; eve= nextve) {
|
||||
nextve= eve->next;
|
||||
if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) {
|
||||
BLI_remlink(&em->verts,eve);
|
||||
free_editvert(em, eve);
|
||||
}
|
||||
}
|
||||
|
||||
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
||||
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
|
||||
// RNA_enum_set(op->ptr, "proportional", 0);
|
||||
// RNA_boolean_set(op->ptr, "mirror", 0);
|
||||
// WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
|
||||
#endif
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void MESH_OT_rip(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Rip";
|
||||
ot->idname= "MESH_OT_rip";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke= mesh_rip_invoke;
|
||||
ot->poll= EM_view3d_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* to give to transform */
|
||||
Properties_Proportional(ot);
|
||||
RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
|
||||
}
|
||||
|
||||
|
||||
/************************ Shape Operators *************************/
|
||||
|
||||
void shape_propagate(Scene *scene, Object *obedit, EditMesh *em, wmOperator *op)
|
||||
|
@ -458,7 +458,7 @@ void ED_keymap_mesh(wmWindowManager *wm)
|
||||
//WM_keymap_add_item(keymap, "MESH_OT_colors_mirror",EIGHTKEY, KM_PRESS, KM_ALT, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_colors_reverse",EIGHTKEY, KM_PRESS, KM_ALT, 0);
|
||||
|
||||
WM_keymap_add_item(keymap, "MESH_OT_rip_move",VKEY, KM_PRESS, 0, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_rip_move",VKEY, KM_PRESS, KM_SHIFT, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_merge", MKEY, KM_PRESS, KM_ALT, 0);
|
||||
|
||||
/* add/remove */
|
||||
|
@ -571,8 +571,8 @@ void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
|
||||
{
|
||||
float vec4[4];
|
||||
|
||||
adr[0]= IS_CLIPPED;
|
||||
VECCOPY(vec4, vec);
|
||||
adr[0]= IS_CLIPPED;
|
||||
vec4[3]= 1.0;
|
||||
|
||||
Mat4MulVec4fl(mat, vec4);
|
||||
|
Loading…
Reference in New Issue
Block a user