Draco: update to version 1.5.2
Differential Revision: https://developer.blender.org/D15233
This commit is contained in:
committed by
Brecht Van Lommel
parent
524a9e3db8
commit
33bad77043
4
extern/draco/README.blender
vendored
4
extern/draco/README.blender
vendored
@@ -1,5 +1,5 @@
|
||||
Project: Draco
|
||||
URL: https://google.github.io/draco/
|
||||
License: Apache 2.0
|
||||
Upstream version: 1.3.6
|
||||
Local modifications: None
|
||||
Upstream version: 1.5.2
|
||||
Local modifications: Apply patches/blender.patch
|
||||
|
||||
@@ -38,6 +38,46 @@ void AttributeOctahedronTransform::CopyToAttributeTransformData(
|
||||
out_data->AppendParameterValue(quantization_bits_);
|
||||
}
|
||||
|
||||
bool AttributeOctahedronTransform::TransformAttribute(
|
||||
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
|
||||
PointAttribute *target_attribute) {
|
||||
return GeneratePortableAttribute(attribute, point_ids,
|
||||
target_attribute->size(), target_attribute);
|
||||
}
|
||||
|
||||
bool AttributeOctahedronTransform::InverseTransformAttribute(
|
||||
const PointAttribute &attribute, PointAttribute *target_attribute) {
|
||||
if (target_attribute->data_type() != DT_FLOAT32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int num_points = target_attribute->size();
|
||||
const int num_components = target_attribute->num_components();
|
||||
if (num_components != 3) {
|
||||
return false;
|
||||
}
|
||||
constexpr int kEntrySize = sizeof(float) * 3;
|
||||
float att_val[3];
|
||||
const int32_t *source_attribute_data = reinterpret_cast<const int32_t *>(
|
||||
attribute.GetAddress(AttributeValueIndex(0)));
|
||||
uint8_t *target_address =
|
||||
target_attribute->GetAddress(AttributeValueIndex(0));
|
||||
OctahedronToolBox octahedron_tool_box;
|
||||
if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_)) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < num_points; ++i) {
|
||||
const int32_t s = *source_attribute_data++;
|
||||
const int32_t t = *source_attribute_data++;
|
||||
octahedron_tool_box.QuantizedOctahedralCoordsToUnitVector(s, t, att_val);
|
||||
|
||||
// Store the decoded floating point values into the attribute buffer.
|
||||
std::memcpy(target_address, att_val, kEntrySize);
|
||||
target_address += kEntrySize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AttributeOctahedronTransform::SetParameters(int quantization_bits) {
|
||||
quantization_bits_ = quantization_bits;
|
||||
}
|
||||
@@ -51,38 +91,55 @@ bool AttributeOctahedronTransform::EncodeParameters(
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<PointAttribute>
|
||||
AttributeOctahedronTransform::GeneratePortableAttribute(
|
||||
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
|
||||
int num_points) const {
|
||||
DRACO_DCHECK(is_initialized());
|
||||
bool AttributeOctahedronTransform::DecodeParameters(
|
||||
const PointAttribute &attribute, DecoderBuffer *decoder_buffer) {
|
||||
uint8_t quantization_bits;
|
||||
if (!decoder_buffer->Decode(&quantization_bits)) {
|
||||
return false;
|
||||
}
|
||||
quantization_bits_ = quantization_bits;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allocate portable attribute.
|
||||
const int num_entries = static_cast<int>(point_ids.size());
|
||||
std::unique_ptr<PointAttribute> portable_attribute =
|
||||
InitPortableAttribute(num_entries, 2, num_points, attribute, true);
|
||||
bool AttributeOctahedronTransform::GeneratePortableAttribute(
|
||||
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
|
||||
int num_points, PointAttribute *target_attribute) const {
|
||||
DRACO_DCHECK(is_initialized());
|
||||
|
||||
// Quantize all values in the order given by point_ids into portable
|
||||
// attribute.
|
||||
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
|
||||
portable_attribute->GetAddress(AttributeValueIndex(0)));
|
||||
target_attribute->GetAddress(AttributeValueIndex(0)));
|
||||
float att_val[3];
|
||||
int32_t dst_index = 0;
|
||||
OctahedronToolBox converter;
|
||||
if (!converter.SetQuantizationBits(quantization_bits_)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < point_ids.size(); ++i) {
|
||||
const AttributeValueIndex att_val_id = attribute.mapped_index(point_ids[i]);
|
||||
attribute.GetValue(att_val_id, att_val);
|
||||
// Encode the vector into a s and t octahedral coordinates.
|
||||
int32_t s, t;
|
||||
converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
|
||||
portable_attribute_data[dst_index++] = s;
|
||||
portable_attribute_data[dst_index++] = t;
|
||||
if (!point_ids.empty()) {
|
||||
for (uint32_t i = 0; i < point_ids.size(); ++i) {
|
||||
const AttributeValueIndex att_val_id =
|
||||
attribute.mapped_index(point_ids[i]);
|
||||
attribute.GetValue(att_val_id, att_val);
|
||||
// Encode the vector into a s and t octahedral coordinates.
|
||||
int32_t s, t;
|
||||
converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
|
||||
portable_attribute_data[dst_index++] = s;
|
||||
portable_attribute_data[dst_index++] = t;
|
||||
}
|
||||
} else {
|
||||
for (PointIndex i(0); i < num_points; ++i) {
|
||||
const AttributeValueIndex att_val_id = attribute.mapped_index(i);
|
||||
attribute.GetValue(att_val_id, att_val);
|
||||
// Encode the vector into a s and t octahedral coordinates.
|
||||
int32_t s, t;
|
||||
converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
|
||||
portable_attribute_data[dst_index++] = s;
|
||||
portable_attribute_data[dst_index++] = t;
|
||||
}
|
||||
}
|
||||
|
||||
return portable_attribute;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace draco
|
||||
|
||||
@@ -37,19 +37,40 @@ class AttributeOctahedronTransform : public AttributeTransform {
|
||||
void CopyToAttributeTransformData(
|
||||
AttributeTransformData *out_data) const override;
|
||||
|
||||
bool TransformAttribute(const PointAttribute &attribute,
|
||||
const std::vector<PointIndex> &point_ids,
|
||||
PointAttribute *target_attribute) override;
|
||||
|
||||
bool InverseTransformAttribute(const PointAttribute &attribute,
|
||||
PointAttribute *target_attribute) override;
|
||||
|
||||
// Set number of quantization bits.
|
||||
void SetParameters(int quantization_bits);
|
||||
|
||||
// Encode relevant parameters into buffer.
|
||||
bool EncodeParameters(EncoderBuffer *encoder_buffer) const;
|
||||
bool EncodeParameters(EncoderBuffer *encoder_buffer) const override;
|
||||
|
||||
bool DecodeParameters(const PointAttribute &attribute,
|
||||
DecoderBuffer *decoder_buffer) override;
|
||||
|
||||
bool is_initialized() const { return quantization_bits_ != -1; }
|
||||
int32_t quantization_bits() const { return quantization_bits_; }
|
||||
|
||||
// Create portable attribute.
|
||||
std::unique_ptr<PointAttribute> GeneratePortableAttribute(
|
||||
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
|
||||
int num_points) const;
|
||||
protected:
|
||||
DataType GetTransformedDataType(
|
||||
const PointAttribute &attribute) const override {
|
||||
return DT_UINT32;
|
||||
}
|
||||
int GetTransformedNumComponents(
|
||||
const PointAttribute &attribute) const override {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Perform the actual transformation.
|
||||
bool GeneratePortableAttribute(const PointAttribute &attribute,
|
||||
const std::vector<PointIndex> &point_ids,
|
||||
int num_points,
|
||||
PointAttribute *target_attribute) const;
|
||||
|
||||
private:
|
||||
int32_t quantization_bits_;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
// Copyright 2017 The Draco Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -51,13 +50,74 @@ void AttributeQuantizationTransform::CopyToAttributeTransformData(
|
||||
out_data->AppendParameterValue(range_);
|
||||
}
|
||||
|
||||
void AttributeQuantizationTransform::SetParameters(int quantization_bits,
|
||||
bool AttributeQuantizationTransform::TransformAttribute(
|
||||
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
|
||||
PointAttribute *target_attribute) {
|
||||
if (point_ids.empty()) {
|
||||
GeneratePortableAttribute(attribute, target_attribute->size(),
|
||||
target_attribute);
|
||||
} else {
|
||||
GeneratePortableAttribute(attribute, point_ids, target_attribute->size(),
|
||||
target_attribute);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttributeQuantizationTransform::InverseTransformAttribute(
|
||||
const PointAttribute &attribute, PointAttribute *target_attribute) {
|
||||
if (target_attribute->data_type() != DT_FLOAT32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert all quantized values back to floats.
|
||||
const int32_t max_quantized_value =
|
||||
(1u << static_cast<uint32_t>(quantization_bits_)) - 1;
|
||||
const int num_components = target_attribute->num_components();
|
||||
const int entry_size = sizeof(float) * num_components;
|
||||
const std::unique_ptr<float[]> att_val(new float[num_components]);
|
||||
int quant_val_id = 0;
|
||||
int out_byte_pos = 0;
|
||||
Dequantizer dequantizer;
|
||||
if (!dequantizer.Init(range_, max_quantized_value)) {
|
||||
return false;
|
||||
}
|
||||
const int32_t *const source_attribute_data =
|
||||
reinterpret_cast<const int32_t *>(
|
||||
attribute.GetAddress(AttributeValueIndex(0)));
|
||||
|
||||
const int num_values = target_attribute->size();
|
||||
|
||||
for (uint32_t i = 0; i < num_values; ++i) {
|
||||
for (int c = 0; c < num_components; ++c) {
|
||||
float value =
|
||||
dequantizer.DequantizeFloat(source_attribute_data[quant_val_id++]);
|
||||
value = value + min_values_[c];
|
||||
att_val[c] = value;
|
||||
}
|
||||
// Store the floating point value into the attribute buffer.
|
||||
target_attribute->buffer()->Write(out_byte_pos, att_val.get(), entry_size);
|
||||
out_byte_pos += entry_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttributeQuantizationTransform::IsQuantizationValid(
|
||||
int quantization_bits) {
|
||||
// Currently we allow only up to 30 bit quantization.
|
||||
return quantization_bits >= 1 && quantization_bits <= 30;
|
||||
}
|
||||
|
||||
bool AttributeQuantizationTransform::SetParameters(int quantization_bits,
|
||||
const float *min_values,
|
||||
int num_components,
|
||||
float range) {
|
||||
if (!IsQuantizationValid(quantization_bits)) {
|
||||
return false;
|
||||
}
|
||||
quantization_bits_ = quantization_bits;
|
||||
min_values_.assign(min_values, min_values + num_components);
|
||||
range_ = range;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttributeQuantizationTransform::ComputeParameters(
|
||||
@@ -65,6 +125,9 @@ bool AttributeQuantizationTransform::ComputeParameters(
|
||||
if (quantization_bits_ != -1) {
|
||||
return false; // already initialized.
|
||||
}
|
||||
if (!IsQuantizationValid(quantization_bits)) {
|
||||
return false;
|
||||
}
|
||||
quantization_bits_ = quantization_bits;
|
||||
|
||||
const int num_components = attribute.num_components();
|
||||
@@ -121,20 +184,37 @@ bool AttributeQuantizationTransform::EncodeParameters(
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<PointAttribute>
|
||||
AttributeQuantizationTransform::GeneratePortableAttribute(
|
||||
const PointAttribute &attribute, int num_points) const {
|
||||
bool AttributeQuantizationTransform::DecodeParameters(
|
||||
const PointAttribute &attribute, DecoderBuffer *decoder_buffer) {
|
||||
min_values_.resize(attribute.num_components());
|
||||
if (!decoder_buffer->Decode(&min_values_[0],
|
||||
sizeof(float) * min_values_.size())) {
|
||||
return false;
|
||||
}
|
||||
if (!decoder_buffer->Decode(&range_)) {
|
||||
return false;
|
||||
}
|
||||
uint8_t quantization_bits;
|
||||
if (!decoder_buffer->Decode(&quantization_bits)) {
|
||||
return false;
|
||||
}
|
||||
if (!IsQuantizationValid(quantization_bits)) {
|
||||
return false;
|
||||
}
|
||||
quantization_bits_ = quantization_bits;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AttributeQuantizationTransform::GeneratePortableAttribute(
|
||||
const PointAttribute &attribute, int num_points,
|
||||
PointAttribute *target_attribute) const {
|
||||
DRACO_DCHECK(is_initialized());
|
||||
|
||||
// Allocate portable attribute.
|
||||
const int num_entries = num_points;
|
||||
const int num_components = attribute.num_components();
|
||||
std::unique_ptr<PointAttribute> portable_attribute =
|
||||
InitPortableAttribute(num_entries, num_components, 0, attribute, true);
|
||||
|
||||
// Quantize all values using the order given by point_ids.
|
||||
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
|
||||
portable_attribute->GetAddress(AttributeValueIndex(0)));
|
||||
target_attribute->GetAddress(AttributeValueIndex(0)));
|
||||
const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
|
||||
Quantizer quantizer;
|
||||
quantizer.Init(range(), max_quantized_value);
|
||||
@@ -149,24 +229,18 @@ AttributeQuantizationTransform::GeneratePortableAttribute(
|
||||
portable_attribute_data[dst_index++] = q_val;
|
||||
}
|
||||
}
|
||||
return portable_attribute;
|
||||
}
|
||||
|
||||
std::unique_ptr<PointAttribute>
|
||||
AttributeQuantizationTransform::GeneratePortableAttribute(
|
||||
void AttributeQuantizationTransform::GeneratePortableAttribute(
|
||||
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
|
||||
int num_points) const {
|
||||
int num_points, PointAttribute *target_attribute) const {
|
||||
DRACO_DCHECK(is_initialized());
|
||||
|
||||
// Allocate portable attribute.
|
||||
const int num_entries = static_cast<int>(point_ids.size());
|
||||
const int num_components = attribute.num_components();
|
||||
std::unique_ptr<PointAttribute> portable_attribute = InitPortableAttribute(
|
||||
num_entries, num_components, num_points, attribute, true);
|
||||
|
||||
// Quantize all values using the order given by point_ids.
|
||||
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
|
||||
portable_attribute->GetAddress(AttributeValueIndex(0)));
|
||||
target_attribute->GetAddress(AttributeValueIndex(0)));
|
||||
const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
|
||||
Quantizer quantizer;
|
||||
quantizer.Init(range(), max_quantized_value);
|
||||
@@ -181,7 +255,6 @@ AttributeQuantizationTransform::GeneratePortableAttribute(
|
||||
portable_attribute_data[dst_index++] = q_val;
|
||||
}
|
||||
}
|
||||
return portable_attribute;
|
||||
}
|
||||
|
||||
} // namespace draco
|
||||
|
||||
@@ -37,14 +37,24 @@ class AttributeQuantizationTransform : public AttributeTransform {
|
||||
void CopyToAttributeTransformData(
|
||||
AttributeTransformData *out_data) const override;
|
||||
|
||||
void SetParameters(int quantization_bits, const float *min_values,
|
||||
bool TransformAttribute(const PointAttribute &attribute,
|
||||
const std::vector<PointIndex> &point_ids,
|
||||
PointAttribute *target_attribute) override;
|
||||
|
||||
bool InverseTransformAttribute(const PointAttribute &attribute,
|
||||
PointAttribute *target_attribute) override;
|
||||
|
||||
bool SetParameters(int quantization_bits, const float *min_values,
|
||||
int num_components, float range);
|
||||
|
||||
bool ComputeParameters(const PointAttribute &attribute,
|
||||
const int quantization_bits);
|
||||
|
||||
// Encode relevant parameters into buffer.
|
||||
bool EncodeParameters(EncoderBuffer *encoder_buffer) const;
|
||||
bool EncodeParameters(EncoderBuffer *encoder_buffer) const override;
|
||||
|
||||
bool DecodeParameters(const PointAttribute &attribute,
|
||||
DecoderBuffer *decoder_buffer) override;
|
||||
|
||||
int32_t quantization_bits() const { return quantization_bits_; }
|
||||
float min_value(int axis) const { return min_values_[axis]; }
|
||||
@@ -52,16 +62,30 @@ class AttributeQuantizationTransform : public AttributeTransform {
|
||||
float range() const { return range_; }
|
||||
bool is_initialized() const { return quantization_bits_ != -1; }
|
||||
|
||||
protected:
|
||||
// Create portable attribute using 1:1 mapping between points in the input and
|
||||
// output attribute.
|
||||
std::unique_ptr<PointAttribute> GeneratePortableAttribute(
|
||||
const PointAttribute &attribute, int num_points) const;
|
||||
void GeneratePortableAttribute(const PointAttribute &attribute,
|
||||
int num_points,
|
||||
PointAttribute *target_attribute) const;
|
||||
|
||||
// Create portable attribute using custom mapping between input and output
|
||||
// points.
|
||||
std::unique_ptr<PointAttribute> GeneratePortableAttribute(
|
||||
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
|
||||
int num_points) const;
|
||||
void GeneratePortableAttribute(const PointAttribute &attribute,
|
||||
const std::vector<PointIndex> &point_ids,
|
||||
int num_points,
|
||||
PointAttribute *target_attribute) const;
|
||||
|
||||
DataType GetTransformedDataType(
|
||||
const PointAttribute &attribute) const override {
|
||||
return DT_UINT32;
|
||||
}
|
||||
int GetTransformedNumComponents(
|
||||
const PointAttribute &attribute) const override {
|
||||
return attribute.num_components();
|
||||
}
|
||||
|
||||
static bool IsQuantizationValid(int quantization_bits);
|
||||
|
||||
private:
|
||||
int32_t quantization_bits_;
|
||||
|
||||
@@ -24,21 +24,18 @@ bool AttributeTransform::TransferToAttribute(PointAttribute *attribute) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<PointAttribute> AttributeTransform::InitPortableAttribute(
|
||||
int num_entries, int num_components, int num_points,
|
||||
const PointAttribute &attribute, bool is_unsigned) const {
|
||||
const DataType dt = is_unsigned ? DT_UINT32 : DT_INT32;
|
||||
GeometryAttribute va;
|
||||
va.Init(attribute.attribute_type(), nullptr, num_components, dt, false,
|
||||
std::unique_ptr<PointAttribute> AttributeTransform::InitTransformedAttribute(
|
||||
const PointAttribute &src_attribute, int num_entries) {
|
||||
const int num_components = GetTransformedNumComponents(src_attribute);
|
||||
const DataType dt = GetTransformedDataType(src_attribute);
|
||||
GeometryAttribute ga;
|
||||
ga.Init(src_attribute.attribute_type(), nullptr, num_components, dt, false,
|
||||
num_components * DataTypeLength(dt), 0);
|
||||
std::unique_ptr<PointAttribute> portable_attribute(new PointAttribute(va));
|
||||
portable_attribute->Reset(num_entries);
|
||||
if (num_points) {
|
||||
portable_attribute->SetExplicitMapping(num_points);
|
||||
} else {
|
||||
portable_attribute->SetIdentityMapping();
|
||||
}
|
||||
return portable_attribute;
|
||||
std::unique_ptr<PointAttribute> transformed_attribute(new PointAttribute(ga));
|
||||
transformed_attribute->Reset(num_entries);
|
||||
transformed_attribute->SetIdentityMapping();
|
||||
transformed_attribute->set_unique_id(src_attribute.unique_id());
|
||||
return transformed_attribute;
|
||||
}
|
||||
|
||||
} // namespace draco
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "draco/attributes/attribute_transform_data.h"
|
||||
#include "draco/attributes/point_attribute.h"
|
||||
#include "draco/core/decoder_buffer.h"
|
||||
#include "draco/core/encoder_buffer.h"
|
||||
|
||||
namespace draco {
|
||||
|
||||
@@ -35,10 +37,38 @@ class AttributeTransform {
|
||||
AttributeTransformData *out_data) const = 0;
|
||||
bool TransferToAttribute(PointAttribute *attribute) const;
|
||||
|
||||
// Applies the transform to |attribute| and stores the result in
|
||||
// |target_attribute|. |point_ids| is an optional vector that can be used to
|
||||
// remap values during the transform.
|
||||
virtual bool TransformAttribute(const PointAttribute &attribute,
|
||||
const std::vector<PointIndex> &point_ids,
|
||||
PointAttribute *target_attribute) = 0;
|
||||
|
||||
// Applies an inverse transform to |attribute| and stores the result in
|
||||
// |target_attribute|. In this case, |attribute| is an attribute that was
|
||||
// already transformed (e.g. quantized) and |target_attribute| is the
|
||||
// attribute before the transformation.
|
||||
virtual bool InverseTransformAttribute(const PointAttribute &attribute,
|
||||
PointAttribute *target_attribute) = 0;
|
||||
|
||||
// Encodes all data needed by the transformation into the |encoder_buffer|.
|
||||
virtual bool EncodeParameters(EncoderBuffer *encoder_buffer) const = 0;
|
||||
|
||||
// Decodes all data needed to transform |attribute| back to the original
|
||||
// format.
|
||||
virtual bool DecodeParameters(const PointAttribute &attribute,
|
||||
DecoderBuffer *decoder_buffer) = 0;
|
||||
|
||||
// Initializes a transformed attribute that can be used as target in the
|
||||
// TransformAttribute() function call.
|
||||
virtual std::unique_ptr<PointAttribute> InitTransformedAttribute(
|
||||
const PointAttribute &src_attribute, int num_entries);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<PointAttribute> InitPortableAttribute(
|
||||
int num_entries, int num_components, int num_points,
|
||||
const PointAttribute &attribute, bool is_unsigned) const;
|
||||
virtual DataType GetTransformedDataType(
|
||||
const PointAttribute &attribute) const = 0;
|
||||
virtual int GetTransformedNumComponents(
|
||||
const PointAttribute &attribute) const = 0;
|
||||
};
|
||||
|
||||
} // namespace draco
|
||||
|
||||
@@ -43,10 +43,6 @@ void GeometryAttribute::Init(GeometryAttribute::Type attribute_type,
|
||||
}
|
||||
|
||||
bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) {
|
||||
if (buffer_ == nullptr || src_att.buffer_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size());
|
||||
num_components_ = src_att.num_components_;
|
||||
data_type_ = src_att.data_type_;
|
||||
normalized_ = src_att.normalized_;
|
||||
@@ -55,6 +51,14 @@ bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) {
|
||||
attribute_type_ = src_att.attribute_type_;
|
||||
buffer_descriptor_ = src_att.buffer_descriptor_;
|
||||
unique_id_ = src_att.unique_id_;
|
||||
if (src_att.buffer_ == nullptr) {
|
||||
buffer_ = nullptr;
|
||||
} else {
|
||||
if (buffer_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "draco/attributes/geometry_indices.h"
|
||||
#include "draco/core/data_buffer.h"
|
||||
#include "draco/core/hash_utils.h"
|
||||
#include "draco/draco_features.h"
|
||||
|
||||
namespace draco {
|
||||
|
||||
@@ -51,6 +52,16 @@ class GeometryAttribute {
|
||||
// predefined use case. Such attributes are often used for a shader specific
|
||||
// data.
|
||||
GENERIC,
|
||||
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||
// TODO(ostava): Adding a new attribute would be bit-stream change for GLTF.
|
||||
// Older decoders wouldn't know what to do with this attribute type. This
|
||||
// should be open-sourced only when we are ready to increase our bit-stream
|
||||
// version.
|
||||
TANGENT,
|
||||
MATERIAL,
|
||||
JOINTS,
|
||||
WEIGHTS,
|
||||
#endif
|
||||
// Total number of different attribute types.
|
||||
// Always keep behind all named attributes.
|
||||
NAMED_ATTRIBUTES_COUNT,
|
||||
@@ -111,6 +122,9 @@ class GeometryAttribute {
|
||||
const int64_t byte_pos = GetBytePos(att_index);
|
||||
return buffer_->data() + byte_pos;
|
||||
}
|
||||
inline bool IsAddressValid(const uint8_t *address) const {
|
||||
return ((buffer_->data() + buffer_->data_size()) > address);
|
||||
}
|
||||
|
||||
// Fills out_data with the raw value of the requested attribute entry.
|
||||
// out_data must be at least byte_stride_ long.
|
||||
@@ -263,7 +277,35 @@ class GeometryAttribute {
|
||||
|
||||
// Convert all components available in both the original and output formats.
|
||||
for (int i = 0; i < std::min(num_components_, out_num_components); ++i) {
|
||||
if (!IsAddressValid(src_address)) {
|
||||
return false;
|
||||
}
|
||||
const T in_value = *reinterpret_cast<const T *>(src_address);
|
||||
|
||||
// Make sure the in_value fits within the range of values that OutT
|
||||
// is able to represent. Perform the check only for integral types.
|
||||
if (std::is_integral<T>::value && std::is_integral<OutT>::value) {
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4804)
|
||||
#endif
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wbool-compare"
|
||||
#endif
|
||||
static constexpr OutT kOutMin =
|
||||
std::is_signed<T>::value ? std::numeric_limits<OutT>::lowest() : 0;
|
||||
if (in_value < kOutMin || in_value > std::numeric_limits<OutT>::max()) {
|
||||
return false;
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
out_value[i] = static_cast<OutT>(in_value);
|
||||
// When converting integer to floating point, normalize the value if
|
||||
// necessary.
|
||||
|
||||
@@ -222,4 +222,47 @@ AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||
void PointAttribute::RemoveUnusedValues() {
|
||||
if (is_mapping_identity()) {
|
||||
return; // For identity mapping, all values are always used.
|
||||
}
|
||||
// For explicit mapping we need to check if any point is mapped to a value.
|
||||
// If not we can delete the value.
|
||||
IndexTypeVector<AttributeValueIndex, bool> is_value_used(size(), false);
|
||||
int num_used_values = 0;
|
||||
for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
|
||||
const AttributeValueIndex avi = indices_map_[pi];
|
||||
if (!is_value_used[avi]) {
|
||||
is_value_used[avi] = true;
|
||||
num_used_values++;
|
||||
}
|
||||
}
|
||||
if (num_used_values == size()) {
|
||||
return; // All values are used.
|
||||
}
|
||||
|
||||
// Remap the values and update the point to value mapping.
|
||||
IndexTypeVector<AttributeValueIndex, AttributeValueIndex>
|
||||
old_to_new_value_map(size(), kInvalidAttributeValueIndex);
|
||||
AttributeValueIndex new_avi(0);
|
||||
for (AttributeValueIndex avi(0); avi < size(); ++avi) {
|
||||
if (!is_value_used[avi]) {
|
||||
continue;
|
||||
}
|
||||
if (avi != new_avi) {
|
||||
SetAttributeValue(new_avi, GetAddress(avi));
|
||||
}
|
||||
old_to_new_value_map[avi] = new_avi++;
|
||||
}
|
||||
|
||||
// Remap all points to the new attribute values.
|
||||
for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
|
||||
indices_map_[pi] = old_to_new_value_map[indices_map_[pi]];
|
||||
}
|
||||
|
||||
num_unique_entries_ = num_used_values;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace draco
|
||||
|
||||
@@ -133,6 +133,12 @@ class PointAttribute : public GeometryAttribute {
|
||||
return attribute_transform_data_.get();
|
||||
}
|
||||
|
||||
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||
// Removes unused values from the attribute. Value is unused when no point
|
||||
// is mapped to the value. Only applicable when the mapping is not identity.
|
||||
void RemoveUnusedValues();
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
|
||||
template <typename T>
|
||||
|
||||
@@ -43,9 +43,18 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that decoded number of attributes is valid.
|
||||
if (num_attributes == 0) {
|
||||
return false;
|
||||
}
|
||||
if (num_attributes > 5 * in_buffer->remaining_size()) {
|
||||
// The decoded number of attributes is unreasonably high, because at least
|
||||
// five bytes of attribute descriptor data per attribute are expected.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode attribute descriptor data.
|
||||
point_attribute_ids_.resize(num_attributes);
|
||||
PointCloud *pc = point_cloud_;
|
||||
for (uint32_t i = 0; i < num_attributes; ++i) {
|
||||
@@ -69,9 +78,14 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
|
||||
if (data_type == DT_INVALID || data_type >= DT_TYPES_COUNT) {
|
||||
return false;
|
||||
}
|
||||
const DataType draco_dt = static_cast<DataType>(data_type);
|
||||
|
||||
// Add the attribute to the point cloud
|
||||
// Check decoded attribute descriptor data.
|
||||
if (num_components == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the attribute to the point cloud.
|
||||
const DataType draco_dt = static_cast<DataType>(data_type);
|
||||
GeometryAttribute ga;
|
||||
ga.Init(static_cast<GeometryAttribute::Type>(att_type), nullptr,
|
||||
num_components, draco_dt, normalized > 0,
|
||||
@@ -90,7 +104,9 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
DecodeVarint(&unique_id, in_buffer);
|
||||
if (!DecodeVarint(&unique_id, in_buffer)) {
|
||||
return false;
|
||||
}
|
||||
ga.set_unique_id(unique_id);
|
||||
}
|
||||
const int att_id = pc->AddAttribute(
|
||||
|
||||
@@ -15,14 +15,16 @@
|
||||
#include "draco/compression/attributes/attributes_encoder.h"
|
||||
|
||||
#include "draco/core/varint_encoding.h"
|
||||
#include "draco/draco_features.h"
|
||||
|
||||
namespace draco {
|
||||
|
||||
AttributesEncoder::AttributesEncoder()
|
||||
: point_cloud_encoder_(nullptr), point_cloud_(nullptr) {}
|
||||
|
||||
AttributesEncoder::AttributesEncoder(int att_id) : AttributesEncoder() {
|
||||
AddAttributeId(att_id);
|
||||
AttributesEncoder::AttributesEncoder(int point_attrib_id)
|
||||
: AttributesEncoder() {
|
||||
AddAttributeId(point_attrib_id);
|
||||
}
|
||||
|
||||
bool AttributesEncoder::Init(PointCloudEncoder *encoder, const PointCloud *pc) {
|
||||
@@ -37,7 +39,15 @@ bool AttributesEncoder::EncodeAttributesEncoderData(EncoderBuffer *out_buffer) {
|
||||
for (uint32_t i = 0; i < num_attributes(); ++i) {
|
||||
const int32_t att_id = point_attribute_ids_[i];
|
||||
const PointAttribute *const pa = point_cloud_->attribute(att_id);
|
||||
out_buffer->Encode(static_cast<uint8_t>(pa->attribute_type()));
|
||||
GeometryAttribute::Type type = pa->attribute_type();
|
||||
#ifdef DRACO_TRANSCODER_SUPPORTED
|
||||
// Attribute types TANGENT, MATERIAL, JOINTS, and WEIGHTS are not supported
|
||||
// in the official bitstream. They will be encoded as GENERIC.
|
||||
if (type > GeometryAttribute::GENERIC) {
|
||||
type = GeometryAttribute::GENERIC;
|
||||
}
|
||||
#endif
|
||||
out_buffer->Encode(static_cast<uint8_t>(type));
|
||||
out_buffer->Encode(static_cast<uint8_t>(pa->data_type()));
|
||||
out_buffer->Encode(static_cast<uint8_t>(pa->num_components()));
|
||||
out_buffer->Encode(static_cast<uint8_t>(pa->normalized()));
|
||||
|
||||
@@ -72,7 +72,7 @@ class PointAttributeVectorOutputIterator {
|
||||
|
||||
Self &operator*() { return *this; }
|
||||
// Still needed in some cases.
|
||||
// TODO(hemmer): remove.
|
||||
// TODO(b/199760123): Remove.
|
||||
// hardcoded to 3 based on legacy usage.
|
||||
const Self &operator=(const VectorD<CoeffT, 3> &val) {
|
||||
DRACO_DCHECK_EQ(attributes_.size(), 1); // Expect only ONE attribute.
|
||||
@@ -278,8 +278,10 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
||||
return false;
|
||||
}
|
||||
AttributeQuantizationTransform transform;
|
||||
transform.SetParameters(quantization_bits, min_value.data(),
|
||||
num_components, max_value_dif);
|
||||
if (!transform.SetParameters(quantization_bits, min_value.data(),
|
||||
num_components, max_value_dif)) {
|
||||
return false;
|
||||
}
|
||||
const int num_transforms =
|
||||
static_cast<int>(attribute_quantization_transforms_.size());
|
||||
if (!transform.TransferToAttribute(
|
||||
@@ -293,7 +295,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
||||
// Decode transform data for signed integer attributes.
|
||||
for (int i = 0; i < min_signed_values_.size(); ++i) {
|
||||
int32_t val;
|
||||
DecodeVarint(&val, in_buffer);
|
||||
if (!DecodeVarint(&val, in_buffer)) {
|
||||
return false;
|
||||
}
|
||||
min_signed_values_[i] = val;
|
||||
}
|
||||
return true;
|
||||
@@ -353,8 +357,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
||||
return false;
|
||||
}
|
||||
if (6 < compression_level) {
|
||||
LOGE("KdTreeAttributesDecoder: compression level %i not supported.\n",
|
||||
compression_level);
|
||||
DRACO_LOGE(
|
||||
"KdTreeAttributesDecoder: compression level %i not supported.\n",
|
||||
compression_level);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -371,7 +376,7 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
|
||||
GetDecoder()->point_cloud()->attribute(att_id);
|
||||
attr->Reset(num_points);
|
||||
attr->SetIdentityMapping();
|
||||
};
|
||||
}
|
||||
|
||||
PointAttributeVectorOutputIterator<uint32_t> out_it(atts);
|
||||
|
||||
|
||||
@@ -71,16 +71,21 @@ bool KdTreeAttributesEncoder::TransformAttributesToPortableFormat() {
|
||||
att->num_components(), range);
|
||||
} else {
|
||||
// Compute quantization settings from the attribute values.
|
||||
attribute_quantization_transform.ComputeParameters(*att,
|
||||
quantization_bits);
|
||||
if (!attribute_quantization_transform.ComputeParameters(
|
||||
*att, quantization_bits)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
attribute_quantization_transforms_.push_back(
|
||||
attribute_quantization_transform);
|
||||
// Store the quantized attribute in an array that will be used when we do
|
||||
// the actual encoding of the data.
|
||||
quantized_portable_attributes_.push_back(
|
||||
attribute_quantization_transform.GeneratePortableAttribute(
|
||||
*att, static_cast<int>(num_points)));
|
||||
auto portable_att =
|
||||
attribute_quantization_transform.InitTransformedAttribute(*att,
|
||||
num_points);
|
||||
attribute_quantization_transform.TransformAttribute(*att, {},
|
||||
portable_att.get());
|
||||
quantized_portable_attributes_.push_back(std::move(portable_att));
|
||||
} else if (att->data_type() == DT_INT32 || att->data_type() == DT_INT16 ||
|
||||
att->data_type() == DT_INT8) {
|
||||
// For signed types, find the minimum value for each component. These
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_
|
||||
#define DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_
|
||||
#ifndef DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_
|
||||
#define DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_
|
||||
|
||||
#include "draco/attributes/attribute_quantization_transform.h"
|
||||
#include "draco/compression/attributes/attributes_encoder.h"
|
||||
@@ -48,4 +48,4 @@ class KdTreeAttributesEncoder : public AttributesEncoder {
|
||||
|
||||
} // namespace draco
|
||||
|
||||
#endif // DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_
|
||||
#endif // DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_
|
||||
|
||||
@@ -53,6 +53,7 @@ class OctahedronToolBox {
|
||||
: quantization_bits_(-1),
|
||||
max_quantized_value_(-1),
|
||||
max_value_(-1),
|
||||
dequantization_scale_(1.f),
|
||||
center_value_(-1) {}
|
||||
|
||||
bool SetQuantizationBits(int32_t q) {
|
||||
@@ -62,6 +63,7 @@ class OctahedronToolBox {
|
||||
quantization_bits_ = q;
|
||||
max_quantized_value_ = (1 << quantization_bits_) - 1;
|
||||
max_value_ = max_quantized_value_ - 1;
|
||||
dequantization_scale_ = 2.f / max_value_;
|
||||
center_value_ = max_value_ / 2;
|
||||
return true;
|
||||
}
|
||||
@@ -192,64 +194,11 @@ class OctahedronToolBox {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/149328891): Change function to not use templates as |T| is only
|
||||
// float.
|
||||
template <typename T>
|
||||
void OctaherdalCoordsToUnitVector(T in_s, T in_t, T *out_vector) const {
|
||||
DRACO_DCHECK_GE(in_s, 0);
|
||||
DRACO_DCHECK_GE(in_t, 0);
|
||||
DRACO_DCHECK_LE(in_s, 1);
|
||||
DRACO_DCHECK_LE(in_t, 1);
|
||||
T s = in_s;
|
||||
T t = in_t;
|
||||
T spt = s + t;
|
||||
T smt = s - t;
|
||||
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 {
|
||||
// Left hemisphere.
|
||||
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;
|
||||
}
|
||||
const T y = 2.0 * s - 1.0;
|
||||
const T z = 2.0 * t - 1.0;
|
||||
const T 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;
|
||||
// Normalize the computed vector.
|
||||
const T 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 T d = 1.0 / std::sqrt(normSquared);
|
||||
out_vector[0] = x * d;
|
||||
out_vector[1] = y * d;
|
||||
out_vector[2] = z * d;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void QuantizedOctaherdalCoordsToUnitVector(int32_t in_s, int32_t in_t,
|
||||
T *out_vector) const {
|
||||
T scale = 1.0 / static_cast<T>(max_value_);
|
||||
OctaherdalCoordsToUnitVector(in_s * scale, in_t * scale, out_vector);
|
||||
inline void QuantizedOctahedralCoordsToUnitVector(int32_t in_s, int32_t in_t,
|
||||
float *out_vector) const {
|
||||
OctahedralCoordsToUnitVector(in_s * dequantization_scale_ - 1.f,
|
||||
in_t * dequantization_scale_ - 1.f,
|
||||
out_vector);
|
||||
}
|
||||
|
||||
// |s| and |t| are expected to be signed values.
|
||||
@@ -333,9 +282,77 @@ class OctahedronToolBox {
|
||||
int32_t center_value() const { return center_value_; }
|
||||
|
||||
private:
|
||||
inline void OctahedralCoordsToUnitVector(float in_s_scaled, float in_t_scaled,
|
||||
float *out_vector) const {
|
||||
// Background about the encoding:
|
||||
// A normal is encoded in a normalized space <s, t> depicted below. The
|
||||
// encoding correponds to an octahedron that is unwrapped to a 2D plane.
|
||||
// During encoding, a normal is projected to the surface of the octahedron
|
||||
// and the projection is then unwrapped to the 2D plane. Decoding is the
|
||||
// reverse of this process.
|
||||
// All points in the central diamond are located on triangles on the
|
||||
// right "hemisphere" of the octahedron while all points outside of the
|
||||
// diamond are on the left hemisphere (basically, they would have to be
|
||||
// wrapped along the diagonal edges to form the octahedron). The central
|
||||
// point corresponds to the right most vertex of the octahedron and all
|
||||
// corners of the plane correspond to the left most vertex of the
|
||||
// octahedron.
|
||||
//
|
||||
// t
|
||||
// ^ *-----*-----*
|
||||
// | | /|\ |
|
||||
// | / | \ |
|
||||
// | / | \ |
|
||||
// | / | \ |
|
||||
// *-----*---- *
|
||||
// | \ | / |
|
||||
// | \ | / |
|
||||
// | \ | / |
|
||||
// | \|/ |
|
||||
// *-----*-----* --> s
|
||||
|
||||
// Note that the input |in_s_scaled| and |in_t_scaled| are already scaled to
|
||||
// <-1, 1> range. This way, the central point is at coordinate (0, 0).
|
||||
float y = in_s_scaled;
|
||||
float z = in_t_scaled;
|
||||
|
||||
// Remaining coordinate can be computed by projecting the (y, z) values onto
|
||||
// the surface of the octahedron.
|
||||
const float x = 1.f - std::abs(y) - std::abs(z);
|
||||
|
||||
// |x| is essentially a signed distance from the diagonal edges of the
|
||||
// diamond shown on the figure above. It is positive for all points in the
|
||||
// diamond (right hemisphere) and negative for all points outside the
|
||||
// diamond (left hemisphere). For all points on the left hemisphere we need
|
||||
// to update their (y, z) coordinates to account for the wrapping along
|
||||
// the edges of the diamond.
|
||||
float x_offset = -x;
|
||||
x_offset = x_offset < 0 ? 0 : x_offset;
|
||||
|
||||
// This will do nothing for the points on the right hemisphere but it will
|
||||
// mirror the (y, z) location along the nearest diagonal edge of the
|
||||
// diamond.
|
||||
y += y < 0 ? x_offset : -x_offset;
|
||||
z += z < 0 ? x_offset : -x_offset;
|
||||
|
||||
// Normalize the computed vector.
|
||||
const float norm_squared = x * x + y * y + z * z;
|
||||
if (norm_squared < 1e-6) {
|
||||
out_vector[0] = 0;
|
||||
out_vector[1] = 0;
|
||||
out_vector[2] = 0;
|
||||
} else {
|
||||
const float d = 1.0f / std::sqrt(norm_squared);
|
||||
out_vector[0] = x * d;
|
||||
out_vector[1] = y * d;
|
||||
out_vector[2] = z * d;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t quantization_bits_;
|
||||
int32_t max_quantized_value_;
|
||||
int32_t max_value_;
|
||||
float dequantization_scale_;
|
||||
int32_t center_value_;
|
||||
};
|
||||
} // namespace draco
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_
|
||||
#define DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_
|
||||
#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_
|
||||
#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_
|
||||
|
||||
#include "draco/mesh/corner_table.h"
|
||||
#include "draco/mesh/mesh.h"
|
||||
|
||||
@@ -69,7 +69,14 @@ class MeshPredictionSchemeGeometricNormalPredictorArea
|
||||
|
||||
// Computing cross product.
|
||||
const VectorD<int64_t, 3> cross = CrossProduct(delta_next, delta_prev);
|
||||
normal = normal + cross;
|
||||
|
||||
// Prevent signed integer overflows by doing math as unsigned.
|
||||
auto normal_data = reinterpret_cast<uint64_t *>(normal.data());
|
||||
auto cross_data = reinterpret_cast<const uint64_t *>(cross.data());
|
||||
normal_data[0] = normal_data[0] + cross_data[0];
|
||||
normal_data[1] = normal_data[1] + cross_data[1];
|
||||
normal_data[2] = normal_data[2] + cross_data[2];
|
||||
|
||||
cit.Next();
|
||||
}
|
||||
|
||||
|
||||
@@ -60,8 +60,13 @@ inline bool ComputeParallelogramPrediction(
|
||||
const int v_next_off = vert_next * num_components;
|
||||
const int v_prev_off = vert_prev * num_components;
|
||||
for (int 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];
|
||||
const int64_t in_data_next_off = in_data[v_next_off + c];
|
||||
const int64_t in_data_prev_off = in_data[v_prev_off + c];
|
||||
const int64_t in_data_opp_off = in_data[v_opp_off + c];
|
||||
const int64_t result =
|
||||
(in_data_next_off + in_data_prev_off) - in_data_opp_off;
|
||||
|
||||
out_prediction[c] = static_cast<DataTypeT>(result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,13 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
|
||||
const VectorD<int64_t, 2> x_uv =
|
||||
n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv);
|
||||
|
||||
const int64_t pn_absmax_element =
|
||||
std::max(std::max(std::abs(pn[0]), std::abs(pn[1])), std::abs(pn[2]));
|
||||
if (cn_dot_pn > std::numeric_limits<int64_t>::max() / pn_absmax_element) {
|
||||
// return false if squared length calculation would overflow.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute squared length of vector CX in position coordinate system:
|
||||
const VectorD<int64_t, 3> x_pos =
|
||||
next_pos + (cn_dot_pn * pn) / pn_norm2_squared;
|
||||
|
||||
@@ -18,34 +18,51 @@ namespace draco {
|
||||
|
||||
PredictionSchemeMethod SelectPredictionMethod(
|
||||
int att_id, const PointCloudEncoder *encoder) {
|
||||
if (encoder->options()->GetSpeed() >= 10) {
|
||||
return SelectPredictionMethod(att_id, *encoder->options(), encoder);
|
||||
}
|
||||
|
||||
PredictionSchemeMethod SelectPredictionMethod(
|
||||
int att_id, const EncoderOptions &options,
|
||||
const PointCloudEncoder *encoder) {
|
||||
if (options.GetSpeed() >= 10) {
|
||||
// Selected fastest, though still doing some compression.
|
||||
return PREDICTION_DIFFERENCE;
|
||||
}
|
||||
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
|
||||
// Use speed setting to select the best encoding method.
|
||||
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
|
||||
if (att->attribute_type() == GeometryAttribute::TEX_COORD) {
|
||||
if (encoder->options()->GetSpeed() < 4) {
|
||||
if (att->attribute_type() == GeometryAttribute::TEX_COORD &&
|
||||
att->num_components() == 2) {
|
||||
if (options.GetSpeed() < 4) {
|
||||
// Use texture coordinate prediction for speeds 0, 1, 2, 3.
|
||||
return MESH_PREDICTION_TEX_COORDS_PORTABLE;
|
||||
}
|
||||
}
|
||||
if (att->attribute_type() == GeometryAttribute::NORMAL) {
|
||||
#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
|
||||
if (encoder->options()->GetSpeed() < 4) {
|
||||
if (options.GetSpeed() < 4) {
|
||||
// Use geometric normal prediction for speeds 0, 1, 2, 3.
|
||||
return MESH_PREDICTION_GEOMETRIC_NORMAL;
|
||||
// For this prediction, the position attribute needs to be either
|
||||
// integer or quantized as well.
|
||||
const int pos_att_id = encoder->point_cloud()->GetNamedAttributeId(
|
||||
GeometryAttribute::POSITION);
|
||||
const PointAttribute *const pos_att =
|
||||
encoder->point_cloud()->GetNamedAttribute(
|
||||
GeometryAttribute::POSITION);
|
||||
if (pos_att && (IsDataTypeIntegral(pos_att->data_type()) ||
|
||||
options.GetAttributeInt(pos_att_id, "quantization_bits",
|
||||
-1) > 0)) {
|
||||
return MESH_PREDICTION_GEOMETRIC_NORMAL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return PREDICTION_DIFFERENCE; // default
|
||||
}
|
||||
// Handle other attribute types.
|
||||
if (encoder->options()->GetSpeed() >= 8) {
|
||||
if (options.GetSpeed() >= 8) {
|
||||
return PREDICTION_DIFFERENCE;
|
||||
}
|
||||
if (encoder->options()->GetSpeed() >= 2 ||
|
||||
encoder->point_cloud()->num_points() < 40) {
|
||||
if (options.GetSpeed() >= 2 || encoder->point_cloud()->num_points() < 40) {
|
||||
// Parallelogram prediction is used for speeds 2 - 7 or when the overhead
|
||||
// of using constrained multi-parallelogram would be too high.
|
||||
return MESH_PREDICTION_PARALLELOGRAM;
|
||||
|
||||
@@ -38,6 +38,10 @@ namespace draco {
|
||||
PredictionSchemeMethod SelectPredictionMethod(int att_id,
|
||||
const PointCloudEncoder *encoder);
|
||||
|
||||
PredictionSchemeMethod SelectPredictionMethod(int att_id,
|
||||
const EncoderOptions &options,
|
||||
const PointCloudEncoder *encoder);
|
||||
|
||||
// Factory class for creating mesh prediction schemes.
|
||||
template <typename DataTypeT>
|
||||
struct MeshPredictionSchemeEncoderFactory {
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_
|
||||
#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_
|
||||
#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_
|
||||
#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_
|
||||
|
||||
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h"
|
||||
#include "draco/core/encoder_buffer.h"
|
||||
@@ -52,4 +52,4 @@ class PredictionSchemeTypedEncoderInterface
|
||||
|
||||
} // namespace draco
|
||||
|
||||
#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_
|
||||
#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_
|
||||
|
||||
@@ -36,9 +36,25 @@ class PredictionSchemeWrapDecodingTransform
|
||||
inline void ComputeOriginalValue(const DataTypeT *predicted_vals,
|
||||
const CorrTypeT *corr_vals,
|
||||
DataTypeT *out_original_vals) const {
|
||||
// For now we assume both |DataTypeT| and |CorrTypeT| are equal.
|
||||
static_assert(std::is_same<DataTypeT, CorrTypeT>::value,
|
||||
"Predictions and corrections must have the same type.");
|
||||
|
||||
// The only valid implementation right now is for int32_t.
|
||||
static_assert(std::is_same<DataTypeT, int32_t>::value,
|
||||
"Only int32_t is supported for predicted values.");
|
||||
|
||||
predicted_vals = this->ClampPredictedValue(predicted_vals);
|
||||
|
||||
// Perform the wrapping using unsigned coordinates to avoid potential signed
|
||||
// integer overflows caused by malformed input.
|
||||
const uint32_t *const uint_predicted_vals =
|
||||
reinterpret_cast<const uint32_t *>(predicted_vals);
|
||||
const uint32_t *const uint_corr_vals =
|
||||
reinterpret_cast<const uint32_t *>(corr_vals);
|
||||
for (int i = 0; i < this->num_components(); ++i) {
|
||||
out_original_vals[i] = predicted_vals[i] + corr_vals[i];
|
||||
out_original_vals[i] =
|
||||
static_cast<DataTypeT>(uint_predicted_vals[i] + uint_corr_vals[i]);
|
||||
if (out_original_vals[i] > this->max_value()) {
|
||||
out_original_vals[i] -= this->max_dif();
|
||||
} else if (out_original_vals[i] < this->min_value()) {
|
||||
|
||||
@@ -73,7 +73,7 @@ class PredictionSchemeWrapTransformBase {
|
||||
return &clamped_value_[0];
|
||||
}
|
||||
|
||||
// TODO(hemmer): Consider refactoring to avoid this dummy.
|
||||
// TODO(b/199760123): Consider refactoring to avoid this dummy.
|
||||
int quantization_bits() const {
|
||||
DRACO_DCHECK(false);
|
||||
return -1;
|
||||
|
||||
@@ -26,8 +26,8 @@ SequentialAttributeEncodersController::SequentialAttributeEncodersController(
|
||||
: sequencer_(std::move(sequencer)) {}
|
||||
|
||||
SequentialAttributeEncodersController::SequentialAttributeEncodersController(
|
||||
std::unique_ptr<PointsSequencer> sequencer, int att_id)
|
||||
: AttributesEncoder(att_id), sequencer_(std::move(sequencer)) {}
|
||||
std::unique_ptr<PointsSequencer> sequencer, int point_attrib_id)
|
||||
: AttributesEncoder(point_attrib_id), sequencer_(std::move(sequencer)) {}
|
||||
|
||||
bool SequentialAttributeEncodersController::Init(PointCloudEncoder *encoder,
|
||||
const PointCloud *pc) {
|
||||
|
||||
@@ -53,6 +53,11 @@ bool SequentialIntegerAttributeDecoder::DecodeValues(
|
||||
if (!in_buffer->Decode(&prediction_transform_type)) {
|
||||
return false;
|
||||
}
|
||||
// Check that decoded prediction scheme transform type is valid.
|
||||
if (prediction_transform_type < PREDICTION_TRANSFORM_NONE ||
|
||||
prediction_transform_type >= NUM_PREDICTION_SCHEME_TRANSFORM_TYPES) {
|
||||
return false;
|
||||
}
|
||||
prediction_scheme_ = CreateIntPredictionScheme(
|
||||
static_cast<PredictionSchemeMethod>(prediction_scheme_method),
|
||||
static_cast<PredictionSchemeTransformType>(prediction_transform_type));
|
||||
@@ -143,8 +148,9 @@ bool SequentialIntegerAttributeDecoder::DecodeIntegerValues(
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < num_values; ++i) {
|
||||
if (!in_buffer->Decode(portable_attribute_data + i, num_bytes))
|
||||
if (!in_buffer->Decode(portable_attribute_data + i, num_bytes)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,12 +229,13 @@ void SequentialIntegerAttributeDecoder::StoreTypedValues(uint32_t num_values) {
|
||||
|
||||
void SequentialIntegerAttributeDecoder::PreparePortableAttribute(
|
||||
int num_entries, int num_components) {
|
||||
GeometryAttribute va;
|
||||
va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
|
||||
GeometryAttribute ga;
|
||||
ga.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
|
||||
false, num_components * DataTypeLength(DT_INT32), 0);
|
||||
std::unique_ptr<PointAttribute> port_att(new PointAttribute(va));
|
||||
std::unique_ptr<PointAttribute> port_att(new PointAttribute(ga));
|
||||
port_att->SetIdentityMapping();
|
||||
port_att->Reset(num_entries);
|
||||
port_att->set_unique_id(attribute()->unique_id());
|
||||
SetPortableAttribute(std::move(port_att));
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,9 @@ bool SequentialIntegerAttributeEncoder::TransformAttributeToPortableFormat(
|
||||
value_to_value_map[orig_att->mapped_index(point_ids[i])] =
|
||||
AttributeValueIndex(i);
|
||||
}
|
||||
if (portable_att->is_mapping_identity()) {
|
||||
portable_att->SetExplicitMapping(encoder()->point_cloud()->num_points());
|
||||
}
|
||||
// Go over all points of the original attribute and update the mapping in
|
||||
// the portable attribute.
|
||||
for (PointIndex i(0); i < encoder()->point_cloud()->num_points(); ++i) {
|
||||
|
||||
@@ -14,18 +14,17 @@
|
||||
//
|
||||
#include "draco/compression/attributes/sequential_normal_attribute_decoder.h"
|
||||
|
||||
#include "draco/attributes/attribute_octahedron_transform.h"
|
||||
#include "draco/compression/attributes/normal_compression_utils.h"
|
||||
|
||||
namespace draco {
|
||||
|
||||
SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder()
|
||||
: quantization_bits_(-1) {}
|
||||
SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder() {}
|
||||
|
||||
bool SequentialNormalAttributeDecoder::Init(PointCloudDecoder *decoder,
|
||||
int attribute_id) {
|
||||
if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id))
|
||||
if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id)) {
|
||||
return false;
|
||||
}
|
||||
// Currently, this encoder works only for 3-component normal vectors.
|
||||
if (attribute()->num_components() != 3) {
|
||||
return false;
|
||||
@@ -41,11 +40,13 @@ bool SequentialNormalAttributeDecoder::DecodeIntegerValues(
|
||||
const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) {
|
||||
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
|
||||
if (decoder()->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) {
|
||||
uint8_t quantization_bits;
|
||||
if (!in_buffer->Decode(&quantization_bits)) {
|
||||
// Note: in older bitstreams, we do not have a PortableAttribute() decoded
|
||||
// at this stage so we cannot pass it down to the DecodeParameters() call.
|
||||
// It still works fine for octahedral transform because it does not need to
|
||||
// use any data from the attribute.
|
||||
if (!octahedral_transform_.DecodeParameters(*attribute(), in_buffer)) {
|
||||
return false;
|
||||
}
|
||||
quantization_bits_ = quantization_bits;
|
||||
}
|
||||
#endif
|
||||
return SequentialIntegerAttributeDecoder::DecodeIntegerValues(point_ids,
|
||||
@@ -56,39 +57,20 @@ bool SequentialNormalAttributeDecoder::DecodeDataNeededByPortableTransform(
|
||||
const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) {
|
||||
if (decoder()->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 0)) {
|
||||
// For newer file version, decode attribute transform data here.
|
||||
uint8_t quantization_bits;
|
||||
if (!in_buffer->Decode(&quantization_bits)) {
|
||||
if (!octahedral_transform_.DecodeParameters(*GetPortableAttribute(),
|
||||
in_buffer)) {
|
||||
return false;
|
||||
}
|
||||
quantization_bits_ = quantization_bits;
|
||||
}
|
||||
|
||||
// Store the decoded transform data in portable attribute.
|
||||
AttributeOctahedronTransform octahedral_transform;
|
||||
octahedral_transform.SetParameters(quantization_bits_);
|
||||
return octahedral_transform.TransferToAttribute(portable_attribute());
|
||||
return octahedral_transform_.TransferToAttribute(portable_attribute());
|
||||
}
|
||||
|
||||
bool SequentialNormalAttributeDecoder::StoreValues(uint32_t num_points) {
|
||||
// Convert all quantized values back to floats.
|
||||
const int num_components = attribute()->num_components();
|
||||
const int entry_size = sizeof(float) * num_components;
|
||||
float att_val[3];
|
||||
int quant_val_id = 0;
|
||||
int out_byte_pos = 0;
|
||||
const int32_t *const portable_attribute_data = GetPortableAttributeData();
|
||||
OctahedronToolBox octahedron_tool_box;
|
||||
if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_))
|
||||
return false;
|
||||
for (uint32_t i = 0; i < num_points; ++i) {
|
||||
const int32_t s = portable_attribute_data[quant_val_id++];
|
||||
const int32_t t = portable_attribute_data[quant_val_id++];
|
||||
octahedron_tool_box.QuantizedOctaherdalCoordsToUnitVector(s, t, att_val);
|
||||
// Store the decoded floating point value into the attribute buffer.
|
||||
attribute()->buffer()->Write(out_byte_pos, att_val, entry_size);
|
||||
out_byte_pos += entry_size;
|
||||
}
|
||||
return true;
|
||||
return octahedral_transform_.InverseTransformAttribute(
|
||||
*GetPortableAttribute(), attribute());
|
||||
}
|
||||
|
||||
} // namespace draco
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_
|
||||
#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_
|
||||
|
||||
#include "draco/attributes/attribute_octahedron_transform.h"
|
||||
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h"
|
||||
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h"
|
||||
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h"
|
||||
@@ -42,7 +43,7 @@ class SequentialNormalAttributeDecoder
|
||||
bool StoreValues(uint32_t num_points) override;
|
||||
|
||||
private:
|
||||
int32_t quantization_bits_;
|
||||
AttributeOctahedronTransform octahedral_transform_;
|
||||
|
||||
std::unique_ptr<PredictionSchemeTypedDecoderInterface<int32_t>>
|
||||
CreateIntPredictionScheme(
|
||||
|
||||
@@ -20,8 +20,9 @@ namespace draco {
|
||||
|
||||
bool SequentialNormalAttributeEncoder::Init(PointCloudEncoder *encoder,
|
||||
int attribute_id) {
|
||||
if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id))
|
||||
if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) {
|
||||
return false;
|
||||
}
|
||||
// Currently this encoder works only for 3-component normal vectors.
|
||||
if (attribute()->num_components() != 3) {
|
||||
return false;
|
||||
@@ -44,9 +45,13 @@ bool SequentialNormalAttributeEncoder::EncodeDataNeededByPortableTransform(
|
||||
|
||||
bool SequentialNormalAttributeEncoder::PrepareValues(
|
||||
const std::vector<PointIndex> &point_ids, int num_points) {
|
||||
SetPortableAttribute(
|
||||
attribute_octahedron_transform_.GeneratePortableAttribute(
|
||||
*(attribute()), point_ids, num_points));
|
||||
auto portable_att = attribute_octahedron_transform_.InitTransformedAttribute(
|
||||
*(attribute()), point_ids.size());
|
||||
if (!attribute_octahedron_transform_.TransformAttribute(
|
||||
*(attribute()), point_ids, portable_att.get())) {
|
||||
return false;
|
||||
}
|
||||
SetPortableAttribute(std::move(portable_att));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,12 @@
|
||||
//
|
||||
#include "draco/compression/attributes/sequential_quantization_attribute_decoder.h"
|
||||
|
||||
#include "draco/attributes/attribute_quantization_transform.h"
|
||||
#include "draco/core/quantization_utils.h"
|
||||
|
||||
namespace draco {
|
||||
|
||||
SequentialQuantizationAttributeDecoder::SequentialQuantizationAttributeDecoder()
|
||||
: quantization_bits_(-1), max_value_dif_(0.f) {}
|
||||
SequentialQuantizationAttributeDecoder::
|
||||
SequentialQuantizationAttributeDecoder() {}
|
||||
|
||||
bool SequentialQuantizationAttributeDecoder::Init(PointCloudDecoder *decoder,
|
||||
int attribute_id) {
|
||||
@@ -59,62 +58,31 @@ bool SequentialQuantizationAttributeDecoder::
|
||||
}
|
||||
|
||||
// Store the decoded transform data in portable attribute;
|
||||
AttributeQuantizationTransform transform;
|
||||
transform.SetParameters(quantization_bits_, min_value_.get(),
|
||||
attribute()->num_components(), max_value_dif_);
|
||||
return transform.TransferToAttribute(portable_attribute());
|
||||
return quantization_transform_.TransferToAttribute(portable_attribute());
|
||||
}
|
||||
|
||||
bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_values) {
|
||||
return DequantizeValues(num_values);
|
||||
bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_points) {
|
||||
return DequantizeValues(num_points);
|
||||
}
|
||||
|
||||
bool SequentialQuantizationAttributeDecoder::DecodeQuantizedDataInfo() {
|
||||
const int num_components = attribute()->num_components();
|
||||
min_value_ = std::unique_ptr<float[]>(new float[num_components]);
|
||||
if (!decoder()->buffer()->Decode(min_value_.get(),
|
||||
sizeof(float) * num_components)) {
|
||||
return false;
|
||||
// Get attribute used as source for decoding.
|
||||
auto att = GetPortableAttribute();
|
||||
if (att == nullptr) {
|
||||
// This should happen only in the backward compatibility mode. It will still
|
||||
// work fine for this case because the only thing the quantization transform
|
||||
// cares about is the number of components that is the same for both source
|
||||
// and target attributes.
|
||||
att = attribute();
|
||||
}
|
||||
if (!decoder()->buffer()->Decode(&max_value_dif_)) {
|
||||
return false;
|
||||
}
|
||||
uint8_t quantization_bits;
|
||||
if (!decoder()->buffer()->Decode(&quantization_bits) ||
|
||||
quantization_bits > 31) {
|
||||
return false;
|
||||
}
|
||||
quantization_bits_ = quantization_bits;
|
||||
return true;
|
||||
return quantization_transform_.DecodeParameters(*att, decoder()->buffer());
|
||||
}
|
||||
|
||||
bool SequentialQuantizationAttributeDecoder::DequantizeValues(
|
||||
uint32_t num_values) {
|
||||
// Convert all quantized values back to floats.
|
||||
const int32_t max_quantized_value =
|
||||
(1u << static_cast<uint32_t>(quantization_bits_)) - 1;
|
||||
const int num_components = attribute()->num_components();
|
||||
const int entry_size = sizeof(float) * num_components;
|
||||
const std::unique_ptr<float[]> att_val(new float[num_components]);
|
||||
int quant_val_id = 0;
|
||||
int out_byte_pos = 0;
|
||||
Dequantizer dequantizer;
|
||||
if (!dequantizer.Init(max_value_dif_, max_quantized_value)) {
|
||||
return false;
|
||||
}
|
||||
const int32_t *const portable_attribute_data = GetPortableAttributeData();
|
||||
for (uint32_t i = 0; i < num_values; ++i) {
|
||||
for (int c = 0; c < num_components; ++c) {
|
||||
float value =
|
||||
dequantizer.DequantizeFloat(portable_attribute_data[quant_val_id++]);
|
||||
value = value + min_value_[c];
|
||||
att_val[c] = value;
|
||||
}
|
||||
// Store the floating point value into the attribute buffer.
|
||||
attribute()->buffer()->Write(out_byte_pos, att_val.get(), entry_size);
|
||||
out_byte_pos += entry_size;
|
||||
}
|
||||
return true;
|
||||
return quantization_transform_.InverseTransformAttribute(
|
||||
*GetPortableAttribute(), attribute());
|
||||
}
|
||||
|
||||
} // namespace draco
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_
|
||||
#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_
|
||||
|
||||
#include "draco/attributes/attribute_quantization_transform.h"
|
||||
#include "draco/compression/attributes/sequential_integer_attribute_decoder.h"
|
||||
#include "draco/draco_features.h"
|
||||
|
||||
@@ -43,12 +44,7 @@ class SequentialQuantizationAttributeDecoder
|
||||
virtual bool DequantizeValues(uint32_t num_values);
|
||||
|
||||
private:
|
||||
// Max number of quantization bits used to encode each component of the
|
||||
// attribute.
|
||||
int32_t quantization_bits_;
|
||||
|
||||
std::unique_ptr<float[]> min_value_;
|
||||
float max_value_dif_;
|
||||
AttributeQuantizationTransform quantization_transform_;
|
||||
};
|
||||
|
||||
} // namespace draco
|
||||
|
||||
@@ -50,9 +50,11 @@ bool SequentialQuantizationAttributeEncoder::Init(PointCloudEncoder *encoder,
|
||||
&quantization_origin[0]);
|
||||
const float range = encoder->options()->GetAttributeFloat(
|
||||
attribute_id, "quantization_range", 1.f);
|
||||
attribute_quantization_transform_.SetParameters(
|
||||
quantization_bits, quantization_origin.data(),
|
||||
attribute->num_components(), range);
|
||||
if (!attribute_quantization_transform_.SetParameters(
|
||||
quantization_bits, quantization_origin.data(),
|
||||
attribute->num_components(), range)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Compute quantization settings from the attribute values.
|
||||
if (!attribute_quantization_transform_.ComputeParameters(
|
||||
@@ -70,9 +72,14 @@ bool SequentialQuantizationAttributeEncoder::
|
||||
|
||||
bool SequentialQuantizationAttributeEncoder::PrepareValues(
|
||||
const std::vector<PointIndex> &point_ids, int num_points) {
|
||||
SetPortableAttribute(
|
||||
attribute_quantization_transform_.GeneratePortableAttribute(
|
||||
*(attribute()), point_ids, num_points));
|
||||
auto portable_attribute =
|
||||
attribute_quantization_transform_.InitTransformedAttribute(
|
||||
*attribute(), point_ids.size());
|
||||
if (!attribute_quantization_transform_.TransformAttribute(
|
||||
*(attribute()), point_ids, portable_attribute.get())) {
|
||||
return false;
|
||||
}
|
||||
SetPortableAttribute(std::move(portable_attribute));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ enum EncodedGeometryType {
|
||||
INVALID_GEOMETRY_TYPE = -1,
|
||||
POINT_CLOUD = 0,
|
||||
TRIANGULAR_MESH,
|
||||
NUM_ENCODED_GEOMETRY_TYPES
|
||||
};
|
||||
|
||||
// List of encoding methods for point clouds.
|
||||
@@ -105,6 +106,8 @@ enum PredictionSchemeTransformType {
|
||||
// Specialized transform for normal coordinates using canonicalized inverted
|
||||
// tiles.
|
||||
PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED = 3,
|
||||
// The number of valid (non-negative) prediction scheme transform types.
|
||||
NUM_PREDICTION_SCHEME_TRANSFORM_TYPES
|
||||
};
|
||||
|
||||
// List of all mesh traversal methods supported by Draco framework.
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
|
||||
#define DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
|
||||
#ifndef DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
|
||||
#define DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -246,4 +246,4 @@ void DracoOptions<AttributeKeyT>::SetAttributeOptions(
|
||||
|
||||
} // namespace draco
|
||||
|
||||
#endif // DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
|
||||
#endif // DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
|
||||
|
||||
@@ -56,7 +56,10 @@ StatusOr<EncodedGeometryType> Decoder::GetEncodedGeometryType(
|
||||
DecoderBuffer *in_buffer) {
|
||||
DecoderBuffer temp_buffer(*in_buffer);
|
||||
DracoHeader header;
|
||||
DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header))
|
||||
DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header));
|
||||
if (header.encoder_type >= NUM_ENCODED_GEOMETRY_TYPES) {
|
||||
return Status(Status::DRACO_ERROR, "Unsupported geometry type.");
|
||||
}
|
||||
return static_cast<EncodedGeometryType>(header.encoder_type);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_
|
||||
#define DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_
|
||||
#ifndef DRACO_COMPRESSION_ENCODE_BASE_H_
|
||||
#define DRACO_COMPRESSION_ENCODE_BASE_H_
|
||||
|
||||
#include "draco/attributes/geometry_attribute.h"
|
||||
#include "draco/compression/config/compression_shared.h"
|
||||
@@ -98,7 +98,7 @@ class EncoderBase {
|
||||
"Invalid prediction scheme for attribute type.");
|
||||
}
|
||||
}
|
||||
// TODO(hemmer): Try to enable more prediction schemes for normals.
|
||||
// TODO(b/199760123): Try to enable more prediction schemes for normals.
|
||||
if (att_type == GeometryAttribute::NORMAL) {
|
||||
if (!(prediction_scheme == PREDICTION_DIFFERENCE ||
|
||||
prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) {
|
||||
@@ -128,4 +128,4 @@ void EncoderBase<EncoderOptionsT>::SetTrackEncodedProperties(bool flag) {
|
||||
|
||||
} // namespace draco
|
||||
|
||||
#endif // DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_
|
||||
#endif // DRACO_COMPRESSION_ENCODE_BASE_H_
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef DRACO_CORE_ANS_H_
|
||||
#define DRACO_CORE_ANS_H_
|
||||
#ifndef DRACO_COMPRESSION_ENTROPY_ANS_H_
|
||||
#define DRACO_COMPRESSION_ENTROPY_ANS_H_
|
||||
// An implementation of Asymmetric Numeral Systems (rANS).
|
||||
// See http://arxiv.org/abs/1311.2540v2 for more information on rANS.
|
||||
// This file is based off libvpx's ans.h.
|
||||
@@ -391,7 +391,6 @@ class RAnsEncoder {
|
||||
ans_.buf[ans_.buf_offset++] = ans_.state % DRACO_ANS_IO_BASE;
|
||||
ans_.state /= DRACO_ANS_IO_BASE;
|
||||
}
|
||||
// TODO(ostava): The division and multiplication should be optimized.
|
||||
ans_.state =
|
||||
(ans_.state / p) * rans_precision + ans_.state % p + sym->cum_prob;
|
||||
}
|
||||
@@ -524,4 +523,4 @@ class RAnsDecoder {
|
||||
|
||||
} // namespace draco
|
||||
|
||||
#endif // DRACO_CORE_ANS_H_
|
||||
#endif // DRACO_COMPRESSION_ENTROPY_ANS_H_
|
||||
|
||||
@@ -31,11 +31,10 @@ constexpr int ComputeRAnsUnclampedPrecision(int symbols_bit_length) {
|
||||
// our rANS library (which is between 12 to 20 bits).
|
||||
constexpr int ComputeRAnsPrecisionFromUniqueSymbolsBitLength(
|
||||
int symbols_bit_length) {
|
||||
return ComputeRAnsUnclampedPrecision(symbols_bit_length) < 12
|
||||
? 12
|
||||
: ComputeRAnsUnclampedPrecision(symbols_bit_length) > 20
|
||||
? 20
|
||||
: ComputeRAnsUnclampedPrecision(symbols_bit_length);
|
||||
return ComputeRAnsUnclampedPrecision(symbols_bit_length) < 12 ? 12
|
||||
: ComputeRAnsUnclampedPrecision(symbols_bit_length) > 20
|
||||
? 20
|
||||
: ComputeRAnsUnclampedPrecision(symbols_bit_length);
|
||||
}
|
||||
|
||||
// Compute approximate frequency table size needed for storing the provided
|
||||
|
||||
@@ -125,8 +125,8 @@ bool RAnsSymbolEncoder<unique_symbols_bit_length_t>::Create(
|
||||
for (int i = 0; i < num_symbols; ++i) {
|
||||
sorted_probabilities[i] = i;
|
||||
}
|
||||
std::sort(sorted_probabilities.begin(), sorted_probabilities.end(),
|
||||
ProbabilityLess(&probability_table_));
|
||||
std::stable_sort(sorted_probabilities.begin(), sorted_probabilities.end(),
|
||||
ProbabilityLess(&probability_table_));
|
||||
if (total_rans_prob < rans_precision_) {
|
||||
// This happens rather infrequently, just add the extra needed precision
|
||||
// to the most frequent symbol.
|
||||
|
||||
@@ -72,7 +72,7 @@ bool DecodeTaggedSymbols(uint32_t num_values, int num_components,
|
||||
int value_id = 0;
|
||||
for (uint32_t i = 0; i < num_values; i += num_components) {
|
||||
// Decode the tag.
|
||||
const int bit_length = tag_decoder.DecodeSymbol();
|
||||
const uint32_t bit_length = tag_decoder.DecodeSymbol();
|
||||
// Decode the actual value.
|
||||
for (int j = 0; j < num_components; ++j) {
|
||||
uint32_t val;
|
||||
|
||||
@@ -67,7 +67,7 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc,
|
||||
kd_tree_possible = false;
|
||||
}
|
||||
if (kd_tree_possible && att->data_type() == DT_FLOAT32 &&
|
||||
options().GetAttributeInt(0, "quantization_bits", -1) <= 0) {
|
||||
options().GetAttributeInt(i, "quantization_bits", -1) <= 0) {
|
||||
kd_tree_possible = false; // Quantization not enabled.
|
||||
}
|
||||
if (!kd_tree_possible) {
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_
|
||||
#define DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_
|
||||
#ifndef DRACO_COMPRESSION_EXPERT_ENCODE_H_
|
||||
#define DRACO_COMPRESSION_EXPERT_ENCODE_H_
|
||||
|
||||
#include "draco/compression/config/compression_shared.h"
|
||||
#include "draco/compression/config/encoder_options.h"
|
||||
@@ -144,4 +144,4 @@ class ExpertEncoder : public EncoderBase<EncoderOptions> {
|
||||
|
||||
} // namespace draco
|
||||
|
||||
#endif // DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_
|
||||
#endif // DRACO_COMPRESSION_EXPERT_ENCODE_H_
|
||||
|
||||
@@ -162,6 +162,10 @@ bool MeshEdgebreakerDecoderImpl<TraversalDecoder>::CreateAttributesDecoder(
|
||||
if (!decoder_->buffer()->Decode(&traversal_method_encoded)) {
|
||||
return false;
|
||||
}
|
||||
// Check that decoded traversal method is valid.
|
||||
if (traversal_method_encoded >= NUM_TRAVERSAL_METHODS) {
|
||||
return false;
|
||||
}
|
||||
traversal_method =
|
||||
static_cast<MeshTraversalMethod>(traversal_method_encoded);
|
||||
}
|
||||
@@ -450,7 +454,7 @@ bool MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity() {
|
||||
#endif
|
||||
|
||||
// Decode connectivity of non-position attributes.
|
||||
if (attribute_data_.size() > 0) {
|
||||
if (!attribute_data_.empty()) {
|
||||
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
|
||||
if (decoder_->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 1)) {
|
||||
for (CornerIndex ci(0); ci < corner_table_->num_corners(); ci += 3) {
|
||||
@@ -577,11 +581,16 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
||||
SetOppositeCorners(corner_b, corner + 2);
|
||||
|
||||
// Update vertex mapping.
|
||||
corner_table_->MapCornerToVertex(corner, vertex_x);
|
||||
corner_table_->MapCornerToVertex(
|
||||
corner + 1, corner_table_->Vertex(corner_table_->Next(corner_b)));
|
||||
const VertexIndex vert_a_prev =
|
||||
corner_table_->Vertex(corner_table_->Previous(corner_a));
|
||||
const VertexIndex vert_b_next =
|
||||
corner_table_->Vertex(corner_table_->Next(corner_b));
|
||||
if (vertex_x == vert_a_prev || vertex_x == vert_b_next) {
|
||||
// Encoding is invalid, because face vertices are degenerate.
|
||||
return -1;
|
||||
}
|
||||
corner_table_->MapCornerToVertex(corner, vertex_x);
|
||||
corner_table_->MapCornerToVertex(corner + 1, vert_b_next);
|
||||
corner_table_->MapCornerToVertex(corner + 2, vert_a_prev);
|
||||
corner_table_->SetLeftMostCorner(vert_a_prev, corner + 2);
|
||||
// Mark the vertex |x| as interior.
|
||||
@@ -791,7 +800,7 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
|
||||
return -1; // Unexpected number of decoded vertices.
|
||||
}
|
||||
// Decode start faces and connect them to the faces from the active stack.
|
||||
while (active_corner_stack.size() > 0) {
|
||||
while (!active_corner_stack.empty()) {
|
||||
const CornerIndex corner = active_corner_stack.back();
|
||||
active_corner_stack.pop_back();
|
||||
const bool interior_face =
|
||||
@@ -952,9 +961,13 @@ MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeHoleAndTopologySplitEvents(
|
||||
for (uint32_t i = 0; i < num_topology_splits; ++i) {
|
||||
TopologySplitEventData event_data;
|
||||
uint32_t delta;
|
||||
DecodeVarint<uint32_t>(&delta, decoder_buffer);
|
||||
if (!DecodeVarint<uint32_t>(&delta, decoder_buffer)) {
|
||||
return -1;
|
||||
}
|
||||
event_data.source_symbol_id = delta + last_source_symbol_id;
|
||||
DecodeVarint<uint32_t>(&delta, decoder_buffer);
|
||||
if (!DecodeVarint<uint32_t>(&delta, decoder_buffer)) {
|
||||
return -1;
|
||||
}
|
||||
if (delta > event_data.source_symbol_id) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1009,7 +1022,9 @@ MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeHoleAndTopologySplitEvents(
|
||||
for (uint32_t i = 0; i < num_hole_events; ++i) {
|
||||
HoleEventData event_data;
|
||||
uint32_t delta;
|
||||
DecodeVarint<uint32_t>(&delta, decoder_buffer);
|
||||
if (!DecodeVarint<uint32_t>(&delta, decoder_buffer)) {
|
||||
return -1;
|
||||
}
|
||||
event_data.symbol_id = delta + last_symbol_id;
|
||||
last_symbol_id = event_data.symbol_id;
|
||||
hole_event_data_.push_back(event_data);
|
||||
|
||||
@@ -31,7 +31,6 @@ bool MeshEdgebreakerEncoder::InitializeEncoder() {
|
||||
impl_ = nullptr;
|
||||
// For tiny meshes it's usually better to use the basic edgebreaker as the
|
||||
// overhead of the predictive one may turn out to be too big.
|
||||
// TODO(b/111065939): Check if this can be improved.
|
||||
const bool is_tiny_mesh = mesh()->num_faces() < 1000;
|
||||
|
||||
int selected_edgebreaker_method =
|
||||
|
||||
@@ -408,7 +408,7 @@ Status MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
|
||||
init_face_connectivity_corners.begin(),
|
||||
init_face_connectivity_corners.end());
|
||||
// Encode connectivity for all non-position attributes.
|
||||
if (attribute_data_.size() > 0) {
|
||||
if (!attribute_data_.empty()) {
|
||||
// Use the same order of corner that will be used by the decoder.
|
||||
visited_faces_.assign(mesh_->num_faces(), false);
|
||||
for (CornerIndex ci : processed_connectivity_corners_) {
|
||||
|
||||
@@ -177,7 +177,6 @@ class MeshEdgebreakerEncoderImpl : public MeshEdgebreakerEncoderImplInterface {
|
||||
uint32_t num_split_symbols_;
|
||||
|
||||
// Struct holding data used for encoding each non-position attribute.
|
||||
// TODO(ostava): This should be probably renamed to something better.
|
||||
struct AttributeData {
|
||||
AttributeData() : attribute_index(-1), is_connectivity_used(true) {}
|
||||
int attribute_index;
|
||||
|
||||
@@ -50,8 +50,6 @@ namespace draco {
|
||||
// \ / S \ / / E \
|
||||
// *-------* *-------*
|
||||
//
|
||||
// TODO(ostava): Get rid of the topology bit pattern. It's important only for
|
||||
// encoding but the algorithms should use EdgebreakerSymbol instead.
|
||||
enum EdgebreakerTopologyBitPattern {
|
||||
TOPOLOGY_C = 0x0, // 0
|
||||
TOPOLOGY_S = 0x1, // 1 0 0
|
||||
|
||||
@@ -106,7 +106,12 @@ class MeshEdgebreakerTraversalValenceDecoder
|
||||
context_counters_.resize(context_symbols_.size());
|
||||
for (int i = 0; i < context_symbols_.size(); ++i) {
|
||||
uint32_t num_symbols;
|
||||
DecodeVarint<uint32_t>(&num_symbols, out_buffer);
|
||||
if (!DecodeVarint<uint32_t>(&num_symbols, out_buffer)) {
|
||||
return false;
|
||||
}
|
||||
if (num_symbols > static_cast<uint32_t>(corner_table_->num_faces())) {
|
||||
return false;
|
||||
}
|
||||
if (num_symbols > 0) {
|
||||
context_symbols_[i].resize(num_symbols);
|
||||
DecodeSymbols(num_symbols, 1, out_buffer, context_symbols_[i].data());
|
||||
|
||||
@@ -53,6 +53,11 @@ bool MeshSequentialDecoder::DecodeConnectivity() {
|
||||
if (faces_64 > 0xffffffff / 3) {
|
||||
return false;
|
||||
}
|
||||
if (faces_64 > buffer()->remaining_size() / 3) {
|
||||
// The number of faces is unreasonably high, because face indices do not
|
||||
// fit in the remaining size of the buffer.
|
||||
return false;
|
||||
}
|
||||
if (points_64 > faces_64 * 3) {
|
||||
return false;
|
||||
}
|
||||
@@ -91,7 +96,7 @@ bool MeshSequentialDecoder::DecodeConnectivity() {
|
||||
}
|
||||
mesh()->AddFace(face);
|
||||
}
|
||||
} else if (mesh()->num_points() < (1 << 21) &&
|
||||
} else if (num_points < (1 << 21) &&
|
||||
bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 2)) {
|
||||
// Decode indices as uint32_t.
|
||||
for (uint32_t i = 0; i < num_faces; ++i) {
|
||||
|
||||
@@ -32,8 +32,6 @@ Status MeshSequentialEncoder::EncodeConnectivity() {
|
||||
EncodeVarint(static_cast<uint32_t>(mesh()->num_points()), buffer());
|
||||
|
||||
// We encode all attributes in the original (possibly duplicated) format.
|
||||
// TODO(ostava): This may not be optimal if we have only one attribute or if
|
||||
// all attributes share the same index mapping.
|
||||
if (options()->GetGlobalBool("compress_connectivity", false)) {
|
||||
// 0 = Encode compressed indices.
|
||||
buffer()->Encode(static_cast<uint8_t>(0));
|
||||
@@ -44,8 +42,6 @@ Status MeshSequentialEncoder::EncodeConnectivity() {
|
||||
// 1 = Encode indices directly.
|
||||
buffer()->Encode(static_cast<uint8_t>(1));
|
||||
// Store vertex indices using a smallest data type that fits their range.
|
||||
// TODO(ostava): This can be potentially improved by using a tighter
|
||||
// fit that is not bound by a bit-length of any particular data type.
|
||||
if (mesh()->num_points() < 256) {
|
||||
// Serialize indices as uint8_t.
|
||||
for (FaceIndex i(0); i < num_faces; ++i) {
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace draco {
|
||||
|
||||
// Class that encodes mesh data using a simple binary representation of mesh's
|
||||
// connectivity and geometry.
|
||||
// TODO(ostava): Use a better name.
|
||||
class MeshSequentialEncoder : public MeshEncoder {
|
||||
public:
|
||||
MeshSequentialEncoder();
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace draco {
|
||||
// values based on the traversal of the encoded mesh. The class should be used
|
||||
// as the TraversalObserverT member of a Traverser class such as the
|
||||
// DepthFirstTraverser (depth_first_traverser.h).
|
||||
// TODO(hemmer): rename to AttributeIndicesCodingTraverserObserver
|
||||
// TODO(b/199760123): Rename to AttributeIndicesCodingTraverserObserver.
|
||||
template <class CornerTableT>
|
||||
class MeshAttributeIndicesEncodingObserver {
|
||||
public:
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace draco {
|
||||
// Sequencer that generates point sequence in an order given by a deterministic
|
||||
// traversal on the mesh surface. Note that all attributes encoded with this
|
||||
// sequence must share the same connectivity.
|
||||
// TODO(hemmer): Consider refactoring such that this is an observer.
|
||||
// TODO(b/199760123): Consider refactoring such that this is an observer.
|
||||
template <class TraverserT>
|
||||
class MeshTraversalSequencer : public PointsSequencer {
|
||||
public:
|
||||
|
||||
@@ -227,7 +227,7 @@ bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodeInternal(
|
||||
std::stack<Status> status_stack;
|
||||
status_stack.push(init_status);
|
||||
|
||||
// TODO(hemmer): use preallocated vector instead of stack.
|
||||
// TODO(b/199760123): Use preallocated vector instead of stack.
|
||||
while (!status_stack.empty()) {
|
||||
const DecodingStatus status = status_stack.top();
|
||||
status_stack.pop();
|
||||
@@ -263,7 +263,8 @@ bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodeInternal(
|
||||
|
||||
// Fast decoding of remaining bits if number of points is 1 or 2.
|
||||
if (num_remaining_points <= 2) {
|
||||
// TODO(hemmer): axes_ not necessary, remove would change bitstream!
|
||||
// TODO(b/199760123): |axes_| not necessary, remove would change
|
||||
// bitstream!
|
||||
axes_[0] = axis;
|
||||
for (uint32_t i = 1; i < dimension_; i++) {
|
||||
axes_[i] = DRACO_INCREMENT_MOD(axes_[i - 1], dimension_);
|
||||
|
||||
@@ -280,7 +280,7 @@ void DynamicIntegerPointsKdTreeEncoder<compression_level_t>::EncodeInternal(
|
||||
std::stack<Status> status_stack;
|
||||
status_stack.push(init_status);
|
||||
|
||||
// TODO(hemmer): use preallocated vector instead of stack.
|
||||
// TODO(b/199760123): Use preallocated vector instead of stack.
|
||||
while (!status_stack.empty()) {
|
||||
Status status = status_stack.top();
|
||||
status_stack.pop();
|
||||
@@ -305,7 +305,8 @@ void DynamicIntegerPointsKdTreeEncoder<compression_level_t>::EncodeInternal(
|
||||
// Fast encoding of remaining bits if number of points is 1 or 2.
|
||||
// Doing this also for 2 gives a slight additional speed up.
|
||||
if (num_remaining_points <= 2) {
|
||||
// TODO(hemmer): axes_ not necessary, remove would change bitstream!
|
||||
// TODO(b/199760123): |axes_| not necessary, remove would change
|
||||
// bitstream!
|
||||
axes_[0] = axis;
|
||||
for (uint32_t i = 1; i < dimension_; i++) {
|
||||
axes_[i] = DRACO_INCREMENT_MOD(axes_[i - 1], dimension_);
|
||||
|
||||
@@ -69,18 +69,29 @@ FloatPointsTreeDecoder::FloatPointsTreeDecoder()
|
||||
|
||||
bool FloatPointsTreeDecoder::DecodePointCloudKdTreeInternal(
|
||||
DecoderBuffer *buffer, std::vector<Point3ui> *qpoints) {
|
||||
if (!buffer->Decode(&qinfo_.quantization_bits)) return false;
|
||||
if (qinfo_.quantization_bits > 31) return false;
|
||||
if (!buffer->Decode(&qinfo_.range)) return false;
|
||||
if (!buffer->Decode(&num_points_)) return false;
|
||||
if (num_points_from_header_ > 0 && num_points_ != num_points_from_header_)
|
||||
if (!buffer->Decode(&qinfo_.quantization_bits)) {
|
||||
return false;
|
||||
if (!buffer->Decode(&compression_level_)) return false;
|
||||
}
|
||||
if (qinfo_.quantization_bits > 31) {
|
||||
return false;
|
||||
}
|
||||
if (!buffer->Decode(&qinfo_.range)) {
|
||||
return false;
|
||||
}
|
||||
if (!buffer->Decode(&num_points_)) {
|
||||
return false;
|
||||
}
|
||||
if (num_points_from_header_ > 0 && num_points_ != num_points_from_header_) {
|
||||
return false;
|
||||
}
|
||||
if (!buffer->Decode(&compression_level_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow compression level in [0..6].
|
||||
if (6 < compression_level_) {
|
||||
LOGE("FloatPointsTreeDecoder: compression level %i not supported.\n",
|
||||
compression_level_);
|
||||
DRACO_LOGE("FloatPointsTreeDecoder: compression level %i not supported.\n",
|
||||
compression_level_);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace draco {
|
||||
// there are more leading zeros, which is then compressed better by the
|
||||
// arithmetic encoding.
|
||||
|
||||
// TODO(hemmer): Remove class because it duplicates quantization code.
|
||||
// TODO(b/199760123): Remove class because it duplicates quantization code.
|
||||
class FloatPointsTreeEncoder {
|
||||
public:
|
||||
explicit FloatPointsTreeEncoder(PointCloudCompressionMethod method);
|
||||
@@ -91,7 +91,7 @@ bool FloatPointsTreeEncoder::EncodePointCloud(InputIteratorT points_begin,
|
||||
// Collect necessary data for encoding.
|
||||
num_points_ = std::distance(points_begin, points_end);
|
||||
|
||||
// TODO(hemmer): Extend quantization tools to make this more automatic.
|
||||
// TODO(b/199760123): Extend quantization tools to make this more automatic.
|
||||
// Compute range of points for quantization
|
||||
std::vector<Point3ui> qpoints;
|
||||
qpoints.reserve(num_points_);
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// TODO(hemmer): Make this a wrapper using DynamicIntegerPointsKdTreeDecoder.
|
||||
// TODO(b/199760123): Make this a wrapper using
|
||||
// DynamicIntegerPointsKdTreeDecoder.
|
||||
//
|
||||
// See integer_points_kd_tree_encoder.h for documentation.
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// TODO(hemmer): Make this a wrapper using DynamicIntegerPointsKdTreeEncoder.
|
||||
// TODO(b/199760123): Make this a wrapper using
|
||||
// DynamicIntegerPointsKdTreeEncoder.
|
||||
#ifndef DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_
|
||||
#define DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
namespace draco {
|
||||
|
||||
// TODO(hemmer): Make this a stable bounding box.
|
||||
// TODO(b/199760123): Make this a stable bounding box.
|
||||
struct QuantizationInfo {
|
||||
uint32_t quantization_bits;
|
||||
float range;
|
||||
|
||||
@@ -88,7 +88,9 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options,
|
||||
const uint8_t max_supported_minor_version =
|
||||
header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMinor
|
||||
: kDracoMeshBitstreamVersionMinor;
|
||||
|
||||
// Check for version compatibility.
|
||||
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
|
||||
if (version_major_ < 1 || version_major_ > max_supported_major_version) {
|
||||
return Status(Status::UNKNOWN_VERSION, "Unknown major version.");
|
||||
}
|
||||
@@ -96,6 +98,14 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options,
|
||||
version_minor_ > max_supported_minor_version) {
|
||||
return Status(Status::UNKNOWN_VERSION, "Unknown minor version.");
|
||||
}
|
||||
#else
|
||||
if (version_major_ != max_supported_major_version) {
|
||||
return Status(Status::UNKNOWN_VERSION, "Unsupported major version.");
|
||||
}
|
||||
if (version_minor_ != max_supported_minor_version) {
|
||||
return Status(Status::UNKNOWN_VERSION, "Unsupported minor version.");
|
||||
}
|
||||
#endif
|
||||
buffer_->set_bitstream_version(
|
||||
DRACO_BITSTREAM_VERSION(version_major_, version_minor_));
|
||||
|
||||
|
||||
@@ -62,12 +62,14 @@ Status PointCloudEncoder::EncodeHeader() {
|
||||
buffer_->Encode("DRACO", 5);
|
||||
// Version (major, minor).
|
||||
const uint8_t encoder_type = GetGeometryType();
|
||||
const uint8_t version_major = encoder_type == POINT_CLOUD
|
||||
? kDracoPointCloudBitstreamVersionMajor
|
||||
: kDracoMeshBitstreamVersionMajor;
|
||||
const uint8_t version_minor = encoder_type == POINT_CLOUD
|
||||
? kDracoPointCloudBitstreamVersionMinor
|
||||
: kDracoMeshBitstreamVersionMinor;
|
||||
uint8_t version_major, version_minor;
|
||||
version_major = encoder_type == POINT_CLOUD
|
||||
? kDracoPointCloudBitstreamVersionMajor
|
||||
: kDracoMeshBitstreamVersionMajor;
|
||||
version_minor = encoder_type == POINT_CLOUD
|
||||
? kDracoPointCloudBitstreamVersionMinor
|
||||
: kDracoMeshBitstreamVersionMinor;
|
||||
|
||||
buffer_->Encode(version_major);
|
||||
buffer_->Encode(version_minor);
|
||||
// Type of the encoder (point cloud, mesh, ...).
|
||||
|
||||
@@ -16,8 +16,15 @@
|
||||
|
||||
namespace draco {
|
||||
|
||||
BoundingBox::BoundingBox(const Vector3f &min_point_in,
|
||||
const Vector3f &max_point_in)
|
||||
: min_point_(min_point_in), max_point_(max_point_in) {}
|
||||
BoundingBox::BoundingBox()
|
||||
: BoundingBox(Vector3f(std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max()),
|
||||
Vector3f(std::numeric_limits<float>::lowest(),
|
||||
std::numeric_limits<float>::lowest(),
|
||||
std::numeric_limits<float>::lowest())) {}
|
||||
|
||||
BoundingBox::BoundingBox(const Vector3f &min_point, const Vector3f &max_point)
|
||||
: min_point_(min_point), max_point_(max_point) {}
|
||||
|
||||
} // namespace draco
|
||||
|
||||
42
extern/draco/draco/src/draco/core/bounding_box.h
vendored
42
extern/draco/draco/src/draco/core/bounding_box.h
vendored
@@ -19,22 +19,27 @@
|
||||
|
||||
namespace draco {
|
||||
|
||||
// Class for detecting the bounding box of a point_cloud or mesh.
|
||||
// Use the minimum point and the maximum point to define the bounding box.
|
||||
// TODO(xiaoxumeng): Change the class of BoundingBox to a template, similar to
|
||||
// draco/src/draco/core/vector_d.h
|
||||
// Class for computing the bounding box of points in 3D space.
|
||||
class BoundingBox {
|
||||
public:
|
||||
// Initialization
|
||||
BoundingBox(const Vector3f &min_point_in, const Vector3f &max_point_in);
|
||||
// Creates bounding box object with minimum and maximum points initialized to
|
||||
// the largest positive and the smallest negative values, respectively. The
|
||||
// resulting abstract bounding box effectively has no points and can be
|
||||
// updated by providing any point to Update() method.
|
||||
BoundingBox();
|
||||
|
||||
inline const Vector3f &min_point() const { return min_point_; }
|
||||
inline const Vector3f &max_point() const { return max_point_; }
|
||||
// Creates bounding box object with minimum and maximum points initialized to
|
||||
// |min_point| and |max_point|, respectively.
|
||||
BoundingBox(const Vector3f &min_point, const Vector3f &max_point);
|
||||
|
||||
// Conditionally updates the bounding box.
|
||||
// TODO(xiaoxumeng): Change the function to a template function and change the
|
||||
// argument to an iterator.
|
||||
inline void update_bounding_box(const Vector3f &new_point) {
|
||||
// Returns the minimum point of the bounding box.
|
||||
inline const Vector3f &GetMinPoint() const { return min_point_; }
|
||||
|
||||
// Returns the maximum point of the bounding box.
|
||||
inline const Vector3f &GetMaxPoint() const { return max_point_; }
|
||||
|
||||
// Conditionally updates the bounding box with a given |new_point|.
|
||||
void Update(const Vector3f &new_point) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (new_point[i] < min_point_[i]) {
|
||||
min_point_[i] = new_point[i];
|
||||
@@ -45,6 +50,19 @@ class BoundingBox {
|
||||
}
|
||||
}
|
||||
|
||||
// Updates bounding box with minimum and maximum points of the |other|
|
||||
// bounding box.
|
||||
void Update(const BoundingBox &other) {
|
||||
Update(other.GetMinPoint());
|
||||
Update(other.GetMaxPoint());
|
||||
}
|
||||
|
||||
// Returns the size of the bounding box along each axis.
|
||||
Vector3f Size() const { return max_point_ - min_point_; }
|
||||
|
||||
// Returns the center of the bounding box.
|
||||
Vector3f Center() const { return (min_point_ + max_point_) / 2; }
|
||||
|
||||
private:
|
||||
Vector3f min_point_;
|
||||
Vector3f max_point_;
|
||||
|
||||
14
extern/draco/draco/src/draco/core/cycle_timer.cc
vendored
14
extern/draco/draco/src/draco/core/cycle_timer.cc
vendored
@@ -17,31 +17,31 @@
|
||||
namespace draco {
|
||||
void DracoTimer::Start() {
|
||||
#ifdef _WIN32
|
||||
QueryPerformanceCounter(&tv_start);
|
||||
QueryPerformanceCounter(&tv_start_);
|
||||
#else
|
||||
gettimeofday(&tv_start, nullptr);
|
||||
gettimeofday(&tv_start_, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DracoTimer::Stop() {
|
||||
#ifdef _WIN32
|
||||
QueryPerformanceCounter(&tv_end);
|
||||
QueryPerformanceCounter(&tv_end_);
|
||||
#else
|
||||
gettimeofday(&tv_end, nullptr);
|
||||
gettimeofday(&tv_end_, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t DracoTimer::GetInMs() {
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER elapsed = {0};
|
||||
elapsed.QuadPart = tv_end.QuadPart - tv_start.QuadPart;
|
||||
elapsed.QuadPart = tv_end_.QuadPart - tv_start_.QuadPart;
|
||||
|
||||
LARGE_INTEGER frequency = {0};
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
return elapsed.QuadPart * 1000 / frequency.QuadPart;
|
||||
#else
|
||||
const int64_t seconds = (tv_end.tv_sec - tv_start.tv_sec) * 1000;
|
||||
const int64_t milliseconds = (tv_end.tv_usec - tv_start.tv_usec) / 1000;
|
||||
const int64_t seconds = (tv_end_.tv_sec - tv_start_.tv_sec) * 1000;
|
||||
const int64_t milliseconds = (tv_end_.tv_usec - tv_start_.tv_usec) / 1000;
|
||||
return seconds + milliseconds;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -20,9 +20,10 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
typedef LARGE_INTEGER timeval;
|
||||
typedef LARGE_INTEGER DracoTimeVal;
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
typedef timeval DracoTimeVal;
|
||||
#endif
|
||||
|
||||
#include <cinttypes>
|
||||
@@ -39,8 +40,8 @@ class DracoTimer {
|
||||
int64_t GetInMs();
|
||||
|
||||
private:
|
||||
timeval tv_start;
|
||||
timeval tv_end;
|
||||
DracoTimeVal tv_start_;
|
||||
DracoTimeVal tv_end_;
|
||||
};
|
||||
|
||||
typedef DracoTimer CycleTimer;
|
||||
|
||||
@@ -52,7 +52,7 @@ void DataBuffer::Resize(int64_t size) {
|
||||
}
|
||||
|
||||
void DataBuffer::WriteDataToStream(std::ostream &stream) {
|
||||
if (data_.size() == 0) {
|
||||
if (data_.empty()) {
|
||||
return;
|
||||
}
|
||||
stream.write(reinterpret_cast<char *>(data_.data()), data_.size());
|
||||
|
||||
@@ -54,12 +54,11 @@ class DecoderBuffer {
|
||||
|
||||
// Decodes up to 32 bits into out_val. Can be called only in between
|
||||
// StartBitDecoding and EndBitDecoding. Otherwise returns false.
|
||||
bool DecodeLeastSignificantBits32(int nbits, uint32_t *out_value) {
|
||||
bool DecodeLeastSignificantBits32(uint32_t nbits, uint32_t *out_value) {
|
||||
if (!bit_decoder_active()) {
|
||||
return false;
|
||||
}
|
||||
bit_decoder_.GetBits(nbits, out_value);
|
||||
return true;
|
||||
return bit_decoder_.GetBits(nbits, out_value);
|
||||
}
|
||||
|
||||
// Decodes an arbitrary data type.
|
||||
@@ -158,9 +157,10 @@ class DecoderBuffer {
|
||||
inline void ConsumeBits(int k) { bit_offset_ += k; }
|
||||
|
||||
// Returns |nbits| bits in |x|.
|
||||
inline bool GetBits(int32_t nbits, uint32_t *x) {
|
||||
DRACO_DCHECK_GE(nbits, 0);
|
||||
DRACO_DCHECK_LE(nbits, 32);
|
||||
inline bool GetBits(uint32_t nbits, uint32_t *x) {
|
||||
if (nbits > 32) {
|
||||
return false;
|
||||
}
|
||||
uint32_t value = 0;
|
||||
for (int32_t bit = 0; bit < nbits; ++bit) {
|
||||
value |= GetBit() << bit;
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace draco {
|
||||
// draco_index_type.h .
|
||||
// TODO(ostava): Make the interface more complete. It's currently missing
|
||||
// features such as iterators.
|
||||
// TODO(vytyaz): Add more unit tests for this class.
|
||||
template <class IndexTypeT, class ValueTypeT>
|
||||
class IndexTypeVector {
|
||||
public:
|
||||
@@ -56,7 +55,7 @@ class IndexTypeVector {
|
||||
void push_back(ValueTypeT &&val) { vector_.push_back(std::move(val)); }
|
||||
|
||||
template <typename... Args>
|
||||
void emplace_back(Args &&... args) {
|
||||
void emplace_back(Args &&...args) {
|
||||
vector_.emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
namespace draco {
|
||||
|
||||
// Draco version is comprised of <major>.<minor>.<revision>.
|
||||
static const char kDracoVersion[] = "1.3.6";
|
||||
static const char kDracoVersion[] = "1.5.2";
|
||||
|
||||
const char *Version() { return kDracoVersion; }
|
||||
|
||||
|
||||
27
extern/draco/draco/src/draco/core/macros.h
vendored
27
extern/draco/draco/src/draco/core/macros.h
vendored
@@ -21,11 +21,13 @@
|
||||
#ifdef ANDROID_LOGGING
|
||||
#include <android/log.h>
|
||||
#define LOG_TAG "draco"
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define DRACO_LOGI(...) \
|
||||
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define DRACO_LOGE(...) \
|
||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define LOGI printf
|
||||
#define LOGE printf
|
||||
#define DRACO_LOGI printf
|
||||
#define DRACO_LOGE printf
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
@@ -88,6 +90,10 @@ namespace draco {
|
||||
#define DRACO_MACROS_IMPL_CONCAT_INNER_(x, y) x##y
|
||||
#define DRACO_MACROS_IMPL_CONCAT_(x, y) DRACO_MACROS_IMPL_CONCAT_INNER_(x, y)
|
||||
|
||||
#define DRACO_MACROS_IMPL_CONCAT_INNER_3_(x, y, z) x##y##z
|
||||
#define DRACO_MACROS_IMPL_CONCAT_3_(x, y, z) \
|
||||
DRACO_MACROS_IMPL_CONCAT_INNER_3_(x, y, z)
|
||||
|
||||
// Expand the n-th argument of the macro. Used to select an argument based on
|
||||
// the number of entries in a variadic macro argument. Example usage:
|
||||
//
|
||||
@@ -98,13 +104,20 @@ namespace draco {
|
||||
// #define VARIADIC_MACRO(...)
|
||||
// DRACO_SELECT_NTH_FROM_3(__VA_ARGS__, FUNC_3, FUNC_2, FUNC_1) __VA_ARGS__
|
||||
//
|
||||
#define DRACO_SELECT_NTH_FROM_2(_1, _2, NAME) NAME
|
||||
#define DRACO_SELECT_NTH_FROM_3(_1, _2, _3, NAME) NAME
|
||||
#define DRACO_SELECT_NTH_FROM_4(_1, _2, _3, _4, NAME) NAME
|
||||
#define DRACO_SELECT_NTH_FROM_2(_1, _2, NAME, ...) NAME
|
||||
#define DRACO_SELECT_NTH_FROM_3(_1, _2, _3, NAME, ...) NAME
|
||||
#define DRACO_SELECT_NTH_FROM_4(_1, _2, _3, _4, NAME, ...) NAME
|
||||
|
||||
// Macro that converts the Draco bit-stream into one uint16_t number.
|
||||
// Useful mostly when checking version numbers.
|
||||
#define DRACO_BITSTREAM_VERSION(MAJOR, MINOR) \
|
||||
((static_cast<uint16_t>(MAJOR) << 8) | MINOR)
|
||||
|
||||
// Macro that converts the uint16_t Draco bit-stream number into the major
|
||||
// and minor components respectively.
|
||||
#define DRACO_BISTREAM_VERSION_MAJOR(VERSION) \
|
||||
(static_cast<uint8_t>(VERSION >> 8))
|
||||
#define DRACO_BISTREAM_VERSION_MINOR(VERSION) \
|
||||
(static_cast<uint8_t>(VERSION & 0xFF))
|
||||
|
||||
#endif // DRACO_CORE_MACROS_H_
|
||||
|
||||
2
extern/draco/draco/src/draco/core/options.h
vendored
2
extern/draco/draco/src/draco/core/options.h
vendored
@@ -71,8 +71,6 @@ class Options {
|
||||
private:
|
||||
// All entries are internally stored as strings and converted to the desired
|
||||
// return type based on the used Get* method.
|
||||
// TODO(ostava): Consider adding type safety mechanism that would prevent
|
||||
// unsafe operations such as a conversion from vector to int.
|
||||
std::map<std::string, std::string> options_;
|
||||
};
|
||||
|
||||
|
||||
4
extern/draco/draco/src/draco/core/status.h
vendored
4
extern/draco/draco/src/draco/core/status.h
vendored
@@ -15,6 +15,7 @@
|
||||
#ifndef DRACO_CORE_STATUS_H_
|
||||
#define DRACO_CORE_STATUS_H_
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace draco {
|
||||
@@ -61,6 +62,9 @@ inline std::ostream &operator<<(std::ostream &os, const Status &status) {
|
||||
}
|
||||
|
||||
inline Status OkStatus() { return Status(Status::OK); }
|
||||
inline Status ErrorStatus(const std::string &msg) {
|
||||
return Status(Status::DRACO_ERROR, msg);
|
||||
}
|
||||
|
||||
// Evaluates an expression that returns draco::Status. If the status is not OK,
|
||||
// the macro returns the status object.
|
||||
|
||||
@@ -58,6 +58,7 @@ bool DecodeVarintUnsigned(int depth, IntTypeT *out_val, DecoderBuffer *buffer) {
|
||||
|
||||
// Decodes a specified integer as varint. Note that the IntTypeT must be the
|
||||
// same as the one used in the corresponding EncodeVarint() call.
|
||||
// out_val is undefined if this returns false.
|
||||
template <typename IntTypeT>
|
||||
bool DecodeVarint(IntTypeT *out_val, DecoderBuffer *buffer) {
|
||||
if (std::is_unsigned<IntTypeT>::value) {
|
||||
|
||||
14
extern/draco/draco/src/draco/core/vector_d.h
vendored
14
extern/draco/draco/src/draco/core/vector_d.h
vendored
@@ -20,6 +20,7 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include "draco/core/macros.h"
|
||||
|
||||
@@ -33,7 +34,7 @@ class VectorD {
|
||||
typedef ScalarT Scalar;
|
||||
typedef VectorD<Scalar, dimension_t> Self;
|
||||
|
||||
// TODO(hemmer): Deprecate.
|
||||
// TODO(b/199760123): Deprecate.
|
||||
typedef ScalarT CoefficientType;
|
||||
|
||||
VectorD() {
|
||||
@@ -44,7 +45,7 @@ class VectorD {
|
||||
|
||||
// The following constructor does not compile in opt mode, which for now led
|
||||
// to the constructors further down, which is not ideal.
|
||||
// TODO(hemmer): fix constructor below and remove others.
|
||||
// TODO(b/199760123): Fix constructor below and remove others.
|
||||
// template <typename... Args>
|
||||
// explicit VectorD(Args... args) : v_({args...}) {}
|
||||
|
||||
@@ -110,7 +111,7 @@ class VectorD {
|
||||
|
||||
Scalar &operator[](int i) { return v_[i]; }
|
||||
const Scalar &operator[](int i) const { return v_[i]; }
|
||||
// TODO(hemmer): remove.
|
||||
// TODO(b/199760123): Remove.
|
||||
// Similar to interface of Eigen library.
|
||||
Scalar &operator()(int i) { return v_[i]; }
|
||||
const Scalar &operator()(int i) const { return v_[i]; }
|
||||
@@ -236,7 +237,12 @@ class VectorD {
|
||||
Scalar AbsSum() const {
|
||||
Scalar result(0);
|
||||
for (int i = 0; i < dimension; ++i) {
|
||||
result += std::abs(v_[i]);
|
||||
Scalar next_value = std::abs(v_[i]);
|
||||
if (result > std::numeric_limits<Scalar>::max() - next_value) {
|
||||
// Return the max if adding would have caused an overflow.
|
||||
return std::numeric_limits<Scalar>::max();
|
||||
}
|
||||
result += next_value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,5 @@
|
||||
#define DRACO_MESH_COMPRESSION_SUPPORTED
|
||||
#define DRACO_NORMAL_ENCODING_SUPPORTED
|
||||
#define DRACO_STANDARD_EDGEBREAKER_SUPPORTED
|
||||
#define DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
|
||||
#define DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
|
||||
|
||||
#endif // DRACO_FEATURES_H_
|
||||
|
||||
@@ -66,12 +66,13 @@ bool CornerTable::Reset(int num_faces, int num_vertices) {
|
||||
if (num_faces < 0 || num_vertices < 0) {
|
||||
return false;
|
||||
}
|
||||
if (static_cast<unsigned int>(num_faces) >
|
||||
const unsigned int num_faces_unsigned = num_faces;
|
||||
if (num_faces_unsigned >
|
||||
std::numeric_limits<CornerIndex::ValueType>::max() / 3) {
|
||||
return false;
|
||||
}
|
||||
corner_to_vertex_map_.assign(num_faces * 3, kInvalidVertexIndex);
|
||||
opposite_corners_.assign(num_faces * 3, kInvalidCornerIndex);
|
||||
corner_to_vertex_map_.assign(num_faces_unsigned * 3, kInvalidVertexIndex);
|
||||
opposite_corners_.assign(num_faces_unsigned * 3, kInvalidCornerIndex);
|
||||
vertex_corners_.reserve(num_vertices);
|
||||
valence_cache_.ClearValenceCache();
|
||||
valence_cache_.ClearValenceCacheInaccurate();
|
||||
|
||||
4
extern/draco/draco/src/draco/mesh/mesh.h
vendored
4
extern/draco/draco/src/draco/mesh/mesh.h
vendored
@@ -119,6 +119,10 @@ class Mesh : public PointCloud {
|
||||
const std::vector<PointIndex> &unique_point_ids) override;
|
||||
#endif
|
||||
|
||||
// Exposes |faces_|. Use |faces_| at your own risk. DO NOT store the
|
||||
// reference: the |faces_| object is destroyed with the mesh.
|
||||
IndexTypeVector<FaceIndex, Face> &faces() { return faces_; }
|
||||
|
||||
private:
|
||||
// Mesh specific per-attribute data.
|
||||
std::vector<AttributeData> attribute_data_;
|
||||
|
||||
@@ -130,6 +130,12 @@ class MeshAttributeCornerTable {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDegenerated(FaceIndex face) const {
|
||||
// Introducing seams can't change the degeneracy of the individual faces,
|
||||
// therefore we can delegate the check to the original |corner_table_|.
|
||||
return corner_table_->IsDegenerated(face);
|
||||
}
|
||||
|
||||
bool no_interior_seams() const { return no_interior_seams_; }
|
||||
const CornerTable *corner_table() const { return corner_table_; }
|
||||
|
||||
|
||||
351
extern/draco/draco/src/draco/mesh/mesh_cleanup.cc
vendored
351
extern/draco/draco/src/draco/mesh/mesh_cleanup.cc
vendored
@@ -14,25 +14,42 @@
|
||||
//
|
||||
#include "draco/mesh/mesh_cleanup.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "draco/core/hash_utils.h"
|
||||
|
||||
namespace draco {
|
||||
|
||||
bool MeshCleanup::operator()(Mesh *mesh, const MeshCleanupOptions &options) {
|
||||
if (!options.remove_degenerated_faces && !options.remove_unused_attributes) {
|
||||
return true; // Nothing to cleanup.
|
||||
Status MeshCleanup::Cleanup(Mesh *mesh, const MeshCleanupOptions &options) {
|
||||
if (!options.remove_degenerated_faces && !options.remove_unused_attributes &&
|
||||
!options.remove_duplicate_faces && !options.make_geometry_manifold) {
|
||||
return OkStatus(); // Nothing to cleanup.
|
||||
}
|
||||
const PointAttribute *const pos_att =
|
||||
mesh->GetNamedAttribute(GeometryAttribute::POSITION);
|
||||
if (pos_att == nullptr) {
|
||||
return false;
|
||||
}
|
||||
// Array that is going to store whether a corresponding point is used.
|
||||
std::vector<bool> is_point_used;
|
||||
if (options.remove_unused_attributes) {
|
||||
is_point_used.resize(mesh->num_points(), false);
|
||||
return Status(Status::DRACO_ERROR, "Missing position attribute.");
|
||||
}
|
||||
|
||||
if (options.remove_degenerated_faces) {
|
||||
RemoveDegeneratedFaces(mesh);
|
||||
}
|
||||
|
||||
if (options.remove_duplicate_faces) {
|
||||
RemoveDuplicateFaces(mesh);
|
||||
}
|
||||
|
||||
if (options.remove_unused_attributes) {
|
||||
RemoveUnusedAttributes(mesh);
|
||||
}
|
||||
|
||||
return OkStatus();
|
||||
}
|
||||
|
||||
void MeshCleanup::RemoveDegeneratedFaces(Mesh *mesh) {
|
||||
const PointAttribute *const pos_att =
|
||||
mesh->GetNamedAttribute(GeometryAttribute::POSITION);
|
||||
FaceIndex::ValueType num_degenerated_faces = 0;
|
||||
PointIndex::ValueType num_new_points = 0;
|
||||
// Array for storing position indices on a face.
|
||||
std::array<AttributeValueIndex, 3> pos_indices;
|
||||
for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
|
||||
@@ -40,149 +57,195 @@ bool MeshCleanup::operator()(Mesh *mesh, const MeshCleanupOptions &options) {
|
||||
for (int p = 0; p < 3; ++p) {
|
||||
pos_indices[p] = pos_att->mapped_index(face[p]);
|
||||
}
|
||||
bool is_face_valid = true;
|
||||
if (options.remove_degenerated_faces) {
|
||||
if (pos_indices[0] == pos_indices[1] ||
|
||||
pos_indices[0] == pos_indices[2] ||
|
||||
pos_indices[1] == pos_indices[2]) {
|
||||
++num_degenerated_faces;
|
||||
is_face_valid = false;
|
||||
} else if (num_degenerated_faces > 0) {
|
||||
// Copy the face to its new location.
|
||||
mesh->SetFace(f - num_degenerated_faces, face);
|
||||
}
|
||||
}
|
||||
if (options.remove_unused_attributes && is_face_valid) {
|
||||
for (int p = 0; p < 3; ++p) {
|
||||
if (!is_point_used[face[p].value()]) {
|
||||
is_point_used[face[p].value()] = true;
|
||||
++num_new_points;
|
||||
}
|
||||
}
|
||||
if (pos_indices[0] == pos_indices[1] || pos_indices[0] == pos_indices[2] ||
|
||||
pos_indices[1] == pos_indices[2]) {
|
||||
++num_degenerated_faces;
|
||||
} else if (num_degenerated_faces > 0) {
|
||||
// Copy the face to its new location.
|
||||
mesh->SetFace(f - num_degenerated_faces, face);
|
||||
}
|
||||
}
|
||||
if (num_degenerated_faces > 0) {
|
||||
mesh->SetNumFaces(mesh->num_faces() - num_degenerated_faces);
|
||||
}
|
||||
if (options.remove_unused_attributes) {
|
||||
bool points_changed = false;
|
||||
const PointIndex::ValueType num_original_points = mesh->num_points();
|
||||
// Map from old points to the new ones.
|
||||
IndexTypeVector<PointIndex, PointIndex> point_map(num_original_points);
|
||||
if (num_new_points < static_cast<int>(mesh->num_points())) {
|
||||
// Some of the points were removed. We need to remap the old points to the
|
||||
// new ones.
|
||||
num_new_points = 0;
|
||||
for (PointIndex i(0); i < num_original_points; ++i) {
|
||||
if (is_point_used[i.value()]) {
|
||||
point_map[i] = num_new_points++;
|
||||
} else {
|
||||
point_map[i] = kInvalidPointIndex;
|
||||
}
|
||||
}
|
||||
// Go over faces and update their points.
|
||||
for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
|
||||
Mesh::Face face = mesh->face(f);
|
||||
for (int p = 0; p < 3; ++p) {
|
||||
face[p] = point_map[face[p]];
|
||||
}
|
||||
mesh->SetFace(f, face);
|
||||
}
|
||||
// Set the new number of points.
|
||||
mesh->set_num_points(num_new_points);
|
||||
points_changed = true;
|
||||
} else {
|
||||
// No points were removed. Initialize identity map between the old and new
|
||||
// points.
|
||||
for (PointIndex i(0); i < num_original_points; ++i) {
|
||||
point_map[i] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update index mapping for attributes.
|
||||
IndexTypeVector<AttributeValueIndex, uint8_t> is_att_index_used;
|
||||
IndexTypeVector<AttributeValueIndex, AttributeValueIndex> att_index_map;
|
||||
for (int a = 0; a < mesh->num_attributes(); ++a) {
|
||||
PointAttribute *const att = mesh->attribute(a);
|
||||
// First detect which attribute entries are used (included in a point).
|
||||
is_att_index_used.assign(att->size(), 0);
|
||||
att_index_map.clear();
|
||||
AttributeValueIndex::ValueType num_used_entries = 0;
|
||||
for (PointIndex i(0); i < num_original_points; ++i) {
|
||||
if (point_map[i] != kInvalidPointIndex) {
|
||||
const AttributeValueIndex entry_id = att->mapped_index(i);
|
||||
if (!is_att_index_used[entry_id]) {
|
||||
is_att_index_used[entry_id] = 1;
|
||||
++num_used_entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool att_indices_changed = false;
|
||||
// If there are some unused attribute entries, remap the attribute values
|
||||
// in the attribute buffer.
|
||||
if (num_used_entries < static_cast<int>(att->size())) {
|
||||
att_index_map.resize(att->size());
|
||||
num_used_entries = 0;
|
||||
for (AttributeValueIndex i(0); i < static_cast<uint32_t>(att->size());
|
||||
++i) {
|
||||
if (is_att_index_used[i]) {
|
||||
att_index_map[i] = num_used_entries;
|
||||
if (i > num_used_entries) {
|
||||
const uint8_t *const src_add = att->GetAddress(i);
|
||||
att->buffer()->Write(
|
||||
att->GetBytePos(AttributeValueIndex(num_used_entries)),
|
||||
src_add, att->byte_stride());
|
||||
}
|
||||
++num_used_entries;
|
||||
}
|
||||
}
|
||||
// Update the number of unique entries in the vertex buffer.
|
||||
att->Resize(num_used_entries);
|
||||
att_indices_changed = true;
|
||||
}
|
||||
// If either the points or attribute indices have changed, we need to
|
||||
// update the attribute index mapping.
|
||||
if (points_changed || att_indices_changed) {
|
||||
if (att->is_mapping_identity()) {
|
||||
// The mapping was identity. It'll remain identity only if the
|
||||
// number of point and attribute indices is still the same.
|
||||
if (num_used_entries != static_cast<int>(mesh->num_points())) {
|
||||
// We need to create an explicit mapping.
|
||||
// First we need to initialize the explicit map to the original
|
||||
// number of points to recreate the original identity map.
|
||||
att->SetExplicitMapping(num_original_points);
|
||||
// Set the entries of the explicit map to identity.
|
||||
for (PointIndex::ValueType i = 0; i < num_original_points; ++i) {
|
||||
att->SetPointMapEntry(PointIndex(i), AttributeValueIndex(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!att->is_mapping_identity()) {
|
||||
// Explicit mapping between points and local attribute indices.
|
||||
for (PointIndex i(0); i < num_original_points; ++i) {
|
||||
// The new point id that maps to the currently processed attribute
|
||||
// entry.
|
||||
const PointIndex new_point_id = point_map[i];
|
||||
if (new_point_id == kInvalidPointIndex) {
|
||||
continue;
|
||||
}
|
||||
// Index of the currently processed attribute entry in the original
|
||||
// mesh.
|
||||
const AttributeValueIndex original_entry_index =
|
||||
att->mapped_index(i);
|
||||
// New index of the same entry after unused entries were removed.
|
||||
const AttributeValueIndex new_entry_index =
|
||||
att_index_map[original_entry_index];
|
||||
att->SetPointMapEntry(new_point_id, new_entry_index);
|
||||
}
|
||||
// If the number of points changed, we need to set a new explicit map
|
||||
// size.
|
||||
att->SetExplicitMapping(mesh->num_points());
|
||||
}
|
||||
void MeshCleanup::RemoveDuplicateFaces(Mesh *mesh) {
|
||||
const PointAttribute *const pos_att =
|
||||
mesh->GetNamedAttribute(GeometryAttribute::POSITION);
|
||||
|
||||
typedef std::array<AttributeValueIndex::ValueType, 3> PosTriplet;
|
||||
PosTriplet pos_indices;
|
||||
std::unordered_set<PosTriplet, HashArray<PosTriplet>> is_face_used;
|
||||
|
||||
uint32_t num_duplicate_faces = 0;
|
||||
for (FaceIndex fi(0); fi < mesh->num_faces(); ++fi) {
|
||||
const auto f = mesh->face(fi);
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
pos_indices[c] = pos_att->mapped_index(f[c]).value();
|
||||
}
|
||||
// Shift the position indices until the smallest index is the first one.
|
||||
while (pos_indices[0] > pos_indices[1] || pos_indices[0] > pos_indices[2]) {
|
||||
// Shift to the left.
|
||||
std::swap(pos_indices[0], pos_indices[1]);
|
||||
std::swap(pos_indices[1], pos_indices[2]);
|
||||
}
|
||||
// Check if have encountered the same position triplet on a different face.
|
||||
if (is_face_used.find(pos_indices) != is_face_used.end()) {
|
||||
// Duplicate face. Ignore it.
|
||||
num_duplicate_faces++;
|
||||
} else {
|
||||
// Insert new face to the set.
|
||||
is_face_used.insert(pos_indices);
|
||||
if (num_duplicate_faces > 0) {
|
||||
// Copy the face to its new location.
|
||||
mesh->SetFace(fi - num_duplicate_faces, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (num_duplicate_faces > 0) {
|
||||
mesh->SetNumFaces(mesh->num_faces() - num_duplicate_faces);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshCleanup::RemoveUnusedAttributes(Mesh *mesh) {
|
||||
// Array that is going to store whether a corresponding point is used.
|
||||
std::vector<bool> is_point_used;
|
||||
PointIndex::ValueType num_new_points = 0;
|
||||
is_point_used.resize(mesh->num_points(), false);
|
||||
for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
|
||||
const Mesh::Face &face = mesh->face(f);
|
||||
for (int p = 0; p < 3; ++p) {
|
||||
if (!is_point_used[face[p].value()]) {
|
||||
is_point_used[face[p].value()] = true;
|
||||
++num_new_points;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool points_changed = false;
|
||||
const PointIndex::ValueType num_original_points = mesh->num_points();
|
||||
// Map from old points to the new ones.
|
||||
IndexTypeVector<PointIndex, PointIndex> point_map(num_original_points);
|
||||
if (num_new_points < static_cast<int>(mesh->num_points())) {
|
||||
// Some of the points were removed. We need to remap the old points to the
|
||||
// new ones.
|
||||
num_new_points = 0;
|
||||
for (PointIndex i(0); i < num_original_points; ++i) {
|
||||
if (is_point_used[i.value()]) {
|
||||
point_map[i] = num_new_points++;
|
||||
} else {
|
||||
point_map[i] = kInvalidPointIndex;
|
||||
}
|
||||
}
|
||||
// Go over faces and update their points.
|
||||
for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
|
||||
Mesh::Face face = mesh->face(f);
|
||||
for (int p = 0; p < 3; ++p) {
|
||||
face[p] = point_map[face[p]];
|
||||
}
|
||||
mesh->SetFace(f, face);
|
||||
}
|
||||
// Set the new number of points.
|
||||
mesh->set_num_points(num_new_points);
|
||||
points_changed = true;
|
||||
} else {
|
||||
// No points were removed. Initialize identity map between the old and new
|
||||
// points.
|
||||
for (PointIndex i(0); i < num_original_points; ++i) {
|
||||
point_map[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Update index mapping for attributes.
|
||||
IndexTypeVector<AttributeValueIndex, uint8_t> is_att_index_used;
|
||||
IndexTypeVector<AttributeValueIndex, AttributeValueIndex> att_index_map;
|
||||
for (int a = 0; a < mesh->num_attributes(); ++a) {
|
||||
PointAttribute *const att = mesh->attribute(a);
|
||||
// First detect which attribute entries are used (included in a point).
|
||||
is_att_index_used.assign(att->size(), 0);
|
||||
att_index_map.clear();
|
||||
AttributeValueIndex::ValueType num_used_entries = 0;
|
||||
for (PointIndex i(0); i < num_original_points; ++i) {
|
||||
if (point_map[i] != kInvalidPointIndex) {
|
||||
const AttributeValueIndex entry_id = att->mapped_index(i);
|
||||
if (!is_att_index_used[entry_id]) {
|
||||
is_att_index_used[entry_id] = 1;
|
||||
++num_used_entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool att_indices_changed = false;
|
||||
// If there are some unused attribute entries, remap the attribute values
|
||||
// in the attribute buffer.
|
||||
if (num_used_entries < static_cast<int>(att->size())) {
|
||||
att_index_map.resize(att->size());
|
||||
num_used_entries = 0;
|
||||
for (AttributeValueIndex i(0); i < static_cast<uint32_t>(att->size());
|
||||
++i) {
|
||||
if (is_att_index_used[i]) {
|
||||
att_index_map[i] = num_used_entries;
|
||||
if (i > num_used_entries) {
|
||||
const uint8_t *const src_add = att->GetAddress(i);
|
||||
att->buffer()->Write(
|
||||
att->GetBytePos(AttributeValueIndex(num_used_entries)), src_add,
|
||||
att->byte_stride());
|
||||
}
|
||||
++num_used_entries;
|
||||
}
|
||||
}
|
||||
// Update the number of unique entries in the vertex buffer.
|
||||
att->Resize(num_used_entries);
|
||||
att_indices_changed = true;
|
||||
}
|
||||
// If either the points or attribute indices have changed, we need to
|
||||
// update the attribute index mapping.
|
||||
if (points_changed || att_indices_changed) {
|
||||
if (att->is_mapping_identity()) {
|
||||
// The mapping was identity. It'll remain identity only if the
|
||||
// number of point and attribute indices is still the same.
|
||||
if (num_used_entries != static_cast<int>(mesh->num_points())) {
|
||||
// We need to create an explicit mapping.
|
||||
// First we need to initialize the explicit map to the original
|
||||
// number of points to recreate the original identity map.
|
||||
att->SetExplicitMapping(num_original_points);
|
||||
// Set the entries of the explicit map to identity.
|
||||
for (PointIndex::ValueType i = 0; i < num_original_points; ++i) {
|
||||
att->SetPointMapEntry(PointIndex(i), AttributeValueIndex(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!att->is_mapping_identity()) {
|
||||
// Explicit mapping between points and local attribute indices.
|
||||
for (PointIndex i(0); i < num_original_points; ++i) {
|
||||
// The new point id that maps to the currently processed attribute
|
||||
// entry.
|
||||
const PointIndex new_point_id = point_map[i];
|
||||
if (new_point_id == kInvalidPointIndex) {
|
||||
continue;
|
||||
}
|
||||
// Index of the currently processed attribute entry in the original
|
||||
// mesh.
|
||||
const AttributeValueIndex original_entry_index = att->mapped_index(i);
|
||||
// New index of the same entry after unused entries were removed.
|
||||
const AttributeValueIndex new_entry_index =
|
||||
att_indices_changed ? att_index_map[original_entry_index]
|
||||
: original_entry_index;
|
||||
|
||||
// Update the mapping. Note that the new point index is always smaller
|
||||
// than the processed index |i|, making this operation safe.
|
||||
att->SetPointMapEntry(new_point_id, new_entry_index);
|
||||
}
|
||||
// If the number of points changed, we need to set a new explicit map
|
||||
// size.
|
||||
att->SetExplicitMapping(mesh->num_points());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Status MeshCleanup::MakeGeometryManifold(Mesh *mesh) {
|
||||
return Status(Status::DRACO_ERROR, "Unsupported function.");
|
||||
}
|
||||
|
||||
} // namespace draco
|
||||
|
||||
27
extern/draco/draco/src/draco/mesh/mesh_cleanup.h
vendored
27
extern/draco/draco/src/draco/mesh/mesh_cleanup.h
vendored
@@ -15,27 +15,44 @@
|
||||
#ifndef DRACO_MESH_MESH_CLEANUP_H_
|
||||
#define DRACO_MESH_MESH_CLEANUP_H_
|
||||
|
||||
#include "draco/core/status.h"
|
||||
#include "draco/mesh/mesh.h"
|
||||
|
||||
namespace draco {
|
||||
|
||||
// Options used by the MeshCleanup class.
|
||||
struct MeshCleanupOptions {
|
||||
MeshCleanupOptions()
|
||||
: remove_degenerated_faces(true), remove_unused_attributes(true) {}
|
||||
// If true, the cleanup tool removes any face where two or more vertices
|
||||
// share the same position index.
|
||||
bool remove_degenerated_faces;
|
||||
bool remove_degenerated_faces = true;
|
||||
|
||||
// If true, the cleanup tool removes all duplicate faces. A pair of faces is
|
||||
// duplicate if both faces share the same position indices on all vertices
|
||||
// (that is, position values have to be duduplicated). Note that all
|
||||
// non-position properties are currently ignored.
|
||||
bool remove_duplicate_faces = true;
|
||||
|
||||
// If true, the cleanup tool removes any unused attribute value or unused
|
||||
// point id. For example, it can be used to remove isolated vertices.
|
||||
bool remove_unused_attributes;
|
||||
bool remove_unused_attributes = true;
|
||||
|
||||
// If true, the cleanup tool splits vertices along non-manifold edges and
|
||||
// vertices. This ensures that the connectivity defined by position indices
|
||||
// is manifold.
|
||||
bool make_geometry_manifold = false;
|
||||
};
|
||||
|
||||
// Tool that can be used for removing bad or unused data from draco::Meshes.
|
||||
class MeshCleanup {
|
||||
public:
|
||||
// Performs in-place cleanup of the input mesh according to the input options.
|
||||
bool operator()(Mesh *mesh, const MeshCleanupOptions &options);
|
||||
static Status Cleanup(Mesh *mesh, const MeshCleanupOptions &options);
|
||||
|
||||
private:
|
||||
static void RemoveDegeneratedFaces(Mesh *mesh);
|
||||
static void RemoveDuplicateFaces(Mesh *mesh);
|
||||
static void RemoveUnusedAttributes(Mesh *mesh);
|
||||
static Status MakeGeometryManifold(Mesh *mesh);
|
||||
};
|
||||
|
||||
} // namespace draco
|
||||
|
||||
@@ -67,7 +67,6 @@ inline bool IsCornerOppositeToAttributeSeam(CornerIndex ci,
|
||||
// Interpolates an attribute value on a face using given barycentric
|
||||
// coordinates. InterpolatedVectorT should be a VectorD that corresponds to the
|
||||
// values stored in the attribute.
|
||||
// TODO(ostava): Find a better place for this.
|
||||
template <typename InterpolatedVectorT>
|
||||
InterpolatedVectorT ComputeInterpolatedAttributeValueOnMeshFace(
|
||||
const Mesh &mesh, const PointAttribute &attribute, FaceIndex fi,
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_
|
||||
#define DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_
|
||||
#ifndef DRACO_MESH_MESH_STRIPIFIER_H_
|
||||
#define DRACO_MESH_MESH_STRIPIFIER_H_
|
||||
|
||||
#include "draco/mesh/mesh_misc_functions.h"
|
||||
|
||||
@@ -71,8 +71,6 @@ class MeshStripifier {
|
||||
mesh_ = &mesh;
|
||||
num_strips_ = 0;
|
||||
num_encoded_faces_ = 0;
|
||||
// TODO(ostava): We may be able to avoid computing the corner table if we
|
||||
// already have it stored somewhere.
|
||||
corner_table_ = CreateCornerTableFromPositionAttribute(mesh_);
|
||||
if (corner_table_ == nullptr) {
|
||||
return false;
|
||||
@@ -257,4 +255,4 @@ bool MeshStripifier::GenerateTriangleStripsWithDegenerateTriangles(
|
||||
|
||||
} // namespace draco
|
||||
|
||||
#endif // DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_
|
||||
#endif // DRACO_MESH_MESH_STRIPIFIER_H_
|
||||
|
||||
@@ -41,8 +41,6 @@ void TriangleSoupMeshBuilder::SetAttributeValuesForFace(
|
||||
att->SetAttributeValue(AttributeValueIndex(start_index), corner_value_0);
|
||||
att->SetAttributeValue(AttributeValueIndex(start_index + 1), corner_value_1);
|
||||
att->SetAttributeValue(AttributeValueIndex(start_index + 2), corner_value_2);
|
||||
// TODO(ostava): The below code should be called only for one attribute.
|
||||
// It will work OK even for multiple attributes, but it's redundant.
|
||||
mesh_->SetFace(face_id,
|
||||
{{PointIndex(start_index), PointIndex(start_index + 1),
|
||||
PointIndex(start_index + 2)}});
|
||||
|
||||
@@ -18,6 +18,19 @@
|
||||
|
||||
namespace draco {
|
||||
|
||||
AttributeMetadata::AttributeMetadata(const AttributeMetadata &metadata)
|
||||
: Metadata(metadata) {
|
||||
att_unique_id_ = metadata.att_unique_id_;
|
||||
}
|
||||
|
||||
GeometryMetadata::GeometryMetadata(const GeometryMetadata &metadata)
|
||||
: Metadata(metadata) {
|
||||
for (size_t i = 0; i < metadata.att_metadatas_.size(); ++i) {
|
||||
att_metadatas_.push_back(std::unique_ptr<AttributeMetadata>(
|
||||
new AttributeMetadata(*metadata.att_metadatas_[i])));
|
||||
}
|
||||
}
|
||||
|
||||
const AttributeMetadata *GeometryMetadata::GetAttributeMetadataByStringEntry(
|
||||
const std::string &entry_name, const std::string &entry_value) const {
|
||||
for (auto &&att_metadata : att_metadatas_) {
|
||||
@@ -35,7 +48,7 @@ const AttributeMetadata *GeometryMetadata::GetAttributeMetadataByStringEntry(
|
||||
|
||||
bool GeometryMetadata::AddAttributeMetadata(
|
||||
std::unique_ptr<AttributeMetadata> att_metadata) {
|
||||
if (!att_metadata.get()) {
|
||||
if (!att_metadata) {
|
||||
return false;
|
||||
}
|
||||
att_metadatas_.push_back(std::move(att_metadata));
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace draco {
|
||||
class AttributeMetadata : public Metadata {
|
||||
public:
|
||||
AttributeMetadata() : att_unique_id_(0) {}
|
||||
AttributeMetadata(const AttributeMetadata &metadata);
|
||||
explicit AttributeMetadata(const Metadata &metadata)
|
||||
: Metadata(metadata), att_unique_id_(0) {}
|
||||
|
||||
@@ -57,6 +58,7 @@ struct AttributeMetadataHasher {
|
||||
class GeometryMetadata : public Metadata {
|
||||
public:
|
||||
GeometryMetadata() {}
|
||||
GeometryMetadata(const GeometryMetadata &metadata);
|
||||
explicit GeometryMetadata(const Metadata &metadata) : Metadata(metadata) {}
|
||||
|
||||
const AttributeMetadata *GetAttributeMetadataByStringEntry(
|
||||
|
||||
@@ -122,6 +122,14 @@ const Metadata *Metadata::GetSubMetadata(const std::string &name) const {
|
||||
return sub_ptr->second.get();
|
||||
}
|
||||
|
||||
Metadata *Metadata::sub_metadata(const std::string &name) {
|
||||
auto sub_ptr = sub_metadatas_.find(name);
|
||||
if (sub_ptr == sub_metadatas_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return sub_ptr->second.get();
|
||||
}
|
||||
|
||||
void Metadata::RemoveEntry(const std::string &name) {
|
||||
// Actually just remove "name", no need to check if it exists.
|
||||
auto entry_ptr = entries_.find(name);
|
||||
|
||||
@@ -147,6 +147,7 @@ class Metadata {
|
||||
bool AddSubMetadata(const std::string &name,
|
||||
std::unique_ptr<Metadata> sub_metadata);
|
||||
const Metadata *GetSubMetadata(const std::string &name) const;
|
||||
Metadata *sub_metadata(const std::string &name);
|
||||
|
||||
void RemoveEntry(const std::string &name);
|
||||
|
||||
|
||||
@@ -78,8 +78,10 @@ bool MetadataDecoder::DecodeMetadata(Metadata *metadata) {
|
||||
std::unique_ptr<Metadata> sub_metadata =
|
||||
std::unique_ptr<Metadata>(new Metadata());
|
||||
metadata = sub_metadata.get();
|
||||
mp.parent_metadata->AddSubMetadata(sub_metadata_name,
|
||||
std::move(sub_metadata));
|
||||
if (!mp.parent_metadata->AddSubMetadata(sub_metadata_name,
|
||||
std::move(sub_metadata))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (metadata == nullptr) {
|
||||
return false;
|
||||
@@ -98,6 +100,10 @@ bool MetadataDecoder::DecodeMetadata(Metadata *metadata) {
|
||||
if (!DecodeVarint(&num_sub_metadata, buffer_)) {
|
||||
return false;
|
||||
}
|
||||
if (num_sub_metadata > buffer_->remaining_size()) {
|
||||
// The decoded number of metadata items is unreasonably high.
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < num_sub_metadata; ++i) {
|
||||
metadata_stack.push_back({metadata, nullptr});
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ void PointCloud::ApplyPointIdDeduplication(
|
||||
bool PointCloud::DeduplicateAttributeValues() {
|
||||
// Go over all attributes and create mapping between duplicate entries.
|
||||
if (num_points() == 0) {
|
||||
return false; // Unexpected attribute size.
|
||||
return true; // Nothing to deduplicate.
|
||||
}
|
||||
// Deduplicate all attributes.
|
||||
for (int32_t att_id = 0; att_id < num_attributes(); ++att_id) {
|
||||
@@ -253,17 +253,11 @@ bool PointCloud::DeduplicateAttributeValues() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO(xiaoxumeng): Consider to cash the BBox.
|
||||
// TODO(b/199760503): Consider to cache the BBox.
|
||||
BoundingBox PointCloud::ComputeBoundingBox() const {
|
||||
BoundingBox bounding_box =
|
||||
BoundingBox(Vector3f(std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max()),
|
||||
Vector3f(-std::numeric_limits<float>::max(),
|
||||
-std::numeric_limits<float>::max(),
|
||||
-std::numeric_limits<float>::max()));
|
||||
BoundingBox bounding_box;
|
||||
auto pc_att = GetNamedAttribute(GeometryAttribute::POSITION);
|
||||
// TODO(xiaoxumeng): Make the BoundingBox a template type, it may not be easy
|
||||
// TODO(b/199760503): Make the BoundingBox a template type, it may not be easy
|
||||
// because PointCloud is not a template.
|
||||
// Or simply add some preconditioning here to make sure the position attribute
|
||||
// is valid, because the current code works only if the position attribute is
|
||||
@@ -274,7 +268,7 @@ BoundingBox PointCloud::ComputeBoundingBox() const {
|
||||
for (AttributeValueIndex i(0); i < static_cast<uint32_t>(pc_att->size());
|
||||
++i) {
|
||||
pc_att->GetValue(i, &p[0]);
|
||||
bounding_box.update_bounding_box(p);
|
||||
bounding_box.Update(p);
|
||||
}
|
||||
return bounding_box;
|
||||
}
|
||||
|
||||
30
extern/draco/patches/blender.patch
vendored
Normal file
30
extern/draco/patches/blender.patch
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
diff --git a/draco/src/draco/attributes/geometry_attribute.h b/draco/src/draco/attributes/geometry_attribute.h
|
||||
index fd478a4..c1c0148 100644
|
||||
--- a/draco/src/draco/attributes/geometry_attribute.h
|
||||
+++ b/draco/src/draco/attributes/geometry_attribute.h
|
||||
@@ -285,11 +285,25 @@ class GeometryAttribute {
|
||||
// Make sure the in_value fits within the range of values that OutT
|
||||
// is able to represent. Perform the check only for integral types.
|
||||
if (std::is_integral<T>::value && std::is_integral<OutT>::value) {
|
||||
+#ifdef _MSC_VER
|
||||
+# pragma warning(push)
|
||||
+# pragma warning(disable:4804)
|
||||
+#endif
|
||||
+#if defined(__GNUC__) && !defined(__clang__)
|
||||
+# pragma GCC diagnostic push
|
||||
+# pragma GCC diagnostic ignored "-Wbool-compare"
|
||||
+#endif
|
||||
static constexpr OutT kOutMin =
|
||||
std::is_signed<T>::value ? std::numeric_limits<OutT>::lowest() : 0;
|
||||
if (in_value < kOutMin || in_value > std::numeric_limits<OutT>::max()) {
|
||||
return false;
|
||||
}
|
||||
+#ifdef __GNUC__
|
||||
+# pragma GCC diagnostic pop
|
||||
+#endif
|
||||
+#ifdef _MSC_VER
|
||||
+# pragma warning(pop)
|
||||
+#endif
|
||||
}
|
||||
|
||||
out_value[i] = static_cast<OutT>(in_value);
|
||||
28
extern/draco/src/common.cpp
vendored
28
extern/draco/src/common.cpp
vendored
@@ -54,20 +54,20 @@ size_t getComponentByteLength(size_t componentType)
|
||||
{
|
||||
switch (componentType)
|
||||
{
|
||||
case ComponentType::Byte:
|
||||
case ComponentType::UnsignedByte:
|
||||
return 1;
|
||||
|
||||
case ComponentType::Short:
|
||||
case ComponentType::UnsignedShort:
|
||||
return 2;
|
||||
|
||||
case ComponentType::UnsignedInt:
|
||||
case ComponentType::Float:
|
||||
return 4;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
case ComponentType::Byte:
|
||||
case ComponentType::UnsignedByte:
|
||||
return 1;
|
||||
|
||||
case ComponentType::Short:
|
||||
case ComponentType::UnsignedShort:
|
||||
return 2;
|
||||
|
||||
case ComponentType::UnsignedInt:
|
||||
case ComponentType::Float:
|
||||
return 4;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2
extern/draco/src/common.h
vendored
2
extern/draco/src/common.h
vendored
@@ -33,7 +33,7 @@
|
||||
#define API(returnType) extern "C" returnType
|
||||
#endif
|
||||
|
||||
enum ComponentType: size_t
|
||||
enum ComponentType : size_t
|
||||
{
|
||||
Byte = 5120,
|
||||
UnsignedByte = 5121,
|
||||
|
||||
74
extern/draco/src/decoder.cpp
vendored
74
extern/draco/src/decoder.cpp
vendored
@@ -17,7 +17,6 @@
|
||||
* @date 2020-11-18
|
||||
*/
|
||||
|
||||
|
||||
#include "decoder.h"
|
||||
|
||||
#include <memory>
|
||||
@@ -30,7 +29,8 @@
|
||||
|
||||
#define LOG_PREFIX "DracoDecoder | "
|
||||
|
||||
struct Decoder {
|
||||
struct Decoder
|
||||
{
|
||||
std::unique_ptr<draco::Mesh> mesh;
|
||||
std::vector<uint8_t> indexBuffer;
|
||||
std::map<uint32_t, std::vector<uint8_t>> buffers;
|
||||
@@ -54,20 +54,20 @@ bool decoderDecode(Decoder *decoder, void *data, size_t byteLength)
|
||||
draco::Decoder dracoDecoder;
|
||||
draco::DecoderBuffer dracoDecoderBuffer;
|
||||
dracoDecoderBuffer.Init(reinterpret_cast<char *>(data), byteLength);
|
||||
|
||||
|
||||
auto decoderStatus = dracoDecoder.DecodeMeshFromBuffer(&dracoDecoderBuffer);
|
||||
if (!decoderStatus.ok())
|
||||
{
|
||||
printf(LOG_PREFIX "Error during Draco decoding: %s\n", decoderStatus.status().error_msg());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
decoder->mesh = std::move(decoderStatus).value();
|
||||
decoder->vertexCount = decoder->mesh->num_points();
|
||||
decoder->indexCount = decoder->mesh->num_faces() * 3;
|
||||
|
||||
|
||||
printf(LOG_PREFIX "Decoded %" PRIu32 " vertices, %" PRIu32 " indices\n", decoder->vertexCount, decoder->indexCount);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -83,32 +83,32 @@ uint32_t decoderGetIndexCount(Decoder *decoder)
|
||||
|
||||
bool decoderAttributeIsNormalized(Decoder *decoder, uint32_t id)
|
||||
{
|
||||
const draco::PointAttribute* attribute = decoder->mesh->GetAttributeByUniqueId(id);
|
||||
const draco::PointAttribute *attribute = decoder->mesh->GetAttributeByUniqueId(id);
|
||||
return attribute != nullptr && attribute->normalized();
|
||||
}
|
||||
|
||||
bool decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType)
|
||||
{
|
||||
const draco::PointAttribute* attribute = decoder->mesh->GetAttributeByUniqueId(id);
|
||||
|
||||
const draco::PointAttribute *attribute = decoder->mesh->GetAttributeByUniqueId(id);
|
||||
|
||||
if (attribute == nullptr)
|
||||
{
|
||||
printf(LOG_PREFIX "Attribute with id=%" PRIu32 " does not exist in Draco data\n", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
size_t stride = getAttributeStride(componentType, dataType);
|
||||
|
||||
|
||||
std::vector<uint8_t> decodedData;
|
||||
decodedData.resize(stride * decoder->vertexCount);
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < decoder->vertexCount; ++i)
|
||||
{
|
||||
auto index = attribute->mapped_index(draco::PointIndex(i));
|
||||
uint8_t *value = decodedData.data() + i * stride;
|
||||
|
||||
|
||||
bool converted = false;
|
||||
|
||||
|
||||
switch (componentType)
|
||||
{
|
||||
case ComponentType::Byte:
|
||||
@@ -139,7 +139,7 @@ bool decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, c
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
decoder->buffers[id] = decodedData;
|
||||
return true;
|
||||
}
|
||||
@@ -166,13 +166,13 @@ void decoderCopyAttribute(Decoder *decoder, size_t id, void *output)
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
void decodeIndices(Decoder *decoder)
|
||||
{
|
||||
std::vector<uint8_t> decodedIndices;
|
||||
decodedIndices.resize(decoder->indexCount * sizeof(T));
|
||||
T *typedView = reinterpret_cast<T *>(decodedIndices.data());
|
||||
|
||||
|
||||
for (uint32_t faceIndex = 0; faceIndex < decoder->mesh->num_faces(); ++faceIndex)
|
||||
{
|
||||
const draco::Mesh::Face &face = decoder->mesh->face(draco::FaceIndex(faceIndex));
|
||||
@@ -180,7 +180,7 @@ void decodeIndices(Decoder *decoder)
|
||||
typedView[faceIndex * 3 + 1] = face[1].value();
|
||||
typedView[faceIndex * 3 + 2] = face[2].value();
|
||||
}
|
||||
|
||||
|
||||
decoder->indexBuffer = decodedIndices;
|
||||
}
|
||||
|
||||
@@ -188,26 +188,26 @@ bool decoderReadIndices(Decoder *decoder, size_t indexComponentType)
|
||||
{
|
||||
switch (indexComponentType)
|
||||
{
|
||||
case ComponentType::Byte:
|
||||
decodeIndices<int8_t>(decoder);
|
||||
break;
|
||||
case ComponentType::UnsignedByte:
|
||||
decodeIndices<uint8_t>(decoder);
|
||||
break;
|
||||
case ComponentType::Short:
|
||||
decodeIndices<int16_t>(decoder);
|
||||
break;
|
||||
case ComponentType::UnsignedShort:
|
||||
decodeIndices<uint16_t>(decoder);
|
||||
break;
|
||||
case ComponentType::UnsignedInt:
|
||||
decodeIndices<uint32_t>(decoder);
|
||||
break;
|
||||
default:
|
||||
printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
|
||||
return false;
|
||||
case ComponentType::Byte:
|
||||
decodeIndices<int8_t>(decoder);
|
||||
break;
|
||||
case ComponentType::UnsignedByte:
|
||||
decodeIndices<uint8_t>(decoder);
|
||||
break;
|
||||
case ComponentType::Short:
|
||||
decodeIndices<int16_t>(decoder);
|
||||
break;
|
||||
case ComponentType::UnsignedShort:
|
||||
decodeIndices<uint16_t>(decoder);
|
||||
break;
|
||||
case ComponentType::UnsignedInt:
|
||||
decodeIndices<uint32_t>(decoder);
|
||||
break;
|
||||
default:
|
||||
printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
36
extern/draco/src/decoder.h
vendored
36
extern/draco/src/decoder.h
vendored
@@ -28,26 +28,38 @@
|
||||
|
||||
struct Decoder;
|
||||
|
||||
API(Decoder *) decoderCreate();
|
||||
API(Decoder *)
|
||||
decoderCreate();
|
||||
|
||||
API(void) decoderRelease(Decoder *decoder);
|
||||
API(void)
|
||||
decoderRelease(Decoder *decoder);
|
||||
|
||||
API(bool) decoderDecode(Decoder *decoder, void *data, size_t byteLength);
|
||||
API(bool)
|
||||
decoderDecode(Decoder *decoder, void *data, size_t byteLength);
|
||||
|
||||
API(uint32_t) decoderGetVertexCount(Decoder *decoder);
|
||||
API(uint32_t)
|
||||
decoderGetVertexCount(Decoder *decoder);
|
||||
|
||||
API(uint32_t) decoderGetIndexCount(Decoder *decoder);
|
||||
API(uint32_t)
|
||||
decoderGetIndexCount(Decoder *decoder);
|
||||
|
||||
API(bool) decoderAttributeIsNormalized(Decoder *decoder, uint32_t id);
|
||||
API(bool)
|
||||
decoderAttributeIsNormalized(Decoder *decoder, uint32_t id);
|
||||
|
||||
API(bool) decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType);
|
||||
API(bool)
|
||||
decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType);
|
||||
|
||||
API(size_t) decoderGetAttributeByteLength(Decoder *decoder, size_t id);
|
||||
API(size_t)
|
||||
decoderGetAttributeByteLength(Decoder *decoder, size_t id);
|
||||
|
||||
API(void) decoderCopyAttribute(Decoder *decoder, size_t id, void *output);
|
||||
API(void)
|
||||
decoderCopyAttribute(Decoder *decoder, size_t id, void *output);
|
||||
|
||||
API(bool) decoderReadIndices(Decoder *decoder, size_t indexComponentType);
|
||||
API(bool)
|
||||
decoderReadIndices(Decoder *decoder, size_t indexComponentType);
|
||||
|
||||
API(size_t) decoderGetIndicesByteLength(Decoder *decoder);
|
||||
API(size_t)
|
||||
decoderGetIndicesByteLength(Decoder *decoder);
|
||||
|
||||
API(void) decoderCopyIndices(Decoder *decoder, void *output);
|
||||
API(void)
|
||||
decoderCopyIndices(Decoder *decoder, void *output);
|
||||
|
||||
97
extern/draco/src/encoder.cpp
vendored
97
extern/draco/src/encoder.cpp
vendored
@@ -59,7 +59,8 @@ void encoderRelease(Encoder *encoder)
|
||||
delete encoder;
|
||||
}
|
||||
|
||||
void encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel) {
|
||||
void encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel)
|
||||
{
|
||||
encoder->compressionLevel = compressionLevel;
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ void encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t no
|
||||
bool encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder)
|
||||
{
|
||||
printf(LOG_PREFIX "Preserve triangle order: %s\n", preserveTriangleOrder ? "yes" : "no");
|
||||
|
||||
|
||||
draco::Encoder dracoEncoder;
|
||||
|
||||
int speed = 10 - static_cast<int>(encoder->compressionLevel);
|
||||
@@ -87,12 +88,12 @@ bool encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder)
|
||||
dracoEncoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, encoder->quantization.color);
|
||||
dracoEncoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, encoder->quantization.generic);
|
||||
dracoEncoder.SetTrackEncodedProperties(true);
|
||||
|
||||
|
||||
if (preserveTriangleOrder)
|
||||
{
|
||||
dracoEncoder.SetEncodingMethod(draco::MESH_SEQUENTIAL_ENCODING);
|
||||
}
|
||||
|
||||
|
||||
auto encoderStatus = dracoEncoder.EncodeMeshToBuffer(encoder->mesh, &encoder->encoderBuffer);
|
||||
if (encoderStatus.ok())
|
||||
{
|
||||
@@ -130,20 +131,19 @@ void encoderCopy(Encoder *encoder, uint8_t *data)
|
||||
memcpy(data, encoder->encoderBuffer.data(), encoder->encoderBuffer.size());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
void encodeIndices(Encoder *encoder, uint32_t indexCount, T *indices)
|
||||
{
|
||||
int face_count = indexCount / 3;
|
||||
encoder->mesh.SetNumFaces(static_cast<size_t>(face_count));
|
||||
encoder->rawSize += indexCount * sizeof(T);
|
||||
|
||||
|
||||
for (int i = 0; i < face_count; ++i)
|
||||
{
|
||||
draco::Mesh::Face face = {
|
||||
draco::PointIndex(indices[3 * i + 0]),
|
||||
draco::PointIndex(indices[3 * i + 1]),
|
||||
draco::PointIndex(indices[3 * i + 2])
|
||||
};
|
||||
draco::PointIndex(indices[3 * i + 2])};
|
||||
encoder->mesh.SetFace(draco::FaceIndex(static_cast<uint32_t>(i)), face);
|
||||
}
|
||||
}
|
||||
@@ -152,23 +152,23 @@ void encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t ind
|
||||
{
|
||||
switch (indexComponentType)
|
||||
{
|
||||
case ComponentType::Byte:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<int8_t *>(indices));
|
||||
break;
|
||||
case ComponentType::UnsignedByte:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<uint8_t *>(indices));
|
||||
break;
|
||||
case ComponentType::Short:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<int16_t *>(indices));
|
||||
break;
|
||||
case ComponentType::UnsignedShort:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<uint16_t *>(indices));
|
||||
break;
|
||||
case ComponentType::UnsignedInt:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<uint32_t *>(indices));
|
||||
break;
|
||||
default:
|
||||
printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
|
||||
case ComponentType::Byte:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<int8_t *>(indices));
|
||||
break;
|
||||
case ComponentType::UnsignedByte:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<uint8_t *>(indices));
|
||||
break;
|
||||
case ComponentType::Short:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<int16_t *>(indices));
|
||||
break;
|
||||
case ComponentType::UnsignedShort:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<uint16_t *>(indices));
|
||||
break;
|
||||
case ComponentType::UnsignedInt:
|
||||
encodeIndices(encoder, indexCount, reinterpret_cast<uint32_t *>(indices));
|
||||
break;
|
||||
default:
|
||||
printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ draco::GeometryAttribute::Type getAttributeSemantics(char *attribute)
|
||||
{
|
||||
return draco::GeometryAttribute::COLOR;
|
||||
}
|
||||
|
||||
|
||||
return draco::GeometryAttribute::GENERIC;
|
||||
}
|
||||
|
||||
@@ -198,37 +198,38 @@ draco::DataType getDataType(size_t componentType)
|
||||
{
|
||||
switch (componentType)
|
||||
{
|
||||
case ComponentType::Byte:
|
||||
return draco::DataType::DT_INT8;
|
||||
|
||||
case ComponentType::UnsignedByte:
|
||||
return draco::DataType::DT_UINT8;
|
||||
|
||||
case ComponentType::Short:
|
||||
return draco::DataType::DT_INT16;
|
||||
|
||||
case ComponentType::UnsignedShort:
|
||||
return draco::DataType::DT_UINT16;
|
||||
|
||||
case ComponentType::UnsignedInt:
|
||||
return draco::DataType::DT_UINT32;
|
||||
|
||||
case ComponentType::Float:
|
||||
return draco::DataType::DT_FLOAT32;
|
||||
|
||||
default:
|
||||
return draco::DataType::DT_INVALID;
|
||||
case ComponentType::Byte:
|
||||
return draco::DataType::DT_INT8;
|
||||
|
||||
case ComponentType::UnsignedByte:
|
||||
return draco::DataType::DT_UINT8;
|
||||
|
||||
case ComponentType::Short:
|
||||
return draco::DataType::DT_INT16;
|
||||
|
||||
case ComponentType::UnsignedShort:
|
||||
return draco::DataType::DT_UINT16;
|
||||
|
||||
case ComponentType::UnsignedInt:
|
||||
return draco::DataType::DT_UINT32;
|
||||
|
||||
case ComponentType::Float:
|
||||
return draco::DataType::DT_FLOAT32;
|
||||
|
||||
default:
|
||||
return draco::DataType::DT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
API(uint32_t) encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data)
|
||||
API(uint32_t)
|
||||
encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data)
|
||||
{
|
||||
auto buffer = std::make_unique<draco::DataBuffer>();
|
||||
uint32_t count = encoder->mesh.num_points();
|
||||
size_t componentCount = getNumberOfComponents(dataType);
|
||||
size_t stride = getAttributeStride(componentType, dataType);
|
||||
draco::DataType dracoDataType = getDataType(componentType);
|
||||
|
||||
|
||||
draco::GeometryAttribute::Type semantics = getAttributeSemantics(attributeName);
|
||||
draco::GeometryAttribute attribute;
|
||||
attribute.Init(semantics, &*buffer, componentCount, getDataType(componentType), false, stride, 0);
|
||||
|
||||
33
extern/draco/src/encoder.h
vendored
33
extern/draco/src/encoder.h
vendored
@@ -28,24 +28,35 @@
|
||||
|
||||
struct Encoder;
|
||||
|
||||
API(Encoder *) encoderCreate(uint32_t vertexCount);
|
||||
API(Encoder *)
|
||||
encoderCreate(uint32_t vertexCount);
|
||||
|
||||
API(void) encoderRelease(Encoder *encoder);
|
||||
API(void)
|
||||
encoderRelease(Encoder *encoder);
|
||||
|
||||
API(void) encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel);
|
||||
API(void)
|
||||
encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel);
|
||||
|
||||
API(void) encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t normal, uint32_t uv, uint32_t color, uint32_t generic);
|
||||
API(void)
|
||||
encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t normal, uint32_t uv, uint32_t color, uint32_t generic);
|
||||
|
||||
API(bool) encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder);
|
||||
API(bool)
|
||||
encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder);
|
||||
|
||||
API(uint64_t) encoderGetByteLength(Encoder *encoder);
|
||||
API(uint64_t)
|
||||
encoderGetByteLength(Encoder *encoder);
|
||||
|
||||
API(void) encoderCopy(Encoder *encoder, uint8_t *data);
|
||||
API(void)
|
||||
encoderCopy(Encoder *encoder, uint8_t *data);
|
||||
|
||||
API(void) encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t indexCount, void *indices);
|
||||
API(void)
|
||||
encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t indexCount, void *indices);
|
||||
|
||||
API(uint32_t) encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data);
|
||||
API(uint32_t)
|
||||
encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data);
|
||||
|
||||
API(uint32_t) encoderGetEncodedVertexCount(Encoder *encoder);
|
||||
API(uint32_t)
|
||||
encoderGetEncodedVertexCount(Encoder *encoder);
|
||||
|
||||
API(uint32_t) encoderGetEncodedIndexCount(Encoder *encoder);
|
||||
API(uint32_t)
|
||||
encoderGetEncodedIndexCount(Encoder *encoder);
|
||||
|
||||
Reference in New Issue
Block a user