Cycles: svn merge -r41467:41531 ^/trunk/blender
[blender.git] / source / blender / editors / mesh / mesh_data.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) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/mesh/mesh_data.c
28  *  \ingroup edmesh
29  */
30
31
32 #include <math.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_material_types.h"
39 #include "DNA_meshdata_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_view3d_types.h"
43
44 #include "BLI_math.h"
45 #include "BLI_editVert.h"
46 #include "BLI_edgehash.h"
47 #include "BLI_utildefines.h"
48
49 #include "BKE_context.h"
50 #include "BKE_depsgraph.h"
51 #include "BKE_displist.h"
52 #include "BKE_image.h"
53 #include "BKE_library.h"
54 #include "BKE_main.h"
55 #include "BKE_material.h"
56 #include "BKE_mesh.h"
57 #include "BKE_report.h"
58
59 #include "RNA_access.h"
60 #include "RNA_define.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "ED_mesh.h"
66 #include "ED_object.h"
67 #include "ED_uvedit.h"
68 #include "ED_view3d.h"
69
70 #include "RE_render_ext.h"
71
72 #include "mesh_intern.h"
73
74 static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *layer)
75 {
76         Mesh *me = ob->data;
77         CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
78         void *actlayerdata, *rndlayerdata, *clonelayerdata, *stencillayerdata, *layerdata=layer->data;
79         int type= layer->type;
80         int index= CustomData_get_layer_index(data, type);
81         int i, actindex, rndindex, cloneindex, stencilindex;
82         
83         /* ok, deleting a non-active layer needs to preserve the active layer indices.
84           to do this, we store a pointer to the .data member of both layer and the active layer,
85           (to detect if we're deleting the active layer or not), then use the active
86           layer data pointer to find where the active layer has ended up.
87           
88           this is necassary because the deletion functions only support deleting the active
89           layer. */
90         actlayerdata = data->layers[CustomData_get_active_layer_index(data, type)].data;
91         rndlayerdata = data->layers[CustomData_get_render_layer_index(data, type)].data;
92         clonelayerdata = data->layers[CustomData_get_clone_layer_index(data, type)].data;
93         stencillayerdata = data->layers[CustomData_get_stencil_layer_index(data, type)].data;
94         CustomData_set_layer_active(data, type, layer - &data->layers[index]);
95
96         if(me->edit_mesh) {
97                 EM_free_data_layer(me->edit_mesh, data, type);
98         }
99         else {
100                 CustomData_free_layer_active(data, type, me->totface);
101                 mesh_update_customdata_pointers(me);
102         }
103
104         if(!CustomData_has_layer(data, type) && (type == CD_MCOL && (ob->mode & OB_MODE_VERTEX_PAINT)))
105                 ED_object_toggle_modes(C, OB_MODE_VERTEX_PAINT);
106
107         /* reconstruct active layer */
108         if (actlayerdata != layerdata) {
109                 /* find index */
110                 actindex = CustomData_get_layer_index(data, type);
111                 for (i=actindex; i<data->totlayer; i++) {
112                         if (data->layers[i].data == actlayerdata) {
113                                 actindex = i - actindex;
114                                 break;
115                         }
116                 }
117                 
118                 /* set index */
119                 CustomData_set_layer_active(data, type, actindex);
120         }
121         
122         if (rndlayerdata != layerdata) {
123                 /* find index */
124                 rndindex = CustomData_get_layer_index(data, type);
125                 for (i=rndindex; i<data->totlayer; i++) {
126                         if (data->layers[i].data == rndlayerdata) {
127                                 rndindex = i - rndindex;
128                                 break;
129                         }
130                 }
131                 
132                 /* set index */
133                 CustomData_set_layer_render(data, type, rndindex);
134         }
135         
136         if (clonelayerdata != layerdata) {
137                 /* find index */
138                 cloneindex = CustomData_get_layer_index(data, type);
139                 for (i=cloneindex; i<data->totlayer; i++) {
140                         if (data->layers[i].data == clonelayerdata) {
141                                 cloneindex = i - cloneindex;
142                                 break;
143                         }
144                 }
145                 
146                 /* set index */
147                 CustomData_set_layer_clone(data, type, cloneindex);
148         }
149         
150         if (stencillayerdata != layerdata) {
151                 /* find index */
152                 stencilindex = CustomData_get_layer_index(data, type);
153                 for (i=stencilindex; i<data->totlayer; i++) {
154                         if (data->layers[i].data == stencillayerdata) {
155                                 stencilindex = i - stencilindex;
156                                 break;
157                         }
158                 }
159                 
160                 /* set index */
161                 CustomData_set_layer_stencil(data, type, stencilindex);
162         }
163 }
164
165 static void copy_editface_active_customdata(EditMesh *em, int type, int index)
166 {
167         EditFace *efa;
168         int n= CustomData_get_active_layer(&em->fdata, type);
169
170         for(efa= em->faces.first; efa; efa= efa->next) {
171                 void *data= CustomData_em_get_n(&em->fdata, efa->data, type, n);
172                 CustomData_em_set_n(&em->fdata, efa->data, type, index, data);
173         }
174 }
175
176 int ED_mesh_uv_texture_add(bContext *C, Mesh *me, const char *name, int active_set)
177 {
178         EditMesh *em;
179         int layernum;
180
181         if(me->edit_mesh) {
182                 em= me->edit_mesh;
183
184                 layernum= CustomData_number_of_layers(&em->fdata, CD_MTFACE);
185                 if(layernum >= MAX_MTFACE)
186                         return 0;
187
188                 EM_add_data_layer(em, &em->fdata, CD_MTFACE, name);
189
190                 if(layernum) /* copy data from active UV */
191                         copy_editface_active_customdata(em, CD_MTFACE, layernum);
192
193                 if(active_set || layernum==0)
194                         CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum);
195         }
196         else {
197                 layernum= CustomData_number_of_layers(&me->fdata, CD_MTFACE);
198                 if(layernum >= MAX_MTFACE)
199                         return 0;
200
201                 if(me->mtface)
202                         CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface, name);
203                 else
204                         CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface, name);
205
206                 if(active_set || layernum==0)
207                         CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum);
208
209                 mesh_update_customdata_pointers(me);
210         }
211
212         DAG_id_tag_update(&me->id, 0);
213         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
214
215         return 1;
216 }
217
218 int ED_mesh_uv_texture_remove(bContext *C, Object *ob, Mesh *me)
219 {
220         CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
221         CustomDataLayer *cdl;
222         int index;
223
224         index= CustomData_get_active_layer_index(data, CD_MTFACE);
225         cdl= (index == -1) ? NULL: &data->layers[index];
226
227         if(!cdl)
228                 return 0;
229
230         delete_customdata_layer(C, ob, cdl);
231         DAG_id_tag_update(&me->id, 0);
232         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
233
234         return 1;
235 }
236
237 int ED_mesh_color_add(bContext *C, Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *me, const char *name, int active_set)
238 {
239         EditMesh *em;
240         int layernum;
241
242         if(me->edit_mesh) {
243                 em= me->edit_mesh;
244
245                 layernum= CustomData_number_of_layers(&em->fdata, CD_MCOL);
246                 if(layernum >= MAX_MCOL)
247                         return 0;
248
249                 EM_add_data_layer(em, &em->fdata, CD_MCOL, name);
250
251                 if(layernum) /* copy data from active vertex color layer */
252                         copy_editface_active_customdata(em, CD_MCOL, layernum);
253
254                 if(active_set || layernum==0)
255                         CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum);
256         }
257         else {
258                 layernum= CustomData_number_of_layers(&me->fdata, CD_MCOL);
259                 if(layernum >= MAX_MCOL)
260                         return 0;
261
262                 if(me->mcol)
263                         CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface, name);
264                 else
265                         CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface, name);
266
267                 if(active_set || layernum==0)
268                         CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);
269
270                 mesh_update_customdata_pointers(me);
271         }
272
273         DAG_id_tag_update(&me->id, 0);
274         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
275
276         return 1;
277 }
278
279 int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me)
280 {
281         CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
282         CustomDataLayer *cdl;
283         int index;
284
285          index= CustomData_get_active_layer_index(data, CD_MCOL);
286         cdl= (index == -1)? NULL: &data->layers[index];
287
288         if(!cdl)
289                 return 0;
290
291         delete_customdata_layer(C, ob, cdl);
292         DAG_id_tag_update(&me->id, 0);
293         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
294
295         return 1;
296 }
297
298 /*********************** UV texture operators ************************/
299
300 static int layers_poll(bContext *C)
301 {
302         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
303         ID *data= (ob)? ob->data: NULL;
304         return (ob && !ob->id.lib && ob->type==OB_MESH && data && !data->lib);
305 }
306
307 static int uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op))
308 {
309         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
310         Mesh *me= ob->data;
311
312         if(!ED_mesh_uv_texture_add(C, me, NULL, TRUE))
313                 return OPERATOR_CANCELLED;
314
315         return OPERATOR_FINISHED;
316 }
317
318 void MESH_OT_uv_texture_add(wmOperatorType *ot)
319 {
320         /* identifiers */
321         ot->name= "Add UV Texture";
322         ot->description= "Add UV texture layer";
323         ot->idname= "MESH_OT_uv_texture_add";
324         
325         /* api callbacks */
326         ot->poll= layers_poll;
327         ot->exec= uv_texture_add_exec;
328
329         /* flags */
330         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
331 }
332
333 static int drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
334 {
335         Main *bmain= CTX_data_main(C);
336         Scene *scene= CTX_data_scene(C);
337         View3D *v3d= CTX_wm_view3d(C);
338         Base *base= ED_view3d_give_base_under_cursor(C, event->mval);
339         Image *ima= NULL;
340         Mesh *me;
341         Object *obedit;
342         int exitmode= 0;
343         char name[32];
344         
345         /* Check context */
346         if(base==NULL || base->object->type!=OB_MESH) {
347                 BKE_report(op->reports, RPT_ERROR, "Not an Object or Mesh");
348                 return OPERATOR_CANCELLED;
349         }
350         
351         /* check input variables */
352         if(RNA_property_is_set(op->ptr, "filepath")) {
353                 char path[FILE_MAX];
354                 
355                 RNA_string_get(op->ptr, "filepath", path);
356                 ima= BKE_add_image_file(path);
357         }
358         else {
359                 RNA_string_get(op->ptr, "name", name);
360                 ima= (Image *)find_id("IM", name);
361         }
362         
363         if(!ima) {
364                 BKE_report(op->reports, RPT_ERROR, "Not an Image");
365                 return OPERATOR_CANCELLED;
366         }
367         
368         /* turn mesh in editmode */
369         /* BKE_mesh_get/end_editmesh: ED_uvedit_assign_image also calls this */
370
371         obedit= base->object;
372         me= obedit->data;
373         if(me->edit_mesh==NULL) {
374                 make_editMesh(scene, obedit);
375                 exitmode= 1;
376         }
377         if(me->edit_mesh==NULL)
378                 return OPERATOR_CANCELLED;
379         
380         ED_uvedit_assign_image(bmain, scene, obedit, ima, NULL);
381
382         if(exitmode) {
383                 load_editMesh(scene, obedit);
384                 free_editMesh(me->edit_mesh);
385                 MEM_freeN(me->edit_mesh);
386                 me->edit_mesh= NULL;
387         }
388
389         /* dummie drop support; ensure view shows a result :) */
390         if(v3d)
391                 v3d->flag2 |= V3D_SOLID_TEX;
392         
393         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
394         
395         return OPERATOR_FINISHED;
396 }
397
398 void MESH_OT_drop_named_image(wmOperatorType *ot)
399 {
400         /* identifiers */
401         ot->name= "Assign Image to UV Texture";
402         ot->description= "Assigns Image to active UV layer, or creates a UV layer";
403         ot->idname= "MESH_OT_drop_named_image";
404         
405         /* api callbacks */
406         ot->poll= layers_poll;
407         ot->invoke= drop_named_image_invoke;
408         
409         /* flags */
410         ot->flag= OPTYPE_UNDO;
411         
412         /* properties */
413         RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Image name to assign");
414         RNA_def_string(ot->srna, "filepath", "Path", FILE_MAX, "Filepath", "Path to image file");
415 }
416
417 static int uv_texture_remove_exec(bContext *C, wmOperator *UNUSED(op))
418 {
419         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
420         Mesh *me= ob->data;
421
422         if(!ED_mesh_uv_texture_remove(C, ob, me))
423                 return OPERATOR_CANCELLED;
424
425         return OPERATOR_FINISHED;
426 }
427
428 void MESH_OT_uv_texture_remove(wmOperatorType *ot)
429 {
430         /* identifiers */
431         ot->name= "Remove UV Texture";
432         ot->description= "Remove UV texture layer";
433         ot->idname= "MESH_OT_uv_texture_remove";
434         
435         /* api callbacks */
436         ot->poll= layers_poll;
437         ot->exec= uv_texture_remove_exec;
438
439         /* flags */
440         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
441 }
442
443 /*********************** vertex color operators ************************/
444
445 static int vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op))
446 {
447         Scene *scene= CTX_data_scene(C);
448         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
449         Mesh *me= ob->data;
450
451         if(!ED_mesh_color_add(C, scene, ob, me, NULL, TRUE))
452                 return OPERATOR_CANCELLED;
453
454         return OPERATOR_FINISHED;
455 }
456
457 void MESH_OT_vertex_color_add(wmOperatorType *ot)
458 {
459         /* identifiers */
460         ot->name= "Add Vertex Color";
461         ot->description= "Add vertex color layer";
462         ot->idname= "MESH_OT_vertex_color_add";
463         
464         /* api callbacks */
465         ot->poll= layers_poll;
466         ot->exec= vertex_color_add_exec;
467
468         /* flags */
469         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
470 }
471
472 static int vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op))
473 {
474         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
475         Mesh *me= ob->data;
476
477         if(!ED_mesh_color_remove(C, ob, me))
478                 return OPERATOR_CANCELLED;
479
480         return OPERATOR_FINISHED;
481 }
482
483 void MESH_OT_vertex_color_remove(wmOperatorType *ot)
484 {
485         /* identifiers */
486         ot->name= "Remove Vertex Color";
487         ot->description= "Remove vertex color layer";
488         ot->idname= "MESH_OT_vertex_color_remove";
489         
490         /* api callbacks */
491         ot->exec= vertex_color_remove_exec;
492         ot->poll= layers_poll;
493
494         /* flags */
495         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
496 }
497
498 /*********************** sticky operators ************************/
499
500 static int sticky_add_exec(bContext *C, wmOperator *UNUSED(op))
501 {
502         Scene *scene= CTX_data_scene(C);
503         View3D *v3d= CTX_wm_view3d(C);
504         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
505         Mesh *me= ob->data;
506
507         /*if(me->msticky)
508                 return OPERATOR_CANCELLED;*/
509
510         RE_make_sticky(scene, v3d);
511
512         DAG_id_tag_update(&me->id, 0);
513         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
514
515         return OPERATOR_FINISHED;
516 }
517
518 void MESH_OT_sticky_add(wmOperatorType *ot)
519 {
520         /* identifiers */
521         ot->name= "Add Sticky";
522         ot->description= "Add sticky UV texture layer";
523         ot->idname= "MESH_OT_sticky_add";
524         
525         /* api callbacks */
526         ot->poll= layers_poll;
527         ot->exec= sticky_add_exec;
528
529         /* flags */
530         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
531 }
532
533 static int sticky_remove_exec(bContext *C, wmOperator *UNUSED(op))
534 {
535         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
536         Mesh *me= ob->data;
537
538         if(!me->msticky)
539                 return OPERATOR_CANCELLED;
540
541         CustomData_free_layer_active(&me->vdata, CD_MSTICKY, me->totvert);
542         me->msticky= NULL;
543
544         DAG_id_tag_update(&me->id, 0);
545         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
546
547         return OPERATOR_FINISHED;
548 }
549
550 void MESH_OT_sticky_remove(wmOperatorType *ot)
551 {
552         /* identifiers */
553         ot->name= "Remove Sticky";
554         ot->description= "Remove sticky UV texture layer";
555         ot->idname= "MESH_OT_sticky_remove";
556         
557         /* api callbacks */
558         ot->poll= layers_poll;
559         ot->exec= sticky_remove_exec;
560
561         /* flags */
562         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
563 }
564
565 /************************** Add Geometry Layers *************************/
566
567 void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges)
568 {
569         if(calc_edges || (mesh->totface && mesh->totedge == 0))
570                 BKE_mesh_calc_edges(mesh, calc_edges);
571
572         mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL);
573
574         DAG_id_tag_update(&mesh->id, 0);
575         WM_event_add_notifier(C, NC_GEOM|ND_DATA, mesh);
576 }
577
578 static void mesh_add_verts(Mesh *mesh, int len)
579 {
580         CustomData vdata;
581         MVert *mvert;
582         int i, totvert;
583
584         if(len == 0)
585                 return;
586
587         totvert= mesh->totvert + len;
588         CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
589         CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
590
591         if(!CustomData_has_layer(&vdata, CD_MVERT))
592                 CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
593
594         CustomData_free(&mesh->vdata, mesh->totvert);
595         mesh->vdata= vdata;
596         mesh_update_customdata_pointers(mesh);
597
598         /* scan the input list and insert the new vertices */
599
600         mvert= &mesh->mvert[mesh->totvert];
601         for(i=0; i<len; i++, mvert++)
602                 mvert->flag |= SELECT;
603
604         /* set final vertex list size */
605         mesh->totvert= totvert;
606 }
607
608 void ED_mesh_transform(Mesh *me, float *mat)
609 {
610         int i;
611         MVert *mvert= me->mvert;
612
613         for(i= 0; i < me->totvert; i++, mvert++)
614                 mul_m4_v3((float (*)[4])mat, mvert->co);
615
616         mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
617 }
618
619 static void mesh_add_edges(Mesh *mesh, int len)
620 {
621         CustomData edata;
622         MEdge *medge;
623         int i, totedge;
624
625         if(len == 0)
626                 return;
627
628         totedge= mesh->totedge+len;
629
630         /* update customdata  */
631         CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
632         CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
633
634         if(!CustomData_has_layer(&edata, CD_MEDGE))
635                 CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
636
637         CustomData_free(&mesh->edata, mesh->totedge);
638         mesh->edata= edata;
639         mesh_update_customdata_pointers(mesh);
640
641         /* set default flags */
642         medge= &mesh->medge[mesh->totedge];
643         for(i=0; i<len; i++, medge++)
644                 medge->flag= ME_EDGEDRAW|ME_EDGERENDER|SELECT;
645
646         mesh->totedge= totedge;
647 }
648
649 static void mesh_add_faces(Mesh *mesh, int len)
650 {
651         CustomData fdata;
652         MFace *mface;
653         int i, totface;
654
655         if(len == 0)
656                 return;
657
658         totface= mesh->totface + len;   /* new face count */
659
660         /* update customdata */
661         CustomData_copy(&mesh->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
662         CustomData_copy_data(&mesh->fdata, &fdata, 0, 0, mesh->totface);
663
664         if(!CustomData_has_layer(&fdata, CD_MFACE))
665                 CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
666
667         CustomData_free(&mesh->fdata, mesh->totface);
668         mesh->fdata= fdata;
669         mesh_update_customdata_pointers(mesh);
670
671         /* set default flags */
672         mface= &mesh->mface[mesh->totface];
673         for(i=0; i<len; i++, mface++)
674                 mface->flag= ME_FACE_SEL;
675
676         mesh->totface= totface;
677 }
678
679 /*
680 void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces)
681 {
682         if(mesh->edit_mesh) {
683                 BKE_report(reports, RPT_ERROR, "Can't add geometry in edit mode");
684                 return;
685         }
686
687         if(verts)
688                 mesh_add_verts(mesh, verts);
689         if(edges)
690                 mesh_add_edges(mesh, edges);
691         if(faces)
692                 mesh_add_faces(mesh, faces);
693 }
694 */
695
696 void ED_mesh_faces_add(Mesh *mesh, ReportList *reports, int count)
697 {
698         if(mesh->edit_mesh) {
699                 BKE_report(reports, RPT_ERROR, "Can't add faces in edit mode");
700                 return;
701         }
702
703         mesh_add_faces(mesh, count);
704 }
705
706 void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count)
707 {
708         if(mesh->edit_mesh) {
709                 BKE_report(reports, RPT_ERROR, "Can't add edges in edit mode");
710                 return;
711         }
712
713         mesh_add_edges(mesh, count);
714 }
715
716 void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count)
717 {
718         if(mesh->edit_mesh) {
719                 BKE_report(reports, RPT_ERROR, "Can't add vertices in edit mode");
720                 return;
721         }
722
723         mesh_add_verts(mesh, count);
724 }
725
726 void ED_mesh_calc_normals(Mesh *me)
727 {
728         mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
729 }