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