Merge branch 'blender2.7' of git.blender.org:blender
[blender.git] / intern / opensubdiv / internal / opensubdiv_converter_factory.cc
1 // Copyright 2015 Blender Foundation. All rights reserved.
2 //
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License
5 // as published by the Free Software Foundation; either version 2
6 // of the License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software Foundation,
15 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 //
17 // Author: Sergey Sharybin
18
19 #ifdef _MSC_VER
20 #  include <iso646.h>
21 #endif
22
23 #include "internal/opensubdiv_converter_factory.h"
24
25 #include <cassert>
26 #include <cstdio>
27
28 #include <opensubdiv/far/topologyRefinerFactory.h>
29
30 #include "internal/opensubdiv_converter_internal.h"
31 #include "internal/opensubdiv_converter_orient.h"
32 #include "internal/opensubdiv_internal.h"
33 #include "internal/opensubdiv_util.h"
34 #include "opensubdiv_converter_capi.h"
35
36 using opensubdiv_capi::min;
37 using opensubdiv_capi::vector;
38 using opensubdiv_capi::stack;
39
40 struct TopologyRefinerData {
41   const OpenSubdiv_Converter* converter;
42 };
43
44 namespace OpenSubdiv {
45 namespace OPENSUBDIV_VERSION {
46 namespace Far {
47
48 template <>
49 inline bool
50 TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology(
51     TopologyRefiner& refiner,
52     const TopologyRefinerData& cb_data) {
53   const OpenSubdiv_Converter* converter = cb_data.converter;
54   // Faces and face-vertices.
55   const int num_faces = converter->getNumFaces(converter);
56   setNumBaseFaces(refiner, num_faces);
57   for (int face_index = 0; face_index < num_faces; ++face_index) {
58     const int num_face_vertices =
59         converter->getNumFaceVertices(converter, face_index);
60     setNumBaseFaceVertices(refiner, face_index, num_face_vertices);
61   }
62   // Vertices.
63   const int num_vertices = converter->getNumVertices(converter);
64   setNumBaseVertices(refiner, num_vertices);
65   // If converter does not provide full topology, we are done.
66   if (!converter->specifiesFullTopology(converter)) {
67     return true;
68   }
69   // Edges and edge-faces.
70   const int num_edges = converter->getNumEdges(converter);
71   setNumBaseEdges(refiner, num_edges);
72   for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
73     const int num_edge_faces =
74         converter->getNumEdgeFaces(converter, edge_index);
75     setNumBaseEdgeFaces(refiner, edge_index, num_edge_faces);
76   }
77   // Vertex-faces and vertex-edges.
78   for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
79     const int num_vert_edges =
80         converter->getNumVertexEdges(converter, vertex_index);
81     const int num_vert_faces =
82         converter->getNumVertexFaces(converter, vertex_index);
83     setNumBaseVertexEdges(refiner, vertex_index, num_vert_edges);
84     setNumBaseVertexFaces(refiner, vertex_index, num_vert_faces);
85   }
86   return true;
87 }
88
89 template <>
90 inline bool
91 TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology(
92     TopologyRefiner& refiner,
93     const TopologyRefinerData& cb_data) {
94   using Far::IndexArray;
95   const OpenSubdiv_Converter* converter = cb_data.converter;
96   const bool full_topology_specified =
97           converter->specifiesFullTopology(converter);
98   // Face relations.
99   const int num_faces = converter->getNumFaces(converter);
100   for (int face_index = 0; face_index < num_faces; ++face_index) {
101     IndexArray dst_face_verts = getBaseFaceVertices(refiner, face_index);
102     converter->getFaceVertices(converter, face_index, &dst_face_verts[0]);
103     if (full_topology_specified) {
104       IndexArray dst_face_edges = getBaseFaceEdges(refiner, face_index);
105       converter->getFaceEdges(converter, face_index, &dst_face_edges[0]);
106     }
107   }
108   // If converter does not provide full topology, we are done.
109   if (!full_topology_specified) {
110     return true;
111   }
112   // Edge relations.
113   const int num_edges = converter->getNumEdges(converter);
114   for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
115     // Edge-vertices.
116     IndexArray dst_edge_vertices = getBaseEdgeVertices(refiner, edge_index);
117     converter->getEdgeVertices(converter, edge_index, &dst_edge_vertices[0]);
118     // Edge-faces.
119     IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge_index);
120     converter->getEdgeFaces(converter, edge_index, &dst_edge_faces[0]);
121   }
122   // Vertex relations.
123   const int num_vertices = converter->getNumVertices(converter);
124   vector<int> vertex_faces, vertex_edges;
125   for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
126     // Vertex-faces.
127     IndexArray dst_vertex_faces = getBaseVertexFaces(refiner, vertex_index);
128     const int num_vertex_faces =
129         converter->getNumVertexFaces(converter, vertex_index);
130     vertex_faces.resize(num_vertex_faces);
131     converter->getVertexFaces(converter, vertex_index, &vertex_faces[0]);
132     // Vertex-edges.
133     IndexArray dst_vertex_edges = getBaseVertexEdges(refiner, vertex_index);
134     const int num_vertex_edges =
135         converter->getNumVertexEdges(converter, vertex_index);
136     vertex_edges.resize(num_vertex_edges);
137     converter->getVertexEdges(converter, vertex_index, &vertex_edges[0]);
138     memcpy(&dst_vertex_edges[0], &vertex_edges[0],
139            sizeof(int) * num_vertex_edges);
140     memcpy(&dst_vertex_faces[0], &vertex_faces[0],
141            sizeof(int) * num_vertex_faces);
142   }
143   populateBaseLocalIndices(refiner);
144   return true;
145 }
146
147 template <>
148 inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags(
149     TopologyRefiner& refiner,
150     const TopologyRefinerData& cb_data) {
151   using OpenSubdiv::Sdc::Crease;
152   const OpenSubdiv_Converter* converter = cb_data.converter;
153   const bool full_topology_specified =
154           converter->specifiesFullTopology(converter);
155   const int num_edges = converter->getNumEdges(converter);
156   for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
157     const float sharpness =
158         converter->getEdgeSharpness(converter, edge_index);
159     if (sharpness < 1e-6f) {
160       continue;
161     }
162     if (full_topology_specified) {
163       setBaseEdgeSharpness(refiner, edge_index, sharpness);
164     } else {
165       int edge_vertices[2];
166       converter->getEdgeVertices(converter, edge_index, edge_vertices);
167       const int base_edge_index = findBaseEdge(
168           refiner, edge_vertices[0], edge_vertices[1]);
169       if (base_edge_index == OpenSubdiv::Far::INDEX_INVALID) {
170         printf("OpenSubdiv Error: failed to find reconstructed edge\n");
171         return false;
172       }
173       setBaseEdgeSharpness(refiner, base_edge_index, sharpness);
174     }
175   }
176   // OpenSubdiv expects non-manifold vertices to be sharp but at the time it
177   // handles correct cases when vertex is a corner of plane. Currently mark
178   // vertices which are adjacent to a loose edge as sharp, but this decision
179   // needs some more investigation.
180   const int num_vertices = converter->getNumVertices(converter);
181   for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
182     ConstIndexArray vertex_edges = getBaseVertexEdges(refiner, vertex_index);
183     if (converter->isInfiniteSharpVertex(converter, vertex_index)) {
184       setBaseVertexSharpness(
185           refiner, vertex_index, Crease::SHARPNESS_INFINITE);
186       continue;
187     }
188     float sharpness = converter->getVertexSharpness(converter, vertex_index);
189     if (vertex_edges.size() == 2) {
190       const int edge0 = vertex_edges[0], edge1 = vertex_edges[1];
191       const float sharpness0 = refiner._levels[0]->getEdgeSharpness(edge0);
192       const float sharpness1 = refiner._levels[0]->getEdgeSharpness(edge1);
193       // TODO(sergey): Find a better mixing between edge and vertex sharpness.
194       sharpness += min(sharpness0, sharpness1);
195       sharpness = min(sharpness, 10.0f);
196     }
197     setBaseVertexSharpness(refiner, vertex_index, sharpness);
198   }
199   return true;
200 }
201
202 template <>
203 inline bool
204 TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology(
205     TopologyRefiner& refiner,
206     const TopologyRefinerData& cb_data) {
207   const OpenSubdiv_Converter* converter = cb_data.converter;
208   const int num_layers = converter->getNumUVLayers(converter);
209   if (num_layers <= 0) {
210     // No UV maps, we can skip any face-varying data.
211     return true;
212   }
213   const int num_faces = getNumBaseFaces(refiner);
214   for (int layer_index = 0; layer_index < num_layers; ++layer_index) {
215     converter->precalcUVLayer(converter, layer_index);
216     const int num_uvs = converter->getNumUVCoordinates(converter);
217     // Fill in per-corner index of the UV.
218     const int channel = createBaseFVarChannel(refiner, num_uvs);
219     // TODO(sergey): Need to check whether converter changed the winding of
220     // face to match OpenSubdiv's expectations.
221     for (int face_index = 0; face_index < num_faces; ++face_index) {
222       Far::IndexArray dst_face_uvs =
223           getBaseFaceFVarValues(refiner, face_index, channel);
224       for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
225         const int uv_index =
226            converter->getFaceCornerUVIndex(converter, face_index, corner);
227         dst_face_uvs[corner] = uv_index;
228       }
229     }
230     converter->finishUVLayer(converter);
231   }
232   return true;
233 }
234
235 template <>
236 inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology(
237     TopologyError /*errCode*/, const char* msg,
238     const TopologyRefinerData& /*mesh*/) {
239   printf("OpenSubdiv Error: %s\n", msg);
240 }
241
242 } /* namespace Far */
243 } /* namespace OPENSUBDIV_VERSION */
244 } /* namespace OpenSubdiv */
245
246 namespace opensubdiv_capi {
247
248 namespace {
249
250 OpenSubdiv::Sdc::Options::VtxBoundaryInterpolation
251 getVtxBoundaryInterpolationFromCAPI(
252     OpenSubdiv_VtxBoundaryInterpolation boundary_interpolation) {
253   using OpenSubdiv::Sdc::Options;
254   switch (boundary_interpolation) {
255     case OSD_VTX_BOUNDARY_NONE:
256       return Options::VTX_BOUNDARY_NONE;
257     case OSD_VTX_BOUNDARY_EDGE_ONLY:
258       return Options::VTX_BOUNDARY_EDGE_ONLY;
259     case OSD_VTX_BOUNDARY_EDGE_AND_CORNER:
260       return Options::VTX_BOUNDARY_EDGE_AND_CORNER;
261   }
262   assert(!"Unknown veretx boundary interpolation.");
263   return Options::VTX_BOUNDARY_EDGE_ONLY;
264 }
265
266 }  // namespace
267
268 OpenSubdiv::Far::TopologyRefiner* createOSDTopologyRefinerFromConverter(
269     OpenSubdiv_Converter* converter) {
270   using OpenSubdiv::Sdc::Options;
271   using OpenSubdiv::Far::TopologyRefinerFactory;
272   const OpenSubdiv::Sdc::SchemeType scheme_type =
273       getSchemeTypeFromCAPI(converter->getSchemeType(converter));
274   const Options::FVarLinearInterpolation linear_interpolation =
275       getFVarLinearInterpolationFromCAPI(
276           converter->getFVarLinearInterpolation(converter));
277   Options options;
278   options.SetVtxBoundaryInterpolation(
279       getVtxBoundaryInterpolationFromCAPI(
280           converter->getVtxBoundaryInterpolation(converter)));
281   options.SetCreasingMethod(Options::CREASE_UNIFORM);
282   options.SetFVarLinearInterpolation(linear_interpolation);
283
284   TopologyRefinerFactory<TopologyRefinerData>::Options topology_options(
285       scheme_type, options);
286 #ifdef OPENSUBDIV_VALIDATE_TOPOLOGY
287   topology_options.validateFullTopology = true;
288 #endif
289   TopologyRefinerData cb_data;
290   cb_data.converter = converter;
291   return TopologyRefinerFactory<TopologyRefinerData>::Create(
292       cb_data, topology_options);
293 }
294
295 }  // namespace opensubdiv_capi