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