diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-03-15 17:06:31 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-03-15 17:06:31 +0400 |
commit | 03f02019f221cb4c0f122d0bb1fe982cac60f70e (patch) | |
tree | 4e98d0e763bc776356f9ba6d534baad857add45d /source | |
parent | 6dc4ea34e44ae77125918ab9eda0fcfe7d9f0b3c (diff) |
knife projection feature,
apart of 3d printing tools - use to cookie-cut text into a mesh.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/mesh/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife.c | 165 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife_project.c | 163 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_intern.h | 5 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_ops.c | 1 |
5 files changed, 335 insertions, 0 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 169e7a60fb1..7e194d7ed5c 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -43,6 +43,7 @@ set(SRC editmesh_add.c editmesh_bvh.c editmesh_knife.c + editmesh_knife_project.c editmesh_loopcut.c editmesh_rip.c editmesh_select.c diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index f822b398003..0bdd1275714 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_array.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_smallhash.h" #include "BLI_memarena.h" @@ -3270,3 +3271,167 @@ void MESH_OT_knife_tool(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_occlude_geometry", TRUE, "Occlude Geometry", "Only cut the front most geometry"); RNA_def_boolean(ot->srna, "only_selected", FALSE, "Only Selected", "Only cut selected geometry"); } + + +/* -------------------------------------------------------------------- */ +/* Knife tool as a utility function + * that can be used for internal slicing operations */ + +static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, float projmat[4][4]) +{ + float co[3]; + float co_ss[2]; + + { + BMLoop *l; + float tangent[3]; + + l = BM_FACE_FIRST_LOOP(f); + BM_loop_calc_face_tangent(l, tangent); + /* get a point inside the face (tiny offset) - we could be more clever here */ + mul_v3_fl(tangent, 0.02f); + add_v3_v3v3(co, l->v->co, tangent); + } + + ED_view3d_project_float_v3_m4(ar, co, co_ss, projmat); + + /* check */ + { + LinkNode *p = polys; + int isect = 0; + + while (p) { + const float (*mval_fl)[2] = p->link; + const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); + isect += (int)isect_point_poly_v2(co_ss, mval_fl, mval_tot - 1); + p = p->next; + } + + if (isect % 2) { + return true; + } + } + + return false; +} + +/** + * \param use_tag When set, tag all faces inside the polylines. + */ +void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag) +{ + KnifeTool_OpData *kcd; + + view3d_operator_needs_opengl(C); + + /* init */ + { + const bool only_select = false; + const bool cut_through = false; + + kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__); + + knifetool_init(C, kcd, only_select, cut_through); + + kcd->ignore_edge_snapping = true; + kcd->ignore_vert_snapping = true; + + if (use_tag) { + BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false); + } + } + + /* execute */ + { + LinkNode *p = polys; + + knife_recalc_projmat(kcd); + + while (p) { + const float (*mval_fl)[2] = p->link; + const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); + int i; + + for (i = 0; i < mval_tot; i++) { + knifetool_update_mval(kcd, mval_fl[i]); + if (i == 0) { + knife_start_cut(kcd); + kcd->mode = MODE_DRAGGING; + } + else { + knife_add_cut(kcd); + } + } + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + p = p->next; + } + } + + /* finish */ + { + knifetool_finish_ex(kcd); + + /* tag faces inside! */ + if (use_tag) { + BMesh *bm = kcd->em->bm; + float projmat[4][4]; + + BMEdge *e; + BMIter iter; + + bool keep_search; + + ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, projmat); + + BM_mesh_elem_hflag_disable_all(kcd->em->bm, BM_FACE, BM_ELEM_TAG, false); + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + + /* check are we tagged?, then we are an original face */ + if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) { + BMFace *f; + BMIter fiter; + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + + /* if we trusy b*/ + if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + } + } + } + } + + do { + BMFace *f; + keep_search = false; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG) == false) { + /* am I connected to a tagged face via a tagged edge (ie, not across a cut) */ + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; + int found = false; + + do { + if (BM_elem_flag_test(l_iter, BM_ELEM_TAG) != false) { + found = true; + break; + } + } while ((l_iter = l_iter->next) != l_first); + + if (found) { + // if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) + { + BM_elem_flag_enable(f, BM_ELEM_TAG); + keep_search = true; + } + } + } + } + } while (keep_search); + } + + knifetool_exit_ex(C, kcd); + kcd = NULL; + } +} diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c new file mode 100644 index 00000000000..7bb7e362c98 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -0,0 +1,163 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_knife_project.c + * \ingroup edmesh + */ + +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_linklist.h" +#include "BLI_listbase.h" + +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_tessmesh.h" +#include "BKE_report.h" + +#include "MEM_guardedalloc.h" + +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "mesh_intern.h" + + +static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object *ob, LinkNode *polys) +{ + DerivedMesh *dm; + bool dm_needsFree; + + if (ob->type == OB_MESH || ob->derivedFinal) { + dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + dm_needsFree = false; + } + else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + dm = CDDM_from_curve(ob); + dm_needsFree = true; + } + + if (dm) { + ListBase nurbslist = {NULL, NULL}; + float projmat[4][4]; + + BKE_mesh_to_curve_nurblist(dm, &nurbslist, 0); /* wire */ + BKE_mesh_to_curve_nurblist(dm, &nurbslist, 1); /* boundary */ + + ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat); + + if (nurbslist.first) { + Nurb *nu; + for (nu = nurbslist.first; nu; nu = nu->next) { + if (nu->bp) { + int a; + BPoint *bp; + bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0; + float (*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__); + + for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) { + ED_view3d_project_float_v3_m4(ar, bp->vec, mval[a], projmat); + } + if (is_cyclic) { + copy_v2_v2(mval[a], mval[0]); + } + + BLI_linklist_prepend(&polys, mval); + } + } + } + + BKE_nurbList_free(&nurbslist); + + if (dm_needsFree) { + dm->release(dm); + } + } + + + return polys; +} + +static int knifeproject_exec(bContext *C, wmOperator *op) +{ + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BMEdit_FromObject(obedit); + + LinkNode *polys = NULL; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + if (ob != obedit) { + polys = knifeproject_poly_from_object(ar, scene, ob, polys); + } + } + CTX_DATA_END; + + if (polys) { + EDBM_mesh_knife(C, polys, true); + + /* select only tagged faces */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, BM_ELEM_TAG); + + BLI_linklist_freeN(polys); + + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No other selected objects found to use for projection"); + return OPERATOR_CANCELLED; + } +} + +void MESH_OT_knife_project(wmOperatorType *ot) +{ + /* description */ + ot->name = "Knife Project"; + ot->idname = "MESH_OT_knife_project"; + ot->description = "Use other objects outlines & boundaries to project knife cuts"; + + /* callbacks */ + ot->exec = knifeproject_exec; + ot->poll = ED_operator_editmesh_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; +} + diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index e3d795e88ca..f2b11877a70 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -48,6 +48,7 @@ struct wmKeyConfig; struct wmKeyMap; struct wmOperator; struct wmOperatorType; +struct LinkNode; /* ******************** editmesh_utils.c */ @@ -204,6 +205,8 @@ void MESH_OT_edgering_select(struct wmOperatorType *ot); void MESH_OT_loopcut(struct wmOperatorType *ot); void MESH_OT_knife_tool(struct wmOperatorType *ot); +void MESH_OT_knife_project(wmOperatorType *ot); + void MESH_OT_bevel(struct wmOperatorType *ot); void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot); @@ -221,4 +224,6 @@ void MESH_OT_navmesh_face_add(struct wmOperatorType *ot); void MESH_OT_navmesh_reset(struct wmOperatorType *ot); void MESH_OT_navmesh_clear(struct wmOperatorType *ot); +void EDBM_mesh_knife(struct bContext *C, struct LinkNode *polys, bool use_tag); + #endif /* __MESH_INTERN_H__ */ diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 884c4a3bee1..50c1b55ac1c 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -149,6 +149,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_select_nth); WM_operatortype_append(MESH_OT_vert_connect); WM_operatortype_append(MESH_OT_knife_tool); + WM_operatortype_append(MESH_OT_knife_project); WM_operatortype_append(MESH_OT_bevel); |