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 #include "draco/compression/mesh/mesh_edgebreaker_encoder_impl.h"
16 
17 #include <algorithm>
18 
19 #include "draco/compression/attributes/sequential_attribute_encoders_controller.h"
20 #include "draco/compression/mesh/mesh_edgebreaker_encoder.h"
21 #include "draco/compression/mesh/mesh_edgebreaker_traversal_predictive_encoder.h"
22 #include "draco/compression/mesh/mesh_edgebreaker_traversal_valence_encoder.h"
23 #include "draco/compression/mesh/traverser/depth_first_traverser.h"
24 #include "draco/compression/mesh/traverser/max_prediction_degree_traverser.h"
25 #include "draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h"
26 #include "draco/compression/mesh/traverser/mesh_traversal_sequencer.h"
27 #include "draco/compression/mesh/traverser/traverser_base.h"
28 #include "draco/mesh/corner_table_iterators.h"
29 #include "draco/mesh/mesh_misc_functions.h"
30 
31 namespace draco {
32 // TODO(draco-eng) consider converting 'typedef' to 'using' and deduplicate.
33 typedef CornerIndex CornerIndex;
34 typedef FaceIndex FaceIndex;
35 typedef VertexIndex VertexIndex;
36 
37 template <class TraversalEncoder>
MeshEdgebreakerEncoderImpl()38 MeshEdgebreakerEncoderImpl<TraversalEncoder>::MeshEdgebreakerEncoderImpl()
39     : encoder_(nullptr),
40       mesh_(nullptr),
41       last_encoded_symbol_id_(-1),
42       num_split_symbols_(0),
43       use_single_connectivity_(false) {}
44 
45 template <class TraversalEncoder>
Init(MeshEdgebreakerEncoder * encoder)46 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::Init(
47     MeshEdgebreakerEncoder *encoder) {
48   encoder_ = encoder;
49   mesh_ = encoder->mesh();
50   attribute_encoder_to_data_id_map_.clear();
51 
52   if (encoder_->options()->IsGlobalOptionSet("split_mesh_on_seams")) {
53     use_single_connectivity_ =
54         encoder_->options()->GetGlobalBool("split_mesh_on_seams", false);
55   } else if (encoder_->options()->GetSpeed() >= 6) {
56     // Else use default setting based on speed.
57     use_single_connectivity_ = true;
58   } else {
59     use_single_connectivity_ = false;
60   }
61   return true;
62 }
63 
64 template <class TraversalEncoder>
65 const MeshAttributeCornerTable *
GetAttributeCornerTable(int att_id) const66 MeshEdgebreakerEncoderImpl<TraversalEncoder>::GetAttributeCornerTable(
67     int att_id) const {
68   for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
69     if (attribute_data_[i].attribute_index == att_id) {
70       if (attribute_data_[i].is_connectivity_used) {
71         return &attribute_data_[i].connectivity_data;
72       }
73       return nullptr;
74     }
75   }
76   return nullptr;
77 }
78 
79 template <class TraversalEncoder>
80 const MeshAttributeIndicesEncodingData *
GetAttributeEncodingData(int att_id) const81 MeshEdgebreakerEncoderImpl<TraversalEncoder>::GetAttributeEncodingData(
82     int att_id) const {
83   for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
84     if (attribute_data_[i].attribute_index == att_id) {
85       return &attribute_data_[i].encoding_data;
86     }
87   }
88   return &pos_encoding_data_;
89 }
90 
91 template <class TraversalEncoder>
92 template <class TraverserT>
93 std::unique_ptr<PointsSequencer>
CreateVertexTraversalSequencer(MeshAttributeIndicesEncodingData * encoding_data)94 MeshEdgebreakerEncoderImpl<TraversalEncoder>::CreateVertexTraversalSequencer(
95     MeshAttributeIndicesEncodingData *encoding_data) {
96   typedef typename TraverserT::TraversalObserver AttObserver;
97   typedef typename TraverserT::CornerTable CornerTable;
98 
99   std::unique_ptr<MeshTraversalSequencer<TraverserT>> traversal_sequencer(
100       new MeshTraversalSequencer<TraverserT>(mesh_, encoding_data));
101 
102   AttObserver att_observer(corner_table_.get(), mesh_,
103                            traversal_sequencer.get(), encoding_data);
104 
105   TraverserT att_traverser;
106   att_traverser.Init(corner_table_.get(), att_observer);
107 
108   // Set order of corners to simulate the corner order of the decoder.
109   traversal_sequencer->SetCornerOrder(processed_connectivity_corners_);
110   traversal_sequencer->SetTraverser(att_traverser);
111   return std::move(traversal_sequencer);
112 }
113 
114 template <class TraversalEncoder>
GenerateAttributesEncoder(int32_t att_id)115 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::GenerateAttributesEncoder(
116     int32_t att_id) {
117   // For now, either create one encoder for each attribute or use a single
118   // encoder for all attributes. Ideally we can share the same encoder for
119   // a sub-set of attributes with the same connectivity (this is especially true
120   // for per-vertex attributes).
121   if (use_single_connectivity_ && GetEncoder()->num_attributes_encoders() > 0) {
122     // We are using single connectivity and we already have an attribute
123     // encoder. Add the attribute to the encoder and return.
124     GetEncoder()->attributes_encoder(0)->AddAttributeId(att_id);
125     return true;
126   }
127   const int32_t element_type =
128       GetEncoder()->mesh()->GetAttributeElementType(att_id);
129   const PointAttribute *const att =
130       GetEncoder()->point_cloud()->attribute(att_id);
131   int32_t att_data_id = -1;
132   for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
133     if (attribute_data_[i].attribute_index == att_id) {
134       att_data_id = i;
135       break;
136     }
137   }
138   MeshTraversalMethod traversal_method = MESH_TRAVERSAL_DEPTH_FIRST;
139   std::unique_ptr<PointsSequencer> sequencer;
140   if (use_single_connectivity_ ||
141       att->attribute_type() == GeometryAttribute::POSITION ||
142       element_type == MESH_VERTEX_ATTRIBUTE ||
143       (element_type == MESH_CORNER_ATTRIBUTE &&
144        attribute_data_[att_data_id].connectivity_data.no_interior_seams())) {
145     // Per-vertex attribute reached, use the basic corner table to traverse the
146     // mesh.
147     MeshAttributeIndicesEncodingData *encoding_data;
148     if (use_single_connectivity_ ||
149         att->attribute_type() == GeometryAttribute::POSITION) {
150       encoding_data = &pos_encoding_data_;
151     } else {
152       encoding_data = &attribute_data_[att_data_id].encoding_data;
153 
154       // Ensure we use the correct number of vertices in the encoding data.
155       encoding_data->vertex_to_encoded_attribute_value_index_map.assign(
156           corner_table_->num_vertices(), -1);
157 
158       // Mark the attribute specific connectivity data as not used as we use the
159       // position attribute connectivity data.
160       attribute_data_[att_data_id].is_connectivity_used = false;
161     }
162 
163     if (GetEncoder()->options()->GetSpeed() == 0 &&
164         att->attribute_type() == GeometryAttribute::POSITION) {
165       traversal_method = MESH_TRAVERSAL_PREDICTION_DEGREE;
166       if (use_single_connectivity_ && mesh_->num_attributes() > 1) {
167         // Make sure we don't use the prediction degree traversal when we encode
168         // multiple attributes using the same connectivity.
169         // TODO(ostava): We should investigate this and see if the prediction
170         // degree can be actually used efficiently for non-position attributes.
171         traversal_method = MESH_TRAVERSAL_DEPTH_FIRST;
172       }
173     }
174     // Defining sequencer via a traversal scheme.
175     if (traversal_method == MESH_TRAVERSAL_PREDICTION_DEGREE) {
176       typedef MeshAttributeIndicesEncodingObserver<CornerTable> AttObserver;
177       typedef MaxPredictionDegreeTraverser<CornerTable, AttObserver>
178           AttTraverser;
179       sequencer = CreateVertexTraversalSequencer<AttTraverser>(encoding_data);
180     } else if (traversal_method == MESH_TRAVERSAL_DEPTH_FIRST) {
181       typedef MeshAttributeIndicesEncodingObserver<CornerTable> AttObserver;
182       typedef DepthFirstTraverser<CornerTable, AttObserver> AttTraverser;
183       sequencer = CreateVertexTraversalSequencer<AttTraverser>(encoding_data);
184     }
185   } else {
186     // Per-corner attribute encoder.
187     typedef MeshAttributeIndicesEncodingObserver<MeshAttributeCornerTable>
188         AttObserver;
189     typedef DepthFirstTraverser<MeshAttributeCornerTable, AttObserver>
190         AttTraverser;
191 
192     MeshAttributeIndicesEncodingData *const encoding_data =
193         &attribute_data_[att_data_id].encoding_data;
194     const MeshAttributeCornerTable *const corner_table =
195         &attribute_data_[att_data_id].connectivity_data;
196 
197     // Ensure we use the correct number of vertices in the encoding data.
198     attribute_data_[att_data_id]
199         .encoding_data.vertex_to_encoded_attribute_value_index_map.assign(
200             attribute_data_[att_data_id].connectivity_data.num_vertices(), -1);
201 
202     std::unique_ptr<MeshTraversalSequencer<AttTraverser>> traversal_sequencer(
203         new MeshTraversalSequencer<AttTraverser>(mesh_, encoding_data));
204 
205     AttObserver att_observer(corner_table, mesh_, traversal_sequencer.get(),
206                              encoding_data);
207 
208     AttTraverser att_traverser;
209     att_traverser.Init(corner_table, att_observer);
210 
211     // Set order of corners to simulate the corner order of the decoder.
212     traversal_sequencer->SetCornerOrder(processed_connectivity_corners_);
213     traversal_sequencer->SetTraverser(att_traverser);
214     sequencer = std::move(traversal_sequencer);
215   }
216 
217   if (!sequencer) {
218     return false;
219   }
220 
221   if (att_data_id == -1) {
222     pos_traversal_method_ = traversal_method;
223   } else {
224     attribute_data_[att_data_id].traversal_method = traversal_method;
225   }
226 
227   std::unique_ptr<SequentialAttributeEncodersController> att_controller(
228       new SequentialAttributeEncodersController(std::move(sequencer), att_id));
229 
230   // Update the mapping between the encoder id and the attribute data id.
231   // This will be used by the decoder to select the appropriate attribute
232   // decoder and the correct connectivity.
233   attribute_encoder_to_data_id_map_.push_back(att_data_id);
234   GetEncoder()->AddAttributesEncoder(std::move(att_controller));
235   return true;
236 }  // namespace draco
237 
238 template <class TraversalEncoder>
239 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::
EncodeAttributesEncoderIdentifier(int32_t att_encoder_id)240     EncodeAttributesEncoderIdentifier(int32_t att_encoder_id) {
241   const int8_t att_data_id = attribute_encoder_to_data_id_map_[att_encoder_id];
242   encoder_->buffer()->Encode(att_data_id);
243 
244   // Also encode the type of the encoder that we used.
245   int32_t element_type = MESH_VERTEX_ATTRIBUTE;
246   MeshTraversalMethod traversal_method;
247   if (att_data_id >= 0) {
248     const int32_t att_id = attribute_data_[att_data_id].attribute_index;
249     element_type = GetEncoder()->mesh()->GetAttributeElementType(att_id);
250     traversal_method = attribute_data_[att_data_id].traversal_method;
251   } else {
252     traversal_method = pos_traversal_method_;
253   }
254   if (element_type == MESH_VERTEX_ATTRIBUTE ||
255       (element_type == MESH_CORNER_ATTRIBUTE &&
256        attribute_data_[att_data_id].connectivity_data.no_interior_seams())) {
257     // Per-vertex encoder.
258     encoder_->buffer()->Encode(static_cast<uint8_t>(MESH_VERTEX_ATTRIBUTE));
259   } else {
260     // Per-corner encoder.
261     encoder_->buffer()->Encode(static_cast<uint8_t>(MESH_CORNER_ATTRIBUTE));
262   }
263   // Encode the mesh traversal method.
264   encoder_->buffer()->Encode(static_cast<uint8_t>(traversal_method));
265   return true;
266 }
267 
268 template <class TraversalEncoder>
EncodeConnectivity()269 Status MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
270   // To encode the mesh, we need face connectivity data stored in a corner
271   // table. To compute the connectivity we must use indices associated with
272   // POSITION attribute, because they define which edges can be connected
273   // together, unless the option |use_single_connectivity_| is set in which case
274   // we break the mesh along attribute seams and use the same connectivity for
275   // all attributes.
276   if (use_single_connectivity_) {
277     corner_table_ = CreateCornerTableFromAllAttributes(mesh_);
278   } else {
279     corner_table_ = CreateCornerTableFromPositionAttribute(mesh_);
280   }
281   if (corner_table_ == nullptr ||
282       corner_table_->num_faces() == corner_table_->NumDegeneratedFaces()) {
283     // Failed to construct the corner table.
284     // TODO(ostava): Add better error reporting.
285     return Status(Status::DRACO_ERROR, "All triangles are degenerate.");
286   }
287 
288   traversal_encoder_.Init(this);
289 
290   // Also encode the total number of vertices that is going to be encoded.
291   // This can be different from the mesh_->num_points() + num_new_vertices,
292   // because some of the vertices of the input mesh can be ignored (e.g.
293   // vertices on degenerated faces or isolated vertices not attached to any
294   // face).
295   const uint32_t num_vertices_to_be_encoded =
296       corner_table_->num_vertices() - corner_table_->NumIsolatedVertices();
297   EncodeVarint(num_vertices_to_be_encoded, encoder_->buffer());
298 
299   const uint32_t num_faces =
300       corner_table_->num_faces() - corner_table_->NumDegeneratedFaces();
301   EncodeVarint(num_faces, encoder_->buffer());
302 
303   // Reset encoder data that may have been initialized in previous runs.
304   visited_faces_.assign(mesh_->num_faces(), false);
305   pos_encoding_data_.vertex_to_encoded_attribute_value_index_map.assign(
306       corner_table_->num_vertices(), -1);
307   pos_encoding_data_.encoded_attribute_value_index_to_corner_map.clear();
308   pos_encoding_data_.encoded_attribute_value_index_to_corner_map.reserve(
309       corner_table_->num_faces() * 3);
310   visited_vertex_ids_.assign(corner_table_->num_vertices(), false);
311   vertex_traversal_length_.clear();
312   last_encoded_symbol_id_ = -1;
313   num_split_symbols_ = 0;
314   topology_split_event_data_.clear();
315   face_to_split_symbol_map_.clear();
316   visited_holes_.clear();
317   vertex_hole_id_.assign(corner_table_->num_vertices(), -1);
318   processed_connectivity_corners_.clear();
319   processed_connectivity_corners_.reserve(corner_table_->num_faces());
320   pos_encoding_data_.num_values = 0;
321 
322   if (!FindHoles()) {
323     return Status(Status::DRACO_ERROR, "Failed to process mesh holes.");
324   }
325 
326   if (!InitAttributeData()) {
327     return Status(Status::DRACO_ERROR, "Failed to initialize attribute data.");
328   }
329 
330   const uint8_t num_attribute_data =
331       static_cast<uint8_t>(attribute_data_.size());
332   encoder_->buffer()->Encode(num_attribute_data);
333   traversal_encoder_.SetNumAttributeData(num_attribute_data);
334 
335   const int num_corners = corner_table_->num_corners();
336 
337   traversal_encoder_.Start();
338 
339   std::vector<CornerIndex> init_face_connectivity_corners;
340   // Traverse the surface starting from each unvisited corner.
341   for (int c_id = 0; c_id < num_corners; ++c_id) {
342     CornerIndex corner_index(c_id);
343     const FaceIndex face_id = corner_table_->Face(corner_index);
344     if (visited_faces_[face_id.value()]) {
345       continue;  // Face has been already processed.
346     }
347     if (corner_table_->IsDegenerated(face_id)) {
348       continue;  // Ignore degenerated faces.
349     }
350 
351     CornerIndex start_corner;
352     const bool interior_config =
353         FindInitFaceConfiguration(face_id, &start_corner);
354     traversal_encoder_.EncodeStartFaceConfiguration(interior_config);
355 
356     if (interior_config) {
357       // Select the correct vertex on the face as the root.
358       corner_index = start_corner;
359       const VertexIndex vert_id = corner_table_->Vertex(corner_index);
360       // Mark all vertices of a given face as visited.
361       const VertexIndex next_vert_id =
362           corner_table_->Vertex(corner_table_->Next(corner_index));
363       const VertexIndex prev_vert_id =
364           corner_table_->Vertex(corner_table_->Previous(corner_index));
365 
366       visited_vertex_ids_[vert_id.value()] = true;
367       visited_vertex_ids_[next_vert_id.value()] = true;
368       visited_vertex_ids_[prev_vert_id.value()] = true;
369       // New traversal started. Initiate it's length with the first vertex.
370       vertex_traversal_length_.push_back(1);
371 
372       // Mark the face as visited.
373       visited_faces_[face_id.value()] = true;
374       // Start compressing from the opposite face of the "next" corner. This way
375       // the first encoded corner corresponds to the tip corner of the regular
376       // edgebreaker traversal (essentially the initial face can be then viewed
377       // as a TOPOLOGY_C face).
378       init_face_connectivity_corners.push_back(
379           corner_table_->Next(corner_index));
380       const CornerIndex opp_id =
381           corner_table_->Opposite(corner_table_->Next(corner_index));
382       const FaceIndex opp_face_id = corner_table_->Face(opp_id);
383       if (opp_face_id != kInvalidFaceIndex &&
384           !visited_faces_[opp_face_id.value()]) {
385         if (!EncodeConnectivityFromCorner(opp_id)) {
386           return Status(Status::DRACO_ERROR,
387                         "Failed to encode mesh component.");
388         }
389       }
390     } else {
391       // Boundary configuration. We start on a boundary rather than on a face.
392       // First encode the hole that's opposite to the start_corner.
393       EncodeHole(corner_table_->Next(start_corner), true);
394       // Start processing the face opposite to the boundary edge (the face
395       // containing the start_corner).
396       if (!EncodeConnectivityFromCorner(start_corner)) {
397         return Status(Status::DRACO_ERROR, "Failed to encode mesh component.");
398       }
399     }
400   }
401   // Reverse the order of connectivity corners to match the order in which
402   // they are going to be decoded.
403   std::reverse(processed_connectivity_corners_.begin(),
404                processed_connectivity_corners_.end());
405   // Append the init face connectivity corners (which are processed in order by
406   // the decoder after the regular corners.
407   processed_connectivity_corners_.insert(processed_connectivity_corners_.end(),
408                                          init_face_connectivity_corners.begin(),
409                                          init_face_connectivity_corners.end());
410   // Encode connectivity for all non-position attributes.
411   if (!attribute_data_.empty()) {
412     // Use the same order of corner that will be used by the decoder.
413     visited_faces_.assign(mesh_->num_faces(), false);
414     for (CornerIndex ci : processed_connectivity_corners_) {
415       EncodeAttributeConnectivitiesOnFace(ci);
416     }
417   }
418   traversal_encoder_.Done();
419 
420   // Encode the number of symbols.
421   const uint32_t num_encoded_symbols =
422       static_cast<uint32_t>(traversal_encoder_.NumEncodedSymbols());
423   EncodeVarint(num_encoded_symbols, encoder_->buffer());
424 
425   // Encode the number of split symbols.
426   EncodeVarint(num_split_symbols_, encoder_->buffer());
427 
428   // Append the traversal buffer.
429   if (!EncodeSplitData()) {
430     return Status(Status::DRACO_ERROR, "Failed to encode split data.");
431   }
432   encoder_->buffer()->Encode(traversal_encoder_.buffer().data(),
433                              traversal_encoder_.buffer().size());
434 
435   return OkStatus();
436 }
437 
438 template <class TraversalEncoder>
EncodeSplitData()439 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeSplitData() {
440   uint32_t num_events =
441       static_cast<uint32_t>(topology_split_event_data_.size());
442   EncodeVarint(num_events, encoder_->buffer());
443   if (num_events > 0) {
444     // Encode split symbols using delta and varint coding. Split edges are
445     // encoded using direct bit coding.
446     int last_source_symbol_id = 0;  // Used for delta coding.
447     for (uint32_t i = 0; i < num_events; ++i) {
448       const TopologySplitEventData &event_data = topology_split_event_data_[i];
449       // Encode source symbol id as delta from the previous source symbol id.
450       // Source symbol ids are always stored in increasing order so the delta is
451       // going to be positive.
452       EncodeVarint<uint32_t>(
453           event_data.source_symbol_id - last_source_symbol_id,
454           encoder_->buffer());
455       // Encode split symbol id as delta from the current source symbol id.
456       // Split symbol id is always smaller than source symbol id so the below
457       // delta is going to be positive.
458       EncodeVarint<uint32_t>(
459           event_data.source_symbol_id - event_data.split_symbol_id,
460           encoder_->buffer());
461       last_source_symbol_id = event_data.source_symbol_id;
462     }
463     encoder_->buffer()->StartBitEncoding(num_events, false);
464     for (uint32_t i = 0; i < num_events; ++i) {
465       const TopologySplitEventData &event_data = topology_split_event_data_[i];
466       encoder_->buffer()->EncodeLeastSignificantBits32(1,
467                                                        event_data.source_edge);
468     }
469     encoder_->buffer()->EndBitEncoding();
470   }
471   return true;
472 }
473 
474 template <class TraversalEncoder>
FindInitFaceConfiguration(FaceIndex face_id,CornerIndex * out_corner) const475 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::FindInitFaceConfiguration(
476     FaceIndex face_id, CornerIndex *out_corner) const {
477   CornerIndex corner_index = CornerIndex(3 * face_id.value());
478   for (int i = 0; i < 3; ++i) {
479     if (corner_table_->Opposite(corner_index) == kInvalidCornerIndex) {
480       // If there is a boundary edge, the configuration is exterior and return
481       // the CornerIndex opposite to the first boundary edge.
482       *out_corner = corner_index;
483       return false;
484     }
485     if (vertex_hole_id_[corner_table_->Vertex(corner_index).value()] != -1) {
486       // Boundary vertex found. Find the first boundary edge attached to the
487       // point and return the corner opposite to it.
488       CornerIndex right_corner = corner_index;
489       while (right_corner != kInvalidCornerIndex) {
490         corner_index = right_corner;
491         right_corner = corner_table_->SwingRight(right_corner);
492       }
493       // |corner_index| now lies on a boundary edge and its previous corner is
494       // guaranteed to be the opposite corner of the boundary edge.
495       *out_corner = corner_table_->Previous(corner_index);
496       return false;
497     }
498     corner_index = corner_table_->Next(corner_index);
499   }
500   // Else we have an interior configuration. Return the first corner id.
501   *out_corner = corner_index;
502   return true;
503 }
504 
505 template <class TraversalEncoder>
EncodeConnectivityFromCorner(CornerIndex corner_id)506 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivityFromCorner(
507     CornerIndex corner_id) {
508   corner_traversal_stack_.clear();
509   corner_traversal_stack_.push_back(corner_id);
510   const int num_faces = mesh_->num_faces();
511   while (!corner_traversal_stack_.empty()) {
512     // Currently processed corner.
513     corner_id = corner_traversal_stack_.back();
514     // Make sure the face hasn't been visited yet.
515     if (corner_id == kInvalidCornerIndex ||
516         visited_faces_[corner_table_->Face(corner_id).value()]) {
517       // This face has been already traversed.
518       corner_traversal_stack_.pop_back();
519       continue;
520     }
521     int num_visited_faces = 0;
522     while (num_visited_faces < num_faces) {
523       // Mark the current face as visited.
524       ++num_visited_faces;
525       ++last_encoded_symbol_id_;
526 
527       const FaceIndex face_id = corner_table_->Face(corner_id);
528       visited_faces_[face_id.value()] = true;
529       processed_connectivity_corners_.push_back(corner_id);
530       traversal_encoder_.NewCornerReached(corner_id);
531       const VertexIndex vert_id = corner_table_->Vertex(corner_id);
532       const bool on_boundary = (vertex_hole_id_[vert_id.value()] != -1);
533       if (!IsVertexVisited(vert_id)) {
534         // A new unvisited vertex has been reached. We need to store its
535         // position difference using next, prev, and opposite vertices.
536         visited_vertex_ids_[vert_id.value()] = true;
537         if (!on_boundary) {
538           // If the vertex is on boundary it must correspond to an unvisited
539           // hole and it will be encoded with TOPOLOGY_S symbol later).
540           traversal_encoder_.EncodeSymbol(TOPOLOGY_C);
541           // Move to the right triangle.
542           corner_id = GetRightCorner(corner_id);
543           continue;
544         }
545       }
546       // The current vertex has been already visited or it was on a boundary.
547       // We need to determine whether we can visit any of it's neighboring
548       // faces.
549       const CornerIndex right_corner_id = GetRightCorner(corner_id);
550       const CornerIndex left_corner_id = GetLeftCorner(corner_id);
551       const FaceIndex right_face_id = corner_table_->Face(right_corner_id);
552       const FaceIndex left_face_id = corner_table_->Face(left_corner_id);
553       if (IsRightFaceVisited(corner_id)) {
554         // Right face has been already visited.
555         // Check whether there is a topology split event.
556         if (right_face_id != kInvalidFaceIndex) {
557           CheckAndStoreTopologySplitEvent(last_encoded_symbol_id_,
558                                           face_id.value(), RIGHT_FACE_EDGE,
559                                           right_face_id.value());
560         }
561         if (IsLeftFaceVisited(corner_id)) {
562           // Both neighboring faces are visited. End reached.
563           // Check whether there is a topology split event on the left face.
564           if (left_face_id != kInvalidFaceIndex) {
565             CheckAndStoreTopologySplitEvent(last_encoded_symbol_id_,
566                                             face_id.value(), LEFT_FACE_EDGE,
567                                             left_face_id.value());
568           }
569           traversal_encoder_.EncodeSymbol(TOPOLOGY_E);
570           corner_traversal_stack_.pop_back();
571           break;  // Break from the while (num_visited_faces < num_faces) loop.
572         } else {
573           traversal_encoder_.EncodeSymbol(TOPOLOGY_R);
574           // Go to the left face.
575           corner_id = left_corner_id;
576         }
577       } else {
578         // Right face was not visited.
579         if (IsLeftFaceVisited(corner_id)) {
580           // Check whether there is a topology split event on the left face.
581           if (left_face_id != kInvalidFaceIndex) {
582             CheckAndStoreTopologySplitEvent(last_encoded_symbol_id_,
583                                             face_id.value(), LEFT_FACE_EDGE,
584                                             left_face_id.value());
585           }
586           traversal_encoder_.EncodeSymbol(TOPOLOGY_L);
587           // Left face visited, go to the right one.
588           corner_id = right_corner_id;
589         } else {
590           traversal_encoder_.EncodeSymbol(TOPOLOGY_S);
591           ++num_split_symbols_;
592           // Both neighboring faces are unvisited, we need to visit both of
593           // them.
594           if (on_boundary) {
595             // The tip vertex is on a hole boundary. If the hole hasn't been
596             // visited yet we need to encode it.
597             const int hole_id = vertex_hole_id_[vert_id.value()];
598             if (!visited_holes_[hole_id]) {
599               EncodeHole(corner_id, false);
600             }
601           }
602           face_to_split_symbol_map_[face_id.value()] = last_encoded_symbol_id_;
603           // Split the traversal.
604           // First make the top of the current corner stack point to the left
605           // face (this one will be processed second).
606           corner_traversal_stack_.back() = left_corner_id;
607           // Add a new corner to the top of the stack (right face needs to
608           // be traversed first).
609           corner_traversal_stack_.push_back(right_corner_id);
610           // Break from the while (num_visited_faces < num_faces) loop.
611           break;
612         }
613       }
614     }
615   }
616   return true;  // All corners have been processed.
617 }
618 
619 template <class TraversalEncoder>
EncodeHole(CornerIndex start_corner_id,bool encode_first_vertex)620 int MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeHole(
621     CornerIndex start_corner_id, bool encode_first_vertex) {
622   // We know that the start corner lies on a hole but we first need to find the
623   // boundary edge going from that vertex. It is the first edge in CW
624   // direction.
625   CornerIndex corner_id = start_corner_id;
626   corner_id = corner_table_->Previous(corner_id);
627   while (corner_table_->Opposite(corner_id) != kInvalidCornerIndex) {
628     corner_id = corner_table_->Opposite(corner_id);
629     corner_id = corner_table_->Next(corner_id);
630   }
631   const VertexIndex start_vertex_id = corner_table_->Vertex(start_corner_id);
632 
633   int num_encoded_hole_verts = 0;
634   if (encode_first_vertex) {
635     visited_vertex_ids_[start_vertex_id.value()] = true;
636     ++num_encoded_hole_verts;
637   }
638 
639   // corner_id is now opposite to the boundary edge.
640   // Mark the hole as visited.
641   visited_holes_[vertex_hole_id_[start_vertex_id.value()]] = true;
642   // Get the start vertex of the edge and use it as a reference.
643   VertexIndex start_vert_id =
644       corner_table_->Vertex(corner_table_->Next(corner_id));
645   // Get the end vertex of the edge.
646   VertexIndex act_vertex_id =
647       corner_table_->Vertex(corner_table_->Previous(corner_id));
648   while (act_vertex_id != start_vertex_id) {
649     // Encode the end vertex of the boundary edge.
650 
651     start_vert_id = act_vertex_id;
652 
653     // Mark the vertex as visited.
654     visited_vertex_ids_[act_vertex_id.value()] = true;
655     ++num_encoded_hole_verts;
656     corner_id = corner_table_->Next(corner_id);
657     // Look for the next attached open boundary edge.
658     while (corner_table_->Opposite(corner_id) != kInvalidCornerIndex) {
659       corner_id = corner_table_->Opposite(corner_id);
660       corner_id = corner_table_->Next(corner_id);
661     }
662     act_vertex_id = corner_table_->Vertex(corner_table_->Previous(corner_id));
663   }
664   return num_encoded_hole_verts;
665 }
666 
667 template <class TraversalEncoder>
GetRightCorner(CornerIndex corner_id) const668 CornerIndex MeshEdgebreakerEncoderImpl<TraversalEncoder>::GetRightCorner(
669     CornerIndex corner_id) const {
670   const CornerIndex next_corner_id = corner_table_->Next(corner_id);
671   return corner_table_->Opposite(next_corner_id);
672 }
673 
674 template <class TraversalEncoder>
GetLeftCorner(CornerIndex corner_id) const675 CornerIndex MeshEdgebreakerEncoderImpl<TraversalEncoder>::GetLeftCorner(
676     CornerIndex corner_id) const {
677   const CornerIndex prev_corner_id = corner_table_->Previous(corner_id);
678   return corner_table_->Opposite(prev_corner_id);
679 }
680 
681 template <class TraversalEncoder>
IsRightFaceVisited(CornerIndex corner_id) const682 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::IsRightFaceVisited(
683     CornerIndex corner_id) const {
684   const CornerIndex next_corner_id = corner_table_->Next(corner_id);
685   const CornerIndex opp_corner_id = corner_table_->Opposite(next_corner_id);
686   if (opp_corner_id != kInvalidCornerIndex) {
687     return visited_faces_[corner_table_->Face(opp_corner_id).value()];
688   }
689   // Else we are on a boundary.
690   return true;
691 }
692 
693 template <class TraversalEncoder>
IsLeftFaceVisited(CornerIndex corner_id) const694 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::IsLeftFaceVisited(
695     CornerIndex corner_id) const {
696   const CornerIndex prev_corner_id = corner_table_->Previous(corner_id);
697   const CornerIndex opp_corner_id = corner_table_->Opposite(prev_corner_id);
698   if (opp_corner_id != kInvalidCornerIndex) {
699     return visited_faces_[corner_table_->Face(opp_corner_id).value()];
700   }
701   // Else we are on a boundary.
702   return true;
703 }
704 
705 template <class TraversalEncoder>
FindHoles()706 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::FindHoles() {
707   // TODO(ostava): Add more error checking for invalid geometry data.
708   const int num_corners = corner_table_->num_corners();
709   // Go over all corners and detect non-visited open boundaries
710   for (CornerIndex i(0); i < num_corners; ++i) {
711     if (corner_table_->IsDegenerated(corner_table_->Face(i))) {
712       continue;  // Don't process corners assigned to degenerated faces.
713     }
714     if (corner_table_->Opposite(i) == kInvalidCornerIndex) {
715       // No opposite corner means no opposite face, so the opposite edge
716       // of the corner is an open boundary.
717       // Check whether we have already traversed the boundary.
718       VertexIndex boundary_vert_id =
719           corner_table_->Vertex(corner_table_->Next(i));
720       if (vertex_hole_id_[boundary_vert_id.value()] != -1) {
721         // The start vertex of the boundary edge is already assigned to an
722         // open boundary. No need to traverse it again.
723         continue;
724       }
725       // Else we found a new open boundary and we are going to traverse along it
726       // and mark all visited vertices.
727       const int boundary_id = static_cast<int>(visited_holes_.size());
728       visited_holes_.push_back(false);
729 
730       CornerIndex corner_id = i;
731       while (vertex_hole_id_[boundary_vert_id.value()] == -1) {
732         // Mark the first vertex on the open boundary.
733         vertex_hole_id_[boundary_vert_id.value()] = boundary_id;
734         corner_id = corner_table_->Next(corner_id);
735         // Look for the next attached open boundary edge.
736         while (corner_table_->Opposite(corner_id) != kInvalidCornerIndex) {
737           corner_id = corner_table_->Opposite(corner_id);
738           corner_id = corner_table_->Next(corner_id);
739         }
740         // Id of the next vertex in the vertex on the hole.
741         boundary_vert_id =
742             corner_table_->Vertex(corner_table_->Next(corner_id));
743       }
744     }
745   }
746   return true;
747 }
748 
749 template <class TraversalEncoder>
GetSplitSymbolIdOnFace(int face_id) const750 int MeshEdgebreakerEncoderImpl<TraversalEncoder>::GetSplitSymbolIdOnFace(
751     int face_id) const {
752   auto it = face_to_split_symbol_map_.find(face_id);
753   if (it == face_to_split_symbol_map_.end()) {
754     return -1;
755   }
756   return it->second;
757 }
758 
759 template <class TraversalEncoder>
760 void MeshEdgebreakerEncoderImpl<
CheckAndStoreTopologySplitEvent(int src_symbol_id,int,EdgeFaceName src_edge,int neighbor_face_id)761     TraversalEncoder>::CheckAndStoreTopologySplitEvent(int src_symbol_id,
762                                                        int /* src_face_id */,
763                                                        EdgeFaceName src_edge,
764                                                        int neighbor_face_id) {
765   const int symbol_id = GetSplitSymbolIdOnFace(neighbor_face_id);
766   if (symbol_id == -1) {
767     return;  // Not a split symbol, no topology split event could happen.
768   }
769   TopologySplitEventData event_data;
770 
771   event_data.split_symbol_id = symbol_id;
772   event_data.source_symbol_id = src_symbol_id;
773   event_data.source_edge = src_edge;
774   topology_split_event_data_.push_back(event_data);
775 }
776 
777 template <class TraversalEncoder>
InitAttributeData()778 bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::InitAttributeData() {
779   if (use_single_connectivity_) {
780     return true;  // All attributes use the same connectivity.
781   }
782 
783   const int num_attributes = mesh_->num_attributes();
784   // Ignore the position attribute. It's decoded separately.
785   attribute_data_.resize(num_attributes - 1);
786   if (num_attributes == 1) {
787     return true;
788   }
789   int data_index = 0;
790   for (int i = 0; i < num_attributes; ++i) {
791     const int32_t att_index = i;
792     if (mesh_->attribute(att_index)->attribute_type() ==
793         GeometryAttribute::POSITION) {
794       continue;
795     }
796     const PointAttribute *const att = mesh_->attribute(att_index);
797     attribute_data_[data_index].attribute_index = att_index;
798     attribute_data_[data_index]
799         .encoding_data.encoded_attribute_value_index_to_corner_map.clear();
800     attribute_data_[data_index]
801         .encoding_data.encoded_attribute_value_index_to_corner_map.reserve(
802             corner_table_->num_corners());
803     attribute_data_[data_index].encoding_data.num_values = 0;
804     attribute_data_[data_index].connectivity_data.InitFromAttribute(
805         mesh_, corner_table_.get(), att);
806     ++data_index;
807   }
808   return true;
809 }
810 
811 // TODO(ostava): Note that if the input mesh used the same attribute index on
812 // multiple different vertices, such attribute will be duplicated using the
813 // encoding below. Eventually, we may consider either using a different encoding
814 // scheme for such cases, or at least deduplicating the attributes in the
815 // decoder.
816 template <class TraversalEncoder>
817 bool MeshEdgebreakerEncoderImpl<
EncodeAttributeConnectivitiesOnFace(CornerIndex corner)818     TraversalEncoder>::EncodeAttributeConnectivitiesOnFace(CornerIndex corner) {
819   // Three corners of the face.
820   const CornerIndex corners[3] = {corner, corner_table_->Next(corner),
821                                   corner_table_->Previous(corner)};
822 
823   const FaceIndex src_face_id = corner_table_->Face(corner);
824   visited_faces_[src_face_id.value()] = true;
825   for (int c = 0; c < 3; ++c) {
826     const CornerIndex opp_corner = corner_table_->Opposite(corners[c]);
827     if (opp_corner == kInvalidCornerIndex) {
828       continue;  // Don't encode attribute seams on boundary edges.
829     }
830     const FaceIndex opp_face_id = corner_table_->Face(opp_corner);
831     // Don't encode edges when the opposite face has been already processed.
832     if (visited_faces_[opp_face_id.value()]) {
833       continue;
834     }
835 
836     for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
837       if (attribute_data_[i].connectivity_data.IsCornerOppositeToSeamEdge(
838               corners[c])) {
839         traversal_encoder_.EncodeAttributeSeam(i, true);
840       } else {
841         traversal_encoder_.EncodeAttributeSeam(i, false);
842       }
843     }
844   }
845   return true;
846 }
847 
848 template class MeshEdgebreakerEncoderImpl<MeshEdgebreakerTraversalEncoder>;
849 template class MeshEdgebreakerEncoderImpl<
850     MeshEdgebreakerTraversalPredictiveEncoder>;
851 template class MeshEdgebreakerEncoderImpl<
852     MeshEdgebreakerTraversalValenceEncoder>;
853 
854 }  // namespace draco
855