eb6927cec657b47f44f60bdadfdddbd824c7d615
[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         CustomDataLayer *cdl;
200         int index;
201
202         index= CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
203         cdl= (index == -1)? NULL: &me->fdata.layers[index];
204
205         if(!cdl)
206                 return 0;
207
208         delete_customdata_layer(C, ob, cdl);
209         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
210         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
211
212         return 1;
213 }
214
215 int ED_mesh_color_add(bContext *C, Scene *scene, Object *ob, Mesh *me)
216 {
217         EditMesh *em;
218         MCol *mcol;
219         int layernum;
220
221         if(me->edit_mesh) {
222                 em= me->edit_mesh;
223
224                 layernum= CustomData_number_of_layers(&em->fdata, CD_MCOL);
225                 if(layernum >= MAX_MCOL)
226                         return 0;
227
228                 EM_add_data_layer(em, &em->fdata, CD_MCOL);
229                 CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum);
230         }
231         else {
232                 layernum= CustomData_number_of_layers(&me->fdata, CD_MCOL);
233                 if(layernum >= MAX_MCOL)
234                         return 0;
235
236                 mcol= me->mcol;
237
238                 if(me->mcol)
239                         CustomData_add_layer(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface);
240                 else
241                         CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface);
242
243                 CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);
244                 mesh_update_customdata_pointers(me);
245
246                 if(!mcol)
247                         shadeMeshMCol(scene, ob, me);
248         }
249
250         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
251         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
252
253         return 1;
254 }
255
256 int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me)
257 {
258         CustomDataLayer *cdl;
259         int index;
260
261         index= CustomData_get_active_layer_index(&me->fdata, CD_MCOL);
262         cdl= (index == -1)? NULL: &me->fdata.layers[index];
263
264         if(!cdl)
265                 return 0;
266
267         delete_customdata_layer(C, ob, cdl);
268         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
269         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
270
271         return 1;
272 }
273
274 /*********************** UV texture operators ************************/
275
276 static int layers_poll(bContext *C)
277 {
278         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
279         ID *data= (ob)? ob->data: NULL;
280         return (ob && !ob->id.lib && ob->type==OB_MESH && data && !data->lib);
281 }
282
283 static int uv_texture_add_exec(bContext *C, wmOperator *op)
284 {
285         Scene *scene= CTX_data_scene(C);
286         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
287         Mesh *me= ob->data;
288
289         if(!ED_mesh_uv_texture_add(C, scene, ob, me))
290                 return OPERATOR_CANCELLED;
291
292         return OPERATOR_FINISHED;
293 }
294
295 void MESH_OT_uv_texture_add(wmOperatorType *ot)
296 {
297         /* identifiers */
298         ot->name= "Add UV Texture";
299         ot->description= "Add UV texture layer.";
300         ot->idname= "MESH_OT_uv_texture_add";
301         
302         /* api callbacks */
303         ot->poll= layers_poll;
304         ot->exec= uv_texture_add_exec;
305
306         /* flags */
307         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
308 }
309
310 static int uv_texture_remove_exec(bContext *C, wmOperator *op)
311 {
312         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
313         Mesh *me= ob->data;
314
315         if(!ED_mesh_uv_texture_remove(C, ob, me))
316                 return OPERATOR_CANCELLED;
317
318         return OPERATOR_FINISHED;
319 }
320
321 void MESH_OT_uv_texture_remove(wmOperatorType *ot)
322 {
323         /* identifiers */
324         ot->name= "Remove UV Texture";
325         ot->description= "Remove UV texture layer.";
326         ot->idname= "MESH_OT_uv_texture_remove";
327         
328         /* api callbacks */
329         ot->poll= layers_poll;
330         ot->exec= uv_texture_remove_exec;
331
332         /* flags */
333         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
334 }
335
336 /*********************** vertex color operators ************************/
337
338 static int vertex_color_add_exec(bContext *C, wmOperator *op)
339 {
340         Scene *scene= CTX_data_scene(C);
341         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
342         Mesh *me= ob->data;
343
344         if(!ED_mesh_color_add(C, scene, ob, me))
345                 return OPERATOR_CANCELLED;
346
347         return OPERATOR_FINISHED;
348 }
349
350 void MESH_OT_vertex_color_add(wmOperatorType *ot)
351 {
352         /* identifiers */
353         ot->name= "Add Vertex Color";
354         ot->description= "Add vertex color layer.";
355         ot->idname= "MESH_OT_vertex_color_add";
356         
357         /* api callbacks */
358         ot->poll= layers_poll;
359         ot->exec= vertex_color_add_exec;
360
361         /* flags */
362         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
363 }
364
365 static int vertex_color_remove_exec(bContext *C, wmOperator *op)
366 {
367         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
368         Mesh *me= ob->data;
369
370         if(!ED_mesh_color_remove(C, ob, me))
371                 return OPERATOR_CANCELLED;
372
373         return OPERATOR_FINISHED;
374 }
375
376 void MESH_OT_vertex_color_remove(wmOperatorType *ot)
377 {
378         /* identifiers */
379         ot->name= "Remove Vertex Color";
380         ot->description= "Remove vertex color layer.";
381         ot->idname= "MESH_OT_vertex_color_remove";
382         
383         /* api callbacks */
384         ot->exec= vertex_color_remove_exec;
385         ot->poll= layers_poll;
386
387         /* flags */
388         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
389 }
390
391 /*********************** sticky operators ************************/
392
393 static int sticky_add_exec(bContext *C, wmOperator *op)
394 {
395         Scene *scene= CTX_data_scene(C);
396         View3D *v3d= CTX_wm_view3d(C);
397         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
398         Mesh *me= ob->data;
399
400         /*if(me->msticky)
401                 return OPERATOR_CANCELLED;*/
402
403         RE_make_sticky(scene, v3d);
404
405         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
406         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
407
408         return OPERATOR_FINISHED;
409 }
410
411 void MESH_OT_sticky_add(wmOperatorType *ot)
412 {
413         /* identifiers */
414         ot->name= "Add Sticky";
415         ot->description= "Add sticky UV texture layer.";
416         ot->idname= "MESH_OT_sticky_add";
417         
418         /* api callbacks */
419         ot->poll= layers_poll;
420         ot->exec= sticky_add_exec;
421
422         /* flags */
423         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
424 }
425
426 static int sticky_remove_exec(bContext *C, wmOperator *op)
427 {
428         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
429         Mesh *me= ob->data;
430
431         if(!me->msticky)
432                 return OPERATOR_CANCELLED;
433
434         CustomData_free_layer_active(&me->vdata, CD_MSTICKY, me->totvert);
435         me->msticky= NULL;
436
437         DAG_id_flush_update(&me->id, OB_RECALC_DATA);
438         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
439
440         return OPERATOR_FINISHED;
441 }
442
443 void MESH_OT_sticky_remove(wmOperatorType *ot)
444 {
445         /* identifiers */
446         ot->name= "Remove Sticky";
447         ot->description= "Remove sticky UV texture layer.";
448         ot->idname= "MESH_OT_sticky_remove";
449         
450         /* api callbacks */
451         ot->poll= layers_poll;
452         ot->exec= sticky_remove_exec;
453
454         /* flags */
455         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
456 }
457
458 /************************** Add Geometry Layers *************************/
459
460 static void mesh_calc_edges(Mesh *mesh, int update)
461 {
462         CustomData edata;
463         EdgeHashIterator *ehi;
464         MFace *mf = mesh->mface;
465         MEdge *med, *med_orig;
466         EdgeHash *eh = BLI_edgehash_new();
467         int i, *index, totedge, totface = mesh->totface;
468
469         if(mesh->totedge==0)
470                 update= 0;
471
472         if(update) {
473                 /* assume existing edges are valid
474                  * useful when adding more faces and generating edges from them */
475                 med= mesh->medge;
476                 for(i= 0; i<mesh->totedge; i++, med++)
477                         BLI_edgehash_insert(eh, med->v1, med->v2, med);
478         }
479
480         for (i = 0; i < totface; i++, mf++) {
481                 if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
482                         BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
483                 if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
484                         BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
485                 
486                 if (mf->v4) {
487                         if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
488                                 BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
489                         if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
490                                 BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
491                 } else {
492                         if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
493                                 BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
494                 }
495         }
496
497         totedge = BLI_edgehash_size(eh);
498
499         /* write new edges into a temporary CustomData */
500         memset(&edata, 0, sizeof(edata));
501         CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
502
503         ehi = BLI_edgehashIterator_new(eh);
504         med = CustomData_get_layer(&edata, CD_MEDGE);
505         for(i = 0; !BLI_edgehashIterator_isDone(ehi);
506             BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) {
507
508                 if(update && (med_orig=BLI_edgehashIterator_getValue(ehi))) {
509                         *med= *med_orig; /* copy from the original */
510                 } else {
511                         BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
512                         med->flag = ME_EDGEDRAW|ME_EDGERENDER;
513                 }
514         }
515         BLI_edgehashIterator_free(ehi);
516
517         /* free old CustomData and assign new one */
518         CustomData_free(&mesh->edata, mesh->totedge);
519         mesh->edata = edata;
520         mesh->totedge = totedge;
521
522         mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
523
524         BLI_edgehash_free(eh, NULL);
525 }
526
527 void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges)
528 {
529         if(calc_edges || (mesh->totface && mesh->totedge == 0))
530                 mesh_calc_edges(mesh, calc_edges);
531
532         mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL);
533
534         DAG_id_flush_update(&mesh->id, OB_RECALC_DATA);
535         WM_event_add_notifier(C, NC_GEOM|ND_DATA, mesh);
536 }
537
538 static void mesh_add_verts(Mesh *mesh, int len)
539 {
540         CustomData vdata;
541         MVert *mvert;
542         int i, totvert;
543
544         if(len == 0)
545                 return;
546
547         totvert= mesh->totvert + len;
548         CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
549         CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
550
551         if(!CustomData_has_layer(&vdata, CD_MVERT))
552                 CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
553
554         CustomData_free(&mesh->vdata, mesh->totvert);
555         mesh->vdata= vdata;
556         mesh_update_customdata_pointers(mesh);
557
558         /* scan the input list and insert the new vertices */
559
560         mvert= &mesh->mvert[mesh->totvert];
561         for(i=0; i<len; i++, mvert++)
562                 mvert->flag |= SELECT;
563
564         /* set final vertex list size */
565         mesh->totvert= totvert;
566 }
567
568 void ED_mesh_transform(Mesh *me, float *mat)
569 {
570         int i;
571         MVert *mvert= me->mvert;
572
573         for(i= 0; i < me->totvert; i++, mvert++)
574                 mul_m4_v3((float (*)[4])mat, mvert->co);
575
576         mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
577 }
578
579 static void mesh_add_edges(Mesh *mesh, int len)
580 {
581         CustomData edata;
582         MEdge *medge;
583         int i, totedge;
584
585         if(len == 0)
586                 return;
587
588         totedge= mesh->totedge+len;
589
590         /* update customdata  */
591         CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
592         CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
593
594         if(!CustomData_has_layer(&edata, CD_MEDGE))
595                 CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
596
597         CustomData_free(&mesh->edata, mesh->totedge);
598         mesh->edata= edata;
599         mesh_update_customdata_pointers(mesh);
600
601         /* set default flags */
602         medge= &mesh->medge[mesh->totedge];
603         for(i=0; i<len; i++, medge++)
604                 medge->flag= ME_EDGEDRAW|ME_EDGERENDER|SELECT;
605
606         mesh->totedge= totedge;
607 }
608
609 static void mesh_add_faces(Mesh *mesh, int len)
610 {
611         CustomData fdata;
612         MFace *mface;
613         int i, totface;
614
615         if(len == 0)
616                 return;
617
618         totface= mesh->totface + len;   /* new face count */
619
620         /* update customdata */
621         CustomData_copy(&mesh->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
622         CustomData_copy_data(&mesh->fdata, &fdata, 0, 0, mesh->totface);
623
624         if(!CustomData_has_layer(&fdata, CD_MFACE))
625                 CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
626
627         CustomData_free(&mesh->fdata, mesh->totface);
628         mesh->fdata= fdata;
629         mesh_update_customdata_pointers(mesh);
630
631         /* set default flags */
632         mface= &mesh->mface[mesh->totface];
633         for(i=0; i<len; i++, mface++)
634                 mface->flag= SELECT;
635
636         mesh->totface= totface;
637 }
638
639 void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces)
640 {
641         if(mesh->edit_mesh) {
642                 BKE_report(reports, RPT_ERROR, "Can't add geometry in edit mode.");
643                 return;
644         }
645
646         if(verts)
647                 mesh_add_verts(mesh, verts);
648         if(edges)
649                 mesh_add_edges(mesh, edges);
650         if(faces)
651                 mesh_add_faces(mesh, faces);
652 }
653
654 void ED_mesh_calc_normals(Mesh *me)
655 {
656         mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
657 }
658
659 void ED_mesh_material_add(Mesh *me, Material *ma)
660 {
661         int i;
662         int totcol = me->totcol + 1;
663         Material **mat;
664
665         /* don't add if mesh already has it */
666         for(i = 0; i < me->totcol; i++)
667                 if(me->mat[i] == ma)
668                         return;
669
670         mat= MEM_callocN(sizeof(void*)*totcol, "newmatar");
671
672         if(me->totcol) memcpy(mat, me->mat, sizeof(void*) * me->totcol);
673         if(me->mat) MEM_freeN(me->mat);
674
675         me->mat = mat;
676         me->mat[me->totcol++] = ma;
677         ma->id.us++;
678
679         test_object_materials((ID*)me);
680 }
681