Orientation for 3D cursor
[blender.git] / source / blender / editors / mesh / editmesh_knife_project.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Campbell Barton
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/mesh/editmesh_knife_project.c
28  *  \ingroup edmesh
29  */
30
31 #include "DNA_curve_types.h"
32 #include "DNA_object_types.h"
33
34 #include "BLI_math.h"
35 #include "BLI_linklist.h"
36 #include "BLI_listbase.h"
37
38 #include "BKE_mesh.h"
39 #include "BKE_context.h"
40 #include "BKE_curve.h"
41 #include "BKE_cdderivedmesh.h"
42 #include "BKE_editmesh.h"
43 #include "BKE_report.h"
44
45 #include "DEG_depsgraph.h"
46
47 #include "RNA_define.h"
48 #include "RNA_access.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "WM_types.h"
53
54 #include "ED_mesh.h"
55 #include "ED_screen.h"
56 #include "ED_view3d.h"
57
58 #include "mesh_intern.h"  /* own include */
59
60
61 static LinkNode *knifeproject_poly_from_object(const bContext *C, Scene *scene, Object *ob, LinkNode *polys)
62 {
63         Depsgraph *depsgraph = CTX_data_depsgraph(C);
64         ARegion *ar = CTX_wm_region(C);
65         DerivedMesh *dm;
66         bool dm_needsFree;
67
68         if (ob->type == OB_MESH || ob->derivedFinal) {
69                 dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(depsgraph, scene, ob, CD_MASK_BAREMESH);
70                 dm_needsFree = false;
71         }
72         else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
73                 dm = CDDM_from_curve(ob);
74                 dm_needsFree = true;
75         }
76         else {
77                 dm = NULL;
78         }
79
80         if (dm) {
81                 ListBase nurbslist = {NULL, NULL};
82                 float projmat[4][4];
83
84                 BKE_mesh_to_curve_nurblist(dm, &nurbslist, 0);  /* wire */
85                 BKE_mesh_to_curve_nurblist(dm, &nurbslist, 1);  /* boundary */
86
87                 ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat);
88
89                 if (nurbslist.first) {
90                         Nurb *nu;
91                         for (nu = nurbslist.first; nu; nu = nu->next) {
92                                 if (nu->bp) {
93                                         int a;
94                                         BPoint *bp;
95                                         bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0;
96                                         float (*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__);
97
98                                         for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) {
99                                                 ED_view3d_project_float_v2_m4(ar, bp->vec, mval[a], projmat);
100                                         }
101                                         if (is_cyclic) {
102                                                 copy_v2_v2(mval[a], mval[0]);
103                                         }
104
105                                         BLI_linklist_prepend(&polys, mval);
106                                 }
107                         }
108                 }
109
110                 BKE_nurbList_free(&nurbslist);
111
112                 if (dm_needsFree) {
113                         dm->release(dm);
114                 }
115         }
116
117
118         return polys;
119 }
120
121 static int knifeproject_exec(bContext *C, wmOperator *op)
122 {
123         Scene *scene = CTX_data_scene(C);
124         Object *obedit = CTX_data_edit_object(C);
125         BMEditMesh *em = BKE_editmesh_from_object(obedit);
126         const bool cut_through = RNA_boolean_get(op->ptr, "cut_through");
127
128         LinkNode *polys = NULL;
129
130         CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
131         {
132                 if (ob != obedit) {
133                         polys = knifeproject_poly_from_object(C, scene, ob, polys);
134                 }
135         }
136         CTX_DATA_END;
137
138         if (polys) {
139                 EDBM_mesh_knife(C, polys, true, cut_through);
140
141                 /* select only tagged faces */
142                 BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
143
144                 /* not essential, but switch out of vertex mode since the
145                  * selected regions wont be nicely isolated after flushing.
146                  * note: call after de-select to avoid selection flushing */
147                 EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
148
149                 BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
150
151                 BM_mesh_select_mode_flush(em->bm);
152
153                 BLI_linklist_freeN(polys);
154
155                 return OPERATOR_FINISHED;
156         }
157         else {
158                 BKE_report(op->reports, RPT_ERROR, "No other selected objects found to use for projection");
159                 return OPERATOR_CANCELLED;
160         }
161 }
162
163 void MESH_OT_knife_project(wmOperatorType *ot)
164 {
165         /* description */
166         ot->name = "Knife Project";
167         ot->idname = "MESH_OT_knife_project";
168         ot->description = "Use other objects outlines & boundaries to project knife cuts";
169
170         /* callbacks */
171         ot->exec = knifeproject_exec;
172         ot->poll = ED_operator_editmesh_region_view3d;
173
174         /* flags */
175         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
176
177         /* parameters */
178         RNA_def_boolean(ot->srna, "cut_through", false, "Cut through", "Cut through all faces, not just visible ones");
179 }