2008-12-30 13:16:14 +00:00
|
|
|
/**
|
|
|
|
|
* $Id:
|
|
|
|
|
*
|
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2004 Blender Foundation.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
|
*
|
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
editmesh_mods.c, UI level access, no geometry changes
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2009-09-06 00:36:26 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
#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_texture_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
|
#include "DNA_space_types.h"
|
|
|
|
|
#include "DNA_view3d_types.h"
|
|
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "BLI_editVert.h"
|
|
|
|
|
#include "BLI_rand.h"
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
#include "BKE_context.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "BKE_displist.h"
|
|
|
|
|
#include "BKE_depsgraph.h"
|
|
|
|
|
#include "BKE_DerivedMesh.h"
|
|
|
|
|
#include "BKE_customdata.h"
|
|
|
|
|
#include "BKE_global.h"
|
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
|
#include "BKE_material.h"
|
2009-08-15 19:48:50 +00:00
|
|
|
#include "BKE_paint.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "BKE_texture.h"
|
|
|
|
|
#include "BKE_utildefines.h"
|
2009-02-14 21:31:34 +00:00
|
|
|
#include "BKE_report.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
|
|
|
|
|
|
#include "RE_render_ext.h" /* externtex */
|
|
|
|
|
|
2008-12-31 17:11:42 +00:00
|
|
|
#include "WM_api.h"
|
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
2009-10-07 09:23:29 +00:00
|
|
|
#include "UI_resources.h"
|
|
|
|
|
|
2009-01-01 13:15:35 +00:00
|
|
|
#include "RNA_access.h"
|
|
|
|
|
#include "RNA_define.h"
|
2009-11-26 19:32:33 +00:00
|
|
|
#include "RNA_enum_types.h"
|
2009-01-01 13:15:35 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "ED_mesh.h"
|
2009-01-01 13:15:35 +00:00
|
|
|
#include "ED_screen.h"
|
2008-12-30 16:03:29 +00:00
|
|
|
#include "ED_view3d.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
#include "BIF_gl.h"
|
|
|
|
|
#include "BIF_glutil.h"
|
|
|
|
|
|
2009-01-01 13:15:35 +00:00
|
|
|
#include "mesh_intern.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
#include "BLO_sys_types.h" // for intptr_t support
|
|
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* XXX */
|
2009-07-31 01:40:15 +00:00
|
|
|
static void waitcursor(int val) {}
|
2008-12-30 13:16:14 +00:00
|
|
|
static int pupmenu() {return 0;}
|
|
|
|
|
|
|
|
|
|
/* ****************************** MIRROR **************** */
|
|
|
|
|
|
2009-10-20 16:31:03 +00:00
|
|
|
void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-10-20 16:31:03 +00:00
|
|
|
EditVert *eve, *eve_mirror;
|
|
|
|
|
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
eve->tmp.v= NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if(eve->tmp.v==NULL) {
|
|
|
|
|
eve_mirror = editmesh_get_x_mirror_vert(ob, em, eve->co);
|
2009-10-20 17:10:01 +00:00
|
|
|
if(eve_mirror) {
|
|
|
|
|
eve->tmp.v= eve_mirror;
|
|
|
|
|
eve_mirror->tmp.v = eve;
|
|
|
|
|
}
|
2009-10-20 16:31:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EM_select_mirrored(Object *obedit, EditMesh *em, int extend)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
|
|
|
|
|
EM_cache_x_mirror_vert(obedit, em);
|
|
|
|
|
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if(eve->f & SELECT && eve->tmp.v) {
|
|
|
|
|
eve->tmp.v->f |= SELECT;
|
|
|
|
|
|
|
|
|
|
if(extend==FALSE)
|
|
|
|
|
eve->f &= ~SELECT;
|
|
|
|
|
|
|
|
|
|
/* remove the interference */
|
|
|
|
|
eve->tmp.v->tmp.v= eve->tmp.v= NULL;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-08 15:50:42 +00:00
|
|
|
void EM_automerge(Scene *scene, Object *obedit, int update)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-10-08 19:06:32 +00:00
|
|
|
Mesh *me= obedit ? obedit->data : NULL; /* can be NULL */
|
2009-10-08 15:50:42 +00:00
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
if ((scene->toolsettings->automerge) &&
|
2009-10-11 19:06:38 +00:00
|
|
|
(obedit && obedit->type==OB_MESH && (obedit->mode & OB_MODE_EDIT)) &&
|
2009-10-08 15:50:42 +00:00
|
|
|
(me->mr==NULL)
|
|
|
|
|
) {
|
|
|
|
|
Mesh *me= (Mesh*)obedit->data;
|
|
|
|
|
EditMesh *em= me->edit_mesh;
|
|
|
|
|
|
|
|
|
|
len = removedoublesflag(em, 1, 1, scene->toolsettings->doublimit);
|
|
|
|
|
if (len) {
|
|
|
|
|
em->totvert -= len; /* saves doing a countall */
|
|
|
|
|
if (update) {
|
|
|
|
|
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ****************************** SELECTION ROUTINES **************** */
|
|
|
|
|
|
|
|
|
|
unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0; /* set in drawobject.c ... for colorindices */
|
|
|
|
|
|
|
|
|
|
/* facilities for border select and circle select */
|
|
|
|
|
static char *selbuf= NULL;
|
|
|
|
|
|
|
|
|
|
/* opengl doesn't support concave... */
|
|
|
|
|
static void draw_triangulated(short mcords[][2], short tot)
|
|
|
|
|
{
|
|
|
|
|
ListBase lb={NULL, NULL};
|
|
|
|
|
DispList *dl;
|
|
|
|
|
float *fp;
|
|
|
|
|
int a;
|
|
|
|
|
|
|
|
|
|
/* make displist */
|
|
|
|
|
dl= MEM_callocN(sizeof(DispList), "poly disp");
|
|
|
|
|
dl->type= DL_POLY;
|
|
|
|
|
dl->parts= 1;
|
|
|
|
|
dl->nr= tot;
|
|
|
|
|
dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts");
|
|
|
|
|
BLI_addtail(&lb, dl);
|
|
|
|
|
|
|
|
|
|
for(a=0; a<tot; a++, fp+=3) {
|
|
|
|
|
fp[0]= (float)mcords[a][0];
|
|
|
|
|
fp[1]= (float)mcords[a][1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* do the fill */
|
|
|
|
|
filldisplist(&lb, &lb);
|
|
|
|
|
|
|
|
|
|
/* do the draw */
|
|
|
|
|
dl= lb.first; /* filldisplist adds in head of list */
|
|
|
|
|
if(dl->type==DL_INDEX3) {
|
|
|
|
|
int *index;
|
|
|
|
|
|
|
|
|
|
a= dl->parts;
|
|
|
|
|
fp= dl->verts;
|
|
|
|
|
index= dl->index;
|
|
|
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
|
while(a--) {
|
|
|
|
|
glVertex3fv(fp+3*index[0]);
|
|
|
|
|
glVertex3fv(fp+3*index[1]);
|
|
|
|
|
glVertex3fv(fp+3*index[2]);
|
|
|
|
|
index+= 3;
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
freedisplist(&lb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* reads rect, and builds selection array for quick lookup */
|
|
|
|
|
/* returns if all is OK */
|
2009-01-01 19:18:03 +00:00
|
|
|
int EM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
struct ImBuf *buf;
|
|
|
|
|
unsigned int *dr;
|
|
|
|
|
int a;
|
|
|
|
|
|
2009-01-02 19:10:35 +00:00
|
|
|
if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-01 19:18:03 +00:00
|
|
|
buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
|
2008-12-30 13:16:14 +00:00
|
|
|
if(buf==NULL) return 0;
|
2009-01-01 19:18:03 +00:00
|
|
|
if(em_vertoffs==0) return 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
dr = buf->rect;
|
|
|
|
|
|
|
|
|
|
/* build selection lookup */
|
|
|
|
|
selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
|
|
|
|
|
|
|
|
|
|
a= (xmax-xmin+1)*(ymax-ymin+1);
|
|
|
|
|
while(a--) {
|
|
|
|
|
if(*dr>0 && *dr<=em_vertoffs)
|
|
|
|
|
selbuf[*dr]= 1;
|
|
|
|
|
dr++;
|
|
|
|
|
}
|
|
|
|
|
IMB_freeImBuf(buf);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int EM_check_backbuf(unsigned int index)
|
|
|
|
|
{
|
|
|
|
|
if(selbuf==NULL) return 1;
|
|
|
|
|
if(index>0 && index<=em_vertoffs)
|
|
|
|
|
return selbuf[index];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EM_free_backbuf(void)
|
|
|
|
|
{
|
|
|
|
|
if(selbuf) MEM_freeN(selbuf);
|
|
|
|
|
selbuf= NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* mcords is a polygon mask
|
|
|
|
|
- grab backbuffer,
|
|
|
|
|
- draw with black in backbuffer,
|
|
|
|
|
- grab again and compare
|
|
|
|
|
returns 'OK'
|
|
|
|
|
*/
|
2009-01-01 19:18:03 +00:00
|
|
|
int EM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
unsigned int *dr, *drm;
|
|
|
|
|
struct ImBuf *buf, *bufmask;
|
|
|
|
|
int a;
|
|
|
|
|
|
|
|
|
|
/* method in use for face selecting too */
|
2009-01-02 19:10:35 +00:00
|
|
|
if(vc->obedit==NULL) {
|
2009-08-15 19:48:50 +00:00
|
|
|
if(paint_facesel_test(vc->obact));
|
2008-12-30 13:16:14 +00:00
|
|
|
else return 0;
|
|
|
|
|
}
|
2009-01-01 19:18:03 +00:00
|
|
|
else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-01 19:18:03 +00:00
|
|
|
buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
|
2008-12-30 13:16:14 +00:00
|
|
|
if(buf==NULL) return 0;
|
2.5
Sanitized the 'tweak' event.
Original idea was to have WM event system generating it
automatically. However, I first tested it via a handler
and operator, to check what kind of configurations would
be useful. It appeared to not work nice, also because
that inserting a tweak operator in a keymap is confusing.
Now 'tweaks' are generated automatically, and can be
catched by keymaps as any event. The current definition
of tweak is:
- if Left/Middle/Rightmouse pressed
if event wasn't handled by window queue (modal handlers)
start checking mousepositions
- while mousepositions are checked
- escape on any event other than mouse
- on mouse events:
- add tweak event if mousemove > 10 pixels
- stop checking for tweak if mousebutton released
- Tweak events have a define indicating mousebutton used
EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R
- In keymap definitions you can use _S or _A to map to
action or select mouse userdef.
- Event value in keymap should be KM_ANY for all tweaks,
or use one of the eight directions:
EVT_GESTURE_E, _SE, _S, _SW, _W, _NW, _N, _NE
- And of course you can add modifier checks in keymaps for it.
- Because tweaks are a result of mouse events, the handlers get
both to evaluate. That means that RMB-select + tweak will work
correctly.
In case you don't want both to be handled, for example the
CTRL+LMB 'extrude' and CTRL+LMB-tweak 'lasso select', you will
need to set the first acting on a EVT_RELEASE, this event only
gets passed on when tweak fails.
The current system allows all options, configurable, we had in 2.48,
and many more! A diagram of what's possible is on the todo. :)
Also in this commit: lasso select editmesh failed with 'zbuffer
occluded select'. Also circle-select failed.
2009-02-02 14:13:14 +00:00
|
|
|
if(em_vertoffs==0) return 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
dr = buf->rect;
|
|
|
|
|
|
|
|
|
|
/* draw the mask */
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
|
|
|
|
|
|
glColor3ub(0, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* yah, opengl doesn't do concave... tsk! */
|
2.5
Sanitized the 'tweak' event.
Original idea was to have WM event system generating it
automatically. However, I first tested it via a handler
and operator, to check what kind of configurations would
be useful. It appeared to not work nice, also because
that inserting a tweak operator in a keymap is confusing.
Now 'tweaks' are generated automatically, and can be
catched by keymaps as any event. The current definition
of tweak is:
- if Left/Middle/Rightmouse pressed
if event wasn't handled by window queue (modal handlers)
start checking mousepositions
- while mousepositions are checked
- escape on any event other than mouse
- on mouse events:
- add tweak event if mousemove > 10 pixels
- stop checking for tweak if mousebutton released
- Tweak events have a define indicating mousebutton used
EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R
- In keymap definitions you can use _S or _A to map to
action or select mouse userdef.
- Event value in keymap should be KM_ANY for all tweaks,
or use one of the eight directions:
EVT_GESTURE_E, _SE, _S, _SW, _W, _NW, _N, _NE
- And of course you can add modifier checks in keymaps for it.
- Because tweaks are a result of mouse events, the handlers get
both to evaluate. That means that RMB-select + tweak will work
correctly.
In case you don't want both to be handled, for example the
CTRL+LMB 'extrude' and CTRL+LMB-tweak 'lasso select', you will
need to set the first acting on a EVT_RELEASE, this event only
gets passed on when tweak fails.
The current system allows all options, configurable, we had in 2.48,
and many more! A diagram of what's possible is on the todo. :)
Also in this commit: lasso select editmesh failed with 'zbuffer
occluded select'. Also circle-select failed.
2009-02-02 14:13:14 +00:00
|
|
|
ED_region_pixelspace(vc->ar);
|
2008-12-30 13:16:14 +00:00
|
|
|
draw_triangulated(mcords, tot);
|
|
|
|
|
|
|
|
|
|
glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
|
|
|
|
|
for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
|
|
glFinish(); /* to be sure readpixels sees mask */
|
|
|
|
|
|
|
|
|
|
/* grab mask */
|
2009-01-01 19:18:03 +00:00
|
|
|
bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
|
2008-12-30 13:16:14 +00:00
|
|
|
drm = bufmask->rect;
|
|
|
|
|
if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
|
|
|
|
|
|
|
|
|
|
/* build selection lookup */
|
|
|
|
|
selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
|
|
|
|
|
|
|
|
|
|
a= (xmax-xmin+1)*(ymax-ymin+1);
|
|
|
|
|
while(a--) {
|
|
|
|
|
if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
|
|
|
|
|
dr++; drm++;
|
|
|
|
|
}
|
|
|
|
|
IMB_freeImBuf(buf);
|
|
|
|
|
IMB_freeImBuf(bufmask);
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* circle shaped sample area */
|
2009-01-01 19:18:03 +00:00
|
|
|
int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
struct ImBuf *buf;
|
|
|
|
|
unsigned int *dr;
|
|
|
|
|
short xmin, ymin, xmax, ymax, xc, yc;
|
|
|
|
|
int radsq;
|
|
|
|
|
|
|
|
|
|
/* method in use for face selecting too */
|
2009-01-02 19:10:35 +00:00
|
|
|
if(vc->obedit==NULL) {
|
2009-08-15 19:48:50 +00:00
|
|
|
if(paint_facesel_test(vc->obact));
|
2008-12-30 13:16:14 +00:00
|
|
|
else return 0;
|
|
|
|
|
}
|
2009-01-01 19:18:03 +00:00
|
|
|
else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
xmin= xs-rads; xmax= xs+rads;
|
|
|
|
|
ymin= ys-rads; ymax= ys+rads;
|
2009-01-01 19:18:03 +00:00
|
|
|
buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
|
2.5
Sanitized the 'tweak' event.
Original idea was to have WM event system generating it
automatically. However, I first tested it via a handler
and operator, to check what kind of configurations would
be useful. It appeared to not work nice, also because
that inserting a tweak operator in a keymap is confusing.
Now 'tweaks' are generated automatically, and can be
catched by keymaps as any event. The current definition
of tweak is:
- if Left/Middle/Rightmouse pressed
if event wasn't handled by window queue (modal handlers)
start checking mousepositions
- while mousepositions are checked
- escape on any event other than mouse
- on mouse events:
- add tweak event if mousemove > 10 pixels
- stop checking for tweak if mousebutton released
- Tweak events have a define indicating mousebutton used
EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R
- In keymap definitions you can use _S or _A to map to
action or select mouse userdef.
- Event value in keymap should be KM_ANY for all tweaks,
or use one of the eight directions:
EVT_GESTURE_E, _SE, _S, _SW, _W, _NW, _N, _NE
- And of course you can add modifier checks in keymaps for it.
- Because tweaks are a result of mouse events, the handlers get
both to evaluate. That means that RMB-select + tweak will work
correctly.
In case you don't want both to be handled, for example the
CTRL+LMB 'extrude' and CTRL+LMB-tweak 'lasso select', you will
need to set the first acting on a EVT_RELEASE, this event only
gets passed on when tweak fails.
The current system allows all options, configurable, we had in 2.48,
and many more! A diagram of what's possible is on the todo. :)
Also in this commit: lasso select editmesh failed with 'zbuffer
occluded select'. Also circle-select failed.
2009-02-02 14:13:14 +00:00
|
|
|
if(em_vertoffs==0) return 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
if(buf==NULL) return 0;
|
|
|
|
|
|
|
|
|
|
dr = buf->rect;
|
|
|
|
|
|
|
|
|
|
/* build selection lookup */
|
|
|
|
|
selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
|
|
|
|
|
radsq= rads*rads;
|
|
|
|
|
for(yc= -rads; yc<=rads; yc++) {
|
|
|
|
|
for(xc= -rads; xc<=rads; xc++, dr++) {
|
|
|
|
|
if(xc*xc + yc*yc < radsq) {
|
|
|
|
|
if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IMB_freeImBuf(buf);
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
|
|
|
|
|
{
|
|
|
|
|
struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
|
|
|
|
|
|
|
|
|
|
if (data->pass==0) {
|
|
|
|
|
if (index<=data->lastIndex)
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
if (index>data->lastIndex)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data->dist>3) {
|
|
|
|
|
int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
|
|
|
|
|
if ((eve->f&1) == data->select) {
|
|
|
|
|
if (data->strict == 1)
|
|
|
|
|
return;
|
|
|
|
|
else
|
|
|
|
|
temp += 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (temp<data->dist) {
|
|
|
|
|
data->dist = temp;
|
|
|
|
|
data->closest = eve;
|
|
|
|
|
data->closestIndex = index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-01-15 15:01:39 +00:00
|
|
|
static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-15 15:01:39 +00:00
|
|
|
EditMesh *em= (EditMesh *)handle;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditVert *eve = BLI_findlink(&em->verts, index-1);
|
|
|
|
|
|
|
|
|
|
if(eve && (eve->f & SELECT)) return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* findnearestvert
|
|
|
|
|
*
|
|
|
|
|
* dist (in/out): minimal distance to the nearest and at the end, actual distance
|
|
|
|
|
* sel: selection bias
|
|
|
|
|
* if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
|
|
|
|
|
* if 0, unselected vertice are given the bias
|
|
|
|
|
* strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
|
|
|
|
|
*/
|
2008-12-30 16:03:29 +00:00
|
|
|
EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2008-12-30 16:03:29 +00:00
|
|
|
if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
|
2008-12-30 13:16:14 +00:00
|
|
|
int distance;
|
|
|
|
|
unsigned int index;
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
|
2009-01-15 15:01:39 +00:00
|
|
|
if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest);
|
|
|
|
|
else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
eve = BLI_findlink(&vc->em->verts, index-1);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if(eve && distance < *dist) {
|
|
|
|
|
*dist = distance;
|
|
|
|
|
return eve;
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
|
|
|
|
|
static int lastSelectedIndex=0;
|
|
|
|
|
static EditVert *lastSelected=NULL;
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) {
|
2008-12-30 13:16:14 +00:00
|
|
|
lastSelectedIndex = 0;
|
|
|
|
|
lastSelected = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data.lastIndex = lastSelectedIndex;
|
2008-12-31 17:11:42 +00:00
|
|
|
data.mval[0] = vc->mval[0];
|
|
|
|
|
data.mval[1] = vc->mval[1];
|
2008-12-30 13:16:14 +00:00
|
|
|
data.select = sel;
|
|
|
|
|
data.dist = *dist;
|
|
|
|
|
data.strict = strict;
|
|
|
|
|
data.closest = NULL;
|
|
|
|
|
data.closestIndex = 0;
|
|
|
|
|
|
|
|
|
|
data.pass = 0;
|
2009-10-11 20:32:25 +00:00
|
|
|
|
|
|
|
|
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if (data.dist>3) {
|
|
|
|
|
data.pass = 1;
|
2008-12-30 16:03:29 +00:00
|
|
|
mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*dist = data.dist;
|
|
|
|
|
lastSelected = data.closest;
|
|
|
|
|
lastSelectedIndex = data.closestIndex;
|
|
|
|
|
|
|
|
|
|
return data.closest;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns labda for closest distance v1 to line-piece v2-v3 */
|
|
|
|
|
static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
|
|
|
|
|
{
|
|
|
|
|
float rc[2], len;
|
|
|
|
|
|
|
|
|
|
rc[0]= v3[0]-v2[0];
|
|
|
|
|
rc[1]= v3[1]-v2[1];
|
|
|
|
|
len= rc[0]*rc[0]+ rc[1]*rc[1];
|
|
|
|
|
if(len==0.0f)
|
|
|
|
|
return 0.0f;
|
|
|
|
|
|
|
|
|
|
return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* note; uses v3d, so needs active 3d window */
|
|
|
|
|
static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
|
|
|
|
|
{
|
2008-12-30 16:03:29 +00:00
|
|
|
struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData;
|
2008-12-30 13:16:14 +00:00
|
|
|
float v1[2], v2[2];
|
|
|
|
|
int distance;
|
2009-11-21 16:44:05 +00:00
|
|
|
|
|
|
|
|
ED_view3d_local_clipping(data->vc.rv3d, data->vc.obedit->obmat); /* for local clipping lookups */
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
v1[0] = x0;
|
|
|
|
|
v1[1] = y0;
|
|
|
|
|
v2[0] = x1;
|
|
|
|
|
v2[1] = y1;
|
2009-11-21 16:44:05 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
distance= dist_to_line_segment_v2(data->mval, v1, v2);
|
2009-11-21 16:44:05 +00:00
|
|
|
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
if(eed->f & SELECT) distance+=5;
|
|
|
|
|
if(distance < data->dist) {
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
|
2008-12-30 13:16:14 +00:00
|
|
|
float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
|
|
|
|
|
float vec[3];
|
|
|
|
|
|
|
|
|
|
vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
|
|
|
|
|
vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
|
|
|
|
|
vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
|
|
|
|
|
|
2009-11-21 16:44:05 +00:00
|
|
|
if(view3d_test_clipping(data->vc.rv3d, vec, 1)==0) {
|
2008-12-30 13:16:14 +00:00
|
|
|
data->dist = distance;
|
|
|
|
|
data->closest = eed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
data->dist = distance;
|
|
|
|
|
data->closest = eed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-30 16:03:29 +00:00
|
|
|
EditEdge *findnearestedge(ViewContext *vc, int *dist)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
|
2008-12-30 13:16:14 +00:00
|
|
|
int distance;
|
2009-01-15 15:01:39 +00:00
|
|
|
unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL, NULL);
|
2008-12-30 16:03:29 +00:00
|
|
|
EditEdge *eed = BLI_findlink(&vc->em->edges, index-1);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if (eed && distance<*dist) {
|
|
|
|
|
*dist = distance;
|
|
|
|
|
return eed;
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2008-12-30 16:03:29 +00:00
|
|
|
struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } data;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
data.vc= *vc;
|
2008-12-31 17:11:42 +00:00
|
|
|
data.mval[0] = vc->mval[0];
|
|
|
|
|
data.mval[1] = vc->mval[1];
|
2008-12-30 13:16:14 +00:00
|
|
|
data.dist = *dist;
|
|
|
|
|
data.closest = NULL;
|
|
|
|
|
|
2009-10-11 20:32:25 +00:00
|
|
|
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
|
2008-12-30 16:03:29 +00:00
|
|
|
mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
*dist = data.dist;
|
|
|
|
|
return data.closest;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int index)
|
|
|
|
|
{
|
|
|
|
|
struct { short mval[2]; int dist; EditFace *toFace; } *data = userData;
|
|
|
|
|
|
|
|
|
|
if (efa==data->toFace) {
|
|
|
|
|
int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
|
|
|
|
|
|
|
|
|
|
if (temp<data->dist)
|
|
|
|
|
data->dist = temp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
|
|
|
|
|
{
|
|
|
|
|
struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData;
|
|
|
|
|
|
|
|
|
|
if (data->pass==0) {
|
|
|
|
|
if (index<=data->lastIndex)
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
if (index>data->lastIndex)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data->dist>3) {
|
|
|
|
|
int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
|
|
|
|
|
|
|
|
|
|
if (temp<data->dist) {
|
|
|
|
|
data->dist = temp;
|
|
|
|
|
data->closest = efa;
|
|
|
|
|
data->closestIndex = index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-30 16:03:29 +00:00
|
|
|
static EditFace *findnearestface(ViewContext *vc, int *dist)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
|
2009-01-01 19:18:03 +00:00
|
|
|
unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
|
2008-12-30 16:03:29 +00:00
|
|
|
EditFace *efa = BLI_findlink(&vc->em->faces, index-1);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if (efa) {
|
|
|
|
|
struct { short mval[2]; int dist; EditFace *toFace; } data;
|
|
|
|
|
|
2008-12-31 17:11:42 +00:00
|
|
|
data.mval[0] = vc->mval[0];
|
|
|
|
|
data.mval[1] = vc->mval[1];
|
2008-12-30 13:16:14 +00:00
|
|
|
data.dist = 0x7FFF; /* largest short */
|
|
|
|
|
data.toFace = efa;
|
|
|
|
|
|
2009-10-11 20:32:25 +00:00
|
|
|
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
|
2008-12-30 16:03:29 +00:00
|
|
|
mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
|
2008-12-30 13:16:14 +00:00
|
|
|
*dist= data.dist;
|
|
|
|
|
return efa;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
|
|
|
|
|
static int lastSelectedIndex=0;
|
|
|
|
|
static EditFace *lastSelected=NULL;
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) {
|
2008-12-30 13:16:14 +00:00
|
|
|
lastSelectedIndex = 0;
|
|
|
|
|
lastSelected = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data.lastIndex = lastSelectedIndex;
|
2008-12-31 17:11:42 +00:00
|
|
|
data.mval[0] = vc->mval[0];
|
|
|
|
|
data.mval[1] = vc->mval[1];
|
2008-12-30 13:16:14 +00:00
|
|
|
data.dist = *dist;
|
|
|
|
|
data.closest = NULL;
|
|
|
|
|
data.closestIndex = 0;
|
|
|
|
|
|
|
|
|
|
data.pass = 0;
|
2009-10-11 20:32:25 +00:00
|
|
|
|
|
|
|
|
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
|
2008-12-30 16:03:29 +00:00
|
|
|
mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if (data.dist>3) {
|
|
|
|
|
data.pass = 1;
|
2008-12-30 16:03:29 +00:00
|
|
|
mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*dist = data.dist;
|
|
|
|
|
lastSelected = data.closest;
|
|
|
|
|
lastSelectedIndex = data.closestIndex;
|
|
|
|
|
|
|
|
|
|
return data.closest;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* best distance based on screen coords.
|
|
|
|
|
use em->selectmode to define how to use
|
|
|
|
|
selected vertices and edges get disadvantage
|
|
|
|
|
return 1 if found one
|
|
|
|
|
*/
|
2008-12-30 16:03:29 +00:00
|
|
|
static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed, EditFace **efa)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2008-12-30 16:03:29 +00:00
|
|
|
EditMesh *em= vc->em;
|
2008-12-30 13:16:14 +00:00
|
|
|
int dist= 75;
|
|
|
|
|
|
|
|
|
|
*eve= NULL;
|
|
|
|
|
*eed= NULL;
|
|
|
|
|
*efa= NULL;
|
|
|
|
|
|
2009-01-15 15:01:39 +00:00
|
|
|
/* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
|
|
|
|
|
view3d_validate_backbuf(vc);
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
if(em->selectmode & SCE_SELECT_VERTEX)
|
2008-12-30 16:03:29 +00:00
|
|
|
*eve= findnearestvert(vc, &dist, SELECT, 0);
|
2008-12-30 13:16:14 +00:00
|
|
|
if(em->selectmode & SCE_SELECT_FACE)
|
2008-12-30 16:03:29 +00:00
|
|
|
*efa= findnearestface(vc, &dist);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */
|
|
|
|
|
if(em->selectmode & SCE_SELECT_EDGE)
|
2008-12-30 16:03:29 +00:00
|
|
|
*eed= findnearestedge(vc, &dist);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* return only one of 3 pointers, for frontbuffer redraws */
|
|
|
|
|
if(*eed) {
|
|
|
|
|
*efa= NULL; *eve= NULL;
|
|
|
|
|
}
|
|
|
|
|
else if(*efa) {
|
|
|
|
|
*eve= NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (*eve || *eed || *efa);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-31 15:21:26 +00:00
|
|
|
/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
|
|
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
/* selects new faces/edges/verts based on the existing selection */
|
|
|
|
|
|
2009-10-14 19:19:43 +00:00
|
|
|
/* VERT GROUP */
|
|
|
|
|
|
|
|
|
|
#define SIMVERT_NORMAL 0
|
|
|
|
|
#define SIMVERT_FACE 1
|
|
|
|
|
#define SIMVERT_VGROUP 2
|
|
|
|
|
#define SIMVERT_TOT 3
|
|
|
|
|
|
|
|
|
|
/* EDGE GROUP */
|
|
|
|
|
|
|
|
|
|
#define SIMEDGE_LENGTH 101
|
|
|
|
|
#define SIMEDGE_DIR 102
|
|
|
|
|
#define SIMEDGE_FACE 103
|
|
|
|
|
#define SIMEDGE_FACE_ANGLE 104
|
|
|
|
|
#define SIMEDGE_CREASE 105
|
|
|
|
|
#define SIMEDGE_SEAM 106
|
|
|
|
|
#define SIMEDGE_SHARP 107
|
|
|
|
|
#define SIMEDGE_TOT 108
|
|
|
|
|
|
|
|
|
|
/* FACE GROUP */
|
2009-07-08 15:34:41 +00:00
|
|
|
|
|
|
|
|
#define SIMFACE_MATERIAL 201
|
|
|
|
|
#define SIMFACE_IMAGE 202
|
|
|
|
|
#define SIMFACE_AREA 203
|
|
|
|
|
#define SIMFACE_PERIMETER 204
|
|
|
|
|
#define SIMFACE_NORMAL 205
|
|
|
|
|
#define SIMFACE_COPLANAR 206
|
2009-10-14 19:19:43 +00:00
|
|
|
#define SIMFACE_TOT 207
|
2009-01-31 15:21:26 +00:00
|
|
|
|
2009-10-14 19:19:43 +00:00
|
|
|
static EnumPropertyItem prop_similar_types[] = {
|
|
|
|
|
{SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
|
|
|
|
|
{SIMVERT_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
|
|
|
|
|
{SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
|
|
|
|
|
{SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
|
|
|
|
|
{SIMEDGE_DIR, "DIR", 0, "Direction", ""},
|
|
|
|
|
{SIMEDGE_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
|
|
|
|
|
{SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
|
|
|
|
|
{SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
|
|
|
|
|
{SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
|
|
|
|
|
{SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
|
2009-07-08 15:34:41 +00:00
|
|
|
{SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
|
|
|
|
|
{SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
|
|
|
|
|
{SIMFACE_AREA, "AREA", 0, "Area", ""},
|
|
|
|
|
{SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
|
|
|
|
|
{SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
|
|
|
|
|
{SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
|
2009-06-16 00:52:21 +00:00
|
|
|
{0, NULL, 0, NULL, NULL}
|
2009-01-31 16:54:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2009-01-31 15:21:26 +00:00
|
|
|
/* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes
|
|
|
|
|
*0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
|
|
|
|
|
#define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
|
|
|
|
|
|
2009-01-31 16:54:37 +00:00
|
|
|
static int similar_face_select__internal(Scene *scene, EditMesh *em, int mode)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditFace *efa, *base_efa=NULL;
|
|
|
|
|
unsigned int selcount=0; /*count how many new faces we select*/
|
|
|
|
|
|
|
|
|
|
/*deselcount, count how many deselected faces are left, so we can bail out early
|
|
|
|
|
also means that if there are no deselected faces, we can avoid a lot of looping */
|
|
|
|
|
unsigned int deselcount=0;
|
2009-01-31 16:54:37 +00:00
|
|
|
float thresh= scene->toolsettings->select_thresh;
|
2008-12-30 13:16:14 +00:00
|
|
|
short ok=0;
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (!efa->h) {
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
efa->f1=1;
|
|
|
|
|
ok=1;
|
|
|
|
|
} else {
|
|
|
|
|
efa->f1=0;
|
|
|
|
|
deselcount++; /* a deselected face we may select later */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ok || !deselcount) /* no data selected OR no more data to select */
|
|
|
|
|
return 0;
|
|
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
if (mode==SIMFACE_AREA) {
|
2008-12-30 13:16:14 +00:00
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
efa->tmp.fp= EM_face_area(efa);
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMFACE_PERIMETER) {
|
2008-12-30 13:16:14 +00:00
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
efa->tmp.fp= EM_face_perimeter(efa);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
|
|
|
|
|
if (base_efa->f1) { /* This was one of the faces originaly selected */
|
2009-07-08 15:34:41 +00:00
|
|
|
if (mode==SIMFACE_MATERIAL) { /* same material */
|
2008-12-30 13:16:14 +00:00
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (
|
|
|
|
|
!(efa->f & SELECT) &&
|
|
|
|
|
!efa->h &&
|
|
|
|
|
base_efa->mat_nr == efa->mat_nr
|
|
|
|
|
) {
|
|
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMFACE_IMAGE) { /* same image */
|
2008-12-30 13:16:14 +00:00
|
|
|
MTFace *tf, *base_tf;
|
|
|
|
|
|
|
|
|
|
base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
|
|
|
|
|
CD_MTFACE);
|
|
|
|
|
|
|
|
|
|
if(!base_tf)
|
|
|
|
|
return selcount;
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (!(efa->f & SELECT) && !efa->h) {
|
|
|
|
|
tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
|
|
|
|
|
CD_MTFACE);
|
|
|
|
|
|
|
|
|
|
if(base_tf->tpage == tf->tpage) {
|
|
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMFACE_AREA || mode==SIMFACE_PERIMETER) { /* same area OR same perimeter, both use the same temp var */
|
2008-12-30 13:16:14 +00:00
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (
|
|
|
|
|
(!(efa->f & SELECT) && !efa->h) &&
|
|
|
|
|
SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
|
|
|
|
|
) {
|
|
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMFACE_NORMAL) {
|
2008-12-30 13:16:14 +00:00
|
|
|
float angle;
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (!(efa->f & SELECT) && !efa->h) {
|
2009-11-10 20:43:45 +00:00
|
|
|
angle= RAD2DEG(angle_v2v2(base_efa->n, efa->n));
|
2008-12-30 13:16:14 +00:00
|
|
|
if (angle/180.0<=thresh) {
|
|
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMFACE_COPLANAR) { /* same planer */
|
2008-12-30 13:16:14 +00:00
|
|
|
float angle, base_dot, dot;
|
2009-11-10 20:43:45 +00:00
|
|
|
base_dot= dot_v3v3(base_efa->cent, base_efa->n);
|
2008-12-30 13:16:14 +00:00
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (!(efa->f & SELECT) && !efa->h) {
|
2009-11-10 20:43:45 +00:00
|
|
|
angle= RAD2DEG(angle_v2v2(base_efa->n, efa->n));
|
2008-12-30 13:16:14 +00:00
|
|
|
if (angle/180.0<=thresh) {
|
2009-11-10 20:43:45 +00:00
|
|
|
dot=dot_v3v3(efa->cent, base_efa->n);
|
2008-12-30 13:16:14 +00:00
|
|
|
if (fabs(base_dot-dot) <= thresh) {
|
|
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} /* end base_efa loop */
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-31 16:54:37 +00:00
|
|
|
static int similar_face_select_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
|
Mesh *me= obedit->data;
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(me);
|
2009-01-31 16:54:37 +00:00
|
|
|
|
|
|
|
|
int selcount = similar_face_select__internal(scene, em, RNA_int_get(op->ptr, "type"));
|
|
|
|
|
|
|
|
|
|
if (selcount) {
|
|
|
|
|
/* here was an edge-mode only select flush case, has to be generalized */
|
|
|
|
|
EM_selectmode_flush(em);
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-31 16:54:37 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-31 16:54:37 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ***************************************************** */
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
static int similar_edge_select__internal(ToolSettings *ts, EditMesh *em, int mode)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditEdge *eed, *base_eed=NULL;
|
|
|
|
|
unsigned int selcount=0; /* count how many new edges we select*/
|
|
|
|
|
|
|
|
|
|
/*count how many visible selected edges there are,
|
|
|
|
|
so we can return when there are none left */
|
|
|
|
|
unsigned int deselcount=0;
|
|
|
|
|
|
|
|
|
|
short ok=0;
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
float thresh= ts->select_thresh;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (!eed->h) {
|
|
|
|
|
if (eed->f & SELECT) {
|
|
|
|
|
eed->f1=1;
|
|
|
|
|
ok=1;
|
|
|
|
|
} else {
|
|
|
|
|
eed->f1=0;
|
|
|
|
|
deselcount++;
|
|
|
|
|
}
|
|
|
|
|
/* set all eed->tmp.l to 0 we use it later.
|
|
|
|
|
for counting face users*/
|
|
|
|
|
eed->tmp.l=0;
|
2009-07-08 15:34:41 +00:00
|
|
|
eed->f2=0; /* only for mode SIMEDGE_FACE_ANGLE, edge animations */
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ok || !deselcount) /* no data selected OR no more data to select*/
|
|
|
|
|
return 0;
|
|
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
if (mode==SIMEDGE_LENGTH) { /*store length*/
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (!eed->h) /* dont calc data for hidden edges*/
|
2009-11-10 20:43:45 +00:00
|
|
|
eed->tmp.fp= len_v3v3(eed->v1->co, eed->v2->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMEDGE_FACE) { /*store face users*/
|
2008-12-30 13:16:14 +00:00
|
|
|
EditFace *efa;
|
|
|
|
|
/* cound how many faces each edge uses use tmp->l */
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
efa->e1->tmp.l++;
|
|
|
|
|
efa->e2->tmp.l++;
|
|
|
|
|
efa->e3->tmp.l++;
|
|
|
|
|
if (efa->e4) efa->e4->tmp.l++;
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMEDGE_FACE_ANGLE) { /*store edge angles */
|
2008-12-30 13:16:14 +00:00
|
|
|
EditFace *efa;
|
|
|
|
|
int j;
|
|
|
|
|
/* cound how many faces each edge uses use tmp.l */
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
/* here we use the edges temp data to assign a face
|
|
|
|
|
if a face has alredy been assigned (eed->f2==1)
|
|
|
|
|
we calculate the angle between the current face and
|
|
|
|
|
the edges previously found face.
|
|
|
|
|
store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
|
|
|
|
|
but tagging eed->f2==2, so we know not to look at it again.
|
|
|
|
|
This only works for edges that connect to 2 faces. but its good enough
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* se we can loop through face edges*/
|
|
|
|
|
j=0;
|
|
|
|
|
eed= efa->e1;
|
|
|
|
|
while (j<4) {
|
|
|
|
|
if (j==1) eed= efa->e2;
|
|
|
|
|
else if (j==2) eed= efa->e3;
|
|
|
|
|
else if (j==3) {
|
|
|
|
|
eed= efa->e4;
|
|
|
|
|
if (!eed)
|
|
|
|
|
break;
|
|
|
|
|
} /* done looping */
|
|
|
|
|
|
|
|
|
|
if (!eed->h) { /* dont calc data for hidden edges*/
|
|
|
|
|
if (eed->f2==2)
|
|
|
|
|
break;
|
|
|
|
|
else if (eed->f2==0) /* first access, assign the face */
|
|
|
|
|
eed->tmp.f= efa;
|
|
|
|
|
else if (eed->f2==1) /* second, we assign the angle*/
|
2009-11-10 20:43:45 +00:00
|
|
|
eed->tmp.fp= RAD2DEG(angle_v2v2(eed->tmp.f->n, efa->n))/180;
|
2008-12-30 13:16:14 +00:00
|
|
|
eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
|
|
|
|
|
if (base_eed->f1) {
|
2009-07-08 15:34:41 +00:00
|
|
|
if (mode==SIMEDGE_LENGTH) { /* same length */
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (
|
|
|
|
|
!(eed->f & SELECT) &&
|
|
|
|
|
!eed->h &&
|
|
|
|
|
SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
|
|
|
|
|
) {
|
|
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMEDGE_DIR) { /* same direction */
|
2008-12-30 13:16:14 +00:00
|
|
|
float base_dir[3], dir[3], angle;
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(base_dir, base_eed->v1->co, base_eed->v2->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (!(eed->f & SELECT) && !eed->h) {
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(dir, eed->v1->co, eed->v2->co);
|
|
|
|
|
angle= RAD2DEG(angle_v2v2(base_dir, dir));
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if (angle>90) /* use the smallest angle between the edges */
|
|
|
|
|
angle= fabs(angle-180.0f);
|
|
|
|
|
|
|
|
|
|
if (angle/90.0<=thresh) {
|
|
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMEDGE_FACE) { /* face users */
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (
|
|
|
|
|
!(eed->f & SELECT) &&
|
|
|
|
|
!eed->h &&
|
|
|
|
|
base_eed->tmp.l==eed->tmp.l
|
|
|
|
|
) {
|
|
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMEDGE_FACE_ANGLE && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (
|
|
|
|
|
!(eed->f & SELECT) &&
|
|
|
|
|
!eed->h &&
|
|
|
|
|
eed->f2==2 &&
|
|
|
|
|
(fabs(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
|
|
|
|
|
) {
|
|
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMEDGE_CREASE) { /* edge crease */
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (
|
|
|
|
|
!(eed->f & SELECT) &&
|
|
|
|
|
!eed->h &&
|
|
|
|
|
(fabs(base_eed->crease-eed->crease) <= thresh)
|
|
|
|
|
) {
|
|
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMEDGE_SEAM) { /* edge seam */
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (
|
|
|
|
|
!(eed->f & SELECT) &&
|
|
|
|
|
!eed->h &&
|
|
|
|
|
(eed->seam == base_eed->seam)
|
|
|
|
|
) {
|
|
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
} else if (mode==SIMEDGE_SHARP) { /* edge sharp */
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (
|
|
|
|
|
!(eed->f & SELECT) &&
|
|
|
|
|
!eed->h &&
|
|
|
|
|
(eed->sharp == base_eed->sharp)
|
|
|
|
|
) {
|
|
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
|
|
|
|
if (!deselcount) /*have we selected all posible faces?, if so return*/
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return selcount;
|
|
|
|
|
}
|
|
|
|
|
/* wrap the above function but do selection flushing edge to face */
|
2009-01-31 16:54:37 +00:00
|
|
|
static int similar_edge_select_exec(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
ToolSettings *ts= CTX_data_tool_settings(C);
|
2009-01-31 16:54:37 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
|
Mesh *me= obedit->data;
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(me);
|
2009-01-31 16:54:37 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
int selcount = similar_edge_select__internal(ts, em, RNA_int_get(op->ptr, "type"));
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if (selcount) {
|
2009-01-31 16:54:37 +00:00
|
|
|
/* here was an edge-mode only select flush case, has to be generalized */
|
|
|
|
|
EM_selectmode_flush(em);
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-31 16:54:37 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-01-31 16:54:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-31 16:54:37 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-31 16:54:37 +00:00
|
|
|
/* ********************************* */
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-31 15:21:26 +00:00
|
|
|
static int similar_vert_select_exec(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
ToolSettings *ts= CTX_data_tool_settings(C);
|
2009-01-31 15:21:26 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
|
Mesh *me= obedit->data;
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(me);
|
2008-12-30 13:16:14 +00:00
|
|
|
EditVert *eve, *base_eve=NULL;
|
|
|
|
|
unsigned int selcount=0; /* count how many new edges we select*/
|
|
|
|
|
|
|
|
|
|
/*count how many visible selected edges there are,
|
|
|
|
|
so we can return when there are none left */
|
|
|
|
|
unsigned int deselcount=0;
|
2009-07-08 15:34:41 +00:00
|
|
|
int mode= RNA_enum_get(op->ptr, "type");
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
short ok=0;
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
float thresh= ts->select_thresh;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if (!eve->h) {
|
|
|
|
|
if (eve->f & SELECT) {
|
|
|
|
|
eve->f1=1;
|
|
|
|
|
ok=1;
|
|
|
|
|
} else {
|
|
|
|
|
eve->f1=0;
|
|
|
|
|
deselcount++;
|
|
|
|
|
}
|
|
|
|
|
/* set all eve->tmp.l to 0 we use them later.*/
|
|
|
|
|
eve->tmp.l=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-30 07:28:37 +00:00
|
|
|
if (!ok || !deselcount) { /* no data selected OR no more data to select*/
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2008-12-30 13:16:14 +00:00
|
|
|
return 0;
|
2009-03-30 07:28:37 +00:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
if(mode == SIMVERT_FACE) {
|
2009-01-31 15:21:26 +00:00
|
|
|
/* store face users */
|
2008-12-30 13:16:14 +00:00
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
|
|
/* count how many faces each edge uses use tmp->l */
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
efa->v1->tmp.l++;
|
|
|
|
|
efa->v2->tmp.l++;
|
|
|
|
|
efa->v3->tmp.l++;
|
|
|
|
|
if (efa->v4) efa->v4->tmp.l++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
|
|
|
|
|
if (base_eve->f1) {
|
|
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
if(mode == SIMVERT_NORMAL) {
|
2008-12-30 13:16:14 +00:00
|
|
|
float angle;
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if (!(eve->f & SELECT) && !eve->h) {
|
2009-11-10 20:43:45 +00:00
|
|
|
angle= RAD2DEG(angle_v2v2(base_eve->no, eve->no));
|
2008-12-30 13:16:14 +00:00
|
|
|
if (angle/180.0<=thresh) {
|
|
|
|
|
eve->f |= SELECT;
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
2009-03-30 07:28:37 +00:00
|
|
|
if (!deselcount) {/*have we selected all posible faces?, if so return*/
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2008-12-30 13:16:14 +00:00
|
|
|
return selcount;
|
2009-03-30 07:28:37 +00:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-31 15:21:26 +00:00
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
else if(mode == SIMVERT_FACE) {
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if (
|
|
|
|
|
!(eve->f & SELECT) &&
|
|
|
|
|
!eve->h &&
|
|
|
|
|
base_eve->tmp.l==eve->tmp.l
|
|
|
|
|
) {
|
|
|
|
|
eve->f |= SELECT;
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
2009-03-30 07:28:37 +00:00
|
|
|
if (!deselcount) {/*have we selected all posible faces?, if so return*/
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2008-12-30 13:16:14 +00:00
|
|
|
return selcount;
|
2009-03-30 07:28:37 +00:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-31 15:21:26 +00:00
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
else if(mode == SIMVERT_VGROUP) {
|
2008-12-30 13:16:14 +00:00
|
|
|
MDeformVert *dvert, *base_dvert;
|
|
|
|
|
short i, j; /* weight index */
|
|
|
|
|
|
|
|
|
|
base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
|
|
|
|
|
CD_MDEFORMVERT);
|
|
|
|
|
|
2009-03-30 07:28:37 +00:00
|
|
|
if (!base_dvert || base_dvert->totweight == 0) {
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2008-12-30 13:16:14 +00:00
|
|
|
return selcount;
|
2009-03-30 07:28:37 +00:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
dvert= CustomData_em_get(&em->vdata, eve->data,
|
|
|
|
|
CD_MDEFORMVERT);
|
|
|
|
|
|
|
|
|
|
if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
|
|
|
|
|
/* do the extra check for selection in the following if, so were not
|
|
|
|
|
checking verts that may be alredy selected */
|
|
|
|
|
for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) {
|
|
|
|
|
for (j=0; dvert->totweight >j; j++) {
|
|
|
|
|
if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
|
|
|
|
|
eve->f |= SELECT;
|
|
|
|
|
selcount++;
|
|
|
|
|
deselcount--;
|
2009-03-30 07:28:37 +00:00
|
|
|
if (!deselcount) { /*have we selected all posible faces?, if so return*/
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2008-12-30 13:16:14 +00:00
|
|
|
return selcount;
|
2009-03-30 07:28:37 +00:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} /* end basevert loop */
|
2009-01-31 15:21:26 +00:00
|
|
|
|
|
|
|
|
if(selcount) {
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-31 15:21:26 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(me, em);
|
2009-01-31 15:21:26 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
static int select_similar_exec(bContext *C, wmOperator *op)
|
2009-01-31 15:21:26 +00:00
|
|
|
{
|
2009-07-08 15:34:41 +00:00
|
|
|
int type= RNA_enum_get(op->ptr, "type");
|
|
|
|
|
|
|
|
|
|
if(type < 100)
|
|
|
|
|
return similar_vert_select_exec(C, op);
|
|
|
|
|
else if(type < 200)
|
|
|
|
|
return similar_edge_select_exec(C, op);
|
|
|
|
|
else
|
|
|
|
|
return similar_face_select_exec(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
RNA
* Enums can now be dynamically created in the _itemf callback,
using RNA_enum_item(s)_add, RNA_enum_item_end. All places asking
for enum items now need to potentially free the items.
* This callback now also gets context, this was added specifically
for operators. This doesn't fit design well at all, needed to do
some ugly hacks, but can't find a good solution at the moment.
* All enums must have a default list of items too, even with an
_itemf callback, for docs and fallback in case there is no context.
* Used by MESH_OT_merge, MESH_OT_select_similar, TFM_OT_select_orientation.
* Also changes some operator properties that were enums to booleas
(unselected, deselect), to make them consistent with other ops.
2009-07-10 19:56:13 +00:00
|
|
|
static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *ptr, int *free)
|
2009-07-08 15:34:41 +00:00
|
|
|
{
|
2009-10-14 19:19:43 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-07-13 19:33:59 +00:00
|
|
|
EnumPropertyItem *item= NULL;
|
2009-10-14 19:19:43 +00:00
|
|
|
int a, totitem= 0;
|
2009-07-13 19:33:59 +00:00
|
|
|
|
2009-10-14 19:19:43 +00:00
|
|
|
if(obedit && obedit->type == OB_MESH) {
|
|
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
|
RNA
* Enums can now be dynamically created in the _itemf callback,
using RNA_enum_item(s)_add, RNA_enum_item_end. All places asking
for enum items now need to potentially free the items.
* This callback now also gets context, this was added specifically
for operators. This doesn't fit design well at all, needed to do
some ugly hacks, but can't find a good solution at the moment.
* All enums must have a default list of items too, even with an
_itemf callback, for docs and fallback in case there is no context.
* Used by MESH_OT_merge, MESH_OT_select_similar, TFM_OT_select_orientation.
* Also changes some operator properties that were enums to booleas
(unselected, deselect), to make them consistent with other ops.
2009-07-10 19:56:13 +00:00
|
|
|
|
2009-10-14 19:19:43 +00:00
|
|
|
if(em->selectmode & SCE_SELECT_VERTEX) {
|
|
|
|
|
for(a=SIMVERT_NORMAL; a<=SIMVERT_TOT; a++)
|
|
|
|
|
RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
|
|
|
|
|
}
|
|
|
|
|
else if(em->selectmode & SCE_SELECT_EDGE) {
|
|
|
|
|
for(a=SIMEDGE_LENGTH; a<=SIMEDGE_TOT; a++)
|
|
|
|
|
RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
|
|
|
|
|
}
|
|
|
|
|
else if(em->selectmode & SCE_SELECT_FACE) {
|
|
|
|
|
for(a=SIMFACE_MATERIAL; a<=SIMFACE_TOT; a++)
|
|
|
|
|
RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
}
|
RNA
* Enums can now be dynamically created in the _itemf callback,
using RNA_enum_item(s)_add, RNA_enum_item_end. All places asking
for enum items now need to potentially free the items.
* This callback now also gets context, this was added specifically
for operators. This doesn't fit design well at all, needed to do
some ugly hacks, but can't find a good solution at the moment.
* All enums must have a default list of items too, even with an
_itemf callback, for docs and fallback in case there is no context.
* Used by MESH_OT_merge, MESH_OT_select_similar, TFM_OT_select_orientation.
* Also changes some operator properties that were enums to booleas
(unselected, deselect), to make them consistent with other ops.
2009-07-10 19:56:13 +00:00
|
|
|
}
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
|
|
|
|
|
RNA_enum_item_end(&item, &totitem);
|
|
|
|
|
*free= 1;
|
2009-10-14 19:19:43 +00:00
|
|
|
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
return item;
|
2009-07-08 15:34:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MESH_OT_select_similar(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
2009-01-31 15:21:26 +00:00
|
|
|
/* identifiers */
|
2009-07-08 15:34:41 +00:00
|
|
|
ot->name= "Select Similar";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select similar vertices, edges or faces by property types.";
|
2009-07-08 15:34:41 +00:00
|
|
|
ot->idname= "MESH_OT_select_similar";
|
2009-01-31 15:21:26 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->invoke= WM_menu_invoke;
|
2009-07-08 15:34:41 +00:00
|
|
|
ot->exec= select_similar_exec;
|
2009-01-31 15:21:26 +00:00
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
2009-01-31 15:21:26 +00:00
|
|
|
/* properties */
|
2009-10-14 19:19:43 +00:00
|
|
|
prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
|
2009-07-08 15:34:41 +00:00
|
|
|
RNA_def_enum_funcs(prop, select_similar_type_itemf);
|
2009-01-31 15:21:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ******************************************* */
|
|
|
|
|
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
int mesh_layers_menu_charlen(CustomData *data, int type)
|
|
|
|
|
{
|
|
|
|
|
int i, len = 0;
|
|
|
|
|
/* see if there is a duplicate */
|
|
|
|
|
for(i=0; i<data->totlayer; i++) {
|
|
|
|
|
if((&data->layers[i])->type == type) {
|
|
|
|
|
/* we could count the chars here but we'll just assumeme each
|
|
|
|
|
* is 32 chars with some room for the menu text - 40 should be fine */
|
|
|
|
|
len+=40;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* this function adds menu text into an existing string.
|
|
|
|
|
* this string's size should be allocated with mesh_layers_menu_charlen */
|
2009-01-31 15:21:26 +00:00
|
|
|
void mesh_layers_menu_concat(CustomData *data, int type, char *str)
|
|
|
|
|
{
|
2008-12-30 13:16:14 +00:00
|
|
|
int i, count = 0;
|
|
|
|
|
char *str_pt = str;
|
|
|
|
|
CustomDataLayer *layer;
|
|
|
|
|
|
|
|
|
|
/* see if there is a duplicate */
|
|
|
|
|
for(i=0; i<data->totlayer; i++) {
|
|
|
|
|
layer = &data->layers[i];
|
|
|
|
|
if(layer->type == type) {
|
|
|
|
|
str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count);
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int mesh_layers_menu(CustomData *data, int type) {
|
|
|
|
|
int ret;
|
|
|
|
|
char *str_pt, *str;
|
|
|
|
|
|
|
|
|
|
str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu");
|
|
|
|
|
str[0] = '\0';
|
|
|
|
|
|
|
|
|
|
str_pt += sprintf(str_pt, "Layers%%t|");
|
|
|
|
|
|
|
|
|
|
mesh_layers_menu_concat(data, type, str_pt);
|
|
|
|
|
|
|
|
|
|
ret = pupmenu(str);
|
|
|
|
|
MEM_freeN(str);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EM_mesh_copy_edge(EditMesh *em, short type)
|
|
|
|
|
{
|
|
|
|
|
EditSelection *ese;
|
|
|
|
|
short change=0;
|
|
|
|
|
|
|
|
|
|
EditEdge *eed, *eed_act;
|
|
|
|
|
float vec[3], vec_mid[3], eed_len, eed_len_act;
|
|
|
|
|
|
|
|
|
|
if (!em) return;
|
|
|
|
|
|
|
|
|
|
ese = em->selected.last;
|
|
|
|
|
if (!ese) return;
|
|
|
|
|
|
|
|
|
|
eed_act = (EditEdge*)ese->data;
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 1: /* copy crease */
|
|
|
|
|
for(eed=em->edges.first; eed; eed=eed->next) {
|
|
|
|
|
if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) {
|
|
|
|
|
eed->crease = eed_act->crease;
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2: /* copy bevel weight */
|
|
|
|
|
for(eed=em->edges.first; eed; eed=eed->next) {
|
|
|
|
|
if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) {
|
|
|
|
|
eed->bweight = eed_act->bweight;
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3: /* copy length */
|
2009-11-10 20:43:45 +00:00
|
|
|
eed_len_act = len_v3v3(eed_act->v1->co, eed_act->v2->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
for(eed=em->edges.first; eed; eed=eed->next) {
|
|
|
|
|
if (eed->f & SELECT && eed != eed_act) {
|
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
eed_len = len_v3v3(eed->v1->co, eed->v2->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if (eed_len == eed_len_act) continue;
|
|
|
|
|
/* if this edge is zero length we cont do anything with it*/
|
|
|
|
|
if (eed_len == 0.0f) continue;
|
|
|
|
|
if (eed_len_act == 0.0f) {
|
2009-11-10 20:43:45 +00:00
|
|
|
add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
|
|
|
|
|
mul_v3_fl(vec_mid, 0.5);
|
2008-12-30 13:16:14 +00:00
|
|
|
VECCOPY(eed->v1->co, vec_mid);
|
|
|
|
|
VECCOPY(eed->v2->co, vec_mid);
|
|
|
|
|
} else {
|
|
|
|
|
/* copy the edge length */
|
2009-11-10 20:43:45 +00:00
|
|
|
add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
|
|
|
|
|
mul_v3_fl(vec_mid, 0.5);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* SCALE 1 */
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(vec, eed->v1->co, vec_mid);
|
|
|
|
|
mul_v3_fl(vec, eed_len_act/eed_len);
|
|
|
|
|
add_v3_v3v3(eed->v1->co, vec, vec_mid);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* SCALE 2 */
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(vec, eed->v2->co, vec_mid);
|
|
|
|
|
mul_v3_fl(vec, eed_len_act/eed_len);
|
|
|
|
|
add_v3_v3v3(eed->v2->co, vec, vec_mid);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (change)
|
|
|
|
|
recalc_editnormals(em);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (change) {
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
// DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-14 21:31:34 +00:00
|
|
|
void EM_mesh_copy_face(EditMesh *em, wmOperator *op, short type)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
short change=0;
|
|
|
|
|
|
|
|
|
|
EditFace *efa, *efa_act;
|
|
|
|
|
MTFace *tf, *tf_act = NULL;
|
|
|
|
|
MCol *mcol, *mcol_act = NULL;
|
|
|
|
|
if (!em) return;
|
|
|
|
|
efa_act = EM_get_actFace(em, 0);
|
|
|
|
|
|
|
|
|
|
if (!efa_act) return;
|
|
|
|
|
|
|
|
|
|
tf_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE);
|
|
|
|
|
mcol_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL);
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 1: /* copy material */
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) {
|
|
|
|
|
efa->mat_nr = efa_act->mat_nr;
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2: /* copy image */
|
|
|
|
|
if (!tf_act) {
|
2009-07-08 21:31:28 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
|
2008-12-30 13:16:14 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT && efa != efa_act) {
|
|
|
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
|
if (tf_act->tpage) {
|
|
|
|
|
tf->tpage = tf_act->tpage;
|
|
|
|
|
tf->mode |= TF_TEX;
|
|
|
|
|
} else {
|
|
|
|
|
tf->tpage = NULL;
|
|
|
|
|
tf->mode &= ~TF_TEX;
|
|
|
|
|
}
|
|
|
|
|
tf->tile= tf_act->tile;
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3: /* copy UV's */
|
|
|
|
|
if (!tf_act) {
|
2009-07-08 21:31:28 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
|
2008-12-30 13:16:14 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT && efa != efa_act) {
|
|
|
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
|
memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 4: /* mode's */
|
|
|
|
|
if (!tf_act) {
|
2009-07-08 21:31:28 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
|
2008-12-30 13:16:14 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT && efa != efa_act) {
|
|
|
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
|
tf->mode= tf_act->mode;
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 5: /* copy transp's */
|
|
|
|
|
if (!tf_act) {
|
2009-07-08 21:31:28 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
|
2008-12-30 13:16:14 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT && efa != efa_act) {
|
|
|
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
|
tf->transp= tf_act->transp;
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 6: /* copy vcols's */
|
|
|
|
|
if (!mcol_act) {
|
2009-07-08 21:31:28 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers.");
|
2008-12-30 13:16:14 +00:00
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
/* guess the 4th color if needs be */
|
|
|
|
|
float val =- 1;
|
|
|
|
|
|
|
|
|
|
if (!efa_act->v4) {
|
|
|
|
|
/* guess the othe vale, we may need to use it
|
|
|
|
|
*
|
|
|
|
|
* Modifying the 4th value of the mcol is ok here since its not seen
|
|
|
|
|
* on a triangle
|
|
|
|
|
* */
|
|
|
|
|
val = ((float)(mcol_act->r + (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255);
|
|
|
|
|
(mcol_act+3)->r = (char)val;
|
|
|
|
|
|
|
|
|
|
val = ((float)(mcol_act->g + (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255);
|
|
|
|
|
(mcol_act+3)->g = (char)val;
|
|
|
|
|
|
|
|
|
|
val = ((float)(mcol_act->b + (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255);
|
|
|
|
|
(mcol_act+3)->b = (char)val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT && efa != efa_act) {
|
|
|
|
|
/* TODO - make copy from tri to quad guess the 4th vert */
|
|
|
|
|
mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
|
|
|
|
|
memcpy(mcol, mcol_act, sizeof(MCol)*4);
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (change) {
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
// DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-02-14 21:31:34 +00:00
|
|
|
void EM_mesh_copy_face_layer(EditMesh *em, wmOperator *op, short type)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
short change=0;
|
|
|
|
|
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
MTFace *tf, *tf_from;
|
|
|
|
|
MCol *mcol, *mcol_from;
|
|
|
|
|
|
|
|
|
|
if (!em) return;
|
|
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
|
case 7:
|
|
|
|
|
case 8:
|
|
|
|
|
case 9:
|
|
|
|
|
if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
|
2009-02-14 21:31:34 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "mesh does not have multiple uv/image layers");
|
2008-12-30 13:16:14 +00:00
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
int layer_orig_idx, layer_idx;
|
|
|
|
|
|
|
|
|
|
layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE);
|
|
|
|
|
if (layer_idx<0) return;
|
|
|
|
|
|
|
|
|
|
/* warning, have not updated mesh pointers however this is not needed since we swicth back */
|
|
|
|
|
layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE);
|
|
|
|
|
if (layer_idx==layer_orig_idx)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* get the tfaces */
|
|
|
|
|
CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx);
|
|
|
|
|
/* store the tfaces in our temp */
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 10: /* select vcol layers - make sure this stays in sync with above code */
|
|
|
|
|
if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
|
2009-02-14 21:31:34 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "mesh does not have multiple color layers");
|
2008-12-30 13:16:14 +00:00
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
int layer_orig_idx, layer_idx;
|
|
|
|
|
|
|
|
|
|
layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL);
|
|
|
|
|
if (layer_idx<0) return;
|
|
|
|
|
|
|
|
|
|
/* warning, have not updated mesh pointers however this is not needed since we swicth back */
|
|
|
|
|
layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL);
|
|
|
|
|
if (layer_idx==layer_orig_idx)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* get the tfaces */
|
|
|
|
|
CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx);
|
|
|
|
|
/* store the tfaces in our temp */
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* layer copy only - sanity checks done above */
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 7: /* copy UV's only */
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
|
|
|
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
|
memcpy(tf->uv, tf_from->uv, sizeof(tf->uv));
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 8: /* copy image settings only */
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
|
|
|
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
|
if (tf_from->tpage) {
|
|
|
|
|
tf->tpage = tf_from->tpage;
|
|
|
|
|
tf->mode |= TF_TEX;
|
|
|
|
|
} else {
|
|
|
|
|
tf->tpage = NULL;
|
|
|
|
|
tf->mode &= ~TF_TEX;
|
|
|
|
|
}
|
|
|
|
|
tf->tile= tf_from->tile;
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 9: /* copy all tface info */
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
|
|
|
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
|
memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv));
|
|
|
|
|
tf->tpage = tf_from->tpage;
|
|
|
|
|
tf->mode = tf_from->mode;
|
|
|
|
|
tf->transp = tf_from->transp;
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 10:
|
|
|
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
mcol_from = (MCol *)efa->tmp.p;
|
|
|
|
|
mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
|
|
|
|
|
memcpy(mcol, mcol_from, sizeof(MCol)*4);
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (change) {
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
// DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ctrl+c in mesh editmode */
|
2009-02-14 21:31:34 +00:00
|
|
|
void mesh_copy_menu(EditMesh *em, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditSelection *ese;
|
|
|
|
|
int ret;
|
|
|
|
|
if (!em) return;
|
|
|
|
|
|
|
|
|
|
ese = em->selected.last;
|
|
|
|
|
|
|
|
|
|
/* Faces can have a NULL ese, so dont return on a NULL ese here */
|
|
|
|
|
|
|
|
|
|
if(ese && ese->type == EDITVERT) {
|
|
|
|
|
/* EditVert *ev, *ev_act = (EditVert*)ese->data;
|
|
|
|
|
ret= pupmenu(""); */
|
|
|
|
|
} else if(ese && ese->type == EDITEDGE) {
|
|
|
|
|
ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3");
|
|
|
|
|
if (ret<1) return;
|
|
|
|
|
|
|
|
|
|
EM_mesh_copy_edge(em, ret);
|
|
|
|
|
|
|
|
|
|
} else if(ese==NULL || ese->type == EDITFACE) {
|
|
|
|
|
ret= pupmenu(
|
|
|
|
|
"Copy Face Selected%t|"
|
|
|
|
|
"Active Material%x1|Active Image%x2|Active UV Coords%x3|"
|
|
|
|
|
"Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|"
|
|
|
|
|
|
|
|
|
|
"TexFace UVs from layer%x7|"
|
|
|
|
|
"TexFace Images from layer%x8|"
|
|
|
|
|
"TexFace All from layer%x9|"
|
|
|
|
|
"Vertex Colors from layer%x10");
|
|
|
|
|
if (ret<1) return;
|
|
|
|
|
|
|
|
|
|
if (ret<=6) {
|
2009-02-14 21:31:34 +00:00
|
|
|
EM_mesh_copy_face(em, op, ret);
|
2008-12-30 13:16:14 +00:00
|
|
|
} else {
|
2009-02-14 21:31:34 +00:00
|
|
|
EM_mesh_copy_face_layer(em, op, ret);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* **************** LOOP SELECTS *************** */
|
|
|
|
|
|
|
|
|
|
/* selects quads in loop direction of indicated edge */
|
|
|
|
|
/* only flush over edges with valence <= 2 */
|
|
|
|
|
void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
|
|
|
|
|
{
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
int looking= 1;
|
|
|
|
|
|
|
|
|
|
/* in eed->f1 we put the valence (amount of faces in edge) */
|
|
|
|
|
/* in eed->f2 we put tagged flag as correct loop */
|
|
|
|
|
/* in efa->f1 we put tagged flag as correct to select */
|
|
|
|
|
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
eed->f1= 0;
|
|
|
|
|
eed->f2= 0;
|
|
|
|
|
}
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
efa->f1= 0;
|
|
|
|
|
if(efa->h==0) {
|
|
|
|
|
efa->e1->f1++;
|
|
|
|
|
efa->e2->f1++;
|
|
|
|
|
efa->e3->f1++;
|
|
|
|
|
if(efa->e4) efa->e4->f1++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* tag startedge OK*/
|
|
|
|
|
startedge->f2= 1;
|
|
|
|
|
|
|
|
|
|
while(looking) {
|
|
|
|
|
looking= 0;
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->h==0 && efa->e4 && efa->f1==0) { /* not done quad */
|
|
|
|
|
if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
|
|
|
|
|
|
|
|
|
|
/* if edge tagged, select opposing edge and mark face ok */
|
|
|
|
|
if(efa->e1->f2) {
|
|
|
|
|
efa->e3->f2= 1;
|
|
|
|
|
efa->f1= 1;
|
|
|
|
|
looking= 1;
|
|
|
|
|
}
|
|
|
|
|
else if(efa->e2->f2) {
|
|
|
|
|
efa->e4->f2= 1;
|
|
|
|
|
efa->f1= 1;
|
|
|
|
|
looking= 1;
|
|
|
|
|
}
|
|
|
|
|
if(efa->e3->f2) {
|
|
|
|
|
efa->e1->f2= 1;
|
|
|
|
|
efa->f1= 1;
|
|
|
|
|
looking= 1;
|
|
|
|
|
}
|
|
|
|
|
if(efa->e4->f2) {
|
|
|
|
|
efa->e2->f2= 1;
|
|
|
|
|
efa->f1= 1;
|
|
|
|
|
looking= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* (de)select the faces */
|
|
|
|
|
if(select!=2) {
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->f1) EM_select_face(efa, select);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* helper for edgeloop_select, checks for eed->f2 tag in faces */
|
|
|
|
|
static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
|
|
|
|
|
{
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->h==0) {
|
|
|
|
|
if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) { /* edge is in face */
|
|
|
|
|
if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) { /* face is tagged */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* selects or deselects edges that:
|
|
|
|
|
- if edges has 2 faces:
|
|
|
|
|
- has vertices with valence of 4
|
|
|
|
|
- not shares face with previous edge
|
|
|
|
|
- if edge has 1 face:
|
|
|
|
|
- has vertices with valence 4
|
|
|
|
|
- not shares face with previous edge
|
|
|
|
|
- but also only 1 face
|
|
|
|
|
- if edge no face:
|
|
|
|
|
- has vertices with valence 2
|
|
|
|
|
*/
|
|
|
|
|
static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
|
|
|
|
|
{
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
int looking= 1;
|
|
|
|
|
|
|
|
|
|
/* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
|
|
|
|
|
/* in eed->f2 and efa->f1 we put tagged flag as correct loop */
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
eve->f1= 0;
|
|
|
|
|
eve->f2= 0;
|
|
|
|
|
}
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
eed->f1= 0;
|
|
|
|
|
eed->f2= 0;
|
|
|
|
|
if((eed->h & 1)==0) { /* fgon edges add to valence too */
|
|
|
|
|
eed->v1->f1++; eed->v2->f1++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
efa->f1= 0;
|
|
|
|
|
if(efa->h==0) {
|
|
|
|
|
efa->e1->f1++;
|
|
|
|
|
efa->e2->f1++;
|
|
|
|
|
efa->e3->f1++;
|
|
|
|
|
if(efa->e4) efa->e4->f1++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* looped edges & vertices get tagged f2 */
|
|
|
|
|
starteed->f2= 1;
|
|
|
|
|
if(starteed->v1->f1<5) starteed->v1->f2= 1;
|
|
|
|
|
if(starteed->v2->f1<5) starteed->v2->f2= 1;
|
|
|
|
|
/* sorry, first edge isnt even ok */
|
|
|
|
|
if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
|
|
|
|
|
|
|
|
|
|
while(looking) {
|
|
|
|
|
looking= 0;
|
|
|
|
|
|
|
|
|
|
/* find correct valence edges which are not tagged yet, but connect to tagged one */
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
|
|
|
|
|
if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
|
|
|
|
|
/* new edge is not allowed to be in face with tagged edge */
|
|
|
|
|
if(edge_not_in_tagged_face(em, eed)) {
|
|
|
|
|
if(eed->f1==starteed->f1) { /* same amount of faces */
|
|
|
|
|
looking= 1;
|
|
|
|
|
eed->f2= 1;
|
|
|
|
|
if(eed->v2->f1<5) eed->v2->f2= 1;
|
|
|
|
|
if(eed->v1->f1<5) eed->v1->f2= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* and we do the select */
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->f2) EM_select_edge(eed, select);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Almostly exactly the same code as faceloop select
|
|
|
|
|
*/
|
|
|
|
|
static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
|
|
|
|
|
{
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
int looking= 1;
|
|
|
|
|
|
|
|
|
|
/* in eed->f1 we put the valence (amount of faces in edge) */
|
|
|
|
|
/* in eed->f2 we put tagged flag as correct loop */
|
|
|
|
|
/* in efa->f1 we put tagged flag as correct to select */
|
|
|
|
|
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
eed->f1= 0;
|
|
|
|
|
eed->f2= 0;
|
|
|
|
|
}
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
efa->f1= 0;
|
|
|
|
|
if(efa->h==0) {
|
|
|
|
|
efa->e1->f1++;
|
|
|
|
|
efa->e2->f1++;
|
|
|
|
|
efa->e3->f1++;
|
|
|
|
|
if(efa->e4) efa->e4->f1++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* tag startedge OK */
|
|
|
|
|
startedge->f2= 1;
|
|
|
|
|
|
|
|
|
|
while(looking) {
|
|
|
|
|
looking= 0;
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->e4 && efa->f1==0 && !efa->h) { /* not done quad */
|
|
|
|
|
if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
|
|
|
|
|
|
|
|
|
|
/* if edge tagged, select opposing edge and mark face ok */
|
|
|
|
|
if(efa->e1->f2) {
|
|
|
|
|
efa->e3->f2= 1;
|
|
|
|
|
efa->f1= 1;
|
|
|
|
|
looking= 1;
|
|
|
|
|
}
|
|
|
|
|
else if(efa->e2->f2) {
|
|
|
|
|
efa->e4->f2= 1;
|
|
|
|
|
efa->f1= 1;
|
|
|
|
|
looking= 1;
|
|
|
|
|
}
|
|
|
|
|
if(efa->e3->f2) {
|
|
|
|
|
efa->e1->f2= 1;
|
|
|
|
|
efa->f1= 1;
|
|
|
|
|
looking= 1;
|
|
|
|
|
}
|
|
|
|
|
if(efa->e4->f2) {
|
|
|
|
|
efa->e2->f2= 1;
|
|
|
|
|
efa->f1= 1;
|
|
|
|
|
looking= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* (de)select the edges */
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->f2) EM_select_edge(eed, select);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
static int loop_multiselect(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-02-02 19:31:43 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2008-12-30 13:16:14 +00:00
|
|
|
EditEdge *eed;
|
|
|
|
|
EditEdge **edarray;
|
|
|
|
|
int edindex, edfirstcount;
|
2009-02-02 19:31:43 +00:00
|
|
|
int looptype= RNA_boolean_get(op->ptr, "ring");
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-15 15:01:39 +00:00
|
|
|
/* sets em->totedgesel */
|
|
|
|
|
EM_nedges_selected(em);
|
|
|
|
|
|
|
|
|
|
edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array");
|
2008-12-30 13:16:14 +00:00
|
|
|
edindex = 0;
|
2009-01-15 15:01:39 +00:00
|
|
|
edfirstcount = em->totedgesel;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
for(eed=em->edges.first; eed; eed=eed->next){
|
|
|
|
|
if(eed->f&SELECT){
|
|
|
|
|
edarray[edindex] = eed;
|
|
|
|
|
edindex += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(looptype){
|
|
|
|
|
for(edindex = 0; edindex < edfirstcount; edindex +=1){
|
|
|
|
|
eed = edarray[edindex];
|
|
|
|
|
edgering_select(em, eed,SELECT);
|
|
|
|
|
}
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
for(edindex = 0; edindex < edfirstcount; edindex +=1){
|
|
|
|
|
eed = edarray[edindex];
|
|
|
|
|
edgeloop_select(em, eed,SELECT);
|
|
|
|
|
}
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
}
|
|
|
|
|
MEM_freeN(edarray);
|
|
|
|
|
// if (EM_texFaceCheck())
|
2009-02-02 19:31:43 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-02-02 19:31:43 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-12 17:43:43 +00:00
|
|
|
void MESH_OT_loop_multi_select(wmOperatorType *ot)
|
2009-02-02 19:31:43 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Multi Select Loops";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select a loop of connected edges by connection type.";
|
2009-04-12 17:43:43 +00:00
|
|
|
ot->idname= "MESH_OT_loop_multi_select";
|
2009-02-02 19:31:43 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= loop_multiselect;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
|
RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-02-02 19:31:43 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* ***************** MAIN MOUSE SELECTION ************** */
|
|
|
|
|
|
|
|
|
|
|
2009-01-30 18:53:54 +00:00
|
|
|
/* ***************** loop select (non modal) ************** */
|
|
|
|
|
|
|
|
|
|
static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-30 18:53:54 +00:00
|
|
|
ViewContext vc;
|
|
|
|
|
EditMesh *em;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditEdge *eed;
|
|
|
|
|
int select= 1;
|
|
|
|
|
int dist= 50;
|
|
|
|
|
|
2009-01-30 18:53:54 +00:00
|
|
|
em_setup_viewcontext(C, &vc);
|
|
|
|
|
vc.mval[0]= mval[0];
|
|
|
|
|
vc.mval[1]= mval[1];
|
|
|
|
|
em= vc.em;
|
2009-09-21 17:32:25 +00:00
|
|
|
|
|
|
|
|
/* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
|
|
|
|
|
view3d_validate_backbuf(&vc);
|
2009-01-30 18:53:54 +00:00
|
|
|
|
|
|
|
|
eed= findnearestedge(&vc, &dist);
|
2008-12-30 13:16:14 +00:00
|
|
|
if(eed) {
|
2009-01-31 13:30:56 +00:00
|
|
|
if(extend==0) EM_clear_flag_all(em, SELECT);
|
|
|
|
|
|
|
|
|
|
if((eed->f & SELECT)==0) select=1;
|
|
|
|
|
else if(extend) select=0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-31 13:30:56 +00:00
|
|
|
if(em->selectmode & SCE_SELECT_FACE) {
|
|
|
|
|
faceloop_select(em, eed, select);
|
|
|
|
|
}
|
|
|
|
|
else if(em->selectmode & SCE_SELECT_EDGE) {
|
|
|
|
|
if(ring)
|
|
|
|
|
edgering_select(em, eed, select);
|
|
|
|
|
else
|
|
|
|
|
edgeloop_select(em, eed, select);
|
|
|
|
|
}
|
|
|
|
|
else if(em->selectmode & SCE_SELECT_VERTEX) {
|
|
|
|
|
if(ring)
|
|
|
|
|
edgering_select(em, eed, select);
|
|
|
|
|
else
|
|
|
|
|
edgeloop_select(em, eed, select);
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-31 13:30:56 +00:00
|
|
|
EM_selectmode_flush(em);
|
2008-12-30 13:16:14 +00:00
|
|
|
// if (EM_texFaceCheck())
|
2009-01-31 13:30:56 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
|
2009-01-31 13:30:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-29 02:15:13 +00:00
|
|
|
static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
2009-01-31 13:30:56 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
view3d_operator_needs_opengl(C);
|
|
|
|
|
|
2009-02-19 19:03:53 +00:00
|
|
|
mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
|
2009-01-31 13:30:56 +00:00
|
|
|
RNA_boolean_get(op->ptr, "ring"));
|
|
|
|
|
|
|
|
|
|
/* cannot do tweaks for as long this keymap is after transform map */
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-12 17:43:43 +00:00
|
|
|
void MESH_OT_loop_select(wmOperatorType *ot)
|
2009-01-31 13:30:56 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Loop Select";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select a loop of connected edges.";
|
2009-04-12 17:43:43 +00:00
|
|
|
ot->idname= "MESH_OT_loop_select";
|
2009-01-31 13:30:56 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2009-03-29 02:15:13 +00:00
|
|
|
ot->invoke= mesh_select_loop_invoke;
|
2009-01-31 13:30:56 +00:00
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
2009-01-31 13:30:56 +00:00
|
|
|
/* properties */
|
|
|
|
|
RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
|
|
|
|
|
RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ******************* mesh shortest path select, uses prev-selected edge ****************** */
|
|
|
|
|
|
|
|
|
|
/* since you want to create paths with multiple selects, it doesn't have extend option */
|
|
|
|
|
static void mouse_mesh_shortest_path(bContext *C, short mval[2])
|
|
|
|
|
{
|
|
|
|
|
ViewContext vc;
|
|
|
|
|
EditMesh *em;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
int dist= 50;
|
|
|
|
|
|
|
|
|
|
em_setup_viewcontext(C, &vc);
|
|
|
|
|
vc.mval[0]= mval[0];
|
|
|
|
|
vc.mval[1]= mval[1];
|
|
|
|
|
em= vc.em;
|
|
|
|
|
|
2009-09-21 17:32:25 +00:00
|
|
|
/* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
|
|
|
|
|
view3d_validate_backbuf(&vc);
|
|
|
|
|
|
2009-01-31 13:30:56 +00:00
|
|
|
eed= findnearestedge(&vc, &dist);
|
|
|
|
|
if(eed) {
|
|
|
|
|
Mesh *me= vc.obedit->data;
|
|
|
|
|
int path = 0;
|
|
|
|
|
|
|
|
|
|
if (em->selected.last) {
|
|
|
|
|
EditSelection *ese = em->selected.last;
|
2008-12-31 17:11:42 +00:00
|
|
|
|
2009-01-31 13:30:56 +00:00
|
|
|
if(ese && ese->type == EDITEDGE) {
|
|
|
|
|
EditEdge *eed_act;
|
|
|
|
|
eed_act = (EditEdge*)ese->data;
|
|
|
|
|
if (eed_act != eed) {
|
|
|
|
|
if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
|
|
|
|
|
EM_remove_selection(em, eed_act, EDITEDGE);
|
|
|
|
|
path = 1;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-31 13:30:56 +00:00
|
|
|
}
|
|
|
|
|
if (path==0) {
|
|
|
|
|
int act = (edgetag_context_check(vc.scene, eed)==0);
|
|
|
|
|
edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
|
|
|
|
|
/* even if this is selected it may not be in the selection list */
|
|
|
|
|
if(edgetag_context_check(vc.scene, eed)==0)
|
|
|
|
|
EM_remove_selection(em, eed, EDITEDGE);
|
|
|
|
|
else
|
|
|
|
|
EM_store_selection(em, eed, EDITEDGE);
|
|
|
|
|
|
|
|
|
|
/* force drawmode for mesh */
|
|
|
|
|
switch (vc.scene->toolsettings->edge_mode) {
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
2009-01-31 13:30:56 +00:00
|
|
|
me->drawflag |= ME_DRAWSEAMS;
|
2008-12-30 13:16:14 +00:00
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_SHARP:
|
2009-01-31 13:30:56 +00:00
|
|
|
me->drawflag |= ME_DRAWSHARP;
|
2008-12-30 13:16:14 +00:00
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
2009-01-31 13:30:56 +00:00
|
|
|
me->drawflag |= ME_DRAWCREASES;
|
2008-12-30 13:16:14 +00:00
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
2009-01-31 13:30:56 +00:00
|
|
|
me->drawflag |= ME_DRAWBWEIGHTS;
|
2008-12-30 13:16:14 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2009-01-30 18:53:54 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(vc.obedit->data, OB_RECALC_DATA);
|
|
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-31 13:30:56 +00:00
|
|
|
|
|
|
|
|
static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
2009-01-30 18:53:54 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
view3d_operator_needs_opengl(C);
|
2009-01-31 13:30:56 +00:00
|
|
|
|
2009-02-19 19:03:53 +00:00
|
|
|
mouse_mesh_shortest_path(C, event->mval);
|
2009-01-30 18:53:54 +00:00
|
|
|
|
2009-01-31 09:23:17 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-01-30 18:53:54 +00:00
|
|
|
}
|
2009-01-31 13:30:56 +00:00
|
|
|
|
2009-04-15 15:40:31 +00:00
|
|
|
void MESH_OT_select_shortest_path(wmOperatorType *ot)
|
2009-01-30 18:53:54 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2009-01-31 13:30:56 +00:00
|
|
|
ot->name= "Shortest Path Select";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select shortest path between two selections.";
|
2009-04-15 15:40:31 +00:00
|
|
|
ot->idname= "MESH_OT_select_shortest_path";
|
2009-01-30 18:53:54 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2009-01-31 13:30:56 +00:00
|
|
|
ot->invoke= mesh_shortest_path_select_invoke;
|
2009-01-30 18:53:54 +00:00
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
2009-01-30 18:53:54 +00:00
|
|
|
/* properties */
|
2009-01-31 09:23:17 +00:00
|
|
|
RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
|
2009-01-30 18:53:54 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-31 13:30:56 +00:00
|
|
|
|
2009-01-30 18:53:54 +00:00
|
|
|
/* ************************************************** */
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* here actual select happens */
|
2009-01-01 13:15:35 +00:00
|
|
|
/* gets called via generic mouse select operator */
|
2009-11-24 04:59:52 +00:00
|
|
|
int mouse_mesh(bContext *C, short mval[2], short extend)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2008-12-30 16:03:29 +00:00
|
|
|
ViewContext vc;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditVert *eve;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
/* setup view context for argument to callbacks */
|
|
|
|
|
em_setup_viewcontext(C, &vc);
|
2008-12-31 17:11:42 +00:00
|
|
|
vc.mval[0]= mval[0];
|
|
|
|
|
vc.mval[1]= mval[1];
|
2008-12-30 16:03:29 +00:00
|
|
|
|
2009-01-30 18:53:54 +00:00
|
|
|
if(unified_findnearest(&vc, &eve, &eed, &efa)) {
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2008-12-31 17:50:00 +00:00
|
|
|
if(extend==0) EM_clear_flag_all(vc.em, SELECT);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if(efa) {
|
|
|
|
|
/* set the last selected face */
|
2008-12-31 17:11:42 +00:00
|
|
|
EM_set_actFace(vc.em, efa);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
if( (efa->f & SELECT)==0 ) {
|
2008-12-31 17:11:42 +00:00
|
|
|
EM_store_selection(vc.em, efa, EDITFACE);
|
|
|
|
|
EM_select_face_fgon(vc.em, efa, 1);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2008-12-31 17:50:00 +00:00
|
|
|
else if(extend) {
|
2008-12-31 17:11:42 +00:00
|
|
|
EM_remove_selection(vc.em, efa, EDITFACE);
|
|
|
|
|
EM_select_face_fgon(vc.em, efa, 0);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(eed) {
|
|
|
|
|
if((eed->f & SELECT)==0) {
|
2008-12-31 17:11:42 +00:00
|
|
|
EM_store_selection(vc.em, eed, EDITEDGE);
|
2008-12-30 13:16:14 +00:00
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
}
|
2008-12-31 17:50:00 +00:00
|
|
|
else if(extend) {
|
2008-12-31 17:11:42 +00:00
|
|
|
EM_remove_selection(vc.em, eed, EDITEDGE);
|
2008-12-30 13:16:14 +00:00
|
|
|
EM_select_edge(eed, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(eve) {
|
|
|
|
|
if((eve->f & SELECT)==0) {
|
|
|
|
|
eve->f |= SELECT;
|
2008-12-31 17:11:42 +00:00
|
|
|
EM_store_selection(vc.em, eve, EDITVERT);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2008-12-31 17:50:00 +00:00
|
|
|
else if(extend){
|
2008-12-31 17:11:42 +00:00
|
|
|
EM_remove_selection(vc.em, eve, EDITVERT);
|
2008-12-30 13:16:14 +00:00
|
|
|
eve->f &= ~SELECT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-31 17:11:42 +00:00
|
|
|
EM_selectmode_flush(vc.em);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
// if (EM_texFaceCheck()) {
|
|
|
|
|
|
2009-01-02 19:10:35 +00:00
|
|
|
if (efa && efa->mat_nr != vc.obedit->actcol-1) {
|
|
|
|
|
vc.obedit->actcol= efa->mat_nr+1;
|
|
|
|
|
vc.em->mat_nr= efa->mat_nr;
|
2008-12-30 13:16:14 +00:00
|
|
|
// BIF_preview_changed(ID_MA);
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-24 04:59:52 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2008-12-31 17:11:42 +00:00
|
|
|
|
2009-11-24 04:59:52 +00:00
|
|
|
return 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
/* *********** select linked ************* */
|
|
|
|
|
|
|
|
|
|
/* for use with selectconnected_delimit_mesh only! */
|
|
|
|
|
#define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
|
|
|
|
|
#define is_face_tag(efa) is_edge_delimit_ok(efa->e1) || is_edge_delimit_ok(efa->e2) || is_edge_delimit_ok(efa->e3) || (efa->v4 && is_edge_delimit_ok(efa->e4))
|
|
|
|
|
|
|
|
|
|
#define face_tag(efa)\
|
|
|
|
|
if(efa->v4) efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
|
|
|
|
|
else efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
|
|
|
|
|
|
|
|
|
|
/* all - 1) use all faces for extending the selection 2) only use the mouse face
|
|
|
|
|
* sel - 1) select 0) deselect
|
|
|
|
|
* */
|
|
|
|
|
|
|
|
|
|
/* legacy warning, this function combines too much :) */
|
|
|
|
|
static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-02-02 19:31:43 +00:00
|
|
|
EditMesh *em= vc->em;
|
|
|
|
|
EditFace *efa;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditEdge *eed;
|
2009-02-02 19:31:43 +00:00
|
|
|
EditVert *eve;
|
|
|
|
|
short done=1, change=0;
|
|
|
|
|
|
|
|
|
|
if(em->faces.first==0) return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
|
|
/* flag all edges+faces as off*/
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next)
|
|
|
|
|
eed->tmp.l=0;
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
efa->tmp.l = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (all) {
|
|
|
|
|
// XXX verts?
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->f & SELECT)
|
|
|
|
|
eed->tmp.l= 1;
|
|
|
|
|
}
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
face_tag(efa);
|
|
|
|
|
} else {
|
|
|
|
|
efa->tmp.l = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if( unified_findnearest(vc, &eve, &eed, &efa) ) {
|
|
|
|
|
|
|
|
|
|
if(efa) {
|
|
|
|
|
efa->tmp.l = 1;
|
|
|
|
|
face_tag(efa);
|
|
|
|
|
}
|
|
|
|
|
else if(eed)
|
|
|
|
|
eed->tmp.l= 1;
|
|
|
|
|
else {
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next)
|
|
|
|
|
if(eed->v1==eve || eed->v2==eve)
|
|
|
|
|
break;
|
|
|
|
|
eed->tmp.l= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
while(done==1) {
|
|
|
|
|
done= 0;
|
2009-02-02 19:31:43 +00:00
|
|
|
/* simple algo - select all faces that have a selected edge
|
|
|
|
|
* this intern selects the edge, repeat until nothing is left to do */
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if ((efa->tmp.l == 0) && (!efa->h)) {
|
|
|
|
|
if (is_face_tag(efa)) {
|
|
|
|
|
face_tag(efa);
|
|
|
|
|
done= 1;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (efa->tmp.l) {
|
|
|
|
|
if (sel) {
|
|
|
|
|
if (!(efa->f & SELECT)) {
|
|
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
EM_select_face(efa, 0);
|
|
|
|
|
change = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
if (!change)
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next)
|
|
|
|
|
if (efa->f & SELECT)
|
|
|
|
|
EM_select_face(efa, 1);
|
2009-01-31 19:40:40 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
// if (EM_texFaceCheck())
|
2009-01-31 19:40:40 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
|
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
#undef is_edge_delimit_ok
|
|
|
|
|
#undef is_face_tag
|
|
|
|
|
#undef face_tag
|
2009-01-17 16:11:12 +00:00
|
|
|
|
2009-11-17 10:57:49 +00:00
|
|
|
static void linked_limit_default(bContext *C, wmOperator *op) {
|
|
|
|
|
if(!RNA_property_is_set(op->ptr, "limit")) {
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
|
|
|
|
|
if(em->selectmode == SCE_SELECT_FACE)
|
|
|
|
|
RNA_boolean_set(op->ptr, "limit", TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-01 12:40:27 +00:00
|
|
|
static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-17 16:11:12 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2008-12-30 16:03:29 +00:00
|
|
|
ViewContext vc;
|
2008-12-30 13:16:14 +00:00
|
|
|
EditVert *eve, *v1, *v2;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
2009-01-17 16:11:12 +00:00
|
|
|
short done=1, toggle=0;
|
|
|
|
|
int sel= !RNA_boolean_get(op->ptr, "deselect");
|
2009-11-17 10:57:49 +00:00
|
|
|
int limit;
|
2009-01-17 16:11:12 +00:00
|
|
|
|
2009-11-17 10:57:49 +00:00
|
|
|
linked_limit_default(C, op);
|
|
|
|
|
|
|
|
|
|
limit = RNA_boolean_get(op->ptr, "limit");
|
|
|
|
|
|
2009-01-17 16:11:12 +00:00
|
|
|
/* unified_finednearest needs ogl */
|
|
|
|
|
view3d_operator_needs_opengl(C);
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
/* setup view context for argument to callbacks */
|
|
|
|
|
em_setup_viewcontext(C, &vc);
|
|
|
|
|
|
2009-01-17 16:11:12 +00:00
|
|
|
if(vc.em->edges.first==0) return OPERATOR_CANCELLED;
|
|
|
|
|
|
2009-02-19 19:03:53 +00:00
|
|
|
vc.mval[0]= event->mval[0];
|
|
|
|
|
vc.mval[1]= event->mval[1];
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
/* return warning! */
|
|
|
|
|
if(limit) {
|
|
|
|
|
int retval= select_linked_limited_invoke(&vc, 0, sel);
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-02-02 19:31:43 +00:00
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-02-02 19:31:43 +00:00
|
|
|
|
2009-01-17 16:11:12 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* clear test flags */
|
2008-12-30 16:03:29 +00:00
|
|
|
for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* start vertex/face/edge */
|
|
|
|
|
if(eve) eve->f1= 1;
|
|
|
|
|
else if(eed) eed->v1->f1= eed->v2->f1= 1;
|
|
|
|
|
else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
|
|
|
|
|
|
|
|
|
|
/* set flag f1 if affected */
|
|
|
|
|
while(done==1) {
|
|
|
|
|
done= 0;
|
|
|
|
|
toggle++;
|
|
|
|
|
|
2008-12-30 16:03:29 +00:00
|
|
|
if(toggle & 1) eed= vc.em->edges.first;
|
|
|
|
|
else eed= vc.em->edges.last;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
while(eed) {
|
|
|
|
|
v1= eed->v1;
|
|
|
|
|
v2= eed->v2;
|
|
|
|
|
|
|
|
|
|
if(eed->h==0) {
|
|
|
|
|
if(v1->f1 && v2->f1==0) {
|
|
|
|
|
v2->f1= 1;
|
|
|
|
|
done= 1;
|
|
|
|
|
}
|
|
|
|
|
else if(v1->f1==0 && v2->f1) {
|
|
|
|
|
v1->f1= 1;
|
|
|
|
|
done= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(toggle & 1) eed= eed->next;
|
|
|
|
|
else eed= eed->prev;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* now use vertex f1 flag to select/deselect */
|
2008-12-30 16:03:29 +00:00
|
|
|
for(eed= vc.em->edges.first; eed; eed= eed->next) {
|
2008-12-30 13:16:14 +00:00
|
|
|
if(eed->v1->f1 && eed->v2->f1)
|
|
|
|
|
EM_select_edge(eed, sel);
|
|
|
|
|
}
|
2008-12-30 16:03:29 +00:00
|
|
|
for(efa= vc.em->faces.first; efa; efa= efa->next) {
|
2008-12-30 13:16:14 +00:00
|
|
|
if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
|
|
|
|
|
EM_select_face(efa, sel);
|
|
|
|
|
}
|
|
|
|
|
/* no flush needed, connected geometry is done */
|
|
|
|
|
|
|
|
|
|
// if (EM_texFaceCheck())
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-01 12:40:27 +00:00
|
|
|
void MESH_OT_select_linked_pick(wmOperatorType *ot)
|
2009-01-13 02:09:58 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2009-02-01 18:07:02 +00:00
|
|
|
ot->name= "Select Linked";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "(un)select all vertices linked to the active mesh.";
|
2009-02-01 12:40:27 +00:00
|
|
|
ot->idname= "MESH_OT_select_linked_pick";
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2009-02-01 12:40:27 +00:00
|
|
|
ot->invoke= select_linked_pick_invoke;
|
2009-01-13 02:09:58 +00:00
|
|
|
ot->poll= ED_operator_editmesh;
|
2009-01-31 19:40:40 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
2009-01-17 16:11:12 +00:00
|
|
|
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
|
2009-02-02 19:31:43 +00:00
|
|
|
RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-17 16:11:12 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
/* ************************* */
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
void selectconnected_mesh_all(EditMesh *em)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-02-02 19:31:43 +00:00
|
|
|
EditVert *v1,*v2;
|
2008-12-30 16:03:29 +00:00
|
|
|
EditEdge *eed;
|
2009-02-02 19:31:43 +00:00
|
|
|
short done=1, toggle=0;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
if(em->edges.first==0) return;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
while(done==1) {
|
|
|
|
|
done= 0;
|
2009-02-02 19:31:43 +00:00
|
|
|
|
|
|
|
|
toggle++;
|
|
|
|
|
if(toggle & 1) eed= em->edges.first;
|
|
|
|
|
else eed= em->edges.last;
|
|
|
|
|
|
|
|
|
|
while(eed) {
|
|
|
|
|
v1= eed->v1;
|
|
|
|
|
v2= eed->v2;
|
|
|
|
|
if(eed->h==0) {
|
|
|
|
|
if(v1->f & SELECT) {
|
|
|
|
|
if( (v2->f & SELECT)==0 ) {
|
|
|
|
|
v2->f |= SELECT;
|
|
|
|
|
done= 1;
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-02-02 19:31:43 +00:00
|
|
|
else if(v2->f & SELECT) {
|
|
|
|
|
if( (v1->f & SELECT)==0 ) {
|
|
|
|
|
v1->f |= SELECT;
|
|
|
|
|
done= 1;
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-02-02 19:31:43 +00:00
|
|
|
if(toggle & 1) eed= eed->next;
|
|
|
|
|
else eed= eed->prev;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
/* now use vertex select flag to select rest */
|
|
|
|
|
EM_select_flush(em);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
// if (EM_texFaceCheck())
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
static int select_linked_exec(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-02-02 19:31:43 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
|
2009-02-02 19:31:43 +00:00
|
|
|
|
|
|
|
|
if( RNA_boolean_get(op->ptr, "limit") ) {
|
|
|
|
|
ViewContext vc;
|
|
|
|
|
em_setup_viewcontext(C, &vc);
|
|
|
|
|
select_linked_limited_invoke(&vc, 1, 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
selectconnected_mesh_all(em);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-02-02 19:31:43 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-02-02 19:31:43 +00:00
|
|
|
|
2009-11-17 10:57:49 +00:00
|
|
|
static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
linked_limit_default(C, op);
|
|
|
|
|
return select_linked_exec(C, op);
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
void MESH_OT_select_linked(wmOperatorType *ot)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-02-02 19:31:43 +00:00
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Select Linked All";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select all vertices linked to the active mesh.";
|
2009-02-02 19:31:43 +00:00
|
|
|
ot->idname= "MESH_OT_select_linked";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= select_linked_exec;
|
2009-11-17 10:57:49 +00:00
|
|
|
ot->invoke= select_linked_invoke;
|
2009-02-02 19:31:43 +00:00
|
|
|
ot->poll= ED_operator_editmesh;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-02 19:31:43 +00:00
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ************************* */
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* swap is 0 or 1, if 1 it hides not selected */
|
2009-02-09 20:58:31 +00:00
|
|
|
void EM_hide_mesh(EditMesh *em, int swap)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
int a;
|
|
|
|
|
|
2009-01-02 19:10:35 +00:00
|
|
|
if(em==NULL) return;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
|
|
|
|
|
/* - vertex hidden, always means edge is hidden too
|
|
|
|
|
- edge hidden, always means face is hidden too
|
|
|
|
|
- face hidden, only set face hide
|
|
|
|
|
- then only flush back down what's absolute hidden
|
|
|
|
|
*/
|
|
|
|
|
if(em->selectmode & SCE_SELECT_VERTEX) {
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if((eve->f & SELECT)!=swap) {
|
|
|
|
|
eve->f &= ~SELECT;
|
|
|
|
|
eve->h= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->v1->h || eed->v2->h) {
|
|
|
|
|
eed->h |= 1;
|
|
|
|
|
eed->f &= ~SELECT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
|
|
|
|
|
efa->h= 1;
|
|
|
|
|
efa->f &= ~SELECT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(em->selectmode & SCE_SELECT_EDGE) {
|
|
|
|
|
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if((eed->f & SELECT)!=swap) {
|
|
|
|
|
eed->h |= 1;
|
|
|
|
|
EM_select_edge(eed, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
|
|
|
|
|
efa->h= 1;
|
|
|
|
|
efa->f &= ~SELECT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if((efa->f & SELECT)!=swap) {
|
|
|
|
|
efa->h= 1;
|
|
|
|
|
EM_select_face(efa, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* flush down, only whats 100% hidden */
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
|
|
|
|
|
|
|
|
|
|
if(em->selectmode & SCE_SELECT_FACE) {
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->h) a= 1; else a= 2;
|
|
|
|
|
efa->e1->f1 |= a;
|
|
|
|
|
efa->e2->f1 |= a;
|
|
|
|
|
efa->e3->f1 |= a;
|
|
|
|
|
if(efa->e4) efa->e4->f1 |= a;
|
|
|
|
|
/* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */
|
|
|
|
|
if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) {
|
|
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(em->selectmode >= SCE_SELECT_EDGE) {
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->f1==1) eed->h |= 1;
|
|
|
|
|
if(eed->h & 1) a= 1; else a= 2;
|
|
|
|
|
eed->v1->f1 |= a;
|
|
|
|
|
eed->v2->f1 |= a;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(em->selectmode >= SCE_SELECT_VERTEX) {
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if(eve->f1==1) eve->h= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 15:01:39 +00:00
|
|
|
em->totedgesel= em->totfacesel= em->totvertsel= 0;
|
2008-12-30 13:16:14 +00:00
|
|
|
// if(EM_texFaceCheck())
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
// DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-13 02:09:58 +00:00
|
|
|
static int hide_mesh_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-02-20 20:39:27 +00:00
|
|
|
EM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-01 12:40:27 +00:00
|
|
|
void MESH_OT_hide(wmOperatorType *ot)
|
2009-01-13 02:09:58 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2009-02-01 18:07:02 +00:00
|
|
|
ot->name= "Hide Selection";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Hide (un)selected vertices, edges or faces.";
|
2009-02-01 12:40:27 +00:00
|
|
|
ot->idname= "MESH_OT_hide";
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= hide_mesh_exec;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
2009-01-31 19:40:40 +00:00
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* props */
|
2009-02-20 20:39:27 +00:00
|
|
|
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-09 20:58:31 +00:00
|
|
|
void EM_reveal_mesh(EditMesh *em)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
2009-01-02 19:10:35 +00:00
|
|
|
if(em==NULL) return;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if(eve->h) {
|
|
|
|
|
eve->h= 0;
|
|
|
|
|
eve->f |= SELECT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->h & 1) {
|
|
|
|
|
eed->h &= ~1;
|
|
|
|
|
if(em->selectmode & SCE_SELECT_VERTEX);
|
|
|
|
|
else EM_select_edge(eed, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->h) {
|
|
|
|
|
efa->h= 0;
|
|
|
|
|
if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX));
|
|
|
|
|
else EM_select_face(efa, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EM_fgon_flags(em); /* redo flags and indices for fgons */
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
|
|
|
|
|
// if (EM_texFaceCheck())
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
// DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-13 02:09:58 +00:00
|
|
|
static int reveal_mesh_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-02-09 20:58:31 +00:00
|
|
|
EM_reveal_mesh(em);
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-01 12:40:27 +00:00
|
|
|
void MESH_OT_reveal(wmOperatorType *ot)
|
2009-01-13 02:09:58 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2009-02-01 18:07:02 +00:00
|
|
|
ot->name= "Reveal Hidden";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Reveal all hidden vertices, edges and faces.";
|
2009-02-01 12:40:27 +00:00
|
|
|
ot->idname= "MESH_OT_reveal";
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= reveal_mesh_exec;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
2009-01-31 19:40:40 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
int select_by_number_vertices_exec(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-07-08 15:34:41 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2008-12-30 13:16:14 +00:00
|
|
|
EditFace *efa;
|
2009-07-08 15:34:41 +00:00
|
|
|
int numverts= RNA_enum_get(op->ptr, "type");
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
|
|
|
|
|
* faces
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* for loose vertices/edges, we first select all, loop below will deselect */
|
2009-07-08 15:34:41 +00:00
|
|
|
if(numverts==5) {
|
2008-12-30 13:16:14 +00:00
|
|
|
EM_set_flag_all(em, SELECT);
|
2009-07-08 15:34:41 +00:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
else if(em->selectmode!=SCE_SELECT_FACE) {
|
2009-02-14 21:31:34 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Only works in face selection mode");
|
2009-07-08 15:34:41 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (efa->e4) {
|
|
|
|
|
EM_select_face(efa, (numverts==4) );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
EM_select_face(efa, (numverts==3) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-07-08 15:34:41 +00:00
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
static const EnumPropertyItem type_items[]= {
|
|
|
|
|
{3, "TRIANGLES", 0, "Triangles", NULL},
|
|
|
|
|
{4, "QUADS", 0, "Triangles", NULL},
|
|
|
|
|
{5, "OTHER", 0, "Other", NULL},
|
|
|
|
|
{0, NULL, 0, NULL, NULL}};
|
|
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Select by Number of Vertices";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select vertices or faces by vertex count.";
|
2009-07-08 15:34:41 +00:00
|
|
|
ot->idname= "MESH_OT_select_by_number_vertices";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= select_by_number_vertices_exec;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
/* props */
|
|
|
|
|
RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select.");
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-20 16:31:03 +00:00
|
|
|
|
|
|
|
|
int select_mirror_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
|
|
|
|
|
|
|
|
|
int extend= RNA_boolean_get(op->ptr, "extend");
|
|
|
|
|
|
|
|
|
|
EM_select_mirrored(obedit, em, extend);
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
|
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MESH_OT_select_mirror(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Select Mirror";
|
|
|
|
|
ot->description= "Select mesh items at mirrored locations.";
|
|
|
|
|
ot->idname= "MESH_OT_select_mirror";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= select_mirror_exec;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
/* props */
|
|
|
|
|
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-29 18:54:22 +00:00
|
|
|
static int select_sharp_edges_exec(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
/* Find edges that have exactly two neighboring faces,
|
2009-01-29 18:54:22 +00:00
|
|
|
* check the angle between those faces, and if angle is
|
|
|
|
|
* small enough, select the edge
|
|
|
|
|
*/
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2008-12-30 13:16:14 +00:00
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
EditFace **efa1;
|
|
|
|
|
EditFace **efa2;
|
2009-01-29 18:54:22 +00:00
|
|
|
intptr_t edgecount = 0, i = 0;
|
|
|
|
|
float sharpness, fsharpness;
|
|
|
|
|
|
|
|
|
|
/* 'standard' behaviour - check if selected, then apply relevant selection */
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
if(em->selectmode==SCE_SELECT_FACE) {
|
2009-02-14 21:31:34 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode");
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-29 18:54:22 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-29 18:54:22 +00:00
|
|
|
sharpness= RNA_float_get(op->ptr, "sharpness");
|
2008-12-30 13:16:14 +00:00
|
|
|
fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
|
|
|
|
|
|
|
|
|
|
/* count edges, use tmp.l */
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
edgecount++;
|
|
|
|
|
eed->tmp.l = i;
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* for each edge, we want a pointer to two adjacent faces */
|
|
|
|
|
efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
|
|
|
|
|
"pairs of edit face pointers");
|
|
|
|
|
efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
|
|
|
|
|
"pairs of edit face pointers");
|
|
|
|
|
|
|
|
|
|
#define face_table_edge(eed) { \
|
|
|
|
|
i = eed->tmp.l; \
|
|
|
|
|
if (i != -1) { \
|
|
|
|
|
if (efa1[i]) { \
|
|
|
|
|
if (efa2[i]) { \
|
|
|
|
|
/* invalidate, edge has more than two neighbors */ \
|
|
|
|
|
eed->tmp.l = -1; \
|
|
|
|
|
} \
|
|
|
|
|
else { \
|
|
|
|
|
efa2[i] = efa; \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
else { \
|
|
|
|
|
efa1[i] = efa; \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find the adjacent faces of each edge, we want only two */
|
|
|
|
|
efa= em->faces.first;
|
|
|
|
|
while(efa) {
|
|
|
|
|
face_table_edge(efa->e1);
|
|
|
|
|
face_table_edge(efa->e2);
|
|
|
|
|
face_table_edge(efa->e3);
|
|
|
|
|
if (efa->e4) {
|
|
|
|
|
face_table_edge(efa->e4);
|
|
|
|
|
}
|
|
|
|
|
efa= efa->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef face_table_edge
|
|
|
|
|
|
|
|
|
|
eed = em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
i = eed->tmp.l;
|
|
|
|
|
if (i != -1) {
|
|
|
|
|
/* edge has two or less neighboring faces */
|
|
|
|
|
if ( (efa1[i]) && (efa2[i]) ) {
|
|
|
|
|
/* edge has exactly two neighboring faces, check angle */
|
|
|
|
|
float angle;
|
|
|
|
|
angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
|
|
|
|
|
efa1[i]->n[1]*efa2[i]->n[1] +
|
|
|
|
|
efa1[i]->n[2]*efa2[i]->n[2]);
|
|
|
|
|
if (fabs(angle) >= fsharpness)
|
|
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_freeN(efa1);
|
|
|
|
|
MEM_freeN(efa2);
|
|
|
|
|
|
|
|
|
|
// if (EM_texFaceCheck())
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); //TODO is this needed ?
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-12 17:43:43 +00:00
|
|
|
void MESH_OT_edges_select_sharp(wmOperatorType *ot)
|
2009-01-13 02:09:58 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Select Sharp Edges";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Marked selected edges as sharp.";
|
2009-04-12 17:43:43 +00:00
|
|
|
ot->idname= "MESH_OT_edges_select_sharp";
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= select_sharp_edges_exec;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
2009-01-31 19:40:40 +00:00
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-01-29 18:54:22 +00:00
|
|
|
/* props */
|
2009-01-16 23:58:10 +00:00
|
|
|
RNA_def_float(ot->srna, "sharpness", 0.01f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-02-14 21:31:34 +00:00
|
|
|
static void select_linked_flat_faces(EditMesh *em, wmOperator *op, float sharpness)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
/* Find faces that are linked to selected faces that are
|
|
|
|
|
* relatively flat (angle between faces is higher than
|
|
|
|
|
* specified angle)
|
|
|
|
|
*/
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
EditFace **efa1;
|
|
|
|
|
EditFace **efa2;
|
|
|
|
|
intptr_t edgecount = 0, i, faceselcount=0, faceselcountold=0;
|
2009-01-29 18:54:22 +00:00
|
|
|
float fsharpness;
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
if(em->selectmode!=SCE_SELECT_FACE) {
|
2009-02-14 21:31:34 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Only works in face selection mode");
|
2008-12-30 13:16:14 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
|
|
|
|
|
|
|
|
|
|
i=0;
|
|
|
|
|
/* count edges, use tmp.l */
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
edgecount++;
|
|
|
|
|
eed->tmp.l = i;
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* for each edge, we want a pointer to two adjacent faces */
|
|
|
|
|
efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
|
|
|
|
|
"pairs of edit face pointers");
|
|
|
|
|
efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
|
|
|
|
|
"pairs of edit face pointers");
|
|
|
|
|
|
|
|
|
|
#define face_table_edge(eed) { \
|
|
|
|
|
i = eed->tmp.l; \
|
|
|
|
|
if (i != -1) { \
|
|
|
|
|
if (efa1[i]) { \
|
|
|
|
|
if (efa2[i]) { \
|
|
|
|
|
/* invalidate, edge has more than two neighbors */ \
|
|
|
|
|
eed->tmp.l = -1; \
|
|
|
|
|
} \
|
|
|
|
|
else { \
|
|
|
|
|
efa2[i] = efa; \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
else { \
|
|
|
|
|
efa1[i] = efa; \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find the adjacent faces of each edge, we want only two */
|
|
|
|
|
efa= em->faces.first;
|
|
|
|
|
while(efa) {
|
|
|
|
|
face_table_edge(efa->e1);
|
|
|
|
|
face_table_edge(efa->e2);
|
|
|
|
|
face_table_edge(efa->e3);
|
|
|
|
|
if (efa->e4) {
|
|
|
|
|
face_table_edge(efa->e4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* while were at it, count the selected faces */
|
|
|
|
|
if (efa->f & SELECT) ++faceselcount;
|
|
|
|
|
|
|
|
|
|
efa= efa->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef face_table_edge
|
|
|
|
|
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
i = eed->tmp.l;
|
|
|
|
|
if (i != -1) {
|
|
|
|
|
/* edge has two or less neighboring faces */
|
|
|
|
|
if ( (efa1[i]) && (efa2[i]) ) {
|
|
|
|
|
/* edge has exactly two neighboring faces, check angle */
|
|
|
|
|
float angle;
|
|
|
|
|
angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
|
|
|
|
|
efa1[i]->n[1]*efa2[i]->n[1] +
|
|
|
|
|
efa1[i]->n[2]*efa2[i]->n[2]);
|
|
|
|
|
/* invalidate: edge too sharp */
|
|
|
|
|
if (fabs(angle) >= fsharpness)
|
|
|
|
|
eed->tmp.l = -1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* invalidate: less than two neighbors */
|
|
|
|
|
eed->tmp.l = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define select_flat_neighbor(eed) { \
|
|
|
|
|
i = eed->tmp.l; \
|
|
|
|
|
if (i!=-1) { \
|
|
|
|
|
if (! (efa1[i]->f & SELECT) ) { \
|
|
|
|
|
EM_select_face(efa1[i], 1); \
|
|
|
|
|
++faceselcount; \
|
|
|
|
|
} \
|
|
|
|
|
if (! (efa2[i]->f & SELECT) ) { \
|
|
|
|
|
EM_select_face(efa2[i], 1); \
|
|
|
|
|
++faceselcount; \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (faceselcount != faceselcountold) {
|
|
|
|
|
faceselcountold = faceselcount;
|
|
|
|
|
|
|
|
|
|
efa= em->faces.first;
|
|
|
|
|
while(efa) {
|
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
|
select_flat_neighbor(efa->e1);
|
|
|
|
|
select_flat_neighbor(efa->e2);
|
|
|
|
|
select_flat_neighbor(efa->e3);
|
|
|
|
|
if (efa->e4) {
|
|
|
|
|
select_flat_neighbor(efa->e4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
efa= efa->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef select_flat_neighbor
|
|
|
|
|
|
|
|
|
|
MEM_freeN(efa1);
|
|
|
|
|
MEM_freeN(efa2);
|
|
|
|
|
|
|
|
|
|
// if (EM_texFaceCheck())
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-13 02:09:58 +00:00
|
|
|
static int select_linked_flat_faces_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-02-14 21:31:34 +00:00
|
|
|
select_linked_flat_faces(em, op, RNA_float_get(op->ptr, "sharpness"));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-12 17:43:43 +00:00
|
|
|
void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
|
2009-01-13 02:09:58 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Select Linked Flat Faces";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select linked faces by angle.";
|
2009-04-12 17:43:43 +00:00
|
|
|
ot->idname= "MESH_OT_faces_select_linked_flat";
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= select_linked_flat_faces_exec;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
2009-01-31 19:40:40 +00:00
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* props */
|
2009-01-16 23:58:10 +00:00
|
|
|
RNA_def_float(ot->srna, "sharpness", 0.0f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
|
|
|
|
|
2009-02-14 21:31:34 +00:00
|
|
|
void select_non_manifold(EditMesh *em, wmOperator *op )
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
|
|
/* Selects isolated verts, and edges that do not have 2 neighboring
|
|
|
|
|
* faces
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if(em->selectmode==SCE_SELECT_FACE) {
|
2009-02-14 21:31:34 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode");
|
2008-12-30 13:16:14 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eve= em->verts.first;
|
|
|
|
|
while(eve) {
|
|
|
|
|
/* this will count how many edges are connected
|
|
|
|
|
* to this vert */
|
|
|
|
|
eve->f1= 0;
|
|
|
|
|
eve= eve->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
/* this will count how many faces are connected to
|
|
|
|
|
* this edge */
|
|
|
|
|
eed->f1= 0;
|
|
|
|
|
/* increase edge count for verts */
|
|
|
|
|
++eed->v1->f1;
|
|
|
|
|
++eed->v2->f1;
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
efa= em->faces.first;
|
|
|
|
|
while(efa) {
|
|
|
|
|
/* increase face count for edges */
|
|
|
|
|
++efa->e1->f1;
|
|
|
|
|
++efa->e2->f1;
|
|
|
|
|
++efa->e3->f1;
|
|
|
|
|
if (efa->e4)
|
|
|
|
|
++efa->e4->f1;
|
|
|
|
|
efa= efa->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* select verts that are attached to an edge that does not
|
|
|
|
|
* have 2 neighboring faces */
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
if (eed->h==0 && eed->f1 != 2) {
|
|
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
}
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* select isolated verts */
|
|
|
|
|
if(em->selectmode & SCE_SELECT_VERTEX) {
|
|
|
|
|
eve= em->verts.first;
|
|
|
|
|
while(eve) {
|
|
|
|
|
if (eve->f1 == 0) {
|
|
|
|
|
if (!eve->h) eve->f |= SELECT;
|
|
|
|
|
}
|
|
|
|
|
eve= eve->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if (EM_texFaceCheck())
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-13 02:09:58 +00:00
|
|
|
static int select_non_manifold_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-02-14 21:31:34 +00:00
|
|
|
select_non_manifold(em, op);
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MESH_OT_select_non_manifold(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Select Non Manifold";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select all non-manifold vertices or edges.";
|
2009-01-13 02:09:58 +00:00
|
|
|
ot->idname= "MESH_OT_select_non_manifold";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= select_non_manifold_exec;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
2009-01-31 19:40:40 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
|
|
|
|
|
2009-02-07 01:27:46 +00:00
|
|
|
void EM_select_swap(EditMesh *em) /* exported for UV */
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
|
|
if(em->selectmode & SCE_SELECT_VERTEX) {
|
|
|
|
|
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if(eve->h==0) {
|
|
|
|
|
if(eve->f & SELECT) eve->f &= ~SELECT;
|
|
|
|
|
else eve->f|= SELECT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(em->selectmode & SCE_SELECT_EDGE) {
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->h==0) {
|
|
|
|
|
EM_select_edge(eed, !(eed->f & SELECT));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->h==0) {
|
|
|
|
|
EM_select_face(efa, !(efa->f & SELECT));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
|
|
|
|
|
// if (EM_texFaceCheck())
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 21:31:28 +00:00
|
|
|
static int select_inverse_mesh_exec(bContext *C, wmOperator *op)
|
2009-01-13 02:09:58 +00:00
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-02-07 01:27:46 +00:00
|
|
|
EM_select_swap(em);
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 21:31:28 +00:00
|
|
|
void MESH_OT_select_inverse(wmOperatorType *ot)
|
2009-01-13 02:09:58 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2009-07-08 21:31:28 +00:00
|
|
|
ot->name= "Select Inverse";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select inverse of (un)selected vertices, edges or faces.";
|
2009-07-08 21:31:28 +00:00
|
|
|
ot->idname= "MESH_OT_select_inverse";
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2009-07-08 21:31:28 +00:00
|
|
|
ot->exec= select_inverse_mesh_exec;
|
2009-01-13 02:09:58 +00:00
|
|
|
ot->poll= ED_operator_editmesh;
|
2009-01-31 19:40:40 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-01 13:15:35 +00:00
|
|
|
/* ******************** (de)select all operator **************** */
|
|
|
|
|
|
2009-02-07 01:27:46 +00:00
|
|
|
void EM_toggle_select_all(EditMesh *em) /* exported for UV */
|
|
|
|
|
{
|
|
|
|
|
if(EM_nvertices_selected(em))
|
|
|
|
|
EM_clear_flag_all(em, SELECT);
|
|
|
|
|
else
|
|
|
|
|
EM_set_flag_all(em, SELECT);
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-19 09:52:13 +00:00
|
|
|
void EM_select_all(EditMesh *em)
|
|
|
|
|
{
|
|
|
|
|
EM_set_flag_all(em, SELECT);
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-01 13:15:35 +00:00
|
|
|
static int toggle_select_all_exec(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-01 13:15:35 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-07 01:27:46 +00:00
|
|
|
EM_toggle_select_all(em);
|
2009-01-01 13:15:35 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-02-07 01:27:46 +00:00
|
|
|
|
2009-01-01 13:15:35 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-03-29 02:15:13 +00:00
|
|
|
void MESH_OT_select_all_toggle(wmOperatorType *ot)
|
2009-01-01 13:15:35 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2009-06-26 15:48:09 +00:00
|
|
|
ot->name= "Select/Deselect All";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "(de)select all vertices, edges or faces.";
|
2009-03-29 02:15:13 +00:00
|
|
|
ot->idname= "MESH_OT_select_all_toggle";
|
2009-01-01 13:15:35 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= toggle_select_all_exec;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
2009-01-31 19:40:40 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-01 13:15:35 +00:00
|
|
|
/* ******************** **************** */
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
void EM_select_more(EditMesh *em)
|
|
|
|
|
{
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if(eve->f & SELECT) eve->f1= 1;
|
|
|
|
|
else eve->f1 = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set f1 flags in vertices to select 'more' */
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->h==0) {
|
|
|
|
|
if (eed->v1->f & SELECT)
|
|
|
|
|
eed->v2->f1 = 1;
|
|
|
|
|
if (eed->v2->f & SELECT)
|
|
|
|
|
eed->v1->f1 = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* new selected edges, but not in facemode */
|
|
|
|
|
if(em->selectmode <= SCE_SELECT_EDGE) {
|
|
|
|
|
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->h==0) {
|
|
|
|
|
if(eed->v1->f1 && eed->v2->f1) EM_select_edge(eed, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* new selected faces */
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->h==0) {
|
|
|
|
|
if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
|
|
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-13 02:09:58 +00:00
|
|
|
static int select_more(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-13 02:09:58 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)) ;
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
EM_select_more(em);
|
|
|
|
|
|
|
|
|
|
// if (EM_texFaceCheck(em))
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MESH_OT_select_more(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Select More";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select more vertices, edges or faces connected to initial selection.";
|
2009-01-13 02:09:58 +00:00
|
|
|
ot->idname= "MESH_OT_select_more";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= select_more;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
2009-01-31 19:40:40 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EM_select_less(EditMesh *em)
|
|
|
|
|
{
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
|
|
if(em->selectmode <= SCE_SELECT_EDGE) {
|
|
|
|
|
/* eed->f1 == 1: edge with a selected and deselected vert */
|
|
|
|
|
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
eed->f1= 0;
|
|
|
|
|
if(eed->h==0) {
|
|
|
|
|
|
|
|
|
|
if ( !(eed->v1->f & SELECT) && (eed->v2->f & SELECT) )
|
|
|
|
|
eed->f1= 1;
|
|
|
|
|
if ( (eed->v1->f & SELECT) && !(eed->v2->f & SELECT) )
|
|
|
|
|
eed->f1= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* deselect edges with flag set */
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if (eed->h==0 && eed->f1 == 1) {
|
|
|
|
|
EM_select_edge(eed, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EM_deselect_flush(em);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* deselect faces with 1 or more deselect edges */
|
|
|
|
|
/* eed->f1 == mixed selection edge */
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
|
|
|
|
|
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->h==0) {
|
|
|
|
|
if(efa->f & SELECT) {
|
|
|
|
|
efa->e1->f1 |= 1;
|
|
|
|
|
efa->e2->f1 |= 1;
|
|
|
|
|
efa->e3->f1 |= 1;
|
|
|
|
|
if(efa->e4) efa->e4->f1 |= 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
efa->e1->f1 |= 2;
|
|
|
|
|
efa->e2->f1 |= 2;
|
|
|
|
|
efa->e3->f1 |= 2;
|
|
|
|
|
if(efa->e4) efa->e4->f1 |= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->h==0) {
|
|
|
|
|
if(efa->e1->f1==3 || efa->e2->f1==3 || efa->e3->f1==3 || (efa->e4 && efa->e4->f1==3)) {
|
|
|
|
|
EM_select_face(efa, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-13 02:09:58 +00:00
|
|
|
static int select_less(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-13 02:09:58 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
EM_select_less(em);
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
// if (EM_texFaceCheck(em))
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-13 02:09:58 +00:00
|
|
|
void MESH_OT_select_less(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Select Less";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Select less vertices, edges or faces connected to initial selection.";
|
2009-01-13 02:09:58 +00:00
|
|
|
ot->idname= "MESH_OT_select_less";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= select_less;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
2009-01-31 19:40:40 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-01 12:40:27 +00:00
|
|
|
static void selectrandom_mesh(EditMesh *em, float perc) /* randomly selects a user-set % of vertices/edges/faces */
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
EditFace *efa;
|
2009-02-11 23:02:21 +00:00
|
|
|
float randfac= perc;
|
2008-12-30 13:16:14 +00:00
|
|
|
/* Get the percentage of vertices to randomly select as 'randfac' */
|
|
|
|
|
// XXX if(button(&randfac,0, 100,"Percentage:")==0) return;
|
|
|
|
|
|
|
|
|
|
BLI_srand( BLI_rand() ); /* random seed */
|
|
|
|
|
|
|
|
|
|
if(em->selectmode & SCE_SELECT_VERTEX) {
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if(eve->h==0) {
|
2009-02-01 12:40:27 +00:00
|
|
|
if (BLI_frand() < randfac)
|
2008-12-30 13:16:14 +00:00
|
|
|
eve->f |= SELECT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
}
|
|
|
|
|
else if(em->selectmode & SCE_SELECT_EDGE) {
|
|
|
|
|
for(eed= em->edges.first; eed; eed= eed->next) {
|
|
|
|
|
if(eed->h==0) {
|
2009-02-01 12:40:27 +00:00
|
|
|
if (BLI_frand() < randfac)
|
2008-12-30 13:16:14 +00:00
|
|
|
EM_select_edge(eed, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for(efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if(efa->h==0) {
|
2009-02-01 12:40:27 +00:00
|
|
|
if (BLI_frand() < randfac)
|
2008-12-30 13:16:14 +00:00
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
}
|
|
|
|
|
// if (EM_texFaceCheck())
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-01 12:40:27 +00:00
|
|
|
static int mesh_select_random_exec(bContext *C, wmOperator *op)
|
2009-01-31 23:57:04 +00:00
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-01-31 23:57:04 +00:00
|
|
|
|
2009-02-01 12:40:27 +00:00
|
|
|
selectrandom_mesh(em, RNA_float_get(op->ptr,"percent"));
|
2009-01-31 23:57:04 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-01-31 23:57:04 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-01-31 23:57:04 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-01 12:40:27 +00:00
|
|
|
void MESH_OT_select_random(wmOperatorType *ot)
|
2009-01-31 23:57:04 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2009-02-01 12:40:27 +00:00
|
|
|
ot->name= "Select Random";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Randomly select vertices.";
|
2009-02-01 12:40:27 +00:00
|
|
|
ot->idname= "MESH_OT_select_random";
|
|
|
|
|
|
2009-01-31 23:57:04 +00:00
|
|
|
/* api callbacks */
|
2009-02-01 12:40:27 +00:00
|
|
|
ot->exec= mesh_select_random_exec;
|
2009-07-08 15:34:41 +00:00
|
|
|
ot->invoke= WM_operator_props_popup;
|
2009-01-31 23:57:04 +00:00
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
2009-02-17 21:07:01 +00:00
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-31 23:57:04 +00:00
|
|
|
|
|
|
|
|
/* props */
|
2009-09-21 21:19:58 +00:00
|
|
|
RNA_def_float_percentage(ot->srna, "percent", 50.0f, 0.0f, 100.0f, "Percent", "Percentage of vertices to select randomly.", 0.0001f, 1.0f);
|
2009-01-31 23:57:04 +00:00
|
|
|
}
|
|
|
|
|
|
2009-06-24 14:07:48 +00:00
|
|
|
void EM_select_by_material(EditMesh *em, int index)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
|
|
for (efa=em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (efa->mat_nr==index) {
|
|
|
|
|
EM_select_face(efa, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-24 14:07:48 +00:00
|
|
|
void EM_deselect_by_material(EditMesh *em, int index)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
|
|
for (efa=em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (efa->mat_nr==index) {
|
|
|
|
|
EM_select_face(efa, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EM_selectmode_flush(em);
|
|
|
|
|
}
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
static void mesh_selection_type(ToolSettings *ts, EditMesh *em, int val)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
if(val>0) {
|
2009-11-26 19:32:33 +00:00
|
|
|
//if(ctrl) EM_convertsel(em, em->selectmode, SCE_SELECT_EDGE);
|
|
|
|
|
//if((ctrl)) EM_convertsel(em, em->selectmode, SCE_SELECT_FACE);
|
|
|
|
|
|
|
|
|
|
em->selectmode= val;
|
|
|
|
|
EM_selectmode_set(em);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-01 13:24:19 +00:00
|
|
|
/* note, em stores selectmode to be able to pass it on everywhere without scene,
|
|
|
|
|
this is only until all select modes and toolsettings are settled more */
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
ts->selectmode= em->selectmode;
|
2008-12-30 13:16:14 +00:00
|
|
|
// if (EM_texFaceCheck())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-01 03:12:31 +00:00
|
|
|
static int mesh_selection_type_exec(bContext *C, wmOperator *op)
|
2009-02-01 01:04:00 +00:00
|
|
|
{
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
ToolSettings *ts= CTX_data_tool_settings(C);
|
2009-02-01 01:04:00 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-02-01 01:04:00 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
mesh_selection_type(ts, em, RNA_enum_get(op->ptr,"type"));
|
2009-02-01 01:04:00 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
2009-11-26 19:32:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE|ND_MODE, NULL); /* header redraw */
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-02-01 01:04:00 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-01 12:40:27 +00:00
|
|
|
void MESH_OT_selection_type(wmOperatorType *ot)
|
2009-02-01 01:04:00 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Selection Mode";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Set the selection mode type.";
|
2009-02-01 12:40:27 +00:00
|
|
|
ot->idname= "MESH_OT_selection_type";
|
2009-02-01 01:04:00 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2009-02-01 02:37:12 +00:00
|
|
|
ot->invoke= WM_menu_invoke;
|
2009-02-01 03:12:31 +00:00
|
|
|
ot->exec= mesh_selection_type_exec;
|
2009-02-01 01:04:00 +00:00
|
|
|
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
2009-11-26 19:32:33 +00:00
|
|
|
ot->flag= OPTYPE_UNDO;
|
2009-02-01 01:04:00 +00:00
|
|
|
|
2009-02-01 02:37:12 +00:00
|
|
|
/* props */
|
2009-11-26 19:32:33 +00:00
|
|
|
RNA_def_enum(ot->srna, "type", mesh_select_mode_items, 0, "Type", "Set the mesh selection type");
|
2009-02-01 01:04:00 +00:00
|
|
|
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
/* ************************* SEAMS AND EDGES **************** */
|
|
|
|
|
|
2009-02-04 02:58:21 +00:00
|
|
|
static int editmesh_mark_seam(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-02-04 02:58:21 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-02-04 02:58:21 +00:00
|
|
|
Mesh *me= ((Mesh *)obedit->data);
|
2008-12-30 13:16:14 +00:00
|
|
|
EditEdge *eed;
|
2009-02-04 02:58:21 +00:00
|
|
|
int clear = RNA_boolean_get(op->ptr, "clear");
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* auto-enable seams drawing */
|
|
|
|
|
if(clear==0) {
|
2009-01-31 13:30:56 +00:00
|
|
|
me->drawflag |= ME_DRAWSEAMS;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(clear) {
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
if((eed->h==0) && (eed->f & SELECT)) {
|
|
|
|
|
eed->seam = 0;
|
|
|
|
|
}
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
if((eed->h==0) && (eed->f & SELECT)) {
|
|
|
|
|
eed->seam = 1;
|
|
|
|
|
}
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
|
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
2009-02-04 02:58:21 +00:00
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-02-04 02:58:21 +00:00
|
|
|
void MESH_OT_mark_seam(wmOperatorType *ot)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-02-04 02:58:21 +00:00
|
|
|
/* identifiers */
|
2009-07-08 21:31:28 +00:00
|
|
|
ot->name= "Mark Seam";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "(un)mark selected edges as a seam.";
|
2009-02-04 02:58:21 +00:00
|
|
|
ot->idname= "MESH_OT_mark_seam";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= editmesh_mark_seam;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int editmesh_mark_sharp(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-02-04 02:58:21 +00:00
|
|
|
Mesh *me= ((Mesh *)obedit->data);
|
2009-07-08 21:31:28 +00:00
|
|
|
int clear = RNA_boolean_get(op->ptr, "clear");
|
2008-12-30 13:16:14 +00:00
|
|
|
EditEdge *eed;
|
|
|
|
|
|
|
|
|
|
/* auto-enable sharp edge drawing */
|
2009-07-08 21:31:28 +00:00
|
|
|
if(clear == 0) {
|
2009-01-31 13:30:56 +00:00
|
|
|
me->drawflag |= ME_DRAWSHARP;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-08 21:31:28 +00:00
|
|
|
if(!clear) {
|
2008-12-30 13:16:14 +00:00
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
if(!eed->h && (eed->f & SELECT)) eed->sharp = 1;
|
|
|
|
|
eed = eed->next;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
if(!eed->h && (eed->f & SELECT)) eed->sharp = 0;
|
|
|
|
|
eed = eed->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
|
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
2009-02-04 02:58:21 +00:00
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MESH_OT_mark_sharp(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2009-07-08 21:31:28 +00:00
|
|
|
ot->name= "Mark Sharp";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "(un)mark selected edges as sharp.";
|
2009-02-04 02:58:21 +00:00
|
|
|
ot->idname= "MESH_OT_mark_sharp";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= editmesh_mark_sharp;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
2009-07-08 21:31:28 +00:00
|
|
|
RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* **************** NORMALS ************** */
|
|
|
|
|
|
2009-01-29 18:54:22 +00:00
|
|
|
/* XXX value of select is messed up, it means two things */
|
2008-12-30 13:16:14 +00:00
|
|
|
void righthandfaces(EditMesh *em, int select) /* makes faces righthand turning */
|
|
|
|
|
{
|
|
|
|
|
EditEdge *eed, *ed1, *ed2, *ed3, *ed4;
|
|
|
|
|
EditFace *efa, *startvl;
|
|
|
|
|
float maxx, nor[3], cent[3];
|
|
|
|
|
int totsel, found, foundone, direct, turn, tria_nr;
|
|
|
|
|
|
|
|
|
|
/* 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 ...' */
|
|
|
|
|
|
|
|
|
|
waitcursor(1);
|
|
|
|
|
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
eed->f2= 0; /* edge direction */
|
|
|
|
|
eed->f1= 0; /* counter */
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* count faces and edges */
|
|
|
|
|
totsel= 0;
|
|
|
|
|
efa= em->faces.first;
|
|
|
|
|
while(efa) {
|
|
|
|
|
if(select==0 || (efa->f & SELECT) ) {
|
|
|
|
|
efa->f1= 1;
|
|
|
|
|
totsel++;
|
|
|
|
|
efa->e1->f1++;
|
|
|
|
|
efa->e2->f1++;
|
|
|
|
|
efa->e3->f1++;
|
|
|
|
|
if(efa->v4) efa->e4->f1++;
|
|
|
|
|
}
|
|
|
|
|
else efa->f1= 0;
|
|
|
|
|
|
|
|
|
|
efa= efa->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while(totsel>0) {
|
|
|
|
|
/* from the outside to the inside */
|
|
|
|
|
|
|
|
|
|
efa= em->faces.first;
|
|
|
|
|
startvl= NULL;
|
|
|
|
|
maxx= -1.0e10;
|
|
|
|
|
tria_nr= 0;
|
|
|
|
|
|
|
|
|
|
while(efa) {
|
|
|
|
|
if(efa->f1) {
|
2009-11-10 20:43:45 +00:00
|
|
|
cent_tri_v3(cent, efa->v1->co, efa->v2->co, efa->v3->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
|
|
|
|
|
|
|
|
|
|
if(cent[0]>maxx) {
|
|
|
|
|
maxx= cent[0];
|
|
|
|
|
startvl= efa;
|
|
|
|
|
tria_nr= 0;
|
|
|
|
|
}
|
|
|
|
|
if(efa->v4) {
|
2009-11-10 20:43:45 +00:00
|
|
|
cent_tri_v3(cent, efa->v1->co, efa->v3->co, efa->v4->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
|
|
|
|
|
|
|
|
|
|
if(cent[0]>maxx) {
|
|
|
|
|
maxx= cent[0];
|
|
|
|
|
startvl= efa;
|
|
|
|
|
tria_nr= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
efa= efa->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (startvl==NULL)
|
|
|
|
|
startvl= em->faces.first;
|
|
|
|
|
|
|
|
|
|
/* set first face correct: calc normal */
|
|
|
|
|
|
|
|
|
|
if(tria_nr==1) {
|
2009-11-10 20:43:45 +00:00
|
|
|
normal_tri_v3( nor,startvl->v1->co, startvl->v3->co, startvl->v4->co);
|
|
|
|
|
cent_tri_v3(cent, startvl->v1->co, startvl->v3->co, startvl->v4->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
} else {
|
2009-11-10 20:43:45 +00:00
|
|
|
normal_tri_v3( nor,startvl->v1->co, startvl->v2->co, startvl->v3->co);
|
|
|
|
|
cent_tri_v3(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
/* first normal is oriented this way or the other */
|
|
|
|
|
if(select) {
|
|
|
|
|
if(select==2) {
|
|
|
|
|
if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0) flipface(em, startvl);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(em, startvl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(em, startvl);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eed= startvl->e1;
|
|
|
|
|
if(eed->v1==startvl->v1) eed->f2= 1;
|
|
|
|
|
else eed->f2= 2;
|
|
|
|
|
|
|
|
|
|
eed= startvl->e2;
|
|
|
|
|
if(eed->v1==startvl->v2) eed->f2= 1;
|
|
|
|
|
else eed->f2= 2;
|
|
|
|
|
|
|
|
|
|
eed= startvl->e3;
|
|
|
|
|
if(eed->v1==startvl->v3) eed->f2= 1;
|
|
|
|
|
else eed->f2= 2;
|
|
|
|
|
|
|
|
|
|
eed= startvl->e4;
|
|
|
|
|
if(eed) {
|
|
|
|
|
if(eed->v1==startvl->v4) eed->f2= 1;
|
|
|
|
|
else eed->f2= 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
startvl->f1= 0;
|
|
|
|
|
totsel--;
|
|
|
|
|
|
|
|
|
|
/* test normals */
|
|
|
|
|
found= 1;
|
|
|
|
|
direct= 1;
|
|
|
|
|
while(found) {
|
|
|
|
|
found= 0;
|
|
|
|
|
if(direct) efa= em->faces.first;
|
|
|
|
|
else efa= em->faces.last;
|
|
|
|
|
while(efa) {
|
|
|
|
|
if(efa->f1) {
|
|
|
|
|
turn= 0;
|
|
|
|
|
foundone= 0;
|
|
|
|
|
|
|
|
|
|
ed1= efa->e1;
|
|
|
|
|
ed2= efa->e2;
|
|
|
|
|
ed3= efa->e3;
|
|
|
|
|
ed4= efa->e4;
|
|
|
|
|
|
|
|
|
|
if(ed1->f2) {
|
|
|
|
|
if(ed1->v1==efa->v1 && ed1->f2==1) turn= 1;
|
|
|
|
|
if(ed1->v2==efa->v1 && ed1->f2==2) turn= 1;
|
|
|
|
|
foundone= 1;
|
|
|
|
|
}
|
|
|
|
|
else if(ed2->f2) {
|
|
|
|
|
if(ed2->v1==efa->v2 && ed2->f2==1) turn= 1;
|
|
|
|
|
if(ed2->v2==efa->v2 && ed2->f2==2) turn= 1;
|
|
|
|
|
foundone= 1;
|
|
|
|
|
}
|
|
|
|
|
else if(ed3->f2) {
|
|
|
|
|
if(ed3->v1==efa->v3 && ed3->f2==1) turn= 1;
|
|
|
|
|
if(ed3->v2==efa->v3 && ed3->f2==2) turn= 1;
|
|
|
|
|
foundone= 1;
|
|
|
|
|
}
|
|
|
|
|
else if(ed4 && ed4->f2) {
|
|
|
|
|
if(ed4->v1==efa->v4 && ed4->f2==1) turn= 1;
|
|
|
|
|
if(ed4->v2==efa->v4 && ed4->f2==2) turn= 1;
|
|
|
|
|
foundone= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(foundone) {
|
|
|
|
|
found= 1;
|
|
|
|
|
totsel--;
|
|
|
|
|
efa->f1= 0;
|
|
|
|
|
|
|
|
|
|
if(turn) {
|
|
|
|
|
if(ed1->v1==efa->v1) ed1->f2= 2;
|
|
|
|
|
else ed1->f2= 1;
|
|
|
|
|
if(ed2->v1==efa->v2) ed2->f2= 2;
|
|
|
|
|
else ed2->f2= 1;
|
|
|
|
|
if(ed3->v1==efa->v3) ed3->f2= 2;
|
|
|
|
|
else ed3->f2= 1;
|
|
|
|
|
if(ed4) {
|
|
|
|
|
if(ed4->v1==efa->v4) ed4->f2= 2;
|
|
|
|
|
else ed4->f2= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flipface(em, efa);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if(ed1->v1== efa->v1) ed1->f2= 1;
|
|
|
|
|
else ed1->f2= 2;
|
|
|
|
|
if(ed2->v1==efa->v2) ed2->f2= 1;
|
|
|
|
|
else ed2->f2= 2;
|
|
|
|
|
if(ed3->v1==efa->v3) ed3->f2= 1;
|
|
|
|
|
else ed3->f2= 2;
|
|
|
|
|
if(ed4) {
|
|
|
|
|
if(ed4->v1==efa->v4) ed4->f2= 1;
|
|
|
|
|
else ed4->f2= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(direct) efa= efa->next;
|
|
|
|
|
else efa= efa->prev;
|
|
|
|
|
}
|
|
|
|
|
direct= 1-direct;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
recalc_editnormals(em);
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
// DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
waitcursor(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-13 02:09:58 +00:00
|
|
|
static int righthandfaces_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* 'standard' behaviour - check if selected, then apply relevant selection */
|
|
|
|
|
|
2009-01-29 18:54:22 +00:00
|
|
|
// XXX need other args
|
2009-01-31 15:21:26 +00:00
|
|
|
righthandfaces(em, RNA_boolean_get(op->ptr, "inside"));
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
|
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
|
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); //TODO is this needed ?
|
2009-03-30 07:28:37 +00:00
|
|
|
|
2009-01-13 02:09:58 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-15 15:40:31 +00:00
|
|
|
void MESH_OT_normals_make_consistent(wmOperatorType *ot)
|
2009-01-13 02:09:58 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
2009-04-15 15:40:31 +00:00
|
|
|
ot->name= "Make Normals Consistent";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Flip all selected vertex and face normals in a consistent direction.";
|
2009-04-15 15:40:31 +00:00
|
|
|
ot->idname= "MESH_OT_normals_make_consistent";
|
2009-01-13 02:09:58 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec= righthandfaces_exec;
|
|
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
2009-01-31 19:40:40 +00:00
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
2009-01-13 02:09:58 +00:00
|
|
|
|
2009-01-31 15:21:26 +00:00
|
|
|
RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
|
2009-01-13 02:09:58 +00:00
|
|
|
}
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* ********** ALIGN WITH VIEW **************** */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void editmesh_calc_selvert_center(EditMesh *em, float cent_r[3])
|
|
|
|
|
{
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
int nsel= 0;
|
|
|
|
|
|
|
|
|
|
cent_r[0]= cent_r[1]= cent_r[0]= 0.0;
|
|
|
|
|
|
|
|
|
|
for (eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if (eve->f & SELECT) {
|
|
|
|
|
cent_r[0]+= eve->co[0];
|
|
|
|
|
cent_r[1]+= eve->co[1];
|
|
|
|
|
cent_r[2]+= eve->co[2];
|
|
|
|
|
nsel++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nsel) {
|
|
|
|
|
cent_r[0]/= nsel;
|
|
|
|
|
cent_r[1]/= nsel;
|
|
|
|
|
cent_r[2]/= nsel;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int mface_is_selected(MFace *mf)
|
|
|
|
|
{
|
|
|
|
|
return (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XXX, code for both these functions should be abstract,
|
|
|
|
|
* then unified, then written for other things (like objects,
|
|
|
|
|
* which would use same as vertices method), then added
|
|
|
|
|
* to interface! Hoera! - zr
|
|
|
|
|
*/
|
2009-02-14 21:31:34 +00:00
|
|
|
void faceselect_align_view_to_selected(View3D *v3d, RegionView3D *rv3d, Mesh *me, wmOperator *op, int axis)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
float norm[3];
|
|
|
|
|
int i, totselected = 0;
|
|
|
|
|
|
|
|
|
|
norm[0]= norm[1]= norm[2]= 0.0;
|
|
|
|
|
for (i=0; i<me->totface; i++) {
|
|
|
|
|
MFace *mf= ((MFace*) me->mface) + i;
|
|
|
|
|
|
|
|
|
|
if (mface_is_selected(mf)) {
|
|
|
|
|
float *v1, *v2, *v3, fno[3];
|
|
|
|
|
|
|
|
|
|
v1= me->mvert[mf->v1].co;
|
|
|
|
|
v2= me->mvert[mf->v2].co;
|
|
|
|
|
v3= me->mvert[mf->v3].co;
|
|
|
|
|
if (mf->v4) {
|
|
|
|
|
float *v4= me->mvert[mf->v4].co;
|
2009-11-10 20:43:45 +00:00
|
|
|
normal_quad_v3( fno,v1, v2, v3, v4);
|
2008-12-30 13:16:14 +00:00
|
|
|
} else {
|
2009-11-10 20:43:45 +00:00
|
|
|
normal_tri_v3( fno,v1, v2, v3);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
norm[0]+= fno[0];
|
|
|
|
|
norm[1]+= fno[1];
|
|
|
|
|
norm[2]+= fno[2];
|
|
|
|
|
|
|
|
|
|
totselected++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (totselected == 0)
|
2009-02-14 21:31:34 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "No faces selected.");
|
2008-12-30 13:16:14 +00:00
|
|
|
else
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* helper for below, to survive non-uniform scaled objects */
|
2009-01-02 19:10:35 +00:00
|
|
|
static void face_getnormal_obspace(Object *obedit, EditFace *efa, float *fno)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
float vec[4][3];
|
|
|
|
|
|
|
|
|
|
VECCOPY(vec[0], efa->v1->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_mat3_m4_v3(obedit->obmat, vec[0]);
|
2008-12-30 13:16:14 +00:00
|
|
|
VECCOPY(vec[1], efa->v2->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_mat3_m4_v3(obedit->obmat, vec[1]);
|
2008-12-30 13:16:14 +00:00
|
|
|
VECCOPY(vec[2], efa->v3->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_mat3_m4_v3(obedit->obmat, vec[2]);
|
2008-12-30 13:16:14 +00:00
|
|
|
if(efa->v4) {
|
|
|
|
|
VECCOPY(vec[3], efa->v4->co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_mat3_m4_v3(obedit->obmat, vec[3]);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
normal_quad_v3( fno,vec[0], vec[1], vec[2], vec[3]);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-11-10 20:43:45 +00:00
|
|
|
else normal_tri_v3( fno,vec[0], vec[1], vec[2]);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-02-14 21:31:34 +00:00
|
|
|
void editmesh_align_view_to_selected(Object *obedit, EditMesh *em, wmOperator *op, View3D *v3d, RegionView3D *rv3d, int axis)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
int nselverts= EM_nvertices_selected(em);
|
|
|
|
|
float norm[3]={0.0, 0.0, 0.0}; /* used for storing the mesh normal */
|
|
|
|
|
|
|
|
|
|
if (nselverts==0) {
|
2009-02-14 21:31:34 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "No faces or vertices selected.");
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
else if (EM_nfaces_selected(em)) {
|
|
|
|
|
EditFace *efa;
|
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
|
if (faceselectedAND(efa, SELECT)) {
|
|
|
|
|
float fno[3];
|
|
|
|
|
|
2009-01-02 19:10:35 +00:00
|
|
|
face_getnormal_obspace(obedit, efa, fno);
|
2008-12-30 13:16:14 +00:00
|
|
|
norm[0]+= fno[0];
|
|
|
|
|
norm[1]+= fno[1];
|
|
|
|
|
norm[2]+= fno[2];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
else if (nselverts>2) {
|
|
|
|
|
float cent[3];
|
|
|
|
|
EditVert *eve, *leve= NULL;
|
|
|
|
|
|
|
|
|
|
editmesh_calc_selvert_center(em, cent);
|
|
|
|
|
for (eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if (eve->f & SELECT) {
|
|
|
|
|
if (leve) {
|
|
|
|
|
float tno[3];
|
2009-11-10 20:43:45 +00:00
|
|
|
normal_tri_v3( tno,cent, leve->co, eve->co);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* XXX, fixme, should be flipped intp a
|
|
|
|
|
* consistent direction. -zr
|
|
|
|
|
*/
|
|
|
|
|
norm[0]+= tno[0];
|
|
|
|
|
norm[1]+= tno[1];
|
|
|
|
|
norm[2]+= tno[2];
|
|
|
|
|
}
|
|
|
|
|
leve= eve;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_mat3_m4_v3(obedit->obmat, norm);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
else if (nselverts==2) { /* Align view to edge (or 2 verts) */
|
|
|
|
|
EditVert *eve, *leve= NULL;
|
|
|
|
|
|
|
|
|
|
for (eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if (eve->f & SELECT) {
|
|
|
|
|
if (leve) {
|
|
|
|
|
norm[0]= leve->co[0] - eve->co[0];
|
|
|
|
|
norm[1]= leve->co[1] - eve->co[1];
|
|
|
|
|
norm[2]= leve->co[2] - eve->co[2];
|
|
|
|
|
break; /* we know there are only 2 verts so no need to keep looking */
|
|
|
|
|
}
|
|
|
|
|
leve= eve;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_mat3_m4_v3(obedit->obmat, norm);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
else if (nselverts==1) { /* Align view to vert normal */
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
|
|
|
|
|
for (eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if (eve->f & SELECT) {
|
|
|
|
|
norm[0]= eve->no[0];
|
|
|
|
|
norm[1]= eve->no[1];
|
|
|
|
|
norm[2]= eve->no[2];
|
|
|
|
|
break; /* we know this is the only selected vert, so no need to keep looking */
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_mat3_m4_v3(obedit->obmat, norm);
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* **************** VERTEX DEFORMS *************** */
|
|
|
|
|
|
2009-02-04 02:58:21 +00:00
|
|
|
static int smooth_vertex(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-02-04 02:58:21 +00:00
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-07-08 21:31:28 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2008-12-30 13:16:14 +00:00
|
|
|
EditVert *eve, *eve_mir = NULL;
|
|
|
|
|
EditEdge *eed;
|
|
|
|
|
float *adror, *adr, fac;
|
|
|
|
|
float fvec[3];
|
|
|
|
|
int teller=0;
|
2009-07-08 21:31:28 +00:00
|
|
|
ModifierData *md;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
/* count */
|
|
|
|
|
eve= em->verts.first;
|
|
|
|
|
while(eve) {
|
|
|
|
|
if(eve->f & SELECT) teller++;
|
|
|
|
|
eve= eve->next;
|
|
|
|
|
}
|
2009-03-30 07:28:37 +00:00
|
|
|
if(teller==0) {
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-03-30 07:28:37 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
|
|
|
|
|
eve= em->verts.first;
|
|
|
|
|
while(eve) {
|
|
|
|
|
if(eve->f & SELECT) {
|
|
|
|
|
eve->tmp.p = (void*)adr;
|
|
|
|
|
eve->f1= 0;
|
|
|
|
|
eve->f2= 0;
|
|
|
|
|
adr+= 3;
|
|
|
|
|
}
|
|
|
|
|
eve= eve->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if there is a mirror modifier with clipping, flag the verts that
|
|
|
|
|
* are within tolerance of the plane(s) of reflection
|
|
|
|
|
*/
|
2009-07-08 21:31:28 +00:00
|
|
|
for(md=obedit->modifiers.first; md; md=md->next) {
|
|
|
|
|
if(md->type==eModifierType_Mirror) {
|
2008-12-30 13:16:14 +00:00
|
|
|
MirrorModifierData *mmd = (MirrorModifierData*) md;
|
|
|
|
|
|
|
|
|
|
if(mmd->flag & MOD_MIR_CLIPPING) {
|
|
|
|
|
for (eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
|
if(eve->f & SELECT) {
|
|
|
|
|
|
|
|
|
|
switch(mmd->axis){
|
|
|
|
|
case 0:
|
|
|
|
|
if (fabs(eve->co[0]) < mmd->tolerance)
|
|
|
|
|
eve->f2 |= 1;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
if (fabs(eve->co[1]) < mmd->tolerance)
|
|
|
|
|
eve->f2 |= 2;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
if (fabs(eve->co[2]) < mmd->tolerance)
|
|
|
|
|
eve->f2 |= 4;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eed= em->edges.first;
|
|
|
|
|
while(eed) {
|
|
|
|
|
if( (eed->v1->f & SELECT) || (eed->v2->f & SELECT) ) {
|
|
|
|
|
fvec[0]= (eed->v1->co[0]+eed->v2->co[0])/2.0;
|
|
|
|
|
fvec[1]= (eed->v1->co[1]+eed->v2->co[1])/2.0;
|
|
|
|
|
fvec[2]= (eed->v1->co[2]+eed->v2->co[2])/2.0;
|
|
|
|
|
|
|
|
|
|
if((eed->v1->f & SELECT) && eed->v1->f1<255) {
|
|
|
|
|
eed->v1->f1++;
|
2009-11-10 20:43:45 +00:00
|
|
|
add_v3_v3v3(eed->v1->tmp.p, eed->v1->tmp.p, fvec);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
if((eed->v2->f & SELECT) && eed->v2->f1<255) {
|
|
|
|
|
eed->v2->f1++;
|
2009-11-10 20:43:45 +00:00
|
|
|
add_v3_v3v3(eed->v2->tmp.p, eed->v2->tmp.p, fvec);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
eed= eed->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eve= em->verts.first;
|
|
|
|
|
while(eve) {
|
|
|
|
|
if(eve->f & SELECT) {
|
|
|
|
|
if(eve->f1) {
|
|
|
|
|
|
2009-10-14 14:28:05 +00:00
|
|
|
if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
|
2009-01-29 18:54:22 +00:00
|
|
|
eve_mir= editmesh_get_x_mirror_vert(obedit, em, eve->co);
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
adr = eve->tmp.p;
|
|
|
|
|
fac= 0.5/(float)eve->f1;
|
|
|
|
|
|
|
|
|
|
eve->co[0]= 0.5*eve->co[0]+fac*adr[0];
|
|
|
|
|
eve->co[1]= 0.5*eve->co[1]+fac*adr[1];
|
|
|
|
|
eve->co[2]= 0.5*eve->co[2]+fac*adr[2];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* clip if needed by mirror modifier */
|
|
|
|
|
if (eve->f2) {
|
|
|
|
|
if (eve->f2 & 1) {
|
|
|
|
|
eve->co[0]= 0.0f;
|
|
|
|
|
}
|
|
|
|
|
if (eve->f2 & 2) {
|
|
|
|
|
eve->co[1]= 0.0f;
|
|
|
|
|
}
|
|
|
|
|
if (eve->f2 & 4) {
|
|
|
|
|
eve->co[2]= 0.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eve_mir) {
|
|
|
|
|
eve_mir->co[0]=-eve->co[0];
|
|
|
|
|
eve_mir->co[1]= eve->co[1];
|
|
|
|
|
eve_mir->co[2]= eve->co[2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
eve->tmp.p= NULL;
|
|
|
|
|
}
|
|
|
|
|
eve= eve->next;
|
|
|
|
|
}
|
|
|
|
|
MEM_freeN(adror);
|
|
|
|
|
|
|
|
|
|
recalc_editnormals(em);
|
|
|
|
|
|
2009-07-08 15:34:41 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-02-04 02:58:21 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
|
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-02-04 02:58:21 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-06 12:34:48 +00:00
|
|
|
static int smooth_vertex_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
int repeat = RNA_int_get(op->ptr, "repeat");
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!repeat) repeat = 1;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<repeat; i++) {
|
|
|
|
|
smooth_vertex(C, op);
|
|
|
|
|
}
|
2009-08-15 16:36:25 +00:00
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2009-08-06 12:34:48 +00:00
|
|
|
}
|
|
|
|
|
|
2009-04-12 17:43:43 +00:00
|
|
|
void MESH_OT_vertices_smooth(wmOperatorType *ot)
|
2009-02-04 02:58:21 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Smooth Vertex";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Flatten angles of selected vertices.";
|
2009-04-12 17:43:43 +00:00
|
|
|
ot->idname= "MESH_OT_vertices_smooth";
|
2009-02-04 02:58:21 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2009-08-06 12:34:48 +00:00
|
|
|
ot->exec= smooth_vertex_exec;
|
2009-02-04 02:58:21 +00:00
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
2009-08-06 12:34:48 +00:00
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
|
2009-08-24 21:45:09 +00:00
|
|
|
RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Smooth Iterations", "", 1, INT_MAX);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-02 19:10:35 +00:00
|
|
|
void vertexnoise(Object *obedit, EditMesh *em)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
Material *ma;
|
|
|
|
|
Tex *tex;
|
|
|
|
|
EditVert *eve;
|
|
|
|
|
float b2, ofs, vec[3];
|
|
|
|
|
|
2009-01-02 19:10:35 +00:00
|
|
|
if(em==NULL) return;
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2009-01-02 19:10:35 +00:00
|
|
|
ma= give_current_material(obedit, obedit->actcol);
|
2008-12-30 13:16:14 +00:00
|
|
|
if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
tex= ma->mtex[0]->tex;
|
|
|
|
|
|
|
|
|
|
ofs= tex->turbul/200.0;
|
|
|
|
|
|
|
|
|
|
eve= (struct EditVert *)em->verts.first;
|
|
|
|
|
while(eve) {
|
|
|
|
|
if(eve->f & SELECT) {
|
|
|
|
|
|
|
|
|
|
if(tex->type==TEX_STUCCI) {
|
|
|
|
|
|
|
|
|
|
b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
|
|
|
|
|
if(tex->stype) ofs*=(b2*b2);
|
|
|
|
|
vec[0]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
|
|
|
|
|
vec[1]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
|
|
|
|
|
vec[2]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
|
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
add_v3_v3v3(eve->co, eve->co, vec);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
float tin, dum;
|
|
|
|
|
externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum);
|
|
|
|
|
eve->co[2]+= 0.05*tin;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
eve= eve->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
recalc_editnormals(em);
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
// DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-05 01:32:37 +00:00
|
|
|
void flipface(EditMesh *em, EditFace *efa)
|
|
|
|
|
{
|
|
|
|
|
if(efa->v4) {
|
|
|
|
|
SWAP(EditVert *, efa->v2, efa->v4);
|
|
|
|
|
SWAP(EditEdge *, efa->e1, efa->e4);
|
|
|
|
|
SWAP(EditEdge *, efa->e2, efa->e3);
|
|
|
|
|
EM_data_interp_from_faces(em, efa, NULL, efa, 0, 3, 2, 1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
SWAP(EditVert *, efa->v2, efa->v3);
|
|
|
|
|
SWAP(EditEdge *, efa->e1, efa->e3);
|
|
|
|
|
efa->e2->dir= 1-efa->e2->dir;
|
|
|
|
|
EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 1, 3);
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
if(efa->v4) normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
|
|
|
|
|
else normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
|
2009-02-05 01:32:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-07-08 21:31:28 +00:00
|
|
|
static int flip_normals(bContext *C, wmOperator *op)
|
2009-02-05 01:32:37 +00:00
|
|
|
{
|
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
2009-04-11 08:26:51 +00:00
|
|
|
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
|
2009-02-05 01:32:37 +00:00
|
|
|
EditFace *efa;
|
|
|
|
|
|
|
|
|
|
efa= em->faces.first;
|
|
|
|
|
while(efa) {
|
|
|
|
|
if( efa->f & SELECT ){
|
|
|
|
|
flipface(em, efa);
|
|
|
|
|
}
|
|
|
|
|
efa= efa->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* update vertex normals too */
|
|
|
|
|
recalc_editnormals(em);
|
|
|
|
|
|
2009-04-11 08:26:51 +00:00
|
|
|
BKE_mesh_end_editmesh(obedit->data, em);
|
2009-07-08 15:34:41 +00:00
|
|
|
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
|
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
2009-07-08 15:34:41 +00:00
|
|
|
|
2009-02-05 01:32:37 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 21:31:28 +00:00
|
|
|
void MESH_OT_flip_normals(wmOperatorType *ot)
|
2009-02-05 01:32:37 +00:00
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name= "Flip Normals";
|
2009-08-17 04:15:53 +00:00
|
|
|
ot->description= "Toggle the direction of selected face's vertex and face normals.";
|
2009-07-08 21:31:28 +00:00
|
|
|
ot->idname= "MESH_OT_flip_normals";
|
2009-02-05 01:32:37 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
2009-07-08 21:31:28 +00:00
|
|
|
ot->exec= flip_normals;
|
2009-02-05 01:32:37 +00:00
|
|
|
ot->poll= ED_operator_editmesh;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
|
}
|
2009-07-08 15:34:41 +00:00
|
|
|
|