Fix T67033 EEVEE: Random Flickering Materials
[blender.git] / source / blender / blenkernel / intern / editmesh.c
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) 2005 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup bke
22  */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "DNA_listBase.h"
27 #include "DNA_object_types.h"
28 #include "DNA_mesh_types.h"
29
30 #include "BLI_math.h"
31
32 #include "BKE_editmesh.h"
33 #include "BKE_cdderivedmesh.h"
34 #include "BKE_library.h"
35
36 BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
37 {
38   BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
39
40   em->bm = bm;
41   if (do_tessellate) {
42     BKE_editmesh_tessface_calc(em);
43   }
44
45   return em;
46 }
47
48 BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
49 {
50   BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
51   *em_copy = *em;
52
53   em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
54
55   em_copy->derivedVertColor = NULL;
56   em_copy->derivedVertColorLen = 0;
57   em_copy->derivedFaceColor = NULL;
58   em_copy->derivedFaceColorLen = 0;
59
60   em_copy->bm = BM_mesh_copy(em->bm);
61
62   /* The tessellation is NOT calculated on the copy here,
63    * because currently all the callers of this function use
64    * it to make a backup copy of the BMEditMesh to restore
65    * it in the case of errors in an operation. For perf
66    * reasons, in that case it makes more sense to do the
67    * tessellation only when/if that copy ends up getting
68    * used.*/
69   em_copy->looptris = NULL;
70
71   return em_copy;
72 }
73
74 /**
75  * \brief Return the BMEditMesh for a given object
76  *
77  * \note this function assumes this is a mesh object,
78  * don't add NULL data check here. caller must do that
79  */
80 BMEditMesh *BKE_editmesh_from_object(Object *ob)
81 {
82   BLI_assert(ob->type == OB_MESH);
83   /* sanity check */
84 #if 0 /* disable in mutlti-object edit. */
85 #  ifndef NDEBUG
86   if (((Mesh *)ob->data)->edit_mesh) {
87     BLI_assert(((Mesh *)ob->data)->edit_mesh->ob == ob);
88   }
89 #  endif
90 #endif
91   return ((Mesh *)ob->data)->edit_mesh;
92 }
93
94 static void editmesh_tessface_calc_intern(BMEditMesh *em)
95 {
96   /* allocating space before calculating the tessellation */
97
98   BMesh *bm = em->bm;
99
100   /* this assumes all faces can be scan-filled, which isn't always true,
101    * worst case we over alloc a little which is acceptable */
102   const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
103   const int looptris_tot_prev_alloc = em->looptris ?
104                                           (MEM_allocN_len(em->looptris) / sizeof(*em->looptris)) :
105                                           0;
106
107   BMLoop *(*looptris)[3];
108
109   /* this means no reallocs for quad dominant models, for */
110   if ((em->looptris != NULL) &&
111       /* (*em->tottri >= looptris_tot)) */
112       /* check against alloc'd size incase we over alloc'd a little */
113       ((looptris_tot_prev_alloc >= looptris_tot) &&
114        (looptris_tot_prev_alloc <= looptris_tot * 2))) {
115     looptris = em->looptris;
116   }
117   else {
118     if (em->looptris) {
119       MEM_freeN(em->looptris);
120     }
121     looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
122   }
123
124   em->looptris = looptris;
125
126   /* after allocating the em->looptris, we're ready to tessellate */
127   BM_mesh_calc_tessellation(em->bm, em->looptris, &em->tottri);
128 }
129
130 void BKE_editmesh_tessface_calc(BMEditMesh *em)
131 {
132   editmesh_tessface_calc_intern(em);
133
134   /* commented because editbmesh_build_data() ensures we get tessfaces */
135 #if 0
136   if (em->mesh_eval_final && em->mesh_eval_final == em->mesh_eval_cage) {
137     BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
138   }
139   else if (em->mesh_eval_final) {
140     BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
141     BKE_mesh_runtime_looptri_ensure(em->mesh_eval_cage);
142   }
143 #endif
144 }
145
146 void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
147 {
148   if (em->mesh_eval_cage) {
149     BKE_id_free(NULL, em->mesh_eval_cage);
150   }
151   if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) {
152     BKE_id_free(NULL, em->mesh_eval_final);
153   }
154   em->mesh_eval_cage = em->mesh_eval_final = NULL;
155 }
156
157 /*does not free the BMEditMesh struct itself*/
158 void BKE_editmesh_free(BMEditMesh *em)
159 {
160   BKE_editmesh_free_derivedmesh(em);
161
162   BKE_editmesh_color_free(em);
163
164   if (em->looptris) {
165     MEM_freeN(em->looptris);
166   }
167
168   if (em->bm) {
169     BM_mesh_free(em->bm);
170   }
171 }
172
173 void BKE_editmesh_color_free(BMEditMesh *em)
174 {
175   if (em->derivedVertColor) {
176     MEM_freeN(em->derivedVertColor);
177   }
178   if (em->derivedFaceColor) {
179     MEM_freeN(em->derivedFaceColor);
180   }
181   em->derivedVertColor = NULL;
182   em->derivedFaceColor = NULL;
183
184   em->derivedVertColorLen = 0;
185   em->derivedFaceColorLen = 0;
186 }
187
188 void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
189 {
190   switch (htype) {
191     case BM_VERT:
192       if (em->derivedVertColorLen != em->bm->totvert) {
193         BKE_editmesh_color_free(em);
194         em->derivedVertColor = MEM_mallocN(sizeof(*em->derivedVertColor) * em->bm->totvert,
195                                            __func__);
196         em->derivedVertColorLen = em->bm->totvert;
197       }
198       break;
199     case BM_FACE:
200       if (em->derivedFaceColorLen != em->bm->totface) {
201         BKE_editmesh_color_free(em);
202         em->derivedFaceColor = MEM_mallocN(sizeof(*em->derivedFaceColor) * em->bm->totface,
203                                            __func__);
204         em->derivedFaceColorLen = em->bm->totface;
205       }
206       break;
207     default:
208       BLI_assert(0);
209       break;
210   }
211 }
212
213 float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
214 {
215   BMIter iter;
216   BMVert *eve;
217   float(*orco)[3];
218   int i;
219
220   orco = MEM_mallocN(em->bm->totvert * sizeof(*orco), __func__);
221
222   BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
223     copy_v3_v3(orco[i], eve->co);
224   }
225
226   *r_numVerts = em->bm->totvert;
227
228   return orco;
229 }
230
231 void BKE_editmesh_lnorspace_update(BMEditMesh *em)
232 {
233   BMesh *bm = em->bm;
234
235   /* We need to create clnors data if none exist yet, otherwise there is no way to edit them.
236    * Similar code to MESH_OT_customdata_custom_splitnormals_add operator,
237    * we want to keep same shading in case we were using autosmooth so far.
238    * Note: there is a problem here, which is that if someone starts a normal editing operation on
239    * previously autosmooth-ed mesh, and cancel that operation, generated clnors data remain,
240    * with related sharp edges (and hence autosmooth is 'lost').
241    * Not sure how critical this is, and how to fix that issue? */
242   if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
243     Mesh *me = em->ob->data;
244     if (me->flag & ME_AUTOSMOOTH) {
245       BM_edges_sharp_from_angle_set(bm, me->smoothresh);
246     }
247   }
248
249   BM_lnorspace_update(bm);
250 }
251
252 /* If autosmooth not already set, set it */
253 void BKE_editmesh_ensure_autosmooth(BMEditMesh *em)
254 {
255   Mesh *me = em->ob->data;
256   if (!(me->flag & ME_AUTOSMOOTH)) {
257     me->flag |= ME_AUTOSMOOTH;
258     BKE_editmesh_lnorspace_update(em);
259   }
260 }