Merge branch 'blender2.7'
[blender.git] / source / blender / editors / mesh / editmesh_add.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) 2004 by Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joseph Eagar
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/mesh/editmesh_add.c
29  *  \ingroup edmesh
30  */
31
32 #include "DNA_meshdata_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35
36 #include "BLI_math.h"
37
38 #include "BLT_translation.h"
39
40 #include "BKE_context.h"
41 #include "BKE_editmesh.h"
42
43 #include "RNA_define.h"
44 #include "RNA_access.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48
49 #include "ED_mesh.h"
50 #include "ED_screen.h"
51 #include "ED_object.h"
52 #include "ED_uvedit.h"
53
54 #include "mesh_intern.h"  /* own include */
55
56
57 #define MESH_ADD_VERTS_MAXI 10000000
58
59
60 /* ********* add primitive operators ************* */
61
62 typedef struct MakePrimitiveData {
63         float mat[4][4];
64         bool was_editmode;
65 } MakePrimitiveData;
66
67 static Object *make_prim_init(
68         bContext *C, const char *idname,
69         const float loc[3], const float rot[3], ushort local_view_bits,
70         MakePrimitiveData *r_creation_data)
71 {
72         Object *obedit = CTX_data_edit_object(C);
73
74         r_creation_data->was_editmode = false;
75         if (obedit == NULL || obedit->type != OB_MESH) {
76                 obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, local_view_bits);
77
78                 /* create editmode */
79                 /* rare cases the active layer is messed up */
80                 ED_object_editmode_enter(C, EM_IGNORE_LAYER);
81                 r_creation_data->was_editmode = true;
82         }
83
84         ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
85
86         return obedit;
87 }
88
89 static void make_prim_finish(bContext *C, Object *obedit, const MakePrimitiveData *creation_data, int enter_editmode)
90 {
91         BMEditMesh *em = BKE_editmesh_from_object(obedit);
92         const bool exit_editmode = ((creation_data->was_editmode == true) && (enter_editmode == false));
93
94         /* Primitive has all verts selected, use vert select flush
95          * to push this up to edges & faces. */
96         EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
97
98         /* only recalc editmode tessface if we are staying in editmode */
99         EDBM_update_generic(em, !exit_editmode, true);
100
101         /* userdef */
102         if (exit_editmode) {
103                 ED_object_editmode_exit(C, EM_FREEDATA);
104         }
105         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
106 }
107
108 static int add_primitive_plane_exec(bContext *C, wmOperator *op)
109 {
110         MakePrimitiveData creation_data;
111         Object *obedit;
112         BMEditMesh *em;
113         float loc[3], rot[3];
114         bool enter_editmode;
115         ushort local_view_bits;
116         const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
117
118         WM_operator_view3d_unit_defaults(C, op);
119         ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
120         obedit = make_prim_init(
121                 C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"),
122                 loc, rot, local_view_bits, &creation_data);
123         em = BKE_editmesh_from_object(obedit);
124
125         if (calc_uvs) {
126                 ED_mesh_uv_texture_ensure(obedit->data, NULL);
127         }
128
129         if (!EDBM_op_call_and_selectf(
130                 em, op, "verts.out", false,
131                 "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
132                 1, 1, RNA_float_get(op->ptr, "size") / 2.0f, creation_data.mat, calc_uvs))
133         {
134                 return OPERATOR_CANCELLED;
135         }
136
137         make_prim_finish(C, obedit, &creation_data, enter_editmode);
138
139         return OPERATOR_FINISHED;
140 }
141
142 void MESH_OT_primitive_plane_add(wmOperatorType *ot)
143 {
144         /* identifiers */
145         ot->name = "Add Plane";
146         ot->description = "Construct a filled planar mesh with 4 vertices";
147         ot->idname = "MESH_OT_primitive_plane_add";
148
149         /* api callbacks */
150         ot->exec = add_primitive_plane_exec;
151         ot->poll = ED_operator_scene_editable;
152
153         /* flags */
154         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
155
156         ED_object_add_unit_props_size(ot);
157         ED_object_add_mesh_props(ot);
158         ED_object_add_generic_props(ot, true);
159 }
160
161 static int add_primitive_cube_exec(bContext *C, wmOperator *op)
162 {
163         MakePrimitiveData creation_data;
164         Object *obedit;
165         BMEditMesh *em;
166         float loc[3], rot[3];
167         bool enter_editmode;
168         ushort local_view_bits;
169         const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
170
171         WM_operator_view3d_unit_defaults(C, op);
172         ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
173         obedit = make_prim_init(
174                 C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"),
175                 loc, rot, local_view_bits, &creation_data);
176         em = BKE_editmesh_from_object(obedit);
177
178         if (calc_uvs) {
179                 ED_mesh_uv_texture_ensure(obedit->data, NULL);
180         }
181
182         if (!EDBM_op_call_and_selectf(
183                 em, op, "verts.out", false,
184                 "create_cube matrix=%m4 size=%f calc_uvs=%b",
185                 creation_data.mat, RNA_float_get(op->ptr, "size"), calc_uvs))
186         {
187                 return OPERATOR_CANCELLED;
188         }
189
190         /* BMESH_TODO make plane side this: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */
191         make_prim_finish(C, obedit, &creation_data, enter_editmode);
192
193         return OPERATOR_FINISHED;
194 }
195
196 void MESH_OT_primitive_cube_add(wmOperatorType *ot)
197 {
198         /* identifiers */
199         ot->name = "Add Cube";
200         ot->description = "Construct a cube mesh";
201         ot->idname = "MESH_OT_primitive_cube_add";
202
203         /* api callbacks */
204         ot->exec = add_primitive_cube_exec;
205         ot->poll = ED_operator_scene_editable;
206
207         /* flags */
208         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
209
210         ED_object_add_unit_props_size(ot);
211         ED_object_add_mesh_props(ot);
212         ED_object_add_generic_props(ot, true);
213 }
214
215 static const EnumPropertyItem fill_type_items[] = {
216         {0, "NOTHING", 0, "Nothing", "Don't fill at all"},
217         {1, "NGON", 0, "Ngon", "Use ngons"},
218         {2, "TRIFAN", 0, "Triangle Fan", "Use triangle fans"},
219         {0, NULL, 0, NULL, NULL}};
220
221 static int add_primitive_circle_exec(bContext *C, wmOperator *op)
222 {
223         MakePrimitiveData creation_data;
224         Object *obedit;
225         BMEditMesh *em;
226         float loc[3], rot[3];
227         bool enter_editmode;
228         ushort local_view_bits;
229         int cap_end, cap_tri;
230         const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
231
232         cap_end = RNA_enum_get(op->ptr, "fill_type");
233         cap_tri = (cap_end == 2);
234
235         WM_operator_view3d_unit_defaults(C, op);
236         ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
237         obedit = make_prim_init(
238                 C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"),
239                 loc, rot, local_view_bits, &creation_data);
240         em = BKE_editmesh_from_object(obedit);
241
242         if (calc_uvs) {
243                 ED_mesh_uv_texture_ensure(obedit->data, NULL);
244         }
245
246         if (!EDBM_op_call_and_selectf(
247                 em, op, "verts.out", false,
248                 "create_circle segments=%i radius=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b",
249                 RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
250                 cap_end, cap_tri, creation_data.mat, calc_uvs))
251         {
252                 return OPERATOR_CANCELLED;
253         }
254
255         make_prim_finish(C, obedit, &creation_data, enter_editmode);
256
257         return OPERATOR_FINISHED;
258 }
259
260 void MESH_OT_primitive_circle_add(wmOperatorType *ot)
261 {
262         /* identifiers */
263         ot->name = "Add Circle";
264         ot->description = "Construct a circle mesh";
265         ot->idname = "MESH_OT_primitive_circle_add";
266
267         /* api callbacks */
268         ot->exec = add_primitive_circle_exec;
269         ot->poll = ED_operator_scene_editable;
270
271         /* flags */
272         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
273
274         /* props */
275         RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
276         ED_object_add_unit_props_radius(ot);
277         RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", "");
278
279         ED_object_add_mesh_props(ot);
280         ED_object_add_generic_props(ot, true);
281 }
282
283 static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
284 {
285         MakePrimitiveData creation_data;
286         Object *obedit;
287         BMEditMesh *em;
288         float loc[3], rot[3];
289         bool enter_editmode;
290         ushort local_view_bits;
291         const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
292         const bool cap_end = (end_fill_type != 0);
293         const bool cap_tri = (end_fill_type == 2);
294         const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
295
296         WM_operator_view3d_unit_defaults(C, op);
297         ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
298         obedit = make_prim_init(
299                 C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"),
300                 loc, rot, local_view_bits, &creation_data);
301         em = BKE_editmesh_from_object(obedit);
302
303         if (calc_uvs) {
304                 ED_mesh_uv_texture_ensure(obedit->data, NULL);
305         }
306
307         if (!EDBM_op_call_and_selectf(
308                 em, op, "verts.out", false,
309                 "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
310                 RNA_int_get(op->ptr, "vertices"),
311                 RNA_float_get(op->ptr, "radius"),
312                 RNA_float_get(op->ptr, "radius"),
313                 cap_end, cap_tri,
314                 RNA_float_get(op->ptr, "depth"), creation_data.mat, calc_uvs))
315         {
316                 return OPERATOR_CANCELLED;
317         }
318
319         make_prim_finish(C, obedit, &creation_data, enter_editmode);
320
321         return OPERATOR_FINISHED;
322 }
323
324 void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
325 {
326         /* identifiers */
327         ot->name = "Add Cylinder";
328         ot->description = "Construct a cylinder mesh";
329         ot->idname = "MESH_OT_primitive_cylinder_add";
330
331         /* api callbacks */
332         ot->exec = add_primitive_cylinder_exec;
333         ot->poll = ED_operator_scene_editable;
334
335         /* flags */
336         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
337
338         /* props */
339         RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
340         ED_object_add_unit_props_radius(ot);
341         RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
342         RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", "");
343
344         ED_object_add_mesh_props(ot);
345         ED_object_add_generic_props(ot, true);
346 }
347
348 static int add_primitive_cone_exec(bContext *C, wmOperator *op)
349 {
350         MakePrimitiveData creation_data;
351         Object *obedit;
352         BMEditMesh *em;
353         float loc[3], rot[3];
354         bool enter_editmode;
355         ushort local_view_bits;
356         const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
357         const bool cap_end = (end_fill_type != 0);
358         const bool cap_tri = (end_fill_type == 2);
359         const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
360
361         WM_operator_view3d_unit_defaults(C, op);
362         ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
363         obedit = make_prim_init(
364                 C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"),
365                 loc, rot, local_view_bits, &creation_data);
366         em = BKE_editmesh_from_object(obedit);
367
368         if (calc_uvs) {
369                 ED_mesh_uv_texture_ensure(obedit->data, NULL);
370         }
371
372         if (!EDBM_op_call_and_selectf(
373                 em, op, "verts.out", false,
374                 "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
375                 RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"),
376                 RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"),
377                 creation_data.mat, calc_uvs))
378         {
379                 return OPERATOR_CANCELLED;
380         }
381
382         make_prim_finish(C, obedit, &creation_data, enter_editmode);
383
384         return OPERATOR_FINISHED;
385 }
386
387 void MESH_OT_primitive_cone_add(wmOperatorType *ot)
388 {
389         /* identifiers */
390         ot->name = "Add Cone";
391         ot->description = "Construct a conic mesh";
392         ot->idname = "MESH_OT_primitive_cone_add";
393
394         /* api callbacks */
395         ot->exec = add_primitive_cone_exec;
396         ot->poll = ED_operator_scene_editable;
397
398         /* flags */
399         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
400
401         /* props */
402         RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
403         RNA_def_float_distance(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00);
404         RNA_def_float_distance(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.0, 100.00);
405         RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
406         RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", "");
407
408         ED_object_add_mesh_props(ot);
409         ED_object_add_generic_props(ot, true);
410 }
411
412 static int add_primitive_grid_exec(bContext *C, wmOperator *op)
413 {
414         MakePrimitiveData creation_data;
415         Object *obedit;
416         BMEditMesh *em;
417         float loc[3], rot[3];
418         bool enter_editmode;
419         ushort local_view_bits;
420         const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
421
422         WM_operator_view3d_unit_defaults(C, op);
423         ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
424         obedit = make_prim_init(
425                 C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"),
426                 loc, rot, local_view_bits, &creation_data);
427         em = BKE_editmesh_from_object(obedit);
428
429         if (calc_uvs) {
430                 ED_mesh_uv_texture_ensure(obedit->data, NULL);
431         }
432
433         if (!EDBM_op_call_and_selectf(
434                 em, op, "verts.out", false,
435                 "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
436                 RNA_int_get(op->ptr, "x_subdivisions"),
437                 RNA_int_get(op->ptr, "y_subdivisions"),
438                 RNA_float_get(op->ptr, "size") / 2.0f, creation_data.mat, calc_uvs))
439         {
440                 return OPERATOR_CANCELLED;
441         }
442
443         make_prim_finish(C, obedit, &creation_data, enter_editmode);
444
445         return OPERATOR_FINISHED;
446 }
447
448 void MESH_OT_primitive_grid_add(wmOperatorType *ot)
449 {
450         /* identifiers */
451         ot->name = "Add Grid";
452         ot->description = "Construct a grid mesh";
453         ot->idname = "MESH_OT_primitive_grid_add";
454
455         /* api callbacks */
456         ot->exec = add_primitive_grid_exec;
457         ot->poll = ED_operator_scene_editable;
458
459         /* flags */
460         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
461
462         /* props */
463         /* Note that if you use MESH_ADD_VERTS_MAXI for both x and y at the same time you will still reach
464          * impossible values (10^12 vertices or so...). */
465         RNA_def_int(ot->srna, "x_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "X Subdivisions", "", 2, 1000);
466         RNA_def_int(ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000);
467
468         ED_object_add_unit_props_size(ot);
469         ED_object_add_mesh_props(ot);
470         ED_object_add_generic_props(ot, true);
471 }
472
473 static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
474 {
475         MakePrimitiveData creation_data;
476         Object *obedit;
477         BMEditMesh *em;
478         float loc[3], rot[3];
479         float dia;
480         bool enter_editmode;
481         ushort local_view_bits;
482         const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
483
484         WM_operator_view3d_unit_defaults(C, op);
485         ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &local_view_bits, NULL);
486
487         obedit = make_prim_init(
488                 C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"),
489                 loc, rot, local_view_bits, &creation_data);
490         dia = RNA_float_get(op->ptr, "size") / 2.0f;
491         mul_mat3_m4_fl(creation_data.mat, dia);
492
493         em = BKE_editmesh_from_object(obedit);
494
495         if (calc_uvs) {
496                 ED_mesh_uv_texture_ensure(obedit->data, NULL);
497         }
498
499         if (!EDBM_op_call_and_selectf(
500                 em, op, "verts.out",  false,
501                 "create_monkey matrix=%m4 calc_uvs=%b", creation_data.mat, calc_uvs))
502         {
503                 return OPERATOR_CANCELLED;
504         }
505
506         make_prim_finish(C, obedit, &creation_data, enter_editmode);
507
508         return OPERATOR_FINISHED;
509 }
510
511 void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
512 {
513         /* identifiers */
514         ot->name = "Add Monkey";
515         ot->description = "Construct a Suzanne mesh";
516         ot->idname = "MESH_OT_primitive_monkey_add";
517
518         /* api callbacks */
519         ot->exec = add_primitive_monkey_exec;
520         ot->poll = ED_operator_scene_editable;
521
522         /* flags */
523         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
524
525         /* props */
526         ED_object_add_unit_props_size(ot);
527         ED_object_add_mesh_props(ot);
528         ED_object_add_generic_props(ot, true);
529 }
530
531 static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
532 {
533         MakePrimitiveData creation_data;
534         Object *obedit;
535         BMEditMesh *em;
536         float loc[3], rot[3];
537         bool enter_editmode;
538         ushort local_view_bits;
539         const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
540
541         WM_operator_view3d_unit_defaults(C, op);
542         ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
543         obedit = make_prim_init(
544                 C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"),
545                 loc, rot, local_view_bits, &creation_data);
546         em = BKE_editmesh_from_object(obedit);
547
548         if (calc_uvs) {
549                 ED_mesh_uv_texture_ensure(obedit->data, NULL);
550         }
551
552         if (!EDBM_op_call_and_selectf(
553                 em, op, "verts.out", false,
554                 "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b",
555                 RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"),
556                 RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs))
557         {
558                 return OPERATOR_CANCELLED;
559         }
560
561         make_prim_finish(C, obedit, &creation_data, enter_editmode);
562
563         return OPERATOR_FINISHED;
564 }
565
566 void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
567 {
568         /* identifiers */
569         ot->name = "Add UV Sphere";
570         ot->description = "Construct a UV sphere mesh";
571         ot->idname = "MESH_OT_primitive_uv_sphere_add";
572
573         /* api callbacks */
574         ot->exec = add_primitive_uvsphere_exec;
575         ot->poll = ED_operator_scene_editable;
576
577         /* flags */
578         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
579
580         /* props */
581         RNA_def_int(ot->srna, "segments", 32, 3, MESH_ADD_VERTS_MAXI / 100, "Segments", "", 3, 500);
582         RNA_def_int(ot->srna, "ring_count", 16, 3, MESH_ADD_VERTS_MAXI / 100, "Rings", "", 3, 500);
583
584         ED_object_add_unit_props_radius(ot);
585         ED_object_add_mesh_props(ot);
586         ED_object_add_generic_props(ot, true);
587 }
588
589 static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
590 {
591         MakePrimitiveData creation_data;
592         Object *obedit;
593         BMEditMesh *em;
594         float loc[3], rot[3];
595         bool enter_editmode;
596         ushort local_view_bits;
597         const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
598
599         WM_operator_view3d_unit_defaults(C, op);
600         ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
601         obedit = make_prim_init(
602                 C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"),
603                 loc, rot, local_view_bits, &creation_data);
604         em = BKE_editmesh_from_object(obedit);
605
606         if (calc_uvs) {
607                 ED_mesh_uv_texture_ensure(obedit->data, NULL);
608         }
609
610         if (!EDBM_op_call_and_selectf(
611                 em, op, "verts.out", false,
612                 "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b",
613                 RNA_int_get(op->ptr, "subdivisions"),
614                 RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs))
615         {
616                 return OPERATOR_CANCELLED;
617         }
618
619         make_prim_finish(C, obedit, &creation_data, enter_editmode);
620
621         return OPERATOR_FINISHED;
622 }
623
624 void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
625 {
626         /* identifiers */
627         ot->name = "Add Ico Sphere";
628         ot->description = "Construct an Icosphere mesh";
629         ot->idname = "MESH_OT_primitive_ico_sphere_add";
630
631         /* api callbacks */
632         ot->exec = add_primitive_icosphere_exec;
633         ot->poll = ED_operator_scene_editable;
634
635         /* flags */
636         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
637
638         /* props */
639         RNA_def_int(ot->srna, "subdivisions", 2, 1, 10, "Subdivisions", "", 1, 8);
640
641         ED_object_add_unit_props_radius(ot);
642         ED_object_add_mesh_props(ot);
643         ED_object_add_generic_props(ot, true);
644 }