// Copyright 2016 The Draco Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "compression/encode.h" #include "compression/mesh/mesh_edgebreaker_encoder.h" #include "compression/mesh/mesh_sequential_encoder.h" #include "compression/point_cloud/point_cloud_kd_tree_encoder.h" #include "compression/point_cloud/point_cloud_sequential_encoder.h" namespace draco { // Encodes header common to all methods. bool EncodeHeader(const PointCloudEncoder &encoder, EncoderBuffer *out_buffer) { // Encode the header according to our v1 specification. // Five bytes for Draco format. out_buffer->Encode("DRACO", 5); // Version (major, minor). const uint8_t major_version = 1; const uint8_t minor_version = 1; out_buffer->Encode(major_version); out_buffer->Encode(minor_version); // Type of the encoder (point cloud, mesh, ...). const uint8_t encoder_type = encoder.GetGeometryType(); out_buffer->Encode(encoder_type); // Unique identifier for the selected encoding method (edgebreaker, etc...). out_buffer->Encode(encoder.GetEncodingMethod()); // Reserved for flags. out_buffer->Encode(static_cast(0)); return true; } bool EncodeGeometryToBuffer(PointCloudEncoder *encoder, const EncoderOptions &options, EncoderBuffer *out_buffer) { if (!encoder) return false; if (!EncodeHeader(*encoder, out_buffer)) return false; if (!encoder->Encode(options, out_buffer)) return false; return true; } bool EncodePointCloudToBuffer(const PointCloud &pc, const EncoderOptions &options, EncoderBuffer *out_buffer) { std::unique_ptr encoder; const int encoding_method = options.GetGlobalInt("encoding_method", -1); if (encoding_method == POINT_CLOUD_KD_TREE_ENCODING || (options.GetSpeed() < 10 && pc.num_attributes() == 1)) { const PointAttribute *const att = pc.attribute(0); bool create_kd_tree_encoder = true; // Kd-Tree encoder can be currently used only under following conditions: // - Point cloud has one attribute describing positions // - Position is described by three components (x,y,z) // - Position data type is one of the following: // -float32 and quantization is enabled // -uint32 if (att->attribute_type() != GeometryAttribute::POSITION || att->components_count() != 3) create_kd_tree_encoder = false; if (create_kd_tree_encoder && att->data_type() != DT_FLOAT32 && att->data_type() != DT_UINT32) create_kd_tree_encoder = false; if (create_kd_tree_encoder && att->data_type() == DT_FLOAT32 && options.GetAttributeInt(0, "quantization_bits", -1) <= 0) create_kd_tree_encoder = false; // Quantization not enabled. if (create_kd_tree_encoder) { // Create kD-tree encoder (all checks passed). encoder = std::unique_ptr(new PointCloudKdTreeEncoder()); } else if (encoding_method == POINT_CLOUD_KD_TREE_ENCODING) { // Encoding method was explicitly specified but we cannot use it for the // given input (some of the checks above failed). return false; } } if (!encoder) { // Default choice. encoder = std::unique_ptr(new PointCloudSequentialEncoder()); } if (encoder) encoder->SetPointCloud(pc); return EncodeGeometryToBuffer(encoder.get(), options, out_buffer); } bool EncodeMeshToBuffer(const Mesh &m, const EncoderOptions &options, EncoderBuffer *out_buffer) { std::unique_ptr encoder; // Select the encoding method only based on the provided options. int encoding_method = options.GetGlobalInt("encoding_method", -1); if (encoding_method == -1) { // For now select the edgebreaker for all options expect of speed 10 if (options.GetSpeed() == 10) { encoding_method = MESH_SEQUENTIAL_ENCODING; } else { encoding_method = MESH_EDGEBREAKER_ENCODING; } } if (encoding_method == MESH_EDGEBREAKER_ENCODING) { encoder = std::unique_ptr(new MeshEdgeBreakerEncoder()); } else { encoder = std::unique_ptr(new MeshSequentialEncoder()); } if (encoder) encoder->SetMesh(m); return EncodeGeometryToBuffer(encoder.get(), options, out_buffer); } EncoderOptions CreateDefaultEncoderOptions() { return EncoderOptions::CreateDefaultOptions(); } void SetSpeedOptions(EncoderOptions *options, int encoding_speed, int decoding_speed) { options->GetGlobalOptions()->SetInt("encoding_speed", encoding_speed); options->GetGlobalOptions()->SetInt("decoding_speed", decoding_speed); } void SetNamedAttributeQuantization(EncoderOptions *options, const PointCloud &pc, GeometryAttribute::Type type, int quantization_bits) { Options *const o = options->GetNamedAttributeOptions(pc, type); if (o) { SetAttributeQuantization(o, quantization_bits); } } void SetAttributeQuantization(Options *options, int quantization_bits) { options->SetInt("quantization_bits", quantization_bits); } void SetUseBuiltInAttributeCompression(EncoderOptions *options, bool enabled) { options->GetGlobalOptions()->SetBool("use_built_in_attribute_compression", enabled); } void SetEncodingMethod(EncoderOptions *options, int encoding_method) { options->GetGlobalOptions()->SetInt("encoding_method", encoding_method); } void SetNamedAttributePredictionScheme(EncoderOptions *options, const PointCloud &pc, GeometryAttribute::Type type, int prediction_scheme_method) { Options *const o = options->GetNamedAttributeOptions(pc, type); if (o) { SetAttributePredictionScheme(o, prediction_scheme_method); } } void SetAttributePredictionScheme(Options *options, int prediction_scheme_method) { options->SetInt("prediction_scheme", prediction_scheme_method); } } // namespace draco