commit of transform pinning patch by Fabian Fricke (frigi). wip hotkey is enter/alt-enter to pin/unpin verts. pinned verts aren't affected by transform, e.g. grab, rotate, etc. this could probably work nicer for proportional editing, but that can be done later. also the UI for this probably needs reviewing and feedback. still, very nice patch by Fabian, something I for one will probably find very useful :)

This commit is contained in:
Joseph Eagar 2009-09-10 03:59:12 +00:00
parent b0a1904d33
commit 4c072f85d9
18 changed files with 368 additions and 9 deletions

@ -109,6 +109,7 @@ struct EditMesh;
#define BM_SMOOTH (1<<5)
#define BM_ACTIVE (1<<6)
#define BM_NONORMCALC (1<<7)
#define BM_PINNED (1<<8)
typedef struct BMHeader {
struct BMHeader *next, *prev;

@ -8,6 +8,12 @@ typedef struct BMEditSelection
void *data;
} BMEditSelection;
/* pinning code */
void BM_Pin(BMesh *bm, void *element, int pin);
void BM_Pin_Vert(BMesh *bm, BMVert *v, int pin);
void BM_Pin_Edge(BMesh *bm, BMEdge *e, int pin);
void BM_Pin_Face(BMesh *bm, BMFace *f, int pin);
/*geometry hiding code*/
void BM_Hide(BMesh *bm, void *element, int hide);
void BM_Hide_Vert(BMesh *bm, BMVert *v, int hide);

@ -542,6 +542,7 @@ int BMFlags_To_MEFlags(void *element) {
BMHeader *h = element;
int f = 0;
if (h->flag & BM_PINNED) f |= ME_PIN;
if (h->flag & BM_HIDDEN) f |= ME_HIDE;
if (h->type == BM_FACE) {
@ -571,6 +572,7 @@ int BMFlags_To_MEFlags(void *element) {
*/
int MEFlags_To_BMFlags(int flag, int type) {
int f = 0;
if (flag & ME_PIN) f |= BM_PINNED;
if (type == BM_FACE) {
if (flag & ME_FACE_SEL) f |= BM_SELECT;

@ -532,6 +532,51 @@ void BM_validate_selections(BMesh *em)
}
}
/***************** Pinning **************/
#define SETPIN(ele) pin ? BM_SetHFlag(ele, BM_PINNED) : BM_ClearHFlag(ele, BM_PINNED);
void BM_Pin_Vert(BMesh *bm, BMVert *v, int pin)
{
SETPIN(v);
}
void BM_Pin_Edge(BMesh *bm, BMEdge *e, int pin)
{
SETPIN(e->v1);
SETPIN(e->v2);
}
void BM_Pin_Face(BMesh *bm, BMFace *f, int pin)
{
BMIter vfiter;
BMVert *vf;
BM_ITER(vf, &vfiter, bm, BM_VERTS_OF_FACE, f) {
SETPIN(vf);
}
}
void BM_Pin(BMesh *bm, void *element, int pin)
{
BMHeader *h = element;
switch (h->type) {
case BM_VERT:
BM_Pin_Vert(bm, element, pin);
break;
case BM_EDGE:
BM_Pin_Edge(bm, element, pin);
break;
case BM_FACE:
BM_Pin_Face(bm, element, pin);
break;
}
}
/***************** Mesh Hiding stuff *************/
#define SETHIDE(ele) hide ? BM_SetHFlag(ele, BM_HIDDEN) : BM_ClearHFlag(ele, BM_HIDDEN);

@ -194,8 +194,6 @@ void BM_Compute_Normals(BMesh *bm)
unsigned int maxlength = 0;
float (*projectverts)[3];
//return;
/*first, find out the largest face in mesh*/
for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){
if (BM_TestHFlag(f, BM_HIDDEN))

@ -111,6 +111,9 @@ void EDBM_editselection_plane(struct BMEditMesh *em, float *plane, struct BMEdit
void EDBM_editselection_normal(float *normal, struct BMEditSelection *ese);
int EDBM_vertColorCheck(struct BMEditMesh *em);
void EDBM_pin_mesh(struct BMEditMesh *em, int swap);
void EDBM_unpin_mesh(struct BMEditMesh *em, int swap);
void EDBM_hide_mesh(struct BMEditMesh *em, int swap);
void EDBM_reveal_mesh(struct BMEditMesh *em);

@ -202,6 +202,9 @@ enum {
TH_DOPESHEET_CHANNELOB,
TH_DOPESHEET_CHANNELSUBOB,
TH_PIN,
TH_PIN_OPAC,
};
/* XXX WARNING: previous is saved in file, so do not change order! */

@ -355,6 +355,10 @@ char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_DOPESHEET_CHANNELSUBOB:
cp= ts->ds_subchannel;
break;
case TH_PIN:
cp= ts->pin; break;
case TH_PIN_OPAC:
cp= &ts->pin_opac; break;
}
}
@ -475,6 +479,9 @@ void ui_theme_init_userdef(void)
SETCOL(btheme->tv3d.bone_solid, 200, 200, 200, 255);
SETCOL(btheme->tv3d.bone_pose, 80, 200, 255, 80); // alpha 80 is not meant editable, used for wire+action draw
SETCOL(btheme->tv3d.pin, 115, 171, 209, 255);
btheme->tv3d.pin_opac = 40;
/* space buttons */

@ -1703,6 +1703,127 @@ void MESH_OT_edge_rotate(wmOperatorType *ot)
RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around.");
}
/* pinning code */
/* swap is 0 or 1, if 1 it pins not selected */
void EDBM_pin_mesh(BMEditMesh *em, int swap)
{
BMIter iter;
BMHeader *h;
int itermode;
if(em==NULL) return;
if (em->selectmode & SCE_SELECT_VERTEX)
itermode = BM_VERTS_OF_MESH;
else if (em->selectmode & SCE_SELECT_EDGE)
itermode = BM_EDGES_OF_MESH;
else
itermode = BM_FACES_OF_MESH;
BM_ITER(h, &iter, em->bm, itermode, NULL) {
if (BM_TestHFlag(h, BM_SELECT) ^ swap)
BM_Pin(em->bm, h, 1);
}
EDBM_selectmode_flush(em);
}
static int pin_mesh_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
Mesh *me= ((Mesh *)obedit->data);
me->drawflag |= ME_DRAW_PINS;
EDBM_pin_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
return OPERATOR_FINISHED;
}
void MESH_OT_pin(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Pin Selection";
ot->idname= "MESH_OT_pin";
/* api callbacks */
ot->exec= pin_mesh_exec;
ot->poll= ED_operator_editmesh;
ot->description= "Pin (un)selected vertices, edges or faces.";
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* props */
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Pin unselected rather than selected.");
}
/* swap is 0 or 1, if 1 it unhides not selected */
void EDBM_unpin_mesh(BMEditMesh *em, int swap)
{
BMIter iter;
BMHeader *ele;
int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & SCE_SELECT_VERTEX | SCE_SELECT_EDGE)};
int itermode;
if(em==NULL) return;
if (em->selectmode & SCE_SELECT_VERTEX)
itermode = BM_VERTS_OF_MESH;
else if (em->selectmode & SCE_SELECT_EDGE)
itermode = BM_EDGES_OF_MESH;
else
itermode = BM_FACES_OF_MESH;
BM_ITER(ele, &iter, em->bm, itermode, NULL) {
if (BM_TestHFlag(ele, BM_SELECT) ^ swap)
BM_Pin(em->bm, ele, 0);
}
EDBM_selectmode_flush(em);
}
static int unpin_mesh_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
Mesh *me= ((Mesh *)obedit->data);
EDBM_unpin_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
return OPERATOR_FINISHED;
}
void MESH_OT_unpin(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Unpin Selection";
ot->idname= "MESH_OT_unpin";
ot->description= "Unpin (un)selected vertices, edges or faces.";
/* api callbacks */
ot->exec= unpin_mesh_exec;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* props */
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Unpin unselected rather than selected.");
}
/* swap is 0 or 1, if 1 it hides not selected */
void EDBM_hide_mesh(BMEditMesh *em, int swap)
{

@ -205,6 +205,8 @@ void MESH_OT_select_inverse(struct wmOperatorType *ot);
void MESH_OT_select_non_manifold(struct wmOperatorType *ot);
void MESH_OT_select_linked(struct wmOperatorType *ot);
void MESH_OT_select_linked_pick(struct wmOperatorType *ot);
void MESH_OT_pin(struct wmOperatorType *ot);
void MESH_OT_unpin(struct wmOperatorType *ot);
void MESH_OT_hide(struct wmOperatorType *ot);
void MESH_OT_reveal(struct wmOperatorType *ot);
void MESH_OT_select_by_number_vertices(struct wmOperatorType *ot);

@ -204,6 +204,8 @@ static int specials_invoke(bContext *C, wmOperator *op, wmEvent *event)
uiItemO(layout, "Remove Doubles", 0, "MESH_OT_remove_doubles");
uiItemO(layout, "Hide", 0, "MESH_OT_hide");
uiItemO(layout, "Reveal", 0, "MESH_OT_reveal");
uiItemO(layout, "Pin", 0, "MESH_OT_pin");
uiItemO(layout, "Unpin", 0, "MESH_OT_unpin");
uiItemO(layout, "Select Inverse", 0, "MESH_OT_select_inverse");
uiItemO(layout, NULL, 0, "MESH_OT_flip_normals");
uiItemO(layout, "Smooth", 0, "MESH_OT_vertices_smooth");
@ -248,6 +250,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_select_linked_pick);
WM_operatortype_append(MESH_OT_select_random);
WM_operatortype_append(MESH_OT_selection_type);
WM_operatortype_append(MESH_OT_pin);
WM_operatortype_append(MESH_OT_unpin);
WM_operatortype_append(MESH_OT_hide);
WM_operatortype_append(MESH_OT_reveal);
WM_operatortype_append(MESH_OT_select_by_number_vertices);
@ -396,6 +400,12 @@ void ED_keymap_mesh(wmWindowManager *wm)
/* selection mode */
WM_keymap_add_item(keymap, "MESH_OT_selection_type", TABKEY, KM_PRESS, KM_CTRL, 0);
/* pin */
WM_keymap_add_item(keymap, "MESH_OT_pin", RETKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "MESH_OT_pin", RETKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "unselected", 1);
WM_keymap_add_item(keymap, "MESH_OT_unpin", RETKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "MESH_OT_unpin", RETKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "unselected", 1);
/* hide */
WM_keymap_add_item(keymap, "MESH_OT_hide", HKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "MESH_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "unselected", 1);

@ -1528,6 +1528,62 @@ static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
glEnd();
}
/* check if all verts of the face are pinned */
static int check_pinned_face(BMesh *bm, BMFace *efa)
{
BMIter vfiter;
BMVert *v;
int vcount = 0;
BM_ITER(v, &vfiter, bm, BM_VERTS_OF_FACE, efa) {
if(BM_TestHFlag(v, BM_PINNED)) vcount ++;
}
if( vcount == efa->len) return 1;
return 0;
}
static void draw_dm_vert_pins__mapFunc(void *userData, int index, float *co)
{
struct {BMEditMesh *em; Mesh *me;} *data = userData;
BMVert *eve = EDBM_get_vert_for_index(data->em, index);
BMFace *fv;
BMIter fviter;
float vsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
int small=0;
if (!BM_TestHFlag(eve, BM_HIDDEN)) {
if (BM_TestHFlag(eve, BM_PINNED)) {
BM_ITER(fv, &fviter, data->em->bm, BM_FACES_OF_VERT, eve) {
small += check_pinned_face(data->em->bm, fv);
}
if(small == 0) {
bglEnd();
glPointSize(vsize*1.5);
glBegin(GL_POINTS);
glVertex3fv(co);
}
else {
bglEnd();
glPointSize(vsize*0.5);
glBegin(GL_POINTS);
glVertex3fv(co);
}
}
}
}
static void draw_dm_vert_pins(BMEditMesh *em, DerivedMesh *dm, Mesh *me)
{
struct { BMEditMesh *em; Mesh *me;} data;
data.em = em;
data.me = me;
dm->foreachMappedVert(dm, draw_dm_vert_pins__mapFunc, &data);
glEnd();
}
/* Draw verts with color set based on selection */
static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
{
@ -1661,6 +1717,55 @@ static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
}
/* Draw only pinned edges */
static int draw_dm_edges_pins__setDrawOptions(void *userData, int index)
{
struct {BMEditMesh *em; Mesh *me;} *data = userData;
BMEdge *eed = EDBM_get_edge_for_index(data->em, index);
BMIter feiter;
BMFace *fe;
int fcount, fpcount = 0;
int pin = 0;
/* If pinned faces are drawn then only draw pinned edges at the borders.
This looks way better and the user still has all the info he needs. */
if(data->me->drawflag & ME_DRAW_PINS) {
if( BM_TestHFlag(eed->v1, BM_PINNED) && BM_TestHFlag(eed->v2, BM_PINNED) ) {
pin = 1;
fcount = 0;
BM_ITER(fe, &feiter, data->em->bm, BM_FACES_OF_EDGE, eed) {
fcount ++;
fpcount += check_pinned_face(data->em->bm, fe);
}
}
}
else {
pin = BM_TestHFlag(eed->v1, BM_PINNED) && BM_TestHFlag(eed->v2, BM_PINNED);
}
if( !BM_TestHFlag(eed, BM_HIDDEN)) {
/* Edges with at least one adherent pinned face are considered borders.
If there are more than two adherent faces overall of which at least two are pinned it's also consideres a border. */
if( fpcount == 2 && fcount <= 2) {
return 0; }
else {
return pin; }
}
}
static void draw_dm_edges_pins(BMEditMesh *em, DerivedMesh *dm, Mesh *me)
{
struct { BMEditMesh *em; Mesh *me;} data;
data.em = em;
data.me = me;
dm->drawMappedEdges(dm, draw_dm_edges_pins__setDrawOptions, &data);
}
/* Draw only sharp edges */
static int draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
{
@ -1678,18 +1783,35 @@ static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
* return 2 for the active face so it renders with stipple enabled */
static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *drawSmooth_r)
{
struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; } *data = userData;
struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} *data = userData;
BMFace *efa = EDBM_get_face_for_index(data->em, index);
unsigned char *col;
BMIter vfiter;
BMVert *v;
int vcount, pin=0;
int opac = UI_GetThemeValue(TH_PIN_OPAC);
if (!BM_TestHFlag(efa, BM_HIDDEN)) {
/* Check if all verts of a face are pinned. If so, then display it in a darker shade. */
if(data->me->drawflag & ME_DRAW_PINS)
pin = check_pinned_face(data->em->bm, efa);
if (efa == data->efa_act) {
glColor4ubv(data->cols[2]);
if(pin==0) { glColor4ubv(data->cols[2]); }
else {
col = data->cols[2];
glColor4ub(col[0]-col[0]*0.9, col[1]-col[1]*0.9, col[2]-col[2]*0.9, opac*2.55);
}
return 2; /* stipple */
} else {
col = data->cols[BM_TestHFlag(efa, BM_SELECT)?1:0];
if (col[3]==0) return 0;
glColor4ubv(col);
if(pin==0) { glColor4ubv(col); }
else { glColor4ub(col[0]-col[0]*0.9, col[1]-col[1]*0.9, col[2]-col[2]*0.9, opac*2.55); }
return 1;
}
}
@ -1698,15 +1820,16 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *dra
/* also draws the active face */
static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
unsigned char *selCol, unsigned char *actCol, BMFace *efa_act, Mesh *me)
{
struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; } data;
struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} data;
data.cols[0] = baseCol;
data.em = em;
data.cols[1] = selCol;
data.cols[2] = actCol;
data.efa_act = efa_act;
data.me = me;
dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0);
}
@ -2168,7 +2291,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
if CHECK_OB_DRAWTEXTURE(v3d, dt)
col1[3] = 0;
draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@ -2183,7 +2306,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glEnable(GL_BLEND);
glDepthMask(0); // disable write in zbuffer, needed for nice transp
draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@ -2224,6 +2347,16 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
if(me->drawflag & ME_DRAWBWEIGHTS) {
draw_dm_bweights(em, scene, cageDM);
}
if(me->drawflag & ME_DRAW_PINS) {
UI_ThemeColor(TH_PIN);
glLineWidth(2);
draw_dm_edges_pins(em, cageDM, me);
glColor3ub(0,0,0);
glLineWidth(1);
}
draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
}
@ -2240,6 +2373,10 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
UI_ThemeColor(TH_NORMAL);
draw_dm_vert_normals(em, scene, cageDM);
}
if(me->drawflag & ME_DRAW_PINS) {
UI_ThemeColor(TH_PIN);
draw_dm_vert_pins(em, cageDM, me);
}
if(me->drawflag & (ME_DRAW_EDGELEN|ME_DRAW_FACEAREA|ME_DRAW_EDGEANG))
draw_em_measure_stats(v3d, rv3d, ob, em, &scene->unit);

@ -2281,6 +2281,9 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
if(propmode || selstate[a]) {
VertsToTransData(t, tob, bm, eve);
/* pinned */
if(BM_TestHFlag(eve,BM_PINNED)) tob->flag |= TD_SKIP;
/* selected */
if(selstate[a]) tob->flag |= TD_SELECTED;

@ -162,6 +162,8 @@ typedef struct TFace {
#define ME_DRAW_FACEAREA (1 << 11)
#define ME_DRAW_EDGEANG (1 << 12)
#define ME_DRAW_PINS (1 << 13)
/* old global flags:
#define G_DRAWEDGES (1 << 18)
#define G_DRAWFACES (1 << 7)

@ -210,6 +210,7 @@ typedef struct PartialVisibility {
#define ME_SPHERETEST 2
#define ME_SPHERETEMP 4
#define ME_HIDE 16
#define ME_PIN 64
#define ME_VERT_MERGED (1<<6)
/* medge->flag (1=SELECT)*/

@ -218,6 +218,9 @@ typedef struct ThemeSpace {
char hpad[3];
char pad[4];
char pin[4];
int pin_opac;
} ThemeSpace;

@ -1412,6 +1412,11 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Face Area", "Displays the area of selected faces");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "draw_pins", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_PINS);
RNA_def_property_ui_text(prop, "Draw Pins", "Displays pinned mesh elements");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
rna_def_texmat_common(srna, "rna_Mesh_texspace_editable");
RNA_api_mesh(srna);

@ -679,6 +679,16 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Current Frame", "");
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop= RNA_def_property(srna, "pin", PROP_FLOAT, PROP_COLOR);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Pin", "");
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop= RNA_def_property(srna, "pin_opac", PROP_INT, PROP_PERCENTAGE);
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop, "Pin Face Opacity", "");
RNA_def_property_update(prop, NC_WINDOW, NULL);
}
static void rna_def_userdef_theme_space_graph(BlenderRNA *brna)