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