This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/mesh/editmesh_polybuild.c
Sergey Sharybin 79312c1912 Depsgraph: Remove duplicated sets of recalc/update flags
There were at least three copies of those:

- OB_RECALC* family of flags, which are rudiment of an old
  dependency graph system.
- PSYS_RECALC* which were used by old dependency graph system
  as a separate set since the graph itself did not handle
  particle systems.
- DEG_TAG_* which was used to tag IDs.

Now there is a single set, which defines what can be tagged
and queried for an update. It also has some aggregate flags
to make queries simpler.

Lets once and for all solve the madness of those flags, stick
to a single set, which will not overlap with anything or require
any extra conversion.

Technically, shouldn't be measurable user difference, but some
of the agregate flags for few dependency graph components did
change.

Fixes T58632: Particle don't update rotation settings
2018-12-07 11:37:38 +01:00

500 lines
13 KiB
C

/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/mesh/editmesh_polybuild.c
* \ingroup edmesh
*
* Tools to implement polygon building tool,
* an experimental tool for quickly constructing/manipulating faces.
*/
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_layer.h"
#include "WM_types.h"
#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_view3d.h"
#include "bmesh.h"
#include "mesh_intern.h" /* own include */
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
#include "DEG_depsgraph.h"
/* -------------------------------------------------------------------- */
/** \name Local Utilities
* \{ */
static void edbm_selectmode_ensure(Scene *scene, BMEditMesh *em, short selectmode)
{
if ((scene->toolsettings->selectmode & selectmode) == 0) {
scene->toolsettings->selectmode |= selectmode;
em->selectmode = scene->toolsettings->selectmode;
EDBM_selectmode_set(em);
}
}
/* Could make public, for now just keep here. */
static void edbm_flag_disable_all_multi(ViewLayer *view_layer, View3D *v3d, const char hflag)
{
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob_iter = objects[ob_index];
BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
BMesh *bm_iter = em_iter->bm;
if (bm_iter->totvertsel) {
EDBM_flag_disable_all(em_iter, hflag);
DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
}
}
MEM_freeN(objects);
}
/* When accessed as a tool, get the active edge from the preselection gizmo. */
static bool edbm_preselect_or_active(
bContext *C,
Base **r_base,
BMElem **r_ele)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
ARegion *ar = CTX_wm_region(C);
wmGizmoMap *gzmap = ar->gizmo_map;
wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_mesh_preselect_elem") : NULL;
if (gzgroup != NULL) {
wmGizmo *gz = gzgroup->gizmos.first;
const int object_index = RNA_int_get(gz->ptr, "object_index");
/* weak, allocate an array just to access the index. */
Base *base = NULL;
Object *obedit = NULL;
{
uint bases_len;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(view_layer, CTX_wm_view3d(C), &bases_len);
if (object_index < bases_len) {
base = bases[object_index];
obedit = base->object;
}
MEM_freeN(bases);
}
*r_base = base;
*r_ele = NULL;
if (obedit) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
const int vert_index = RNA_int_get(gz->ptr, "vert_index");
const int edge_index = RNA_int_get(gz->ptr, "edge_index");
const int face_index = RNA_int_get(gz->ptr, "face_index");
if (vert_index != -1) {
*r_ele = (BMElem *)BM_vert_at_index_find(bm, vert_index);
}
else if (edge_index != -1) {
*r_ele = (BMElem *)BM_edge_at_index_find(bm, edge_index);
}
else if (face_index != -1) {
*r_ele = (BMElem *)BM_face_at_index_find(bm, face_index);
}
}
}
else {
Base *base = view_layer->basact;
Object *obedit = base->object;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
*r_base = base;
*r_ele = BM_mesh_active_elem_get(bm);
}
return (*r_ele != NULL);
}
static bool edbm_preselect_or_active_init_viewcontext(
bContext *C,
ViewContext *vc,
Base **r_base,
BMElem **r_ele)
{
em_setup_viewcontext(C, vc);
bool ok = edbm_preselect_or_active(C, r_base, r_ele);
if (ok) {
ED_view3d_viewcontext_init_object(vc, (*r_base)->object);
}
return ok;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Face at Cursor
* \{ */
static int edbm_polybuild_face_at_cursor_invoke(
bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
float center[3];
bool changed = false;
ViewContext vc;
Base *basact = NULL;
BMElem *ele_act = NULL;
edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
BMEditMesh *em = vc.em;
BMesh *bm = em->bm;
invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
if (ele_act == NULL || ele_act->head.htype == BM_FACE) {
/* Just add vert */
copy_v3_v3(center, vc.scene->cursor.location);
mul_v3_m4v3(center, vc.obedit->obmat, center);
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
mul_m4_v3(vc.obedit->imat, center);
BMVert *v_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
BM_vert_select_set(bm, v_new, true);
BM_select_history_store(bm, v_new);
changed = true;
}
else if (ele_act->head.htype == BM_EDGE) {
BMEdge *e_act = (BMEdge *)ele_act;
BMFace *f_reference = e_act->l ? e_act->l->f : NULL;
mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co);
mul_m4_v3(vc.obedit->obmat, center);
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
mul_m4_v3(vc.obedit->imat, center);
BMVert *v_tri[3];
v_tri[0] = e_act->v1;
v_tri[1] = e_act->v2;
v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
if (e_act->l && e_act->l->v == v_tri[0]) {
SWAP(BMVert *, v_tri[0], v_tri[1]);
}
// BMFace *f_new =
BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
BM_vert_select_set(bm, v_tri[2], true);
BM_select_history_store(bm, v_tri[2]);
changed = true;
}
else if (ele_act->head.htype == BM_VERT) {
BMVert *v_act = (BMVert *)ele_act;
BMEdge *e_pair[2] = {NULL};
if (v_act->e != NULL) {
for (uint allow_wire = 0; allow_wire < 2 && (e_pair[1] == NULL); allow_wire++) {
int i = 0;
BMEdge *e_iter = v_act->e;
do {
if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) &&
(allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter)))
{
if (i == 2) {
e_pair[0] = e_pair[1] = NULL;
break;
}
e_pair[i++] = e_iter;
}
} while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_act)) != v_act->e);
}
}
if (e_pair[1] != NULL) {
/* Quad from edge pair. */
if (BM_edge_calc_length_squared(e_pair[0]) <
BM_edge_calc_length_squared(e_pair[1]))
{
SWAP(BMEdge *, e_pair[0], e_pair[1]);
}
BMFace *f_reference = e_pair[0]->l ? e_pair[0]->l->f : NULL;
mul_v3_m4v3(center, vc.obedit->obmat, v_act->co);
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
mul_m4_v3(vc.obedit->imat, center);
BMVert *v_quad[4];
v_quad[0] = v_act;
v_quad[1] = BM_edge_other_vert(e_pair[0], v_act);
v_quad[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
v_quad[3] = BM_edge_other_vert(e_pair[1], v_act);
if (e_pair[0]->l && e_pair[0]->l->v == v_quad[0]) {
SWAP(BMVert *, v_quad[1], v_quad[3]);
}
// BMFace *f_new =
BM_face_create_verts(bm, v_quad, 4, f_reference, BM_CREATE_NOP, true);
edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
BM_vert_select_set(bm, v_quad[2], true);
BM_select_history_store(bm, v_quad[2]);
changed = true;
}
else {
/* Just add edge */
mul_m4_v3(vc.obedit->obmat, center);
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, v_act->co, event->mval, center);
mul_m4_v3(vc.obedit->imat, center);
BMVert *v_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
BM_edge_create(bm, v_act, v_new, NULL, BM_CREATE_NOP);
BM_vert_select_set(bm, v_new, true);
BM_select_history_store(bm, v_new);
changed = true;
}
}
if (changed) {
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
if (basact != NULL) {
if (vc.view_layer->basact != basact) {
ED_object_base_activate(C, basact);
}
}
WM_event_add_mousemove(C);
return OPERATOR_FINISHED;
}
else {
return OPERATOR_CANCELLED;
}
}
void MESH_OT_polybuild_face_at_cursor(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Poly Build Face at Cursor";
ot->idname = "MESH_OT_polybuild_face_at_cursor";
/* api callbacks */
ot->invoke = edbm_polybuild_face_at_cursor_invoke;
ot->poll = EDBM_view3d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Split at Cursor
* \{ */
static int edbm_polybuild_split_at_cursor_invoke(
bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
float center[3];
bool changed = false;
ViewContext vc;
Base *basact = NULL;
BMElem *ele_act = NULL;
edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
BMEditMesh *em = vc.em;
BMesh *bm = em->bm;
invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
if (ele_act == NULL || ele_act->head.hflag == BM_FACE) {
return OPERATOR_PASS_THROUGH;
}
else if (ele_act->head.htype == BM_EDGE) {
BMEdge *e_act = (BMEdge *)ele_act;
mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co);
mul_m4_v3(vc.obedit->obmat, center);
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
mul_m4_v3(vc.obedit->imat, center);
const float fac = line_point_factor_v3(center, e_act->v1->co, e_act->v2->co);
BMVert *v_new = BM_edge_split(bm, e_act, e_act->v1, NULL, CLAMPIS(fac, 0.0f, 1.0f));
copy_v3_v3(v_new->co, center);
edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
BM_vert_select_set(bm, v_new, true);
BM_select_history_store(bm, v_new);
changed = true;
}
else if (ele_act->head.htype == BM_VERT) {
/* Just do nothing, allow dragging. */
return OPERATOR_FINISHED;
}
if (changed) {
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
WM_event_add_mousemove(C);
if (vc.view_layer->basact != basact) {
ED_object_base_activate(C, basact);
}
return OPERATOR_FINISHED;
}
else {
return OPERATOR_CANCELLED;
}
}
void MESH_OT_polybuild_split_at_cursor(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Poly Build Split at Cursor";
ot->idname = "MESH_OT_polybuild_split_at_cursor";
/* api callbacks */
ot->invoke = edbm_polybuild_split_at_cursor_invoke;
ot->poll = EDBM_view3d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Dissolve at Cursor
*
* \{ */
static int edbm_polybuild_dissolve_at_cursor_invoke(
bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
bool changed = false;
ViewContext vc;
Base *basact = NULL;
BMElem *ele_act = NULL;
edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
BMEditMesh *em = vc.em;
BMesh *bm = em->bm;
if (ele_act == NULL) {
/* pass */
}
else if (ele_act->head.htype == BM_EDGE) {
BMEdge *e_act = (BMEdge *)ele_act;
BMLoop *l_a, *l_b;
if (BM_edge_loop_pair(e_act, &l_a, &l_b)) {
BMFace *f_new = BM_faces_join_pair(bm, l_a, l_b, true);
if (f_new) {
changed = true;
}
}
}
else if (ele_act->head.htype == BM_VERT) {
BMVert *v_act = (BMVert *)ele_act;
if (BM_vert_is_edge_pair(v_act)) {
BM_edge_collapse(
bm, v_act->e, v_act,
true, true);
}
else {
/* too involved to do inline */
/* Avoid using selection so failure wont leave modified state. */
EDBM_flag_disable_all(em, BM_ELEM_TAG);
BM_elem_flag_enable(v_act, BM_ELEM_TAG);
if (!EDBM_op_callf(em, op,
"dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
BM_ELEM_TAG, false, false))
{
return OPERATOR_CANCELLED;
}
}
changed = true;
}
if (changed) {
edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
if (vc.view_layer->basact != basact) {
ED_object_base_activate(C, basact);
}
WM_event_add_mousemove(C);
return OPERATOR_FINISHED;
}
else {
return OPERATOR_CANCELLED;
}
}
void MESH_OT_polybuild_dissolve_at_cursor(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Poly Build Dissolve at Cursor";
ot->idname = "MESH_OT_polybuild_dissolve_at_cursor";
/* api callbacks */
ot->invoke = edbm_polybuild_dissolve_at_cursor_invoke;
ot->poll = EDBM_view3d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */