This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/bmesh/operators/utils.c
Joseph Eagar eb34e3ad7c Brought Extrude all the way back. The contextual menu works,
as does only edges and individual faces extrude (individual vert 
extrude already did).

Note that I need to port this, after we all figure out how to handle
operators with variable transform follow-ons.

I also implemented the merge->collapse function, which is currently
accessable under ctrl->v, Bmesh Test Operator.  I still need to
implement the other merge modes, and properly hook everything into
the merge menu tool, which I plan on doing soon (tomorrow hopefully).

The cool thing about the collapse tool, is not only does it handle (all)
UV layers, it handles vcols as well.  To do this, I had to add a few math
functions to the customdata API, which seem to be working well.
2009-08-11 07:49:35 +00:00

386 lines
8.3 KiB
C

#include "MEM_guardedalloc.h"
#include "BKE_customdata.h"
#include "DNA_listBase.h"
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include <string.h>
#include "BKE_utildefines.h"
#include "BKE_mesh.h"
#include "BKE_global.h"
#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
#include "BLI_editVert.h"
#include "mesh_intern.h"
#include "ED_mesh.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_edgehash.h"
#include "bmesh.h"
/*
* UTILS.C
*
* utility bmesh operators, e.g. transform,
* translate, rotate, scale, etc.
*
*/
void bmesh_makevert_exec(BMesh *bm, BMOperator *op)
{
float vec[3];
BMO_Get_Vec(op, "co", vec);
BMO_SetFlag(bm, BM_Make_Vert(bm, vec, NULL), 1);
BMO_Flag_To_Slot(bm, op, "newvertout", 1, BM_VERT);
}
void bmesh_transform_exec(BMesh *bm, BMOperator *op)
{
BMOIter iter;
BMVert *v;
float mat[4][4];
BMO_Get_Mat4(op, "mat", mat);
BMO_ITER(v, &iter, bm, op, "verts", BM_VERT) {
Mat4MulVecfl(mat, v->co);
}
}
/*this operator calls the transform operator, which
is a little complex, but makes it easier to make
sure the transform op is working, since initially
only this one will be used.*/
void bmesh_translate_exec(BMesh *bm, BMOperator *op)
{
float mat[4][4], vec[3];
BMO_Get_Vec(op, "vec", vec);
Mat4One(mat);
VECCOPY(mat[3], vec);
BMO_CallOpf(bm, "transform mat=%m4 verts=%s", mat, op, "verts");
}
void bmesh_rotate_exec(BMesh *bm, BMOperator *op)
{
float vec[3];
BMO_Get_Vec(op, "cent", vec);
/*there has to be a proper matrix way to do this, but
this is how editmesh did it and I'm too tired to think
through the math right now.*/
VecMulf(vec, -1);
BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec);
BMO_CallOpf(bm, "transform mat=%s verts=%s", op, "mat", op, "verts");
VecMulf(vec, -1);
BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec);
}
void bmesh_reversefaces_exec(BMesh *bm, BMOperator *op)
{
BMOIter siter;
BMFace *f;
BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
BM_flip_normal(bm, f);
}
}
void bmesh_edgerotate_exec(BMesh *bm, BMOperator *op)
{
BMOIter siter;
BMEdge *e, *e2;
int ccw = BMO_Get_Int(op, "ccw");
BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
if (!(e2 = BM_Rotate_Edge(bm, e, ccw))) {
BMO_RaiseError(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge");
return;
}
BMO_SetFlag(bm, e2, 1);
}
BMO_Flag_To_Slot(bm, op, "edgeout", 1, BM_EDGE);
}
#define SEL_FLAG 1
#define SEL_ORIG 2
static void bmesh_regionextend_extend(BMesh *bm, BMOperator *op, int usefaces)
{
BMVert *v;
BMEdge *e;
BMIter eiter;
BMOIter siter;
if (!usefaces) {
BMO_ITER(v, &siter, bm, op, "geom", BM_VERT) {
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
if (!BMO_TestFlag(bm, e, SEL_ORIG))
break;
}
if (e) {
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
BMO_SetFlag(bm, e, SEL_FLAG);
BMO_SetFlag(bm, BM_OtherEdgeVert(e, v), SEL_FLAG);
}
}
}
} else {
BMIter liter, fiter;
BMFace *f, *f2;
BMLoop *l;
BMO_ITER(f, &siter, bm, op, "geom", BM_FACE) {
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
if (!BMO_TestFlag(bm, f2, SEL_ORIG))
BMO_SetFlag(bm, f2, SEL_FLAG);
}
}
}
}
}
static void bmesh_regionextend_constrict(BMesh *bm, BMOperator *op, int usefaces)
{
BMVert *v;
BMEdge *e;
BMIter eiter;
BMOIter siter;
if (!usefaces) {
BMO_ITER(v, &siter, bm, op, "geom", BM_VERT) {
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
if (!BMO_TestFlag(bm, e, SEL_ORIG))
break;
}
if (e) {
BMO_SetFlag(bm, v, SEL_FLAG);
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
BMO_SetFlag(bm, e, SEL_FLAG);
}
}
}
} else {
BMIter liter, fiter;
BMFace *f, *f2;
BMLoop *l;
BMO_ITER(f, &siter, bm, op, "geom", BM_FACE) {
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
if (!BMO_TestFlag(bm, f2, SEL_ORIG)) {
BMO_SetFlag(bm, f, SEL_FLAG);
break;
}
}
}
}
}
}
void bmesh_regionextend_exec(BMesh *bm, BMOperator *op)
{
int usefaces = BMO_Get_Int(op, "usefaces");
int constrict = BMO_Get_Int(op, "constrict");
BMO_Flag_Buffer(bm, op, "geom", SEL_ORIG, BM_ALL);
if (constrict)
bmesh_regionextend_constrict(bm, op, usefaces);
else
bmesh_regionextend_extend(bm, op, usefaces);
BMO_Flag_To_Slot(bm, op, "geomout", SEL_FLAG, BM_ALL);
}
/********* righthand faces implementation ********/
#define FACE_VIS 1
#define FACE_FLAG 2
#define FACE_MARK 4
/* NOTE: these are the original righthandfaces comment in editmesh_mods.c,
copied here for reference.
*/
/* based at a select-connected to witness loose objects */
/* count per edge the amount of faces */
/* find the ultimate left, front, upper face (not manhattan dist!!) */
/* also evaluate both triangle cases in quad, since these can be non-flat */
/* put normal to the outside, and set the first direction flags in edges */
/* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces */
/* this is in fact the 'select connected' */
/* in case (selected) faces were not done: start over with 'find the ultimate ...' */
/*note: this function uses recursion, which is a little unusual for a bmop
function, but acceptable I think.*/
void bmesh_righthandfaces_exec(BMesh *bm, BMOperator *op)
{
BMIter liter, liter2;
BMOIter siter;
BMFace *f, *startf, **fstack = NULL;
V_DECLARE(fstack);
BMLoop *l, *l2;
float maxx, cent[3];
int i, maxi;
startf= NULL;
maxx= -1.0e10;
BMO_Flag_Buffer(bm, op, "faces", FACE_FLAG, BM_FACE);
/*find a starting face*/
BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
if (BMO_TestFlag(bm, f, FACE_VIS))
continue;
if (!startf) startf = f;
BM_Compute_Face_Center(bm, f, cent);
cent[0] = cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
if (cent[0] > maxx) {
maxx = cent[0];
startf = f;
}
}
if (!startf) return;
BM_Compute_Face_Center(bm, startf, cent);
/*make sure the starting face has the correct winding*/
if (cent[0]*startf->no[0] + cent[1]*startf->no[1] + cent[2]*startf->no[2] < 0.0)
BM_flip_normal(bm, startf);
/*now that we've found our starting face, make all connected faces
have the same winding. this is done recursively, using a manual
stack (if we use simple function recursion, we'd end up overloading
the stack on large meshes).*/
V_GROW(fstack);
fstack[0] = startf;
BMO_SetFlag(bm, startf, FACE_VIS);
i = 0;
maxi = 1;
while (i >= 0) {
f = fstack[i];
i--;
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_LOOP, l) {
if (!BMO_TestFlag(bm, l2->f, FACE_FLAG) || l2 == l)
continue;
if (!BMO_TestFlag(bm, l2->f, FACE_VIS)) {
BMO_SetFlag(bm, l2->f, FACE_VIS);
i++;
if (l2->v == l->v)
BM_flip_normal(bm, l2->f);
if (i == maxi) {
V_GROW(fstack);
maxi++;
}
fstack[i] = l2->f;
}
}
}
}
V_FREE(fstack);
/*check if we have faces yet to do. if so, recurse.*/
BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
if (!BMO_TestFlag(bm, f, FACE_VIS)) {
bmesh_righthandfaces_exec(bm, op);
break;
}
}
}
void bmesh_vertexsmooth_exec(BMesh *bm, BMOperator *op)
{
BMOIter siter;
BMIter iter;
BMVert *v;
BMEdge *e;
V_DECLARE(cos);
float (*cos)[3] = NULL;
float *co, *co2, clipdist = BMO_Get_Float(op, "clipdist");
int i, j, clipx, clipy, clipz;
clipx = BMO_Get_Int(op, "mirror_clip_x");
clipy = BMO_Get_Int(op, "mirror_clip_y");
clipz = BMO_Get_Int(op, "mirror_clip_z");
i = 0;
BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
V_GROW(cos);
co = cos[i];
j = 0;
BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
co2 = BM_OtherEdgeVert(e, v)->co;
VECADD(co, co, co2);
j += 1;
}
if (!j) {
VECCOPY(co, v->co);
i++;
continue;
}
co[0] /= (float)j;
co[1] /= (float)j;
co[2] /= (float)j;
co[0] = v->co[0]*0.5 + co[0]*0.5;
co[1] = v->co[1]*0.5 + co[1]*0.5;
co[2] = v->co[2]*0.5 + co[2]*0.5;
if (clipx && fabs(v->co[0]) < clipdist)
co[0] = 0.0f;
if (clipy && fabs(v->co[1]) < clipdist)
co[1] = 0.0f;
if (clipz && fabs(v->co[2]) < clipdist)
co[2] = 0.0f;
i++;
}
i = 0;
BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
VECCOPY(v->co, cos[i]);
i++;
}
V_FREE(cos);
}