tornavis/intern/opensubdiv/internal/topology/mesh_topology_compare.cc

230 lines
6.0 KiB
C++

/* SPDX-FileCopyrightText: 2020 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Author: Sergey Sharybin. */
#include "internal/topology/mesh_topology.h"
#include <cassert>
#include <cstring>
#include <opensubdiv/sdc/crease.h>
#include "internal/base/type.h"
#include "opensubdiv_converter_capi.hh"
namespace blender {
namespace opensubdiv {
namespace {
////////////////////////////////////////////////////////////////////////////////
// Quick preliminary checks.
int getEffectiveNumEdges(const OpenSubdiv_Converter *converter)
{
if (converter->getNumEdges == nullptr) {
return 0;
}
return converter->getNumEdges(converter);
}
bool isEqualGeometryCounters(const MeshTopology &mesh_topology,
const OpenSubdiv_Converter *converter)
{
if (converter->getNumVertices(converter) != mesh_topology.getNumVertices()) {
return false;
}
if (converter->getNumFaces(converter) != mesh_topology.getNumFaces()) {
return false;
}
if (getEffectiveNumEdges(converter) != mesh_topology.getNumEdges()) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Geometry.
// Edges.
bool isEqualGeometryEdge(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
{
const int num_requested_edges = getEffectiveNumEdges(converter);
if (num_requested_edges != mesh_topology.getNumEdges()) {
return false;
}
// NOTE: Ignoring the sharpness we don't really care of the content of the
// edges, they should be in the consistent state with faces and face-vertices.
// If that's not the case the mesh is invalid and comparison can not happen
// reliably.
//
// For sharpness it is important to know that edges are connecting same pair
// of vertices. But since sharpness is stored sparesly the connectivity will
// be checked when comparing edge sharpness.
return true;
}
// Faces.
bool isEqualGeometryFace(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
{
const int num_requested_faces = converter->getNumFaces(converter);
if (num_requested_faces != mesh_topology.getNumFaces()) {
return false;
}
vector<int> vertices_of_face;
for (int face_index = 0; face_index < num_requested_faces; ++face_index) {
int num_face_vertices = converter->getNumFaceVertices(converter, face_index);
if (mesh_topology.getNumFaceVertices(face_index) != num_face_vertices) {
return false;
}
vertices_of_face.resize(num_face_vertices);
converter->getFaceVertices(converter, face_index, vertices_of_face.data());
if (!mesh_topology.isFaceVertexIndicesEqual(face_index, vertices_of_face)) {
return false;
}
}
return true;
}
// Geometry comparison entry point.
bool isEqualGeometry(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
{
if (!isEqualGeometryEdge(mesh_topology, converter)) {
return false;
}
if (!isEqualGeometryFace(mesh_topology, converter)) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Geometry tags.
// Vertices.
// TODO(sergey): Make this function usable by factory as well.
float getEffectiveVertexSharpness(const OpenSubdiv_Converter *converter, const int vertex_index)
{
if (converter->isInfiniteSharpVertex != nullptr &&
converter->isInfiniteSharpVertex(converter, vertex_index))
{
return OpenSubdiv::Sdc::Crease::SHARPNESS_INFINITE;
}
if (converter->getVertexSharpness != nullptr) {
return converter->getVertexSharpness(converter, vertex_index);
}
return 0.0f;
}
bool isEqualVertexTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
{
const int num_vertices = mesh_topology.getNumVertices();
for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
const float current_sharpness = mesh_topology.getVertexSharpness(vertex_index);
const float requested_sharpness = getEffectiveVertexSharpness(converter, vertex_index);
if (current_sharpness != requested_sharpness) {
return false;
}
}
return true;
}
// Edges.
// TODO(sergey): Make this function usable by factory as well.
float getEffectiveEdgeSharpness(const OpenSubdiv_Converter *converter, const int edge_index)
{
if (converter->getEdgeSharpness != nullptr) {
return converter->getEdgeSharpness(converter, edge_index);
}
return 0.0f;
}
bool isEqualEdgeTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
{
const int num_edges = mesh_topology.getNumEdges();
for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
const float current_sharpness = mesh_topology.getEdgeSharpness(edge_index);
const float requested_sharpness = getEffectiveEdgeSharpness(converter, edge_index);
if (current_sharpness != requested_sharpness) {
return false;
}
if (current_sharpness < 1e-6f) {
continue;
}
int requested_edge_vertices[2];
converter->getEdgeVertices(converter, edge_index, requested_edge_vertices);
if (!mesh_topology.isEdgeEqual(
edge_index, requested_edge_vertices[0], requested_edge_vertices[1])) {
return false;
}
}
return true;
}
// Tags comparison entry point.
bool isEqualTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter)
{
if (!isEqualVertexTags(mesh_topology, converter)) {
return false;
}
if (!isEqualEdgeTags(mesh_topology, converter)) {
return false;
}
return true;
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// Entry point.
bool MeshTopology::isEqualToConverter(const OpenSubdiv_Converter *converter) const
{
// Preliminary checks.
if (!isEqualGeometryCounters(*this, converter)) {
return false;
}
// Geometry.
if (!isEqualGeometry(*this, converter)) {
return false;
}
// Tags.
if (!isEqualTags(*this, converter)) {
return false;
}
return true;
}
} // namespace opensubdiv
} // namespace blender