diff options
author | Dalai Felinto <dfelinto@gmail.com> | 2015-09-24 18:24:20 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2015-09-24 18:24:20 +0300 |
commit | 27b3ea622f8bd313a8e2827dfec752bf2125566c (patch) | |
tree | f212e49d224ce8e1cfc3b17a64ae524711494391 /intern/opensubdiv/opensubdiv_converter.cc | |
parent | 372dff8d1dc7e24d4b2cd37de245588ecfce8bfa (diff) | |
parent | de80e687689032cb85179a1f7e89750573631d5d (diff) |
Merge remote-tracking branch 'origin/master' into cycles_camera_nodescycles_camera_nodes
Note: the branch currently crashes in blender_camera_nodes.cpp:
BL::NodeTree b_ntree = b_data.node_groups[nodes_tree_name];
The crash was introduced in:
cb7cf523e5c000609f32a382e2c0fcc57f635a42
Conflicts:
intern/cycles/SConscript
intern/cycles/blender/addon/__init__.py
intern/cycles/blender/addon/properties.py
intern/cycles/blender/blender_camera.cpp
intern/cycles/kernel/kernel_types.h
intern/cycles/kernel/svm/svm.h
intern/cycles/kernel/svm/svm_types.h
intern/cycles/render/camera.cpp
intern/cycles/render/camera.h
Diffstat (limited to 'intern/opensubdiv/opensubdiv_converter.cc')
-rw-r--r-- | intern/opensubdiv/opensubdiv_converter.cc | 682 |
1 files changed, 682 insertions, 0 deletions
diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc new file mode 100644 index 00000000000..3fadde68d32 --- /dev/null +++ b/intern/opensubdiv/opensubdiv_converter.cc @@ -0,0 +1,682 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <cstdio> +#include <vector> + +#ifdef _MSC_VER +# include "iso646.h" +#endif + +#include <opensubdiv/far/topologyRefinerFactory.h> + +#include "opensubdiv_converter_capi.h" +#include "opensubdiv_intern.h" + +#include <stack> + +#ifdef OPENSUBDIV_ORIENT_TOPOLOGY +namespace { + +inline void reverse_face_verts(int *face_verts, int num_verts) +{ + int last_vert = face_verts[num_verts - 1]; + for (int i = num_verts - 1; i > 0; --i) { + face_verts[i] = face_verts[i - 1]; + } + face_verts[0] = last_vert; +} + +} /* namespace */ +#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */ + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { +namespace Far { + +namespace { + +template <typename T> +inline int findInArray(T array, int value) +{ + return (int)(std::find(array.begin(), array.end(), value) - array.begin()); +} + +#ifdef OPENSUBDIV_ORIENT_TOPOLOGY +inline int get_loop_winding(int vert0_of_face, int vert1_of_face) +{ + int delta_face = vert1_of_face - vert0_of_face; + if (abs(delta_face) != 1) { + if (delta_face > 0) { + delta_face = -1; + } + else { + delta_face = 1; + } + } + return delta_face; +} + +inline void reverse_face_loops(IndexArray face_verts, IndexArray face_edges) +{ + for (int i = 0; i < face_verts.size() / 2; ++i) { + int j = face_verts.size() - i - 1; + if (i != j) { + std::swap(face_verts[i], face_verts[j]); + std::swap(face_edges[i], face_edges[j]); + } + } + reverse_face_verts(&face_verts[0], face_verts.size()); +} + +inline void check_oriented_vert_connectivity(const int num_vert_edges, + const int num_vert_faces, + const int *vert_edges, + const int *vert_faces, + const int *dst_vert_edges, + const int *dst_vert_faces) +{ +# ifndef NDEBUG + for (int i = 0; i < num_vert_faces; ++i) { + bool found = false; + for (int j = 0; j < num_vert_faces; ++j) { + if (vert_faces[i] == dst_vert_faces[j]) { + found = true; + break; + } + } + if (!found) { + assert(!"vert-faces connectivity ruined"); + } + } + for (int i = 0; i < num_vert_edges; ++i) { + bool found = false; + for (int j = 0; j < num_vert_edges; ++j) { + if (vert_edges[i] == dst_vert_edges[j]) { + found = true; + break; + } + } + if (!found) { + assert(!"vert-edges connectivity ruined"); + } + } +# else + (void)num_vert_edges; + (void)num_vert_faces; + (void)vert_edges; + (void)vert_faces; + (void)dst_vert_edges; + (void)dst_vert_faces; +# endif +} +#endif + +} /* namespace */ + +template <> +inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopology( + TopologyRefiner& refiner, + const OpenSubdiv_Converter& conv) +{ + /* Faces and face-verts */ + const int num_faces = conv.get_num_faces(&conv); + setNumBaseFaces(refiner, num_faces); + for (int face = 0; face < num_faces; ++face) { + const int num_verts = conv.get_num_face_verts(&conv, face); + setNumBaseFaceVertices(refiner, face, num_verts); + } + /* Edges and edge-faces. */ + const int num_edges = conv.get_num_edges(&conv); + setNumBaseEdges(refiner, num_edges); + for (int edge = 0; edge < num_edges; ++edge) { + const int num_edge_faces = conv.get_num_edge_faces(&conv, edge); + setNumBaseEdgeFaces(refiner, edge, num_edge_faces); + } + /* Vertices and vert-faces and vert-edges/ */ + const int num_verts = conv.get_num_verts(&conv); + setNumBaseVertices(refiner, num_verts); + for (int vert = 0; vert < num_verts; ++vert) { + const int num_vert_edges = conv.get_num_vert_edges(&conv, vert), + num_vert_faces = conv.get_num_vert_faces(&conv, vert); + setNumBaseVertexEdges(refiner, vert, num_vert_edges); + setNumBaseVertexFaces(refiner, vert, num_vert_faces); + } + return true; +} + +template <> +inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopology( + TopologyRefiner& refiner, + const OpenSubdiv_Converter& conv) +{ + using Far::IndexArray; + /* Face relations. */ + const int num_faces = conv.get_num_faces(&conv); + for (int face = 0; face < num_faces; ++face) { + IndexArray dst_face_verts = getBaseFaceVertices(refiner, face); + conv.get_face_verts(&conv, face, &dst_face_verts[0]); + IndexArray dst_face_edges = getBaseFaceEdges(refiner, face); + conv.get_face_edges(&conv, face, &dst_face_edges[0]); + } + /* Edge relations. */ + const int num_edges = conv.get_num_edges(&conv); + for (int edge = 0; edge < num_edges; ++edge) { + /* Edge-vertices */ + IndexArray dst_edge_verts = getBaseEdgeVertices(refiner, edge); + conv.get_edge_verts(&conv, edge, &dst_edge_verts[0]); + /* Edge-faces */ + IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge); + conv.get_edge_faces(&conv, edge, &dst_edge_faces[0]); + } +#ifdef OPENSUBDIV_ORIENT_TOPOLOGY + /* Make face normals consistent. */ + bool *face_used = new bool[num_faces]; + memset(face_used, 0, sizeof(bool) * num_faces); + std::stack<int> traverse_stack; + int face_start = 0, num_traversed_faces = 0; + /* Traverse all islands. */ + while (num_traversed_faces != num_faces) { + /* Find first face of any untraversed islands. */ + while (face_used[face_start]) { + ++face_start; + } + /* Add first face to the stack. */ + traverse_stack.push(face_start); + face_used[face_start] = true; + /* Go over whole connected component. */ + while (!traverse_stack.empty()) { + int face = traverse_stack.top(); + traverse_stack.pop(); + IndexArray face_edges = getBaseFaceEdges(refiner, face); + ConstIndexArray face_verts = getBaseFaceVertices(refiner, face); + for (int edge_index = 0; edge_index < face_edges.size(); ++edge_index) { + const int edge = face_edges[edge_index]; + ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge); + if (edge_faces.size() != 2) { + /* Can't make consistent normals for non-manifolds. */ + continue; + } + ConstIndexArray edge_verts = getBaseEdgeVertices(refiner, edge); + /* Get winding of the reference face. */ + int vert0_of_face = findInArray(face_verts, edge_verts[0]), + vert1_of_face = findInArray(face_verts, edge_verts[1]); + int delta_face = get_loop_winding(vert0_of_face, vert1_of_face); + for (int edge_face = 0; edge_face < edge_faces.size(); ++edge_face) { + int other_face = edge_faces[edge_face]; + /* Never re-traverse faces, only move forward. */ + if (face_used[other_face]) { + continue; + } + IndexArray other_face_verts = getBaseFaceVertices(refiner, + other_face); + int vert0_of_other_face = findInArray(other_face_verts, + edge_verts[0]), + vert1_of_other_face = findInArray(other_face_verts, + edge_verts[1]); + int delta_other_face = get_loop_winding(vert0_of_other_face, + vert1_of_other_face); + if (delta_face * delta_other_face > 0) { + IndexArray other_face_verts = getBaseFaceVertices(refiner, + other_face), + other_face_edges = getBaseFaceEdges(refiner, + other_face); + reverse_face_loops(other_face_verts, + other_face_edges); + } + traverse_stack.push(other_face); + face_used[other_face] = true; + } + } + ++num_traversed_faces; + } + } +#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */ + /* Vertex relations */ + const int num_verts = conv.get_num_verts(&conv); + for (int vert = 0; vert < num_verts; ++vert) { + + /* Vert-Faces */ + IndexArray dst_vert_faces = getBaseVertexFaces(refiner, vert); + int num_vert_faces = conv.get_num_vert_faces(&conv, vert); + int *vert_faces = new int[num_vert_faces]; + conv.get_vert_faces(&conv, vert, vert_faces); + /* Vert-Edges */ + IndexArray dst_vert_edges = getBaseVertexEdges(refiner, vert); + int num_vert_edges = conv.get_num_vert_edges(&conv, vert); + int *vert_edges = new int[num_vert_edges]; + conv.get_vert_edges(&conv, vert, vert_edges); +#ifdef OPENSUBDIV_ORIENT_TOPOLOGY + /* ** Order vertex edges and faces in a CCW order. ** */ + memset(face_used, 0, sizeof(bool) * num_faces); + /* Number of edges and faces added to the ordered array. */ + int edge_count_ordered = 0, face_count_ordered = 0; + /* Add loose edges straight into the edges array. */ + bool has_fan_connections = false; + for (int i = 0; i < num_vert_edges; ++i) { + IndexArray edge_faces = getBaseEdgeFaces(refiner, vert_edges[i]); + if (edge_faces.size() == 0) { + dst_vert_edges[edge_count_ordered++] = vert_edges[i]; + } + else if (edge_faces.size() > 2) { + has_fan_connections = true; + } + } + if (has_fan_connections) { + /* OpenSubdiv currently doesn't give us clues how to handle + * fan face connections. and since handling such connections + * complicates the loop below we simply don't do special + * orientation for them. + */ + memcpy(&dst_vert_edges[0], vert_edges, sizeof(int) * num_vert_edges); + memcpy(&dst_vert_faces[0], vert_faces, sizeof(int) * num_vert_faces); + delete [] vert_edges; + delete [] vert_faces; + continue; + } + /* Perform at max numbder of vert-edges iteration and try to avoid + * deadlock here for malformed mesh. + */ + for (int global_iter = 0; global_iter < num_vert_edges; ++global_iter) { + /* Numbr of edges and faces which are still to be ordered. */ + int num_vert_edges_remained = num_vert_edges - edge_count_ordered, + num_vert_faces_remained = num_vert_faces - face_count_ordered; + if (num_vert_edges_remained == 0 && num_vert_faces_remained == 0) { + /* All done, nothing to do anymore. */ + break; + } + /* Face, edge and face-vertex inndex to start traversal from. */ + int face_start = -1, edge_start = -1, face_vert_start = -1; + if (num_vert_edges_remained == num_vert_faces_remained) { + /* Vertex is eitehr complete manifold or is connected to seevral + * manifold islands (hourglass-like configuration), can pick up + * random edge unused and start from it. + */ + /* TODO(sergey): Start from previous edge from which traversal + * began at previous iteration. + */ + for (int i = 0; i < num_vert_edges; ++i) { + face_start = vert_faces[i]; + if (!face_used[face_start]) { + ConstIndexArray + face_verts = getBaseFaceVertices(refiner, face_start), + face_edges = getBaseFaceEdges(refiner, face_start); + face_vert_start = findInArray(face_verts, vert); + edge_start = face_edges[face_vert_start]; + break; + } + } + } + else { + /* Special handle of non-manifold vertex. */ + for (int i = 0; i < num_vert_edges; ++i) { + bool start_found = false; + edge_start = vert_edges[i]; + IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start); + if (edge_faces.size() == 1) { + face_start = edge_faces[0]; + if (!face_used[face_start]) { + ConstIndexArray + face_verts = getBaseFaceVertices(refiner, face_start), + face_edges = getBaseFaceEdges(refiner, face_start); + face_vert_start = findInArray(face_verts, vert); + if (edge_start == face_edges[face_vert_start]) { + start_found = true; + break; + } + } + } + if (start_found) { + break; + } + /* Reset indices for sanity check below. */ + face_start = edge_start = face_vert_start = -1; + } + } + /* Sanity check. */ + assert(face_start != -1 && + edge_start != -1 && + face_vert_start != -1); + /* Traverse faces starting from the current one. */ + int edge_first = edge_start; + dst_vert_faces[face_count_ordered++] = face_start; + dst_vert_edges[edge_count_ordered++] = edge_start; + face_used[face_start] = true; + while (edge_count_ordered < num_vert_edges) { + IndexArray face_verts = getBaseFaceVertices(refiner, face_start); + IndexArray face_edges = getBaseFaceEdges(refiner, face_start); + int face_edge_start = face_vert_start; + int face_edge_next = (face_edge_start > 0) ? (face_edge_start - 1) : (face_verts.size() - 1); + Index edge_next = face_edges[face_edge_next]; + if (edge_next == edge_first) { + /* Multiple manifolds found, stop for now and handle rest + * in the next iteration. + */ + break; + } + dst_vert_edges[edge_count_ordered++] = edge_next; + if (face_count_ordered < num_vert_faces) { + IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_next); + assert(edge_faces.size() != 0); + if (edge_faces.size() == 1) { + assert(edge_faces[0] == face_start); + break; + } + else if (edge_faces.size() != 2) { + break; + } + assert(edge_faces.size() == 2); + face_start = edge_faces[(edge_faces[0] == face_start) ? 1 : 0]; + face_vert_start = findInArray(getBaseFaceEdges(refiner, face_start), edge_next); + dst_vert_faces[face_count_ordered++] = face_start; + face_used[face_start] = true; + } + edge_start = edge_next; + } + } + /* Verify ordering doesn't ruin connectivity information. */ + assert(face_count_ordered == num_vert_faces); + assert(edge_count_ordered == num_vert_edges); + check_oriented_vert_connectivity(num_vert_edges, + num_vert_faces, + vert_edges, + vert_faces, + &dst_vert_edges[0], + &dst_vert_faces[0]); + /* For the release builds we're failing mesh construction so instead + * of nasty bugs the unsupported mesh will simply disappear from the + * viewport. + */ + if (face_count_ordered != num_vert_faces || + edge_count_ordered != num_vert_edges) + { + delete [] vert_edges; + delete [] vert_faces; + return false; + } +#else /* OPENSUBDIV_ORIENT_TOPOLOGY */ + memcpy(&dst_vert_edges[0], vert_edges, sizeof(int) * num_vert_edges); + memcpy(&dst_vert_faces[0], vert_faces, sizeof(int) * num_vert_faces); +#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */ + delete [] vert_edges; + delete [] vert_faces; + } +#ifdef OPENSUBDIV_ORIENT_TOPOLOGY + delete [] face_used; +#endif + populateBaseLocalIndices(refiner); + return true; +}; + +template <> +inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags( + TopologyRefiner& refiner, + const OpenSubdiv_Converter& conv) +{ + typedef OpenSubdiv::Sdc::Crease Crease; + + int num_edges = conv.get_num_edges(&conv); + for (int edge = 0; edge < num_edges; ++edge) { + float sharpness; + ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge); + if (edge_faces.size() == 2) { + sharpness = conv.get_edge_sharpness(&conv, edge); + } + else { + /* Non-manifold edges must be sharp. */ + sharpness = Crease::SHARPNESS_INFINITE; + } + setBaseEdgeSharpness(refiner, edge, sharpness); + } + + /* OpenSubdiv expects non-manifold vertices to be sharp but at the + * time it handles correct cases when vertex is a corner of plane. + * Currently mark verts which are adjacent to a loose edge as sharp, + * but this decision needs some more investigation. + */ + int num_vert = conv.get_num_verts(&conv); + for (int vert = 0; vert < num_vert; ++vert) { + ConstIndexArray vert_edges = getBaseVertexEdges(refiner, vert); + for (int edge_index = 0; edge_index < vert_edges.size(); ++edge_index) { + int edge = vert_edges[edge_index]; + ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge); + if (edge_faces.size() == 0) { + setBaseVertexSharpness(refiner, vert, Crease::SHARPNESS_INFINITE); + break; + } + } + if (vert_edges.size() == 2) { + int edge0 = vert_edges[0], + edge1 = vert_edges[1]; + float sharpness0 = conv.get_edge_sharpness(&conv, edge0), + sharpness1 = conv.get_edge_sharpness(&conv, edge1); + float sharpness = std::min(sharpness0, sharpness1); + setBaseVertexSharpness(refiner, vert, sharpness); + } + } + + return true; +} + +template <> +inline void TopologyRefinerFactory<OpenSubdiv_Converter>::reportInvalidTopology( + TopologyError /*errCode*/, + const char *msg, + const OpenSubdiv_Converter& /*mesh*/) +{ + printf("OpenSubdiv Error: %s\n", msg); +} + +} /* namespace Far */ +} /* namespace OPENSUBDIV_VERSION */ +} /* namespace OpenSubdiv */ + +namespace { + +OpenSubdiv::Sdc::SchemeType get_capi_scheme_type(OpenSubdiv_SchemeType type) +{ + switch(type) { + case OSD_SCHEME_BILINEAR: + return OpenSubdiv::Sdc::SCHEME_BILINEAR; + case OSD_SCHEME_CATMARK: + return OpenSubdiv::Sdc::SCHEME_CATMARK; + case OSD_SCHEME_LOOP: + return OpenSubdiv::Sdc::SCHEME_LOOP; + } + assert(!"Unknown sceme type passed via C-API"); + return OpenSubdiv::Sdc::SCHEME_CATMARK; +} + +} /* namespace */ + +struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr( + OpenSubdiv_Converter *converter) +{ + typedef OpenSubdiv::Sdc::Options Options; + + using OpenSubdiv::Far::TopologyRefinerFactory; + OpenSubdiv::Sdc::SchemeType scheme_type = + get_capi_scheme_type(converter->get_type(converter)); + Options options; + options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY); + options.SetCreasingMethod(Options::CREASE_UNIFORM); + options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL); + + TopologyRefinerFactory<OpenSubdiv_Converter>::Options + topology_options(scheme_type, options); +#ifdef OPENSUBDIV_VALIDATE_TOPOLOGY + topology_options.validateFullTopology = true; +#endif + /* We don't use guarded allocation here so we can re-use the refiner + * for GL mesh creation directly. + */ + return (struct OpenSubdiv_TopologyRefinerDescr*) + TopologyRefinerFactory<OpenSubdiv_Converter>::Create( + *converter, + topology_options); +} + +void openSubdiv_deleteTopologyRefinerDescr( + OpenSubdiv_TopologyRefinerDescr *topology_refiner) +{ + delete (OpenSubdiv::Far::TopologyRefiner *)topology_refiner; +} + +int openSubdiv_topologyRefinerGetSubdivLevel( + const OpenSubdiv_TopologyRefinerDescr *topology_refiner) +{ + using OpenSubdiv::Far::TopologyRefiner; + const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + return refiner->GetMaxLevel(); +} + +int openSubdiv_topologyRefinerGetNumVerts( + const OpenSubdiv_TopologyRefinerDescr *topology_refiner) +{ + using OpenSubdiv::Far::TopologyLevel; + using OpenSubdiv::Far::TopologyRefiner; + const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyLevel &base_level = refiner->GetLevel(0); + return base_level.GetNumVertices(); +} + +int openSubdiv_topologyRefinerGetNumEdges( + const OpenSubdiv_TopologyRefinerDescr *topology_refiner) +{ + using OpenSubdiv::Far::TopologyLevel; + using OpenSubdiv::Far::TopologyRefiner; + const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyLevel &base_level = refiner->GetLevel(0); + return base_level.GetNumEdges(); +} + +int openSubdiv_topologyRefinerGetNumFaces( + const OpenSubdiv_TopologyRefinerDescr *topology_refiner) +{ + using OpenSubdiv::Far::TopologyLevel; + using OpenSubdiv::Far::TopologyRefiner; + const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyLevel &base_level = refiner->GetLevel(0); + return base_level.GetNumFaces(); +} + +int openSubdiv_topologyRefinerGetNumFaceVerts( + const OpenSubdiv_TopologyRefinerDescr *topology_refiner, + int face) +{ + using OpenSubdiv::Far::TopologyLevel; + using OpenSubdiv::Far::TopologyRefiner; + const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyLevel &base_level = refiner->GetLevel(0); + return base_level.GetFaceVertices(face).size(); +} + +int openSubdiv_topologyRefnerCompareConverter( + const OpenSubdiv_TopologyRefinerDescr *topology_refiner, + OpenSubdiv_Converter *converter) +{ + using OpenSubdiv::Far::ConstIndexArray; + using OpenSubdiv::Far::TopologyRefiner; + using OpenSubdiv::Far::TopologyLevel; + const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyLevel &base_level = refiner->GetLevel(0); + const int num_verts = base_level.GetNumVertices(); + const int num_edges = base_level.GetNumEdges(); + const int num_faces = base_level.GetNumFaces(); + /* Quick preliminary check. */ + OpenSubdiv::Sdc::SchemeType scheme_type = + get_capi_scheme_type(converter->get_type(converter)); + if (scheme_type != refiner->GetSchemeType()) { + return false; + } + if (converter->get_num_verts(converter) != num_verts || + converter->get_num_edges(converter) != num_edges || + converter->get_num_faces(converter) != num_faces) + { + return false; + } + /* Compare all edges. */ + for (int edge = 0; edge < num_edges; ++edge) { + ConstIndexArray edge_verts = base_level.GetEdgeVertices(edge); + int conv_edge_verts[2]; + converter->get_edge_verts(converter, edge, conv_edge_verts); + if (conv_edge_verts[0] != edge_verts[0] || + conv_edge_verts[1] != edge_verts[1]) + { + return false; + } + } + /* Compare all faces. */ + std::vector<int> conv_face_verts; + for (int face = 0; face < num_faces; ++face) { + ConstIndexArray face_verts = base_level.GetFaceVertices(face); + if (face_verts.size() != converter->get_num_face_verts(converter, + face)) + { + return false; + } + conv_face_verts.resize(face_verts.size()); + converter->get_face_verts(converter, face, &conv_face_verts[0]); + bool direct_match = true; + for (int i = 0; i < face_verts.size(); ++i) { + if (conv_face_verts[i] != face_verts[i]) { + direct_match = false; + break; + } + } + if (!direct_match) { + /* If face didn't match in direct direction we also test if it + * matches in reversed direction. This is because conversion might + * reverse loops to make normals consistent. + */ +#ifdef OPENSUBDIV_ORIENT_TOPOLOGY + reverse_face_verts(&conv_face_verts[0], conv_face_verts.size()); + for (int i = 0; i < face_verts.size(); ++i) { + if (conv_face_verts[i] != face_verts[i]) { + return false; + } + } +#else + return false; +#endif + } + } + /* Compare sharpness. */ + for (int edge = 0; edge < num_edges; ++edge) { + ConstIndexArray edge_faces = base_level.GetEdgeFaces(edge); + float sharpness = base_level.GetEdgeSharpness(edge); + float conv_sharpness; + if (edge_faces.size() == 2) { + conv_sharpness = converter->get_edge_sharpness(converter, edge); + } + else { + conv_sharpness = OpenSubdiv::Sdc::Crease::SHARPNESS_INFINITE; + } + if (sharpness != conv_sharpness) { + return false; + } + } + return true; +} |