Merge branch 'blender2.7' into master.
[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 eSubdivFVarLinearInterpolation
47 BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
48 {
49         switch (uv_smooth) {
50                 case SUBSURF_UV_SMOOTH_NONE:
51                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
52                 case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS:
53                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
54                 case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS:
55                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS;
56                 case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
57                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE;
58                 case SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES:
59                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
60                 case SUBSURF_UV_SMOOTH_ALL:
61                         return SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE;
62         }
63         BLI_assert(!"Unknown uv smooth flag");
64         return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
65 }
66
67 Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
68                                       struct OpenSubdiv_Converter *converter)
69 {
70         SubdivStats stats;
71         BKE_subdiv_stats_init(&stats);
72         BKE_subdiv_stats_begin(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
73         OpenSubdiv_TopologyRefinerSettings topology_refiner_settings;
74         topology_refiner_settings.level = settings->level;
75         topology_refiner_settings.is_adaptive = settings->is_adaptive;
76         struct OpenSubdiv_TopologyRefiner *osd_topology_refiner = NULL;
77         if (converter->getNumVertices(converter) != 0) {
78                 osd_topology_refiner =
79                         openSubdiv_createTopologyRefinerFromConverter(
80                                 converter, &topology_refiner_settings);
81
82         }
83         else {
84                 /* TODO(sergey): Check whether original geometry had any vertices.
85                  * The thing here is: OpenSubdiv can only deal with faces, but our
86                  * side of subdiv also deals with loose vertices and edges.
87                  */
88         }
89         Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr");
90         subdiv->settings = *settings;
91         subdiv->topology_refiner = osd_topology_refiner;
92         subdiv->evaluator = NULL;
93         subdiv->displacement_evaluator = NULL;
94         BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
95         subdiv->stats = stats;
96         return subdiv;
97 }
98
99 Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
100                                  struct Mesh *mesh)
101 {
102         if (mesh->totvert == 0) {
103                 return NULL;
104         }
105         OpenSubdiv_Converter converter;
106         BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
107         Subdiv *subdiv = BKE_subdiv_new_from_converter(settings, &converter);
108         BKE_subdiv_converter_free(&converter);
109         return subdiv;
110 }
111
112 void BKE_subdiv_free(Subdiv *subdiv)
113 {
114         if (subdiv->evaluator != NULL) {
115                 openSubdiv_deleteEvaluator(subdiv->evaluator);
116         }
117         if (subdiv->topology_refiner != NULL) {
118                 openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
119         }
120         BKE_subdiv_displacement_detach(subdiv);
121         if (subdiv->cache_.face_ptex_offset != NULL) {
122                 MEM_freeN(subdiv->cache_.face_ptex_offset);
123         }
124         MEM_freeN(subdiv);
125 }
126
127 int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
128 {
129         if (subdiv->cache_.face_ptex_offset != NULL) {
130                 return subdiv->cache_.face_ptex_offset;
131         }
132         OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
133         if (topology_refiner == NULL) {
134                 return NULL;
135         }
136         const int num_coarse_faces =
137                 topology_refiner->getNumFaces(topology_refiner);
138         subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
139                 num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
140         int ptex_offset = 0;
141         for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
142                 const int num_ptex_faces =
143                         topology_refiner->getNumFacePtexFaces(
144                                 topology_refiner, face_index);
145                 subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
146                 ptex_offset += num_ptex_faces;
147         }
148         return subdiv->cache_.face_ptex_offset;
149 }