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