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(b/199760123): 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 } 62 const AttributeValueIndex att_entry_id( 63 encoding_data_ 64 ->vertex_to_encoded_attribute_value_index_map[vert_id.value()]); 65 if (point_id >= num_points || att_entry_id.value() >= num_points) { 66 // There cannot be more attribute values than the number of points. 67 return false; 68 } 69 attribute->SetPointMapEntry(point_id, att_entry_id); 70 } 71 } 72 return true; 73 } 74 75 protected: GenerateSequenceInternal()76 bool GenerateSequenceInternal() override { 77 // Preallocate memory for storing point indices. We expect the number of 78 // points to be the same as the number of corner table vertices. 79 out_point_ids()->reserve(traverser_.corner_table()->num_vertices()); 80 81 traverser_.OnTraversalStart(); 82 if (corner_order_) { 83 for (uint32_t i = 0; i < corner_order_->size(); ++i) { 84 if (!ProcessCorner(corner_order_->at(i))) { 85 return false; 86 } 87 } 88 } else { 89 const int32_t num_faces = traverser_.corner_table()->num_faces(); 90 for (int i = 0; i < num_faces; ++i) { 91 if (!ProcessCorner(CornerIndex(3 * i))) { 92 return false; 93 } 94 } 95 } 96 traverser_.OnTraversalEnd(); 97 return true; 98 } 99 100 private: ProcessCorner(CornerIndex corner_id)101 bool ProcessCorner(CornerIndex corner_id) { 102 return traverser_.TraverseFromCorner(corner_id); 103 } 104 105 TraverserT traverser_; 106 const Mesh *mesh_; 107 const MeshAttributeIndicesEncodingData *encoding_data_; 108 const std::vector<CornerIndex> *corner_order_; 109 }; 110 111 } // namespace draco 112 113 #endif // DRACO_COMPRESSION_MESH_TRAVERSER_MESH_TRAVERSAL_SEQUENCER_H_ 114