knife projection feature,
apart of 3d printing tools - use to cookie-cut text into a mesh.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
163
source/blender/editors/mesh/editmesh_knife_project.c
Normal file
163
source/blender/editors/mesh/editmesh_knife_project.c
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user