merge with trunk/2.5 at r24463
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_customdata_types.h"
36 #include "DNA_material_types.h"
37 #include "DNA_mesh_types.h"
38 #include "DNA_meshdata_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_view3d_types.h"
42 #include "DNA_windowmanager_types.h"
43
44 #include "BKE_context.h"
45 #include "BKE_customdata.h"
46 #include "BKE_depsgraph.h"
47 #include "BKE_displist.h"
48 #include "BKE_global.h"
49 #include "BKE_material.h"
50 #include "BKE_mesh.h"
51 #include "BKE_report.h"
52 #include "BKE_tessmesh.h"
53
54 #include "BLI_arithb.h"
55 #include "BLI_editVert.h"
56 #include "BLI_edgehash.h"
57
58 #include "RNA_access.h"
59 #include "RNA_define.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64 #include "ED_mesh.h"
65 #include "ED_object.h"
66 #include "ED_view3d.h"
67
68 #include "RE_render_ext.h"
69
70 #include "mesh_intern.h"
71
72 static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *layer)
73 {
74         Mesh *me = ob->data;
75         CustomData *data= (me->edit_btmesh)? &me->edit_btmesh->bm->pdata: &me->pdata;
76         void *actlayerdata, *rndlayerdata, *clonelayerdata, *masklayerdata, *layerdata=layer->data;
77         int type= layer->type;
78         int index= CustomData_get_layer_index(data, type);
79         int i, actindex, rndindex, cloneindex, maskindex, tot = me->totpoly;
80         
81         if (layer->type == CD_MLOOPCOL) {
82                 data = (me->edit_btmesh)? &me->edit_btmesh->bm->ldata: &me->ldata;
83                 tot = me->totloop;
84         }
85
86         /* ok, deleting a non-active layer needs to preserve the active layer indices.
87           to do this, we store a pointer to the .data member of both layer and the active layer,
88           (to detect if we're deleting the active layer or not), then use the active
89           layer data pointer to find where the active layer has ended up.
90           
91           this is necassary because the deletion functions only support deleting the active
92           layer. */
93         actlayerdata = data->layers[CustomData_get_active_layer_index(data, type)].data;
94         rndlayerdata = data->layers[CustomData_get_render_layer_index(data, type)].data;
95         clonelayerdata = data->layers[CustomData_get_clone_layer_index(data, type)].data;
96         masklayerdata = data->layers[CustomData_get_mask_layer_index(data, type)].data;
97         CustomData_set_layer_active(data, type, layer - &data->layers[index]);
98
99         if(me->edit_btmesh) {
100                 BM_free_data_layer(me->edit_btmesh->bm, data, type);
101         }
102         else {
103                 CustomData_free_layer_active(data, type, tot);
104                 mesh_update_customdata_pointers(me);
105         }
106
107         if(!CustomData_has_layer(data, type) && (type == CD_MLOOPCOL && (ob->mode & OB_MODE_VERTEX_PAINT)))
108                 ED_object_toggle_modes(C, OB_MODE_VERTEX_PAINT);
109
110         /* reconstruct active layer */
111         if (actlayerdata != layerdata) {
112                 /* find index */
113                 actindex = CustomData_get_layer_index(data, type);
114                 for (i=actindex; i<data->totlayer; i++) {
115                         if (data->layers[i].data == actlayerdata) {
116                                 actindex = i - actindex;
117                                 break;
118                         }
119                 }
120                 
121                 /* set index */
122                 CustomData_set_layer_active(data, type, actindex);
123         }
124         
125         if (rndlayerdata != layerdata) {
126                 /* find index */
127                 rndindex = CustomData_get_layer_index(data, type);
128                 for (i=rndindex; i<data->totlayer; i++) {
129                         if (data->layers[i].data == rndlayerdata) {
130                                 rndindex = i - rndindex;
131                                 break;
132                         }
133                 }
134                 
135                 /* set index */
136                 CustomData_set_layer_render(data, type, rndindex);
137         }
138         
139         if (clonelayerdata != layerdata) {
140                 /* find index */
141                 cloneindex = CustomData_get_layer_index(data, type);
142                 for (i=cloneindex; i<data->totlayer; i++) {
143                         if (data->layers[i].data == clonelayerdata) {
144                                 cloneindex = i - cloneindex;
145                                 break;
146                         }
147                 }
148                 
149                 /* set index */
150                 CustomData_set_layer_clone(data, type, cloneindex);
151         }
152         
153         if (masklayerdata != layerdata) {
154                 /* find index */
155                 maskindex = CustomData_get_layer_index(data, type);
156                 for (i=maskindex; i<data->totlayer; i++) {
157                         if (data->layers[i].data == masklayerdata) {
158                                 maskindex = i - maskindex;
159                                 break;
160                         }
161                 }
162                 
163                 /* set index */
164                 CustomData_set_layer_mask(data, type, maskindex);
165         }
166 }
167
168 int ED_mesh_uv_texture_add(bContext *C, Scene *scene, Object *ob, Mesh *me)
169 {
170         BMEditMesh *em;
171         int layernum;
172
173         if(me->edit_btmesh) {
174                 em= me->edit_btmesh;
175
176                 layernum= CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
177                 if(layernum >= MAX_MTFACE)
178                         return OPERATOR_CANCELLED;
179
180                 BM_add_data_layer(em->bm, &em->bm->pdata, MAX_MTFACE);
181                 CustomData_set_layer_active(&em->bm->pdata, MAX_MTFACE, layernum);
182         }
183         else {
184                 layernum= CustomData_number_of_layers(&me->pdata, MAX_MTFACE);
185                 if(layernum >= MAX_MTFACE)
186                         return OPERATOR_CANCELLED;
187
188                 if(me->mtface)
189                         CustomData_add_layer(&me->pdata, MAX_MTFACE, CD_DUPLICATE, me->mtpoly, me->totpoly);
190                 else
191                         CustomData_add_layer(&me->pdata, MAX_MTFACE, CD_DEFAULT, NULL, me->totpoly);
192
193                 CustomData_set_layer_active(&me->pdata, MAX_MTFACE, layernum);
194                 mesh_update_customdata_pointers(me);
195         }
196
197         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
198         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
199
200         return 1;
201 }
202
203 int ED_mesh_uv_texture_remove(bContext *C, Object *ob, Mesh *me)
204 {
205         CustomDataLayer *cdl;
206         int index;
207
208         index= CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
209         cdl= (index == -1)? NULL: &me->pdata.layers[index];
210
211         if(!cdl)
212                 return 0;
213
214         delete_customdata_layer(C, ob, cdl);
215         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
216         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
217
218         return 1;
219 }
220
221 int ED_mesh_color_add(bContext *C, Scene *scene, Object *ob, Mesh *me)
222 {
223         BMEditMesh *em;
224         MLoopCol *mcol;
225         int layernum;
226
227         if(me->edit_btmesh) {
228                 em= me->edit_btmesh;
229
230                 layernum= CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
231                 if(layernum >= MAX_MCOL)
232                         return 0;
233
234                 BM_add_data_layer(em->bm, &em->bm->pdata, CD_MLOOPCOL);
235                 CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
236         }
237         else {
238                 layernum= CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
239                 if(layernum >= CD_MLOOPCOL)
240                         return 0;
241
242                 mcol= me->mloopcol;
243
244                 if(me->mloopcol)
245                         CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop);
246                 else
247                         CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
248
249                 CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum);
250                 mesh_update_customdata_pointers(me);
251
252                 /*BMESH_TODO
253                 if(!mcol)
254                         shadeMeshMCol(scene, ob, me);
255                 */
256         }
257
258         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
259         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
260
261         return 1;
262 }
263
264 int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me)
265 {
266         CustomDataLayer *cdl;
267         int index;
268
269         index= CustomData_get_active_layer_index(&me->pdata, CD_MLOOPCOL);
270         cdl= (index == -1)? NULL: &me->pdata.layers[index];
271
272         if(!cdl)
273                 return 0;
274
275         delete_customdata_layer(C, ob, cdl);
276         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
277         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
278
279         return 1;
280 }
281
282 /*********************** UV texture operators ************************/
283
284 static int layers_poll(bContext *C)
285 {
286         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
287         ID *data= (ob)? ob->data: NULL;
288         return (ob && !ob->id.lib && ob->type==OB_MESH && data && !data->lib);
289 }
290
291 static int uv_texture_add_exec(bContext *C, wmOperator *op)
292 {
293         Scene *scene= CTX_data_scene(C);
294         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
295         Mesh *me= ob->data;
296
297         if(!ED_mesh_uv_texture_add(C, scene, ob, me))
298                 return OPERATOR_CANCELLED;
299
300         return OPERATOR_FINISHED;
301 }
302
303 void MESH_OT_uv_texture_add(wmOperatorType *ot)
304 {
305         /* identifiers */
306         ot->name= "Add UV Texture";
307         ot->description= "Add UV texture layer.";
308         ot->idname= "MESH_OT_uv_texture_add";
309         
310         /* api callbacks */
311         ot->poll= layers_poll;
312         ot->exec= uv_texture_add_exec;
313
314         /* flags */
315         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
316 }
317
318 static int uv_texture_remove_exec(bContext *C, wmOperator *op)
319 {
320         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
321         Mesh *me= ob->data;
322
323         if(!ED_mesh_uv_texture_remove(C, ob, me))
324                 return OPERATOR_CANCELLED;
325
326         return OPERATOR_FINISHED;
327 }
328
329 void MESH_OT_uv_texture_remove(wmOperatorType *ot)
330 {
331         /* identifiers */
332         ot->name= "Remove UV Texture";
333         ot->description= "Remove UV texture layer.";
334         ot->idname= "MESH_OT_uv_texture_remove";
335         
336         /* api callbacks */
337         ot->poll= layers_poll;
338         ot->exec= uv_texture_remove_exec;
339
340         /* flags */
341         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
342 }
343
344 /*********************** vertex color operators ************************/
345
346 static int vertex_color_add_exec(bContext *C, wmOperator *op)
347 {
348         Scene *scene= CTX_data_scene(C);
349         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
350         Mesh *me= ob->data;
351
352         if(!ED_mesh_color_add(C, scene, ob, me))
353                 return OPERATOR_CANCELLED;
354
355         return OPERATOR_FINISHED;
356 }
357
358 void MESH_OT_vertex_color_add(wmOperatorType *ot)
359 {
360         /* identifiers */
361         ot->name= "Add Vertex Color";
362         ot->description= "Add vertex color layer.";
363         ot->idname= "MESH_OT_vertex_color_add";
364         
365         /* api callbacks */
366         ot->poll= layers_poll;
367         ot->exec= vertex_color_add_exec;
368
369         /* flags */
370         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
371 }
372
373 static int vertex_color_remove_exec(bContext *C, wmOperator *op)
374 {
375         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
376         Mesh *me= ob->data;
377
378         if(!ED_mesh_color_remove(C, ob, me))
379                 return OPERATOR_CANCELLED;
380
381         return OPERATOR_FINISHED;
382 }
383
384 void MESH_OT_vertex_color_remove(wmOperatorType *ot)
385 {
386         /* identifiers */
387         ot->name= "Remove Vertex Color";
388         ot->description= "Remove vertex color layer.";
389         ot->idname= "MESH_OT_vertex_color_remove";
390         
391         /* api callbacks */
392         ot->exec= vertex_color_remove_exec;
393         ot->poll= layers_poll;
394
395         /* flags */
396         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
397 }
398
399 /*********************** sticky operators ************************/
400
401 static int sticky_add_exec(bContext *C, wmOperator *op)
402 {
403         Scene *scene= CTX_data_scene(C);
404         View3D *v3d= CTX_wm_view3d(C);
405         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
406         Mesh *me= ob->data;
407
408         /*if(me->msticky)
409                 return OPERATOR_CANCELLED;*/
410
411         RE_make_sticky(scene, v3d);
412
413         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
414         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
415
416         return OPERATOR_FINISHED;
417 }
418
419 void MESH_OT_sticky_add(wmOperatorType *ot)
420 {
421         /* identifiers */
422         ot->name= "Add Sticky";
423         ot->description= "Add sticky UV texture layer.";
424         ot->idname= "MESH_OT_sticky_add";
425         
426         /* api callbacks */
427         ot->poll= layers_poll;
428         ot->exec= sticky_add_exec;
429
430         /* flags */
431         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
432 }
433
434 static int sticky_remove_exec(bContext *C, wmOperator *op)
435 {
436         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
437         Mesh *me= ob->data;
438
439         if(!me->msticky)
440                 return OPERATOR_CANCELLED;
441
442         CustomData_free_layer_active(&me->vdata, CD_MSTICKY, me->totvert);
443         me->msticky= NULL;
444
445         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
446         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
447
448         return OPERATOR_FINISHED;
449 }
450
451 void MESH_OT_sticky_remove(wmOperatorType *ot)
452 {
453         /* identifiers */
454         ot->name= "Remove Sticky";
455         ot->description= "Remove sticky UV texture layer.";
456         ot->idname= "MESH_OT_sticky_remove";
457         
458         /* api callbacks */
459         ot->poll= layers_poll;
460         ot->exec= sticky_remove_exec;
461
462         /* flags */
463         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
464 }
465
466 /************************** Add Geometry Layers *************************/
467
468 static void mesh_calc_edges(Mesh *mesh, int update)
469 {
470         CustomData edata;
471         EdgeHashIterator *ehi;
472         MFace *mf = mesh->mface;
473         MEdge *med, *med_orig;
474         EdgeHash *eh = BLI_edgehash_new();
475         int i, *index, totedge, totface = mesh->totface;
476
477         if(mesh->totedge==0)
478                 update= 0;
479
480         if(update) {
481                 /* assume existing edges are valid
482                  * useful when adding more faces and generating edges from them */
483                 med= mesh->medge;
484                 for(i= 0; i<mesh->totedge; i++, med++)
485                         BLI_edgehash_insert(eh, med->v1, med->v2, med);
486         }
487
488         for (i = 0; i < totface; i++, mf++) {
489                 if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
490                         BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
491                 if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
492                         BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
493                 
494                 if (mf->v4) {
495                         if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
496                                 BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
497                         if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
498                                 BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
499                 } else {
500                         if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
501                                 BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
502                 }
503         }
504
505         totedge = BLI_edgehash_size(eh);
506
507         /* write new edges into a temporary CustomData */
508         memset(&edata, 0, sizeof(edata));
509         CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
510
511         ehi = BLI_edgehashIterator_new(eh);
512         med = CustomData_get_layer(&edata, CD_MEDGE);
513         for(i = 0; !BLI_edgehashIterator_isDone(ehi);
514             BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) {
515
516                 if(update && (med_orig=BLI_edgehashIterator_getValue(ehi))) {
517                         *med= *med_orig; /* copy from the original */
518                 } else {
519                 BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
520                 med->flag = ME_EDGEDRAW|ME_EDGERENDER;
521         }
522         }
523         BLI_edgehashIterator_free(ehi);
524
525         /* free old CustomData and assign new one */
526         CustomData_free(&mesh->edata, mesh->totedge);
527         mesh->edata = edata;
528         mesh->totedge = totedge;
529
530         mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
531
532         BLI_edgehash_free(eh, NULL);
533 }
534
535 void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges)
536 {
537         if(calc_edges || (mesh->totface && mesh->totedge == 0))
538                 mesh_calc_edges(mesh, calc_edges);
539
540         mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL);
541
542         DAG_id_flush_update(&mesh->id, OB_RECALC_DATA);
543         WM_event_add_notifier(C, NC_GEOM|ND_DATA, mesh);
544 }
545
546 static void mesh_add_verts(Mesh *mesh, int len)
547 {
548         CustomData vdata;
549         MVert *mvert;
550         int i, totvert;
551
552         if(len == 0)
553                 return;
554
555         totvert= mesh->totvert + len;
556         CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
557         CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
558
559         if(!CustomData_has_layer(&vdata, CD_MVERT))
560                 CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
561
562         CustomData_free(&mesh->vdata, mesh->totvert);
563         mesh->vdata= vdata;
564         mesh_update_customdata_pointers(mesh);
565
566         /* scan the input list and insert the new vertices */
567
568         mvert= &mesh->mvert[mesh->totvert];
569         for(i=0; i<len; i++, mvert++)
570                 mvert->flag |= SELECT;
571
572         /* set final vertex list size */
573         mesh->totvert= totvert;
574 }
575
576 void ED_mesh_transform(Mesh *me, float *mat)
577 {
578         int i;
579         MVert *mvert= me->mvert;
580
581         for(i= 0; i < me->totvert; i++, mvert++)
582                 Mat4MulVecfl((float (*)[4])mat, mvert->co);
583
584         mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
585 }
586
587 static void mesh_add_edges(Mesh *mesh, int len)
588 {
589         CustomData edata;
590         MEdge *medge;
591         int i, totedge;
592
593         if(len == 0)
594                 return;
595
596         totedge= mesh->totedge+len;
597
598         /* update customdata  */
599         CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
600         CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
601
602         if(!CustomData_has_layer(&edata, CD_MEDGE))
603                 CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
604
605         CustomData_free(&mesh->edata, mesh->totedge);
606         mesh->edata= edata;
607         mesh_update_customdata_pointers(mesh);
608
609         /* set default flags */
610         medge= &mesh->medge[mesh->totedge];
611         for(i=0; i<len; i++, medge++)
612                 medge->flag= ME_EDGEDRAW|ME_EDGERENDER|SELECT;
613
614         mesh->totedge= totedge;
615 }
616
617 static void mesh_add_faces(Mesh *mesh, int len)
618 {
619         CustomData fdata;
620         MFace *mface;
621         int i, totface;
622
623         if(len == 0)
624                 return;
625
626         totface= mesh->totface + len;   /* new face count */
627
628         /* update customdata */
629         CustomData_copy(&mesh->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
630         CustomData_copy_data(&mesh->fdata, &fdata, 0, 0, mesh->totface);
631
632         if(!CustomData_has_layer(&fdata, CD_MFACE))
633                 CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
634
635         CustomData_free(&mesh->fdata, mesh->totface);
636         mesh->fdata= fdata;
637         mesh_update_customdata_pointers(mesh);
638
639         /* set default flags */
640         mface= &mesh->mface[mesh->totface];
641         for(i=0; i<len; i++, mface++)
642                 mface->flag= SELECT;
643
644         mesh->totface= totface;
645 }
646
647 void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces)
648 {
649         if(mesh->edit_btmesh) {
650                 BKE_report(reports, RPT_ERROR, "Can't add geometry in edit mode.");
651                 return;
652         }
653
654         if(verts)
655                 mesh_add_verts(mesh, verts);
656         if(edges)
657                 mesh_add_edges(mesh, edges);
658         if(faces)
659                 mesh_add_faces(mesh, faces);
660 }
661
662 void ED_mesh_calc_normals(Mesh *me)
663 {
664         mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
665 }
666
667 void ED_mesh_material_add(Mesh *me, Material *ma)
668 {
669         int i;
670         int totcol = me->totcol + 1;
671         Material **mat;
672
673         /* don't add if mesh already has it */
674         for(i = 0; i < me->totcol; i++)
675                 if(me->mat[i] == ma)
676                         return;
677
678         mat= MEM_callocN(sizeof(void*)*totcol, "newmatar");
679
680         if(me->totcol) memcpy(mat, me->mat, sizeof(void*) * me->totcol);
681         if(me->mat) MEM_freeN(me->mat);
682
683         me->mat = mat;
684         me->mat[me->totcol++] = ma;
685         ma->id.us++;
686
687         test_object_materials((ID*)me);
688 }
689