Patch #34204: [Render Animation] Fails with "Error: Specified sample_fmt is not suppo...
[blender.git] / source / blender / blenkernel / intern / modifiers_bmesh.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Joseph Eagar
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  */
26
27 /** \file blender/blenkernel/intern/modifiers_bmesh.c
28  *  \ingroup bke
29  */
30
31 #include "BLI_math.h"
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_object_types.h"
36
37 #include "BLI_array.h"
38
39 #include "BKE_DerivedMesh.h"
40 #include "BKE_bmesh.h"
41 #include "BKE_tessmesh.h"
42
43 /**
44  * The main function for copying DerivedMesh data into BMesh.
45  *
46  * \note The mesh may already have geometry. see 'is_init'
47  */
48 void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm)
49 {
50         MVert *mv, *mvert;
51         MEdge *me, *medge;
52         MPoly /* *mpoly, */ /* UNUSED */ *mp;
53         MLoop *mloop, *ml;
54         BMVert *v, **vtable, **verts = NULL;
55         BMEdge *e, **etable, **edges = NULL;
56         float (*face_normals)[3];
57         BMFace *f;
58         BMIter liter;
59         BLI_array_declare(verts);
60         BLI_array_declare(edges);
61         int i, j, k, totvert, totedge /* , totface */ /* UNUSED */ ;
62         bool is_init = (bm->totvert == 0) && (bm->totedge == 0) && (bm->totface == 0);
63         bool is_cddm = (dm->type == DM_TYPE_CDDM);  /* duplicate the arrays for non cddm */
64         char has_orig_hflag = 0;
65
66         int cd_vert_bweight_offset;
67         int cd_edge_bweight_offset;
68         int cd_edge_crease_offset;
69
70         if (is_init == FALSE) {
71                 /* check if we have an origflag */
72                 has_orig_hflag |= CustomData_has_layer(&bm->vdata, CD_ORIGINDEX) ? BM_VERT : 0;
73                 has_orig_hflag |= CustomData_has_layer(&bm->edata, CD_ORIGINDEX) ? BM_EDGE : 0;
74                 has_orig_hflag |= CustomData_has_layer(&bm->pdata, CD_ORIGINDEX) ? BM_FACE : 0;
75         }
76
77         /*merge custom data layout*/
78         CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT);
79         CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_EDGE);
80         CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_LOOP);
81         CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_FACE);
82
83         if (is_init) {
84                 BM_mesh_cd_flag_apply(bm, dm->cd_flag);
85         }
86
87         cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
88         cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
89         cd_edge_crease_offset  = CustomData_get_offset(&bm->edata, CD_CREASE);
90
91         totvert = dm->getNumVerts(dm);
92         totedge = dm->getNumEdges(dm);
93         /* totface = dm->getNumPolys(dm); */ /* UNUSED */
94
95         vtable = MEM_callocN(sizeof(void **) * totvert, __func__);
96         etable = MEM_callocN(sizeof(void **) * totedge, __func__);
97
98         /*do verts*/
99         mv = mvert = is_cddm ? dm->getVertArray(dm) : dm->dupVertArray(dm);
100         for (i = 0; i < totvert; i++, mv++) {
101                 v = BM_vert_create(bm, mv->co, NULL, BM_CREATE_SKIP_CD);
102                 normal_short_to_float_v3(v->no, mv->no);
103                 v->head.hflag = BM_vert_flag_from_mflag(mv->flag);
104                 BM_elem_index_set(v, i); /* set_inline */
105
106                 CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data, true);
107                 vtable[i] = v;
108
109                 /* add bevel weight */
110                 if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mv->bweight / 255.0f);
111
112                 if (UNLIKELY(has_orig_hflag & BM_VERT)) {
113                         int *orig_index = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_ORIGINDEX);
114                         *orig_index = ORIGINDEX_NONE;
115                 }
116         }
117         if (!is_cddm) MEM_freeN(mvert);
118         if (is_init) bm->elem_index_dirty &= ~BM_VERT;
119
120         /*do edges*/
121         me = medge = is_cddm ? dm->getEdgeArray(dm) : dm->dupEdgeArray(dm);
122         for (i = 0; i < totedge; i++, me++) {
123                 //BLI_assert(BM_edge_exists(vtable[me->v1], vtable[me->v2]) == NULL);
124                 e = BM_edge_create(bm, vtable[me->v1], vtable[me->v2], NULL, BM_CREATE_SKIP_CD);
125
126                 e->head.hflag = BM_edge_flag_from_mflag(me->flag);
127                 BM_elem_index_set(e, i); /* set_inline */
128
129                 CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data, true);
130                 etable[i] = e;
131
132                 if (cd_edge_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)me->bweight / 255.0f);
133                 if (cd_edge_crease_offset  != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset,  (float)me->crease  / 255.0f);
134
135                 if (UNLIKELY(has_orig_hflag & BM_EDGE)) {
136                         int *orig_index = CustomData_bmesh_get(&bm->edata, e->head.data, CD_ORIGINDEX);
137                         *orig_index = ORIGINDEX_NONE;
138                 }
139         }
140         if (!is_cddm) MEM_freeN(medge);
141         if (is_init) bm->elem_index_dirty &= ~BM_EDGE;
142
143         /* do faces */
144         /* note: i_alt is aligned with bmesh faces which may not always align with mpolys */
145         mp = dm->getPolyArray(dm);
146         mloop = dm->getLoopArray(dm);
147         face_normals = CustomData_get_layer(&dm->polyData, CD_NORMAL);  /* can be NULL */
148         for (i = 0; i < dm->numPolyData; i++, mp++) {
149                 BMLoop *l;
150
151                 BLI_array_empty(verts);
152                 BLI_array_empty(edges);
153
154                 BLI_array_grow_items(verts, mp->totloop);
155                 BLI_array_grow_items(edges, mp->totloop);
156
157                 ml = mloop + mp->loopstart;
158                 for (j = 0; j < mp->totloop; j++, ml++) {
159
160                         verts[j] = vtable[ml->v];
161                         edges[j] = etable[ml->e];
162                 }
163
164                 f = BM_face_create(bm, verts, edges, mp->totloop, BM_CREATE_SKIP_CD);
165
166                 if (UNLIKELY(f == NULL)) {
167                         continue;
168                 }
169
170                 f->head.hflag = BM_face_flag_from_mflag(mp->flag);
171                 BM_elem_index_set(f, bm->totface - 1); /* set_inline */
172                 f->mat_nr = mp->mat_nr;
173
174                 l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
175
176                 for (k = mp->loopstart; l; l = BM_iter_step(&liter), k++) {
177                         CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, k, &l->head.data, true);
178                 }
179
180                 CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, i, &f->head.data, true);
181
182                 if (face_normals) {
183                         copy_v3_v3(f->no, face_normals[i]);
184                 }
185                 else {
186                         BM_face_normal_update(f);
187                 }
188
189                 if (UNLIKELY(has_orig_hflag & BM_FACE)) {
190                         int *orig_index = CustomData_bmesh_get(&bm->pdata, f->head.data, CD_ORIGINDEX);
191                         *orig_index = ORIGINDEX_NONE;
192                 }
193         }
194         if (is_init) bm->elem_index_dirty &= ~BM_FACE;
195
196         MEM_freeN(vtable);
197         MEM_freeN(etable);
198
199         BLI_array_free(verts);
200         BLI_array_free(edges);
201 }
202
203 /* converts a cddm to a BMEditMesh.  if existing is non-NULL, the
204  * new geometry will be put in there.*/
205 BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, int do_tessellate)
206 {
207         BMEditMesh *em = existing;
208         BMesh *bm;
209
210         if (em) {
211                 bm = em->bm;
212         }
213         else {
214                 bm = BM_mesh_create(&bm_mesh_allocsize_default);
215         }
216
217         DM_to_bmesh_ex(dm, bm);
218
219         if (!em) {
220                 em = BMEdit_Create(bm, do_tessellate);
221         }
222         else {
223                 if (do_tessellate) {
224                         BMEdit_RecalcTessellation(em);
225                 }
226         }
227
228         return em;
229 }
230
231 BMesh *DM_to_bmesh(DerivedMesh *dm)
232 {
233         BMesh *bm;
234
235         bm = BM_mesh_create(&bm_mesh_allocsize_default);
236
237         DM_to_bmesh_ex(dm, bm);
238
239         return bm;
240 }