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