mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-06-04 11:25:44 +08:00
180 lines
7.1 KiB
C++
180 lines
7.1 KiB
C++
// Copyright 2016 The Draco Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
#include "mesh/mesh_attribute_corner_table.h"
|
|
|
|
#include "mesh/mesh_misc_functions.h"
|
|
|
|
namespace draco {
|
|
|
|
MeshAttributeCornerTable::MeshAttributeCornerTable()
|
|
: no_interior_seams_(true), corner_table_(nullptr) {}
|
|
|
|
bool MeshAttributeCornerTable::InitEmpty(const CornerTable *table) {
|
|
if (table == nullptr)
|
|
return false;
|
|
is_edge_on_seam_.assign(table->num_corners(), false);
|
|
is_vertex_on_seam_.assign(table->num_vertices(), false);
|
|
corner_to_vertex_map_.assign(table->num_corners(), kInvalidVertexIndex);
|
|
vertex_to_attribute_entry_id_map_.reserve(table->num_vertices());
|
|
vertex_to_left_most_corner_map_.reserve(table->num_vertices());
|
|
corner_table_ = table;
|
|
no_interior_seams_ = true;
|
|
return true;
|
|
}
|
|
|
|
bool MeshAttributeCornerTable::InitFromAttribute(const Mesh *mesh,
|
|
const CornerTable *table,
|
|
const PointAttribute *att) {
|
|
if (!InitEmpty(table))
|
|
return false;
|
|
|
|
// Find all necessary data for encoding attributes. For now we check which of
|
|
// the mesh vertices is part of an attribute seam, because seams require
|
|
// special handling.
|
|
for (int c = 0; c < corner_table_->num_corners(); ++c) {
|
|
const FaceIndex f = corner_table_->Face(CornerIndex(c));
|
|
if (corner_table_->IsDegenerated(f))
|
|
continue; // Ignore corners on degenerated faces.
|
|
const CornerIndex opp_corner = corner_table_->Opposite(CornerIndex(c));
|
|
if (opp_corner < 0) {
|
|
// Boundary. Mark it as seam edge.
|
|
is_edge_on_seam_[c] = true;
|
|
// Mark seam vertices.
|
|
VertexIndex v;
|
|
v = corner_table_->Vertex(corner_table_->Next(CornerIndex(c)));
|
|
is_vertex_on_seam_[v.value()] = true;
|
|
v = corner_table_->Vertex(corner_table_->Previous(CornerIndex(c)));
|
|
is_vertex_on_seam_[v.value()] = true;
|
|
continue;
|
|
}
|
|
if (opp_corner < c)
|
|
continue; // Opposite corner was already processed.
|
|
|
|
CornerIndex act_c(c), act_sibling_c(opp_corner);
|
|
for (int i = 0; i < 2; ++i) {
|
|
// Get the sibling corners. I.e., the two corners attached to the same
|
|
// vertex but divided by the seam edge.
|
|
act_c = corner_table_->Next(act_c);
|
|
act_sibling_c = corner_table_->Previous(act_sibling_c);
|
|
const PointIndex point_id = CornerToPointId(act_c.value(), mesh);
|
|
const PointIndex sibling_point_id =
|
|
CornerToPointId(act_sibling_c.value(), mesh);
|
|
if (att->mapped_index(point_id) != att->mapped_index(sibling_point_id)) {
|
|
no_interior_seams_ = false;
|
|
is_edge_on_seam_[c] = true;
|
|
is_edge_on_seam_[opp_corner.value()] = true;
|
|
// Mark seam vertices.
|
|
is_vertex_on_seam_[corner_table_
|
|
->Vertex(corner_table_->Next(CornerIndex(c)))
|
|
.value()] = true;
|
|
is_vertex_on_seam_[corner_table_
|
|
->Vertex(corner_table_->Previous(CornerIndex(c)))
|
|
.value()] = true;
|
|
is_vertex_on_seam_
|
|
[corner_table_->Vertex(corner_table_->Next(opp_corner)).value()] =
|
|
true;
|
|
is_vertex_on_seam_[corner_table_
|
|
->Vertex(corner_table_->Previous(opp_corner))
|
|
.value()] = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
RecomputeVertices(mesh, att);
|
|
return true;
|
|
}
|
|
|
|
void MeshAttributeCornerTable::AddSeamEdge(CornerIndex c) {
|
|
is_edge_on_seam_[c.value()] = true;
|
|
// Mark seam vertices.
|
|
is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Next(c)).value()] =
|
|
true;
|
|
is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Previous(c))
|
|
.value()] = true;
|
|
|
|
const CornerIndex opp_corner = corner_table_->Opposite(c);
|
|
if (opp_corner >= 0) {
|
|
no_interior_seams_ = false;
|
|
is_edge_on_seam_[opp_corner.value()] = true;
|
|
is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Next(opp_corner))
|
|
.value()] = true;
|
|
is_vertex_on_seam_
|
|
[corner_table_->Vertex(corner_table_->Previous(opp_corner)).value()] =
|
|
true;
|
|
}
|
|
}
|
|
|
|
void MeshAttributeCornerTable::RecomputeVertices(const Mesh *mesh,
|
|
const PointAttribute *att) {
|
|
if (mesh != nullptr && att != nullptr) {
|
|
RecomputeVerticesInternal<true>(mesh, att);
|
|
} else {
|
|
RecomputeVerticesInternal<false>(nullptr, nullptr);
|
|
}
|
|
}
|
|
|
|
template <bool init_vertex_to_attribute_entry_map>
|
|
void MeshAttributeCornerTable::RecomputeVerticesInternal(
|
|
const Mesh *mesh, const PointAttribute *att) {
|
|
int num_new_vertices = 0;
|
|
for (VertexIndex v(0); v < corner_table_->num_vertices(); ++v) {
|
|
const CornerIndex c = corner_table_->LeftMostCorner(v);
|
|
if (c < 0)
|
|
continue; // Isolated vertex?
|
|
AttributeValueIndex first_vert_id(num_new_vertices++);
|
|
if (init_vertex_to_attribute_entry_map) {
|
|
const PointIndex point_id = CornerToPointId(c.value(), mesh);
|
|
vertex_to_attribute_entry_id_map_.push_back(att->mapped_index(point_id));
|
|
} else {
|
|
// Identity mapping
|
|
vertex_to_attribute_entry_id_map_.push_back(first_vert_id);
|
|
}
|
|
CornerIndex first_c = c;
|
|
CornerIndex act_c;
|
|
// Check if the vertex is on a seam edge, if it is we need to find the first
|
|
// attribute entry on the seam edge when traversing in the ccw direction.
|
|
if (is_vertex_on_seam_[v.value()]) {
|
|
// Try to swing left on the modified corner table. We need to get the
|
|
// first corner that defines an attribute seam.
|
|
act_c = SwingLeft(first_c);
|
|
while (act_c >= 0) {
|
|
first_c = act_c;
|
|
act_c = SwingLeft(act_c);
|
|
}
|
|
}
|
|
corner_to_vertex_map_[first_c.value()] = VertexIndex(first_vert_id.value());
|
|
vertex_to_left_most_corner_map_.push_back(first_c);
|
|
act_c = corner_table_->SwingRight(first_c);
|
|
while (act_c >= 0 && act_c != first_c) {
|
|
if (IsCornerOppositeToSeamEdge(corner_table_->Next(act_c))) {
|
|
first_vert_id = AttributeValueIndex(num_new_vertices++);
|
|
if (init_vertex_to_attribute_entry_map) {
|
|
const PointIndex point_id = CornerToPointId(act_c.value(), mesh);
|
|
vertex_to_attribute_entry_id_map_.push_back(
|
|
att->mapped_index(point_id));
|
|
} else {
|
|
// Identity mapping.
|
|
vertex_to_attribute_entry_id_map_.push_back(first_vert_id);
|
|
}
|
|
vertex_to_left_most_corner_map_.push_back(act_c);
|
|
}
|
|
corner_to_vertex_map_[act_c.value()] = VertexIndex(first_vert_id.value());
|
|
act_c = corner_table_->SwingRight(act_c);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace draco
|