Merge branch 'blender2.7'
[blender.git] / source / blender / blenkernel / intern / subdiv.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) 2018 by Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Sergey Sharybin.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/blenkernel/intern/subdiv.c
27  *  \ingroup bke
28  */
29
30 #include "BKE_subdiv.h"
31
32 #include "DNA_mesh_types.h"
33 #include "DNA_meshdata_types.h"
34 #include "DNA_modifier_types.h"
35
36 #include "BLI_utildefines.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "subdiv_converter.h"
41
42 #include "opensubdiv_capi.h"
43 #include "opensubdiv_converter_capi.h"
44 #include "opensubdiv_evaluator_capi.h"
45 #include "opensubdiv_topology_refiner_capi.h"
46
47 /* ========================== CONVERSION HELPERS ============================ */
48
49 eSubdivFVarLinearInterpolation
50 BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
51 {
52         switch (uv_smooth) {
53                 case SUBSURF_UV_SMOOTH_NONE:
54                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
55                 case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS:
56                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
57                 case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS:
58                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS;
59                 case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
60                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE;
61                 case SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES:
62                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
63                 case SUBSURF_UV_SMOOTH_ALL:
64                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE;
65         }
66         BLI_assert(!"Unknown uv smooth flag");
67         return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
68 }
69
70 /* ================================ SETTINGS ================================ */
71
72 static bool check_mesh_has_non_quad(const Mesh *mesh)
73 {
74         for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
75                 const MPoly *poly = &mesh->mpoly[poly_index];
76                 if (poly->totloop != 4) {
77                         return true;
78                 }
79         }
80         return false;
81 }
82
83 void BKE_subdiv_settings_validate_for_mesh(SubdivSettings *settings,
84                                            const Mesh *mesh)
85 {
86         if (settings->level != 1) {
87                 return;
88         }
89         if (check_mesh_has_non_quad(mesh)) {
90                 settings->level = 2;
91         }
92 }
93
94 bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a,
95                                const SubdivSettings *settings_b)
96 {
97         return
98                 (settings_a->is_simple == settings_b->is_simple &&
99                  settings_a->is_adaptive == settings_b->is_adaptive &&
100                  settings_a->level == settings_b->level &&
101                  settings_a->vtx_boundary_interpolation ==
102                          settings_b->vtx_boundary_interpolation &&
103                  settings_a->fvar_linear_interpolation ==
104                          settings_b->fvar_linear_interpolation);
105 }
106
107 /* ============================== CONSTRUCTION ============================== */
108
109 /* Creation from scratch. */
110
111 Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
112                                       struct OpenSubdiv_Converter *converter)
113 {
114         SubdivStats stats;
115         BKE_subdiv_stats_init(&stats);
116         BKE_subdiv_stats_begin(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
117         OpenSubdiv_TopologyRefinerSettings topology_refiner_settings;
118         topology_refiner_settings.level = settings->level;
119         topology_refiner_settings.is_adaptive = settings->is_adaptive;
120         struct OpenSubdiv_TopologyRefiner *osd_topology_refiner = NULL;
121         if (converter->getNumVertices(converter) != 0) {
122                 osd_topology_refiner =
123                         openSubdiv_createTopologyRefinerFromConverter(
124                                 converter, &topology_refiner_settings);
125         }
126         else {
127                 /* TODO(sergey): Check whether original geometry had any vertices.
128                  * The thing here is: OpenSubdiv can only deal with faces, but our
129                  * side of subdiv also deals with loose vertices and edges. */
130         }
131         Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr");
132         subdiv->settings = *settings;
133         subdiv->topology_refiner = osd_topology_refiner;
134         subdiv->evaluator = NULL;
135         subdiv->displacement_evaluator = NULL;
136         BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
137         subdiv->stats = stats;
138         return subdiv;
139 }
140
141 Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
142                                  const Mesh *mesh)
143 {
144         if (mesh->totvert == 0) {
145                 return NULL;
146         }
147         OpenSubdiv_Converter converter;
148         BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
149         Subdiv *subdiv = BKE_subdiv_new_from_converter(settings, &converter);
150         BKE_subdiv_converter_free(&converter);
151         return subdiv;
152 }
153
154 /* Creation with cached-aware semantic. */
155
156 Subdiv *BKE_subdiv_update_from_converter(Subdiv *subdiv,
157                                          const SubdivSettings *settings,
158                                          OpenSubdiv_Converter *converter)
159 {
160         /* Check if the existing descriptor can be re-used. */
161         bool can_reuse_subdiv = true;
162         if (subdiv != NULL && subdiv->topology_refiner != NULL) {
163                 if (!BKE_subdiv_settings_equal(&subdiv->settings, settings)) {
164                         can_reuse_subdiv = false;
165                 }
166                 else {
167                         BKE_subdiv_stats_begin(
168                                 &subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
169                         can_reuse_subdiv = openSubdiv_topologyRefinerCompareWithConverter(
170                                 subdiv->topology_refiner, converter);
171                         BKE_subdiv_stats_end(
172                                 &subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
173                 }
174         }
175         else {
176                 can_reuse_subdiv = false;
177         }
178         if (can_reuse_subdiv) {
179                 return subdiv;
180         }
181         /* Create new subdiv. */
182         if (subdiv != NULL) {
183                 BKE_subdiv_free(subdiv);
184         }
185         return BKE_subdiv_new_from_converter(settings, converter);
186 }
187
188 Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
189                                     const SubdivSettings *settings,
190                                     const Mesh *mesh)
191 {
192         OpenSubdiv_Converter converter;
193         BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
194         subdiv = BKE_subdiv_update_from_converter(subdiv, settings, &converter);
195         BKE_subdiv_converter_free(&converter);
196         return subdiv;
197 }
198
199 /* Memory release. */
200
201 void BKE_subdiv_free(Subdiv *subdiv)
202 {
203         if (subdiv->evaluator != NULL) {
204                 openSubdiv_deleteEvaluator(subdiv->evaluator);
205         }
206         if (subdiv->topology_refiner != NULL) {
207                 openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
208         }
209         BKE_subdiv_displacement_detach(subdiv);
210         if (subdiv->cache_.face_ptex_offset != NULL) {
211                 MEM_freeN(subdiv->cache_.face_ptex_offset);
212         }
213         MEM_freeN(subdiv);
214 }
215
216 /* =========================== PTEX FACES AND GRIDS ========================= */
217
218 int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
219 {
220         if (subdiv->cache_.face_ptex_offset != NULL) {
221                 return subdiv->cache_.face_ptex_offset;
222         }
223         OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
224         if (topology_refiner == NULL) {
225                 return NULL;
226         }
227         const int num_coarse_faces =
228                 topology_refiner->getNumFaces(topology_refiner);
229         subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
230                 num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
231         int ptex_offset = 0;
232         for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
233                 const int num_ptex_faces =
234                         topology_refiner->getNumFacePtexFaces(
235                                 topology_refiner, face_index);
236                 subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
237                 ptex_offset += num_ptex_faces;
238         }
239         return subdiv->cache_.face_ptex_offset;
240 }