Welcome to mirror list, hosted at ThFree Co, Russian Federation.

mesh_edgebreaker_decoder_impl.h « mesh « compression « draco « src « draco « draco « extern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 78053f91dbe9e215f67a47ec0c487c3b9900d8f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// 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.
//
#ifndef DRACO_COMPRESSION_MESH_MESH_EDGEBREAKER_DECODER_IMPL_H_
#define DRACO_COMPRESSION_MESH_MESH_EDGEBREAKER_DECODER_IMPL_H_

#include <unordered_map>
#include <unordered_set>

#include "draco/compression/attributes/mesh_attribute_indices_encoding_data.h"
#include "draco/compression/mesh/mesh_edgebreaker_decoder_impl_interface.h"
#include "draco/compression/mesh/mesh_edgebreaker_shared.h"
#include "draco/compression/mesh/traverser/mesh_traversal_sequencer.h"
#include "draco/core/decoder_buffer.h"
#include "draco/draco_features.h"
#include "draco/mesh/corner_table.h"
#include "draco/mesh/mesh_attribute_corner_table.h"

namespace draco {

// Implementation of the edgebreaker decoder that decodes data encoded with the
// MeshEdgebreakerEncoderImpl class. The implementation of the decoder is based
// on the algorithm presented in Isenburg et al'02 "Spirale Reversi: Reverse
// decoding of the Edgebreaker encoding". Note that the encoding is still based
// on the standard edgebreaker method as presented in "3D Compression
// Made Simple: Edgebreaker on a Corner-Table" by Rossignac at al.'01.
// http://www.cc.gatech.edu/~jarek/papers/CornerTableSMI.pdf. One difference is
// caused by the properties of the spirale reversi algorithm that decodes the
// symbols from the last one to the first one. To make the decoding more
// efficient, we encode all symbols in the reverse order, therefore the decoder
// can process them one by one.
// The main advantage of the spirale reversi method is that the partially
// decoded mesh has valid connectivity data at any time during the decoding
// process (valid with respect to the decoded portion of the mesh). The standard
// Edgebreaker decoder used two passes (forward decoding + zipping) which not
// only prevented us from having a valid connectivity but it was also slower.
// The main benefit of having the valid connectivity is that we can use the
// known connectivity to predict encoded symbols that can improve the
// compression rate.
template <class TraversalDecoderT>
class MeshEdgebreakerDecoderImpl : public MeshEdgebreakerDecoderImplInterface {
 public:
  MeshEdgebreakerDecoderImpl();
  bool Init(MeshEdgebreakerDecoder *decoder) override;

  const MeshAttributeCornerTable *GetAttributeCornerTable(
      int att_id) const override;
  const MeshAttributeIndicesEncodingData *GetAttributeEncodingData(
      int att_id) const override;

  bool CreateAttributesDecoder(int32_t att_decoder_id) override;
  bool DecodeConnectivity() override;
  bool OnAttributesDecoded() override;
  MeshEdgebreakerDecoder *GetDecoder() const override { return decoder_; }
  const CornerTable *GetCornerTable() const override {
    return corner_table_.get();
  }

 private:
  // Creates a vertex traversal sequencer for the specified |TraverserT| type.
  template <class TraverserT>
  std::unique_ptr<PointsSequencer> CreateVertexTraversalSequencer(
      MeshAttributeIndicesEncodingData *encoding_data);

  // Decodes connectivity between vertices (vertex indices).
  // Returns the number of vertices created by the decoder or -1 on error.
  int DecodeConnectivity(int num_symbols);

  // Returns true if the current symbol was part of a topology split event. This
  // means that the current face was connected to the left edge of a face
  // encoded with the TOPOLOGY_S symbol. |out_symbol_edge| can be used to
  // identify which edge of the source symbol was connected to the TOPOLOGY_S
  // symbol.
  bool IsTopologySplit(int encoder_symbol_id, EdgeFaceName *out_face_edge,
                       int *out_encoder_split_symbol_id) {
    if (topology_split_data_.size() == 0) {
      return false;
    }
    if (topology_split_data_.back().source_symbol_id >
        static_cast<uint32_t>(encoder_symbol_id)) {
      // Something is wrong; if the desired source symbol is greater than the
      // current encoder_symbol_id, we missed it, or the input was tampered
      // (|encoder_symbol_id| keeps decreasing).
      // Return invalid symbol id to notify the decoder that there was an
      // error.
      *out_encoder_split_symbol_id = -1;
      return true;
    }
    if (topology_split_data_.back().source_symbol_id != encoder_symbol_id) {
      return false;
    }
    *out_face_edge =
        static_cast<EdgeFaceName>(topology_split_data_.back().source_edge);
    *out_encoder_split_symbol_id = topology_split_data_.back().split_symbol_id;
    // Remove the latest split event.
    topology_split_data_.pop_back();
    return true;
  }

  // Decodes event data for hole and topology split events and stores them for
  // future use.
  // Returns the number of parsed bytes, or -1 on error.
  int32_t DecodeHoleAndTopologySplitEvents(DecoderBuffer *decoder_buffer);

  // Decodes all non-position attribute connectivity on the currently
  // processed face.
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
  bool DecodeAttributeConnectivitiesOnFaceLegacy(CornerIndex corner);
#endif
  bool DecodeAttributeConnectivitiesOnFace(CornerIndex corner);

  // Initializes mapping between corners and point ids.
  bool AssignPointsToCorners(int num_connectivity_verts);

  bool IsFaceVisited(CornerIndex corner_id) const {
    if (corner_id < 0) {
      return true;  // Invalid corner signalizes that the face does not exist.
    }
    return visited_faces_[corner_table_->Face(corner_id).value()];
  }

  void SetOppositeCorners(CornerIndex corner_0, CornerIndex corner_1) {
    corner_table_->SetOppositeCorner(corner_0, corner_1);
    corner_table_->SetOppositeCorner(corner_1, corner_0);
  }

  MeshEdgebreakerDecoder *decoder_;

  std::unique_ptr<CornerTable> corner_table_;

  // Stack used for storing corners that need to be traversed when decoding
  // mesh vertices. New corner is added for each initial face and a split
  // symbol, and one corner is removed when the end symbol is reached.
  // Stored as member variable to prevent frequent memory reallocations when
  // handling meshes with lots of disjoint components.  Originally, we used
  // recursive functions to handle this behavior, but that can cause stack
  // memory overflow when compressing huge meshes.
  std::vector<CornerIndex> corner_traversal_stack_;

  // Array stores the number of visited visited for each mesh traversal.
  std::vector<int> vertex_traversal_length_;

  // List of decoded topology split events.
  std::vector<TopologySplitEventData> topology_split_data_;

  // List of decoded hole events.
  std::vector<HoleEventData> hole_event_data_;

  // Configuration of the initial face for each mesh component.
  std::vector<bool> init_face_configurations_;

  // Initial corner for each traversal.
  std::vector<CornerIndex> init_corners_;

  // Id of the last processed input symbol.
  int last_symbol_id_;

  // Id of the last decoded vertex.
  int last_vert_id_;

  // Id of the last decoded face.
  int last_face_id_;

  // Array for marking visited faces.
  std::vector<bool> visited_faces_;
  // Array for marking visited vertices.
  std::vector<bool> visited_verts_;
  // Array for marking vertices on open boundaries.
  std::vector<bool> is_vert_hole_;

  // The number of new vertices added by the encoder (because of non-manifold
  // vertices on the input mesh).
  // If there are no non-manifold edges/vertices on the input mesh, this should
  // be 0.
  int num_new_vertices_;
  // For every newly added vertex, this array stores it's mapping to the
  // parent vertex id of the encoded mesh.
  std::unordered_map<int, int> new_to_parent_vertex_map_;
  // The number of vertices that were encoded (can be different from the number
  // of vertices of the input mesh).
  int num_encoded_vertices_;

  // Array for storing the encoded corner ids in the order their associated
  // vertices were decoded.
  std::vector<int32_t> processed_corner_ids_;

  // Array storing corners in the order they were visited during the
  // connectivity decoding (always storing the tip corner of each newly visited
  // face).
  std::vector<int> processed_connectivity_corners_;

  MeshAttributeIndicesEncodingData pos_encoding_data_;

  // Id of an attributes decoder that uses |pos_encoding_data_|.
  int pos_data_decoder_id_;

  // Data for non-position attributes used by the decoder.
  struct AttributeData {
    AttributeData() : decoder_id(-1), is_connectivity_used(true) {}
    // Id of the attribute decoder that was used to decode this attribute data.
    int decoder_id;
    MeshAttributeCornerTable connectivity_data;
    // Flag that can mark the connectivity_data invalid. In such case the base
    // corner table of the mesh should be used instead.
    bool is_connectivity_used;
    MeshAttributeIndicesEncodingData encoding_data;
    // Opposite corners to attribute seam edges.
    std::vector<int32_t> attribute_seam_corners;
  };
  std::vector<AttributeData> attribute_data_;

  TraversalDecoderT traversal_decoder_;
};

}  // namespace draco

#endif  // DRACO_COMPRESSION_MESH_MESH_EDGEBREAKER_DECODER_IMPL_H_