Merge branch 'blender2.7'
[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_mesh_runtime.h"
44 #include "BKE_report.h"
45
46 #include "DEG_depsgraph.h"
47 #include "DEG_depsgraph_query.h"
48
49 #include "RNA_define.h"
50 #include "RNA_access.h"
51
52 #include "MEM_guardedalloc.h"
53
54 #include "WM_types.h"
55
56 #include "ED_mesh.h"
57 #include "ED_screen.h"
58 #include "ED_view3d.h"
59
60 #include "mesh_intern.h"  /* own include */
61
62
63 static LinkNode *knifeproject_poly_from_object(const bContext *C, Scene *scene, Object *ob, LinkNode *polys)
64 {
65         Depsgraph *depsgraph = CTX_data_depsgraph(C);
66         ARegion *ar = CTX_wm_region(C);
67         struct Mesh *me_eval;
68         bool me_eval_needs_free;
69
70         if (ob->type == OB_MESH || ob->runtime.mesh_eval) {
71                 Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
72                 me_eval = ob_eval->runtime.mesh_eval;
73                 if (me_eval == NULL) {
74                         Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
75                         me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, CD_MASK_BAREMESH);
76                 }
77                 me_eval_needs_free = false;
78         }
79         else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
80                 me_eval = BKE_mesh_new_nomain_from_curve(ob);
81                 me_eval_needs_free = true;
82         }
83         else {
84                 me_eval = NULL;
85         }
86
87         if (me_eval) {
88                 ListBase nurbslist = {NULL, NULL};
89                 float projmat[4][4];
90
91                 BKE_mesh_to_curve_nurblist(me_eval, &nurbslist, 0);  /* wire */
92                 BKE_mesh_to_curve_nurblist(me_eval, &nurbslist, 1);  /* boundary */
93
94                 ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat);
95
96                 if (nurbslist.first) {
97                         Nurb *nu;
98                         for (nu = nurbslist.first; nu; nu = nu->next) {
99                                 if (nu->bp) {
100                                         int a;
101                                         BPoint *bp;
102                                         bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0;
103                                         float (*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__);
104
105                                         for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) {
106                                                 ED_view3d_project_float_v2_m4(ar, bp->vec, mval[a], projmat);
107                                         }
108                                         if (is_cyclic) {
109                                                 copy_v2_v2(mval[a], mval[0]);
110                                         }
111
112                                         BLI_linklist_prepend(&polys, mval);
113                                 }
114                         }
115                 }
116
117                 BKE_nurbList_free(&nurbslist);
118
119                 if (me_eval_needs_free) {
120                         BKE_mesh_free(me_eval);
121                 }
122         }
123
124         return polys;
125 }
126
127 static int knifeproject_exec(bContext *C, wmOperator *op)
128 {
129         Scene *scene = CTX_data_scene(C);
130         Object *obedit = CTX_data_edit_object(C);
131         BMEditMesh *em = BKE_editmesh_from_object(obedit);
132         const bool cut_through = RNA_boolean_get(op->ptr, "cut_through");
133
134         LinkNode *polys = NULL;
135
136         CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
137         {
138                 if (ob != obedit) {
139                         polys = knifeproject_poly_from_object(C, scene, ob, polys);
140                 }
141         }
142         CTX_DATA_END;
143
144         if (polys) {
145                 EDBM_mesh_knife(C, polys, true, cut_through);
146
147                 /* select only tagged faces */
148                 BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
149
150                 /* not essential, but switch out of vertex mode since the
151                  * selected regions wont be nicely isolated after flushing.
152                  * note: call after de-select to avoid selection flushing */
153                 EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
154
155                 BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
156
157                 BM_mesh_select_mode_flush(em->bm);
158
159                 BLI_linklist_freeN(polys);
160
161                 return OPERATOR_FINISHED;
162         }
163         else {
164                 BKE_report(op->reports, RPT_ERROR, "No other selected objects found to use for projection");
165                 return OPERATOR_CANCELLED;
166         }
167 }
168
169 void MESH_OT_knife_project(wmOperatorType *ot)
170 {
171         /* description */
172         ot->name = "Knife Project";
173         ot->idname = "MESH_OT_knife_project";
174         ot->description = "Use other objects outlines & boundaries to project knife cuts";
175
176         /* callbacks */
177         ot->exec = knifeproject_exec;
178         ot->poll = ED_operator_editmesh_region_view3d;
179
180         /* flags */
181         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_USE_EVAL_DATA;
182
183         /* parameters */
184         RNA_def_boolean(ot->srna, "cut_through", false, "Cut through", "Cut through all faces, not just visible ones");
185 }