Blender V4.3
mesh_topology_compare.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Foundation
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later
4 *
5 * Author: Sergey Sharybin. */
6
8
9#include <cassert>
10#include <cstring>
11#include <opensubdiv/sdc/crease.h>
12#include <vector>
13
15
16namespace blender::opensubdiv {
17
19// Quick preliminary checks.
20
21static int getEffectiveNumEdges(const OpenSubdiv_Converter *converter)
22{
23 if (converter->getNumEdges == nullptr) {
24 return 0;
25 }
26
27 return converter->getNumEdges(converter);
28}
29
30static bool isEqualGeometryCounters(const MeshTopology &mesh_topology,
31 const OpenSubdiv_Converter *converter)
32{
33 if (converter->getNumVertices(converter) != mesh_topology.getNumVertices()) {
34 return false;
35 }
36 if (converter->getNumFaces(converter) != mesh_topology.getNumFaces()) {
37 return false;
38 }
39 if (getEffectiveNumEdges(converter) != mesh_topology.getNumEdges()) {
40 return false;
41 }
42
43 return true;
44}
45
47// Geometry.
48
49// Edges.
50
51static bool isEqualGeometryEdge(const MeshTopology &mesh_topology,
52 const OpenSubdiv_Converter *converter)
53{
54 const int num_requested_edges = getEffectiveNumEdges(converter);
55 if (num_requested_edges != mesh_topology.getNumEdges()) {
56 return false;
57 }
58
59 // NOTE: Ignoring the sharpness we don't really care of the content of the
60 // edges, they should be in the consistent state with faces and face-vertices.
61 // If that's not the case the mesh is invalid and comparison can not happen
62 // reliably.
63 //
64 // For sharpness it is important to know that edges are connecting same pair
65 // of vertices. But since sharpness is stored sparesly the connectivity will
66 // be checked when comparing edge sharpness.
67
68 return true;
69}
70
71// Faces.
72
73static bool isEqualGeometryFace(const MeshTopology &mesh_topology,
74 const OpenSubdiv_Converter *converter)
75{
76 const int num_requested_faces = converter->getNumFaces(converter);
77 if (num_requested_faces != mesh_topology.getNumFaces()) {
78 return false;
79 }
80
81 std::vector<int> vertices_of_face;
82 for (int face_index = 0; face_index < num_requested_faces; ++face_index) {
83 int num_face_vertices = converter->getNumFaceVertices(converter, face_index);
84 if (mesh_topology.getNumFaceVertices(face_index) != num_face_vertices) {
85 return false;
86 }
87
88 vertices_of_face.resize(num_face_vertices);
89 converter->getFaceVertices(converter, face_index, vertices_of_face.data());
90
91 if (!mesh_topology.isFaceVertexIndicesEqual(face_index, vertices_of_face)) {
92 return false;
93 }
94 }
95
96 return true;
97}
98
99// Geometry comparison entry point.
100
101static bool isEqualGeometry(const MeshTopology &mesh_topology,
102 const OpenSubdiv_Converter *converter)
103{
104 if (!isEqualGeometryEdge(mesh_topology, converter)) {
105 return false;
106 }
107 if (!isEqualGeometryFace(mesh_topology, converter)) {
108 return false;
109 }
110
111 return true;
112}
113
115// Geometry tags.
116
117// Vertices.
118
119// TODO(sergey): Make this function usable by factory as well.
121 const int vertex_index)
122{
123 if (converter->isInfiniteSharpVertex != nullptr &&
124 converter->isInfiniteSharpVertex(converter, vertex_index))
125 {
126 return OpenSubdiv::Sdc::Crease::SHARPNESS_INFINITE;
127 }
128
129 if (converter->getVertexSharpness != nullptr) {
130 return converter->getVertexSharpness(converter, vertex_index);
131 }
132
133 return 0.0f;
134}
135
136static bool isEqualVertexTags(const MeshTopology &mesh_topology,
137 const OpenSubdiv_Converter *converter)
138{
139 const int num_vertices = mesh_topology.getNumVertices();
140 for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
141 const float current_sharpness = mesh_topology.getVertexSharpness(vertex_index);
142 const float requested_sharpness = getEffectiveVertexSharpness(converter, vertex_index);
143
144 if (current_sharpness != requested_sharpness) {
145 return false;
146 }
147 }
148
149 return true;
150}
151
152// Edges.
153
154// TODO(sergey): Make this function usable by factory as well.
155static float getEffectiveEdgeSharpness(const OpenSubdiv_Converter *converter, const int edge_index)
156{
157 if (converter->getEdgeSharpness != nullptr) {
158 return converter->getEdgeSharpness(converter, edge_index);
159 }
160
161 return 0.0f;
162}
163
164static bool isEqualEdgeTags(const MeshTopology &mesh_topology,
165 const OpenSubdiv_Converter *converter)
166{
167 const int num_edges = mesh_topology.getNumEdges();
168 for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
169 const float current_sharpness = mesh_topology.getEdgeSharpness(edge_index);
170 const float requested_sharpness = getEffectiveEdgeSharpness(converter, edge_index);
171
172 if (current_sharpness != requested_sharpness) {
173 return false;
174 }
175
176 if (current_sharpness < 1e-6f) {
177 continue;
178 }
179
180 int requested_edge_vertices[2];
181 converter->getEdgeVertices(converter, edge_index, requested_edge_vertices);
182 if (!mesh_topology.isEdgeEqual(
183 edge_index, requested_edge_vertices[0], requested_edge_vertices[1]))
184 {
185 return false;
186 }
187 }
188
189 return true;
190}
191
192// Tags comparison entry point.
193
194static bool isEqualTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
195{
196 if (!isEqualVertexTags(mesh_topology, converter)) {
197 return false;
198 }
199 if (!isEqualEdgeTags(mesh_topology, converter)) {
200 return false;
201 }
202
203 return true;
204}
205
207// Entry point.
208
210{
211 // Preliminary checks.
212 if (!isEqualGeometryCounters(*this, converter)) {
213 return false;
214 }
215
216 // Geometry.
217 if (!isEqualGeometry(*this, converter)) {
218 return false;
219 }
220
221 // Tags.
222 if (!isEqualTags(*this, converter)) {
223 return false;
224 }
225
226 return true;
227}
228
229} // namespace blender::opensubdiv
bool isEqualToConverter(const OpenSubdiv_Converter *converter) const
bool isEdgeEqual(int edge_index, int expected_v1, int expected_v2) const
float getEdgeSharpness(int edge_index) const
int getNumFaceVertices(int face_index) const
bool isFaceVertexIndicesEqual(int face_index, int num_expected_face_vertex_indices, const int *expected_face_vertex_indices) const
float getVertexSharpness(int vertex_index) const
static bool isEqualVertexTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
static bool isEqualGeometry(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
static int getEffectiveNumEdges(const OpenSubdiv_Converter *converter)
static bool isEqualEdgeTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
static float getEffectiveEdgeSharpness(const OpenSubdiv_Converter *converter, const int edge_index)
static float getEffectiveVertexSharpness(const OpenSubdiv_Converter *converter, const int vertex_index)
static bool isEqualGeometryCounters(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
static bool isEqualGeometryEdge(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
static bool isEqualTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
static bool isEqualGeometryFace(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
int(* getNumFaceVertices)(const OpenSubdiv_Converter *converter, const int face_index)
int(* getNumEdges)(const OpenSubdiv_Converter *converter)
float(* getEdgeSharpness)(const OpenSubdiv_Converter *converter, const int edge_index)
int(* getNumFaces)(const OpenSubdiv_Converter *converter)
void(* getFaceVertices)(const OpenSubdiv_Converter *converter, const int face_index, int *face_vertices)
bool(* isInfiniteSharpVertex)(const OpenSubdiv_Converter *converter, const int vertex_index)
float(* getVertexSharpness)(const OpenSubdiv_Converter *converter, const int vertex_index)
void(* getEdgeVertices)(const OpenSubdiv_Converter *converter, const int edge_index, int edge_vertices[2])
int(* getNumVertices)(const OpenSubdiv_Converter *converter)