mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-06-21 18:16:39 +08:00
Merge pull request #205 from google/update_bitstream_spec
Update bitstream spec to version 2.1
This commit is contained in:
commit
c6575182fe
@ -1,21 +1,295 @@
|
|||||||
|
|
||||||
## Attributes Decoder
|
## Attributes Decoder
|
||||||
|
|
||||||
### DecodeAttributesDecoderData()
|
### ParseAttributeDecodersData()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeAttributesDecoderData(buffer) {
|
void ParseAttributeDecodersData() {
|
||||||
num_attributes varUI32
|
num_attributes_decoders UI8
|
||||||
point_attribute_ids_.resize(num_attributes);
|
if (encoder_method == MESH_EDGEBREAKER_ENCODING) {
|
||||||
for (i = 0; i < num_attributes; ++i) {
|
for (i = 0; i < num_attributes_decoders; ++i) {
|
||||||
att_type UI8
|
att_dec_data_id[i] UI8
|
||||||
data_type UI8
|
att_dec_decoder_type[i] UI8
|
||||||
components_count UI8
|
att_dec_traversal_method[i] UI8
|
||||||
normalized UI8
|
}
|
||||||
custom_id UI16
|
}
|
||||||
Initialize GeometryAttribute ga
|
for (i = 0; i < num_attributes_decoders; ++i) {
|
||||||
att_id = pc->AddAttribute(new PointAttribute(ga));
|
att_dec_num_attributes[i] varUI32
|
||||||
point_attribute_ids_[i] = att_id;
|
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 }
|
{:.draco-syntax }
|
||||||
|
147
docs/spec/boundary.decoder.md
Normal file
147
docs/spec/boundary.decoder.md
Normal file
@ -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}
|
||||||
|
|
15
docs/spec/connectivity.decoder.md
Normal file
15
docs/spec/connectivity.decoder.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
## Connectivity Decoder
|
||||||
|
|
||||||
|
### DecodeConnectivityData()
|
||||||
|
|
||||||
|
~~~~~
|
||||||
|
void DecodeConnectivityData() {
|
||||||
|
if (encoder_method == MESH_SEQUENTIAL_ENCODING)
|
||||||
|
DecodeSequentialConnectivityData();
|
||||||
|
else
|
||||||
|
DecodeEdgebreakerConnectivityData();
|
||||||
|
}
|
||||||
|
|
||||||
|
~~~~~
|
||||||
|
{:.draco-syntax }
|
@ -1,65 +1,16 @@
|
|||||||
|
|
||||||
## Core Functions
|
## Core Functions
|
||||||
|
|
||||||
### DecodeVarint<IT>
|
### DecodeVarint
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeVarint<IT>() {
|
void DecodeVarint(out_val) {
|
||||||
If (std::is_unsigned<IT>::value) {
|
in UI8
|
||||||
in UI8
|
if (in & (1 << 7)) {
|
||||||
If (in & (1 << 7)) {
|
DecodeVarint(out_val);
|
||||||
out = DecodeVarint<IT>()
|
out_val = (out_val << 7) | (in & ((1 << 7) - 1));
|
||||||
out = (out << 7) | (in & ((1 << 7) - 1))
|
|
||||||
} else {
|
|
||||||
typename std::make_unsigned<IT>::type UIT;
|
|
||||||
out = DecodeVarint<UIT>()
|
|
||||||
out = ConvertSymbolToSignedInt(out)
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
~~~~~
|
|
||||||
{:.draco-syntax }
|
|
||||||
|
|
||||||
|
|
||||||
### ConvertSymbolToSignedInt()
|
|
||||||
|
|
||||||
~~~~~
|
|
||||||
ConvertSymbolToSignedInt() {
|
|
||||||
abs_val = val >> 1
|
|
||||||
If (val & 1 == 0) {
|
|
||||||
return abs_val
|
|
||||||
} else {
|
} else {
|
||||||
signed_val = -abs_val - 1
|
out_val = in;
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
|
203
docs/spec/corner.md
Normal file
203
docs/spec/corner.md
Normal file
@ -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}
|
@ -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 }
|
|
@ -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 }
|
|
@ -3,47 +3,28 @@
|
|||||||
### Decode()
|
### Decode()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
Decode() {
|
void Decode() {
|
||||||
DecodeHeader()
|
ParseHeader();
|
||||||
if (flags & METADATA_FLAG_MASK)
|
if (flags & METADATA_FLAG_MASK)
|
||||||
DecodeGeometryMetadata(metadata)
|
DecodeMetadata();
|
||||||
DecodeConnectivityData()
|
DecodeConnectivityData();
|
||||||
DecodeAttributeData()
|
DecodeAttributeData();
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax}
|
{:.draco-syntax}
|
||||||
|
|
||||||
|
|
||||||
### DecodeHeader()
|
### ParseHeader()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeHeader() {
|
ParseHeader() {
|
||||||
draco_string UI8[5]
|
draco_string UI8[5]
|
||||||
major_version UI8
|
major_version UI8
|
||||||
minor_version UI8
|
minor_version UI8
|
||||||
encoder_type UI8
|
encoder_type UI8
|
||||||
encoder_method UI8
|
encoder_method UI8
|
||||||
flags
|
flags UI16
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax}
|
{:.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}
|
|
||||||
|
@ -1,299 +1,80 @@
|
|||||||
## EdgeBreaker Decoder
|
## EdgeBreaker Decoder
|
||||||
|
|
||||||
### DecodeConnectivityData()
|
### ParseEdgebreakerConnectivityData()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeConnectivityData() {
|
void ParseEdgebreakerConnectivityData() {
|
||||||
edgebreaker_traversal_type UI8
|
edgebreaker_traversal_type UI8
|
||||||
num_new_verts varUI32
|
num_new_vertices varUI32
|
||||||
num_encoded_vertices varUI32
|
num_encoded_vertices varUI32
|
||||||
num_faces varUI32
|
num_faces varUI32
|
||||||
num_attribute_data I8
|
num_attribute_data I8
|
||||||
num_encoded_symbols varUI32
|
num_encoded_symbols varUI32
|
||||||
num_encoded_split_symbols varUI32
|
num_encoded_split_symbols varUI32
|
||||||
encoded_connectivity_size 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
|
// file pointer must be set to current position
|
||||||
// + encoded_connectivity_size
|
// + 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
|
// file pointer must be set to old current position
|
||||||
EdgeBreakerTraversalValence_Start(num_encoded_vertices)
|
EdgebreakerTraversalStart();
|
||||||
DecodeConnectivity(num_symbols)
|
DecodeEdgeBreakerConnectivity();
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
|
||||||
### AssignPointsToCorners()
|
### ProcessSplitData()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
AssignPointsToCorners() {
|
void ProcessSplitData() {
|
||||||
decoder_->mesh()->SetNumFaces(corner_table_->num_faces());
|
last_id = 0;
|
||||||
if (attribute_data_.size() == 0) {
|
for (i = 0; i < source_id_delta.size(); ++i) {
|
||||||
for (f = 0; f < decoder_->mesh()->num_faces(); ++f) {
|
source_symbol_id[i] = source_id_delta[i] + last_id;
|
||||||
for (c = 0; c < 3; ++c) {
|
split_symbol_id.[i] = source_symbol_id[i] - split_id_delta[i];
|
||||||
vert_id = corner_table_->Vertex(3 * f + c);
|
last_id = source_symbol_id[i];
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
|
||||||
### UpdateCornerTableForSymbolC()
|
### DecodeTopologySplitEvents()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
UpdateCornerTableForSymbolC(corner) {
|
void DecodeTopologySplitEvents() {
|
||||||
corner_a = active_corner_stack.back();
|
ParseTopologySplitEvents();
|
||||||
corner_b = corner_table_->Previous(corner_a);
|
ProcessSplitData();
|
||||||
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)));
|
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
@ -302,41 +83,32 @@ UpdateCornerTableForInteriorFace() {
|
|||||||
### IsTopologySplit()
|
### IsTopologySplit()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
IsTopologySplit(encoder_symbol_id, *out_face_edge,
|
bool IsTopologySplit(encoder_symbol_id, out_face_edge,
|
||||||
*out_encoder_split_symbol_id) {
|
out_encoder_split_symbol_id) {
|
||||||
if (topology_split_data_.size() == 0)
|
if (source_symbol_id.back() != encoder_symbol_id)
|
||||||
return false;
|
return false;
|
||||||
if (topology_split_data_.back().source_symbol_id != encoder_symbol_id)
|
*out_face_edge = source_edge_bit.pop();
|
||||||
return false;
|
*out_encoder_split_symbol_id = split_symbol_id.pop();
|
||||||
*out_face_edge = topology_split_data_.back().source_edge;
|
source_symbol_id.pop();
|
||||||
*out_encoder_split_symbol_id =
|
|
||||||
topology_split_data_.back().split_symbol_id;
|
|
||||||
topology_split_data_.pop_back();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
|
||||||
### DecodeAttributeConnectivitiesOnFace()
|
### ReplaceVerts()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeAttributeConnectivitiesOnFace(corner) {
|
void ReplaceVerts(from, to) {
|
||||||
corners[3] = {corner, corner_table_->Next(corner),
|
for (i = 0; i < face_to_vertex[0].size(); ++i) {
|
||||||
corner_table_->Previous(corner)}
|
if (face_to_vertex[0][i] == from) {
|
||||||
for (c = 0; c < 3; ++c) {
|
face_to_vertex[0][i] = to;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
|
if (face_to_vertex[1][i] == from) {
|
||||||
bool is_seam = traversal_decoder_.DecodeAttributeSeam(i);
|
face_to_vertex[1][i] = to;
|
||||||
if (is_seam) {
|
}
|
||||||
attribute_data_[i].attribute_seam_corners.push_back(corners[c]);
|
if (face_to_vertex[2][i] == from) {
|
||||||
}
|
face_to_vertex[2][i] = to;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -344,12 +116,238 @@ DecodeAttributeConnectivitiesOnFace(corner) {
|
|||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
|
||||||
### SetOppositeCorners()
|
### UpdateCornersAfterMerge()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
SetOppositeCorners(corner_0, corner_1) {
|
void UpdateCornersAfterMerge(c, v) {
|
||||||
corner_table_->SetOppositeCorner(corner_0, corner_1);
|
opp_corner = PosOpposite(c);
|
||||||
corner_table_->SetOppositeCorner(corner_1, corner_0);
|
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 }
|
{:.draco-syntax }
|
||||||
|
@ -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<AttProcessor, AttObserver> AttTraverser;
|
|
||||||
sequencer = CreateVertexTraversalSequencer<AttTraverser>(encoding_data);
|
|
||||||
} else if (traversal_method == MESH_TRAVERSAL_PREDICTION_DEGREE) {
|
|
||||||
typedef PredictionDegreeTraverser<AttProcessor, AttObserver> AttTraverser;
|
|
||||||
sequencer = CreateVertexTraversalSequencer<AttTraverser>(encoding_data);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
att_controller(new SequentialAttributeDecodersController(std::move(sequencer)))
|
|
||||||
decoder_->SetAttributesDecoder(att_decoder_id, std::move(att_controller));
|
|
||||||
}
|
|
||||||
~~~~~
|
|
||||||
{:.draco-syntax }
|
|
||||||
|
|
@ -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 }
|
|
211
docs/spec/edgebreaker.traversal.md
Normal file
211
docs/spec/edgebreaker.traversal.md
Normal file
@ -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 }
|
113
docs/spec/edgebreaker.traversal.prediction.degree.md
Normal file
113
docs/spec/edgebreaker.traversal.prediction.degree.md
Normal file
@ -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 }
|
@ -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 }
|
|
58
docs/spec/edgebreaker.traversal.valence.md
Normal file
58
docs/spec/edgebreaker.traversal.valence.md
Normal file
@ -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 }
|
||||||
|
|
@ -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 }
|
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
layout: spec-page
|
layout: spec-page
|
||||||
title: Draco Bitstream Specification (Draft)
|
title: Draco Bitstream Specification (Draft)
|
||||||
version: Version 1,2
|
version: Version 2,1
|
||||||
version_date: Released 2017-xx-xx
|
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.02.authors.md %}
|
||||||
{% include_relative 00.00.03.last.modified.md %}
|
{% include_relative 00.00.03.last.modified.md %}
|
||||||
{% include_relative 00.00.04.abstract.md %}
|
{% include_relative 00.00.04.abstract.md %}
|
||||||
|
|
||||||
{% include_relative 00.00.05.toc.md %}
|
{% include_relative 00.00.05.toc.md %}
|
||||||
|
|
||||||
{% include_relative 01.00.00.scope.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 04.00.00.conventions.md %}
|
||||||
{% include_relative draco.decoder.md %}
|
{% include_relative draco.decoder.md %}
|
||||||
{% include_relative metadata.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.decoder.md %}
|
||||||
{% include_relative edgebreaker.hole.and.topology.md %}
|
{% include_relative edgebreaker.traversal.md %}
|
||||||
{% include_relative edgebreaker.traversal.decoder.md %}
|
{% include_relative edgebreaker.traversal.valence.md %}
|
||||||
{% include_relative edgebreaker.traversal.valence.decoder.md %}
|
{% include_relative edgebreaker.traversal.prediction.degree.md %}
|
||||||
{% include_relative attributes.decoder.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 sequential.integer.attribute.decoder.md %}
|
||||||
|
{% include_relative boundary.decoder.md %}
|
||||||
|
{% include_relative prediction.decoder.md %}
|
||||||
{% include_relative sequential.quantization.attribute.decoder.md %}
|
{% include_relative sequential.quantization.attribute.decoder.md %}
|
||||||
{% include_relative prediction.scheme.transform.md %}
|
{% include_relative sequential.normal.attribute.decoder.md %}
|
||||||
{% include_relative prediction.scheme.wrap.transform.md %}
|
{% include_relative prediction.texcoords.decoder.md %}
|
||||||
{% include_relative mesh.prediction.scheme.parallelogram.md %}
|
{% include_relative prediction.normal.decoder.md %}
|
||||||
{% include_relative cornertable.traversal.processor.md %}
|
{% include_relative prediction.normal.transform.md %}
|
||||||
{% include_relative mesh.attribute.indices.encoding.observer.md %}
|
{% include_relative prediction.wrap.transform.md %}
|
||||||
{% include_relative edgebreaker.traverser.md %}
|
{% include_relative prediction.parallelogram.decoder.md %}
|
||||||
{% include_relative mesh.traversal.sequencer.md %}
|
{% include_relative prediction.multi.parallelogram.decoder.md %}
|
||||||
{% include_relative corner.table.md %}
|
|
||||||
{% include_relative mesh.attribute.corner.table.md %}
|
|
||||||
{% include_relative symbol.decoding.md %}
|
|
||||||
{% include_relative rans.decoding.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 core.functions.md %}
|
||||||
{% include_relative variable.descriptions.md %}
|
{% include_relative variable.descriptions.md %}
|
||||||
|
|
||||||
|
@ -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<false>(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 }
|
|
@ -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 }
|
|
@ -1,2 +0,0 @@
|
|||||||
## Mesh Decoder
|
|
||||||
|
|
@ -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 }
|
|
@ -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 }
|
|
@ -1,52 +1,78 @@
|
|||||||
## Metadata Decoder
|
## 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()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeMetadata(metadata) {
|
void DecodeMetadata() {
|
||||||
num_entries varUI32
|
ParseMetedataCount();
|
||||||
for (i = 0; i < num_entries; ++i) {
|
|
||||||
DecodeEntry(metadata)
|
for (i = 0; i < num_att_metadata; ++i) {
|
||||||
}
|
ParseAttributeMetadataId(i);
|
||||||
num_sub_metadata varUI32
|
DecodeMetadataElement(att_metadata[i]);
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
DecodeMetadataElement(file_metadata);
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax}
|
{:.draco-syntax}
|
||||||
|
|
||||||
|
|
||||||
### DecodeEntry()
|
### ParseMetedataCount()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeEntry(metadata) {
|
void ParseMetedataCount() {
|
||||||
size UI8
|
num_att_metadata varUI32
|
||||||
name size * UI8
|
}
|
||||||
size varUI32
|
~~~~~
|
||||||
value size * UI8
|
{:.draco-syntax}
|
||||||
metadata.entries.insert(name, value)
|
|
||||||
|
|
||||||
|
### 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}
|
{:.draco-syntax}
|
||||||
|
280
docs/spec/prediction.decoder.md
Normal file
280
docs/spec/prediction.decoder.md
Normal file
@ -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}
|
75
docs/spec/prediction.multi.parallelogram.decoder.md
Normal file
75
docs/spec/prediction.multi.parallelogram.decoder.md
Normal file
@ -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}
|
189
docs/spec/prediction.normal.decoder.md
Normal file
189
docs/spec/prediction.normal.decoder.md
Normal file
@ -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}
|
185
docs/spec/prediction.normal.transform.md
Normal file
185
docs/spec/prediction.normal.transform.md
Normal file
@ -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}
|
70
docs/spec/prediction.parallelogram.decoder.md
Normal file
70
docs/spec/prediction.parallelogram.decoder.md
Normal file
@ -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}
|
@ -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 }
|
|
@ -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 }
|
|
146
docs/spec/prediction.texcoords.decoder.md
Normal file
146
docs/spec/prediction.texcoords.decoder.md
Normal file
@ -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}
|
44
docs/spec/prediction.wrap.transform.md
Normal file
44
docs/spec/prediction.wrap.transform.md
Normal file
@ -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}
|
@ -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 }
|
|
@ -1,40 +1,231 @@
|
|||||||
|
|
||||||
## Rans Decoding
|
## Rans Decoding
|
||||||
|
|
||||||
### ans_read_init()
|
### DecodeSymbols()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
ans_read_init(AnsDecoder ans, buf, int offset) {
|
void DecodeSymbols(num_symbols, num_components, out_values) {
|
||||||
x = buf[offset - 1] >> 6
|
scheme UI8
|
||||||
If (x == 0) {
|
if (scheme == 0) {
|
||||||
ans->buf_offset = offset - 1;
|
DecodeTaggedSymbols(num_symbols, num_components, out_values);
|
||||||
ans->state = buf[offset - 1] & 0x3F;
|
} else if (scheme == 1) {
|
||||||
} else if (x == 1) {
|
DecodeRawSymbols(num_symbols, out_values);
|
||||||
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
|
|
||||||
}
|
}
|
||||||
ans->state += l_base;
|
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
|
||||||
### int rabs_desc_read()
|
### DecodeSymbols
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) {
|
void ReadEncodedData(bytes_encoded, buffer) {
|
||||||
AnsP8 p = ans_p8_precision - p0;
|
bytes_encoded varUI64
|
||||||
if (ans->state < l_base) {
|
buffer UI8[size]
|
||||||
ans->state = ans->state * io_base + ans->buf[--ans->buf_offset];
|
}
|
||||||
|
~~~~~
|
||||||
|
{:.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;
|
x = ans->state;
|
||||||
quot = x / ans_p8_precision;
|
quot = x / rabs_ans_p8_precision;
|
||||||
rem = x % ans_p8_precision;
|
rem = x % rabs_ans_p8_precision;
|
||||||
xn = quot * p;
|
xn = quot * p;
|
||||||
val = rem < p;
|
val = rem < p;
|
||||||
if (val) {
|
if (val) {
|
||||||
@ -42,81 +233,7 @@ int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) {
|
|||||||
} else {
|
} else {
|
||||||
ans->state = x - xn - p;
|
ans->state = x - xn - p;
|
||||||
}
|
}
|
||||||
return val;
|
out_val = 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;
|
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
|
|
||||||
## Sequential Attribute Decoder
|
|
||||||
|
|
||||||
~~~~~
|
|
||||||
Initialize(...) {
|
|
||||||
// Init some members
|
|
||||||
}
|
|
||||||
~~~~~
|
|
||||||
{:.draco-syntax }
|
|
||||||
|
|
||||||
|
|
||||||
### DecodeValues()
|
|
||||||
|
|
||||||
~~~~~
|
|
||||||
DecodeValues(const std::vector<PointIndex> &point_ids) {
|
|
||||||
num_values = point_ids.size();
|
|
||||||
entry_size = attribute_->byte_stride();
|
|
||||||
std::unique_ptr<uint8_t[]> 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 }
|
|
||||||
|
|
@ -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 }
|
|
||||||
|
|
72
docs/spec/sequential.decoder.md
Normal file
72
docs/spec/sequential.decoder.md
Normal file
@ -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 }
|
@ -1,55 +1,64 @@
|
|||||||
|
|
||||||
## Sequential Integer Attribute Decoder
|
## Sequential Integer Attribute Decoder
|
||||||
|
|
||||||
|
### ConvertSymbolToSignedInt()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
Initialize(...) {
|
int ConvertSymbolToSignedInt(val) {
|
||||||
SequentialAttributeDecoder_Initialize()
|
is_positive = !static_cast<bool>(val & 1);
|
||||||
|
val >>= 1;
|
||||||
|
if (is_positive) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
val = -val - 1;
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
|
||||||
### DecodeValues()
|
### ConvertSymbolsToSignedInts()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeValues(point_ids) {
|
void ConvertSymbolsToSignedInts() {
|
||||||
prediction_scheme_method I8
|
decoded_symbols = seq_int_att_dec_decoded_values[curr_att_dec][curr_att];
|
||||||
if (prediction_scheme_method != PREDICTION_NONE) {
|
for (i = 0; i < decoded_symbols.size(); ++i) {
|
||||||
prediction_transform_type I8
|
val = ConvertSymbolToSignedInt(decoded_symbols[i]);
|
||||||
prediction_scheme_ = CreateIntPredictionScheme(...)
|
seq_int_att_dec_symbols_to_signed_ints[i] = val;
|
||||||
}
|
}
|
||||||
if (prediction_scheme_) {
|
|
||||||
}
|
|
||||||
DecodeIntegerValues(point_ids)
|
|
||||||
//SequentialQuantizationAttributeDecoder_DecodeIntegerValues()
|
|
||||||
//StoreValues()
|
|
||||||
DequantizeValues(num_values)
|
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
|
||||||
### DecodeIntegerValues()
|
### SequentialIntegerAttributeDecoder_DecodeIntegerValues()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeIntegerValues(point_ids) {
|
void SequentialIntegerAttributeDecoder_DecodeIntegerValues() {
|
||||||
compressed UI8
|
num_components = GetNumComponents();
|
||||||
if (compressed) {
|
num_entries = att_dec_num_values_to_decode[curr_att_dec][curr_att];
|
||||||
DecodeSymbols(..., values_.data())
|
num_values = num_entries * num_components;
|
||||||
} else {
|
if (seq_int_att_dec_compressed[curr_att_dec][curr_att] > 0) {
|
||||||
// TODO
|
DecodeSymbols(num_values, num_components, &decoded_symbols);
|
||||||
}
|
}
|
||||||
if (!prediction_scheme_->AreCorrectionsPositive()) {
|
seq_int_att_dec_decoded_values[curr_att_dec][curr_att] = decoded_symbols;
|
||||||
ConvertSymbolsToSignedInts(...)
|
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 }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
103
docs/spec/sequential.normal.attribute.decoder.md
Normal file
103
docs/spec/sequential.normal.attribute.decoder.md
Normal file
@ -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 }
|
||||||
|
|
@ -1,51 +1,71 @@
|
|||||||
|
|
||||||
## Sequential Quantization Attribute Decoder
|
## Sequential Quantization Attribute Decoder
|
||||||
|
|
||||||
|
### ParseQuantizationBits()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
Initialize(...) {
|
void ParseQuantizationBits() {
|
||||||
SequentialIntegerAttributeDecoder_Initialize()
|
quantized_data_quantization_bits[curr_att_dec][curr_att] UI8
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
|
||||||
### DecodeIntegerValues()
|
### ParseQuantizationData()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DecodeIntegerValues(point_ids) {
|
void ParseQuantizationData() {
|
||||||
// REMOVE < DRACO_BITSTREAM_VERSION(2, 0)
|
num_components = GetNumComponents();
|
||||||
// DecodeQuantizedDataInfo()
|
for (j = 0; j < num_components; ++j) {
|
||||||
num_components = attribute()->components_count();
|
quantized_data_min_values[curr_att_dec][curr_att][i] Float
|
||||||
for (i = 0; i < num_components; ++i) {
|
|
||||||
min_value_[i] F32
|
|
||||||
}
|
}
|
||||||
max_value_dif_ F32
|
quantized_data_max_value_df[curr_att_dec][curr_att] Float
|
||||||
quantization_bits_ UI8
|
ParseQuantizationBits();
|
||||||
// REMOVE < DRACO_BITSTREAM_VERSION(2, 0)
|
|
||||||
SequentialIntegerAttributeDecoder::DecodeIntegerValues()
|
|
||||||
}
|
}
|
||||||
~~~~~
|
~~~~~
|
||||||
{:.draco-syntax }
|
{:.draco-syntax }
|
||||||
|
|
||||||
|
|
||||||
### DequantizeValues()
|
### DequantizeFloat()
|
||||||
|
|
||||||
~~~~~
|
~~~~~
|
||||||
DequantizeValues(num_values) {
|
float DequantizeFloat(val, max_quantized_value_factor_, range_) {
|
||||||
max_quantized_value = (1 << (quantization_bits_)) - 1;
|
neg = (val < 0);
|
||||||
num_components = attribute()->components_count();
|
if (neg) {
|
||||||
entry_size = sizeof(float) * num_components;
|
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;
|
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 (i = 0; i < num_values; ++i) {
|
||||||
for (c = 0; c < num_components; ++c) {
|
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];
|
value = value + min_value_[c];
|
||||||
att_val[c] = value;
|
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 }
|
{:.draco-syntax }
|
||||||
|
@ -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 }
|
|
87
docs/spec/vector.md
Normal file
87
docs/spec/vector.md
Normal file
@ -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}
|
Loading…
x
Reference in New Issue
Block a user