1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2006 Blender Foundation.
17 * All rights reserved.
18 * Implementation of CDDerivedMesh.
19 *
20 * BKE_cdderivedmesh.h contains the function prototypes for this file.
21 */
22
23 /** \file
24 * \ingroup bke
25 */
26
27 #include "atomic_ops.h"
28
29 #include "BLI_math.h"
30 #include "BLI_utildefines.h"
31
32 #include "BKE_DerivedMesh.h"
33 #include "BKE_cdderivedmesh.h"
34 #include "BKE_curve.h"
35 #include "BKE_editmesh.h"
36 #include "BKE_mesh.h"
37 #include "BKE_mesh_mapping.h"
38 #include "BKE_object.h"
39 #include "BKE_paint.h"
40 #include "BKE_pbvh.h"
41
42 #include "DNA_curve_types.h" /* for Curve */
43 #include "DNA_mesh_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_object_types.h"
46
47 #include "MEM_guardedalloc.h"
48
49 #include <limits.h>
50 #include <math.h>
51 #include <string.h>
52
53 typedef struct {
54 DerivedMesh dm;
55
56 /* these point to data in the DerivedMesh custom data layers,
57 * they are only here for efficiency and convenience */
58 MVert *mvert;
59 MEdge *medge;
60 MFace *mface;
61 MLoop *mloop;
62 MPoly *mpoly;
63
64 /* Cached */
65 struct PBVH *pbvh;
66 bool pbvh_draw;
67
68 /* Mesh connectivity */
69 MeshElemMap *pmap;
70 int *pmap_mem;
71 } CDDerivedMesh;
72
73 /**************** DerivedMesh interface functions ****************/
cdDM_getNumVerts(DerivedMesh * dm)74 static int cdDM_getNumVerts(DerivedMesh *dm)
75 {
76 return dm->numVertData;
77 }
78
cdDM_getNumEdges(DerivedMesh * dm)79 static int cdDM_getNumEdges(DerivedMesh *dm)
80 {
81 return dm->numEdgeData;
82 }
83
cdDM_getNumTessFaces(DerivedMesh * dm)84 static int cdDM_getNumTessFaces(DerivedMesh *dm)
85 {
86 /* uncomment and add a breakpoint on the printf()
87 * to help debug tessfaces issues since BMESH merge. */
88 #if 0
89 if (dm->numTessFaceData == 0 && dm->numPolyData != 0) {
90 printf("%s: has no faces!\n");
91 }
92 #endif
93 return dm->numTessFaceData;
94 }
95
cdDM_getNumLoops(DerivedMesh * dm)96 static int cdDM_getNumLoops(DerivedMesh *dm)
97 {
98 return dm->numLoopData;
99 }
100
cdDM_getNumPolys(DerivedMesh * dm)101 static int cdDM_getNumPolys(DerivedMesh *dm)
102 {
103 return dm->numPolyData;
104 }
105
cdDM_getVert(DerivedMesh * dm,int index,MVert * r_vert)106 static void cdDM_getVert(DerivedMesh *dm, int index, MVert *r_vert)
107 {
108 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
109 *r_vert = cddm->mvert[index];
110 }
111
cdDM_getEdge(DerivedMesh * dm,int index,MEdge * r_edge)112 static void cdDM_getEdge(DerivedMesh *dm, int index, MEdge *r_edge)
113 {
114 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
115 *r_edge = cddm->medge[index];
116 }
117
cdDM_getTessFace(DerivedMesh * dm,int index,MFace * r_face)118 static void cdDM_getTessFace(DerivedMesh *dm, int index, MFace *r_face)
119 {
120 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
121 *r_face = cddm->mface[index];
122 }
123
cdDM_copyVertArray(DerivedMesh * dm,MVert * r_vert)124 static void cdDM_copyVertArray(DerivedMesh *dm, MVert *r_vert)
125 {
126 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
127 memcpy(r_vert, cddm->mvert, sizeof(*r_vert) * dm->numVertData);
128 }
129
cdDM_copyEdgeArray(DerivedMesh * dm,MEdge * r_edge)130 static void cdDM_copyEdgeArray(DerivedMesh *dm, MEdge *r_edge)
131 {
132 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
133 memcpy(r_edge, cddm->medge, sizeof(*r_edge) * dm->numEdgeData);
134 }
135
cdDM_copyTessFaceArray(DerivedMesh * dm,MFace * r_face)136 static void cdDM_copyTessFaceArray(DerivedMesh *dm, MFace *r_face)
137 {
138 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
139 memcpy(r_face, cddm->mface, sizeof(*r_face) * dm->numTessFaceData);
140 }
141
cdDM_copyLoopArray(DerivedMesh * dm,MLoop * r_loop)142 static void cdDM_copyLoopArray(DerivedMesh *dm, MLoop *r_loop)
143 {
144 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
145 memcpy(r_loop, cddm->mloop, sizeof(*r_loop) * dm->numLoopData);
146 }
147
cdDM_copyPolyArray(DerivedMesh * dm,MPoly * r_poly)148 static void cdDM_copyPolyArray(DerivedMesh *dm, MPoly *r_poly)
149 {
150 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
151 memcpy(r_poly, cddm->mpoly, sizeof(*r_poly) * dm->numPolyData);
152 }
153
cdDM_getVertCo(DerivedMesh * dm,int index,float r_co[3])154 static void cdDM_getVertCo(DerivedMesh *dm, int index, float r_co[3])
155 {
156 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
157
158 copy_v3_v3(r_co, cddm->mvert[index].co);
159 }
160
cdDM_getVertNo(DerivedMesh * dm,int index,float r_no[3])161 static void cdDM_getVertNo(DerivedMesh *dm, int index, float r_no[3])
162 {
163 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
164 normal_short_to_float_v3(r_no, cddm->mvert[index].no);
165 }
166
cdDM_getPolyMap(Object * ob,DerivedMesh * dm)167 static const MeshElemMap *cdDM_getPolyMap(Object *ob, DerivedMesh *dm)
168 {
169 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
170
171 if (!cddm->pmap && ob->type == OB_MESH) {
172 Mesh *me = ob->data;
173
174 BKE_mesh_vert_poly_map_create(
175 &cddm->pmap, &cddm->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
176 }
177
178 return cddm->pmap;
179 }
180
cdDM_recalc_looptri(DerivedMesh * dm)181 static void cdDM_recalc_looptri(DerivedMesh *dm)
182 {
183 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
184 const unsigned int totpoly = dm->numPolyData;
185 const unsigned int totloop = dm->numLoopData;
186
187 DM_ensure_looptri_data(dm);
188 BLI_assert(totpoly == 0 || cddm->dm.looptris.array_wip != NULL);
189
190 BKE_mesh_recalc_looptri(
191 cddm->mloop, cddm->mpoly, cddm->mvert, totloop, totpoly, cddm->dm.looptris.array_wip);
192
193 BLI_assert(cddm->dm.looptris.array == NULL);
194 atomic_cas_ptr(
195 (void **)&cddm->dm.looptris.array, cddm->dm.looptris.array, cddm->dm.looptris.array_wip);
196 cddm->dm.looptris.array_wip = NULL;
197 }
198
cdDM_free_internal(CDDerivedMesh * cddm)199 static void cdDM_free_internal(CDDerivedMesh *cddm)
200 {
201 if (cddm->pmap) {
202 MEM_freeN(cddm->pmap);
203 }
204 if (cddm->pmap_mem) {
205 MEM_freeN(cddm->pmap_mem);
206 }
207 }
208
cdDM_release(DerivedMesh * dm)209 static void cdDM_release(DerivedMesh *dm)
210 {
211 CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
212
213 if (DM_release(dm)) {
214 cdDM_free_internal(cddm);
215 MEM_freeN(cddm);
216 }
217 }
218
219 /**************** CDDM interface functions ****************/
cdDM_create(const char * desc)220 static CDDerivedMesh *cdDM_create(const char *desc)
221 {
222 CDDerivedMesh *cddm;
223 DerivedMesh *dm;
224
225 cddm = MEM_callocN(sizeof(*cddm), desc);
226 dm = &cddm->dm;
227
228 dm->getNumVerts = cdDM_getNumVerts;
229 dm->getNumEdges = cdDM_getNumEdges;
230 dm->getNumTessFaces = cdDM_getNumTessFaces;
231 dm->getNumLoops = cdDM_getNumLoops;
232 dm->getNumPolys = cdDM_getNumPolys;
233
234 dm->getVert = cdDM_getVert;
235 dm->getEdge = cdDM_getEdge;
236 dm->getTessFace = cdDM_getTessFace;
237
238 dm->copyVertArray = cdDM_copyVertArray;
239 dm->copyEdgeArray = cdDM_copyEdgeArray;
240 dm->copyTessFaceArray = cdDM_copyTessFaceArray;
241 dm->copyLoopArray = cdDM_copyLoopArray;
242 dm->copyPolyArray = cdDM_copyPolyArray;
243
244 dm->getVertData = DM_get_vert_data;
245 dm->getEdgeData = DM_get_edge_data;
246 dm->getTessFaceData = DM_get_tessface_data;
247 dm->getVertDataArray = DM_get_vert_data_layer;
248 dm->getEdgeDataArray = DM_get_edge_data_layer;
249 dm->getTessFaceDataArray = DM_get_tessface_data_layer;
250
251 dm->recalcLoopTri = cdDM_recalc_looptri;
252
253 dm->getVertCo = cdDM_getVertCo;
254 dm->getVertNo = cdDM_getVertNo;
255
256 dm->getPolyMap = cdDM_getPolyMap;
257
258 dm->release = cdDM_release;
259
260 return cddm;
261 }
262
cdDM_from_mesh_ex(Mesh * mesh,eCDAllocType alloctype,const CustomData_MeshMasks * mask)263 static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh,
264 eCDAllocType alloctype,
265 const CustomData_MeshMasks *mask)
266 {
267 CDDerivedMesh *cddm = cdDM_create(__func__);
268 DerivedMesh *dm = &cddm->dm;
269 CustomData_MeshMasks cddata_masks = *mask;
270
271 cddata_masks.lmask &= ~CD_MASK_MDISPS;
272
273 /* this does a referenced copy, with an exception for fluidsim */
274
275 DM_init(dm,
276 DM_TYPE_CDDM,
277 mesh->totvert,
278 mesh->totedge,
279 0 /* mesh->totface */,
280 mesh->totloop,
281 mesh->totpoly);
282
283 /* This should actually be dm->deformedOnly = mesh->runtime.deformed_only,
284 * but only if the original mesh had its deformed_only flag correctly set
285 * (which isn't generally the case). */
286 dm->deformedOnly = 1;
287 dm->cd_flag = mesh->cd_flag;
288
289 if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
290 dm->dirty |= DM_DIRTY_NORMALS;
291 }
292 /* TODO DM_DIRTY_TESS_CDLAYERS ? Maybe not though,
293 * since we probably want to switch to looptris? */
294
295 CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype, mesh->totvert);
296 CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype, mesh->totedge);
297 CustomData_merge(&mesh->fdata,
298 &dm->faceData,
299 cddata_masks.fmask | CD_MASK_ORIGINDEX,
300 alloctype,
301 0 /* mesh->totface */);
302 CustomData_merge(&mesh->ldata, &dm->loopData, cddata_masks.lmask, alloctype, mesh->totloop);
303 CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype, mesh->totpoly);
304
305 cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
306 cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
307 cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
308 cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
309 #if 0
310 cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
311 #else
312 cddm->mface = NULL;
313 #endif
314
315 /* commented since even when CD_ORIGINDEX was first added this line fails
316 * on the default cube, (after editmode toggle too) - campbell */
317 #if 0
318 BLI_assert(CustomData_has_layer(&cddm->dm.faceData, CD_ORIGINDEX));
319 #endif
320
321 return dm;
322 }
323
CDDM_from_mesh(Mesh * mesh)324 DerivedMesh *CDDM_from_mesh(Mesh *mesh)
325 {
326 return cdDM_from_mesh_ex(mesh, CD_REFERENCE, &CD_MASK_MESH);
327 }
328
CDDM_copy(DerivedMesh * source)329 DerivedMesh *CDDM_copy(DerivedMesh *source)
330 {
331 CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
332 DerivedMesh *dm = &cddm->dm;
333 int numVerts = source->numVertData;
334 int numEdges = source->numEdgeData;
335 int numTessFaces = 0;
336 int numLoops = source->numLoopData;
337 int numPolys = source->numPolyData;
338
339 /* NOTE: Don't copy tessellation faces if not requested explicitly. */
340
341 /* ensure these are created if they are made on demand */
342 source->getVertDataArray(source, CD_ORIGINDEX);
343 source->getEdgeDataArray(source, CD_ORIGINDEX);
344 source->getPolyDataArray(source, CD_ORIGINDEX);
345
346 /* this initializes dm, and copies all non mvert/medge/mface layers */
347 DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys);
348 dm->deformedOnly = source->deformedOnly;
349 dm->cd_flag = source->cd_flag;
350 dm->dirty = source->dirty;
351
352 /* Tessellation data is never copied, so tag it here.
353 * Only tag dirty layers if we really ignored tessellation faces.
354 */
355 dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
356
357 CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
358 CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
359
360 /* now add mvert/medge/mface layers */
361 cddm->mvert = source->dupVertArray(source);
362 cddm->medge = source->dupEdgeArray(source);
363
364 CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
365 CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
366
367 DM_DupPolys(source, dm);
368
369 cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
370 cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
371
372 return dm;
373 }
374