This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/intern/opensubdiv/internal/topology/mesh_topology.cc
Sergey Sharybin efa4ae17f0 OpenSubdiv: Only store edges topology for non-smooth edges
This change makes it so vertices of edge are only stored when edge
has non-zero crease. This allows to lower memory footprint of 1.5M
faces from 78 MiB to 54 MiB in the case all creases are zero.

Meshes with crease are more hard to predict due to array-based
storage, so it all depends on index of edge with crease. Worst case
(all edges are creased) still stays at 78 MiB.
2020-05-27 12:07:16 +02:00

274 lines
7.1 KiB
C++

// Copyright 2020 Blender Foundation. All rights reserved.
//
// 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.
//
// Author: Sergey Sharybin
#include "internal/topology/mesh_topology.h"
#include <cassert>
namespace blender {
namespace opensubdiv {
MeshTopology::MeshTopology() : num_vertices_(0), num_edges_(0), num_faces_(0)
{
}
MeshTopology::~MeshTopology()
{
}
////////////////////////////////////////////////////////////////////////////////
// Vertices.
void MeshTopology::setNumVertices(int num_vertices)
{
num_vertices_ = num_vertices;
}
int MeshTopology::getNumVertices() const
{
return num_vertices_;
}
void MeshTopology::setVertexSharpness(int vertex_index, float sharpness)
{
assert(vertex_index >= 0);
assert(vertex_index < getNumVertices());
ensureVertexTagsSize(vertex_index + 1);
vertex_tags_[vertex_index].sharpness = sharpness;
}
float MeshTopology::getVertexSharpness(int vertex_index) const
{
assert(vertex_index >= 0);
assert(vertex_index < getNumVertices());
if (vertex_index >= vertex_tags_.size()) {
// Sharpness for the vertex was never provided.
return 0.0f;
}
return vertex_tags_[vertex_index].sharpness;
}
void MeshTopology::ensureVertexTagsSize(int num_vertices)
{
if (vertex_tags_.size() < num_vertices) {
vertex_tags_.resize(num_vertices);
}
}
////////////////////////////////////////////////////////////////////////////////
// Edges.
void MeshTopology::setNumEdges(int num_edges)
{
num_edges_ = num_edges;
}
int MeshTopology::getNumEdges() const
{
return num_edges_;
}
void MeshTopology::setEdgeVertexIndices(int edge_index, int v1, int v2)
{
assert(edge_index >= 0);
assert(edge_index < getNumEdges());
assert(v1 >= 0);
assert(v1 < getNumVertices());
assert(v2 >= 0);
assert(v2 < getNumVertices());
ensureNumEdgesAtLeast(edge_index + 1);
Edge &edge = edges_[edge_index];
edge.v1 = v1;
edge.v2 = v2;
}
void MeshTopology::getEdgeVertexIndices(int edge_index, int *v1, int *v2) const
{
assert(edge_index >= 0);
assert(edge_index < getNumEdges());
if (edge_index >= edges_.size()) {
*v1 = -1;
*v1 = -1;
return;
}
const Edge &edge = edges_[edge_index];
*v1 = edge.v1;
*v2 = edge.v2;
}
bool MeshTopology::isEdgeEqual(int edge_index, int expected_v1, int expected_v2) const
{
assert(edge_index >= 0);
assert(edge_index < getNumEdges());
if (edge_index >= edges_.size()) {
return false;
}
const Edge &edge = edges_[edge_index];
return edge.v1 == expected_v1 && edge.v2 == expected_v2;
}
void MeshTopology::setEdgeSharpness(int edge_index, float sharpness)
{
assert(edge_index >= 0);
assert(edge_index < getNumEdges());
if (sharpness < 1e-6f) {
return;
}
ensureEdgeTagsSize(edge_index + 1);
edge_tags_[edge_index].sharpness = sharpness;
}
float MeshTopology::getEdgeSharpness(int edge_index) const
{
assert(edge_index >= 0);
if (edge_index >= edge_tags_.size()) {
// NOTE: It's possible that full topology is not known and that there was
// never sharpness assigned to any of the edges.
return 0.0f;
}
return edge_tags_[edge_index].sharpness;
}
void MeshTopology::ensureNumEdgesAtLeast(int num_edges)
{
if (edges_.size() < num_edges) {
edges_.resize(num_edges);
}
}
void MeshTopology::ensureEdgeTagsSize(int num_edges)
{
if (edge_tags_.size() < num_edges) {
edge_tags_.resize(num_edges);
}
}
////////////////////////////////////////////////////////////////////////////////
// Faces.
void MeshTopology::setNumFaces(int num_faces)
{
num_faces_ = num_faces;
// NOTE: Extra element to store fake face past the last real one to make it
// possible to calculate number of verticies in the last face.
faces_first_vertex_index_.resize(num_faces + 1, 0);
}
int MeshTopology::getNumFaces() const
{
return num_faces_;
}
void MeshTopology::setNumFaceVertices(int face_index, int num_face_vertices)
{
assert(face_index >= 0);
assert(face_index < getNumFaces());
faces_first_vertex_index_[face_index + 1] = faces_first_vertex_index_[face_index] +
num_face_vertices;
}
int MeshTopology::getNumFaceVertices(int face_index) const
{
assert(face_index >= 0);
assert(face_index < getNumFaces());
return faces_first_vertex_index_[face_index + 1] - faces_first_vertex_index_[face_index];
}
void MeshTopology::setFaceVertexIndices(int face_index,
int num_face_vertex_indices,
const int *face_vertex_indices)
{
assert(face_index >= 0);
assert(face_index < getNumFaces());
assert(num_face_vertex_indices == getNumFaceVertices(face_index));
int *face_vertex_indices_storage = getFaceVertexIndicesStorage(face_index);
memcpy(face_vertex_indices_storage, face_vertex_indices, sizeof(int) * num_face_vertex_indices);
}
bool MeshTopology::isFaceVertexIndicesEqual(int face_index,
int num_expected_face_vertex_indices,
const int *expected_face_vertex_indices) const
{
assert(face_index >= 0);
assert(face_index < getNumFaces());
if (getNumFaceVertices(face_index) != num_expected_face_vertex_indices) {
return false;
}
const int *face_vertex_indices_storage = getFaceVertexIndicesStorage(face_index);
return memcmp(face_vertex_indices_storage,
expected_face_vertex_indices,
sizeof(int) * num_expected_face_vertex_indices) == 0;
}
bool MeshTopology::isFaceVertexIndicesEqual(int face_index,
const vector<int> &expected_face_vertex_indices) const
{
return isFaceVertexIndicesEqual(
face_index, expected_face_vertex_indices.size(), expected_face_vertex_indices.data());
}
int *MeshTopology::getFaceVertexIndicesStorage(int face_index)
{
const MeshTopology *const_this = this;
return const_cast<int *>(const_this->getFaceVertexIndicesStorage(face_index));
}
const int *MeshTopology::getFaceVertexIndicesStorage(int face_index) const
{
assert(face_index >= 0);
assert(face_index < getNumFaces());
const int offset = faces_first_vertex_index_[face_index];
return face_vertex_indices_.data() + offset;
}
////////////////////////////////////////////////////////////////////////////////
// Pipeline related.
void MeshTopology::finishResizeTopology()
{
if (!faces_first_vertex_index_.empty()) {
face_vertex_indices_.resize(faces_first_vertex_index_.back());
}
}
} // namespace opensubdiv
} // namespace blender