diff --git a/docs/spec/attributes.decoder.md b/docs/spec/attributes.decoder.md index d60164a..8381f4c 100644 --- a/docs/spec/attributes.decoder.md +++ b/docs/spec/attributes.decoder.md @@ -1,21 +1,295 @@ ## Attributes Decoder -### DecodeAttributesDecoderData() +### ParseAttributeDecodersData() ~~~~~ -DecodeAttributesDecoderData(buffer) { - num_attributes varUI32 - point_attribute_ids_.resize(num_attributes); - for (i = 0; i < num_attributes; ++i) { - att_type UI8 - data_type UI8 - components_count UI8 - normalized UI8 - custom_id UI16 - Initialize GeometryAttribute ga - att_id = pc->AddAttribute(new PointAttribute(ga)); - point_attribute_ids_[i] = att_id; +void ParseAttributeDecodersData() { + num_attributes_decoders UI8 + if (encoder_method == MESH_EDGEBREAKER_ENCODING) { + for (i = 0; i < num_attributes_decoders; ++i) { + att_dec_data_id[i] UI8 + att_dec_decoder_type[i] UI8 + att_dec_traversal_method[i] UI8 + } + } + for (i = 0; i < num_attributes_decoders; ++i) { + att_dec_num_attributes[i] varUI32 + for (j = 0; j < att_dec_num_attributes[i]; ++j) { + att_dec_att_type[i][j] UI8 + att_dec_data_type[i][j] UI8 + att_dec_num_components[i][j] UI8 + att_dec_normalized[i][j] UI8 + att_dec_unique_id[i][j] varUI32 + } + for (j = 0; j < att_dec_num_attributes[i]; ++j) { + seq_att_dec_decoder_type[i][j] UI8 + } + } +} +~~~~~ +{:.draco-syntax } + + +### DecodeAttributeData() + +~~~~~ +void DecodeAttributeData() { + ParseAttributeDecodersData(); + vertex_visited_point_ids.assign(num_attributes_decoders, 0); + curr_att_dec = 0; + if (encoder_method == MESH_EDGEBREAKER_ENCODING) { + DecodeAttributeSeams(); + for (i = 0; i < num_encoded_vertices + eb_num_split_symbols; ++i) { + if (is_vert_hole_[i]) { + UpdateVertexToCornerMap(i); + } + } + for (i = 1; i < num_attributes_decoders; ++i) { + curr_att_dec = i; + RecomputeVerticesInternal(); + } + Attribute_AssignPointsToCorners(); + } +ß + for (i = 0; i < num_attributes_decoders; ++i) { + curr_att_dec = i; + is_face_visited_.assign(num_faces, false); + is_vertex_visited_.assign(num_faces * 3, false); + GenerateSequence(); + if (encoder_method == MESH_EDGEBREAKER_ENCODING) { + UpdatePointToAttributeIndexMapping(); + } + } + for (i = 0; i < num_attributes_decoders; ++i) { + for (j = 0; j < att_dec_num_attributes[i]; ++j) { + att_dec_num_values_to_decode[i][j] = + encoded_attribute_value_index_to_corner_map[i].size(); + } + } + for (i = 0; i < num_attributes_decoders; ++i) { + curr_att_dec = i; + DecodePortableAttributes(); + DecodeDataNeededByPortableTransforms(); + TransformAttributesToOriginalFormat(); + } +} +~~~~~ +{:.draco-syntax } + + +### RecomputeVerticesInternal() + +~~~~~ +void RecomputeVerticesInternal() { + attr = curr_att_dec - 1; + num_new_vertices = 0; + attr_face_to_vertex.push_back(face_to_vertex); + corner_to_vertex_map_[curr_att_dec].assign( + attr_face_to_vertex[attr][0].size() * 3, -1); + for (v = 0; v < num_encoded_vertices + eb_num_split_symbols; ++v) { + c = vertex_corners_[v]; + if (c < 0) + continue; + first_vert_id(num_new_vertices++); + first_c = c; + if (IsVertexOnAttributeSeam(attr, v)) { + act_c = SwingLeft(curr_att_dec, first_c); + while (act_c >= 0) { + first_c = act_c; + act_c = SwingLeft(curr_att_dec, act_c); + } + } + corner_to_vertex_map_[curr_att_dec][first_c] = first_vert_id; + vertex_to_left_most_corner_map_[attr].push_back(first_c); + act_c = SwingRight(0, first_c); + while (act_c >= 0 && act_c != first_c) { + next_act_c = Next(act_c); + if (IsCornerOppositeToSeamEdge(next_act_c)) { + first_vert_id = num_new_vertices++; + vertex_to_left_most_corner_map_[attr].push_back(act_c); + } + corner_to_vertex_map_[curr_att_dec][act_c] = first_vert_id; + act_c = SwingRight(0, act_c); + } + } + + for (i = 0; i < corner_to_vertex_map_[curr_att_dec].size(); i += 3) { + face = i / 3; + attr_face_to_vertex[attr][0][face] = corner_to_vertex_map_[curr_att_dec][i]; + attr_face_to_vertex[attr][1][face] = corner_to_vertex_map_[curr_att_dec][i + 1]; + attr_face_to_vertex[attr][2][face] = corner_to_vertex_map_[curr_att_dec][i + 2]; + } +} +~~~~~ +{:.draco-syntax } + + +### Attribute_AssignPointsToCorners() + +~~~~~ +void Attribute_AssignPointsToCorners() { + num_corners = face_to_vertex[0].size() * 3; + for (v = 0; v < num_encoded_vertices + eb_num_split_symbols; ++v) { + c = vertex_corners_[v]; + if (c < 0) + continue; + deduplication_first_corner = c; + if (is_vert_hole_[v]) { + deduplication_first_corner = c; + } else { + for (i = 1; i < num_attributes_decoders; ++i) { + attr_id = i - 1; + if (!IsCornerOnAttributeSeam(0, attr_id, c)) + continue; + vert_id = corner_to_vertex_map_[i][c]; + act_c = SwingRight(0, c); + seam_found = false; + while (act_c != c) { + act_vert_id = corner_to_vertex_map_[i][act_c]; + if (act_vert_id != vert_id) { + deduplication_first_corner = act_c; + seam_found = true; + break; + } + act_c = SwingRight(0, act_c); + } + if (seam_found) + break; + } + } + + c = deduplication_first_corner; + corner_to_point_map[c] = point_to_corner_map.size(); + point_to_corner_map.push_back(c); + prev_c = c; + c = SwingRight(0, c); + while (c >= 0 && c != deduplication_first_corner) { + attribute_seam = false; + for (i = 1; i < num_attributes_decoders; ++i) { + vert_id = corner_to_vertex_map_[i][c]; + prev_vert_id = corner_to_vertex_map_[i][prev_c]; + if (vert_id != prev_vert_id) { + attribute_seam = true; + break; + } + } + if (attribute_seam) { + corner_to_point_map[c] = point_to_corner_map.size(); + point_to_corner_map.push_back(c); + } else { + corner_to_point_map[c] = corner_to_point_map[prev_c]; + } + prev_c = c; + c = SwingRight(0, c); + } + } +} +~~~~~ +{:.draco-syntax } + + +### SequentialGenerateSequence() + +~~~~~ +void SequentialGenerateSequence() { + for (i = 0; i < num_points; ++i) { + encoded_attribute_value_index_to_corner_map[curr_att_dec][i] = i; + } +} +~~~~~ +{:.draco-syntax } + + +### EdgebreakerGenerateSequence() + +~~~~~ +void EdgebreakerGenerateSequence() { + if (att_dec_traversal_method[curr_att_dec] == MESH_TRAVERSAL_PREDICTION_DEGREE) { + prediction_degree_.assign(num_encoded_vertices + eb_num_split_symbols, 0); + } + for (i = 0; i < num_faces; ++i) { + if (att_dec_traversal_method[curr_att_dec] == MESH_TRAVERSAL_DEPTH_FIRST) { + if (curr_att_dec == 0) { + EdgeBreakerTraverser_ProcessCorner(3 * i); + } else { + EdgeBreakerAttributeTraverser_ProcessCorner(3 * i); + } + } else { + PredictionDegree_TraverseFromCorner(3 * i); + } + } +} +~~~~~ +{:.draco-syntax } + + +### GenerateSequence() + +~~~~~ +void GenerateSequence() { + if (encoder_method == MESH_EDGEBREAKER_ENCODING) + EdgebreakerGenerateSequence(); + else + SequentialGenerateSequence(); +} +~~~~~ +{:.draco-syntax } + + +### UpdatePointToAttributeIndexMapping() + +~~~~~ +void UpdatePointToAttributeIndexMapping() { + indices_map_.assign(num_faces * 3, -1); + for (f = 0; f < num_faces; ++f) { + for (p = 0; p < 3; ++p) { + corner = (f * 3) + p; + point_id = corner_to_point_map[corner]; + CornerToVerts(curr_att_dec, corner, &vert, &next, &prev); + att_entry_id = + vertex_to_encoded_attribute_value_index_map[curr_att_dec][vert]; + indices_map_[point_id] = att_entry_id; + } + } +} +~~~~~ +{:.draco-syntax } + + +### TransformAttributesToOriginalFormat_StoreValues() + +~~~~~ +void TransformAttributesToOriginalFormat_StoreValues() { + num_components = GetNumComponents(); + num_values = att_dec_num_values_to_decode[curr_att_dec][curr_att]; + portable_attribute_data = seq_int_att_dec_original_values[curr_att_dec][curr_att]; + for (i = 0; i < num_values; ++i) { + for (c = 0; c < num_components; ++c) { + out_values.push_back(portable_attribute_data[(i * num_components) + c]); + } + } + seq_int_att_dec_dequantized_values[curr_att_dec][curr_att] = out_values; +} +~~~~~ +{:.draco-syntax } + + +### TransformAttributesToOriginalFormat() + +~~~~~ +void TransformAttributesToOriginalFormat() { + for (i = 0; i < att_dec_num_attributes.back(); ++i) { + curr_att = i; + dec_type = seq_att_dec_decoder_type[curr_att_dec][curr_att]; + if (dec_type == SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS) { + TransformAttributesToOriginalFormat_Normal(); + } else if (dec_type == SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGER) { + TransformAttributesToOriginalFormat_StoreValues(); + } else { + SequentialQuantizationAttributeDecoder_DequantizeValues(); + } + } } ~~~~~ {:.draco-syntax } diff --git a/docs/spec/boundary.decoder.md b/docs/spec/boundary.decoder.md new file mode 100644 index 0000000..94fa4ab --- /dev/null +++ b/docs/spec/boundary.decoder.md @@ -0,0 +1,147 @@ +## Boundary Decoder + +### DecodeAttributeSeams() + +~~~~~ +void DecodeAttributeSeams() { + for (a = 0; a < num_attributes_decoders - 1; ++a) { + AnsDecoder ans_decoder_; + RansInitDecoder(ans_decoder_, + attribute_connectivity_decoders_buffer[a].data(), + attribute_connectivity_decoders_size[a], L_RANS_BASE); + ans_decoders.push_back(ans_decoder_); + is_edge_on_seam_[a].assign(face_to_vertex[0].size() * 3, false); + } + + for (j = 0; j < num_faces; ++j) { + face_id = j; + for (k = 0; k < 3; ++k) { + local = k; + corner = (j * 3) + k; + CornerToVerts(0, corner, v, n, p); + opp_corner = PosOpposite(corner); + boundary_edge = opp_corner < 0; + if (!boundary_edge) { + if (opp_corner >= corner) { + for (a = 0; a < num_attributes_decoders - 1; ++a) { + RabsDescRead(&ans_decoders[a], + attribute_connectivity_decoders_prob_zero[a], &val); + if (val) { + att_connectivity_seam_opp[a].push_back(v); + att_connectivity_seam_src[a].push_back(n); + att_connectivity_seam_dest[a].push_back(p); + is_edge_on_seam_[a][corner] = true; + if (opp_corner >= 0) { + CornerToVerts(curr_att_dec, opp_corner, &opp_v, &opp_n, &opp_p); + att_connectivity_seam_opp[a].push_back(opp_v); + att_connectivity_seam_src[a].push_back(opp_n); + att_connectivity_seam_dest[a].push_back(opp_p); + is_edge_on_seam_[a][opp_corner] = true; + } + } + } + } + } else { + for (a = 0; a < num_attributes_decoders - 1; ++a) { + att_connectivity_seam_opp[a].push_back(v); + att_connectivity_seam_src[a].push_back(n); + att_connectivity_seam_dest[a].push_back(p); + is_edge_on_seam_[a][corner] = true; + } + } + } + } +} +~~~~~ +{:.draco-syntax} + + +### IsVertexOnAttributeSeam() + +~~~~~ +bool IsVertexOnAttributeSeam(attr, vert) { + for (i = 0; i < att_connectivity_seam_src[attr].size(); ++i) { + if (att_connectivity_seam_src[attr][i] == vert || + att_connectivity_seam_dest[attr][i] == vert) { + return true; + } + } + return false; +} +~~~~~ +{:.draco-syntax} + + +### IsCornerOnSeam() + +~~~~~ +bool IsCornerOnSeam(corner) { + CornerToVerts(0, corner, &v, &n, &p); + return IsVertexOnAttributeSeam(curr_att_dec - 1, v); +} +~~~~~ +{:.draco-syntax} + + +### IsCornerOnAttributeSeam() + +~~~~~ +bool IsCornerOnAttributeSeam(att_dec, attr, corner) { + CornerToVerts(att_dec, corner, &v, &n, &p); + return IsVertexOnAttributeSeam(attr, v); +} +~~~~~ +{:.draco-syntax} + + +### IsCornerOppositeToSeamEdge() + +~~~~~ +bool IsCornerOppositeToSeamEdge(corner) { + attr = curr_att_dec - 1; + return is_edge_on_seam_[attr][corner]; +} +~~~~~ +{:.draco-syntax} + + +### IsOnPositionBoundary() + +~~~~~ +bool IsOnPositionBoundary(vert_id) { + if (vertex_corners_[vert_id] < 0) + return true; + if (att_dec_decoder_type[curr_att_dec] == MESH_VERTEX_ATTRIBUTE) + return IsCornerOnAttributeSeam(curr_att_dec, curr_att_dec - 1, + vertex_corners_[vert_id]); + return false; +} +~~~~~ +{:.draco-syntax} + + +### IsOnAttributeBoundary() + +~~~~~ +bool IsOnAttributeBoundary(vert) { + corner = vertex_to_left_most_corner_map_[curr_att_dec - 1][vert]; + if (corner < 0) + return true; + return IsCornerOnSeam(corner); +} +~~~~~ +{:.draco-syntax} + + +### IsOnBoundary() + +~~~~~ +bool IsOnBoundary(att_dec, vert_id) { + if (att_dec == 0 || att_dec_decoder_type[att_dec] == MESH_VERTEX_ATTRIBUTE) + return IsOnPositionBoundary(vert_id); + else + return IsOnAttributeBoundary(vert_id); +} +~~~~~ +{:.draco-syntax} + diff --git a/docs/spec/connectivity.decoder.md b/docs/spec/connectivity.decoder.md new file mode 100644 index 0000000..f71ba30 --- /dev/null +++ b/docs/spec/connectivity.decoder.md @@ -0,0 +1,15 @@ + +## Connectivity Decoder + +### DecodeConnectivityData() + +~~~~~ +void DecodeConnectivityData() { + if (encoder_method == MESH_SEQUENTIAL_ENCODING) + DecodeSequentialConnectivityData(); + else + DecodeEdgebreakerConnectivityData(); +} + +~~~~~ +{:.draco-syntax } diff --git a/docs/spec/core.functions.md b/docs/spec/core.functions.md index 0a24c89..47afd24 100644 --- a/docs/spec/core.functions.md +++ b/docs/spec/core.functions.md @@ -1,65 +1,16 @@ ## Core Functions -### DecodeVarint +### DecodeVarint ~~~~~ -DecodeVarint() { - If (std::is_unsigned::value) { - in UI8 - If (in & (1 << 7)) { - out = DecodeVarint() - out = (out << 7) | (in & ((1 << 7) - 1)) - } else { - typename std::make_unsigned::type UIT; - out = DecodeVarint() - out = ConvertSymbolToSignedInt(out) - } - return out; -} -~~~~~ -{:.draco-syntax } - - -### ConvertSymbolToSignedInt() - -~~~~~ -ConvertSymbolToSignedInt() { - abs_val = val >> 1 - If (val & 1 == 0) { - return abs_val +void DecodeVarint(out_val) { + in UI8 + if (in & (1 << 7)) { + DecodeVarint(out_val); + out_val = (out_val << 7) | (in & ((1 << 7) - 1)); } else { - signed_val = -abs_val - 1 - } - return signed_val -} -~~~~~ -{:.draco-syntax } - - -Sequential Decoder - -FIXME: ^^^ Heading level? - -### decode_connectivity() - -~~~~~ -decode_connectivity() { - num_faces I32 - num_points I32 - connectivity _method UI8 - If (connectivity _method == 0) { - // TODO - } else { - loop num_faces { - If (num_points < 256) { - face[] UI8 - } else if (num_points < (1 << 16)) { - face[] UI16 - } else { - face[] UI32 - } - } + out_val = in; } } ~~~~~ diff --git a/docs/spec/corner.md b/docs/spec/corner.md new file mode 100644 index 0000000..0b78bd7 --- /dev/null +++ b/docs/spec/corner.md @@ -0,0 +1,203 @@ +## Corners + +### Next() + +~~~~~ +int Next(corner) { + if (corner < 0) + return corner; + return ((corner % 3) == 2) ? corner - 2 : corner + 1; +} +~~~~~ +{:.draco-syntax} + + +### Previous() + +~~~~~ +int Previous(corner) { + if (corner < 0) + return corner; + return ((corner % 3) == 0) ? corner + 2 : corner - 1; +} +~~~~~ +{:.draco-syntax} + + +### PosOpposite() + +~~~~~ +int PosOpposite(c) { + if (c >= opposite_corners_.size()) + return -1; + return opposite_corners_[c]; +} +~~~~~ +{:.draco-syntax} + + +### AttrOpposite() + +~~~~~ +int AttrOpposite(attr, corner) { + if (IsCornerOppositeToSeamEdge(corner)) + return -1; + return PosOpposite(corner); +} +~~~~~ +{:.draco-syntax} + + +### Opposite() + +~~~~~ +int Opposite(att_dec, c) { + if (att_dec == 0 || att_dec_decoder_type[att_dec] == MESH_VERTEX_ATTRIBUTE) + return PosOpposite(c); + return AttrOpposite(att_dec - 1, c); +} +~~~~~ +{:.draco-syntax} + + +### GetLeftCorner() + +~~~~~ +int GetLeftCorner(corner_id) { + if (corner_id < 0) + return kInvalidCornerIndex; + return PosOpposite(Previous(corner_id)); +} +~~~~~ +{:.draco-syntax} + + +### GetRightCorner() + +~~~~~ +int GetRightCorner(corner_id) { + if (corner_id < 0) + return kInvalidCornerIndex; + return PosOpposite(Next(corner_id)); +} +~~~~~ +{:.draco-syntax} + + +### SwingRight() + +~~~~~ +int SwingRight(attr_dec, corner) { + return Previous(Opposite(attr_dec, Previous(corner))); +} +~~~~~ +{:.draco-syntax} + + +### SwingLeft() + +~~~~~ +int SwingLeft(attr_dec, corner) { + return Next(Opposite(attr_dec, Next(corner))); +} +~~~~~ +{:.draco-syntax} + + +### CornerToVert() + +~~~~~ +int CornerToVert(att_dec, corner_id) { + CornerToVerts(att_dec, corner_id, &v, &n, &p); + return v; +} +~~~~~ +{:.draco-syntax} + + +### CornerToVertsInternal() + +~~~~~ +void CornerToVertsInternal(ftv, corner_id, v, n, p) { + local = corner_id % 3; + face = corner_id / 3; + if (local == 0) { + v = ftv[0][face]; + n = ftv[1][face]; + p = ftv[2][face]; + } else if (local == 1) { + v = ftv[1][face]; + n = ftv[2][face]; + p = ftv[0][face]; + } else if (local == 2) { + v = ftv[2][face]; + n = ftv[0][face]; + p = ftv[1][face]; + } +} +~~~~~ +{:.draco-syntax} + + +### CornerToVerts() + +~~~~~ +void CornerToVerts(att_dec, corner_id, v, n, p) { + if (att_dec == 0) { + return CornerToVertsInternal(face_to_vertex, corner_id, v, n, p); + } else { + if (att_dec_decoder_type[att_dec] == MESH_VERTEX_ATTRIBUTE) { + return CornerToVertsInternal(face_to_vertex, corner_id, v, n, p); + } else { + return CornerToVertsInternal(attr_face_to_vertex[att_dec - 1], corner_id, + v, n, p); + } + } +} +~~~~~ +{:.draco-syntax} + + +### SetOppositeCorners() + +~~~~~ +void SetOppositeCorners(c, opp_c) { + opposite_corners_[c] = opp_c; + opposite_corners_[opp_c] = c; +} +~~~~~ +{:.draco-syntax} + + +### MapCornerToVertex() + +~~~~~ +void MapCornerToVertex(corner_id, vert_id) { + corner_to_vertex_map_[0][corner_id] = vert_id; + if (vert_id >= 0) { + vertex_corners_[vert_id] = corner_id; + } +} +~~~~~ +{:.draco-syntax} + + +### UpdateVertexToCornerMap() + +~~~~~ +void UpdateVertexToCornerMap(vert) { + first_c = vertex_corners_[vert]; + if (first_c < 0) + return; + act_c = SwingLeft(0, first_c); + c = first_c; + while (act_c >= 0 && act_c != first_c) { + c = act_c; + act_c = SwingLeft(0, act_c); + } + if (act_c != first_c) { + vertex_corners_[vert] = c; + } +} +~~~~~ +{:.draco-syntax} diff --git a/docs/spec/corner.table.md b/docs/spec/corner.table.md deleted file mode 100644 index afbb395..0000000 --- a/docs/spec/corner.table.md +++ /dev/null @@ -1,213 +0,0 @@ - -## Corner Table - -### Opposite() - -~~~~~ -Opposite(corner) { - return opposite_corners_[corner]; -} -~~~~~ -{:.draco-syntax } - - -### Next() - -~~~~~ -Next(corner) { - return LocalIndex(++corner) ? corner : corner - 3; -} -~~~~~ -{:.draco-syntax } - - -### Previous() - -~~~~~ -Previous(corner) { - return LocalIndex(corner) ? corner - 1 : corner + 2; -} -~~~~~ -{:.draco-syntax } - - -### Vertex() - -~~~~~ -Vertex(corner) { - faces_[Face(corner)][LocalIndex(corner)]; -} -~~~~~ -{:.draco-syntax } - - -### Face() - -~~~~~ -Face(corner) { - return corner / 3; -} -~~~~~ -{:.draco-syntax } - - -### LocalIndex() - -~~~~~ -LocalIndex(corner) { - return corner % 3; -} -~~~~~ -{:.draco-syntax } - - -### num_vertices() - -~~~~~ -num_vertices() { - return vertex_corners_.size(); -} -~~~~~ -{:.draco-syntax } - - -### num_corners() - -~~~~~ -num_corners() { - return faces_.size() * 3; -} -~~~~~ -{:.draco-syntax } - - -### num_faces() - -~~~~~ -num_faces() { - return faces_.size(); -} -~~~~~ -{:.draco-syntax } - - -### bool IsOnBoundary() - -~~~~~ -bool IsOnBoundary(vert) { - corner = LeftMostCorner(vert); - if (SwingLeft(corner) < 0) - return true; - return false; -} -~~~~~ -{:.draco-syntax } - - -### SwingRight() - -~~~~~ -SwingRight(corner) { - return Previous(Opposite(Previous(corner))); -} -~~~~~ -{:.draco-syntax } - - -### SwingLeft() - -~~~~~ -SwingLeft(corner) { - return Next(Opposite(Next(corner))); -} -~~~~~ -{:.draco-syntax } - - -### GetLeftCorner() - -~~~~~ -GetLeftCorner(corner_id) { - if (corner_id < 0) - return kInvalidCornerIndex; - return Opposite(Previous(corner_id)); -} -~~~~~ -{:.draco-syntax } - - -### GetRightCorner() - -~~~~~ -GetRightCorner(corner_id) { - if (corner_id < 0) - return kInvalidCornerIndex; - return Opposite(Next(corner_id)); -} -~~~~~ -{:.draco-syntax } - - -### SetOppositeCorner() - -~~~~~ -SetOppositeCorner(corner_id, pp_corner_id) { - opposite_corners_[corner_id] = opp_corner_id; -} -~~~~~ -{:.draco-syntax } - - -### MapCornerToVertex() - -~~~~~ -MapCornerToVertex(corner_id, vert_id) { - face = Face(corner_id); - faces_[face][LocalIndex(corner_id)] = vert_id; - if (vert_id >= 0) { - vertex_corners_[vert_id] = corner_id; - } -} -~~~~~ -{:.draco-syntax } - - -### UpdateVertexToCornerMap() - -~~~~~ -UpdateVertexToCornerMap(vert) { - first_c = vertex_corners_[vert]; - if (first_c < 0) - return; - act_c = SwingLeft(first_c); - c = first_c; - while (act_c >= 0 && act_c != first_c) { - c = act_c; - act_c = SwingLeft(act_c); - } - if (act_c != first_c) { - vertex_corners_[vert] = c; - } -} -~~~~~ -{:.draco-syntax } - - -### LeftMostCorner() - -~~~~~ -LeftMostCorner(v) { - return vertex_corners_[v]; -} -~~~~~ -{:.draco-syntax } - - -### MakeVertexIsolated() - -~~~~~ -MakeVertexIsolated(vert) { - vertex_corners_[vert] = kInvalidCornerIndex; -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/cornertable.traversal.processor.md b/docs/spec/cornertable.traversal.processor.md deleted file mode 100644 index 098d795..0000000 --- a/docs/spec/cornertable.traversal.processor.md +++ /dev/null @@ -1,44 +0,0 @@ - -## CornerTable Traversal Processor - - -### IsFaceVisited() - -~~~~~ -IsFaceVisited(corner_id) { - if (corner_id < 0) - return true - return is_face_visited_[corner_id / 3]; -} -~~~~~ -{:.draco-syntax } - - -### MarkFaceVisited() - -~~~~~ -MarkFaceVisited(face_id) { - is_face_visited_[face_id] = true; -} -~~~~~ -{:.draco-syntax } - - -### IsVertexVisited() - -~~~~~ -IsVertexVisited(vert_id) { - return is_vertex_visited_[vert_id]; -} -~~~~~ -{:.draco-syntax } - - -### MarkVertexVisited() - -~~~~~ -MarkVertexVisited(vert_id) { - is_vertex_visited_[vert_id] = true; -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/draco.decoder.md b/docs/spec/draco.decoder.md index b861acb..a147be6 100644 --- a/docs/spec/draco.decoder.md +++ b/docs/spec/draco.decoder.md @@ -3,47 +3,28 @@ ### Decode() ~~~~~ -Decode() { - DecodeHeader() +void Decode() { + ParseHeader(); if (flags & METADATA_FLAG_MASK) - DecodeGeometryMetadata(metadata) - DecodeConnectivityData() - DecodeAttributeData() + DecodeMetadata(); + DecodeConnectivityData(); + DecodeAttributeData(); } ~~~~~ {:.draco-syntax} -### DecodeHeader() +### ParseHeader() ~~~~~ -DecodeHeader() { - draco_string UI8[5] - major_version UI8 - minor_version UI8 - encoder_type UI8 - encoder_method UI8 - flags +ParseHeader() { + draco_string UI8[5] + major_version UI8 + minor_version UI8 + encoder_type UI8 + encoder_method UI8 + flags UI16 } ~~~~~ {:.draco-syntax} - -### DecodeAttributeData() - -~~~~~ -DecodeAttributeData() { - num_attributes_decoders UI8 - for (i = 0; i < num_attributes_decoders; ++i) { - CreateAttributesDecoder(i); - } - for (auto &att_dec : attributes_decoders_) { - att_dec->Initialize(this, point_cloud_) - } - for (i = 0; i < num_attributes_decoders; ++i) { - attributes_decoders_[i]->DecodeAttributesDecoderData(buffer_) - } - DecodeAllAttributes() - OnAttributesDecoded() -~~~~~ -{:.draco-syntax} diff --git a/docs/spec/edgebreaker.decoder.md b/docs/spec/edgebreaker.decoder.md index 2fef020..0ff6b3f 100644 --- a/docs/spec/edgebreaker.decoder.md +++ b/docs/spec/edgebreaker.decoder.md @@ -1,299 +1,80 @@ ## EdgeBreaker Decoder -### DecodeConnectivityData() +### ParseEdgebreakerConnectivityData() ~~~~~ -DecodeConnectivityData() { - edgebreaker_traversal_type UI8 - num_new_verts varUI32 - num_encoded_vertices varUI32 - num_faces varUI32 - num_attribute_data I8 - num_encoded_symbols varUI32 - num_encoded_split_symbols varUI32 - encoded_connectivity_size varUI32 +void ParseEdgebreakerConnectivityData() { + edgebreaker_traversal_type UI8 + num_new_vertices varUI32 + num_encoded_vertices varUI32 + num_faces varUI32 + num_attribute_data I8 + num_encoded_symbols varUI32 + num_encoded_split_symbols varUI32 + encoded_connectivity_size varUI32 +} +~~~~~ +{:.draco-syntax } + + +### ParseTopologySplitEvents() + +~~~~~ +void ParseTopologySplitEvents() { + num_topologoy_splits varUI32 + for (i = 0; i < num_topologoy_splits; ++i) { + source_id_delta[i] varUI32 + split_id_delta[i] varUI32 + } + for (i = 0; i < num_topologoy_splits; ++i) { + split_edge_bit[i] f[1] + source_edge_bit[i] f[1] + } +} +~~~~~ +{:.draco-syntax } + + +### DecodeEdgebreakerConnectivityData() + +~~~~~ +void DecodeEdgebreakerConnectivityData() { + ParseEdgebreakerConnectivityData(); + // file pointer must be set to current position // + encoded_connectivity_size - hole_and_split_bytes = DecodeHoleAndTopologySplitEvents() + DecodeTopologySplitEvents(); + + // file pointer must be saved, as it points to the attribute data // file pointer must be set to old current position - EdgeBreakerTraversalValence_Start(num_encoded_vertices) - DecodeConnectivity(num_symbols) - if (attribute_data_.size() > 0) { - for (ci = 0; ci < corner_table_->num_corners(); ci += 3) { - DecodeAttributeConnectivitiesOnFace(ci) - } - } - for (i = 0; i < corner_table_->num_vertices(); ++i) { - if (is_vert_hole_[i]) { - corner_table_->UpdateVertexToCornerMap(i); - } - } - // Decode attribute connectivity. - for (uint32_t i = 0; i < attribute_data_.size(); ++i) { - attribute_data_[i].connectivity_data.InitEmpty(corner_table_); - for (int32_t c : attribute_data_[i].attribute_seam_corners) { - attribute_data_[i].connectivity_data.AddSeamEdge(c); - } - attribute_data_[i].connectivity_data.RecomputeVertices(nullptr, - nullptr); - } - // Preallocate vertex to value mapping - AssignPointsToCorners() + EdgebreakerTraversalStart(); + DecodeEdgeBreakerConnectivity(); } ~~~~~ {:.draco-syntax } -### AssignPointsToCorners() +### ProcessSplitData() ~~~~~ -AssignPointsToCorners() { - decoder_->mesh()->SetNumFaces(corner_table_->num_faces()); - if (attribute_data_.size() == 0) { - for (f = 0; f < decoder_->mesh()->num_faces(); ++f) { - for (c = 0; c < 3; ++c) { - vert_id = corner_table_->Vertex(3 * f + c); - if (point_id == -1) - point_id = num_points++; - face[c] = point_id; - } - decoder_->mesh()->SetFace(f, face); - } - decoder_->point_cloud()->set_num_points(num_points); - Return true; - } - for (v = 0; v < corner_table_->num_vertices(); ++v) { - c = corner_table_->LeftMostCorner(v); - if (c < 0) - continue; - deduplication_first_corner = c; - if (!is_vert_hole_[v]) { - for (uint32_t i = 0; i < attribute_data_.size(); ++i) { - if (!attribute_data_[i].connectivity_data.IsCornerOnSeam(c)) - continue; - vert_id = attribute_data_[i].connectivity_data.Vertex(c); - act_c = corner_table_->SwingRight(c); - seam_found = false; - while (act_c != c) { - if (attribute_data_[i].connectivity_data.Vertex(act_c) != - vert_id) { - deduplication_first_corner = act_c; - seam_found = true; - break; - } - act_c = corner_table_->SwingRight(act_c); - } - if (seam_found) - break; - } - } - c = deduplication_first_corner; - corner_to_point_map[c] = point_to_corner_map.size(); - point_to_corner_map.push_back(c); - prev_c = c; - c = corner_table_->SwingRight(c); - while (c >= 0 && c != deduplication_first_corner) { - attribute_seam = false; - for (uint32_t i = 0; i < attribute_data_.size(); ++i) { - if (attribute_data_[i].connectivity_data.Vertex(c) != - attribute_data_[i].connectivity_data.Vertex(prev_c)) { - attribute_seam = true; - break; - } - } - if (attribute_seam) { - corner_to_point_map[c] = point_to_corner_map.size(); - point_to_corner_map.push_back(c); - } else { - corner_to_point_map[c] = corner_to_point_map[prev_c]; - } - prev_c = c; - c = corner_table_->SwingRight(c); - } - } - for (f = 0; f < decoder_->mesh()->num_faces(); ++f) { - for (c = 0; c < 3; ++c) { - face[c] = corner_to_point_map[3 * f + c]; - } - decoder_->mesh()->SetFace(f, face); - } - decoder_->point_cloud()->set_num_points(point_to_corner_map.size()); -} -~~~~~ -{:.draco-syntax } - - -### DecodeConnectivity() - -~~~~~ -DecodeConnectivity(num_symbols) { - for (i = 0; i < num_symbols; ++i) { - symbol = TraversalValence_DecodeSymbol() - corner = 3 * num_faces++ - if (symbol == TOPOLOGY_C) { - vertex_x = UpdateCornerTableForSymbolC() - is_vert_hole_[vertex_x] = false; - } else if (symbol == TOPOLOGY_R || symbol == TOPOLOGY_L) { - UpdateCornerTableForSymbolLR() - check_topology_split = true; - } else if (symbol == TOPOLOGY_S) { - HandleSymbolS() - } else if (symbol == TOPOLOGY_E) { - UpdateCornerTableForSymbolE() - check_topology_split = true; - } - active_corner_stack.back() = corner; - traversal_decoder_.NewActiveCornerReached(corner); - if (check_topology_split) { - encoder_symbol_id = num_symbols - symbol_id - 1; - while (true) { - split = IsTopologySplit(encoder_symbol_id, &split_edge, - &encoder_split_symbol_id); - if (!split) { - break; - } - act_top_corner = corner; - if (split_edge == RIGHT_FACE_EDGE) { - new_active_corner = corner_table_->Next(act_top_corner); - } else { - new_active_corner = corner_table_->Previous(act_top_corner); - } - decoder_split_symbol_id = num_symbols - - encoder_split_symbol_id - 1; - topology_split_active_corners[decoder_split_symbol_id] = - new_active_corner; - } - } - } - while (active_corner_stack.size() > 0) { - corner = active_corner_stack.pop_back(); - interior_face = traversal_decoder_.DecodeStartFaceConfiguration(); - if (interior_face == true) { - UpdateCornerTableForInteriorFace() - for (ci = 0; ci < 3; ++ci) { - is_vert_hole_[corner_table_->Vertex(new_corner + ci)] = false; - } - init_face_configurations_.push_back(true); - init_corners_.push_back(new_corner); - } else { - init_face_configurations_.push_back(false); - init_corners_.push_back(corner); - } +void ProcessSplitData() { + last_id = 0; + for (i = 0; i < source_id_delta.size(); ++i) { + source_symbol_id[i] = source_id_delta[i] + last_id; + split_symbol_id.[i] = source_symbol_id[i] - split_id_delta[i]; + last_id = source_symbol_id[i]; } } ~~~~~ {:.draco-syntax } -### UpdateCornerTableForSymbolC() +### DecodeTopologySplitEvents() ~~~~~ -UpdateCornerTableForSymbolC(corner) { - corner_a = active_corner_stack.back(); - corner_b = corner_table_->Previous(corner_a); - while (corner_table_->Opposite(corner_b) >= 0) { - corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b)); - } - SetOppositeCorners(corner_a, corner + 1); - SetOppositeCorners(corner_b, corner + 2); - vertex_x = corner_table_->Vertex(corner_table_->Next(corner_a)); - corner_table_->MapCornerToVertex(corner, vertex_x); - corner_table_->MapCornerToVertex( - corner + 1, corner_table_->Vertex(corner_table_->Next(corner_b))); - corner_table_->MapCornerToVertex( - corner + 2, corner_table_->Vertex(corner_table_->Previous(corner_a))); - return vertex_x; -} -~~~~~ -{:.draco-syntax } - - - -### UpdateCornerTableForSymbolLR() - -~~~~~ -UpdateCornerTableForSymbolLR(corner, symbol) { - if (symbol == TOPOLOGY_R) { - opp_corner = corner + 2; - } else { - opp_corner = corner + 1; - } - SetOppositeCorners(opp_corner, corner_a); - corner_table_->MapCornerToVertex(opp_corner,num_vertices++); - corner_table_->MapCornerToVertex( - corner_table_->Next(opp_corner), - corner_table_->Vertex(corner_table_->Previous(corner_a))); - corner_table_->MapCornerToVertex( - corner_table_->Previous(opp_corner), - corner_table_->Vertex(corner_table_->Next(corner_a))); -} -~~~~~ -{:.draco-syntax } - - -### HandleSymbolS() - -~~~~~ -HandleSymbolS(corner) { - corner_b = active_corner_stack.pop_back(); - it = topology_split_active_corners.find(symbol_id); - if (it != topology_split_active_corners.end()) { - active_corner_stack.push_back(it->second); - } - corner_a = active_corner_stack.back(); - SetOppositeCorners(corner_a, corner + 2); - SetOppositeCorners(corner_b, corner + 1); - vertex_p = corner_table_->Vertex(corner_table_->Previous(corner_a)); - corner_table_->MapCornerToVertex(corner, vertex_p); - corner_table_->MapCornerToVertex( - corner + 1, corner_table_->Vertex(corner_table_->Next(corner_a))); - corner_table_->MapCornerToVertex(corner + 2, - corner_table_->Vertex(corner_table_->Previous(corner_b))); - corner_n = corner_table_->Next(corner_b); - vertex_n = corner_table_->Vertex(corner_n); - traversal_decoder_.MergeVertices(vertex_p, vertex_n); - // TraversalValence_MergeVertices - while (corner_n >= 0) { - corner_table_->MapCornerToVertex(corner_n, vertex_p); - corner_n = corner_table_->SwingLeft(corner_n); - } - corner_table_->MakeVertexIsolated(vertex_n); -} -~~~~~ -{:.draco-syntax } - - -### UpdateCornerTableForSymbolE() - -~~~~~ -UpdateCornerTableForSymbolE() { - corner_table_->MapCornerToVertex(corner, num_vertices++); - corner_table_->MapCornerToVertex(corner + 1, num_vertices++); - corner_table_->MapCornerToVertex(corner + 2, num_vertices++); -} -~~~~~ -{:.draco-syntax } - - -### UpdateCornerTableForInteriorFace() - -~~~~~ -UpdateCornerTableForInteriorFace() { - corner_b = corner_table_->Previous(corner); - while (corner_table_->Opposite(corner_b) >= 0) { - corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b)); - } - corner_c = corner_table_->Next(corner); - while (corner_table_->Opposite(corner_c) >= 0) { - corner_c = corner_table_->Next(corner_table_->Opposite(corner_c)); - } - face(num_faces++); - corner_table_->MapCornerToVertex( - new_corner, corner_table_->Vertex(corner_table_->Next(corner_b))); - corner_table_->MapCornerToVertex( - new_corner + 1, corner_table_->Vertex(corner_table_->Next(corner_c))); - corner_table_->MapCornerToVertex( - new_corner + 2, corner_table_->Vertex(corner_table_->Next(corner))); +void DecodeTopologySplitEvents() { + ParseTopologySplitEvents(); + ProcessSplitData(); } ~~~~~ {:.draco-syntax } @@ -302,41 +83,32 @@ UpdateCornerTableForInteriorFace() { ### IsTopologySplit() ~~~~~ -IsTopologySplit(encoder_symbol_id, *out_face_edge, - *out_encoder_split_symbol_id) { - if (topology_split_data_.size() == 0) +bool IsTopologySplit(encoder_symbol_id, out_face_edge, + out_encoder_split_symbol_id) { + if (source_symbol_id.back() != encoder_symbol_id) return false; - if (topology_split_data_.back().source_symbol_id != encoder_symbol_id) - return false; - *out_face_edge = topology_split_data_.back().source_edge; - *out_encoder_split_symbol_id = - topology_split_data_.back().split_symbol_id; - topology_split_data_.pop_back(); + *out_face_edge = source_edge_bit.pop(); + *out_encoder_split_symbol_id = split_symbol_id.pop(); + source_symbol_id.pop(); return true; } ~~~~~ {:.draco-syntax } -### DecodeAttributeConnectivitiesOnFace() +### ReplaceVerts() ~~~~~ -DecodeAttributeConnectivitiesOnFace(corner) { - corners[3] = {corner, corner_table_->Next(corner), - corner_table_->Previous(corner)} - for (c = 0; c < 3; ++c) { - opp_corner = corner_table_->Opposite(corners[c]); - if (opp_corner < 0) { - for (uint32_t i = 0; i < attribute_data_.size(); ++i) { - attribute_data_[i].attribute_seam_corners.push_back(corners[c]); - } - continue +void ReplaceVerts(from, to) { + for (i = 0; i < face_to_vertex[0].size(); ++i) { + if (face_to_vertex[0][i] == from) { + face_to_vertex[0][i] = to; } - for (uint32_t i = 0; i < attribute_data_.size(); ++i) { - bool is_seam = traversal_decoder_.DecodeAttributeSeam(i); - if (is_seam) { - attribute_data_[i].attribute_seam_corners.push_back(corners[c]); - } + if (face_to_vertex[1][i] == from) { + face_to_vertex[1][i] = to; + } + if (face_to_vertex[2][i] == from) { + face_to_vertex[2][i] = to; } } } @@ -344,12 +116,238 @@ DecodeAttributeConnectivitiesOnFace(corner) { {:.draco-syntax } -### SetOppositeCorners() +### UpdateCornersAfterMerge() ~~~~~ -SetOppositeCorners(corner_0, corner_1) { - corner_table_->SetOppositeCorner(corner_0, corner_1); - corner_table_->SetOppositeCorner(corner_1, corner_0); +void UpdateCornersAfterMerge(c, v) { + opp_corner = PosOpposite(c); + if (opp_corner >= 0) { + corner_n = Next(opp_corner); + while (corner_n >= 0) { + MapCornerToVertex(corner_n, v); + corner_n = SwingLeft(0, corner_n); + } + } +} +~~~~~ +{:.draco-syntax } + + +### NewActiveCornerReached() + +~~~~~ +void NewActiveCornerReached(new_corner, symbol_id) { + check_topology_split = false; + switch (last_symbol_) { + case TOPOLOGY_C: + { + corner_a = active_corner_stack.back(); + corner_b = Previous(corner_a); + while (PosOpposite(corner_b) >= 0) { + b_opp = PosOpposite(corner_b); + corner_b = Previous(b_opp); + } + SetOppositeCorners(corner_a, new_corner + 1); + SetOppositeCorners(corner_b, new_corner + 2); + active_corner_stack.back() = new_corner; + } + vert = CornerToVert(Next(corner_a)); + next = CornerToVert(Next(corner_b)); + prev = CornerToVert(Previous(corner_a)); + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + vertex_valences_[next] += 1; + vertex_valences_[prev] += 1; + } + face_to_vertex[0].push_back(vert); + face_to_vertex[1].push_back(next); + face_to_vertex[2].push_back(prev); + is_vert_hole_[vert] = false; + MapCornerToVertex(new_corner, vert); + MapCornerToVertex(new_corner + 1, next); + MapCornerToVertex(new_corner + 2, prev); + break; + case TOPOLOGY_S: + { + corner_b = active_corner_stack.pop(); + for (i = 0; i < split_active_corners.size(); ++i) { + if (split_active_corners[i].decoder_split_symbol_id == symbol_id) { + active_corner_stack.push_back(split_active_corners[i].corner); + } + } + corner_a = active_corner_stack.back(); + SetOppositeCorners(corner_a, new_corner + 2); + SetOppositeCorners(corner_b, new_corner + 1); + active_corner_stack.back() = new_corner; + } + + vert = CornerToVert(Previous(corner_a)); + next = CornerToVert(Next(corner_a)); + prev = CornerToVert(Previous(corner_b)); + MapCornerToVertex(new_corner, vert); + MapCornerToVertex(new_corner + 1, next); + MapCornerToVertex(new_corner + 2, prev); + corner_n = Next(corner_b); + vertex_n = CornerToVert(corner_n); + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + vertex_valences_[vert] += vertex_valences_[vertex_n]; + } + ReplaceVerts(vertex_n, vert); + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + vertex_valences_[next] += 1; + vertex_valences_[prev] += 1; + } + face_to_vertex[0].push_back(vert); + face_to_vertex[1].push_back(next); + face_to_vertex[2].push_back(prev); + UpdateCornersAfterMerge(new_corner + 1, vert); + vertex_corners_[vertex_n] = kInvalidCornerIndex; + break; + case TOPOLOGY_R: + { + corner_a = active_corner_stack.back(); + opp_corner = new_corner + 2; + SetOppositeCorners(opp_corner, corner_a); + active_corner_stack.back() = new_corner; + } + check_topology_split = true; + vert = CornerToVert(Previous(corner_a)); + next = CornerToVert(Next(corner_a)); + prev = ++last_vert_added; + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + vertex_valences_[vert] += 1; + vertex_valences_[next] += 1; + vertex_valences_[prev] += 2; + } + + face_to_vertex[0].push_back(vert); + face_to_vertex[1].push_back(next); + face_to_vertex[2].push_back(prev); + + MapCornerToVertex(new_corner + 2, prev); + MapCornerToVertex(new_corner, vert); + MapCornerToVertex(new_corner + 1, next); + break; + case TOPOLOGY_L: + { + corner_a = active_corner_stack.back(); + opp_corner = new_corner + 1; + SetOppositeCorners(opp_corner, corner_a); + active_corner_stack.back() = new_corner; + } + check_topology_split = true; + vert = CornerToVert(Previous(corner_a)); + next = CornerToVert(Next(corner_a)); + prev = ++last_vert_added; + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + vertex_valences_[vert] += 1; + vertex_valences_[next] += 1; + vertex_valences_[prev] += 2; + } + + face_to_vertex[0].push_back(vert); + face_to_vertex[1].push_back(next); + face_to_vertex[2].push_back(prev); + + MapCornerToVertex(new_corner + 2, prev); + MapCornerToVertex(new_corner, vert); + MapCornerToVertex(new_corner + 1, next); + break; + case TOPOLOGY_E: + active_corner_stack.push_back(new_corner); + check_topology_split = true; + vert = last_vert_added + 1; + next = vert + 1; + prev = next + 1; + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + vertex_valences_[vert] += 2; + vertex_valences_[next] += 2; + vertex_valences_[prev] += 2; + } + face_to_vertex[0].push_back(vert); + face_to_vertex[1].push_back(next); + face_to_vertex[2].push_back(prev); + last_vert_added = prev; + MapCornerToVertex(new_corner, vert); + MapCornerToVertex(new_corner + 1, next); + MapCornerToVertex(new_corner + 2, prev); + break; + } + + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + // Compute the new context that is going to be used + // to decode the next symbol. + active_valence = vertex_valences_[next]; + if (active_valence < MIN_VALENCE) { + clamped_valence = MIN_VALENCE; + } else if (active_valence > MAX_VALENCE) { + clamped_valence = MAX_VALENCE; + } else { + clamped_valence = active_valence; + } + active_context_ = (clamped_valence - MIN_VALENCE); + } + + if (check_topology_split) { + encoder_symbol_id = num_encoded_symbols - symbol_id - 1; + while (IsTopologySplit(encoder_symbol_id, &split_edge, + &enc_split_id)) { + act_top_corner = active_corner_stack.back(); + if (split_edge == RIGHT_FACE_EDGE) { + new_active_corner = Next(act_top_corner); + } else { + new_active_corner = Previous(act_top_corner); + } + // Convert the encoder split symbol id to decoder symbol id. + dec_split_id = num_encoded_symbols - enc_split_id - 1; + topology_edge_list[dec_split_id] = new_active_corner; + } + } +} +~~~~~ +{:.draco-syntax } + + +### ParseEdgebreakerStandardSymbol() + +~~~~~ +void ParseEdgebreakerStandardSymbol() { + bit_symbol_buffer.DecodeLeastSignificantBits32(1, &symbol); + if (symbol != TOPOLOGY_C) { + // Else decode two additional bits. + bit_symbol_buffer.DecodeLeastSignificantBits32(2, &symbol_suffix); + symbol |= (symbol_suffix << 1); + } + last_symbol_ = symbol; +} +~~~~~ +{:.draco-syntax } + + +### EdgebreakerDecodeSymbol() + +~~~~~ +void EdgebreakerDecodeSymbol() { + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + EdgebreakerValenceDecodeSymbol(sym); + } else { + ParseEdgebreakerStandardSymbol(sym); + } +} +~~~~~ +{:.draco-syntax } + + +### DecodeEdgeBreakerConnectivity() + +~~~~~ +void DecodeEdgeBreakerConnectivity() { + is_vert_hole_.assign(num_encoded_vertices + num_encoded_split_symbols, true); + for (i = 0; i < num_encoded_symbols; ++i) { + EdgebreakerDecodeSymbol(); + corner = 3 * i; + NewActiveCornerReached(corner, i); + } + ProcessInteriorEdges(); } ~~~~~ {:.draco-syntax } diff --git a/docs/spec/edgebreaker.hole.and.topology.md b/docs/spec/edgebreaker.hole.and.topology.md deleted file mode 100644 index 813b093..0000000 --- a/docs/spec/edgebreaker.hole.and.topology.md +++ /dev/null @@ -1,65 +0,0 @@ - -## EdgeBreaker Hole and Topology Split Events - - -### DecodeHoleAndTopologySplitEvents() - -~~~~~ -DecodeHoleAndTopologySplitEvents() { - num_topologoy_splits varUI32 - source_symbol_id = 0 - for (i = 0; i < num_topologoy_splits; ++i) { - delta varUI32 - split_data[i].source_symbol_id = delta + source_symbol_id - delta varUI32 - split_data[i].split_symbol_id = source_symbol_id - delta - } - for (i = 0; i < num_topologoy_splits; ++i) { - split_data[i].split_edge bits1 - split_data[i].source_edge bits1 - } - num_hole_events varUI32 - symbol_id = 0 - for (i = 0; i < num_hole_events; ++i) { - delta varUI32 - hole_data[i].symbol_id = delta + symbol_id - } - return bytes_decoded; -} -~~~~~ -{:.draco-syntax } - - -### CreateAttributesDecoder - -~~~~~ -CreateAttributesDecoder() { - att_data_id I8 - decoder_type UI8 - if (att_data_id >= 0) { - attribute_data_[att_data_id].decoder_id = att_decoder_id; - } - traversal_method_encoded UI8 - if (decoder_type == MESH_VERTEX_ATTRIBUTE) { - if (att_data_id < 0) { - encoding_data = &pos_encoding_data_; - } else { - encoding_data = &attribute_data_[att_data_id].encoding_data; - attribute_data_[att_data_id].is_connectivity_used = false; - } - if (traversal_method == MESH_TRAVERSAL_DEPTH_FIRST) { - typedef EdgeBreakerTraverser AttTraverser; - sequencer = CreateVertexTraversalSequencer(encoding_data); - } else if (traversal_method == MESH_TRAVERSAL_PREDICTION_DEGREE) { - typedef PredictionDegreeTraverser AttTraverser; - sequencer = CreateVertexTraversalSequencer(encoding_data); - } - } else { - // TODO - } - att_controller(new SequentialAttributeDecodersController(std::move(sequencer))) - decoder_->SetAttributesDecoder(att_decoder_id, std::move(att_controller)); -} -~~~~~ -{:.draco-syntax } - diff --git a/docs/spec/edgebreaker.traversal.decoder.md b/docs/spec/edgebreaker.traversal.decoder.md deleted file mode 100644 index 8c3020d..0000000 --- a/docs/spec/edgebreaker.traversal.decoder.md +++ /dev/null @@ -1,46 +0,0 @@ - -## Edgebreaker Traversal Decoder - -### EdgebreakerTraversal_Start() - -~~~~~ -EdgebreakerTraversal_Start() { - size UI64 - symbol_buffer_ size * UI8 - size UI64 - start_face_buffer_ size * UI8 - if (num_attribute_data > 0) { - attribute_connectivity_decoders_ = - new BinaryDecoder[num_attribute_data] - for (i = 0; i < num_attribute_data; ++i) { - attribute_connectivity_decoders_[i].StartDecoding() - // RansBitDecoder_StartDecoding - } -} -~~~~~ -{:.draco-syntax } - - -### Traversal_DecodeSymbol() - -~~~~~ -Traversal_DecodeSymbol() { - symbol_buffer_.DecodeLeastSignificantBits32(1, &symbol); bits1 - if (symbol != TOPOLOGY_C) { - symbol_buffer_.DecodeLeastSignificantBits32(2, &symbol_suffix); bits2 - symbol |= (symbol_suffix << 1); - } - return symbol -} -~~~~~ -{:.draco-syntax } - - -### DecodeAttributeSeam() - -~~~~~ -DecodeAttributeSeam(int attribute) { - return attribute_connectivity_decoders_[attribute].DecodeNextBit(); -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/edgebreaker.traversal.md b/docs/spec/edgebreaker.traversal.md new file mode 100644 index 0000000..487c9f5 --- /dev/null +++ b/docs/spec/edgebreaker.traversal.md @@ -0,0 +1,211 @@ + +## EdgeBreaker Traversal + +### ParseEdgebreakerTraversalStandardData() + +~~~~~ +void ParseEdgebreakerTraversalStandardData() { + eb_symbol_buffer_size UI64 + eb_symbol_buffer size * UI8 + eb_start_face_buffer_size UI64 + eb_start_face_buffer size * UI8 + for (i = 0; i < num_attribute_data; ++i) { + attribute_connectivity_decoders_prob_zero[i] UI8 + attribute_connectivity_decoders_size[i] UI32 + attribute_connectivity_decoders_buffer[i] size * UI8 + } +} +~~~~~ +{:.draco-syntax } + + +### DecodeEdgebreakerTraversalData() + +~~~~~ +void DecodeEdgebreakerTraversalData() { + ParseEdgebreakerTraversalStandardData(); + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + ParseEdgebreakerTraversalValenceData(); + } +} +~~~~~ +{:.draco-syntax } + + +### EdgebreakerTraversalStart() + +~~~~~ +void EdgebreakerTraversalStart() { + last_symbol_ = -1; + active_context_ = -1; + DecodeEdgebreakerTraversalData(); + if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) { + EdgeBreakerTraversalValenceStart(); + } +} +~~~~~ +{:.draco-syntax } + + +### IsFaceVisited() + +~~~~~ +bool IsFaceVisited(face_id) { + if (face_id < 0) + return true; // Invalid faces are always considered as visited. + return is_face_visited_[face_id]; +} +~~~~~ +{:.draco-syntax } + + +### OnNewVertexVisited() + +~~~~~ +void OnNewVertexVisited(vertex, corner) { + encoded_attribute_value_index_to_corner_map[curr_att_dec].push_back(corner); + vertex_to_encoded_attribute_value_index_map[curr_att_dec][vertex] = + vertex_visited_point_ids[curr_att_dec]; + vertex_visited_point_ids[curr_att_dec]++; +} +~~~~~ +{:.draco-syntax } + + +### EdgeBreakerTraverser_ProcessCorner() + +~~~~~ +void EdgeBreakerTraverser_ProcessCorner(corner_id) { + face = corner_id / 3; + if (IsFaceVisited(face)) + return; // Already traversed. + corner_traversal_stack_.push_back(corner_id); + next_vert = face_to_vertex[1][face]; + prev_vert = face_to_vertex[2][face]; + if (!is_vertex_visited_[next_vert]) { + is_vertex_visited_[next_vert] = true; + next_c = Next(corner_id); + OnNewVertexVisited(next_vert, next_c); + } + if (!is_vertex_visited_[prev_vert]) { + is_vertex_visited_[prev_vert] = true; + prev_c = Previous(corner_id); + OnNewVertexVisited(prev_vert, prev_c); + } + while (!corner_traversal_stack_.empty()) { + corner_id = corner_traversal_stack_.back(); + face_id = corner_id / 3; + if (corner_id < 0 || IsFaceVisited(face_id)) { + // This face has been already traversed. + corner_traversal_stack_.pop_back(); + continue; + } + while (true) { + face_id = corner_id / 3; + is_face_visited_[face_id] = true; + vert_id = CornerToVert(0, corner_id); + if (!is_vertex_visited_[vert_id]) { + on_boundary = IsOnPositionBoundary(vert_id); + is_vertex_visited_[vert_id] = true; + OnNewVertexVisited(vert_id, corner_id); + if (!on_boundary) { + corner_id = GetRightCorner(corner_id); + continue; + } + } + right_corner_id = GetRightCorner(corner_id); + left_corner_id = GetLeftCorner(corner_id); + right_face_id((right_corner_id < 0 ? -1 : right_corner_id / 3)); + left_face_id((left_corner_id < 0 ? -1 : left_corner_id / 3)); + if (IsFaceVisited(right_face_id)) { + if (IsFaceVisited(left_face_id)) { + corner_traversal_stack_.pop_back(); + break; + } else { + corner_id = left_corner_id; + } + } else { + if (IsFaceVisited(left_face_id)) { + corner_id = right_corner_id; + } else { + corner_traversal_stack_.back() = left_corner_id; + corner_traversal_stack_.push_back(right_corner_id); + break; + } + } + } + } +} +~~~~~ +{:.draco-syntax } + + +### EdgeBreakerAttributeTraverser_ProcessCorner() + +~~~~~ +void EdgeBreakerAttributeTraverser_ProcessCorner(corner_id) { + face = corner_id / 3; + if (IsFaceVisited(face)) + return; // Already traversed. + corner_traversal_stack_.push_back(corner_id); + CornerToVerts(curr_att_dec, corner_id, &vert_id, &next_vert, &prev_vert); + if (!is_vertex_visited_[next_vert]) { + is_vertex_visited_[next_vert] = true; + next_c = Next(corner_id); + OnNewVertexVisited(next_vert, next_c); + } + if (!is_vertex_visited_[prev_vert]) { + is_vertex_visited_[prev_vert] = true; + prev_c = Previous(corner_id); + OnNewVertexVisited(prev_vert, prev_c); + } + while (!corner_traversal_stack_.empty()) { + corner_id = corner_traversal_stack_.back(); + face_id = corner_id / 3; + if (corner_id < 0 || IsFaceVisited(face_id)) { + corner_traversal_stack_.pop_back(); + continue; + } + while (true) { + face_id = corner_id / 3; + is_face_visited_[face_id] = true; + vert_id = CornerToVert(curr_att_dec, corner_id); + if (!is_vertex_visited_[vert_id]) { + on_seam = IsOnBoundary(curr_att_dec, vert_id); + pos_vert_id = CornerToVert(0, corner_id); + on_boundary = (on_seam) ? on_seam : IsOnPositionBoundary(pos_vert_id); + is_vertex_visited_[vert_id] = true; + OnNewVertexVisited(vert_id, corner_id); + if (!on_boundary) { + corner_id = GetRightCorner(corner_id); + continue; + } + } + next_c = Next(corner_id); + right_seam = IsCornerOppositeToSeamEdge(next_c); + right_corner_id = (right_seam) ? -1 : GetRightCorner(corner_id); + prev_c = Previous(corner_id); + left_seam = IsCornerOppositeToSeamEdge(prev_c); + left_corner_id = (left_seam) ? -1 : GetLeftCorner(corner_id); + right_face_id((right_corner_id < 0 ? -1 : right_corner_id / 3)); + left_face_id((left_corner_id < 0 ? -1 : left_corner_id / 3)); + if (IsFaceVisited(left_face_id)) { + corner_traversal_stack_.pop_back(); + break; + } else { + corner_id = left_corner_id; + } + } else { + if (IsFaceVisited(left_face_id)) { + corner_id = right_corner_id; + } else { + corner_traversal_stack_.back() = left_corner_id; + corner_traversal_stack_.push_back(right_corner_id); + break; + } + } + } + } +} +~~~~~ +{:.draco-syntax } diff --git a/docs/spec/edgebreaker.traversal.prediction.degree.md b/docs/spec/edgebreaker.traversal.prediction.degree.md new file mode 100644 index 0000000..b4d6f58 --- /dev/null +++ b/docs/spec/edgebreaker.traversal.prediction.degree.md @@ -0,0 +1,113 @@ +## EdgeBreaker Traversal Prediction Degree + +### AddCornerToTraversalStack() + +~~~~~ +void AddCornerToTraversalStack(ci, priority) { + traversal_stacks_[priority].push_back(ci); + if (priority < best_priority_) + best_priority_ = priority; +} +~~~~~ +{:.draco-syntax } + + +### ComputePriority() + +~~~~~ +int ComputePriority(corner_id) { + CornerToVerts(curr_att_dec, corner_id, &v_tip, &next_vert, &prev_vert); + priority = 0; + if (!is_vertex_visited_[v_tip]) { + degree = ++prediction_degree_[v_tip]; + priority = (degree > 1 ? 1 : 2); + } + if (priority >= kMaxPriority) + priority = kMaxPriority - 1; + return priority; +} +~~~~~ +{:.draco-syntax } + + +### PopNextCornerToTraverse() + +~~~~~ +int PopNextCornerToTraverse() { + for (i = best_priority_; i < kMaxPriority; ++i) { + if (!traversal_stacks_[i].empty()) { + ret = traversal_stacks_[i].pop(); + best_priority_ = i; + return ret; + } + } + return kInvalidCornerIndex; +} +~~~~~ +{:.draco-syntax } + + +### PredictionDegree_TraverseFromCorner() + +~~~~~ +void PredictionDegree_TraverseFromCorner(corner_id) { + traversal_stacks_[0].push_back(corner_id); + best_priority_ = 0; + CornerToVerts(curr_att_dec, corner_id, &tip_vertex, &next_vert, &prev_vert); + if (!is_vertex_visited_[next_vert]) { + is_vertex_visited_[next_vert] = true; + next_c = Next(corner_id); + OnNewVertexVisited(next_vert, next_c); + } + if (!is_vertex_visited_[prev_vert]) { + is_vertex_visited_[prev_vert] = true; + prev_c = Previous(corner_id); + OnNewVertexVisited(prev_vert, prev_c); + } + if (!is_vertex_visited_[tip_vertex]) { + is_vertex_visited_[tip_vertex] = true; + OnNewVertexVisited(tip_vertex, corner_id); + } + while ((corner_id = PopNextCornerToTraverse()) >= 0) { + face_id(corner_id / 3); + if (IsFaceVisited(face_id)) { + continue; + } + while (true) { + face_id = corner_id / 3; + is_face_visited_[face_id] = true; + CornerToVerts(curr_att_dec, corner_id, &vert_id, &next_vert, &prev_vert); + if (!is_vertex_visited_[vert_id]) { + is_vertex_visited_[vert_id] = true; + OnNewVertexVisited(vert_id, corner_id); + } + right_corner_id = GetRightCorner(corner_id); + left_corner_id = GetLeftCorner(corner_id); + right_face_id((right_corner_id < 0 ? -1 : right_corner_id / 3)); + left_face_id((left_corner_id < 0 ? -1 : left_corner_id / 3)); + is_right_face_visited = IsFaceVisited(right_face_id); + is_left_face_visited = IsFaceVisited(left_face_id); + if (!is_left_face_visited) { + priority = ComputePriority(left_corner_id); + if (is_right_face_visited && priority <= best_priority_) { + corner_id = left_corner_id; + continue; + } else { + AddCornerToTraversalStack(left_corner_id, priority); + } + } + if (!is_right_face_visited) { + priority = ComputePriority(right_corner_id); + if (priority <= best_priority_) { + corner_id = right_corner_id; + continue; + } else { + AddCornerToTraversalStack(right_corner_id, priority); + } + } + break; + } + } +} +~~~~~ +{:.draco-syntax } diff --git a/docs/spec/edgebreaker.traversal.valence.decoder.md b/docs/spec/edgebreaker.traversal.valence.decoder.md deleted file mode 100644 index 010999c..0000000 --- a/docs/spec/edgebreaker.traversal.valence.decoder.md +++ /dev/null @@ -1,89 +0,0 @@ - -## EdgeBreaker Traversal Valence Decoder - -### EdgeBreakerTraversalValence_Start() - -~~~~~ -EdgeBreakerTraversalValence_Start(traversal_num_vertices) { - EdgebreakerTraversal_Start() - num_split_symbols varUI32 - mode == 0 I8 - traversal_num_vertices += num_split_symbols - vertex_valences_ init to 0 - min_valence_ = 2; - max_valence_ = 7; - num_unique_valences = 6 (max_valence_ - min_valence_ + 1) - for (i = 0; i < num_unique_valences; ++i) { - num_symbols varUI32 - if (num_symbols > 0) { - DecodeSymbols(num_symbols, context_symbols_[i]) - } - context_counters_[i] = num_symbols - } -} -~~~~~ -{:.draco-syntax } - - - -### TraversalValence_DecodeSymbol() - -~~~~~ -TraversalValence_DecodeSymbol() { - if (active_context_ != -1) { - symbol_id = context_symbols_[active_context_] - [--context_counters_[active_context_]] - last_symbol_ = edge_breaker_symbol_to_topology_id[symbol_id] - } else { - last_symbol_ = Traversal_DecodeSymbol() - } - return last_symbol_ -} -~~~~~ -{:.draco-syntax } - - - -### TraversalValence_NewActiveCornerReached() - -~~~~~ -TraversalValence_NewActiveCornerReached(corner) { - switch (last_symbol_) { - case TOPOLOGY_C: - case TOPOLOGY_S: - vertex_valences_[ct(next)] += 1; - vertex_valences_[ct(prev)] += 1; - break; - case TOPOLOGY_R: - vertex_valences_[corner] += 1; - vertex_valences_[ct(next)] += 1; - vertex_valences_[ct(prev)] += 2; - break; - case TOPOLOGY_L: - vertex_valences_[corner] += 1; - vertex_valences_[ct(next)] += 2; - vertex_valences_[ct(prev)] += 1; - break; - case TOPOLOGY_E: - vertex_valences_[corner] += 2; - vertex_valences_[ct(next)] += 2; - vertex_valences_[ct(prev)] += 2; - break; - } - valence = vertex_valences_[ct(next)] - valence = max(valence, min_valence_) - valence = min(valence, max_valence_) - active_context_ = (valence - min_valence_); -} -~~~~~ -{:.draco-syntax } - - -### TraversalValence_MergeVertices() - -~~~~~ -TraversalValence_MergeVertices(dest, source) { - vertex_valences_[dest] += vertex_valences_[source]; -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/edgebreaker.traversal.valence.md b/docs/spec/edgebreaker.traversal.valence.md new file mode 100644 index 0000000..c3339a5 --- /dev/null +++ b/docs/spec/edgebreaker.traversal.valence.md @@ -0,0 +1,58 @@ + +## EdgeBreaker Traversal Valence + +### ParseEdgebreakerTraversalValenceData() + +~~~~~ +void ParseEdgebreakerTraversalValenceData() { + eb_num_split_symbols varUI32 + eb_mode I8 +} +~~~~~ +{:.draco-syntax } + + + +### ParseValenceContextCounters() + +~~~~~ +void ParseValenceContextCounters(index) { + ebv_context_counters[index] varUI32 +} +~~~~~ +{:.draco-syntax } + + + +### EdgeBreakerTraversalValenceStart() + +~~~~~ +void EdgeBreakerTraversalValenceStart() { + vertex_valences_.assign(num_encoded_vertices + eb_num_split_symbols, 0); + for (i = 0; i < NUM_UNIQUE_VALENCES; ++i) { + ParseValenceContextCounters(i); + if (ebv_context_counters[i] > 0) { + DecodeSymbols(ebv_context_counters[i], 0, &ebv_context_symbols[i]); + } + } +} +~~~~~ +{:.draco-syntax } + + + +### EdgebreakerValenceDecodeSymbol() + +~~~~~ +void EdgebreakerValenceDecodeSymbol() { + if (active_context_ != -1) { + symbol_id = ebv_context_symbols[active_context_] + [--ebv_context_counters[active_context_]]; + last_symbol_ = edge_breaker_symbol_to_topology_id[symbol_id]; + } else { + ParseEdgebreakerStandardSymbol(); + } +} +~~~~~ +{:.draco-syntax } + diff --git a/docs/spec/edgebreaker.traverser.md b/docs/spec/edgebreaker.traverser.md deleted file mode 100644 index 7ded44c..0000000 --- a/docs/spec/edgebreaker.traverser.md +++ /dev/null @@ -1,71 +0,0 @@ - -## EdgeBreaker Traverser - -### TraverseFromCorner() - -~~~~~ -TraverseFromCorner(corner_id) { - if (processor_.IsFaceVisited(corner_id)) - return - corner_traversal_stack_.clear(); - corner_traversal_stack_.push_back(corner_id); - next_vert = corner_table_->Vertex(corner_table_->Next(corner_id)); - prev_vert = corner_table_->Vertex(corner_table_->Previous(corner_id)); - if (!processor_.IsVertexVisited(next_vert)) { - processor_.MarkVertexVisited(next_vert); - traversal_observer_.OnNewVertexVisited(next_vert, - corner_table_->Next(corner_id)); - } - if (!processor_.IsVertexVisited(prev_vert)) { - processor_.MarkVertexVisited(prev_vert); - traversal_observer_.OnNewVertexVisited(prev_vert, - corner_table_->Previous(corner_id)); - } - while (!corner_traversal_stack_.empty()) { - corner_id = corner_traversal_stack_.back(); - face_id =corner_id / 3; - if (processor_.IsFaceVisited(face_id)) { - corner_traversal_stack_.pop_back(); - continue - } - while(true) { - face_id = corner_id / 3; - processor_.MarkFaceVisited(face_id); - traversal_observer_.OnNewFaceVisited(face_id); - vert_id = corner_table_->Vertex(corner_id); - on_boundary = corner_table_->IsOnBoundary(vert_id); - if (!processor_.IsVertexVisited(vert_id)) { - processor_.MarkVertexVisited(vert_id); - traversal_observer_.OnNewVertexVisited(vert_id, corner_id); - if (!on_boundary) { - corner_id = corner_table_->GetRightCorner(corner_id); - continue; - } - } - // The current vertex has been already visited or it was on a boundary. - right_corner_id = corner_table_->GetRightCorner(corner_id); - left_corner_id = corner_table_->GetLeftCorner(corner_id); - right_face_id((right_corner_id < 0 ? -1 : right_corner_id / 3)); - left_face_id((left_corner_id < 0 ? -1 : left_corner_id / 3)); - if (processor_.IsFaceVisited(right_face_id)) { - if (processor_.IsFaceVisited(left_face_id)) { - corner_traversal_stack_.pop_back(); - break; // Break from while(true) loop - } else { - corner_id = left_corner_id; - } - } else { - if (processor_.IsFaceVisited(left_face_id)) { - corner_id = right_corner_id; - } else { - // Split the traversal. - corner_traversal_stack_.back() = left_corner_id; - corner_traversal_stack_.push_back(right_corner_id); - break; // Break from while(true) loop - } - } - } - } -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/index.md b/docs/spec/index.md index a42f4f4..a3e730b 100644 --- a/docs/spec/index.md +++ b/docs/spec/index.md @@ -1,7 +1,7 @@ --- layout: spec-page title: Draco Bitstream Specification (Draft) -version: Version 1,2 +version: Version 2,1 version_date: Released 2017-xx-xx --- @@ -15,7 +15,6 @@ version_date: Released 2017-xx-xx {% include_relative 00.00.02.authors.md %} {% include_relative 00.00.03.last.modified.md %} {% include_relative 00.00.04.abstract.md %} - {% include_relative 00.00.05.toc.md %} {% include_relative 01.00.00.scope.md %} @@ -24,28 +23,27 @@ version_date: Released 2017-xx-xx {% include_relative 04.00.00.conventions.md %} {% include_relative draco.decoder.md %} {% include_relative metadata.decoder.md %} -{% include_relative mesh.decoder.md %} +{% include_relative connectivity.decoder.md %} +{% include_relative sequential.decoder.md %} {% include_relative edgebreaker.decoder.md %} -{% include_relative edgebreaker.hole.and.topology.md %} -{% include_relative edgebreaker.traversal.decoder.md %} -{% include_relative edgebreaker.traversal.valence.decoder.md %} +{% include_relative edgebreaker.traversal.md %} +{% include_relative edgebreaker.traversal.valence.md %} +{% include_relative edgebreaker.traversal.prediction.degree.md %} {% include_relative attributes.decoder.md %} -{% include_relative sequential.attributes.decoders.controller.md %} -{% include_relative sequential.attribute.decoder.md %} {% include_relative sequential.integer.attribute.decoder.md %} +{% include_relative boundary.decoder.md %} +{% include_relative prediction.decoder.md %} {% include_relative sequential.quantization.attribute.decoder.md %} -{% include_relative prediction.scheme.transform.md %} -{% include_relative prediction.scheme.wrap.transform.md %} -{% include_relative mesh.prediction.scheme.parallelogram.md %} -{% include_relative cornertable.traversal.processor.md %} -{% include_relative mesh.attribute.indices.encoding.observer.md %} -{% include_relative edgebreaker.traverser.md %} -{% include_relative mesh.traversal.sequencer.md %} -{% include_relative corner.table.md %} -{% include_relative mesh.attribute.corner.table.md %} -{% include_relative symbol.decoding.md %} +{% include_relative sequential.normal.attribute.decoder.md %} +{% include_relative prediction.texcoords.decoder.md %} +{% include_relative prediction.normal.decoder.md %} +{% include_relative prediction.normal.transform.md %} +{% include_relative prediction.wrap.transform.md %} +{% include_relative prediction.parallelogram.decoder.md %} +{% include_relative prediction.multi.parallelogram.decoder.md %} {% include_relative rans.decoding.md %} -{% include_relative rans.bit.decoder.md %} +{% include_relative corner.md %} +{% include_relative vector.md %} {% include_relative core.functions.md %} {% include_relative variable.descriptions.md %} diff --git a/docs/spec/mesh.attribute.corner.table.md b/docs/spec/mesh.attribute.corner.table.md deleted file mode 100644 index bdb87da..0000000 --- a/docs/spec/mesh.attribute.corner.table.md +++ /dev/null @@ -1,78 +0,0 @@ - -## Mesh Attribute Corner Table - -### bool IsCornerOnSeam() - -~~~~~ -bool IsCornerOnSeam(corner) { - return is_vertex_on_seam_[corner_table_->Vertex(corner)]; -} -~~~~~ -{:.draco-syntax } - - -### AddSeamEdge() - -~~~~~ -AddSeamEdge(c) { - MarkSeam(c) - opp_corner = corner_table_->Opposite(c); - if (opp_corner >= 0) { - no_interior_seams_ = false; - MarkSeam(opp_corner) - } -} -~~~~~ -{:.draco-syntax } - - -### MarkSeam() - -~~~~~ -MarkSeam(c) { - is_edge_on_seam_[c] = true; - is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Next(c))] = true; - is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Previous(c)) - ] = true; -} -~~~~~ -{:.draco-syntax } - - -### RecomputeVertices() - -~~~~~ -RecomputeVertices() { - // in code RecomputeVerticesInternal(nullptr, nullptr) - num_new_vertices = 0; - for (v = 0; v < corner_table_->num_vertices(); ++v) { - c = corner_table_->LeftMostCorner(v); - if (c < 0) - continue; - first_vert_id(num_new_vertices++); - vertex_to_attribute_entry_id_map_.push_back(first_vert_id); - first_c = c; - if (is_vertex_on_seam_[v]) { - act_c = SwingLeft(first_c); - while (act_c >= 0) { - first_c = act_c; - act_c = SwingLeft(act_c); - } - } - corner_to_vertex_map_[first_c] =first_vert_id; - vertex_to_left_most_corner_map_.push_back(first_c); - act_c = corner_table_->SwingRight(first_c); - while (act_c >= 0 && act_c != first_c) { - if (is_edge_on_seam_[corner_table_->Next(act_c)]) { - // in code IsCornerOppositeToSeamEdge() - first_vert_id = AttributeValueIndex(num_new_vertices++); - vertex_to_attribute_entry_id_map_.push_back(first_vert_id); - vertex_to_left_most_corner_map_.push_back(act_c); - } - corner_to_vertex_map_[act_c] = first_vert_id; - act_c = corner_table_->SwingRight(act_c); - } - } -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/mesh.attribute.indices.encoding.observer.md b/docs/spec/mesh.attribute.indices.encoding.observer.md deleted file mode 100644 index 538c014..0000000 --- a/docs/spec/mesh.attribute.indices.encoding.observer.md +++ /dev/null @@ -1,18 +0,0 @@ - -## Mesh Attribute Indices Encoding Observer - -### OnNewVertexVisited() - -~~~~~ -OnNewVertexVisited(vertex, corner) { - point_id = mesh_->face(corner / 3)[corner % 3]; - sequencer_->AddPointId(point_id); - // Keep track of visited corners. - encoding_data_->encoded_attribute_value_index_to_corner_map.push_back(corner); - encoding_data_ - ->vertex_to_encoded_attribute_value_index_map[vertex] = - encoding_data_->num_values; - encoding_data_->num_values++; -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/mesh.decoder.md b/docs/spec/mesh.decoder.md deleted file mode 100644 index 0f7ae9f..0000000 --- a/docs/spec/mesh.decoder.md +++ /dev/null @@ -1,2 +0,0 @@ -## Mesh Decoder - diff --git a/docs/spec/mesh.prediction.scheme.parallelogram.md b/docs/spec/mesh.prediction.scheme.parallelogram.md deleted file mode 100644 index a197727..0000000 --- a/docs/spec/mesh.prediction.scheme.parallelogram.md +++ /dev/null @@ -1,59 +0,0 @@ - -## Mesh Prediction Scheme Parallelogram - -### Decode() - -~~~~~ -Decode(...) { - this->transform().InitializeDecoding(num_components); - // restore the first value - this->transform().ComputeOriginalValue(pred_vals, - in_corr, out_data, 0); - // PredictionSchemeWrapTransform_ComputeOriginalValue() - corner_map_size = this->mesh_data().data_to_corner_map()->size(); - for (p = 1; p < corner_map_size; ++p) { - corner_id = this->mesh_data().data_to_corner_map()->at(p); - dst_offset = p * num_components; - b= ComputeParallelogramPrediction(p, corner_id, table, - *vertex_to_data_map, out_data, - num_components, pred_vals) - if (!b) { - src_offset = (p - 1) * num_components; - this->transform().ComputeOriginalValue(out_data + src_offset, in_corr, - out_data + dst_offset, dst_offset); - // PredictionSchemeWrapTransform_ComputeOriginalValue() - } else { - this->transform().ComputeOriginalValue(pred_vals, in_corr, - out_data + dst_offset, dst_offset); - // PredictionSchemeWrapTransform_ComputeOriginalValue() - } - } -} -~~~~~ -{:.draco-syntax } - - - -### ComputeParallelogramPrediction() - -~~~~~ -ComputeParallelogramPrediction(...) { - oci = table->Opposite(ci); - vert_opp = vertex_to_data_map[table->Vertex(ci)]; - vert_next = vertex_to_data_map[table->Vertex(table->Next(ci))]; - vert_prev = vertex_to_data_map[table->Vertex(table->Previous(ci))]; - if (vert_opp < data_entry_id && vert_next < data_entry_id && - vert_prev < data_entry_id) { - v_opp_off = vert_opp * num_components; - v_next_off = vert_next * num_components; - v_prev_off = vert_prev * num_components; - for (c = 0; c < num_components; ++c) { - out_prediction[c] = (in_data[v_next_off + c] + in_data[v_prev_off + c]) - - in_data[v_opp_off + c]; - } - Return true; - } - return false; -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/mesh.traversal.sequencer.md b/docs/spec/mesh.traversal.sequencer.md deleted file mode 100644 index a0c3864..0000000 --- a/docs/spec/mesh.traversal.sequencer.md +++ /dev/null @@ -1,68 +0,0 @@ - -## Mesh Traversal Sequencer - -### GenerateSequenceInternal() - -~~~~~ -GenerateSequenceInternal() { - traverser_.OnTraversalStart(); - If (corner_order_) { - // TODO - } else { - int32_t num_faces = traverser_.corner_table()->num_faces(); - for (i = 0; i < num_faces; ++i) { - ProcessCorner(3 * i) - } - } - traverser_.OnTraversalEnd(); -} -~~~~~ -{:.draco-syntax } - - -### ProcessCorner() - -~~~~~ -ProcessCorner(corner_id) { - traverser_.TraverseFromCorner(corner_id); -} -~~~~~ -{:.draco-syntax } - - -### UpdatePointToAttributeIndexMapping() - -~~~~~ -UpdatePointToAttributeIndexMapping(PointAttribute *attribute) { - corner_table = traverser_.corner_table(); - attribute->SetExplicitMapping(mesh_->num_points()); - num_faces = mesh_->num_faces(); - num_points = mesh_->num_points(); - for (f = 0; f < num_faces; ++f) { - face = mesh_->face(f); - for (p = 0; p < 3; ++p) { - point_id = face[p]; - vert_id = corner_table->Vertex(3 * f + p); - att_entry_id( - encoding_data_ - ->vertex_to_encoded_attribute_value_index_map[vert_id]); - attribute->SetPointMapEntry(point_id, att_entry_id); - } - } -} -~~~~~ -{:.draco-syntax } - - -PointsSequencer - -FIXME: ^^^ Heading level? - -### AddPointId() - -~~~~~ -AddPointId(point_id) { - out_point_ids_->push_back(point_id); -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/metadata.decoder.md b/docs/spec/metadata.decoder.md index ec429ca..86f0d54 100644 --- a/docs/spec/metadata.decoder.md +++ b/docs/spec/metadata.decoder.md @@ -1,52 +1,78 @@ ## Metadata Decoder -### DecodeGeometryMetadata() - -~~~~~ -DecodeGeometryMetadata(metadata) { - num_att_metadata varUI32 - for (i = 0; i < num_att_metadata; ++i) { - att_id varUI32 - att_metadata = new AttributeMetadata(att_id) - DecodeMetadata(att_metadata) - metadata.att_metadata.push_back(att_metadata) - } - DecodeMetadata(metadata) -} -~~~~~ -{:.draco-syntax} - - ### DecodeMetadata() ~~~~~ -DecodeMetadata(metadata) { - num_entries varUI32 - for (i = 0; i < num_entries; ++i) { - DecodeEntry(metadata) - } - num_sub_metadata varUI32 - for (i = 0; i < num_sub_metadata; ++i) { - size UI8 - name size * UI8 - temp_metadata = new Metadata() - DecodeMetadata(temp_metadata) - metadata.sub_metadata[name] = temp_metadata +void DecodeMetadata() { + ParseMetedataCount(); + + for (i = 0; i < num_att_metadata; ++i) { + ParseAttributeMetadataId(i); + DecodeMetadataElement(att_metadata[i]); } + DecodeMetadataElement(file_metadata); } ~~~~~ {:.draco-syntax} -### DecodeEntry() +### ParseMetedataCount() ~~~~~ -DecodeEntry(metadata) { - size UI8 - name size * UI8 - size varUI32 - value size * UI8 - metadata.entries.insert(name, value) +void ParseMetedataCount() { + num_att_metadata varUI32 +} +~~~~~ +{:.draco-syntax} + + +### ParseAttributeMetadataId() + +~~~~~ +void ParseAttributeMetadataId(index) { + att_metadata_id[index] varUI32 +} +~~~~~ +{:.draco-syntax} + + +### ParseMetadataElement() + +~~~~~ +void ParseMetadataElement(metadata) { + metadata.num_entries varUI32 + for (i = 0; i < metadata.num_entries; ++i) { + metadata.name_size[i] UI8 + metadata.name[i] I8[size] + metadata.value_size[i] UI8 + metadata.value[i] I8[size] + } + metadata.num_sub_metadata varUI32 +} +~~~~~ +{:.draco-syntax} + + +### ParseSubMetadataName() + +~~~~~ +void ParseSubMetadataName(metadata, index) { + metadata.sub_metadata_name_size[index] UI8 + metadata.sub_metadata_name[index] I8[size] +} +~~~~~ +{:.draco-syntax} + + +### DecodeMetadataElement() + +~~~~~ +void DecodeMetadataElement(metadata) { + ParseMetadataElement(metadata); + for (i = 0; i < metadata.num_sub_metadata; ++i) { + ParseSubMetadataName(metadata, i); + DecodeMetadataElement(metadata.sub_metadata[i]); + } } ~~~~~ {:.draco-syntax} diff --git a/docs/spec/prediction.decoder.md b/docs/spec/prediction.decoder.md new file mode 100644 index 0000000..5483c6f --- /dev/null +++ b/docs/spec/prediction.decoder.md @@ -0,0 +1,280 @@ +## Prediction Decoder + +### ParsePredictionData() + +~~~~~ +void ParsePredictionData() { + seq_att_dec_prediction_scheme[curr_att_dec][curr_att] I8 + if (seq_att_dec_prediction_scheme[curr_att_dec][curr_att] != PREDICTION_NONE) { + seq_att_dec_prediction_transform_type[curr_att_dec][curr_att] I8 + seq_int_att_dec_compressed[curr_att_dec][curr_att] UI8 + } +} +~~~~~ +{:.draco-syntax} + + +### DecodePortableAttributes() + +~~~~~ +void DecodePortableAttributes() { + for (i = 0; i < att_dec_num_attributes.back(); ++i) { + curr_att = i; + ParsePredictionData(); + if (seq_att_dec_prediction_scheme[curr_att_dec][i] != PREDICTION_NONE) { + SequentialIntegerAttributeDecoder_DecodeIntegerValues(); + } + } +} +~~~~~ +{:.draco-syntax} + + +### DecodeDataNeededByPortableTransforms() + +~~~~~ +void DecodeDataNeededByPortableTransforms() { + for (i = 0; i < att_dec_num_attributes.back(); ++i) { + curr_att = i; + if (seq_att_dec_decoder_type[curr_att_dec][curr_att] == + SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS) { + ParseQuantizationBits(); + } else if (seq_att_dec_decoder_type[curr_att_dec][curr_att] == SEQUENTIAL_ATTRIBUTE_ENCODER_QUANTIZATION) { + ParseQuantizationData(); + } + } +} +~~~~~ +{:.draco-syntax} + + +### ParseWrapTransformData() + +~~~~~ +void ParseWrapTransformData() { + pred_trasnform_wrap_min[curr_att_dec][curr_att] I32 + pred_trasnform_wrap_max[curr_att_dec][curr_att] I32 +} +~~~~~ +{:.draco-syntax} + + +### ParseNormalOctahedronCanonicalizedTransformData() + +~~~~~ +void ParseNormalOctahedronCanonicalizedTransformData() { + pred_trasnform_normal_max_q_val[curr_att_dec][curr_att] I32 + temp I32 +} +~~~~~ +{:.draco-syntax} + + +### DecodeTransformData() + +~~~~~ +void DecodeTransformData() { + transform_type = seq_att_dec_prediction_transform_type[curr_att_dec][curr_att]; + if (transform_type == PREDICTION_TRANSFORM_WRAP) { + ParseWrapTransformData(); + } else if (transform_type == + PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED) { + ParseNormalOctahedronCanonicalizedTransformData(); + } +} +~~~~~ +{:.draco-syntax} + + +### ParsePredictionRansData() + +~~~~~ +void ParsePredictionRansData() { + prediction_rans_prob_zero UI8 + prediction_rans_data_size UI32 +} +~~~~~ +{:.draco-syntax} + + +### ParseConstrainedMultiMode() + +~~~~~ +void ParseConstrainedMultiMode() { + temp UI8 +} +~~~~~ +{:.draco-syntax} + + +### ParseConstrainedMultiNumFlags() + +~~~~~ +void ParseConstrainedMultiNumFlags() { + constrained_multi_num_flags varUI32 +} +~~~~~ +{:.draco-syntax} + + +### DecodePredictionData_ConstrainedMulti() + +~~~~~ +void DecodePredictionData_ConstrainedMulti() { + ParseConstrainedMultiMode(); + for (i = 0; i < kMaxNumParallelograms; ++i) { + ParseConstrainedMultiNumFlags(); + if (constrained_multi_num_flags > 0) { + ParsePredictionRansData(); + RansInitDecoder(ans_decoder_, data.data() + pos, + prediction_rans_data_size, L_RANS_BASE); + for (j = 0; j < constrained_multi_num_flags; ++j) { + RabsDescRead(&ans_decoder_, prediction_rans_prob_zero, &val); + is_crease_edge_[i][j] = val > 0; + } + } + } + pred_cons_multi_is_cease_edge[curr_att_dec][curr_att] = is_crease_edge_; +} +~~~~~ +{:.draco-syntax} + + +### ParseTexCoordsNumOrientations() + +~~~~~ +void ParseTexCoordsNumOrientations() { + tex_coords_num_orientations I32 +} +~~~~~ +{:.draco-syntax} + + +### DecodePredictionData_TexCoords() + +~~~~~ +void DecodePredictionData_TexCoords() { + ParseTexCoordsNumOrientations(); + ParsePredictionRansData(); + RansInitDecoder(ans_decoder_, data.data() + pos, + prediction_rans_data_size, L_RANS_BASE); + last_orientation = true; + for (i = 0; i < tex_coords_num_orientations; ++i) { + RabsDescRead(&ans_decoder_, prediction_rans_prob_zero, &val); + if (val == 0) + last_orientation = !last_orientation; + orientaitons.push_back(last_orientation); + } + pred_tex_coords_orientaitons[curr_att_dec][curr_att] = orientaitons; +} +~~~~~ +{:.draco-syntax} + + +### ParseGeometricNormalPredictionMode() + +~~~~~ +void ParseGeometricNormalPredictionMode() { + temp UI8 +} +~~~~~ +{:.draco-syntax} + + +### DecodePredictionData_GeometricNormal() + +~~~~~ +void DecodePredictionData_GeometricNormal() { + ParseGeometricNormalPredictionMode(); + ParsePredictionRansData(); + RansInitDecoder(ans_decoder_, data.data() + pos, + prediction_rans_data_size, L_RANS_BASE); + num_values = att_dec_num_values_to_decode[curr_att_dec][curr_att]; + for (i = 0; i < num_values; ++i) { + RabsDescRead(&ans_decoder_, prediction_rans_prob_zero, &val); + flip_normal_bits.push_back(val > 0); + } + pred_transform_normal_flip_normal_bits[curr_att_dec][curr_att] = flip_normal_bits; +} +~~~~~ +{:.draco-syntax} + + +### DecodePredictionData() + +~~~~~ +void DecodePredictionData(method) { + if (method == MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM) { + DecodePredictionData_ConstrainedMulti(); + } else if (method == MESH_PREDICTION_TEX_COORDS_PORTABLE) { + DecodePredictionData_TexCoords(); + } else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { + DecodeTransformData(); + DecodePredictionData_GeometricNormal(); + } + if (method != MESH_PREDICTION_GEOMETRIC_NORMAL) { + DecodeTransformData(); + } +} +~~~~~ +{:.draco-syntax} + + +### PredictionSchemeTransform_ComputeOriginalValue() + +~~~~~ +void PredictionSchemeTransform_ComputeOriginalValue(pred_vals, corr_vals, + out_orig_vals) { + transform_type = eq_att_dec_prediction_transform_type[curr_att_dec][curr_att]; + if (transform_type == PREDICTION_TRANSFORM_WRAP) { + PredictionSchemeWrapDecodingTransform_ComputeOriginalValue( + pred_vals, corr_vals, out_orig_vals); + } else if (transform_type == + PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED) { + PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform_ComputeOriginalValue( + pred_vals, corr_vals, out_orig_vals); + } +} +~~~~~ +{:.draco-syntax} + + +### PredictionSchemeDifference_ComputeOriginalValues() + +~~~~~ +void PredictionSchemeDifference_ComputeOriginalValues(num_values) { + num_components = GetNumComponents(); + signed_values = seq_int_att_dec_symbols_to_signed_ints[curr_att_dec][curr_att]; + size = num_components * num_values; + zero_vals.assign(num_components, 0); + out_values.insert(out_values.begin(), signed_values.begin(), signed_values.end()); + PredictionSchemeTransform_ComputeOriginalValue( + &zero_vals[0], &signed_values[0], &out_values[0]); + for (i = num_components; i < size; i += num_components) { + PredictionSchemeTransform_ComputeOriginalValue(&out_values[i - num_components], &signed_values[i], &out_values[i]); + } + seq_int_att_dec_original_values[curr_att_dec][curr_att] = out_values; +} +~~~~~ +{:.draco-syntax} + + +### PredictionScheme_ComputeOriginalValues() + +~~~~~ +void PredictionScheme_ComputeOriginalValues(method, num_values) { + if (method == PREDICTION_DIFFERENCE) { + PredictionSchemeDifference_ComputeOriginalValues(num_values); + } else if (method == MESH_PREDICTION_PARALLELOGRAM) { + MeshPredictionSchemeParallelogramDecoder_ComputeOriginalValues(num_values); + } else if (method == MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM) { + MeshPredictionSchemeConstrainedMultiParallelogramDecoder_ComputeOriginalValues( + num_values); + } else if (method == MESH_PREDICTION_TEX_COORDS_PORTABLE) { + MeshPredictionSchemeTexCoordsPortableDecoder_ComputeOriginalValues(num_values); + } else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { + MeshPredictionSchemeGeometricNormalDecoder_ComputeOriginalValues(num_values); + } +} +~~~~~ +{:.draco-syntax} diff --git a/docs/spec/prediction.multi.parallelogram.decoder.md b/docs/spec/prediction.multi.parallelogram.decoder.md new file mode 100644 index 0000000..4ed4361 --- /dev/null +++ b/docs/spec/prediction.multi.parallelogram.decoder.md @@ -0,0 +1,75 @@ +## Multi Parallelogram Prediction Decoder + +### MeshPredictionSchemeConstrainedMultiParallelogramDecoder_ComputeOriginalValues() + +~~~~~ +void MeshPredictionSchemeConstrainedMultiParallelogramDecoder_ComputeOriginalValues( + num_values) { + signed_values = seq_int_att_dec_symbols_to_signed_ints[curr_att_dec][curr_att]; + num_components = GetNumComponents(); + for (i = 0; i < kMaxNumParallelograms; ++i) { + pred_vals[i].resize(num_components, 0); + } + out_values.insert(out_values.begin(), signed_values.begin(), signed_values.end()); + PredictionSchemeTransform_ComputeOriginalValue( + pred_vals[0].data(), &signed_values[0], &out_values[0]); + is_crease_edge_pos(kMaxNumParallelograms, 0); + corner_map_size = num_values; + for (p = 1; p < corner_map_size; ++p) { + start_corner_id = encoded_attribute_value_index_to_corner_map[curr_att_dec][p]; + corner_id(start_corner_id); + num_parallelograms = 0; + first_pass = true; + while (corner_id >= 0) { + if (ComputeParallelogramPrediction(p, corner_id, &out_values[0], + num_components, &(pred_vals[num_parallelograms][0]))) { + ++num_parallelograms; + if (num_parallelograms == kMaxNumParallelograms) + break; + } + if (first_pass) { + corner_id = SwingLeft(curr_att_dec, corner_id); + } else { + corner_id = SwingRight(curr_att_dec, corner_id); + } + if (corner_id == start_corner_id) { + break; + } + if (corner_id < 0 && first_pass) { + first_pass = false; + corner_id = SwingRight(curr_att_dec, start_corner_id); + } + } + is_crease_edge_ = pred_cons_multi_is_cease_edge[curr_att_dec][curr_att]; + num_used_parallelograms = 0; + if (num_parallelograms > 0) { + for (i = 0; i < num_components; ++i) { + multi_pred_vals[i] = 0; + } + for (i = 0; i < num_parallelograms; ++i) { + context = num_parallelograms - 1; + is_crease = is_crease_edge_[context][is_crease_edge_pos[context]++]; + if (!is_crease) { + ++num_used_parallelograms; + for (j = 0; j < num_components; ++j) { + multi_pred_vals[j] += pred_vals[i][j]; + } + } + } + } + dst_offset = p * num_components; + if (num_used_parallelograms == 0) { + src_offset = (p - 1) * num_components; + PredictionSchemeTransform_ComputeOriginalValue(&out_values[src_offset], &signed_values[dst_offset], &out_values[dst_offset]); + } else { + for (c = 0; c < num_components; ++c) { + multi_pred_vals[c] /= num_used_parallelograms; + } + PredictionSchemeTransform_ComputeOriginalValue(multi_pred_vals.data(), &signed_values[dst_offset], &out_values[dst_offset]); + } + } + seq_int_att_dec_original_values[curr_att_dec][curr_att] = out_values; +} + +~~~~~ +{:.draco-syntax} diff --git a/docs/spec/prediction.normal.decoder.md b/docs/spec/prediction.normal.decoder.md new file mode 100644 index 0000000..b7da27e --- /dev/null +++ b/docs/spec/prediction.normal.decoder.md @@ -0,0 +1,189 @@ +## Normal Prediction Decoder + +### GetPositionForDataId() + +~~~~~ +void GetPositionForDataId(data_id, pos) { + corner = encoded_attribute_value_index_to_corner_map[curr_att_dec][data_id]; + point_id = corner_to_point_map[corner]; + mapped_index = indices_map_[0][point_id]; + pos_orig = seq_int_att_dec_original_values[0][0]; + for (i = 0; i < 3; ++i) { + pos.push_back(pos_orig[(mapped_index * 3) + i]); + } +} +~~~~~ +{:.draco-syntax} + + +### GetPositionForCorner() + +~~~~~ +void GetPositionForCorner(ci, pos) { + CornerToVerts(curr_att_dec, ci, &vert_id, &n, &p); + data_id = vertex_to_encoded_attribute_value_index_map[curr_att_dec][vert_id]; + GetPositionForDataId(data_id, pos); +} +~~~~~ +{:.draco-syntax} + + +### MeshPredictionSchemeGeometricNormalPredictorArea_ComputePredictedValue() + +~~~~~ +void MeshPredictionSchemeGeometricNormalPredictorArea_ComputePredictedValue( + corner_id, predicted_value_) { + GetPositionForCorner(corner_id, &pos_cent); + normal.assign(3, 0); + corner = corner_id; + start_corner_ = corner; + left_traversal_ = true; + while (corner >= 0) { + c_next = Next(corner); + c_prev = Previous(corner); + GetPositionForCorner(c_next, &pos_next); + GetPositionForCorner(c_prev, &pos_prev); + SubtractInt64Vectors(pos_next, pos_cent, &delta_next); + SubtractInt64Vectors(pos_prev, pos_cent, &delta_prev); + CrossProduct(delta_next, delta_prev, &cross); + AddVectors(normal, cross, &temp_norm); + for (i = 0; i < temp_norm.size(); ++i) { + normal[i] = temp_norm[i]; + } + if (left_traversal_) { + left_c = SwingLeft(curr_att_dec, corner); + corner = left_c; + if (corner < 0) { + right_c = SwingRight(curr_att_dec, start_corner_); + corner = right_c; + left_traversal_ = false; + } else if (corner == start_corner_) { + corner = kInvalidCornerIndex; + } + } else { + right_c = SwingRight(curr_att_dec, corner); + corner = right_c; + } + } + AbsSum(normal, &abs_sum); + upper_bound = 1 << 29; + if (abs_sum > upper_bound) { + quotient = abs_sum / upper_bound; + DivideScalar(normal, quotient, &vec_div); + for (i = 0; i < vec_div.size(); ++i) { + normal[i] = vec_div[i]; + } + } + predicted_value_[0] = normal[0]; + predicted_value_[1] = normal[1]; + predicted_value_[2] = normal[2]; +} +~~~~~ +{:.draco-syntax} + + +### CanonicalizeIntegerVector() + +~~~~~ +void CanonicalizeIntegerVector(vec, center_value_) { + abs_sum = std::abs(vec[0]) + std::abs(vec[1]) + std::abs(vec[2]); + if (abs_sum == 0) { + vec[0] = center_value_; + } else { + vec[0] = (vec[0] * center_value_) / abs_sum; + vec[1] = (vec[1] * center_value_) / abs_sum; + if (vec[2] >= 0) { + vec[2] = center_value_ - std::abs(vec[0]) - std::abs(vec[1]); + } else { + vec[2] = -(center_value_ - std::abs(vec[0]) - std::abs(vec[1])); + } + } +} +~~~~~ +{:.draco-syntax} + + +### CanonicalizeOctahedralCoords() + +~~~~~ +void CanonicalizeOctahedralCoords(s, t, out_s, + out_t, center_value_, max_value_) { + if ((s == 0 && t == 0) || (s == 0 && t == max_value_) || + (s == max_value_ && t == 0)) { + s = max_value_; + t = max_value_; + } else if (s == 0 && t > center_value_) { + t = center_value_ - (t - center_value_); + } else if (s == max_value_ && t < center_value_) { + t = center_value_ + (center_value_ - t); + } else if (t == max_value_ && s < center_value_) { + s = center_value_ + (center_value_ - s); + } else if (t == 0 && s > center_value_) { + s = center_value_ - (s - center_value_); + } + out_s = s; + out_t = t; +} +~~~~~ +{:.draco-syntax} + + +### IntegerVectorToQuantizedOctahedralCoords() + +~~~~~ +void IntegerVectorToQuantizedOctahedralCoords( + int_vec, out_s, out_t, center_value_, max_value_) { + if (int_vec[0] >= 0) { + s = (int_vec[1] + center_value_); + t = (int_vec[2] + center_value_); + } else { + if (int_vec[1] < 0) { + s = std::abs(int_vec[2]); + } else { + s = (max_value_ - std::abs(int_vec[2])); + } + if (int_vec[2] < 0) { + t = std::abs(int_vec[1]); + } else { + t = (max_value_ - std::abs(int_vec[1])); + } + } + CanonicalizeOctahedralCoords(s, t, out_s, out_t, center_value_, max_value_); +} +~~~~~ +{:.draco-syntax} + + +### MeshPredictionSchemeGeometricNormalDecoder_ComputeOriginalValues() + +~~~~~ +void MeshPredictionSchemeGeometricNormalDecoder_ComputeOriginalValues(num_values) { + signed_values = seq_int_att_dec_symbols_to_signed_ints[curr_att_dec][curr_att]; + encoded_max_quantized_value = + pred_trasnform_normal_max_q_val[curr_att_dec][curr_att]; + quantization_bits_ = MostSignificantBit(encoded_max_quantized_value) + 1; + max_quantized_value_ = (1 << quantization_bits_) - 1; + max_value_ = max_quantized_value_ - 1; + center_value_ = max_value_ / 2; + corner_map_size = num_values; + flip_normal_bits = pred_transform_normal_flip_normal_bits[curr_att_dec][curr_att]; + out_values.insert(out_values.begin(), signed_values.begin(), signed_values.end()); + for (data_id = 0; data_id < corner_map_size; ++data_id) { + corner_id = encoded_attribute_value_index_to_corner_map[curr_att_dec][data_id]; + MeshPredictionSchemeGeometricNormalPredictorArea_ComputePredictedValue(corner_id, &pred_normal_3d); + CanonicalizeIntegerVector(pred_normal_3d, center_value_); + if (flip_normal_bits[data_id]) { + for (i = 0; i < pred_normal_3d.size(); ++i) { + pred_normal_3d[i] = -pred_normal_3d[i]; + } + } + IntegerVectorToQuantizedOctahedralCoords(&pred_normal_3d[0], &pred_normal_oct[0], + &pred_normal_oct[1], center_value_, max_value_); + data_offset = data_id * 2; + PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform_ComputeOriginalValue( + &pred_normal_oct[0], &out_values[data_offset], &out_values[data_offset]); + } + seq_int_att_dec_original_values[curr_att_dec][curr_att] = out_values; +} +~~~~~ +{:.draco-syntax} diff --git a/docs/spec/prediction.normal.transform.md b/docs/spec/prediction.normal.transform.md new file mode 100644 index 0000000..538f5a1 --- /dev/null +++ b/docs/spec/prediction.normal.transform.md @@ -0,0 +1,185 @@ +## Prediction Normal Transform + +### ModMax() + +~~~~~ +int32_t ModMax(x, center_value_, max_quantized_value_) { + if (x > center_value_) + return x - max_quantized_value_; + if (x < -center_value_) + return x + max_quantized_value_; + return x; +} +~~~~~ +{:.draco-syntax} + + +### InvertDiamond() + +~~~~~ +void InvertDiamond(s, t, center_value_) { + sign_s = 0; + sign_t = 0; + if (s >= 0 && t >= 0) { + sign_s = 1; + sign_t = 1; + } else if (s <= 0 && t <= 0) { + sign_s = -1; + sign_t = -1; + } else { + sign_s = (s > 0) ? 1 : -1; + sign_t = (t > 0) ? 1 : -1; + } + corner_point_s = sign_s * center_value_; + corner_point_t = sign_t * center_value_; + s = 2 * s - corner_point_s; + t = 2 * t - corner_point_t; + if (sign_s * sign_t >= 0) { + temp = s; + s = -t; + t = -temp; + } else { + std::swap(s, t); + } + s = (s + corner_point_s) / 2; + t = (t + corner_point_t) / 2; +} +~~~~~ +{:.draco-syntax} + + +### GetRotationCount() + +~~~~~ +void GetRotationCount(pred, count) { + sign_x = pred[0]; + sign_y = pred[1]; + rotation_count = 0; + if (sign_x == 0) { + if (sign_y == 0) { + rotation_count = 0; + } else if (sign_y > 0) { + rotation_count = 3; + } else { + rotation_count = 1; + } + } else if (sign_x > 0) { + if (sign_y >= 0) { + rotation_count = 2; + } else { + rotation_count = 1; + } + } else { + if (sign_y <= 0) { + rotation_count = 0; + } else { + rotation_count = 3; + } + } + count = rotation_count; +} +~~~~~ +{:.draco-syntax} + + +### RotatePoint() + +~~~~~ +void RotatePoint(p, rotation_count, out_p) { + switch (rotation_count) { + case 1: + out_p.push_back(p[1]); + out_p.push_back(-p[0]); + return; + case 2: + out_p.push_back(-p[0]); + out_p.push_back(-p[1]); + return; + case 3: + out_p.push_back(-p[1]); + out_p.push_back(p[0]); + return; + default: + out_p.push_back(p[0]); + out_p.push_back(p[1]); + return; + } +} +~~~~~ +{:.draco-syntax} + + +### IsInBottomLeft() + +~~~~~ +bool IsInBottomLeft(p) { + if (p[0] == 0 && p[1] == 0) + return true; + return (p[0] < 0 && p[1] <= 0); +} +~~~~~ +{:.draco-syntax} + + +### PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform_ComputeOriginalValue2() + +~~~~~ +void PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform_ComputeOriginalValue2( + pred_in, corr, out, center_value_, max_quantized_value_) { + t.assign(2, center_value_); + SubtractVectors(pred_in, t, &pred); + pred_is_in_diamond = std::abs(pred[0]) + std::abs(pred[1]) <= center_value_; + if (!pred_is_in_diamond) { + InvertDiamond(&pred[0], &pred[1], center_value_); + } + pred_is_in_bottom_left = IsInBottomLeft(pred); + GetRotationCount(pred, &rotation_count); + if (!pred_is_in_bottom_left) { + RotatePoint(pred, rotation_count, &temp_rot); + for (i = 0; i < temp_rot.size(); ++i) { + pred[i] = temp_rot[i]; + } + } + + AddVectors(pred, corr, &orig); + orig[0] = ModMax(orig[0], center_value_, max_quantized_value_); + orig[1] = ModMax(orig[1], center_value_, max_quantized_value_); + if (!pred_is_in_bottom_left) { + reverse_rotation_count = (4 - rotation_count) % 4; + RotatePoint(orig, reverse_rotation_count, &temp_rot); + for (i = 0; i < temp_rot.size(); ++i) { + orig[i] = temp_rot[i]; + } + } + if (!pred_is_in_diamond) { + InvertDiamond(&orig[0], &orig[1], center_value_); + } + AddVectors(orig, t, out); +} +~~~~~ +{:.draco-syntax} + + +### PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform_ComputeOriginalValue() + +~~~~~ +void PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform_ComputeOriginalValue( + pred_vals, corr_vals, out_orig_vals) { + encoded_max_quantized_value = + pred_trasnform_normal_max_q_val[curr_att_dec][curr_att]; + quantization_bits_ = MostSignificantBit(encoded_max_quantized_value) + 1; + max_quantized_value_ = (1 << quantization_bits_) - 1; + max_value_ = max_quantized_value_ - 1; + center_value_ = max_value_ / 2; + + pred.push_back(pred_vals[0]); + pred.push_back(pred_vals[1]); + corr.push_back(corr_vals[0]); + corr.push_back(corr_vals[1]); + PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform_ComputeOriginalValue2( + pred, corr, &orig, center_value_, max_quantized_value_); + out_orig_vals[0] = orig[0]; + out_orig_vals[1] = orig[1]; +} +~~~~~ +{:.draco-syntax} diff --git a/docs/spec/prediction.parallelogram.decoder.md b/docs/spec/prediction.parallelogram.decoder.md new file mode 100644 index 0000000..bdd66a1 --- /dev/null +++ b/docs/spec/prediction.parallelogram.decoder.md @@ -0,0 +1,70 @@ +## Parallelogram Prediction Decoder + +### GetParallelogramEntries() + +~~~~~ +void GetParallelogramEntries(ci, opp_entry, + next_entry, prev_entry) { + CornerToVerts(curr_att_dec, ci, &v, &n, &p); + opp_entry = vertex_to_encoded_attribute_value_index_map[curr_att_dec][v]; + next_entry = vertex_to_encoded_attribute_value_index_map[curr_att_dec][n]; + prev_entry = vertex_to_encoded_attribute_value_index_map[curr_att_dec][p]; +} +~~~~~ +{:.draco-syntax} + + +### ComputeParallelogramPrediction() + +~~~~~ +bool ComputeParallelogramPrediction(data_entry_id, ci, in_data, + num_components, out_prediction) { + oci = Opposite(curr_att_dec, ci); + if (oci < 0) + return false; + GetParallelogramEntries(oci, &vert_opp, &vert_next, &vert_prev); + if (vert_opp < data_entry_id && vert_next < data_entry_id && + vert_prev < data_entry_id) { + v_opp_off = vert_opp * num_components; + v_next_off = vert_next * num_components; + v_prev_off = vert_prev * num_components; + for (c = 0; c < num_components; ++c) { + out_prediction[c] = (in_data[v_next_off + c] + in_data[v_prev_off + c]) - + in_data[v_opp_off + c]; + } + return true; + } + return false; +} +~~~~~ +{:.draco-syntax} + + +### MeshPredictionSchemeParallelogramDecoder_ComputeOriginalValues() + +~~~~~ +void MeshPredictionSchemeParallelogramDecoder_ComputeOriginalValues(num_values) { + signed_values = seq_int_att_dec_symbols_to_signed_ints[curr_att_dec][curr_att]; + num_components = GetNumComponents(); + out_values.insert(out_values.begin(), signed_values.begin(), signed_values.end()); + PredictionSchemeWrapDecodingTransform_ComputeOriginalValue(pred_vals.get(), + &signed_values[0], &out_values[0]); + corner_map_size = num_values; + for (p = 1; p < corner_map_size; ++p) { + corner_id = encoded_attribute_value_index_to_corner_map[curr_att_dec][p]; + dst_offset = p * num_components; + if (!ComputeParallelogramPrediction(p, corner_id, &out_values[0], + num_components, pred_vals.get())) { + src_offset = (p - 1) * num_components; + PredictionSchemeWrapDecodingTransform_ComputeOriginalValue( + &out_values[src_offset], &signed_values[dst_offset], + &out_values[dst_offset]); + } else { + PredictionSchemeWrapDecodingTransform_ComputeOriginalValue( + pred_vals.get(), &signed_values[dst_offset], &out_values[dst_offset]); + } + } + seq_int_att_dec_original_values[curr_att_dec][curr_att] = out_values; +} +~~~~~ +{:.draco-syntax} diff --git a/docs/spec/prediction.scheme.transform.md b/docs/spec/prediction.scheme.transform.md deleted file mode 100644 index 6057f14..0000000 --- a/docs/spec/prediction.scheme.transform.md +++ /dev/null @@ -1,15 +0,0 @@ - -## Prediction Scheme Transform - -### ComputeOriginalValue() - -~~~~~ -ComputeOriginalValue(const DataTypeT *predicted_vals, - const CorrTypeT *corr_vals, - DataTypeT *out_original_vals, int val_id) { - for (i = 0; i < num_components_; ++i) { - out_original_vals[i] = predicted_vals[i] + corr_vals[val_id + i]; - } -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/prediction.scheme.wrap.transform.md b/docs/spec/prediction.scheme.wrap.transform.md deleted file mode 100644 index 11121dc..0000000 --- a/docs/spec/prediction.scheme.wrap.transform.md +++ /dev/null @@ -1,46 +0,0 @@ - -## Prediction Scheme Wrap Transform - -### DecodeTransformData() - -~~~~~ -DecodeTransformData(buffer) { - min_value_ DT - max_value_ DT -} -~~~~~ -{:.draco-syntax } - - -### ComputeOriginalValue() - -~~~~~ -ComputeOriginalValue(const DataTypeT *predicted_vals, - const CorrTypeT *corr_vals, - DataTypeT *out_original_vals, int val_id) { - clamped_vals = ClampPredictedValue(predicted_vals); - ComputeOriginalValue(clamped_vals, corr_vals, out_original_vals, val_id) - // PredictionSchemeTransform_ComputeOriginalValue() - for (i = 0; i < this->num_components(); ++i) { - if (out_original_vals[i] > max_value_) { - out_original_vals[i] -= max_dif_; - } else if (out_original_vals[i] < min_value_) { - out_original_vals[i] += max_dif_; - } -} -~~~~~ -{:.draco-syntax } - - -### ClampPredictedValue() - -~~~~~ -ClampPredictedValue(const DataTypeT *predicted_val) { - for (i = 0; i < this->num_components(); ++i) { - clamped_value_[i] = min(predicted_val[i], max_value_) - clamped_value_[i] = max(predicted_val[i], min_value_) - } - return &clamped_value_[0]; -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/prediction.texcoords.decoder.md b/docs/spec/prediction.texcoords.decoder.md new file mode 100644 index 0000000..7de48b0 --- /dev/null +++ b/docs/spec/prediction.texcoords.decoder.md @@ -0,0 +1,146 @@ +## TexCoords Prediction Decoder + +### IntSqrt() + +~~~~~ +uint64_t IntSqrt(number) { + if (number == 0) + return 0; + act_number = number; + square_root = 1; + while (act_number >= 2) { + square_root *= 2; + act_number /= 4; + } + do { + square_root = (square_root + number / square_root) / 2; + } while (square_root * square_root > number); + return square_root; +} +~~~~~ +{:.draco-syntax} + + +### GetPositionForEntryId() + +~~~~~ +void GetPositionForEntryId(entry_id, pos) { + corner = encoded_attribute_value_index_to_corner_map[curr_att_dec][entry_id]; + point_id = corner_to_point_map[corner]; + mapped_index = indices_map_[0][point_id]; + pos_orig = seq_int_att_dec_original_values[std::make_pair(0, 0)]; + for (i = 0; i < 3; ++i) { + pos.push_back(pos_orig[(mapped_index * 3) + i]); + } +} +~~~~~ +{:.draco-syntax} + + +### GetTexCoordForEntryId() + +~~~~~ +void GetTexCoordForEntryId(entry_id, data, tex_coords) { + data_offset = entry_id * kTexCoordsNumComponents; + tex_coords->push_back(data[data_offset]); + tex_coords->push_back(data[data_offset + 1]); +} +~~~~~ +{:.draco-syntax} + + +### MeshPredictionSchemeTexCoordsPortablePredictor_ComputePredictedValue() + +~~~~~ +void MeshPredictionSchemeTexCoordsPortablePredictor_ComputePredictedValue( + corner_id, data, data_id, predicted_value_) { + CornerToVerts(curr_att_dec, corner_id, &vert_id, &next_vert_id, &prev_vert_id); + next_data_id = vertex_to_encoded_attribute_value_index_map[curr_att_dec][next_vert_id]; + prev_data_id = vertex_to_encoded_attribute_value_index_map[curr_att_dec][prev_vert_id]; + + if (prev_data_id < data_id && next_data_id < data_id) { + GetTexCoordForEntryId(next_data_id, data, &n_uv); + GetTexCoordForEntryId(prev_data_id, data, &p_uv); + + if (p_uv == n_uv) { + (*predicted_value_)[0] = p_uv[0]; + (*predicted_value_)[1] = p_uv[1]; + return; + } + GetPositionForEntryId(data_id, &tip_pos); + GetPositionForEntryId(next_data_id, &next_pos); + GetPositionForEntryId(prev_data_id, &prev_pos); + SubtractInt64Vectors(prev_pos, next_pos, &pn); + Dot(pn, pn, &pn_norm2_squared); + + if (pn_norm2_squared != 0) { + SubtractInt64Vectors(tip_pos, next_pos, &cn); + Dot(cn, pn, &cn_dot_pn); + SubtractInt64Vectors(p_uv, n_uv, &pn_uv); + MultiplyScalar(pn_uv, cn_dot_pn, &vec_mult_1); + MultiplyScalar(n_uv, pn_norm2_squared, &vec_mult_2); + AddVectors(vec_mult_1, vec_mult_2, &x_uv); + MultiplyScalar(pn, cn_dot_pn, &vec_mult); + DivideScalar(vec_mult, pn_norm2_squared, &vec_div); + AddVectors(next_pos, vec_div, &x_pos); + SubtractInt64Vectors(tip_pos, x_pos, &vec_sub); + Dot(vec_sub, vec_sub, &cx_norm2_squared); + + temp_vec.push_back(pn_uv[1]); + temp_vec.push_back(-pn_uv[0]); + norm_squared = IntSqrt(cx_norm2_squared * pn_norm2_squared); + MultiplyScalar(temp_vec, norm_squared, &cx_uv); + orientation = pred_tex_coords_orientaitons[curr_att_dec][curr_att].pop(); + if (orientation) + AddVectors(x_uv, cx_uv, &temp_vec); + else + SubtractInt64Vectors(x_uv, cx_uv, &temp_vec); + DivideScalar(temp_vec, pn_norm2_squared, &predicted_uv); + predicted_value_[0] = predicted_uv[0]; + predicted_value_[1] = predicted_uv[1]; + return; + } + } + data_offset = 0; + if (prev_data_id < data_id) { + data_offset = prev_data_id * kTexCoordsNumComponents; + } + if (next_data_id < data_id) { + data_offset = next_data_id * kTexCoordsNumComponents; + } else { + if (data_id > 0) { + data_offset = (data_id - 1) * kTexCoordsNumComponents; + } else { + for (i = 0; i < kTexCoordsNumComponents; ++i) { + predicted_value_[i] = 0; + } + return; + } + } + for (i = 0; i < kTexCoordsNumComponents; ++i) { + predicted_value_[i] = data[data_offset + i]; + } +} +~~~~~ +{:.draco-syntax} + + +### MeshPredictionSchemeTexCoordsPortableDecoder_ComputeOriginalValues() + +~~~~~ +void MeshPredictionSchemeTexCoordsPortableDecoder_ComputeOriginalValues(num_values) { + signed_values = seq_int_att_dec_symbols_to_signed_ints[curr_att_dec][curr_att]; + num_components = GetNumComponents(); + corner_map_size = num_values; + out_values.insert(out_values.begin(), signed_values.begin(), signed_values.end()); + for (p = 0; p < corner_map_size; ++p) { + corner_id = encoded_attribute_value_index_to_corner_map[curr_att_dec][p]; + MeshPredictionSchemeTexCoordsPortablePredictor_ComputePredictedValue(corner_id, &out_values[0], p, &predicted_value_); + dst_offset = p * num_components; + PredictionSchemeWrapDecodingTransform_ComputeOriginalValue( + &predicted_value_[0], &out_values[dst_offset], &out_values[dst_offset]); + } + seq_int_att_dec_original_values[curr_att_dec][curr_att] = out_values; +} +~~~~~ +{:.draco-syntax} diff --git a/docs/spec/prediction.wrap.transform.md b/docs/spec/prediction.wrap.transform.md new file mode 100644 index 0000000..63cd408 --- /dev/null +++ b/docs/spec/prediction.wrap.transform.md @@ -0,0 +1,44 @@ +## Prediction Wrap Transform + +### PredictionSchemeWrapTransformBase_ClampPredictedValue() + +~~~~~ +void PredictionSchemeWrapTransformBase_ClampPredictedValue(predicted_val, + clamped_value_) { + num_components = GetNumComponents(); + min_value_ = pred_trasnform_wrap_min[curr_att_dec][curr_att]; + max_value_ = pred_trasnform_wrap_max[curr_att_dec][curr_att]; + for (int i = 0; i < num_components; ++i) { + if (predicted_val[i] > max_value_) + clamped_value_[i] = max_value_; + else if (predicted_val[i] < min_value_) + clamped_value_[i] = min_value_; + else + clamped_value_[i] = predicted_val[i]; + } +} +~~~~~ +{:.draco-syntax} + + +### PredictionSchemeWrapDecodingTransform_ComputeOriginalValue() + +~~~~~ +void PredictionSchemeWrapDecodingTransform_ComputeOriginalValue( + predicted_vals, corr_vals, out_original_vals) { + num_components = GetNumComponents(); + min = pred_trasnform_wrap_min[curr_att_dec][curr_att]; + max = pred_trasnform_wrap_max[curr_att_dec][curr_att]; + max_dif_ = 1 + max - min; + PredictionSchemeWrapTransformBase_ClampPredictedValue(predicted_vals, + clamped_vals.get()); + for (i = 0; i < num_components; ++i) { + out_original_vals[i] = clamped_vals[i] + corr_vals[i]; + if (out_original_vals[i] > max) + out_original_vals[i] -= max_dif_; + else if (out_original_vals[i] < min) + out_original_vals[i] += max_dif_; + } +} +~~~~~ +{:.draco-syntax} diff --git a/docs/spec/rans.bit.decoder.md b/docs/spec/rans.bit.decoder.md deleted file mode 100644 index 65824d2..0000000 --- a/docs/spec/rans.bit.decoder.md +++ /dev/null @@ -1,25 +0,0 @@ - -## Rans Bit Decoder - -### RansBitDecoder_StartDecoding() - -~~~~~ -RansBitDecoder_StartDecoding() { - prob_zero_ UI8 - size UI32 - buffer_ size * UI8 - ans_read_init(ans_decoder_, buffer_, size) -} -~~~~~ -{:.draco-syntax } - - -### DecodeNextBit() - -~~~~~ -DecodeNextBit() { - uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_); - return bit > 0; -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/rans.decoding.md b/docs/spec/rans.decoding.md index 11b62a8..6a85c43 100644 --- a/docs/spec/rans.decoding.md +++ b/docs/spec/rans.decoding.md @@ -1,40 +1,231 @@ ## Rans Decoding -### ans_read_init() +### DecodeSymbols() ~~~~~ -ans_read_init(AnsDecoder ans, buf, int offset) { - x = buf[offset - 1] >> 6 - If (x == 0) { - ans->buf_offset = offset - 1; - ans->state = buf[offset - 1] & 0x3F; - } else if (x == 1) { - ans->buf_offset = offset - 2; - ans->state = mem_get_le16(buf + offset - 2) & 0x3FFF; - } else if (x == 2) { - ans->buf_offset = offset - 3; - ans->state = mem_get_le24(buf + offset - 3) & 0x3FFFFF; - } else if (x == 3) { - // ERROR +void DecodeSymbols(num_symbols, num_components, out_values) { + scheme UI8 + if (scheme == 0) { + DecodeTaggedSymbols(num_symbols, num_components, out_values); + } else if (scheme == 1) { + DecodeRawSymbols(num_symbols, out_values); } - ans->state += l_base; } ~~~~~ {:.draco-syntax } -### int rabs_desc_read() +### DecodeSymbols ~~~~~ -int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) { - AnsP8 p = ans_p8_precision - p0; - if (ans->state < l_base) { - ans->state = ans->state * io_base + ans->buf[--ans->buf_offset]; +void ReadEncodedData(bytes_encoded, buffer) { + bytes_encoded varUI64 + buffer UI8[size] +} +~~~~~ +{:.draco-syntax } + + +### ComputeRAnsUnclampedPrecision + +~~~~~ +int ComputeRAnsUnclampedPrecision(max_bit_length) { + return (3 * max_bit_length) / 2; +} +~~~~~ +{:.draco-syntax } + + +### ComputeRAnsPrecisionFromMaxSymbolBitLength + +~~~~~ +int ComputeRAnsPrecisionFromMaxSymbolBitLength(max_bit_length) { + return ComputeRAnsUnclampedPrecision(max_bit_length) < 12 + ? 12 + : ComputeRAnsUnclampedPrecision(max_bit_length) > 20 + ? 20 + : ComputeRAnsUnclampedPrecision(max_bit_length); +} +~~~~~ +{:.draco-syntax } + + +### DecodeTaggedSymbols + +~~~~~ +void DecodeTaggedSymbols(num_values, num_components, out_values) { + max_symbol_bit_length_t = 5; + rans_precision_bits_t = + ComputeRAnsPrecisionFromMaxSymbolBitLength(max_symbol_bit_length_t); + rans_precision = 1 << rans_precision_bits_t; + l_rans_base = rans_precision * 4; + num_symbols_ varUI32 + ReadVarUI32(&num_symbols_); + BuildSymbolTables(num_symbols_, lut_table_, probability_table_); + bytes_encoded varUI64 + encoded_data UI8[size] + + RansInitDecoder(ans_, &encoded_data[0], bytes_encoded, l_rans_base); + for (i = 0; i < num_values; i += num_components) { + RansRead(ans_, l_rans_base, rans_precision, + lut_table_, probability_table_, &bit_length); + for (j = 0; j < num_components; ++j) { + val f[bit_length] + out_values.push_back(val); + } + } +} +~~~~~ +{:.draco-syntax } + + +### DecodeRawSymbols + +~~~~~ +void DecodeRawSymbols(num_values, out_values) { + max_bit_length UI8 + num_symbols_ varUI32 + rans_precision_bits = (3 * max_bit_length) / 2; + if (rans_precision_bits > 20) + rans_precision_bits = 20; + if (rans_precision_bits < 12) + rans_precision_bits = 12; + rans_precision = 1 << rans_precision_bits; + l_rans_base = rans_precision * 4; + BuildSymbolTables(num_symbols_, lut_table_, probability_table_); + bytes_encoded UI64 + buffer UI8[size] + RansInitDecoder(ans_, &buffer[0], bytes_encoded, l_rans_base); + for (i = 0; i < num_values; ++i) { + RansRead(ans_, l_rans_base, rans_precision, + lut_table_, probability_table_, &val); + out_values.push_back(val); + } +} +~~~~~ +{:.draco-syntax } + + +### BuildSymbolTables + +~~~~~ +void BuildSymbolTables(num_symbols_, lut_table_, probability_table_) { + for (i = 0; i < num_symbols_; ++i) { + // Decode the first byte and extract the number of extra bytes we need to + // get, or the offset to the next symbol with non-zero probability. + prob_data UI8 + token = prob_data & 3; + if (token == 3) { + offset = prob_data >> 2; + for (j = 0; j < offset + 1; ++j) { + token_probs[i + j] = 0; + } + i += offset; + } else { + prob = prob_data >> 2; + for (j = 0; j < token; ++j) { + eb UI8 + prob = prob | (eb << (8 * (j + 1) - 2)); + } + token_probs[i] = prob; + } + } + rans_build_look_up_table(&token_probs[0], num_symbols_, lut_table_, + probability_table_); +} +~~~~~ +{:.draco-syntax } + + +### rans_build_look_up_table + +~~~~~ +void rans_build_look_up_table( + token_probs[], num_symbols, lut_table_, probability_table_) { + cum_prob = 0; + act_prob = 0; + for (i = 0; i < num_symbols; ++i) { + probability_table_[i].prob = token_probs[i]; + probability_table_[i].cum_prob = cum_prob; + cum_prob += token_probs[i]; + for (j = act_prob; j < cum_prob; ++j) { + lut_table_[j] = i; + } + act_prob = cum_prob; + } +} +~~~~~ +{:.draco-syntax } + + +### RansInitDecoder + +~~~~~ +void RansInitDecoder(ans, buf, offset, l_rans_base) { + ans.buf = buf; + x = buf[offset - 1] >> 6; + if (x == 0) { + ans.buf_offset = offset - 1; + ans.state = buf[offset - 1] & 0x3F; + } else if (x == 1) { + ans.buf_offset = offset - 2; + ans.state = mem_get_le16(buf + offset - 2) & 0x3FFF; + } else if (x == 2) { + ans.buf_offset = offset - 3; + ans.state = mem_get_le24(buf + offset - 3) & 0x3FFFFF; + } else if (x == 3) { + ans.buf_offset = offset - 4; + ans.state = mem_get_le32(buf + offset - 4) & 0x3FFFFFFF; + } + ans.state += l_rans_base; +} +~~~~~ +{:.draco-syntax } + + +### RansRead + +~~~~~ +void RansRead(ans, l_rans_base, rans_precision, + lut_table_, probability_table_, val) { + while (ans.state < l_rans_base && ans.buf_offset > 0) { + ans.state = ans.state * IO_BASE + ans.buf[--ans.buf_offset]; + } + quo = ans.state / rans_precision; + rem = ans.state % rans_precision; + fetch_sym(&sym, rem, lut_table_, probability_table_); + ans.state = quo * sym.prob + rem - sym.cum_prob; + val = sym.val; +} +~~~~~ +{:.draco-syntax } + + +### fetch_sym + +~~~~~ +void fetch_sym(sym, rem, lut_table_, probability_table_) { + symbol = lut_table_[rem]; + sym.val = symbol; + sym.prob = probability_table_[symbol].prob; + sym.cum_prob = probability_table_[symbol].cum_prob; +} +~~~~~ +{:.draco-syntax } + + +### RabsDescRead + +~~~~~ +void RabsDescRead(ans, p0, out_val) { + p = rabs_ans_p8_precision - p0; + if (ans->state < rabs_l_base) { + ans->state = ans->state * IO_BASE + ans->buf[--ans->buf_offset]; } x = ans->state; - quot = x / ans_p8_precision; - rem = x % ans_p8_precision; + quot = x / rabs_ans_p8_precision; + rem = x % rabs_ans_p8_precision; xn = quot * p; val = rem < p; if (val) { @@ -42,81 +233,7 @@ int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) { } else { ans->state = x - xn - p; } - return val; -} -~~~~~ -{:.draco-syntax } - - -### rans_read_init() - -~~~~~ -rans_read_init(UI8 *buf, int offset) { - ans_.buf = buf; - x = buf[offset - 1] >> 6 - If (x == 0) { - ans_.buf_offset = offset - 1; - ans_.state = buf[offset - 1] & 0x3F; - } else if (x == 1) { - ans_.buf_offset = offset - 2; - ans_.state = mem_get_le16(buf + offset - 2) & 0x3FFF; - } else if (x == 2) { - ans_.buf_offset = offset - 3; - ans_.state = mem_get_le24(buf + offset - 3) & 0x3FFFFF; - } else if (x == 3) { - ans_.buf_offset = offset - 4; - ans_.state = mem_get_le32(buf + offset - 4) & 0x3FFFFFFF; - } - ans_.state += l_rans_base; -} -~~~~~ -{:.draco-syntax } - - -### rans_build_look_up_table() - -~~~~~ -rans_build_look_up_table() { - cum_prob = 0 - act_prob = 0 - for (i = 0; i < num_symbols; ++i) { - probability_table_[i].prob = token_probs[i]; - probability_table_[i].cum_prob = cum_prob; - cum_prob += token_probs[i]; - for (j = act_prob; j < cum_prob; ++j) { - Lut_table_[j] = i - } - act_prob = cum_prob -} -~~~~~ -{:.draco-syntax } - - -### rans_read() - -~~~~~ -rans_read() { - while (ans_.state < l_rans_base) { - ans_.state = ans_.state * io_base + ans_.buf[--ans_.buf_offset]; - } - quo = ans_.state / rans_precision; - rem = ans_.state % rans_precision; - sym = fetch_sym() - ans_.state = quo * sym.prob + rem - sym.cum_prob; - return sym.val; -} -~~~~~ -{:.draco-syntax } - - -### fetch_sym() - -~~~~~ -fetch_sym() { - symbol = lut_table[rem] - out->val = symbol - out->prob = probability_table_[symbol].prob; - out->cum_prob = probability_table_[symbol].cum_prob; + out_val = val; } ~~~~~ {:.draco-syntax } diff --git a/docs/spec/sequential.attribute.decoder.md b/docs/spec/sequential.attribute.decoder.md deleted file mode 100644 index 2b8a239..0000000 --- a/docs/spec/sequential.attribute.decoder.md +++ /dev/null @@ -1,28 +0,0 @@ - -## Sequential Attribute Decoder - -~~~~~ -Initialize(...) { - // Init some members -} -~~~~~ -{:.draco-syntax } - - -### DecodeValues() - -~~~~~ -DecodeValues(const std::vector &point_ids) { - num_values = point_ids.size(); - entry_size = attribute_->byte_stride(); - std::unique_ptr value_data_ptr(new uint8_t[entry_size]); - out_byte_pos = 0; - for (i = 0; i < num_values; ++i) { - value_data UI8 * entry_size - attribute_->buffer()->Write(out_byte_pos, value_data, entry_size); - out_byte_pos += entry_size; - } -} -~~~~~ -{:.draco-syntax } - diff --git a/docs/spec/sequential.attributes.decoders.controller.md b/docs/spec/sequential.attributes.decoders.controller.md deleted file mode 100644 index 5e9f14c..0000000 --- a/docs/spec/sequential.attributes.decoders.controller.md +++ /dev/null @@ -1,54 +0,0 @@ - -## Sequential Attributes Decoders Controller - -### DecodeAttributesDecoderData() - -~~~~~ -DecodeAttributesDecoderData(buffer) { - AttributesDecoder_DecodeAttributesDecoderData(buffer) - sequential_decoders_.resize(num_attributes()); - for (i = 0; i < num_attributes(); ++i) { - decoder_type UI8 - sequential_decoders_[i] = CreateSequentialDecoder(decoder_type); - sequential_decoders_[i]->Initialize(decoder(), GetAttributeId(i)) -} -~~~~~ -{:.draco-syntax } - - -### DecodeAttributes() - -~~~~~ -DecodeAttributes(buffer) { - sequencer_->GenerateSequence(&point_ids_) - for (i = 0; i < num_attributes(); ++i) { - pa = decoder()->point_cloud()->attribute(GetAttributeId(i)); - sequencer_->UpdatePointToAttributeIndexMapping(pa) - } - for (i = 0; i < num_attributes(); ++i) { - sequential_decoders_[i]->Decode(point_ids_, buffer) - //SequentialAttributeDecoder_Decode() - } -} -~~~~~ -{:.draco-syntax } - - -### CreateSequentialDecoder() - -~~~~~ -CreateSequentialDecoder(type) { - switch (type) { - case SEQUENTIAL_ATTRIBUTE_ENCODER_GENERIC: - return new SequentialAttributeDecoder() - case SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGER: - return new SequentialIntegerAttributeDecoder() - case SEQUENTIAL_ATTRIBUTE_ENCODER_QUANTIZATION: - return new SequentialQuantizationAttributeDecoder() - case SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS: - return new SequentialNormalAttributeDecoder() - } -} -~~~~~ -{:.draco-syntax } - diff --git a/docs/spec/sequential.decoder.md b/docs/spec/sequential.decoder.md new file mode 100644 index 0000000..2209387 --- /dev/null +++ b/docs/spec/sequential.decoder.md @@ -0,0 +1,72 @@ + +## Sequential Connectivity Decoder + +### ParseSequentialConnectivityData() + +~~~~~ +void ParseSequentialConnectivityData() { + num_faces I32 + num_points I32 + connectivity_method UI8 +} +~~~~~ +{:.draco-syntax } + + +### ParseSequentialIndicesUI8() + +~~~~~ +void ParseSequentialIndicesUI8() { + for (i = 0; i < num_faces; ++i) { + for (j = 0; j < 3; ++j) { + face_to_vertex[j][i] UI8 + } + } +} +~~~~~ +{:.draco-syntax } + + +### ParseSequentialIndicesUI16() + +~~~~~ +void ParseSequentialIndicesUI16() { + for (i = 0; i < num_faces; ++i) { + for (j = 0; j < 3; ++j) { + face_to_vertex[j][i] UI16 + } + } +} +~~~~~ +{:.draco-syntax } + + +### ParseSequentialIndicesUI32() + +~~~~~ +void ParseSequentialIndicesUI32() { + for (i = 0; i < num_faces; ++i) { + for (j = 0; j < 3; ++j) { + face_to_vertex[j][i] UI32 + } + } +} +~~~~~ +{:.draco-syntax } + + +### DecodeSequentialConnectivityData() + +~~~~~ +void DecodeSequentialConnectivityData() { + ParseSequentialConnectivityData(); + if (num_points < 256) { + ParseSequentialIndicesUI8(); + } else if (num_points < (1 << 16)) { + ParseSequentialIndicesUI16(); + } else { + ParseSequentialIndicesUI32(); + } +} +~~~~~ +{:.draco-syntax } diff --git a/docs/spec/sequential.integer.attribute.decoder.md b/docs/spec/sequential.integer.attribute.decoder.md index 661557d..751687c 100644 --- a/docs/spec/sequential.integer.attribute.decoder.md +++ b/docs/spec/sequential.integer.attribute.decoder.md @@ -1,55 +1,64 @@ ## Sequential Integer Attribute Decoder +### ConvertSymbolToSignedInt() + ~~~~~ -Initialize(...) { - SequentialAttributeDecoder_Initialize() +int ConvertSymbolToSignedInt(val) { + is_positive = !static_cast(val & 1); + val >>= 1; + if (is_positive) { + return val; + } + val = -val - 1; + return val; } ~~~~~ {:.draco-syntax } -### DecodeValues() +### ConvertSymbolsToSignedInts() ~~~~~ -DecodeValues(point_ids) { - prediction_scheme_method I8 - if (prediction_scheme_method != PREDICTION_NONE) { - prediction_transform_type I8 - prediction_scheme_ = CreateIntPredictionScheme(...) +void ConvertSymbolsToSignedInts() { + decoded_symbols = seq_int_att_dec_decoded_values[curr_att_dec][curr_att]; + for (i = 0; i < decoded_symbols.size(); ++i) { + val = ConvertSymbolToSignedInt(decoded_symbols[i]); + seq_int_att_dec_symbols_to_signed_ints[i] = val; } - if (prediction_scheme_) { - } - DecodeIntegerValues(point_ids) - //SequentialQuantizationAttributeDecoder_DecodeIntegerValues() - //StoreValues() - DequantizeValues(num_values) } ~~~~~ {:.draco-syntax } -### DecodeIntegerValues() +### SequentialIntegerAttributeDecoder_DecodeIntegerValues() ~~~~~ -DecodeIntegerValues(point_ids) { - compressed UI8 - if (compressed) { - DecodeSymbols(..., values_.data()) - } else { - // TODO +void SequentialIntegerAttributeDecoder_DecodeIntegerValues() { + num_components = GetNumComponents(); + num_entries = att_dec_num_values_to_decode[curr_att_dec][curr_att]; + num_values = num_entries * num_components; + if (seq_int_att_dec_compressed[curr_att_dec][curr_att] > 0) { + DecodeSymbols(num_values, num_components, &decoded_symbols); } - if (!prediction_scheme_->AreCorrectionsPositive()) { - ConvertSymbolsToSignedInts(...) + seq_int_att_dec_decoded_values[curr_att_dec][curr_att] = decoded_symbols; + if (num_values > 0) { + if (seq_att_dec_prediction_transform_type[curr_att_dec][curr_att] == + PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED) { + decoded_symbols = seq_int_att_dec_decoded_values[curr_att_dec][curr_att]; + for (int i = 0; i < decoded_symbols.size(); ++i) { + signed_vals[i] = decoded_symbols[i]; + } + seq_int_att_dec_symbols_to_signed_ints[curr_att_dec][curr_att] = signed_vals; + } else { + ConvertSymbolsToSignedInts(); + } + } + if (seq_att_dec_prediction_scheme[curr_att_dec][curr_att] != PREDICTION_NONE) { + DecodePredictionData(seq_att_dec_prediction_scheme[curr_att_dec][curr_att]); + PredictionScheme_ComputeOriginalValues( + seq_att_dec_prediction_scheme[curr_att_dec][curr_att], num_entries); } - if (prediction_scheme_) { - prediction_scheme_->DecodePredictionData(buffer) - // DecodeTransformData(buffer) - if (!values_.empty()) { - prediction_scheme_->Decode(values_.data(), &values_[0], - values_.size(), num_components, point_ids.data()) - // MeshPredictionSchemeParallelogram_Decode() } ~~~~~ {:.draco-syntax } - diff --git a/docs/spec/sequential.normal.attribute.decoder.md b/docs/spec/sequential.normal.attribute.decoder.md new file mode 100644 index 0000000..0eec3d2 --- /dev/null +++ b/docs/spec/sequential.normal.attribute.decoder.md @@ -0,0 +1,103 @@ + +## Sequential Normal Attribute Decoder + +### MostSignificantBit() + +~~~~~ +int MostSignificantBit(n) { + msb = -1; + while (n != 0) { + msb++; + n >>= 1; + } + return msb; +} +~~~~~ +{:.draco-syntax } + + +### OctaherdalCoordsToUnitVector() + +~~~~~ +void OctaherdalCoordsToUnitVector(in_s, in_t, out_vector) { + s = in_s; + t = in_t; + spt = s + t; + smt = s - t; + x_sign = 1.0; + if (spt >= 0.5 && spt <= 1.5 && smt >= -0.5 && smt <= 0.5) { + // Right hemisphere. Don't do anything. + } else { + x_sign = -1.0; + if (spt <= 0.5) { + s = 0.5 - in_t; + t = 0.5 - in_s; + } else if (spt >= 1.5) { + s = 1.5 - in_t; + t = 1.5 - in_s; + } else if (smt <= -0.5) { + s = in_t - 0.5; + t = in_s + 0.5; + } else { + s = in_t + 0.5; + t = in_s - 0.5; + } + spt = s + t; + smt = s - t; + } + y = 2.0 * s - 1.0; + z = 2.0 * t - 1.0; + x = std::min(std::min(2.0 * spt - 1.0, 3.0 - 2.0 * spt), + std::min(2.0 * smt + 1.0, 1.0 - 2.0 * smt)) * x_sign; + normSquared = x * x + y * y + z * z; + if (normSquared < 1e-6) { + out_vector[0] = 0; + out_vector[1] = 0; + out_vector[2] = 0; + } else { + const float d = 1.0 / std::sqrt(normSquared); + out_vector[0] = x * d; + out_vector[1] = y * d; + out_vector[2] = z * d; + } +} +~~~~~ +{:.draco-syntax } + + +### QuantizedOctaherdalCoordsToUnitVector() + +~~~~~ +void QuantizedOctaherdalCoordsToUnitVector(in_s, in_t, out_vector) { + encoded_max_quantized_value = + pred_trasnform_normal_max_q_val[curr_att_dec][curr_att]; + quantization_bits_ = MostSignificantBit(encoded_max_quantized_value) + 1; + max_quantized_value_ = (1 << quantization_bits_) - 1; + max_value_ = max_quantized_value_ - 1; + scale = 1.0 / max_value_; + OctaherdalCoordsToUnitVector(in_s * scale, in_t * scale, out_vector); +} +~~~~~ +{:.draco-syntax } + + +### TransformAttributesToOriginalFormat_Normal() + +~~~~~ +void TransformAttributesToOriginalFormat_Normal() { + quant_val_id = 0; + portable_attribute_data = seq_int_att_dec_original_values[curr_att_dec][curr_att]; + num_points = att_dec_num_values_to_decode[curr_att_dec][curr_att]; + for (i = 0; i < num_points; ++i) { + s = portable_attribute_data[quant_val_id++]; + t = portable_attribute_data[quant_val_id++]; + QuantizedOctaherdalCoordsToUnitVector(s, t, att_val); + for (j = 0; j < 3; ++j) { + normals.push_back(att_val[j]); + } + } + seq_int_att_dec_dequantized_values[curr_att_dec][curr_att] = normals; +} +~~~~~ +{:.draco-syntax } + diff --git a/docs/spec/sequential.quantization.attribute.decoder.md b/docs/spec/sequential.quantization.attribute.decoder.md index 182ea2c..bf427e7 100644 --- a/docs/spec/sequential.quantization.attribute.decoder.md +++ b/docs/spec/sequential.quantization.attribute.decoder.md @@ -1,51 +1,71 @@ ## Sequential Quantization Attribute Decoder +### ParseQuantizationBits() + ~~~~~ -Initialize(...) { - SequentialIntegerAttributeDecoder_Initialize() +void ParseQuantizationBits() { + quantized_data_quantization_bits[curr_att_dec][curr_att] UI8 } ~~~~~ {:.draco-syntax } -### DecodeIntegerValues() +### ParseQuantizationData() ~~~~~ -DecodeIntegerValues(point_ids) { - // REMOVE < DRACO_BITSTREAM_VERSION(2, 0) - // DecodeQuantizedDataInfo() - num_components = attribute()->components_count(); - for (i = 0; i < num_components; ++i) { - min_value_[i] F32 +void ParseQuantizationData() { + num_components = GetNumComponents(); + for (j = 0; j < num_components; ++j) { + quantized_data_min_values[curr_att_dec][curr_att][i] Float } - max_value_dif_ F32 - quantization_bits_ UI8 - // REMOVE < DRACO_BITSTREAM_VERSION(2, 0) - SequentialIntegerAttributeDecoder::DecodeIntegerValues() + quantized_data_max_value_df[curr_att_dec][curr_att] Float + ParseQuantizationBits(); } ~~~~~ {:.draco-syntax } -### DequantizeValues() +### DequantizeFloat() ~~~~~ -DequantizeValues(num_values) { - max_quantized_value = (1 << (quantization_bits_)) - 1; - num_components = attribute()->components_count(); - entry_size = sizeof(float) * num_components; +float DequantizeFloat(val, max_quantized_value_factor_, range_) { + neg = (val < 0); + if (neg) { + val = -val; + } + norm_value = val * max_quantized_value_factor_; + if (neg) + norm_value = -norm_value; + return norm_value * range_; +} +~~~~~ +{:.draco-syntax } + + +### SequentialQuantizationAttributeDecoder_DequantizeValues() + +~~~~~ +void SequentialQuantizationAttributeDecoder_DequantizeValues() { + quantization_bits = quantized_data_quantization_bits[curr_att_dec][curr_att]; + max_quantized_value = (1 << (quantization_bits)) - 1; + num_components = GetNumComponents(); quant_val_id = 0; - out_byte_pos = 0; + range_ = quantized_data_max_value_df[curr_att_dec][curr_att]; + max_quantized_value_factor_ = 1.f / max_quantized_value; + min_value_ = quantized_data_min_values[curr_att_dec][curr_att]; + original_values = seq_int_att_dec_original_values[curr_att_dec][curr_att]; + num_values = att_dec_num_values_to_decode[curr_att_dec][curr_att]; for (i = 0; i < num_values; ++i) { for (c = 0; c < num_components; ++c) { - value = dequantizer.DequantizeFloat(values()->at(quant_val_id++)); + value = DequantizeFloat(original_values[quant_val_id++], + max_quantized_value_factor_, range_); value = value + min_value_[c]; att_val[c] = value; + dequantized_data.push_back(value); } - attribute()->buffer()->Write(out_byte_pos, att_val, entry_size); - out_byte_pos += entry_size; } + seq_int_att_dec_dequantized_values[curr_att_dec][curr_att] = dequantized_data; } ~~~~~ {:.draco-syntax } diff --git a/docs/spec/symbol.decoding.md b/docs/spec/symbol.decoding.md deleted file mode 100644 index 7f0fba4..0000000 --- a/docs/spec/symbol.decoding.md +++ /dev/null @@ -1,98 +0,0 @@ - -## Symbol Decoding - -### DecodeSymbols() - -~~~~~ -DecodeSymbols(num_symbols, out_values) { - scheme UI8 - If (scheme == 0) { - DecodeTaggedSymbols(num_symbols, out_values) - } else if (scheme == 1) { - DecodeRawSymbols(num_symbols, out_values) - } -} -~~~~~ -{:.draco-syntax } - - -### DecodeTaggedSymbols() - -~~~~~ -DecodeTaggedSymbols() { - FIXME -} -~~~~~ -{:.draco-syntax } - - -### DecodeRawSymbols() - -~~~~~ -DecodeRawSymbols(num_values, out_values) { - max_bit_length UI8 - decoder = CreateRansSymbolDecoder(max_bit_length) - decoder.StartDecoding() - // RansSymbolDecoder_StartDecoding - for (i = 0; i < num_values; ++i) { - out_values[i] = decoder.DecodeSymbol() - // RansSymbolDecoder_DecodeSymbol - } -} -~~~~~ -{:.draco-syntax } - - -### CreateRansSymbolDecoder() - -~~~~~ -CreateRansSymbolDecoder(max_bit_length) { - rans_precision_bits = (3 * max_bit_length) / 2; - rans_precision_bits = min(rans_precision_bits, 20) - rans_precision_bits = max(rans_precision_bits, 12) - rans_precision = 1 << rans_precision_bits_; - l_rans_base = rans_precision * 4; - num_symbols_ UI32 - for (i = 0; i < num_symbols_; ++i) { - prob_data UI8 - if ((prob_data & 3) == 3) { - offset = prob_data >> 2 - for (j = 0; j < offset + 1; ++j) { - probability_table_[i + j] = 0; - } - i += offset; - } else { - prob = prob_data >> 2 - for (j = 0; j < token; ++j) { - eb UI8 - prob = prob | (eb << (8 * (j + 1) - 2) - } - probability_table_[i] = prob; - } - } - rans_build_look_up_table() -} -~~~~~ -{:.draco-syntax } - - -### RansSymbolDecoder_StartDecoding() - -~~~~~ -RansSymbolDecoder_StartDecoding() { - bytes_encoded UI64 - buffer bytes_encoded * UI8 - rans_read_init(buffer, bytes_encoded) -} -~~~~~ -{:.draco-syntax } - - -### RansSymbolDecoder_DecodeSymbol() - -~~~~~ -RansSymbolDecoder_DecodeSymbol() { - return ans_.rans_read() -} -~~~~~ -{:.draco-syntax } diff --git a/docs/spec/vector.md b/docs/spec/vector.md new file mode 100644 index 0000000..da6878b --- /dev/null +++ b/docs/spec/vector.md @@ -0,0 +1,87 @@ +## Vectors + +### Dot() + +~~~~~ +void Dot(vec_x, vec_y, dot) { + dot = 0; + for (i = 0; i < vec_x.size(); ++i) { + dot += vec_x[i] * vec_y[i]; + } +} +~~~~~ +{:.draco-syntax} + + +### AbsSum() + +~~~~~ +void AbsSum(vec, abs_sum) { + result = 0; + for (i = 0; i < vec.size(); ++i) { + result += std::abs(vec[i]); + } + abs_sum = result; +} +~~~~~ +{:.draco-syntax} + + +### MultiplyScalar() + +~~~~~ +void MultiplyScalar(vec, value, out) { + for (i = 0; i < vec.size(); ++i) { + out.push_back(vec[i] * value); + } +} +~~~~~ +{:.draco-syntax} + + +### DivideScalar() + +~~~~~ +void DivideScalar(vec, value, out) { + for (i = 0; i < vec.size(); ++i) { + out.push_back(vec[i] / value); + } +} +~~~~~ +{:.draco-syntax} + + +### AddVectors() + +~~~~~ +void AddVectors(a, b, c) { + for (i = 0; i < a.size(); ++i) { + c.push_back(a[i] + b[i]); + } +} +~~~~~ +{:.draco-syntax} + + +### SubtractVectors() + +~~~~~ +void SubtractVectors(a, b, c) { + for (i = 0; i < a.size(); ++i) { + c.push_back(a[i] - b[i]); + } +} +~~~~~ +{:.draco-syntax} + + +### CrossProduct() + +~~~~~ +void CrossProduct(u, v, r) { + r[0] = (u[1] * v[2]) - (u[2] * v[1]); + r[1] = (u[2] * v[0]) - (u[0] * v[2]); + r[2] = (u[0] * v[1]) - (u[1] * v[0]); +} +~~~~~ +{:.draco-syntax}