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