Merge branch 'master' into blender2.8
[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 "MEM_guardedalloc.h"
32
33 #include "BLI_math.h"
34 #include "BLI_alloca.h"
35
36 #include "BKE_DerivedMesh.h"
37 #include "BKE_editmesh.h"
38
39 /* Static function for alloc */
40 static BMFace *bm_face_create_from_mpoly(
41         MPoly *mp, MLoop *ml,
42         BMesh *bm, BMVert **vtable, BMEdge **etable)
43 {
44         BMVert **verts = BLI_array_alloca(verts, mp->totloop);
45         BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
46         int j;
47
48         for (j = 0; j < mp->totloop; j++, ml++) {
49                 verts[j] = vtable[ml->v];
50                 edges[j] = etable[ml->e];
51         }
52
53         return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
54 }
55
56 /**
57  * The main function for copying DerivedMesh data into BMesh.
58  *
59  * \note The mesh may already have geometry. see 'is_init'
60  */
61 void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
62 {
63         MVert *mv, *mvert;
64         MEdge *me, *medge;
65         MPoly *mpoly, *mp;
66         MLoop *mloop;
67         BMVert *v, **vtable;
68         BMEdge *e, **etable;
69         float (*face_normals)[3];
70         BMFace *f;
71         int i, j, totvert, totedge /* , totface */ /* UNUSED */ ;
72         bool is_init = (bm->totvert == 0) && (bm->totedge == 0) && (bm->totface == 0);
73         char has_orig_htype = 0;
74
75         int cd_vert_bweight_offset;
76         int cd_edge_bweight_offset;
77         int cd_edge_crease_offset;
78
79         if (is_init == false) {
80                 /* check if we have an origflag */
81                 has_orig_htype |= CustomData_has_layer(&bm->vdata, CD_ORIGINDEX) ? BM_VERT : 0;
82                 has_orig_htype |= CustomData_has_layer(&bm->edata, CD_ORIGINDEX) ? BM_EDGE : 0;
83                 has_orig_htype |= CustomData_has_layer(&bm->pdata, CD_ORIGINDEX) ? BM_FACE : 0;
84         }
85
86         /*merge custom data layout*/
87         CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT);
88         CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_EDGE);
89         CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_LOOP);
90         CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_FACE);
91
92         if (is_init) {
93                 BM_mesh_cd_flag_apply(bm, dm->cd_flag);
94         }
95
96         cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
97         cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
98         cd_edge_crease_offset  = CustomData_get_offset(&bm->edata, CD_CREASE);
99
100         totvert = dm->getNumVerts(dm);
101         totedge = dm->getNumEdges(dm);
102         /* totface = dm->getNumPolys(dm); */ /* UNUSED */
103
104         vtable = MEM_mallocN(sizeof(*vtable) * totvert, __func__);
105         etable = MEM_mallocN(sizeof(*etable) * totedge, __func__);
106
107         /*do verts*/
108         bool vert_allocated;
109         mv = mvert = DM_get_vert_array(dm, &vert_allocated);;
110         for (i = 0; i < totvert; i++, mv++) {
111                 v = BM_vert_create(bm, mv->co, NULL, BM_CREATE_SKIP_CD);
112                 normal_short_to_float_v3(v->no, mv->no);
113                 v->head.hflag = BM_vert_flag_from_mflag(mv->flag);
114                 BM_elem_index_set(v, i); /* set_inline */
115
116                 CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data, true);
117                 vtable[i] = v;
118
119                 /* add bevel weight */
120                 if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mv->bweight / 255.0f);
121
122                 if (UNLIKELY(has_orig_htype & BM_VERT)) {
123                         int *orig_index = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_ORIGINDEX);
124                         *orig_index = ORIGINDEX_NONE;
125                 }
126         }
127         if (vert_allocated) MEM_freeN(mvert);
128         if (is_init) bm->elem_index_dirty &= ~BM_VERT;
129
130         /*do edges*/
131         bool edge_allocated;
132         me = medge = DM_get_edge_array(dm, &edge_allocated);
133         for (i = 0; i < totedge; i++, me++) {
134                 //BLI_assert(BM_edge_exists(vtable[me->v1], vtable[me->v2]) == NULL);
135                 e = BM_edge_create(bm, vtable[me->v1], vtable[me->v2], NULL, BM_CREATE_SKIP_CD);
136
137                 e->head.hflag = BM_edge_flag_from_mflag(me->flag);
138                 BM_elem_index_set(e, i); /* set_inline */
139
140                 CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data, true);
141                 etable[i] = e;
142
143                 if (cd_edge_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)me->bweight / 255.0f);
144                 if (cd_edge_crease_offset  != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset,  (float)me->crease  / 255.0f);
145
146                 if (UNLIKELY(has_orig_htype & BM_EDGE)) {
147                         int *orig_index = CustomData_bmesh_get(&bm->edata, e->head.data, CD_ORIGINDEX);
148                         *orig_index = ORIGINDEX_NONE;
149                 }
150         }
151         if (edge_allocated) MEM_freeN(medge);
152         if (is_init) bm->elem_index_dirty &= ~BM_EDGE;
153
154         /* do faces */
155         /* note: i_alt is aligned with bmesh faces which may not always align with mpolys */
156         bool poly_allocated, loop_allocated;
157         mpoly = mp = DM_get_poly_array(dm, &poly_allocated);
158         mloop = DM_get_loop_array(dm, &loop_allocated);
159         face_normals = (dm->dirty & DM_DIRTY_NORMALS) ? NULL : CustomData_get_layer(&dm->polyData, CD_NORMAL);
160         for (i = 0; i < dm->numPolyData; i++, mp++) {
161                 BMLoop *l_iter;
162                 BMLoop *l_first;
163
164                 f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart,
165                                               bm, vtable, etable);
166
167                 if (UNLIKELY(f == NULL)) {
168                         continue;
169                 }
170
171                 f->head.hflag = BM_face_flag_from_mflag(mp->flag);
172                 BM_elem_index_set(f, bm->totface - 1); /* set_inline */
173                 f->mat_nr = mp->mat_nr;
174
175                 j = mp->loopstart;
176                 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
177                 do {
178                         /* Save index of correspsonding MLoop */
179                         CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, j, &l_iter->head.data, true);
180                         BM_elem_index_set(l_iter, j++); /* set_inline */
181                 } while ((l_iter = l_iter->next) != l_first);
182
183                 CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, i, &f->head.data, true);
184
185                 if (calc_face_normal) {
186                         if (face_normals) {
187                                 copy_v3_v3(f->no, face_normals[i]);
188                         }
189                         else {
190                                 BM_face_normal_update(f);
191                         }
192                 }
193
194                 if (UNLIKELY(has_orig_htype & BM_FACE)) {
195                         int *orig_index = CustomData_bmesh_get(&bm->pdata, f->head.data, CD_ORIGINDEX);
196                         *orig_index = ORIGINDEX_NONE;
197                 }
198         }
199         if (poly_allocated) MEM_freeN(mpoly);
200         if (loop_allocated) MEM_freeN(mloop);
201         if (is_init) bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
202
203         MEM_freeN(vtable);
204         MEM_freeN(etable);
205 }
206
207 /* converts a cddm to a BMEditMesh.  if existing is non-NULL, the
208  * new geometry will be put in there.*/
209 BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do_tessellate)
210 {
211         BMEditMesh *em = existing;
212         BMesh *bm;
213
214         if (em) {
215                 bm = em->bm;
216         }
217         else {
218                 bm = BM_mesh_create(
219                         &bm_mesh_allocsize_default,
220                         &((struct BMeshCreateParams){.use_toolflags = false,}));
221         }
222
223         DM_to_bmesh_ex(dm, bm, do_tessellate);
224
225         if (!em) {
226                 em = BKE_editmesh_create(bm, do_tessellate);
227         }
228         else {
229                 if (do_tessellate) {
230                         BKE_editmesh_tessface_calc(em);
231                 }
232         }
233
234         return em;
235 }
236
237 BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal)
238 {
239         BMesh *bm;
240         const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm);
241
242         bm = BM_mesh_create(
243                 &allocsize,
244                 &((struct BMeshCreateParams){.use_toolflags = false,}));
245
246         DM_to_bmesh_ex(dm, bm, calc_face_normal);
247
248         return bm;
249 }