Added a matrix slot type for bmops. Coded a simple transform

bmop, that just multiplies input verts with a matrix.  Also
made a derivative translate bmop.

BMO_CallOpf now has a %s format code, which is used to
copy data from another slot.

Also cleaned the extrude code up some more, and restored extrude-repeat
(which is bound to ctrl-alt-4), though this doesn't work right yet
(the view matrix it uses is incorrect, or something like that).
This commit is contained in:
Joseph Eagar
2009-06-02 07:40:32 +00:00
parent 5faae5e704
commit 40b60cb1fa
10 changed files with 320 additions and 183 deletions

View File

@@ -872,7 +872,7 @@ void Mat4MulVec( float mat[][4], int *vec)
vec[2]=(int)(x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2]);
}
void Mat4MulVecfl( float mat[][4], float *vec)
void Mat4MulVecfl(float mat[][4], float *vec)
{
float x,y;

View File

@@ -48,6 +48,7 @@ struct GHashIterator;
#define BMOP_OPSLOT_INT 1
#define BMOP_OPSLOT_FLT 2
#define BMOP_OPSLOT_PNT 3
#define BMOP_OPSLOT_MAT 4
#define BMOP_OPSLOT_VEC 7
/*after BMOP_OPSLOT_VEC, everything is
@@ -159,6 +160,13 @@ int BMO_CountFlag(struct BMesh *bm, int flag, int type);
%hv will do verts, etc. must pass in at least one
element type letter.
%f[f/e/v] - same as %h.
%v - pointer to a float vector of length 3.
%m[3/4] - matrix, 3/4 refers to the matrix size, 3 or 4. the
corrusponding argument must be a pointer to
a float matrix.
%s - copy a slot from another op, instead of mapping to one
argument, it maps to two, a pointer to an operator and
a slot name.
*/
/*executes an operator*/
int BMO_CallOpf(BMesh *bm, char *fmt, ...);
@@ -196,6 +204,13 @@ void *BMO_Get_Pnt(BMOperator *op, char *slotname);
void BMO_Set_Vec(struct BMOperator *op, char *slotname, float *vec);
void BMO_Get_Vec(BMOperator *op, char *slotname, float *vec_out);
/*only supports square mats*/
/*size must be 3 or 4; this api is meant only for transformation matrices.
note that internally the matrix is stored in 4x4 form, and it's safe to
call whichever BMO_Get_Mat* function you want.*/
void BMO_Set_Mat(struct BMOperator *op, char *slotname, float *mat, int size);
void BMO_Get_Mat4(struct BMOperator *op, char *slotname, float mat[4][4]);
void BMO_Get_Mat3(struct BMOperator *op, char *slotname, float mat[3][3]);
/*puts every element of type type (which is a bitmask) with tool flag flag,
into a slot.*/

View File

@@ -3,15 +3,35 @@
#include <stdio.h>
/*applies a transform to vertices*/
BMOpDefine def_translate= {
"translate",
{{BMOP_OPSLOT_VEC, "vec"},
{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
{0, /*null-terminating sentinel*/}},
bmesh_translate_exec,
0,
};
BMOpDefine def_transform = {
"transform",
{{BMOP_OPSLOT_MAT, "mat"},
{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
{0, /*null-terminating sentinel*/}},
bmesh_transform_exec,
0,
};
/*loads a bmesh into an object*/
BMOpDefine def_object_load_bmesh = {
"object_load_bmesh",
/*pointer to a mesh struct*/
{{BMOP_OPSLOT_PNT, "scene"},
{BMOP_OPSLOT_PNT, "object"},
{0, /*null-terminating sentinel*/}},
bmesh_to_mesh_exec,
0
0,
};
@@ -191,6 +211,8 @@ BMOpDefine *opdefines[] = {
&def_extrudeverts_indiv,
&def_mesh_to_bmesh,
&def_object_load_bmesh,
&def_transform,
&def_translate,
};
int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*));

View File

@@ -1,5 +1,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_arithb.h"
#include "BLI_memarena.h"
#include "BLI_mempool.h"
#include "BLI_blenlib.h"
@@ -259,6 +260,45 @@ void BMO_Set_Int(BMOperator *op, char *slotname, int i)
slot->data.i = i;
}
/*only supports square mats*/
void BMO_Set_Mat(struct BMOperator *op, char *slotname, float *mat, int size)
{
BMOpSlot *slot = BMO_GetSlot(op, slotname);
if( !(slot->slottype == BMOP_OPSLOT_MAT) )
return 0;
slot->len = 4;
slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float)*4*4);
if (size == 4) {
memcpy(slot->data.p, mat, sizeof(float)*4*4);
} else if (size == 3) {
Mat4CpyMat3(slot->data.p, mat);
} else {
printf("yeek! invalid size in BMO_Set_Mat!\n");
memset(slot->data.p, 0, sizeof(float)*4*4);
return;
}
}
void BMO_Get_Mat4(struct BMOperator *op, char *slotname, float mat[4][4])
{
BMOpSlot *slot = BMO_GetSlot(op, slotname);
if( !(slot->slottype == BMOP_OPSLOT_MAT) )
return;
memcpy(mat, slot->data.p, sizeof(float)*4*4);
}
void BMO_Get_Mat3(struct BMOperator *op, char *slotname, float mat[3][3])
{
BMOpSlot *slot = BMO_GetSlot(op, slotname);
if( !(slot->slottype == BMOP_OPSLOT_MAT) )
return;
Mat3CpyMat4(mat, slot->data.p);
}
void BMO_Set_Pnt(BMOperator *op, char *slotname, void *p)
{
@@ -1028,6 +1068,33 @@ int BMO_VInitOpf(BMesh *bm, BMOperator *op, char *fmt, va_list vlist)
case '=':
case '%':
break;
case 'm': {
int size, c;
c = nextc(fmt);
fmt++;
if (c == '3') size = 3;
else if (c == '4') size = 4;
else goto error;
BMO_Set_Mat(op, slotname, va_arg(vlist, void*), size);
state = 1;
break;
}
case 'v': {
BMO_Set_Vec(op, slotname, va_arg(vlist, float*));
state = 1;
break;
}
case 's': {
BMOperator *op2 = va_arg(vlist, void*);
char *slotname2 = va_arg(vlist, char*);
BMO_CopySlot(op2, op, slotname2, slotname);
state = 1;
break;
}
case 'i':
case 'd':
BMO_Set_Int(op, slotname, va_arg(vlist, int));

View File

@@ -23,5 +23,7 @@ void makeprim_exec(BMesh *bm, BMOperator *op);
void extrude_vert_indiv_exec(BMesh *bm, BMOperator *op);
void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op);
void bmesh_to_mesh_exec(BMesh *bm, BMOperator *op);
void bmesh_translate_exec(BMesh *bm, BMOperator *op);
void bmesh_transform_exec(BMesh *bm, BMOperator *op);
#endif

View File

@@ -0,0 +1,63 @@
#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_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") {
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) {
BMOIter iter;
BMVert *v;
float mat[4][4], vec[3];
BMO_Get_Vec(op, "offset", vec);
Mat4One(mat);
VECCOPY(mat[3], vec);
BMO_CallOpf(bm, "transform mat=%m4 verts=%s", mat, op, "verts");
}

View File

@@ -466,7 +466,7 @@ short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float
return 'g'; // g is grab
}
short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int eflag, float *nor)
short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
{
BMesh *bm = em->bm;
BMIter iter;
@@ -475,24 +475,9 @@ short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int eflag, float *nor)
BMVert *vert;
BMEdge *edge;
BMFace *f;
void *el;
ModifierData *md;
int flag;
BMHeader *el;
switch (eflag) {
case SELECT:
flag = BM_SELECT;
break;
default:
flag = BM_SELECT;
break;
}
for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);f;f=BMIter_Step(&iter)) {
add_normal_aligned(nor, f->no);
}
Normalize(nor);
BMO_Init_Op(&extop, "extrudefaceregion");
BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
flag, BM_VERT|BM_EDGE|BM_FACE);
@@ -561,10 +546,19 @@ short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int eflag, float *nor)
BMO_Exec_Op(bm, &extop);
nor[0] = nor[1] = nor[2] = 0.0f;
BMO_ITER(el, &siter, bm, &extop, "geomout") {
BM_Select(bm, el, 1);
if (el->type == BM_FACE) {
f = (BMFace*)el;
add_normal_aligned(nor, f->no);
};
}
Normalize(nor);
BMO_Finish_Op(bm, &extop);
if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
@@ -576,29 +570,6 @@ short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
BMIter iter;
BMEdge *eed;
/*ensure vert flags are consistent for edge selections*/
eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
for ( ; eed; eed=BMIter_Step(&iter)) {
if (BM_TestHFlag(eed, flag)) {
BM_SetHFlag(eed->v1, flag);
BM_SetHFlag(eed->v2, flag);
} else {
if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag))
BM_SetHFlag(eed, flag);
}
}
return EDBM_Extrude_edge(obedit, em, flag, nor);
}
/* generic extrude */
short EDBM_Extrude(Object *obedit, BMEditMesh *em, short flag, float *nor)
{
if(em->selectmode & SCE_SELECT_VERTEX) {
BMIter iter;
BMEdge *eed;
/*ensure vert flags are consistent for edge selections*/
eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
for ( ; eed; eed=BMIter_Step(&iter)) {
@@ -620,18 +591,13 @@ short EDBM_Extrude(Object *obedit, BMEditMesh *em, short flag, float *nor)
}
return EDBM_Extrude_edge(obedit, em, flag, nor);
} else
return EDBM_Extrude_edge(obedit, em, flag, nor);
}
}
static int extrude_repeat_mesh(bContext *C, wmOperator *op)
{
#if 0
Object *obedit= CTX_data_edit_object(C);
EditMesh *em= EM_GetEditMesh((Mesh *)obedit->data);
BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
RegionView3D *rv3d = CTX_wm_region_view3d(C);
int steps = RNA_int_get(op->ptr,"steps");
@@ -656,19 +622,18 @@ static int extrude_repeat_mesh(bContext *C, wmOperator *op)
Mat3MulVecfl(tmat, dvec);
for(a=0; a<steps; a++) {
extrudeflag(obedit, em, SELECT, nor);
translateflag(em, SELECT, dvec);
EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
//BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
//extrudeflag(obedit, em, SELECT, nor);
//translateflag(em, SELECT, dvec);
}
recalc_editnormals(em);
EM_fgon_flags(em);
EDBM_RecalcNormals(em);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
EM_EndEditMesh(obedit->data, em);
#endif
return OPERATOR_FINISHED;
}
@@ -729,7 +694,9 @@ void EDBM_Extrude_Mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
if(nr<1) return;
if(nr==1) transmode= EDBM_Extrude(obedit, em, SELECT, nor);
if(nr==1 && em->selectmode & SCE_SELECT_VERTEX)
transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, SELECT, nor);
else transmode= EDBM_Extrude_face_indiv(em, SELECT, nor);
@@ -850,3 +817,126 @@ void MESH_OT_select_all_toggle(wmOperatorType *ot)
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* *************** add-click-mesh (extrude) operator ************** */
static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
{
#if 0 //BMESH_TODO
ViewContext vc;
EditVert *eve, *v1;
float min[3], max[3];
int done= 0;
em_setup_viewcontext(C, &vc);
INIT_MINMAX(min, max);
for(v1= vc.em->verts.first;v1; v1=v1->next) {
if(v1->f & SELECT) {
DO_MINMAX(v1->co, min, max);
done= 1;
}
}
/* call extrude? */
if(done) {
EditEdge *eed;
float vec[3], cent[3], mat[3][3];
float nor[3]= {0.0, 0.0, 0.0};
/* check for edges that are half selected, use for rotation */
done= 0;
for(eed= vc.em->edges.first; eed; eed= eed->next) {
if( (eed->v1->f & SELECT)+(eed->v2->f & SELECT) == SELECT ) {
if(eed->v1->f & SELECT) VecSubf(vec, eed->v1->co, eed->v2->co);
else VecSubf(vec, eed->v2->co, eed->v1->co);
VecAddf(nor, nor, vec);
done= 1;
}
}
if(done) Normalize(nor);
/* center */
VecAddf(cent, min, max);
VecMulf(cent, 0.5f);
VECCOPY(min, cent);
Mat4MulVecfl(vc.obedit->obmat, min); // view space
view3d_get_view_aligned_coordinate(&vc, min, event->mval);
Mat4Invert(vc.obedit->imat, vc.obedit->obmat);
Mat4MulVecfl(vc.obedit->imat, min); // back in object space
VecSubf(min, min, cent);
/* calculate rotation */
Mat3One(mat);
if(done) {
float dot;
VECCOPY(vec, min);
Normalize(vec);
dot= INPR(vec, nor);
if( fabs(dot)<0.999) {
float cross[3], si, q1[4];
Crossf(cross, nor, vec);
Normalize(cross);
dot= 0.5f*saacos(dot);
si= (float)sin(dot);
q1[0]= (float)cos(dot);
q1[1]= cross[0]*si;
q1[2]= cross[1]*si;
q1[3]= cross[2]*si;
QuatToMat3(q1, mat);
}
}
extrudeflag(vc.obedit, vc.em, SELECT, nor);
rotateflag(vc.em, SELECT, cent, mat);
translateflag(vc.em, SELECT, min);
recalc_editnormals(vc.em);
}
else {
float mat[3][3],imat[3][3];
float *curs= give_cursor(vc.scene, vc.v3d);
VECCOPY(min, curs);
view3d_get_view_aligned_coordinate(&vc, min, event->mval);
eve= addvertlist(vc.em, 0, NULL);
Mat3CpyMat4(mat, vc.obedit->obmat);
Mat3Inv(imat, mat);
VECCOPY(eve->co, min);
Mat3MulVecfl(imat, eve->co);
VecSubf(eve->co, eve->co, vc.obedit->obmat[3]);
eve->f= SELECT;
}
//retopo_do_all();
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
return OPERATOR_FINISHED;
#endif
}
void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Duplicate or Extrude at 3D Cursor";
ot->idname= "MESH_OT_dupli_extrude_cursor";
/* api callbacks */
ot->invoke= dupli_extrude_cursor;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}

View File

@@ -119,129 +119,6 @@ static short icoface[20][3] = {
{10,9,11}
};
/* *************** add-click-mesh (extrude) operator ************** */
static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
{
#if 0 //BMESH_TODO
ViewContext vc;
EditVert *eve, *v1;
float min[3], max[3];
int done= 0;
em_setup_viewcontext(C, &vc);
INIT_MINMAX(min, max);
for(v1= vc.em->verts.first;v1; v1=v1->next) {
if(v1->f & SELECT) {
DO_MINMAX(v1->co, min, max);
done= 1;
}
}
/* call extrude? */
if(done) {
EditEdge *eed;
float vec[3], cent[3], mat[3][3];
float nor[3]= {0.0, 0.0, 0.0};
/* check for edges that are half selected, use for rotation */
done= 0;
for(eed= vc.em->edges.first; eed; eed= eed->next) {
if( (eed->v1->f & SELECT)+(eed->v2->f & SELECT) == SELECT ) {
if(eed->v1->f & SELECT) VecSubf(vec, eed->v1->co, eed->v2->co);
else VecSubf(vec, eed->v2->co, eed->v1->co);
VecAddf(nor, nor, vec);
done= 1;
}
}
if(done) Normalize(nor);
/* center */
VecAddf(cent, min, max);
VecMulf(cent, 0.5f);
VECCOPY(min, cent);
Mat4MulVecfl(vc.obedit->obmat, min); // view space
view3d_get_view_aligned_coordinate(&vc, min, event->mval);
Mat4Invert(vc.obedit->imat, vc.obedit->obmat);
Mat4MulVecfl(vc.obedit->imat, min); // back in object space
VecSubf(min, min, cent);
/* calculate rotation */
Mat3One(mat);
if(done) {
float dot;
VECCOPY(vec, min);
Normalize(vec);
dot= INPR(vec, nor);
if( fabs(dot)<0.999) {
float cross[3], si, q1[4];
Crossf(cross, nor, vec);
Normalize(cross);
dot= 0.5f*saacos(dot);
si= (float)sin(dot);
q1[0]= (float)cos(dot);
q1[1]= cross[0]*si;
q1[2]= cross[1]*si;
q1[3]= cross[2]*si;
QuatToMat3(q1, mat);
}
}
extrudeflag(vc.obedit, vc.em, SELECT, nor);
rotateflag(vc.em, SELECT, cent, mat);
translateflag(vc.em, SELECT, min);
recalc_editnormals(vc.em);
}
else {
float mat[3][3],imat[3][3];
float *curs= give_cursor(vc.scene, vc.v3d);
VECCOPY(min, curs);
view3d_get_view_aligned_coordinate(&vc, min, event->mval);
eve= addvertlist(vc.em, 0, NULL);
Mat3CpyMat4(mat, vc.obedit->obmat);
Mat3Inv(imat, mat);
VECCOPY(eve->co, min);
Mat3MulVecfl(imat, eve->co);
VecSubf(eve->co, eve->co, vc.obedit->obmat[3]);
eve->f= SELECT;
}
//retopo_do_all();
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
return OPERATOR_FINISHED;
#endif
}
void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Duplicate or Extrude at 3D Cursor";
ot->idname= "MESH_OT_dupli_extrude_cursor";
/* api callbacks */
ot->invoke= dupli_extrude_cursor;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* ********************** */

View File

@@ -265,7 +265,7 @@ void ED_keymap_mesh(wmWindowManager *wm)
WM_keymap_add_item(keymap, "MESH_OT_tris_convert_to_quads", JKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "MESH_OT_split", FOURKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "MESH_OT_extrude_repeat", FOURKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "MESH_OT_extrude_repeat", FOURKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
WM_keymap_add_item(keymap, "MESH_OT_edge_rotate", FIVEKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "MESH_OT_loop_to_region",SIXKEY, KM_PRESS, KM_CTRL, 0);

View File

@@ -478,6 +478,7 @@ void recalcData(TransInfo *t)
DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
BMEdit_RecalcTesselation(em);
EDBM_RecalcNormals(em);
}
}