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