From b267d04c49c9467911e5586bea7d1fbf3cb43500 Mon Sep 17 00:00:00 2001 From: Frank Galligan Date: Tue, 8 Aug 2017 12:44:35 -0700 Subject: [PATCH] Add decoder_webidl_wrapper sources. This fixes #176 --- .../sequential_attribute_decoder.cc | 4 +- src/draco/io/mesh_io.cc | 6 +- src/draco/io/point_cloud_io.cc | 6 +- .../emscripten/decoder_webidl_wrapper.cc | 217 ++++++++++++++++++ .../emscripten/decoder_webidl_wrapper.h | 158 +++++++++++++ src/draco/tools/draco_decoder.cc | 8 +- 6 files changed, 390 insertions(+), 9 deletions(-) create mode 100644 src/draco/javascript/emscripten/decoder_webidl_wrapper.cc create mode 100644 src/draco/javascript/emscripten/decoder_webidl_wrapper.h diff --git a/src/draco/compression/attributes/sequential_attribute_decoder.cc b/src/draco/compression/attributes/sequential_attribute_decoder.cc index fda1e34..6bd48c6 100644 --- a/src/draco/compression/attributes/sequential_attribute_decoder.cc +++ b/src/draco/compression/attributes/sequential_attribute_decoder.cc @@ -58,8 +58,8 @@ bool SequentialAttributeDecoder::TransformAttributeToOriginalFormat( const PointAttribute *SequentialAttributeDecoder::GetPortableAttribute() { // If needed, copy point to attribute value index mapping from the final // attribute to the portable attribute. - if (!attribute_->is_mapping_identity() && - portable_attribute_ && portable_attribute_->is_mapping_identity()) { + if (!attribute_->is_mapping_identity() && portable_attribute_ && + portable_attribute_->is_mapping_identity()) { portable_attribute_->SetExplicitMapping(attribute_->indices_map_size()); for (PointIndex i(0); i < attribute_->indices_map_size(); ++i) { portable_attribute_->SetPointMapEntry(i, attribute_->mapped_index(i)); diff --git a/src/draco/io/mesh_io.cc b/src/draco/io/mesh_io.cc index 24160ac..e8d0507 100644 --- a/src/draco/io/mesh_io.cc +++ b/src/draco/io/mesh_io.cc @@ -30,9 +30,9 @@ std::unique_ptr ReadMeshFromFile(const std::string &file_name, bool use_metadata) { std::unique_ptr mesh(new Mesh()); // Analyze file extension. - const std::string extension = - parser::ToLower(file_name.size() >= 4 ? - file_name.substr(file_name.size() - 4) : file_name); + const std::string extension = parser::ToLower( + file_name.size() >= 4 ? file_name.substr(file_name.size() - 4) + : file_name); if (extension == ".obj") { // Wavefront OBJ file format. ObjDecoder obj_decoder; diff --git a/src/draco/io/point_cloud_io.cc b/src/draco/io/point_cloud_io.cc index d3435a3..af57d19 100644 --- a/src/draco/io/point_cloud_io.cc +++ b/src/draco/io/point_cloud_io.cc @@ -17,6 +17,7 @@ #include #include "draco/io/obj_decoder.h" +#include "draco/io/parser_utils.h" #include "draco/io/ply_decoder.h" namespace draco { @@ -25,8 +26,9 @@ std::unique_ptr ReadPointCloudFromFile( const std::string &file_name) { std::unique_ptr pc(new PointCloud()); // Analyze file extension. - const std::string extension = file_name.size() >= 4 ? - file_name.substr(file_name.size() - 4) : file_name; + const std::string extension = parser::ToLower( + file_name.size() >= 4 ? file_name.substr(file_name.size() - 4) + : file_name); if (extension == ".obj") { // Wavefront OBJ file format. ObjDecoder obj_decoder; diff --git a/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc b/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc new file mode 100644 index 0000000..9bbf211 --- /dev/null +++ b/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc @@ -0,0 +1,217 @@ +// 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 "draco/javascript/emscripten/decoder_webidl_wrapper.h" + +#include "draco/compression/decode.h" +#include "draco/mesh/mesh.h" +#include "draco/mesh/mesh_stripifier.h" + +using draco::DecoderBuffer; +using draco::Mesh; +using draco::Metadata; +using draco::PointAttribute; +using draco::PointCloud; +using draco::Status; + +MetadataQuerier::MetadataQuerier() {} + +bool MetadataQuerier::HasIntEntry(const Metadata &metadata, + const char *entry_name) const { + int32_t value = 0; + const std::string name(entry_name); + if (!metadata.GetEntryInt(name, &value)) + return false; + return true; +} + +long MetadataQuerier::GetIntEntry(const Metadata &metadata, + const char *entry_name) const { + int32_t value = 0; + const std::string name(entry_name); + metadata.GetEntryInt(name, &value); + return value; +} + +bool MetadataQuerier::HasDoubleEntry(const Metadata &metadata, + const char *entry_name) const { + double value = 0; + const std::string name(entry_name); + if (!metadata.GetEntryDouble(name, &value)) + return false; + return true; +} + +double MetadataQuerier::GetDoubleEntry(const Metadata &metadata, + const char *entry_name) const { + double value = 0; + const std::string name(entry_name); + metadata.GetEntryDouble(name, &value); + return value; +} + +bool MetadataQuerier::HasStringEntry(const Metadata &metadata, + const char *entry_name) const { + std::string return_value; + const std::string name(entry_name); + if (!metadata.GetEntryString(name, &return_value)) + return false; + return true; +} + +const char *MetadataQuerier::GetStringEntry(const Metadata &metadata, + const char *entry_name) const { + std::string return_value; + const std::string name(entry_name); + metadata.GetEntryString(name, &return_value); + const char *value = return_value.c_str(); + return value; +} + +DracoFloat32Array::DracoFloat32Array() {} + +float DracoFloat32Array::GetValue(int index) const { return values_[index]; } + +bool DracoFloat32Array::SetValues(const float *values, int count) { + if (values) { + values_.assign(values, values + count); + } else { + values_.resize(count); + } + return true; +} + +DracoInt32Array::DracoInt32Array() {} + +int DracoInt32Array::GetValue(int index) const { return values_[index]; } + +bool DracoInt32Array::SetValues(const int *values, int count) { + values_.assign(values, values + count); + return true; +} + +Decoder::Decoder() {} + +draco_EncodedGeometryType Decoder::GetEncodedGeometryType( + DecoderBuffer *in_buffer) { + return draco::Decoder::GetEncodedGeometryType(in_buffer).value(); +} + +const Status *Decoder::DecodeBufferToPointCloud(DecoderBuffer *in_buffer, + PointCloud *out_point_cloud) { + last_status_ = decoder_.DecodeBufferToGeometry(in_buffer, out_point_cloud); + return &last_status_; +} + +const Status *Decoder::DecodeBufferToMesh(DecoderBuffer *in_buffer, + Mesh *out_mesh) { + last_status_ = decoder_.DecodeBufferToGeometry(in_buffer, out_mesh); + return &last_status_; +} + +long Decoder::GetAttributeId(const PointCloud &pc, + draco_GeometryAttribute_Type type) const { + return pc.GetNamedAttributeId(type); +} + +const PointAttribute *Decoder::GetAttribute(const PointCloud &pc, long att_id) { + return pc.attribute(att_id); +} + +long Decoder::GetAttributeIdByName(const PointCloud &pc, + const char *attribute_name) { + const std::string entry_value(attribute_name); + return pc.GetAttributeIdByMetadataEntry("name", entry_value); +} + +long Decoder::GetAttributeIdByMetadataEntry(const PointCloud &pc, + const char *metadata_name, + const char *metadata_value) { + const std::string entry_name(metadata_name); + const std::string entry_value(metadata_value); + return pc.GetAttributeIdByMetadataEntry(entry_name, entry_value); +} + +bool Decoder::GetFaceFromMesh(const Mesh &m, + draco::FaceIndex::ValueType face_id, + DracoInt32Array *out_values) { + const Mesh::Face &face = m.face(draco::FaceIndex(face_id)); + return out_values->SetValues(reinterpret_cast(face.data()), + face.size()); +} + +long Decoder::GetTriangleStripsFromMesh(const Mesh &m, + DracoInt32Array *strip_values) { + draco::MeshStripifier stripifier; + std::vector strip_indices; + if (!stripifier.GenerateTriangleStripsWithDegenerateTriangles( + m, std::back_inserter(strip_indices))) { + return 0; + } + if (!strip_values->SetValues(strip_indices.data(), strip_indices.size())) + return 0; + return stripifier.num_strips(); +} + +bool Decoder::GetAttributeFloat(const PointAttribute &pa, + draco::AttributeValueIndex::ValueType val_index, + DracoFloat32Array *out_values) { + const int kMaxAttributeFloatValues = 4; + const int components = pa.num_components(); + float values[kMaxAttributeFloatValues] = {-2.0, -2.0, -2.0, -2.0}; + if (!pa.ConvertValue(draco::AttributeValueIndex(val_index), values)) + return false; + return out_values->SetValues(values, components); +} + +bool Decoder::GetAttributeFloatForAllPoints(const PointCloud &pc, + const PointAttribute &pa, + DracoFloat32Array *out_values) { + const int components = pa.num_components(); + const int num_points = pc.num_points(); + const int num_entries = num_points * components; + const int kMaxAttributeFloatValues = 4; + float values[kMaxAttributeFloatValues] = {-2.0, -2.0, -2.0, -2.0}; + int entry_id = 0; + + out_values->SetValues(nullptr, num_entries); + for (draco::PointIndex i(0); i < num_points; ++i) { + const draco::AttributeValueIndex val_index = pa.mapped_index(i); + if (!pa.ConvertValue(val_index, values)) + return false; + for (int j = 0; j < components; ++j) { + out_values->SetValue(entry_id++, values[j]); + } + } + return true; +} + +void Decoder::SkipAttributeTransform(draco_GeometryAttribute_Type att_type) { + decoder_.SetSkipAttributeTransform(att_type); +} + +const Metadata *Decoder::GetMetadata(const PointCloud &pc) const { + if (!pc.GetMetadata()) { + return nullptr; + } + return pc.GetMetadata(); +} + +const Metadata *Decoder::GetAttributeMetadata(const PointCloud &pc, + long att_id) const { + if (!pc.GetMetadata()) { + return nullptr; + } + return pc.GetMetadata()->GetAttributeMetadata(att_id); +} diff --git a/src/draco/javascript/emscripten/decoder_webidl_wrapper.h b/src/draco/javascript/emscripten/decoder_webidl_wrapper.h new file mode 100644 index 0000000..e8b53a3 --- /dev/null +++ b/src/draco/javascript/emscripten/decoder_webidl_wrapper.h @@ -0,0 +1,158 @@ +// Copyright 2017 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. +// +#ifndef DRACO_JAVASCRIPT_EMSCRITPEN_DECODER_WEBIDL_WRAPPER_H_ +#define DRACO_JAVASCRIPT_EMSCRITPEN_DECODER_WEBIDL_WRAPPER_H_ + +#include + +#include "draco/attributes/attribute_transform_type.h" +#include "draco/attributes/point_attribute.h" +#include "draco/compression/config/compression_shared.h" +#include "draco/compression/decode.h" +#include "draco/core/decoder_buffer.h" +#include "draco/mesh/mesh.h" + +typedef draco::AttributeTransformType draco_AttributeTransformType; +typedef draco::GeometryAttribute draco_GeometryAttribute; +typedef draco_GeometryAttribute::Type draco_GeometryAttribute_Type; +typedef draco::EncodedGeometryType draco_EncodedGeometryType; +typedef draco::Status draco_Status; +typedef draco::Status::Code draco_StatusCode; + +// To generate Draco JabvaScript bindings you must have emscripten installed. +// Then run make -f Makefile.emcc jslib. + +class MetadataQuerier { + public: + MetadataQuerier(); + + bool HasIntEntry(const draco::Metadata &metadata, + const char *entry_name) const; + long GetIntEntry(const draco::Metadata &metadata, + const char *entry_name) const; + bool HasDoubleEntry(const draco::Metadata &metadata, + const char *entry_name) const; + double GetDoubleEntry(const draco::Metadata &metadata, + const char *entry_name) const; + bool HasStringEntry(const draco::Metadata &metadata, + const char *entry_name) const; + const char *GetStringEntry(const draco::Metadata &metadata, + const char *entry_name) const; +}; + +class DracoFloat32Array { + public: + DracoFloat32Array(); + float GetValue(int index) const; + + // In case |values| is nullptr, the data is allocated but not initialized. + bool SetValues(const float *values, int count); + + // Directly sets a value for a specific index. The array has to be already + // allocated at this point (using SetValues() method). + void SetValue(int index, float val) { values_[index] = val; } + + int size() const { return values_.size(); } + + private: + std::vector values_; +}; + +class DracoInt32Array { + public: + DracoInt32Array(); + int GetValue(int index) const; + bool SetValues(const int *values, int count); + int size() const { return values_.size(); } + + private: + std::vector values_; +}; + +// Class used by emscripten WebIDL Binder [1] to wrap calls to decode Draco +// data. +// [1]http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.html +class Decoder { + public: + Decoder(); + + // Returns the geometry type stored in the |in_buffer|. Return values can be + // INVALID_GEOMETRY_TYPE, POINT_CLOUD, or MESH. + draco_EncodedGeometryType GetEncodedGeometryType( + draco::DecoderBuffer *in_buffer); + + // Decodes a point cloud from the provided buffer. + const draco::Status *DecodeBufferToPointCloud( + draco::DecoderBuffer *in_buffer, draco::PointCloud *out_point_cloud); + + // Decodes a triangular mesh from the provided buffer. + const draco::Status *DecodeBufferToMesh(draco::DecoderBuffer *in_buffer, + draco::Mesh *out_mesh); + + // Returns an attribute id for the first attribute of a given type. + long GetAttributeId(const draco::PointCloud &pc, + draco_GeometryAttribute_Type type) const; + + // Returns an attribute id of an attribute that contains a valid metadata + // entry "name" with value |attribute_name|. + static long GetAttributeIdByName(const draco::PointCloud &pc, + const char *attribute_name); + + // Returns an attribute id of an attribute with a specified metadata pair + // <|metadata_name|, |metadata_value|>. + static long GetAttributeIdByMetadataEntry(const draco::PointCloud &pc, + const char *metadata_name, + const char *metadata_value); + + // Returns a PointAttribute pointer from |att_id| index. + static const draco::PointAttribute *GetAttribute(const draco::PointCloud &pc, + long att_id); + + // Returns Mesh::Face values in |out_values| from |face_id| index. + static bool GetFaceFromMesh(const draco::Mesh &m, + draco::FaceIndex::ValueType face_id, + DracoInt32Array *out_values); + + // Returns triangle strips for mesh |m|. If there's multiple strips, + // the strips will be separated by degenerate faces. + static long GetTriangleStripsFromMesh(const draco::Mesh &m, + DracoInt32Array *strip_values); + + // Returns float attribute values in |out_values| from |entry_index| index. + static bool GetAttributeFloat( + const draco::PointAttribute &pa, + draco::AttributeValueIndex::ValueType entry_index, + DracoFloat32Array *out_values); + + // Returns float attribute values for all point ids of the point cloud. + // I.e., the |out_values| is going to contain m.num_points() entries. + static bool GetAttributeFloatForAllPoints(const draco::PointCloud &pc, + const draco::PointAttribute &pa, + DracoFloat32Array *out_values); + + // Tells the decoder to skip an attribute transform (e.g. dequantization) for + // an attribute of a given type. + void SkipAttributeTransform(draco_GeometryAttribute_Type att_type); + + const draco::Metadata *GetMetadata(const draco::PointCloud &pc) const; + const draco::Metadata *GetAttributeMetadata(const draco::PointCloud &pc, + long att_id) const; + + private: + draco::Decoder decoder_; + draco::Status last_status_; +}; + +#endif // DRACO_JAVASCRIPT_EMSCRITPEN_DECODER_WEBIDL_WRAPPER_H_ diff --git a/src/draco/tools/draco_decoder.cc b/src/draco/tools/draco_decoder.cc index 512301b..d965752 100644 --- a/src/draco/tools/draco_decoder.cc +++ b/src/draco/tools/draco_decoder.cc @@ -18,6 +18,7 @@ #include "draco/compression/decode.h" #include "draco/core/cycle_timer.h" #include "draco/io/obj_encoder.h" +#include "draco/io/parser_utils.h" #include "draco/io/ply_encoder.h" namespace { @@ -134,8 +135,11 @@ int main(int argc, char **argv) { // Save the decoded geometry into a file. // TODO(ostava): Currently only .ply and .obj are supported. - const std::string extension = options.output.size() >= 4 ? - options.output.substr(options.output.size() - 4) : options.output; + const std::string extension = draco::parser::ToLower( + options.output.size() >= 4 + ? options.output.substr(options.output.size() - 4) + : options.output); + if (extension == ".obj") { draco::ObjEncoder obj_encoder; if (mesh) {