Merge pull request #205 from google/update_bitstream_spec

Update bitstream spec to version 2.1
This commit is contained in:
FrankGalligan 2017-09-30 15:12:55 -07:00 committed by GitHub
commit c6575182fe
42 changed files with 2981 additions and 1628 deletions

View File

@ -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 }

View 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}

View File

@ -0,0 +1,15 @@
## Connectivity Decoder
### DecodeConnectivityData()
~~~~~
void DecodeConnectivityData() {
if (encoder_method == MESH_SEQUENTIAL_ENCODING)
DecodeSequentialConnectivityData();
else
DecodeEdgebreakerConnectivityData();
}
~~~~~
{:.draco-syntax }

View File

@ -1,65 +1,16 @@
## Core Functions
### DecodeVarint<IT>
### DecodeVarint
~~~~~
DecodeVarint<IT>() {
If (std::is_unsigned<IT>::value) {
in UI8
If (in & (1 << 7)) {
out = DecodeVarint<IT>()
out = (out << 7) | (in & ((1 << 7) - 1))
} else {
typename std::make_unsigned<IT>::type UIT;
out = DecodeVarint<UIT>()
out = ConvertSymbolToSignedInt(out)
}
return out;
}
~~~~~
{:.draco-syntax }
### ConvertSymbolToSignedInt()
~~~~~
ConvertSymbolToSignedInt() {
abs_val = val >> 1
If (val & 1 == 0) {
return abs_val
void DecodeVarint(out_val) {
in UI8
if (in & (1 << 7)) {
DecodeVarint(out_val);
out_val = (out_val << 7) | (in & ((1 << 7) - 1));
} else {
signed_val = -abs_val - 1
}
return signed_val
}
~~~~~
{:.draco-syntax }
Sequential Decoder
FIXME: ^^^ Heading level?
### decode_connectivity()
~~~~~
decode_connectivity() {
num_faces I32
num_points I32
connectivity _method UI8
If (connectivity _method == 0) {
// TODO
} else {
loop num_faces {
If (num_points < 256) {
face[] UI8
} else if (num_points < (1 << 16)) {
face[] UI16
} else {
face[] UI32
}
}
out_val = in;
}
}
~~~~~

203
docs/spec/corner.md Normal file
View 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}

View File

@ -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 }

View File

@ -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 }

View File

@ -3,47 +3,28 @@
### Decode()
~~~~~
Decode() {
DecodeHeader()
void Decode() {
ParseHeader();
if (flags & METADATA_FLAG_MASK)
DecodeGeometryMetadata(metadata)
DecodeConnectivityData()
DecodeAttributeData()
DecodeMetadata();
DecodeConnectivityData();
DecodeAttributeData();
}
~~~~~
{:.draco-syntax}
### DecodeHeader()
### ParseHeader()
~~~~~
DecodeHeader() {
draco_string UI8[5]
major_version UI8
minor_version UI8
encoder_type UI8
encoder_method UI8
flags
ParseHeader() {
draco_string UI8[5]
major_version UI8
minor_version UI8
encoder_type UI8
encoder_method UI8
flags UI16
}
~~~~~
{:.draco-syntax}
### DecodeAttributeData()
~~~~~
DecodeAttributeData() {
num_attributes_decoders UI8
for (i = 0; i < num_attributes_decoders; ++i) {
CreateAttributesDecoder(i);
}
for (auto &att_dec : attributes_decoders_) {
att_dec->Initialize(this, point_cloud_)
}
for (i = 0; i < num_attributes_decoders; ++i) {
attributes_decoders_[i]->DecodeAttributesDecoderData(buffer_)
}
DecodeAllAttributes()
OnAttributesDecoded()
~~~~~
{:.draco-syntax}

View File

@ -1,299 +1,80 @@
## EdgeBreaker Decoder
### DecodeConnectivityData()
### ParseEdgebreakerConnectivityData()
~~~~~
DecodeConnectivityData() {
edgebreaker_traversal_type UI8
num_new_verts varUI32
num_encoded_vertices varUI32
num_faces varUI32
num_attribute_data I8
num_encoded_symbols varUI32
num_encoded_split_symbols varUI32
encoded_connectivity_size varUI32
void ParseEdgebreakerConnectivityData() {
edgebreaker_traversal_type UI8
num_new_vertices varUI32
num_encoded_vertices varUI32
num_faces varUI32
num_attribute_data I8
num_encoded_symbols varUI32
num_encoded_split_symbols varUI32
encoded_connectivity_size varUI32
}
~~~~~
{:.draco-syntax }
### ParseTopologySplitEvents()
~~~~~
void ParseTopologySplitEvents() {
num_topologoy_splits varUI32
for (i = 0; i < num_topologoy_splits; ++i) {
source_id_delta[i] varUI32
split_id_delta[i] varUI32
}
for (i = 0; i < num_topologoy_splits; ++i) {
split_edge_bit[i] f[1]
source_edge_bit[i] f[1]
}
}
~~~~~
{:.draco-syntax }
### DecodeEdgebreakerConnectivityData()
~~~~~
void DecodeEdgebreakerConnectivityData() {
ParseEdgebreakerConnectivityData();
// file pointer must be set to current position
// + encoded_connectivity_size
hole_and_split_bytes = DecodeHoleAndTopologySplitEvents()
DecodeTopologySplitEvents();
// file pointer must be saved, as it points to the attribute data
// file pointer must be set to old current position
EdgeBreakerTraversalValence_Start(num_encoded_vertices)
DecodeConnectivity(num_symbols)
if (attribute_data_.size() > 0) {
for (ci = 0; ci < corner_table_->num_corners(); ci += 3) {
DecodeAttributeConnectivitiesOnFace(ci)
}
}
for (i = 0; i < corner_table_->num_vertices(); ++i) {
if (is_vert_hole_[i]) {
corner_table_->UpdateVertexToCornerMap(i);
}
}
// Decode attribute connectivity.
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
attribute_data_[i].connectivity_data.InitEmpty(corner_table_);
for (int32_t c : attribute_data_[i].attribute_seam_corners) {
attribute_data_[i].connectivity_data.AddSeamEdge(c);
}
attribute_data_[i].connectivity_data.RecomputeVertices(nullptr,
nullptr);
}
// Preallocate vertex to value mapping
AssignPointsToCorners()
EdgebreakerTraversalStart();
DecodeEdgeBreakerConnectivity();
}
~~~~~
{:.draco-syntax }
### AssignPointsToCorners()
### ProcessSplitData()
~~~~~
AssignPointsToCorners() {
decoder_->mesh()->SetNumFaces(corner_table_->num_faces());
if (attribute_data_.size() == 0) {
for (f = 0; f < decoder_->mesh()->num_faces(); ++f) {
for (c = 0; c < 3; ++c) {
vert_id = corner_table_->Vertex(3 * f + c);
if (point_id == -1)
point_id = num_points++;
face[c] = point_id;
}
decoder_->mesh()->SetFace(f, face);
}
decoder_->point_cloud()->set_num_points(num_points);
Return true;
}
for (v = 0; v < corner_table_->num_vertices(); ++v) {
c = corner_table_->LeftMostCorner(v);
if (c < 0)
continue;
deduplication_first_corner = c;
if (!is_vert_hole_[v]) {
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
if (!attribute_data_[i].connectivity_data.IsCornerOnSeam(c))
continue;
vert_id = attribute_data_[i].connectivity_data.Vertex(c);
act_c = corner_table_->SwingRight(c);
seam_found = false;
while (act_c != c) {
if (attribute_data_[i].connectivity_data.Vertex(act_c) !=
vert_id) {
deduplication_first_corner = act_c;
seam_found = true;
break;
}
act_c = corner_table_->SwingRight(act_c);
}
if (seam_found)
break;
}
}
c = deduplication_first_corner;
corner_to_point_map[c] = point_to_corner_map.size();
point_to_corner_map.push_back(c);
prev_c = c;
c = corner_table_->SwingRight(c);
while (c >= 0 && c != deduplication_first_corner) {
attribute_seam = false;
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
if (attribute_data_[i].connectivity_data.Vertex(c) !=
attribute_data_[i].connectivity_data.Vertex(prev_c)) {
attribute_seam = true;
break;
}
}
if (attribute_seam) {
corner_to_point_map[c] = point_to_corner_map.size();
point_to_corner_map.push_back(c);
} else {
corner_to_point_map[c] = corner_to_point_map[prev_c];
}
prev_c = c;
c = corner_table_->SwingRight(c);
}
}
for (f = 0; f < decoder_->mesh()->num_faces(); ++f) {
for (c = 0; c < 3; ++c) {
face[c] = corner_to_point_map[3 * f + c];
}
decoder_->mesh()->SetFace(f, face);
}
decoder_->point_cloud()->set_num_points(point_to_corner_map.size());
}
~~~~~
{:.draco-syntax }
### DecodeConnectivity()
~~~~~
DecodeConnectivity(num_symbols) {
for (i = 0; i < num_symbols; ++i) {
symbol = TraversalValence_DecodeSymbol()
corner = 3 * num_faces++
if (symbol == TOPOLOGY_C) {
vertex_x = UpdateCornerTableForSymbolC()
is_vert_hole_[vertex_x] = false;
} else if (symbol == TOPOLOGY_R || symbol == TOPOLOGY_L) {
UpdateCornerTableForSymbolLR()
check_topology_split = true;
} else if (symbol == TOPOLOGY_S) {
HandleSymbolS()
} else if (symbol == TOPOLOGY_E) {
UpdateCornerTableForSymbolE()
check_topology_split = true;
}
active_corner_stack.back() = corner;
traversal_decoder_.NewActiveCornerReached(corner);
if (check_topology_split) {
encoder_symbol_id = num_symbols - symbol_id - 1;
while (true) {
split = IsTopologySplit(encoder_symbol_id, &split_edge,
&encoder_split_symbol_id);
if (!split) {
break;
}
act_top_corner = corner;
if (split_edge == RIGHT_FACE_EDGE) {
new_active_corner = corner_table_->Next(act_top_corner);
} else {
new_active_corner = corner_table_->Previous(act_top_corner);
}
decoder_split_symbol_id = num_symbols -
encoder_split_symbol_id - 1;
topology_split_active_corners[decoder_split_symbol_id] =
new_active_corner;
}
}
}
while (active_corner_stack.size() > 0) {
corner = active_corner_stack.pop_back();
interior_face = traversal_decoder_.DecodeStartFaceConfiguration();
if (interior_face == true) {
UpdateCornerTableForInteriorFace()
for (ci = 0; ci < 3; ++ci) {
is_vert_hole_[corner_table_->Vertex(new_corner + ci)] = false;
}
init_face_configurations_.push_back(true);
init_corners_.push_back(new_corner);
} else {
init_face_configurations_.push_back(false);
init_corners_.push_back(corner);
}
void ProcessSplitData() {
last_id = 0;
for (i = 0; i < source_id_delta.size(); ++i) {
source_symbol_id[i] = source_id_delta[i] + last_id;
split_symbol_id.[i] = source_symbol_id[i] - split_id_delta[i];
last_id = source_symbol_id[i];
}
}
~~~~~
{:.draco-syntax }
### UpdateCornerTableForSymbolC()
### DecodeTopologySplitEvents()
~~~~~
UpdateCornerTableForSymbolC(corner) {
corner_a = active_corner_stack.back();
corner_b = corner_table_->Previous(corner_a);
while (corner_table_->Opposite(corner_b) >= 0) {
corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b));
}
SetOppositeCorners(corner_a, corner + 1);
SetOppositeCorners(corner_b, corner + 2);
vertex_x = corner_table_->Vertex(corner_table_->Next(corner_a));
corner_table_->MapCornerToVertex(corner, vertex_x);
corner_table_->MapCornerToVertex(
corner + 1, corner_table_->Vertex(corner_table_->Next(corner_b)));
corner_table_->MapCornerToVertex(
corner + 2, corner_table_->Vertex(corner_table_->Previous(corner_a)));
return vertex_x;
}
~~~~~
{:.draco-syntax }
### UpdateCornerTableForSymbolLR()
~~~~~
UpdateCornerTableForSymbolLR(corner, symbol) {
if (symbol == TOPOLOGY_R) {
opp_corner = corner + 2;
} else {
opp_corner = corner + 1;
}
SetOppositeCorners(opp_corner, corner_a);
corner_table_->MapCornerToVertex(opp_corner,num_vertices++);
corner_table_->MapCornerToVertex(
corner_table_->Next(opp_corner),
corner_table_->Vertex(corner_table_->Previous(corner_a)));
corner_table_->MapCornerToVertex(
corner_table_->Previous(opp_corner),
corner_table_->Vertex(corner_table_->Next(corner_a)));
}
~~~~~
{:.draco-syntax }
### HandleSymbolS()
~~~~~
HandleSymbolS(corner) {
corner_b = active_corner_stack.pop_back();
it = topology_split_active_corners.find(symbol_id);
if (it != topology_split_active_corners.end()) {
active_corner_stack.push_back(it->second);
}
corner_a = active_corner_stack.back();
SetOppositeCorners(corner_a, corner + 2);
SetOppositeCorners(corner_b, corner + 1);
vertex_p = corner_table_->Vertex(corner_table_->Previous(corner_a));
corner_table_->MapCornerToVertex(corner, vertex_p);
corner_table_->MapCornerToVertex(
corner + 1, corner_table_->Vertex(corner_table_->Next(corner_a)));
corner_table_->MapCornerToVertex(corner + 2,
corner_table_->Vertex(corner_table_->Previous(corner_b)));
corner_n = corner_table_->Next(corner_b);
vertex_n = corner_table_->Vertex(corner_n);
traversal_decoder_.MergeVertices(vertex_p, vertex_n);
// TraversalValence_MergeVertices
while (corner_n >= 0) {
corner_table_->MapCornerToVertex(corner_n, vertex_p);
corner_n = corner_table_->SwingLeft(corner_n);
}
corner_table_->MakeVertexIsolated(vertex_n);
}
~~~~~
{:.draco-syntax }
### UpdateCornerTableForSymbolE()
~~~~~
UpdateCornerTableForSymbolE() {
corner_table_->MapCornerToVertex(corner, num_vertices++);
corner_table_->MapCornerToVertex(corner + 1, num_vertices++);
corner_table_->MapCornerToVertex(corner + 2, num_vertices++);
}
~~~~~
{:.draco-syntax }
### UpdateCornerTableForInteriorFace()
~~~~~
UpdateCornerTableForInteriorFace() {
corner_b = corner_table_->Previous(corner);
while (corner_table_->Opposite(corner_b) >= 0) {
corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b));
}
corner_c = corner_table_->Next(corner);
while (corner_table_->Opposite(corner_c) >= 0) {
corner_c = corner_table_->Next(corner_table_->Opposite(corner_c));
}
face(num_faces++);
corner_table_->MapCornerToVertex(
new_corner, corner_table_->Vertex(corner_table_->Next(corner_b)));
corner_table_->MapCornerToVertex(
new_corner + 1, corner_table_->Vertex(corner_table_->Next(corner_c)));
corner_table_->MapCornerToVertex(
new_corner + 2, corner_table_->Vertex(corner_table_->Next(corner)));
void DecodeTopologySplitEvents() {
ParseTopologySplitEvents();
ProcessSplitData();
}
~~~~~
{:.draco-syntax }
@ -302,41 +83,32 @@ UpdateCornerTableForInteriorFace() {
### IsTopologySplit()
~~~~~
IsTopologySplit(encoder_symbol_id, *out_face_edge,
*out_encoder_split_symbol_id) {
if (topology_split_data_.size() == 0)
bool IsTopologySplit(encoder_symbol_id, out_face_edge,
out_encoder_split_symbol_id) {
if (source_symbol_id.back() != encoder_symbol_id)
return false;
if (topology_split_data_.back().source_symbol_id != encoder_symbol_id)
return false;
*out_face_edge = topology_split_data_.back().source_edge;
*out_encoder_split_symbol_id =
topology_split_data_.back().split_symbol_id;
topology_split_data_.pop_back();
*out_face_edge = source_edge_bit.pop();
*out_encoder_split_symbol_id = split_symbol_id.pop();
source_symbol_id.pop();
return true;
}
~~~~~
{:.draco-syntax }
### DecodeAttributeConnectivitiesOnFace()
### ReplaceVerts()
~~~~~
DecodeAttributeConnectivitiesOnFace(corner) {
corners[3] = {corner, corner_table_->Next(corner),
corner_table_->Previous(corner)}
for (c = 0; c < 3; ++c) {
opp_corner = corner_table_->Opposite(corners[c]);
if (opp_corner < 0) {
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
attribute_data_[i].attribute_seam_corners.push_back(corners[c]);
}
continue
void ReplaceVerts(from, to) {
for (i = 0; i < face_to_vertex[0].size(); ++i) {
if (face_to_vertex[0][i] == from) {
face_to_vertex[0][i] = to;
}
for (uint32_t i = 0; i < attribute_data_.size(); ++i) {
bool is_seam = traversal_decoder_.DecodeAttributeSeam(i);
if (is_seam) {
attribute_data_[i].attribute_seam_corners.push_back(corners[c]);
}
if (face_to_vertex[1][i] == from) {
face_to_vertex[1][i] = to;
}
if (face_to_vertex[2][i] == from) {
face_to_vertex[2][i] = to;
}
}
}
@ -344,12 +116,238 @@ DecodeAttributeConnectivitiesOnFace(corner) {
{:.draco-syntax }
### SetOppositeCorners()
### UpdateCornersAfterMerge()
~~~~~
SetOppositeCorners(corner_0, corner_1) {
corner_table_->SetOppositeCorner(corner_0, corner_1);
corner_table_->SetOppositeCorner(corner_1, corner_0);
void UpdateCornersAfterMerge(c, v) {
opp_corner = PosOpposite(c);
if (opp_corner >= 0) {
corner_n = Next(opp_corner);
while (corner_n >= 0) {
MapCornerToVertex(corner_n, v);
corner_n = SwingLeft(0, corner_n);
}
}
}
~~~~~
{:.draco-syntax }
### NewActiveCornerReached()
~~~~~
void NewActiveCornerReached(new_corner, symbol_id) {
check_topology_split = false;
switch (last_symbol_) {
case TOPOLOGY_C:
{
corner_a = active_corner_stack.back();
corner_b = Previous(corner_a);
while (PosOpposite(corner_b) >= 0) {
b_opp = PosOpposite(corner_b);
corner_b = Previous(b_opp);
}
SetOppositeCorners(corner_a, new_corner + 1);
SetOppositeCorners(corner_b, new_corner + 2);
active_corner_stack.back() = new_corner;
}
vert = CornerToVert(Next(corner_a));
next = CornerToVert(Next(corner_b));
prev = CornerToVert(Previous(corner_a));
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
vertex_valences_[next] += 1;
vertex_valences_[prev] += 1;
}
face_to_vertex[0].push_back(vert);
face_to_vertex[1].push_back(next);
face_to_vertex[2].push_back(prev);
is_vert_hole_[vert] = false;
MapCornerToVertex(new_corner, vert);
MapCornerToVertex(new_corner + 1, next);
MapCornerToVertex(new_corner + 2, prev);
break;
case TOPOLOGY_S:
{
corner_b = active_corner_stack.pop();
for (i = 0; i < split_active_corners.size(); ++i) {
if (split_active_corners[i].decoder_split_symbol_id == symbol_id) {
active_corner_stack.push_back(split_active_corners[i].corner);
}
}
corner_a = active_corner_stack.back();
SetOppositeCorners(corner_a, new_corner + 2);
SetOppositeCorners(corner_b, new_corner + 1);
active_corner_stack.back() = new_corner;
}
vert = CornerToVert(Previous(corner_a));
next = CornerToVert(Next(corner_a));
prev = CornerToVert(Previous(corner_b));
MapCornerToVertex(new_corner, vert);
MapCornerToVertex(new_corner + 1, next);
MapCornerToVertex(new_corner + 2, prev);
corner_n = Next(corner_b);
vertex_n = CornerToVert(corner_n);
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
vertex_valences_[vert] += vertex_valences_[vertex_n];
}
ReplaceVerts(vertex_n, vert);
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
vertex_valences_[next] += 1;
vertex_valences_[prev] += 1;
}
face_to_vertex[0].push_back(vert);
face_to_vertex[1].push_back(next);
face_to_vertex[2].push_back(prev);
UpdateCornersAfterMerge(new_corner + 1, vert);
vertex_corners_[vertex_n] = kInvalidCornerIndex;
break;
case TOPOLOGY_R:
{
corner_a = active_corner_stack.back();
opp_corner = new_corner + 2;
SetOppositeCorners(opp_corner, corner_a);
active_corner_stack.back() = new_corner;
}
check_topology_split = true;
vert = CornerToVert(Previous(corner_a));
next = CornerToVert(Next(corner_a));
prev = ++last_vert_added;
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
vertex_valences_[vert] += 1;
vertex_valences_[next] += 1;
vertex_valences_[prev] += 2;
}
face_to_vertex[0].push_back(vert);
face_to_vertex[1].push_back(next);
face_to_vertex[2].push_back(prev);
MapCornerToVertex(new_corner + 2, prev);
MapCornerToVertex(new_corner, vert);
MapCornerToVertex(new_corner + 1, next);
break;
case TOPOLOGY_L:
{
corner_a = active_corner_stack.back();
opp_corner = new_corner + 1;
SetOppositeCorners(opp_corner, corner_a);
active_corner_stack.back() = new_corner;
}
check_topology_split = true;
vert = CornerToVert(Previous(corner_a));
next = CornerToVert(Next(corner_a));
prev = ++last_vert_added;
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
vertex_valences_[vert] += 1;
vertex_valences_[next] += 1;
vertex_valences_[prev] += 2;
}
face_to_vertex[0].push_back(vert);
face_to_vertex[1].push_back(next);
face_to_vertex[2].push_back(prev);
MapCornerToVertex(new_corner + 2, prev);
MapCornerToVertex(new_corner, vert);
MapCornerToVertex(new_corner + 1, next);
break;
case TOPOLOGY_E:
active_corner_stack.push_back(new_corner);
check_topology_split = true;
vert = last_vert_added + 1;
next = vert + 1;
prev = next + 1;
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
vertex_valences_[vert] += 2;
vertex_valences_[next] += 2;
vertex_valences_[prev] += 2;
}
face_to_vertex[0].push_back(vert);
face_to_vertex[1].push_back(next);
face_to_vertex[2].push_back(prev);
last_vert_added = prev;
MapCornerToVertex(new_corner, vert);
MapCornerToVertex(new_corner + 1, next);
MapCornerToVertex(new_corner + 2, prev);
break;
}
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
// Compute the new context that is going to be used
// to decode the next symbol.
active_valence = vertex_valences_[next];
if (active_valence < MIN_VALENCE) {
clamped_valence = MIN_VALENCE;
} else if (active_valence > MAX_VALENCE) {
clamped_valence = MAX_VALENCE;
} else {
clamped_valence = active_valence;
}
active_context_ = (clamped_valence - MIN_VALENCE);
}
if (check_topology_split) {
encoder_symbol_id = num_encoded_symbols - symbol_id - 1;
while (IsTopologySplit(encoder_symbol_id, &split_edge,
&enc_split_id)) {
act_top_corner = active_corner_stack.back();
if (split_edge == RIGHT_FACE_EDGE) {
new_active_corner = Next(act_top_corner);
} else {
new_active_corner = Previous(act_top_corner);
}
// Convert the encoder split symbol id to decoder symbol id.
dec_split_id = num_encoded_symbols - enc_split_id - 1;
topology_edge_list[dec_split_id] = new_active_corner;
}
}
}
~~~~~
{:.draco-syntax }
### ParseEdgebreakerStandardSymbol()
~~~~~
void ParseEdgebreakerStandardSymbol() {
bit_symbol_buffer.DecodeLeastSignificantBits32(1, &symbol);
if (symbol != TOPOLOGY_C) {
// Else decode two additional bits.
bit_symbol_buffer.DecodeLeastSignificantBits32(2, &symbol_suffix);
symbol |= (symbol_suffix << 1);
}
last_symbol_ = symbol;
}
~~~~~
{:.draco-syntax }
### EdgebreakerDecodeSymbol()
~~~~~
void EdgebreakerDecodeSymbol() {
if (edgebreaker_traversal_type == VALENCE_EDGEBREAKER) {
EdgebreakerValenceDecodeSymbol(sym);
} else {
ParseEdgebreakerStandardSymbol(sym);
}
}
~~~~~
{:.draco-syntax }
### DecodeEdgeBreakerConnectivity()
~~~~~
void DecodeEdgeBreakerConnectivity() {
is_vert_hole_.assign(num_encoded_vertices + num_encoded_split_symbols, true);
for (i = 0; i < num_encoded_symbols; ++i) {
EdgebreakerDecodeSymbol();
corner = 3 * i;
NewActiveCornerReached(corner, i);
}
ProcessInteriorEdges();
}
~~~~~
{:.draco-syntax }

View File

@ -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 }

View File

@ -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 }

View 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 }

View 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 }

View File

@ -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 }

View 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 }

View File

@ -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 }

View File

@ -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 %}

View File

@ -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 }

View File

@ -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 }

View File

@ -1,2 +0,0 @@
## Mesh Decoder

View File

@ -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 }

View File

@ -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 }

View File

@ -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}

View 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}

View 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}

View 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}

View 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}

View 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}

View File

@ -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 }

View File

@ -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 }

View 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}

View 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}

View File

@ -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 }

View File

@ -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 }

View File

@ -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 }

View File

@ -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 }

View 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 }

View File

@ -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())
} else {
// TODO
void SequentialIntegerAttributeDecoder_DecodeIntegerValues() {
num_components = GetNumComponents();
num_entries = att_dec_num_values_to_decode[curr_att_dec][curr_att];
num_values = num_entries * num_components;
if (seq_int_att_dec_compressed[curr_att_dec][curr_att] > 0) {
DecodeSymbols(num_values, num_components, &decoded_symbols);
}
if (!prediction_scheme_->AreCorrectionsPositive()) {
ConvertSymbolsToSignedInts(...)
seq_int_att_dec_decoded_values[curr_att_dec][curr_att] = decoded_symbols;
if (num_values > 0) {
if (seq_att_dec_prediction_transform_type[curr_att_dec][curr_att] ==
PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED) {
decoded_symbols = seq_int_att_dec_decoded_values[curr_att_dec][curr_att];
for (int i = 0; i < decoded_symbols.size(); ++i) {
signed_vals[i] = decoded_symbols[i];
}
seq_int_att_dec_symbols_to_signed_ints[curr_att_dec][curr_att] = signed_vals;
} else {
ConvertSymbolsToSignedInts();
}
}
if (seq_att_dec_prediction_scheme[curr_att_dec][curr_att] != PREDICTION_NONE) {
DecodePredictionData(seq_att_dec_prediction_scheme[curr_att_dec][curr_att]);
PredictionScheme_ComputeOriginalValues(
seq_att_dec_prediction_scheme[curr_att_dec][curr_att], num_entries);
}
if (prediction_scheme_) {
prediction_scheme_->DecodePredictionData(buffer)
// DecodeTransformData(buffer)
if (!values_.empty()) {
prediction_scheme_->Decode(values_.data(), &values_[0],
values_.size(), num_components, point_ids.data())
// MeshPredictionSchemeParallelogram_Decode()
}
~~~~~
{:.draco-syntax }

View 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 }

View File

@ -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 }

View File

@ -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
View 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}