mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-06-21 05:03:23 +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
|
||||
|
||||
### DecodeAttributesDecoderData()
|
||||
### ParseAttributeDecodersData()
|
||||
|
||||
~~~~~
|
||||
DecodeAttributesDecoderData(buffer) {
|
||||
num_attributes varUI32
|
||||
point_attribute_ids_.resize(num_attributes);
|
||||
for (i = 0; i < num_attributes; ++i) {
|
||||
att_type UI8
|
||||
data_type UI8
|
||||
components_count UI8
|
||||
normalized UI8
|
||||
custom_id UI16
|
||||
Initialize GeometryAttribute ga
|
||||
att_id = pc->AddAttribute(new PointAttribute(ga));
|
||||
point_attribute_ids_[i] = att_id;
|
||||
void ParseAttributeDecodersData() {
|
||||
num_attributes_decoders UI8
|
||||
if (encoder_method == MESH_EDGEBREAKER_ENCODING) {
|
||||
for (i = 0; i < num_attributes_decoders; ++i) {
|
||||
att_dec_data_id[i] UI8
|
||||
att_dec_decoder_type[i] UI8
|
||||
att_dec_traversal_method[i] UI8
|
||||
}
|
||||
}
|
||||
for (i = 0; i < num_attributes_decoders; ++i) {
|
||||
att_dec_num_attributes[i] varUI32
|
||||
for (j = 0; j < att_dec_num_attributes[i]; ++j) {
|
||||
att_dec_att_type[i][j] UI8
|
||||
att_dec_data_type[i][j] UI8
|
||||
att_dec_num_components[i][j] UI8
|
||||
att_dec_normalized[i][j] UI8
|
||||
att_dec_unique_id[i][j] varUI32
|
||||
}
|
||||
for (j = 0; j < att_dec_num_attributes[i]; ++j) {
|
||||
seq_att_dec_decoder_type[i][j] UI8
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeAttributeData()
|
||||
|
||||
~~~~~
|
||||
void DecodeAttributeData() {
|
||||
ParseAttributeDecodersData();
|
||||
vertex_visited_point_ids.assign(num_attributes_decoders, 0);
|
||||
curr_att_dec = 0;
|
||||
if (encoder_method == MESH_EDGEBREAKER_ENCODING) {
|
||||
DecodeAttributeSeams();
|
||||
for (i = 0; i < num_encoded_vertices + eb_num_split_symbols; ++i) {
|
||||
if (is_vert_hole_[i]) {
|
||||
UpdateVertexToCornerMap(i);
|
||||
}
|
||||
}
|
||||
for (i = 1; i < num_attributes_decoders; ++i) {
|
||||
curr_att_dec = i;
|
||||
RecomputeVerticesInternal();
|
||||
}
|
||||
Attribute_AssignPointsToCorners();
|
||||
}
|
||||
ß
|
||||
for (i = 0; i < num_attributes_decoders; ++i) {
|
||||
curr_att_dec = i;
|
||||
is_face_visited_.assign(num_faces, false);
|
||||
is_vertex_visited_.assign(num_faces * 3, false);
|
||||
GenerateSequence();
|
||||
if (encoder_method == MESH_EDGEBREAKER_ENCODING) {
|
||||
UpdatePointToAttributeIndexMapping();
|
||||
}
|
||||
}
|
||||
for (i = 0; i < num_attributes_decoders; ++i) {
|
||||
for (j = 0; j < att_dec_num_attributes[i]; ++j) {
|
||||
att_dec_num_values_to_decode[i][j] =
|
||||
encoded_attribute_value_index_to_corner_map[i].size();
|
||||
}
|
||||
}
|
||||
for (i = 0; i < num_attributes_decoders; ++i) {
|
||||
curr_att_dec = i;
|
||||
DecodePortableAttributes();
|
||||
DecodeDataNeededByPortableTransforms();
|
||||
TransformAttributesToOriginalFormat();
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### RecomputeVerticesInternal()
|
||||
|
||||
~~~~~
|
||||
void RecomputeVerticesInternal() {
|
||||
attr = curr_att_dec - 1;
|
||||
num_new_vertices = 0;
|
||||
attr_face_to_vertex.push_back(face_to_vertex);
|
||||
corner_to_vertex_map_[curr_att_dec].assign(
|
||||
attr_face_to_vertex[attr][0].size() * 3, -1);
|
||||
for (v = 0; v < num_encoded_vertices + eb_num_split_symbols; ++v) {
|
||||
c = vertex_corners_[v];
|
||||
if (c < 0)
|
||||
continue;
|
||||
first_vert_id(num_new_vertices++);
|
||||
first_c = c;
|
||||
if (IsVertexOnAttributeSeam(attr, v)) {
|
||||
act_c = SwingLeft(curr_att_dec, first_c);
|
||||
while (act_c >= 0) {
|
||||
first_c = act_c;
|
||||
act_c = SwingLeft(curr_att_dec, act_c);
|
||||
}
|
||||
}
|
||||
corner_to_vertex_map_[curr_att_dec][first_c] = first_vert_id;
|
||||
vertex_to_left_most_corner_map_[attr].push_back(first_c);
|
||||
act_c = SwingRight(0, first_c);
|
||||
while (act_c >= 0 && act_c != first_c) {
|
||||
next_act_c = Next(act_c);
|
||||
if (IsCornerOppositeToSeamEdge(next_act_c)) {
|
||||
first_vert_id = num_new_vertices++;
|
||||
vertex_to_left_most_corner_map_[attr].push_back(act_c);
|
||||
}
|
||||
corner_to_vertex_map_[curr_att_dec][act_c] = first_vert_id;
|
||||
act_c = SwingRight(0, act_c);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < corner_to_vertex_map_[curr_att_dec].size(); i += 3) {
|
||||
face = i / 3;
|
||||
attr_face_to_vertex[attr][0][face] = corner_to_vertex_map_[curr_att_dec][i];
|
||||
attr_face_to_vertex[attr][1][face] = corner_to_vertex_map_[curr_att_dec][i + 1];
|
||||
attr_face_to_vertex[attr][2][face] = corner_to_vertex_map_[curr_att_dec][i + 2];
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### Attribute_AssignPointsToCorners()
|
||||
|
||||
~~~~~
|
||||
void Attribute_AssignPointsToCorners() {
|
||||
num_corners = face_to_vertex[0].size() * 3;
|
||||
for (v = 0; v < num_encoded_vertices + eb_num_split_symbols; ++v) {
|
||||
c = vertex_corners_[v];
|
||||
if (c < 0)
|
||||
continue;
|
||||
deduplication_first_corner = c;
|
||||
if (is_vert_hole_[v]) {
|
||||
deduplication_first_corner = c;
|
||||
} else {
|
||||
for (i = 1; i < num_attributes_decoders; ++i) {
|
||||
attr_id = i - 1;
|
||||
if (!IsCornerOnAttributeSeam(0, attr_id, c))
|
||||
continue;
|
||||
vert_id = corner_to_vertex_map_[i][c];
|
||||
act_c = SwingRight(0, c);
|
||||
seam_found = false;
|
||||
while (act_c != c) {
|
||||
act_vert_id = corner_to_vertex_map_[i][act_c];
|
||||
if (act_vert_id != vert_id) {
|
||||
deduplication_first_corner = act_c;
|
||||
seam_found = true;
|
||||
break;
|
||||
}
|
||||
act_c = SwingRight(0, act_c);
|
||||
}
|
||||
if (seam_found)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c = deduplication_first_corner;
|
||||
corner_to_point_map[c] = point_to_corner_map.size();
|
||||
point_to_corner_map.push_back(c);
|
||||
prev_c = c;
|
||||
c = SwingRight(0, c);
|
||||
while (c >= 0 && c != deduplication_first_corner) {
|
||||
attribute_seam = false;
|
||||
for (i = 1; i < num_attributes_decoders; ++i) {
|
||||
vert_id = corner_to_vertex_map_[i][c];
|
||||
prev_vert_id = corner_to_vertex_map_[i][prev_c];
|
||||
if (vert_id != prev_vert_id) {
|
||||
attribute_seam = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (attribute_seam) {
|
||||
corner_to_point_map[c] = point_to_corner_map.size();
|
||||
point_to_corner_map.push_back(c);
|
||||
} else {
|
||||
corner_to_point_map[c] = corner_to_point_map[prev_c];
|
||||
}
|
||||
prev_c = c;
|
||||
c = SwingRight(0, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### SequentialGenerateSequence()
|
||||
|
||||
~~~~~
|
||||
void SequentialGenerateSequence() {
|
||||
for (i = 0; i < num_points; ++i) {
|
||||
encoded_attribute_value_index_to_corner_map[curr_att_dec][i] = i;
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### EdgebreakerGenerateSequence()
|
||||
|
||||
~~~~~
|
||||
void EdgebreakerGenerateSequence() {
|
||||
if (att_dec_traversal_method[curr_att_dec] == MESH_TRAVERSAL_PREDICTION_DEGREE) {
|
||||
prediction_degree_.assign(num_encoded_vertices + eb_num_split_symbols, 0);
|
||||
}
|
||||
for (i = 0; i < num_faces; ++i) {
|
||||
if (att_dec_traversal_method[curr_att_dec] == MESH_TRAVERSAL_DEPTH_FIRST) {
|
||||
if (curr_att_dec == 0) {
|
||||
EdgeBreakerTraverser_ProcessCorner(3 * i);
|
||||
} else {
|
||||
EdgeBreakerAttributeTraverser_ProcessCorner(3 * i);
|
||||
}
|
||||
} else {
|
||||
PredictionDegree_TraverseFromCorner(3 * i);
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### GenerateSequence()
|
||||
|
||||
~~~~~
|
||||
void GenerateSequence() {
|
||||
if (encoder_method == MESH_EDGEBREAKER_ENCODING)
|
||||
EdgebreakerGenerateSequence();
|
||||
else
|
||||
SequentialGenerateSequence();
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### UpdatePointToAttributeIndexMapping()
|
||||
|
||||
~~~~~
|
||||
void UpdatePointToAttributeIndexMapping() {
|
||||
indices_map_.assign(num_faces * 3, -1);
|
||||
for (f = 0; f < num_faces; ++f) {
|
||||
for (p = 0; p < 3; ++p) {
|
||||
corner = (f * 3) + p;
|
||||
point_id = corner_to_point_map[corner];
|
||||
CornerToVerts(curr_att_dec, corner, &vert, &next, &prev);
|
||||
att_entry_id =
|
||||
vertex_to_encoded_attribute_value_index_map[curr_att_dec][vert];
|
||||
indices_map_[point_id] = att_entry_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### TransformAttributesToOriginalFormat_StoreValues()
|
||||
|
||||
~~~~~
|
||||
void TransformAttributesToOriginalFormat_StoreValues() {
|
||||
num_components = GetNumComponents();
|
||||
num_values = att_dec_num_values_to_decode[curr_att_dec][curr_att];
|
||||
portable_attribute_data = seq_int_att_dec_original_values[curr_att_dec][curr_att];
|
||||
for (i = 0; i < num_values; ++i) {
|
||||
for (c = 0; c < num_components; ++c) {
|
||||
out_values.push_back(portable_attribute_data[(i * num_components) + c]);
|
||||
}
|
||||
}
|
||||
seq_int_att_dec_dequantized_values[curr_att_dec][curr_att] = out_values;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### TransformAttributesToOriginalFormat()
|
||||
|
||||
~~~~~
|
||||
void TransformAttributesToOriginalFormat() {
|
||||
for (i = 0; i < att_dec_num_attributes.back(); ++i) {
|
||||
curr_att = i;
|
||||
dec_type = seq_att_dec_decoder_type[curr_att_dec][curr_att];
|
||||
if (dec_type == SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS) {
|
||||
TransformAttributesToOriginalFormat_Normal();
|
||||
} else if (dec_type == SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGER) {
|
||||
TransformAttributesToOriginalFormat_StoreValues();
|
||||
} else {
|
||||
SequentialQuantizationAttributeDecoder_DequantizeValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
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
|
||||
|
||||
### DecodeVarint<IT>
|
||||
### DecodeVarint
|
||||
|
||||
~~~~~
|
||||
DecodeVarint<IT>() {
|
||||
If (std::is_unsigned<IT>::value) {
|
||||
void DecodeVarint(out_val) {
|
||||
in UI8
|
||||
If (in & (1 << 7)) {
|
||||
out = DecodeVarint<IT>()
|
||||
out = (out << 7) | (in & ((1 << 7) - 1))
|
||||
if (in & (1 << 7)) {
|
||||
DecodeVarint(out_val);
|
||||
out_val = (out_val << 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 {
|
||||
signed_val = -abs_val - 1
|
||||
}
|
||||
return signed_val
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
Sequential Decoder
|
||||
|
||||
FIXME: ^^^ Heading level?
|
||||
|
||||
### decode_connectivity()
|
||||
|
||||
~~~~~
|
||||
decode_connectivity() {
|
||||
num_faces I32
|
||||
num_points I32
|
||||
connectivity _method UI8
|
||||
If (connectivity _method == 0) {
|
||||
// TODO
|
||||
} else {
|
||||
loop num_faces {
|
||||
If (num_points < 256) {
|
||||
face[] UI8
|
||||
} else if (num_points < (1 << 16)) {
|
||||
face[] UI16
|
||||
} else {
|
||||
face[] UI32
|
||||
}
|
||||
}
|
||||
out_val = in;
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
|
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() {
|
||||
DecodeHeader()
|
||||
void Decode() {
|
||||
ParseHeader();
|
||||
if (flags & METADATA_FLAG_MASK)
|
||||
DecodeGeometryMetadata(metadata)
|
||||
DecodeConnectivityData()
|
||||
DecodeAttributeData()
|
||||
DecodeMetadata();
|
||||
DecodeConnectivityData();
|
||||
DecodeAttributeData();
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
||||
|
||||
### DecodeHeader()
|
||||
### ParseHeader()
|
||||
|
||||
~~~~~
|
||||
DecodeHeader() {
|
||||
ParseHeader() {
|
||||
draco_string UI8[5]
|
||||
major_version UI8
|
||||
minor_version UI8
|
||||
encoder_type UI8
|
||||
encoder_method UI8
|
||||
flags
|
||||
flags UI16
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
||||
|
||||
### DecodeAttributeData()
|
||||
|
||||
~~~~~
|
||||
DecodeAttributeData() {
|
||||
num_attributes_decoders UI8
|
||||
for (i = 0; i < num_attributes_decoders; ++i) {
|
||||
CreateAttributesDecoder(i);
|
||||
}
|
||||
for (auto &att_dec : attributes_decoders_) {
|
||||
att_dec->Initialize(this, point_cloud_)
|
||||
}
|
||||
for (i = 0; i < num_attributes_decoders; ++i) {
|
||||
attributes_decoders_[i]->DecodeAttributesDecoderData(buffer_)
|
||||
}
|
||||
DecodeAllAttributes()
|
||||
OnAttributesDecoded()
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
@ -1,299 +1,80 @@
|
||||
## EdgeBreaker Decoder
|
||||
|
||||
### DecodeConnectivityData()
|
||||
### ParseEdgebreakerConnectivityData()
|
||||
|
||||
~~~~~
|
||||
DecodeConnectivityData() {
|
||||
void ParseEdgebreakerConnectivityData() {
|
||||
edgebreaker_traversal_type UI8
|
||||
num_new_verts varUI32
|
||||
num_new_vertices varUI32
|
||||
num_encoded_vertices varUI32
|
||||
num_faces varUI32
|
||||
num_attribute_data I8
|
||||
num_encoded_symbols varUI32
|
||||
num_encoded_split_symbols varUI32
|
||||
encoded_connectivity_size varUI32
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### ParseTopologySplitEvents()
|
||||
|
||||
~~~~~
|
||||
void ParseTopologySplitEvents() {
|
||||
num_topologoy_splits varUI32
|
||||
for (i = 0; i < num_topologoy_splits; ++i) {
|
||||
source_id_delta[i] varUI32
|
||||
split_id_delta[i] varUI32
|
||||
}
|
||||
for (i = 0; i < num_topologoy_splits; ++i) {
|
||||
split_edge_bit[i] f[1]
|
||||
source_edge_bit[i] f[1]
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeEdgebreakerConnectivityData()
|
||||
|
||||
~~~~~
|
||||
void DecodeEdgebreakerConnectivityData() {
|
||||
ParseEdgebreakerConnectivityData();
|
||||
|
||||
// file pointer must be set to current position
|
||||
// + encoded_connectivity_size
|
||||
hole_and_split_bytes = DecodeHoleAndTopologySplitEvents()
|
||||
DecodeTopologySplitEvents();
|
||||
|
||||
// file pointer must be saved, as it points to the attribute data
|
||||
// file pointer must be set to old current position
|
||||
EdgeBreakerTraversalValence_Start(num_encoded_vertices)
|
||||
DecodeConnectivity(num_symbols)
|
||||
if (attribute_data_.size() > 0) {
|
||||
for (ci = 0; ci < corner_table_->num_corners(); ci += 3) {
|
||||
DecodeAttributeConnectivitiesOnFace(ci)
|
||||
}
|
||||
}
|
||||
for (i = 0; i < corner_table_->num_vertices(); ++i) {
|
||||
if (is_vert_hole_[i]) {
|
||||
corner_table_->UpdateVertexToCornerMap(i);
|
||||
}
|
||||
}
|
||||
// Decode attribute connectivity.
|
||||
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
|
||||
attribute_data_[i].connectivity_data.InitEmpty(corner_table_);
|
||||
for (int32_t c : attribute_data_[i].attribute_seam_corners) {
|
||||
attribute_data_[i].connectivity_data.AddSeamEdge(c);
|
||||
}
|
||||
attribute_data_[i].connectivity_data.RecomputeVertices(nullptr,
|
||||
nullptr);
|
||||
}
|
||||
// Preallocate vertex to value mapping
|
||||
AssignPointsToCorners()
|
||||
EdgebreakerTraversalStart();
|
||||
DecodeEdgeBreakerConnectivity();
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### AssignPointsToCorners()
|
||||
### ProcessSplitData()
|
||||
|
||||
~~~~~
|
||||
AssignPointsToCorners() {
|
||||
decoder_->mesh()->SetNumFaces(corner_table_->num_faces());
|
||||
if (attribute_data_.size() == 0) {
|
||||
for (f = 0; f < decoder_->mesh()->num_faces(); ++f) {
|
||||
for (c = 0; c < 3; ++c) {
|
||||
vert_id = corner_table_->Vertex(3 * f + c);
|
||||
if (point_id == -1)
|
||||
point_id = num_points++;
|
||||
face[c] = point_id;
|
||||
}
|
||||
decoder_->mesh()->SetFace(f, face);
|
||||
}
|
||||
decoder_->point_cloud()->set_num_points(num_points);
|
||||
Return true;
|
||||
}
|
||||
for (v = 0; v < corner_table_->num_vertices(); ++v) {
|
||||
c = corner_table_->LeftMostCorner(v);
|
||||
if (c < 0)
|
||||
continue;
|
||||
deduplication_first_corner = c;
|
||||
if (!is_vert_hole_[v]) {
|
||||
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
|
||||
if (!attribute_data_[i].connectivity_data.IsCornerOnSeam(c))
|
||||
continue;
|
||||
vert_id = attribute_data_[i].connectivity_data.Vertex(c);
|
||||
act_c = corner_table_->SwingRight(c);
|
||||
seam_found = false;
|
||||
while (act_c != c) {
|
||||
if (attribute_data_[i].connectivity_data.Vertex(act_c) !=
|
||||
vert_id) {
|
||||
deduplication_first_corner = act_c;
|
||||
seam_found = true;
|
||||
break;
|
||||
}
|
||||
act_c = corner_table_->SwingRight(act_c);
|
||||
}
|
||||
if (seam_found)
|
||||
break;
|
||||
}
|
||||
}
|
||||
c = deduplication_first_corner;
|
||||
corner_to_point_map[c] = point_to_corner_map.size();
|
||||
point_to_corner_map.push_back(c);
|
||||
prev_c = c;
|
||||
c = corner_table_->SwingRight(c);
|
||||
while (c >= 0 && c != deduplication_first_corner) {
|
||||
attribute_seam = false;
|
||||
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
|
||||
if (attribute_data_[i].connectivity_data.Vertex(c) !=
|
||||
attribute_data_[i].connectivity_data.Vertex(prev_c)) {
|
||||
attribute_seam = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (attribute_seam) {
|
||||
corner_to_point_map[c] = point_to_corner_map.size();
|
||||
point_to_corner_map.push_back(c);
|
||||
} else {
|
||||
corner_to_point_map[c] = corner_to_point_map[prev_c];
|
||||
}
|
||||
prev_c = c;
|
||||
c = corner_table_->SwingRight(c);
|
||||
}
|
||||
}
|
||||
for (f = 0; f < decoder_->mesh()->num_faces(); ++f) {
|
||||
for (c = 0; c < 3; ++c) {
|
||||
face[c] = corner_to_point_map[3 * f + c];
|
||||
}
|
||||
decoder_->mesh()->SetFace(f, face);
|
||||
}
|
||||
decoder_->point_cloud()->set_num_points(point_to_corner_map.size());
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeConnectivity()
|
||||
|
||||
~~~~~
|
||||
DecodeConnectivity(num_symbols) {
|
||||
for (i = 0; i < num_symbols; ++i) {
|
||||
symbol = TraversalValence_DecodeSymbol()
|
||||
corner = 3 * num_faces++
|
||||
if (symbol == TOPOLOGY_C) {
|
||||
vertex_x = UpdateCornerTableForSymbolC()
|
||||
is_vert_hole_[vertex_x] = false;
|
||||
} else if (symbol == TOPOLOGY_R || symbol == TOPOLOGY_L) {
|
||||
UpdateCornerTableForSymbolLR()
|
||||
check_topology_split = true;
|
||||
} else if (symbol == TOPOLOGY_S) {
|
||||
HandleSymbolS()
|
||||
} else if (symbol == TOPOLOGY_E) {
|
||||
UpdateCornerTableForSymbolE()
|
||||
check_topology_split = true;
|
||||
}
|
||||
active_corner_stack.back() = corner;
|
||||
traversal_decoder_.NewActiveCornerReached(corner);
|
||||
if (check_topology_split) {
|
||||
encoder_symbol_id = num_symbols - symbol_id - 1;
|
||||
while (true) {
|
||||
split = IsTopologySplit(encoder_symbol_id, &split_edge,
|
||||
&encoder_split_symbol_id);
|
||||
if (!split) {
|
||||
break;
|
||||
}
|
||||
act_top_corner = corner;
|
||||
if (split_edge == RIGHT_FACE_EDGE) {
|
||||
new_active_corner = corner_table_->Next(act_top_corner);
|
||||
} else {
|
||||
new_active_corner = corner_table_->Previous(act_top_corner);
|
||||
}
|
||||
decoder_split_symbol_id = num_symbols -
|
||||
encoder_split_symbol_id - 1;
|
||||
topology_split_active_corners[decoder_split_symbol_id] =
|
||||
new_active_corner;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (active_corner_stack.size() > 0) {
|
||||
corner = active_corner_stack.pop_back();
|
||||
interior_face = traversal_decoder_.DecodeStartFaceConfiguration();
|
||||
if (interior_face == true) {
|
||||
UpdateCornerTableForInteriorFace()
|
||||
for (ci = 0; ci < 3; ++ci) {
|
||||
is_vert_hole_[corner_table_->Vertex(new_corner + ci)] = false;
|
||||
}
|
||||
init_face_configurations_.push_back(true);
|
||||
init_corners_.push_back(new_corner);
|
||||
} else {
|
||||
init_face_configurations_.push_back(false);
|
||||
init_corners_.push_back(corner);
|
||||
}
|
||||
void ProcessSplitData() {
|
||||
last_id = 0;
|
||||
for (i = 0; i < source_id_delta.size(); ++i) {
|
||||
source_symbol_id[i] = source_id_delta[i] + last_id;
|
||||
split_symbol_id.[i] = source_symbol_id[i] - split_id_delta[i];
|
||||
last_id = source_symbol_id[i];
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### UpdateCornerTableForSymbolC()
|
||||
### DecodeTopologySplitEvents()
|
||||
|
||||
~~~~~
|
||||
UpdateCornerTableForSymbolC(corner) {
|
||||
corner_a = active_corner_stack.back();
|
||||
corner_b = corner_table_->Previous(corner_a);
|
||||
while (corner_table_->Opposite(corner_b) >= 0) {
|
||||
corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b));
|
||||
}
|
||||
SetOppositeCorners(corner_a, corner + 1);
|
||||
SetOppositeCorners(corner_b, corner + 2);
|
||||
vertex_x = corner_table_->Vertex(corner_table_->Next(corner_a));
|
||||
corner_table_->MapCornerToVertex(corner, vertex_x);
|
||||
corner_table_->MapCornerToVertex(
|
||||
corner + 1, corner_table_->Vertex(corner_table_->Next(corner_b)));
|
||||
corner_table_->MapCornerToVertex(
|
||||
corner + 2, corner_table_->Vertex(corner_table_->Previous(corner_a)));
|
||||
return vertex_x;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
|
||||
### UpdateCornerTableForSymbolLR()
|
||||
|
||||
~~~~~
|
||||
UpdateCornerTableForSymbolLR(corner, symbol) {
|
||||
if (symbol == TOPOLOGY_R) {
|
||||
opp_corner = corner + 2;
|
||||
} else {
|
||||
opp_corner = corner + 1;
|
||||
}
|
||||
SetOppositeCorners(opp_corner, corner_a);
|
||||
corner_table_->MapCornerToVertex(opp_corner,num_vertices++);
|
||||
corner_table_->MapCornerToVertex(
|
||||
corner_table_->Next(opp_corner),
|
||||
corner_table_->Vertex(corner_table_->Previous(corner_a)));
|
||||
corner_table_->MapCornerToVertex(
|
||||
corner_table_->Previous(opp_corner),
|
||||
corner_table_->Vertex(corner_table_->Next(corner_a)));
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### HandleSymbolS()
|
||||
|
||||
~~~~~
|
||||
HandleSymbolS(corner) {
|
||||
corner_b = active_corner_stack.pop_back();
|
||||
it = topology_split_active_corners.find(symbol_id);
|
||||
if (it != topology_split_active_corners.end()) {
|
||||
active_corner_stack.push_back(it->second);
|
||||
}
|
||||
corner_a = active_corner_stack.back();
|
||||
SetOppositeCorners(corner_a, corner + 2);
|
||||
SetOppositeCorners(corner_b, corner + 1);
|
||||
vertex_p = corner_table_->Vertex(corner_table_->Previous(corner_a));
|
||||
corner_table_->MapCornerToVertex(corner, vertex_p);
|
||||
corner_table_->MapCornerToVertex(
|
||||
corner + 1, corner_table_->Vertex(corner_table_->Next(corner_a)));
|
||||
corner_table_->MapCornerToVertex(corner + 2,
|
||||
corner_table_->Vertex(corner_table_->Previous(corner_b)));
|
||||
corner_n = corner_table_->Next(corner_b);
|
||||
vertex_n = corner_table_->Vertex(corner_n);
|
||||
traversal_decoder_.MergeVertices(vertex_p, vertex_n);
|
||||
// TraversalValence_MergeVertices
|
||||
while (corner_n >= 0) {
|
||||
corner_table_->MapCornerToVertex(corner_n, vertex_p);
|
||||
corner_n = corner_table_->SwingLeft(corner_n);
|
||||
}
|
||||
corner_table_->MakeVertexIsolated(vertex_n);
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### UpdateCornerTableForSymbolE()
|
||||
|
||||
~~~~~
|
||||
UpdateCornerTableForSymbolE() {
|
||||
corner_table_->MapCornerToVertex(corner, num_vertices++);
|
||||
corner_table_->MapCornerToVertex(corner + 1, num_vertices++);
|
||||
corner_table_->MapCornerToVertex(corner + 2, num_vertices++);
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### UpdateCornerTableForInteriorFace()
|
||||
|
||||
~~~~~
|
||||
UpdateCornerTableForInteriorFace() {
|
||||
corner_b = corner_table_->Previous(corner);
|
||||
while (corner_table_->Opposite(corner_b) >= 0) {
|
||||
corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b));
|
||||
}
|
||||
corner_c = corner_table_->Next(corner);
|
||||
while (corner_table_->Opposite(corner_c) >= 0) {
|
||||
corner_c = corner_table_->Next(corner_table_->Opposite(corner_c));
|
||||
}
|
||||
face(num_faces++);
|
||||
corner_table_->MapCornerToVertex(
|
||||
new_corner, corner_table_->Vertex(corner_table_->Next(corner_b)));
|
||||
corner_table_->MapCornerToVertex(
|
||||
new_corner + 1, corner_table_->Vertex(corner_table_->Next(corner_c)));
|
||||
corner_table_->MapCornerToVertex(
|
||||
new_corner + 2, corner_table_->Vertex(corner_table_->Next(corner)));
|
||||
void DecodeTopologySplitEvents() {
|
||||
ParseTopologySplitEvents();
|
||||
ProcessSplitData();
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
@ -302,41 +83,32 @@ UpdateCornerTableForInteriorFace() {
|
||||
### IsTopologySplit()
|
||||
|
||||
~~~~~
|
||||
IsTopologySplit(encoder_symbol_id, *out_face_edge,
|
||||
*out_encoder_split_symbol_id) {
|
||||
if (topology_split_data_.size() == 0)
|
||||
bool IsTopologySplit(encoder_symbol_id, out_face_edge,
|
||||
out_encoder_split_symbol_id) {
|
||||
if (source_symbol_id.back() != encoder_symbol_id)
|
||||
return false;
|
||||
if (topology_split_data_.back().source_symbol_id != encoder_symbol_id)
|
||||
return false;
|
||||
*out_face_edge = topology_split_data_.back().source_edge;
|
||||
*out_encoder_split_symbol_id =
|
||||
topology_split_data_.back().split_symbol_id;
|
||||
topology_split_data_.pop_back();
|
||||
*out_face_edge = source_edge_bit.pop();
|
||||
*out_encoder_split_symbol_id = split_symbol_id.pop();
|
||||
source_symbol_id.pop();
|
||||
return true;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeAttributeConnectivitiesOnFace()
|
||||
### ReplaceVerts()
|
||||
|
||||
~~~~~
|
||||
DecodeAttributeConnectivitiesOnFace(corner) {
|
||||
corners[3] = {corner, corner_table_->Next(corner),
|
||||
corner_table_->Previous(corner)}
|
||||
for (c = 0; c < 3; ++c) {
|
||||
opp_corner = corner_table_->Opposite(corners[c]);
|
||||
if (opp_corner < 0) {
|
||||
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
|
||||
attribute_data_[i].attribute_seam_corners.push_back(corners[c]);
|
||||
void ReplaceVerts(from, to) {
|
||||
for (i = 0; i < face_to_vertex[0].size(); ++i) {
|
||||
if (face_to_vertex[0][i] == from) {
|
||||
face_to_vertex[0][i] = to;
|
||||
}
|
||||
continue
|
||||
}
|
||||
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
|
||||
bool is_seam = traversal_decoder_.DecodeAttributeSeam(i);
|
||||
if (is_seam) {
|
||||
attribute_data_[i].attribute_seam_corners.push_back(corners[c]);
|
||||
if (face_to_vertex[1][i] == from) {
|
||||
face_to_vertex[1][i] = to;
|
||||
}
|
||||
if (face_to_vertex[2][i] == from) {
|
||||
face_to_vertex[2][i] = to;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -344,12 +116,238 @@ DecodeAttributeConnectivitiesOnFace(corner) {
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### SetOppositeCorners()
|
||||
### UpdateCornersAfterMerge()
|
||||
|
||||
~~~~~
|
||||
SetOppositeCorners(corner_0, corner_1) {
|
||||
corner_table_->SetOppositeCorner(corner_0, corner_1);
|
||||
corner_table_->SetOppositeCorner(corner_1, corner_0);
|
||||
void UpdateCornersAfterMerge(c, v) {
|
||||
opp_corner = PosOpposite(c);
|
||||
if (opp_corner >= 0) {
|
||||
corner_n = Next(opp_corner);
|
||||
while (corner_n >= 0) {
|
||||
MapCornerToVertex(corner_n, v);
|
||||
corner_n = SwingLeft(0, corner_n);
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### NewActiveCornerReached()
|
||||
|
||||
~~~~~
|
||||
void NewActiveCornerReached(new_corner, symbol_id) {
|
||||
check_topology_split = false;
|
||||
switch (last_symbol_) {
|
||||
case TOPOLOGY_C:
|
||||
{
|
||||
corner_a = active_corner_stack.back();
|
||||
corner_b = Previous(corner_a);
|
||||
while (PosOpposite(corner_b) >= 0) {
|
||||
b_opp = PosOpposite(corner_b);
|
||||
corner_b = Previous(b_opp);
|
||||
}
|
||||
SetOppositeCorners(corner_a, new_corner + 1);
|
||||
SetOppositeCorners(corner_b, new_corner + 2);
|
||||
active_corner_stack.back() = new_corner;
|
||||
}
|
||||
vert = CornerToVert(Next(corner_a));
|
||||
next = CornerToVert(Next(corner_b));
|
||||
prev = CornerToVert(Previous(corner_a));
|
||||
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
|
||||
vertex_valences_[next] += 1;
|
||||
vertex_valences_[prev] += 1;
|
||||
}
|
||||
face_to_vertex[0].push_back(vert);
|
||||
face_to_vertex[1].push_back(next);
|
||||
face_to_vertex[2].push_back(prev);
|
||||
is_vert_hole_[vert] = false;
|
||||
MapCornerToVertex(new_corner, vert);
|
||||
MapCornerToVertex(new_corner + 1, next);
|
||||
MapCornerToVertex(new_corner + 2, prev);
|
||||
break;
|
||||
case TOPOLOGY_S:
|
||||
{
|
||||
corner_b = active_corner_stack.pop();
|
||||
for (i = 0; i < split_active_corners.size(); ++i) {
|
||||
if (split_active_corners[i].decoder_split_symbol_id == symbol_id) {
|
||||
active_corner_stack.push_back(split_active_corners[i].corner);
|
||||
}
|
||||
}
|
||||
corner_a = active_corner_stack.back();
|
||||
SetOppositeCorners(corner_a, new_corner + 2);
|
||||
SetOppositeCorners(corner_b, new_corner + 1);
|
||||
active_corner_stack.back() = new_corner;
|
||||
}
|
||||
|
||||
vert = CornerToVert(Previous(corner_a));
|
||||
next = CornerToVert(Next(corner_a));
|
||||
prev = CornerToVert(Previous(corner_b));
|
||||
MapCornerToVertex(new_corner, vert);
|
||||
MapCornerToVertex(new_corner + 1, next);
|
||||
MapCornerToVertex(new_corner + 2, prev);
|
||||
corner_n = Next(corner_b);
|
||||
vertex_n = CornerToVert(corner_n);
|
||||
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
|
||||
vertex_valences_[vert] += vertex_valences_[vertex_n];
|
||||
}
|
||||
ReplaceVerts(vertex_n, vert);
|
||||
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
|
||||
vertex_valences_[next] += 1;
|
||||
vertex_valences_[prev] += 1;
|
||||
}
|
||||
face_to_vertex[0].push_back(vert);
|
||||
face_to_vertex[1].push_back(next);
|
||||
face_to_vertex[2].push_back(prev);
|
||||
UpdateCornersAfterMerge(new_corner + 1, vert);
|
||||
vertex_corners_[vertex_n] = kInvalidCornerIndex;
|
||||
break;
|
||||
case TOPOLOGY_R:
|
||||
{
|
||||
corner_a = active_corner_stack.back();
|
||||
opp_corner = new_corner + 2;
|
||||
SetOppositeCorners(opp_corner, corner_a);
|
||||
active_corner_stack.back() = new_corner;
|
||||
}
|
||||
check_topology_split = true;
|
||||
vert = CornerToVert(Previous(corner_a));
|
||||
next = CornerToVert(Next(corner_a));
|
||||
prev = ++last_vert_added;
|
||||
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
|
||||
vertex_valences_[vert] += 1;
|
||||
vertex_valences_[next] += 1;
|
||||
vertex_valences_[prev] += 2;
|
||||
}
|
||||
|
||||
face_to_vertex[0].push_back(vert);
|
||||
face_to_vertex[1].push_back(next);
|
||||
face_to_vertex[2].push_back(prev);
|
||||
|
||||
MapCornerToVertex(new_corner + 2, prev);
|
||||
MapCornerToVertex(new_corner, vert);
|
||||
MapCornerToVertex(new_corner + 1, next);
|
||||
break;
|
||||
case TOPOLOGY_L:
|
||||
{
|
||||
corner_a = active_corner_stack.back();
|
||||
opp_corner = new_corner + 1;
|
||||
SetOppositeCorners(opp_corner, corner_a);
|
||||
active_corner_stack.back() = new_corner;
|
||||
}
|
||||
check_topology_split = true;
|
||||
vert = CornerToVert(Previous(corner_a));
|
||||
next = CornerToVert(Next(corner_a));
|
||||
prev = ++last_vert_added;
|
||||
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
|
||||
vertex_valences_[vert] += 1;
|
||||
vertex_valences_[next] += 1;
|
||||
vertex_valences_[prev] += 2;
|
||||
}
|
||||
|
||||
face_to_vertex[0].push_back(vert);
|
||||
face_to_vertex[1].push_back(next);
|
||||
face_to_vertex[2].push_back(prev);
|
||||
|
||||
MapCornerToVertex(new_corner + 2, prev);
|
||||
MapCornerToVertex(new_corner, vert);
|
||||
MapCornerToVertex(new_corner + 1, next);
|
||||
break;
|
||||
case TOPOLOGY_E:
|
||||
active_corner_stack.push_back(new_corner);
|
||||
check_topology_split = true;
|
||||
vert = last_vert_added + 1;
|
||||
next = vert + 1;
|
||||
prev = next + 1;
|
||||
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
|
||||
vertex_valences_[vert] += 2;
|
||||
vertex_valences_[next] += 2;
|
||||
vertex_valences_[prev] += 2;
|
||||
}
|
||||
face_to_vertex[0].push_back(vert);
|
||||
face_to_vertex[1].push_back(next);
|
||||
face_to_vertex[2].push_back(prev);
|
||||
last_vert_added = prev;
|
||||
MapCornerToVertex(new_corner, vert);
|
||||
MapCornerToVertex(new_corner + 1, next);
|
||||
MapCornerToVertex(new_corner + 2, prev);
|
||||
break;
|
||||
}
|
||||
|
||||
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
|
||||
// Compute the new context that is going to be used
|
||||
// to decode the next symbol.
|
||||
active_valence = vertex_valences_[next];
|
||||
if (active_valence < MIN_VALENCE) {
|
||||
clamped_valence = MIN_VALENCE;
|
||||
} else if (active_valence > MAX_VALENCE) {
|
||||
clamped_valence = MAX_VALENCE;
|
||||
} else {
|
||||
clamped_valence = active_valence;
|
||||
}
|
||||
active_context_ = (clamped_valence - MIN_VALENCE);
|
||||
}
|
||||
|
||||
if (check_topology_split) {
|
||||
encoder_symbol_id = num_encoded_symbols - symbol_id - 1;
|
||||
while (IsTopologySplit(encoder_symbol_id, &split_edge,
|
||||
&enc_split_id)) {
|
||||
act_top_corner = active_corner_stack.back();
|
||||
if (split_edge == RIGHT_FACE_EDGE) {
|
||||
new_active_corner = Next(act_top_corner);
|
||||
} else {
|
||||
new_active_corner = Previous(act_top_corner);
|
||||
}
|
||||
// Convert the encoder split symbol id to decoder symbol id.
|
||||
dec_split_id = num_encoded_symbols - enc_split_id - 1;
|
||||
topology_edge_list[dec_split_id] = new_active_corner;
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### ParseEdgebreakerStandardSymbol()
|
||||
|
||||
~~~~~
|
||||
void ParseEdgebreakerStandardSymbol() {
|
||||
bit_symbol_buffer.DecodeLeastSignificantBits32(1, &symbol);
|
||||
if (symbol != TOPOLOGY_C) {
|
||||
// Else decode two additional bits.
|
||||
bit_symbol_buffer.DecodeLeastSignificantBits32(2, &symbol_suffix);
|
||||
symbol |= (symbol_suffix << 1);
|
||||
}
|
||||
last_symbol_ = symbol;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### EdgebreakerDecodeSymbol()
|
||||
|
||||
~~~~~
|
||||
void EdgebreakerDecodeSymbol() {
|
||||
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
|
||||
EdgebreakerValenceDecodeSymbol(sym);
|
||||
} else {
|
||||
ParseEdgebreakerStandardSymbol(sym);
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeEdgeBreakerConnectivity()
|
||||
|
||||
~~~~~
|
||||
void DecodeEdgeBreakerConnectivity() {
|
||||
is_vert_hole_.assign(num_encoded_vertices + num_encoded_split_symbols, true);
|
||||
for (i = 0; i < num_encoded_symbols; ++i) {
|
||||
EdgebreakerDecodeSymbol();
|
||||
corner = 3 * i;
|
||||
NewActiveCornerReached(corner, i);
|
||||
}
|
||||
ProcessInteriorEdges();
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
@ -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
|
||||
title: Draco Bitstream Specification (Draft)
|
||||
version: Version 1,2
|
||||
version: Version 2,1
|
||||
version_date: Released 2017-xx-xx
|
||||
---
|
||||
|
||||
@ -15,7 +15,6 @@ version_date: Released 2017-xx-xx
|
||||
{% include_relative 00.00.02.authors.md %}
|
||||
{% include_relative 00.00.03.last.modified.md %}
|
||||
{% include_relative 00.00.04.abstract.md %}
|
||||
|
||||
{% include_relative 00.00.05.toc.md %}
|
||||
|
||||
{% include_relative 01.00.00.scope.md %}
|
||||
@ -24,28 +23,27 @@ version_date: Released 2017-xx-xx
|
||||
{% include_relative 04.00.00.conventions.md %}
|
||||
{% include_relative draco.decoder.md %}
|
||||
{% include_relative metadata.decoder.md %}
|
||||
{% include_relative mesh.decoder.md %}
|
||||
{% include_relative connectivity.decoder.md %}
|
||||
{% include_relative sequential.decoder.md %}
|
||||
{% include_relative edgebreaker.decoder.md %}
|
||||
{% include_relative edgebreaker.hole.and.topology.md %}
|
||||
{% include_relative edgebreaker.traversal.decoder.md %}
|
||||
{% include_relative edgebreaker.traversal.valence.decoder.md %}
|
||||
{% include_relative edgebreaker.traversal.md %}
|
||||
{% include_relative edgebreaker.traversal.valence.md %}
|
||||
{% include_relative edgebreaker.traversal.prediction.degree.md %}
|
||||
{% include_relative attributes.decoder.md %}
|
||||
{% include_relative sequential.attributes.decoders.controller.md %}
|
||||
{% include_relative sequential.attribute.decoder.md %}
|
||||
{% include_relative sequential.integer.attribute.decoder.md %}
|
||||
{% include_relative boundary.decoder.md %}
|
||||
{% include_relative prediction.decoder.md %}
|
||||
{% include_relative sequential.quantization.attribute.decoder.md %}
|
||||
{% include_relative prediction.scheme.transform.md %}
|
||||
{% include_relative prediction.scheme.wrap.transform.md %}
|
||||
{% include_relative mesh.prediction.scheme.parallelogram.md %}
|
||||
{% include_relative cornertable.traversal.processor.md %}
|
||||
{% include_relative mesh.attribute.indices.encoding.observer.md %}
|
||||
{% include_relative edgebreaker.traverser.md %}
|
||||
{% include_relative mesh.traversal.sequencer.md %}
|
||||
{% include_relative corner.table.md %}
|
||||
{% include_relative mesh.attribute.corner.table.md %}
|
||||
{% include_relative symbol.decoding.md %}
|
||||
{% include_relative sequential.normal.attribute.decoder.md %}
|
||||
{% include_relative prediction.texcoords.decoder.md %}
|
||||
{% include_relative prediction.normal.decoder.md %}
|
||||
{% include_relative prediction.normal.transform.md %}
|
||||
{% include_relative prediction.wrap.transform.md %}
|
||||
{% include_relative prediction.parallelogram.decoder.md %}
|
||||
{% include_relative prediction.multi.parallelogram.decoder.md %}
|
||||
{% include_relative rans.decoding.md %}
|
||||
{% include_relative rans.bit.decoder.md %}
|
||||
{% include_relative corner.md %}
|
||||
{% include_relative vector.md %}
|
||||
{% include_relative core.functions.md %}
|
||||
{% include_relative variable.descriptions.md %}
|
||||
|
||||
|
@ -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
|
||||
|
||||
### DecodeGeometryMetadata()
|
||||
|
||||
~~~~~
|
||||
DecodeGeometryMetadata(metadata) {
|
||||
num_att_metadata varUI32
|
||||
for (i = 0; i < num_att_metadata; ++i) {
|
||||
att_id varUI32
|
||||
att_metadata = new AttributeMetadata(att_id)
|
||||
DecodeMetadata(att_metadata)
|
||||
metadata.att_metadata.push_back(att_metadata)
|
||||
}
|
||||
DecodeMetadata(metadata)
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
||||
|
||||
### DecodeMetadata()
|
||||
|
||||
~~~~~
|
||||
DecodeMetadata(metadata) {
|
||||
num_entries varUI32
|
||||
for (i = 0; i < num_entries; ++i) {
|
||||
DecodeEntry(metadata)
|
||||
}
|
||||
num_sub_metadata varUI32
|
||||
for (i = 0; i < num_sub_metadata; ++i) {
|
||||
size UI8
|
||||
name size * UI8
|
||||
temp_metadata = new Metadata()
|
||||
DecodeMetadata(temp_metadata)
|
||||
metadata.sub_metadata[name] = temp_metadata
|
||||
void DecodeMetadata() {
|
||||
ParseMetedataCount();
|
||||
|
||||
for (i = 0; i < num_att_metadata; ++i) {
|
||||
ParseAttributeMetadataId(i);
|
||||
DecodeMetadataElement(att_metadata[i]);
|
||||
}
|
||||
DecodeMetadataElement(file_metadata);
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
||||
|
||||
### DecodeEntry()
|
||||
### ParseMetedataCount()
|
||||
|
||||
~~~~~
|
||||
DecodeEntry(metadata) {
|
||||
size UI8
|
||||
name size * UI8
|
||||
size varUI32
|
||||
value size * UI8
|
||||
metadata.entries.insert(name, value)
|
||||
void ParseMetedataCount() {
|
||||
num_att_metadata varUI32
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
||||
|
||||
### ParseAttributeMetadataId()
|
||||
|
||||
~~~~~
|
||||
void ParseAttributeMetadataId(index) {
|
||||
att_metadata_id[index] varUI32
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
||||
|
||||
### ParseMetadataElement()
|
||||
|
||||
~~~~~
|
||||
void ParseMetadataElement(metadata) {
|
||||
metadata.num_entries varUI32
|
||||
for (i = 0; i < metadata.num_entries; ++i) {
|
||||
metadata.name_size[i] UI8
|
||||
metadata.name[i] I8[size]
|
||||
metadata.value_size[i] UI8
|
||||
metadata.value[i] I8[size]
|
||||
}
|
||||
metadata.num_sub_metadata varUI32
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
||||
|
||||
### ParseSubMetadataName()
|
||||
|
||||
~~~~~
|
||||
void ParseSubMetadataName(metadata, index) {
|
||||
metadata.sub_metadata_name_size[index] UI8
|
||||
metadata.sub_metadata_name[index] I8[size]
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
||||
|
||||
### DecodeMetadataElement()
|
||||
|
||||
~~~~~
|
||||
void DecodeMetadataElement(metadata) {
|
||||
ParseMetadataElement(metadata);
|
||||
for (i = 0; i < metadata.num_sub_metadata; ++i) {
|
||||
ParseSubMetadataName(metadata, i);
|
||||
DecodeMetadataElement(metadata.sub_metadata[i]);
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax}
|
||||
|
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
|
||||
|
||||
### ans_read_init()
|
||||
### DecodeSymbols()
|
||||
|
||||
~~~~~
|
||||
ans_read_init(AnsDecoder ans, buf, int offset) {
|
||||
x = buf[offset - 1] >> 6
|
||||
If (x == 0) {
|
||||
ans->buf_offset = offset - 1;
|
||||
ans->state = buf[offset - 1] & 0x3F;
|
||||
} else if (x == 1) {
|
||||
ans->buf_offset = offset - 2;
|
||||
ans->state = mem_get_le16(buf + offset - 2) & 0x3FFF;
|
||||
} else if (x == 2) {
|
||||
ans->buf_offset = offset - 3;
|
||||
ans->state = mem_get_le24(buf + offset - 3) & 0x3FFFFF;
|
||||
} else if (x == 3) {
|
||||
// ERROR
|
||||
void DecodeSymbols(num_symbols, num_components, out_values) {
|
||||
scheme UI8
|
||||
if (scheme == 0) {
|
||||
DecodeTaggedSymbols(num_symbols, num_components, out_values);
|
||||
} else if (scheme == 1) {
|
||||
DecodeRawSymbols(num_symbols, out_values);
|
||||
}
|
||||
ans->state += l_base;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### int rabs_desc_read()
|
||||
### DecodeSymbols
|
||||
|
||||
~~~~~
|
||||
int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) {
|
||||
AnsP8 p = ans_p8_precision - p0;
|
||||
if (ans->state < l_base) {
|
||||
ans->state = ans->state * io_base + ans->buf[--ans->buf_offset];
|
||||
void ReadEncodedData(bytes_encoded, buffer) {
|
||||
bytes_encoded varUI64
|
||||
buffer UI8[size]
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### ComputeRAnsUnclampedPrecision
|
||||
|
||||
~~~~~
|
||||
int ComputeRAnsUnclampedPrecision(max_bit_length) {
|
||||
return (3 * max_bit_length) / 2;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### ComputeRAnsPrecisionFromMaxSymbolBitLength
|
||||
|
||||
~~~~~
|
||||
int ComputeRAnsPrecisionFromMaxSymbolBitLength(max_bit_length) {
|
||||
return ComputeRAnsUnclampedPrecision(max_bit_length) < 12
|
||||
? 12
|
||||
: ComputeRAnsUnclampedPrecision(max_bit_length) > 20
|
||||
? 20
|
||||
: ComputeRAnsUnclampedPrecision(max_bit_length);
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeTaggedSymbols
|
||||
|
||||
~~~~~
|
||||
void DecodeTaggedSymbols(num_values, num_components, out_values) {
|
||||
max_symbol_bit_length_t = 5;
|
||||
rans_precision_bits_t =
|
||||
ComputeRAnsPrecisionFromMaxSymbolBitLength(max_symbol_bit_length_t);
|
||||
rans_precision = 1 << rans_precision_bits_t;
|
||||
l_rans_base = rans_precision * 4;
|
||||
num_symbols_ varUI32
|
||||
ReadVarUI32(&num_symbols_);
|
||||
BuildSymbolTables(num_symbols_, lut_table_, probability_table_);
|
||||
bytes_encoded varUI64
|
||||
encoded_data UI8[size]
|
||||
|
||||
RansInitDecoder(ans_, &encoded_data[0], bytes_encoded, l_rans_base);
|
||||
for (i = 0; i < num_values; i += num_components) {
|
||||
RansRead(ans_, l_rans_base, rans_precision,
|
||||
lut_table_, probability_table_, &bit_length);
|
||||
for (j = 0; j < num_components; ++j) {
|
||||
val f[bit_length]
|
||||
out_values.push_back(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeRawSymbols
|
||||
|
||||
~~~~~
|
||||
void DecodeRawSymbols(num_values, out_values) {
|
||||
max_bit_length UI8
|
||||
num_symbols_ varUI32
|
||||
rans_precision_bits = (3 * max_bit_length) / 2;
|
||||
if (rans_precision_bits > 20)
|
||||
rans_precision_bits = 20;
|
||||
if (rans_precision_bits < 12)
|
||||
rans_precision_bits = 12;
|
||||
rans_precision = 1 << rans_precision_bits;
|
||||
l_rans_base = rans_precision * 4;
|
||||
BuildSymbolTables(num_symbols_, lut_table_, probability_table_);
|
||||
bytes_encoded UI64
|
||||
buffer UI8[size]
|
||||
RansInitDecoder(ans_, &buffer[0], bytes_encoded, l_rans_base);
|
||||
for (i = 0; i < num_values; ++i) {
|
||||
RansRead(ans_, l_rans_base, rans_precision,
|
||||
lut_table_, probability_table_, &val);
|
||||
out_values.push_back(val);
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### BuildSymbolTables
|
||||
|
||||
~~~~~
|
||||
void BuildSymbolTables(num_symbols_, lut_table_, probability_table_) {
|
||||
for (i = 0; i < num_symbols_; ++i) {
|
||||
// Decode the first byte and extract the number of extra bytes we need to
|
||||
// get, or the offset to the next symbol with non-zero probability.
|
||||
prob_data UI8
|
||||
token = prob_data & 3;
|
||||
if (token == 3) {
|
||||
offset = prob_data >> 2;
|
||||
for (j = 0; j < offset + 1; ++j) {
|
||||
token_probs[i + j] = 0;
|
||||
}
|
||||
i += offset;
|
||||
} else {
|
||||
prob = prob_data >> 2;
|
||||
for (j = 0; j < token; ++j) {
|
||||
eb UI8
|
||||
prob = prob | (eb << (8 * (j + 1) - 2));
|
||||
}
|
||||
token_probs[i] = prob;
|
||||
}
|
||||
}
|
||||
rans_build_look_up_table(&token_probs[0], num_symbols_, lut_table_,
|
||||
probability_table_);
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### rans_build_look_up_table
|
||||
|
||||
~~~~~
|
||||
void rans_build_look_up_table(
|
||||
token_probs[], num_symbols, lut_table_, probability_table_) {
|
||||
cum_prob = 0;
|
||||
act_prob = 0;
|
||||
for (i = 0; i < num_symbols; ++i) {
|
||||
probability_table_[i].prob = token_probs[i];
|
||||
probability_table_[i].cum_prob = cum_prob;
|
||||
cum_prob += token_probs[i];
|
||||
for (j = act_prob; j < cum_prob; ++j) {
|
||||
lut_table_[j] = i;
|
||||
}
|
||||
act_prob = cum_prob;
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### RansInitDecoder
|
||||
|
||||
~~~~~
|
||||
void RansInitDecoder(ans, buf, offset, l_rans_base) {
|
||||
ans.buf = buf;
|
||||
x = buf[offset - 1] >> 6;
|
||||
if (x == 0) {
|
||||
ans.buf_offset = offset - 1;
|
||||
ans.state = buf[offset - 1] & 0x3F;
|
||||
} else if (x == 1) {
|
||||
ans.buf_offset = offset - 2;
|
||||
ans.state = mem_get_le16(buf + offset - 2) & 0x3FFF;
|
||||
} else if (x == 2) {
|
||||
ans.buf_offset = offset - 3;
|
||||
ans.state = mem_get_le24(buf + offset - 3) & 0x3FFFFF;
|
||||
} else if (x == 3) {
|
||||
ans.buf_offset = offset - 4;
|
||||
ans.state = mem_get_le32(buf + offset - 4) & 0x3FFFFFFF;
|
||||
}
|
||||
ans.state += l_rans_base;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### RansRead
|
||||
|
||||
~~~~~
|
||||
void RansRead(ans, l_rans_base, rans_precision,
|
||||
lut_table_, probability_table_, val) {
|
||||
while (ans.state < l_rans_base && ans.buf_offset > 0) {
|
||||
ans.state = ans.state * IO_BASE + ans.buf[--ans.buf_offset];
|
||||
}
|
||||
quo = ans.state / rans_precision;
|
||||
rem = ans.state % rans_precision;
|
||||
fetch_sym(&sym, rem, lut_table_, probability_table_);
|
||||
ans.state = quo * sym.prob + rem - sym.cum_prob;
|
||||
val = sym.val;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### fetch_sym
|
||||
|
||||
~~~~~
|
||||
void fetch_sym(sym, rem, lut_table_, probability_table_) {
|
||||
symbol = lut_table_[rem];
|
||||
sym.val = symbol;
|
||||
sym.prob = probability_table_[symbol].prob;
|
||||
sym.cum_prob = probability_table_[symbol].cum_prob;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### RabsDescRead
|
||||
|
||||
~~~~~
|
||||
void RabsDescRead(ans, p0, out_val) {
|
||||
p = rabs_ans_p8_precision - p0;
|
||||
if (ans->state < rabs_l_base) {
|
||||
ans->state = ans->state * IO_BASE + ans->buf[--ans->buf_offset];
|
||||
}
|
||||
x = ans->state;
|
||||
quot = x / ans_p8_precision;
|
||||
rem = x % ans_p8_precision;
|
||||
quot = x / rabs_ans_p8_precision;
|
||||
rem = x % rabs_ans_p8_precision;
|
||||
xn = quot * p;
|
||||
val = rem < p;
|
||||
if (val) {
|
||||
@ -42,81 +233,7 @@ int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) {
|
||||
} else {
|
||||
ans->state = x - xn - p;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### rans_read_init()
|
||||
|
||||
~~~~~
|
||||
rans_read_init(UI8 *buf, int offset) {
|
||||
ans_.buf = buf;
|
||||
x = buf[offset - 1] >> 6
|
||||
If (x == 0) {
|
||||
ans_.buf_offset = offset - 1;
|
||||
ans_.state = buf[offset - 1] & 0x3F;
|
||||
} else if (x == 1) {
|
||||
ans_.buf_offset = offset - 2;
|
||||
ans_.state = mem_get_le16(buf + offset - 2) & 0x3FFF;
|
||||
} else if (x == 2) {
|
||||
ans_.buf_offset = offset - 3;
|
||||
ans_.state = mem_get_le24(buf + offset - 3) & 0x3FFFFF;
|
||||
} else if (x == 3) {
|
||||
ans_.buf_offset = offset - 4;
|
||||
ans_.state = mem_get_le32(buf + offset - 4) & 0x3FFFFFFF;
|
||||
}
|
||||
ans_.state += l_rans_base;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### rans_build_look_up_table()
|
||||
|
||||
~~~~~
|
||||
rans_build_look_up_table() {
|
||||
cum_prob = 0
|
||||
act_prob = 0
|
||||
for (i = 0; i < num_symbols; ++i) {
|
||||
probability_table_[i].prob = token_probs[i];
|
||||
probability_table_[i].cum_prob = cum_prob;
|
||||
cum_prob += token_probs[i];
|
||||
for (j = act_prob; j < cum_prob; ++j) {
|
||||
Lut_table_[j] = i
|
||||
}
|
||||
act_prob = cum_prob
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### rans_read()
|
||||
|
||||
~~~~~
|
||||
rans_read() {
|
||||
while (ans_.state < l_rans_base) {
|
||||
ans_.state = ans_.state * io_base + ans_.buf[--ans_.buf_offset];
|
||||
}
|
||||
quo = ans_.state / rans_precision;
|
||||
rem = ans_.state % rans_precision;
|
||||
sym = fetch_sym()
|
||||
ans_.state = quo * sym.prob + rem - sym.cum_prob;
|
||||
return sym.val;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### fetch_sym()
|
||||
|
||||
~~~~~
|
||||
fetch_sym() {
|
||||
symbol = lut_table[rem]
|
||||
out->val = symbol
|
||||
out->prob = probability_table_[symbol].prob;
|
||||
out->cum_prob = probability_table_[symbol].cum_prob;
|
||||
out_val = val;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
@ -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
|
||||
|
||||
### ConvertSymbolToSignedInt()
|
||||
|
||||
~~~~~
|
||||
Initialize(...) {
|
||||
SequentialAttributeDecoder_Initialize()
|
||||
int ConvertSymbolToSignedInt(val) {
|
||||
is_positive = !static_cast<bool>(val & 1);
|
||||
val >>= 1;
|
||||
if (is_positive) {
|
||||
return val;
|
||||
}
|
||||
val = -val - 1;
|
||||
return val;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeValues()
|
||||
### ConvertSymbolsToSignedInts()
|
||||
|
||||
~~~~~
|
||||
DecodeValues(point_ids) {
|
||||
prediction_scheme_method I8
|
||||
if (prediction_scheme_method != PREDICTION_NONE) {
|
||||
prediction_transform_type I8
|
||||
prediction_scheme_ = CreateIntPredictionScheme(...)
|
||||
void ConvertSymbolsToSignedInts() {
|
||||
decoded_symbols = seq_int_att_dec_decoded_values[curr_att_dec][curr_att];
|
||||
for (i = 0; i < decoded_symbols.size(); ++i) {
|
||||
val = ConvertSymbolToSignedInt(decoded_symbols[i]);
|
||||
seq_int_att_dec_symbols_to_signed_ints[i] = val;
|
||||
}
|
||||
if (prediction_scheme_) {
|
||||
}
|
||||
DecodeIntegerValues(point_ids)
|
||||
//SequentialQuantizationAttributeDecoder_DecodeIntegerValues()
|
||||
//StoreValues()
|
||||
DequantizeValues(num_values)
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeIntegerValues()
|
||||
### SequentialIntegerAttributeDecoder_DecodeIntegerValues()
|
||||
|
||||
~~~~~
|
||||
DecodeIntegerValues(point_ids) {
|
||||
compressed UI8
|
||||
if (compressed) {
|
||||
DecodeSymbols(..., values_.data())
|
||||
void SequentialIntegerAttributeDecoder_DecodeIntegerValues() {
|
||||
num_components = GetNumComponents();
|
||||
num_entries = att_dec_num_values_to_decode[curr_att_dec][curr_att];
|
||||
num_values = num_entries * num_components;
|
||||
if (seq_int_att_dec_compressed[curr_att_dec][curr_att] > 0) {
|
||||
DecodeSymbols(num_values, num_components, &decoded_symbols);
|
||||
}
|
||||
seq_int_att_dec_decoded_values[curr_att_dec][curr_att] = decoded_symbols;
|
||||
if (num_values > 0) {
|
||||
if (seq_att_dec_prediction_transform_type[curr_att_dec][curr_att] ==
|
||||
PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED) {
|
||||
decoded_symbols = seq_int_att_dec_decoded_values[curr_att_dec][curr_att];
|
||||
for (int i = 0; i < decoded_symbols.size(); ++i) {
|
||||
signed_vals[i] = decoded_symbols[i];
|
||||
}
|
||||
seq_int_att_dec_symbols_to_signed_ints[curr_att_dec][curr_att] = signed_vals;
|
||||
} else {
|
||||
// TODO
|
||||
ConvertSymbolsToSignedInts();
|
||||
}
|
||||
if (!prediction_scheme_->AreCorrectionsPositive()) {
|
||||
ConvertSymbolsToSignedInts(...)
|
||||
}
|
||||
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()
|
||||
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);
|
||||
}
|
||||
}
|
||||
~~~~~
|
||||
{:.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
|
||||
|
||||
### ParseQuantizationBits()
|
||||
|
||||
~~~~~
|
||||
Initialize(...) {
|
||||
SequentialIntegerAttributeDecoder_Initialize()
|
||||
void ParseQuantizationBits() {
|
||||
quantized_data_quantization_bits[curr_att_dec][curr_att] UI8
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DecodeIntegerValues()
|
||||
### ParseQuantizationData()
|
||||
|
||||
~~~~~
|
||||
DecodeIntegerValues(point_ids) {
|
||||
// REMOVE < DRACO_BITSTREAM_VERSION(2, 0)
|
||||
// DecodeQuantizedDataInfo()
|
||||
num_components = attribute()->components_count();
|
||||
for (i = 0; i < num_components; ++i) {
|
||||
min_value_[i] F32
|
||||
void ParseQuantizationData() {
|
||||
num_components = GetNumComponents();
|
||||
for (j = 0; j < num_components; ++j) {
|
||||
quantized_data_min_values[curr_att_dec][curr_att][i] Float
|
||||
}
|
||||
max_value_dif_ F32
|
||||
quantization_bits_ UI8
|
||||
// REMOVE < DRACO_BITSTREAM_VERSION(2, 0)
|
||||
SequentialIntegerAttributeDecoder::DecodeIntegerValues()
|
||||
quantized_data_max_value_df[curr_att_dec][curr_att] Float
|
||||
ParseQuantizationBits();
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### DequantizeValues()
|
||||
### DequantizeFloat()
|
||||
|
||||
~~~~~
|
||||
DequantizeValues(num_values) {
|
||||
max_quantized_value = (1 << (quantization_bits_)) - 1;
|
||||
num_components = attribute()->components_count();
|
||||
entry_size = sizeof(float) * num_components;
|
||||
float DequantizeFloat(val, max_quantized_value_factor_, range_) {
|
||||
neg = (val < 0);
|
||||
if (neg) {
|
||||
val = -val;
|
||||
}
|
||||
norm_value = val * max_quantized_value_factor_;
|
||||
if (neg)
|
||||
norm_value = -norm_value;
|
||||
return norm_value * range_;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
||||
|
||||
### SequentialQuantizationAttributeDecoder_DequantizeValues()
|
||||
|
||||
~~~~~
|
||||
void SequentialQuantizationAttributeDecoder_DequantizeValues() {
|
||||
quantization_bits = quantized_data_quantization_bits[curr_att_dec][curr_att];
|
||||
max_quantized_value = (1 << (quantization_bits)) - 1;
|
||||
num_components = GetNumComponents();
|
||||
quant_val_id = 0;
|
||||
out_byte_pos = 0;
|
||||
range_ = quantized_data_max_value_df[curr_att_dec][curr_att];
|
||||
max_quantized_value_factor_ = 1.f / max_quantized_value;
|
||||
min_value_ = quantized_data_min_values[curr_att_dec][curr_att];
|
||||
original_values = seq_int_att_dec_original_values[curr_att_dec][curr_att];
|
||||
num_values = att_dec_num_values_to_decode[curr_att_dec][curr_att];
|
||||
for (i = 0; i < num_values; ++i) {
|
||||
for (c = 0; c < num_components; ++c) {
|
||||
value = dequantizer.DequantizeFloat(values()->at(quant_val_id++));
|
||||
value = DequantizeFloat(original_values[quant_val_id++],
|
||||
max_quantized_value_factor_, range_);
|
||||
value = value + min_value_[c];
|
||||
att_val[c] = value;
|
||||
dequantized_data.push_back(value);
|
||||
}
|
||||
attribute()->buffer()->Write(out_byte_pos, att_val, entry_size);
|
||||
out_byte_pos += entry_size;
|
||||
}
|
||||
seq_int_att_dec_dequantized_values[curr_att_dec][curr_att] = dequantized_data;
|
||||
}
|
||||
~~~~~
|
||||
{:.draco-syntax }
|
||||
|
@ -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