1 // Copyright 2016 The Draco Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 #ifndef DRACO_COMPRESSION_MESH_TRAVERSER_MESH_TRAVERSAL_SEQUENCER_H_
16 #define DRACO_COMPRESSION_MESH_TRAVERSER_MESH_TRAVERSAL_SEQUENCER_H_
17 
18 #include "draco/attributes/geometry_indices.h"
19 #include "draco/compression/attributes/mesh_attribute_indices_encoding_data.h"
20 #include "draco/compression/attributes/points_sequencer.h"
21 #include "draco/mesh/mesh.h"
22 
23 namespace draco {
24 
25 // Sequencer that generates point sequence in an order given by a deterministic
26 // traversal on the mesh surface. Note that all attributes encoded with this
27 // sequence must share the same connectivity.
28 // TODO(hemmer): Consider refactoring such that this is an observer.
29 template <class TraverserT>
30 class MeshTraversalSequencer : public PointsSequencer {
31  public:
MeshTraversalSequencer(const Mesh * mesh,const MeshAttributeIndicesEncodingData * encoding_data)32   MeshTraversalSequencer(const Mesh *mesh,
33                          const MeshAttributeIndicesEncodingData *encoding_data)
34       : mesh_(mesh), encoding_data_(encoding_data), corner_order_(nullptr) {}
SetTraverser(const TraverserT & t)35   void SetTraverser(const TraverserT &t) { traverser_ = t; }
36 
37   // Function that can be used to set an order in which the mesh corners should
38   // be processed. This is an optional flag used usually only by the encoder
39   // to match the same corner order that is going to be used by the decoder.
40   // Note that |corner_order| should contain only one corner per face (it can
41   // have all corners but only the first encountered corner for each face is
42   // going to be used to start a traversal). If the corner order is not set, the
43   // corners are processed sequentially based on their ids.
SetCornerOrder(const std::vector<CornerIndex> & corner_order)44   void SetCornerOrder(const std::vector<CornerIndex> &corner_order) {
45     corner_order_ = &corner_order;
46   }
47 
UpdatePointToAttributeIndexMapping(PointAttribute * attribute)48   bool UpdatePointToAttributeIndexMapping(PointAttribute *attribute) override {
49     const auto *corner_table = traverser_.corner_table();
50     attribute->SetExplicitMapping(mesh_->num_points());
51     const size_t num_faces = mesh_->num_faces();
52     const size_t num_points = mesh_->num_points();
53     for (FaceIndex f(0); f < static_cast<uint32_t>(num_faces); ++f) {
54       const auto &face = mesh_->face(f);
55       for (int p = 0; p < 3; ++p) {
56         const PointIndex point_id = face[p];
57         const VertexIndex vert_id =
58             corner_table->Vertex(CornerIndex(3 * f.value() + p));
59         if (vert_id == kInvalidVertexIndex)
60           return false;
61         const AttributeValueIndex att_entry_id(
62             encoding_data_
63                 ->vertex_to_encoded_attribute_value_index_map[vert_id.value()]);
64         if (att_entry_id.value() >= num_points) {
65           // There cannot be more attribute values than the number of points.
66           return false;
67         }
68         attribute->SetPointMapEntry(point_id, att_entry_id);
69       }
70     }
71     return true;
72   }
73 
74  protected:
GenerateSequenceInternal()75   bool GenerateSequenceInternal() override {
76     // Preallocate memory for storing point indices. We expect the number of
77     // points to be the same as the number of corner table vertices.
78     out_point_ids()->reserve(traverser_.corner_table()->num_vertices());
79 
80     traverser_.OnTraversalStart();
81     if (corner_order_) {
82       for (uint32_t i = 0; i < corner_order_->size(); ++i) {
83         if (!ProcessCorner(corner_order_->at(i)))
84           return false;
85       }
86     } else {
87       const int32_t num_faces = traverser_.corner_table()->num_faces();
88       for (int i = 0; i < num_faces; ++i) {
89         if (!ProcessCorner(CornerIndex(3 * i)))
90           return false;
91       }
92     }
93     traverser_.OnTraversalEnd();
94     return true;
95   }
96 
97  private:
ProcessCorner(CornerIndex corner_id)98   bool ProcessCorner(CornerIndex corner_id) {
99     return traverser_.TraverseFromCorner(corner_id);
100   }
101 
102   TraverserT traverser_;
103   const Mesh *mesh_;
104   const MeshAttributeIndicesEncodingData *encoding_data_;
105   const std::vector<CornerIndex> *corner_order_;
106 };
107 
108 }  // namespace draco
109 
110 #endif  // DRACO_COMPRESSION_MESH_TRAVERSER_MESH_TRAVERSAL_SEQUENCER_H_
111