ClangFormat: apply to source, most of intern
[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::stack;
38 using opensubdiv_capi::vector;
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 TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology(
50     TopologyRefiner &refiner, const TopologyRefinerData &cb_data)
51 {
52   const OpenSubdiv_Converter *converter = cb_data.converter;
53   // Faces and face-vertices.
54   const int num_faces = converter->getNumFaces(converter);
55   setNumBaseFaces(refiner, num_faces);
56   for (int face_index = 0; face_index < num_faces; ++face_index) {
57     const int num_face_vertices = converter->getNumFaceVertices(converter, face_index);
58     setNumBaseFaceVertices(refiner, face_index, num_face_vertices);
59   }
60   // Vertices.
61   const int num_vertices = converter->getNumVertices(converter);
62   setNumBaseVertices(refiner, num_vertices);
63   // If converter does not provide full topology, we are done.
64   if (!converter->specifiesFullTopology(converter)) {
65     return true;
66   }
67   // Edges and edge-faces.
68   const int num_edges = converter->getNumEdges(converter);
69   setNumBaseEdges(refiner, num_edges);
70   for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
71     const int num_edge_faces = converter->getNumEdgeFaces(converter, edge_index);
72     setNumBaseEdgeFaces(refiner, edge_index, num_edge_faces);
73   }
74   // Vertex-faces and vertex-edges.
75   for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
76     const int num_vert_edges = converter->getNumVertexEdges(converter, vertex_index);
77     const int num_vert_faces = converter->getNumVertexFaces(converter, vertex_index);
78     setNumBaseVertexEdges(refiner, vertex_index, num_vert_edges);
79     setNumBaseVertexFaces(refiner, vertex_index, num_vert_faces);
80   }
81   return true;
82 }
83
84 template<>
85 inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology(
86     TopologyRefiner &refiner, const TopologyRefinerData &cb_data)
87 {
88   using Far::IndexArray;
89   const OpenSubdiv_Converter *converter = cb_data.converter;
90   const bool full_topology_specified = converter->specifiesFullTopology(converter);
91   // Face relations.
92   const int num_faces = converter->getNumFaces(converter);
93   for (int face_index = 0; face_index < num_faces; ++face_index) {
94     IndexArray dst_face_verts = getBaseFaceVertices(refiner, face_index);
95     converter->getFaceVertices(converter, face_index, &dst_face_verts[0]);
96     if (full_topology_specified) {
97       IndexArray dst_face_edges = getBaseFaceEdges(refiner, face_index);
98       converter->getFaceEdges(converter, face_index, &dst_face_edges[0]);
99     }
100   }
101   // If converter does not provide full topology, we are done.
102   if (!full_topology_specified) {
103     return true;
104   }
105   // Edge relations.
106   const int num_edges = converter->getNumEdges(converter);
107   for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
108     // Edge-vertices.
109     IndexArray dst_edge_vertices = getBaseEdgeVertices(refiner, edge_index);
110     converter->getEdgeVertices(converter, edge_index, &dst_edge_vertices[0]);
111     // Edge-faces.
112     IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge_index);
113     converter->getEdgeFaces(converter, edge_index, &dst_edge_faces[0]);
114   }
115   // Vertex relations.
116   const int num_vertices = converter->getNumVertices(converter);
117   vector<int> vertex_faces, vertex_edges;
118   for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
119     // Vertex-faces.
120     IndexArray dst_vertex_faces = getBaseVertexFaces(refiner, vertex_index);
121     const int num_vertex_faces = converter->getNumVertexFaces(converter, vertex_index);
122     vertex_faces.resize(num_vertex_faces);
123     converter->getVertexFaces(converter, vertex_index, &vertex_faces[0]);
124     // Vertex-edges.
125     IndexArray dst_vertex_edges = getBaseVertexEdges(refiner, vertex_index);
126     const int num_vertex_edges = converter->getNumVertexEdges(converter, vertex_index);
127     vertex_edges.resize(num_vertex_edges);
128     converter->getVertexEdges(converter, vertex_index, &vertex_edges[0]);
129     memcpy(&dst_vertex_edges[0], &vertex_edges[0], sizeof(int) * num_vertex_edges);
130     memcpy(&dst_vertex_faces[0], &vertex_faces[0], sizeof(int) * num_vertex_faces);
131   }
132   populateBaseLocalIndices(refiner);
133   return true;
134 }
135
136 template<>
137 inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags(
138     TopologyRefiner &refiner, const TopologyRefinerData &cb_data)
139 {
140   using OpenSubdiv::Sdc::Crease;
141   const OpenSubdiv_Converter *converter = cb_data.converter;
142   const bool full_topology_specified = converter->specifiesFullTopology(converter);
143   const int num_edges = converter->getNumEdges(converter);
144   for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
145     const float sharpness = converter->getEdgeSharpness(converter, edge_index);
146     if (sharpness < 1e-6f) {
147       continue;
148     }
149     if (full_topology_specified) {
150       setBaseEdgeSharpness(refiner, edge_index, sharpness);
151     }
152     else {
153       int edge_vertices[2];
154       converter->getEdgeVertices(converter, edge_index, edge_vertices);
155       const int base_edge_index = findBaseEdge(refiner, edge_vertices[0], edge_vertices[1]);
156       if (base_edge_index == OpenSubdiv::Far::INDEX_INVALID) {
157         printf("OpenSubdiv Error: failed to find reconstructed edge\n");
158         return false;
159       }
160       setBaseEdgeSharpness(refiner, base_edge_index, sharpness);
161     }
162   }
163   // OpenSubdiv expects non-manifold vertices to be sharp but at the time it
164   // handles correct cases when vertex is a corner of plane. Currently mark
165   // vertices which are adjacent to a loose edge as sharp, but this decision
166   // needs some more investigation.
167   const int num_vertices = converter->getNumVertices(converter);
168   for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
169     ConstIndexArray vertex_edges = getBaseVertexEdges(refiner, vertex_index);
170     if (converter->isInfiniteSharpVertex(converter, vertex_index)) {
171       setBaseVertexSharpness(refiner, vertex_index, Crease::SHARPNESS_INFINITE);
172       continue;
173     }
174     float sharpness = converter->getVertexSharpness(converter, vertex_index);
175     if (vertex_edges.size() == 2) {
176       const int edge0 = vertex_edges[0], edge1 = vertex_edges[1];
177       const float sharpness0 = refiner._levels[0]->getEdgeSharpness(edge0);
178       const float sharpness1 = refiner._levels[0]->getEdgeSharpness(edge1);
179       // TODO(sergey): Find a better mixing between edge and vertex sharpness.
180       sharpness += min(sharpness0, sharpness1);
181       sharpness = min(sharpness, 10.0f);
182     }
183     setBaseVertexSharpness(refiner, vertex_index, sharpness);
184   }
185   return true;
186 }
187
188 template<>
189 inline bool TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology(
190     TopologyRefiner &refiner, const TopologyRefinerData &cb_data)
191 {
192   const OpenSubdiv_Converter *converter = cb_data.converter;
193   const int num_layers = converter->getNumUVLayers(converter);
194   if (num_layers <= 0) {
195     // No UV maps, we can skip any face-varying data.
196     return true;
197   }
198   const int num_faces = getNumBaseFaces(refiner);
199   for (int layer_index = 0; layer_index < num_layers; ++layer_index) {
200     converter->precalcUVLayer(converter, layer_index);
201     const int num_uvs = converter->getNumUVCoordinates(converter);
202     // Fill in per-corner index of the UV.
203     const int channel = createBaseFVarChannel(refiner, num_uvs);
204     // TODO(sergey): Need to check whether converter changed the winding of
205     // face to match OpenSubdiv's expectations.
206     for (int face_index = 0; face_index < num_faces; ++face_index) {
207       Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner, face_index, channel);
208       for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
209         const int uv_index = converter->getFaceCornerUVIndex(converter, face_index, corner);
210         dst_face_uvs[corner] = uv_index;
211       }
212     }
213     converter->finishUVLayer(converter);
214   }
215   return true;
216 }
217
218 template<>
219 inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology(
220     TopologyError /*errCode*/, const char *msg, const TopologyRefinerData & /*mesh*/)
221 {
222   printf("OpenSubdiv Error: %s\n", msg);
223 }
224
225 } /* namespace Far */
226 } /* namespace OPENSUBDIV_VERSION */
227 } /* namespace OpenSubdiv */
228
229 namespace opensubdiv_capi {
230
231 namespace {
232
233 OpenSubdiv::Sdc::Options::VtxBoundaryInterpolation getVtxBoundaryInterpolationFromCAPI(
234     OpenSubdiv_VtxBoundaryInterpolation boundary_interpolation)
235 {
236   using OpenSubdiv::Sdc::Options;
237   switch (boundary_interpolation) {
238     case OSD_VTX_BOUNDARY_NONE:
239       return Options::VTX_BOUNDARY_NONE;
240     case OSD_VTX_BOUNDARY_EDGE_ONLY:
241       return Options::VTX_BOUNDARY_EDGE_ONLY;
242     case OSD_VTX_BOUNDARY_EDGE_AND_CORNER:
243       return Options::VTX_BOUNDARY_EDGE_AND_CORNER;
244   }
245   assert(!"Unknown veretx boundary interpolation.");
246   return Options::VTX_BOUNDARY_EDGE_ONLY;
247 }
248
249 }  // namespace
250
251 OpenSubdiv::Far::TopologyRefiner *createOSDTopologyRefinerFromConverter(
252     OpenSubdiv_Converter *converter)
253 {
254   using OpenSubdiv::Far::TopologyRefinerFactory;
255   using OpenSubdiv::Sdc::Options;
256   const OpenSubdiv::Sdc::SchemeType scheme_type = getSchemeTypeFromCAPI(
257       converter->getSchemeType(converter));
258   const Options::FVarLinearInterpolation linear_interpolation = getFVarLinearInterpolationFromCAPI(
259       converter->getFVarLinearInterpolation(converter));
260   Options options;
261   options.SetVtxBoundaryInterpolation(
262       getVtxBoundaryInterpolationFromCAPI(converter->getVtxBoundaryInterpolation(converter)));
263   options.SetCreasingMethod(Options::CREASE_UNIFORM);
264   options.SetFVarLinearInterpolation(linear_interpolation);
265
266   TopologyRefinerFactory<TopologyRefinerData>::Options topology_options(scheme_type, options);
267 #ifdef OPENSUBDIV_VALIDATE_TOPOLOGY
268   topology_options.validateFullTopology = true;
269 #endif
270   TopologyRefinerData cb_data;
271   cb_data.converter = converter;
272   return TopologyRefinerFactory<TopologyRefinerData>::Create(cb_data, topology_options);
273 }
274
275 }  // namespace opensubdiv_capi