From 48621b5a744f9121f9b5482e05b77682e5e9251f Mon Sep 17 00:00:00 2001 From: Stefan Eilemann Date: Mon, 3 Jun 2019 16:53:02 +0200 Subject: [PATCH] Add TypedArray JS API for selected data types Example Usage (TS code): ``` function _getUint16Array( length: number, decoder: DecoderInstance, mesh: MeshInstance, attributeId: number ): Uint16Array { const nBytes = length * 2; const ptr = draco._malloc(nBytes); const attribute = decoder.GetAttribute(mesh, attributeId); if (!decoder.GetAttributeUInt16ArrayForAllPoints(mesh, attribute, ptr, length)) { throw "GetAttributeUInt16ArrayForAllPoints failed"; } const array = new Uint16Array(draco.HEAPU8.buffer, ptr, length).slice(); draco._free(ptr); return array; } ``` --- .../emscripten/decoder_webidl_wrapper.cc | 94 +++++++++++++++++-- .../emscripten/decoder_webidl_wrapper.h | 67 +++++++++++++ .../emscripten/draco_web_decoder.idl | 24 +++++ 3 files changed, 179 insertions(+), 6 deletions(-) diff --git a/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc b/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc index 0c0caa8..5d5f1ad 100644 --- a/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc +++ b/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc @@ -60,8 +60,7 @@ double MetadataQuerier::GetDoubleEntry(const Metadata &metadata, const char *MetadataQuerier::GetStringEntry(const Metadata &metadata, const char *entry_name) { const std::string name(entry_name); - if (!metadata.GetEntryString(name, &last_string_returned_)) - return nullptr; + if (!metadata.GetEntryString(name, &last_string_returned_)) return nullptr; const char *value = last_string_returned_.c_str(); return value; @@ -81,8 +80,7 @@ const char *MetadataQuerier::GetEntryName(const Metadata &metadata, entry_names_.push_back(entry.first); } } - if (entry_id < 0 || entry_id >= entry_names_.size()) - return nullptr; + if (entry_id < 0 || entry_id >= entry_names_.size()) return nullptr; return entry_names_[entry_id].c_str(); } @@ -154,6 +152,41 @@ long Decoder::GetTriangleStripsFromMesh(const Mesh &m, return stripifier.num_strips(); } +template +bool GetTrianglesArray(const draco::Mesh &m, T *out_values, + const int out_size) { + const uint32_t num_faces = m.num_faces(); + if (num_faces * 3 != out_size) { + return false; + } + + for (uint32_t face_id = 0; face_id < num_faces; ++face_id) { + const Mesh::Face &face = m.face(draco::FaceIndex(face_id)); + if (face.size() != 3 || face[0].value() > std::numeric_limits::max() || + face[1].value() > std::numeric_limits::max() || + face[2].value() > std::numeric_limits::max()) { + return false; + } + + out_values[face_id * 3 + 0] = static_cast(face[0].value()); + out_values[face_id * 3 + 1] = static_cast(face[1].value()); + out_values[face_id * 3 + 2] = static_cast(face[2].value()); + } + return true; +} + +bool Decoder::GetTrianglesUInt16Array(const draco::Mesh &m, void *out_values, + const int out_size) { + return GetTrianglesArray( + m, reinterpret_cast(out_values), out_size); +} + +bool Decoder::GetTrianglesUInt32Array(const draco::Mesh &m, void *out_values, + const int out_size) { + return GetTrianglesArray( + m, reinterpret_cast(out_values), out_size); +} + bool Decoder::GetAttributeFloat(const PointAttribute &pa, draco::AttributeValueIndex::ValueType val_index, DracoFloat32Array *out_values) { @@ -179,8 +212,7 @@ bool Decoder::GetAttributeFloatForAllPoints(const PointCloud &pc, out_values->Resize(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; + if (!pa.ConvertValue(val_index, values)) return false; for (int j = 0; j < components; ++j) { out_values->SetValue(entry_id++, values[j]); } @@ -188,6 +220,32 @@ bool Decoder::GetAttributeFloatForAllPoints(const PointCloud &pc, return true; } +bool Decoder::GetAttributeFloatArrayForAllPoints(const PointCloud &pc, + const PointAttribute &pa, + void *out_values, + const int out_size) { + const int components = pa.num_components(); + const int num_points = pc.num_points(); + const int num_entries = num_points * components; + if (num_entries != out_size) { + return false; + } + + const int kMaxAttributeFloatValues = 4; + float values[kMaxAttributeFloatValues] = {-2.0, -2.0, -2.0, -2.0}; + int entry_id = 0; + float *floats = reinterpret_cast(out_values); + + 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) { + floats[entry_id++] = values[j]; + } + } + return true; +} + bool Decoder::GetAttributeInt8ForAllPoints(const PointCloud &pc, const PointAttribute &pa, DracoInt8Array *out_values) { @@ -202,6 +260,14 @@ bool Decoder::GetAttributeUInt8ForAllPoints(const PointCloud &pc, pc, pa, draco::DT_INT8, draco::DT_UINT8, out_values); } +bool Decoder::GetAttributeUInt8ArrayForAllPoints(const PointCloud &pc, + const PointAttribute &pa, + void *out_values, + const int out_size) { + return GetAttributeDataArrayForAllPoints(pc, pa, draco::DT_UINT8, + out_values, out_size); +} + bool Decoder::GetAttributeInt16ForAllPoints(const PointCloud &pc, const PointAttribute &pa, DracoInt16Array *out_values) { @@ -216,6 +282,14 @@ bool Decoder::GetAttributeUInt16ForAllPoints(const PointCloud &pc, pc, pa, draco::DT_INT16, draco::DT_UINT16, out_values); } +bool Decoder::GetAttributeUInt16ArrayForAllPoints(const PointCloud &pc, + const PointAttribute &pa, + void *out_values, + const int out_size) { + return GetAttributeDataArrayForAllPoints(pc, pa, draco::DT_UINT16, + out_values, out_size); +} + bool Decoder::GetAttributeInt32ForAllPoints(const PointCloud &pc, const PointAttribute &pa, DracoInt32Array *out_values) { @@ -236,6 +310,14 @@ bool Decoder::GetAttributeUInt32ForAllPoints(const PointCloud &pc, pc, pa, draco::DT_INT32, draco::DT_UINT32, out_values); } +bool Decoder::GetAttributeUInt32ArrayForAllPoints(const PointCloud &pc, + const PointAttribute &pa, + void *out_values, + const int out_size) { + return GetAttributeDataArrayForAllPoints(pc, pa, draco::DT_UINT32, + out_values, out_size); +} + void Decoder::SkipAttributeTransform(draco_GeometryAttribute_Type att_type) { decoder_.SetSkipAttributeTransform(att_type); } diff --git a/src/draco/javascript/emscripten/decoder_webidl_wrapper.h b/src/draco/javascript/emscripten/decoder_webidl_wrapper.h index bd2771b..7560ccc 100644 --- a/src/draco/javascript/emscripten/decoder_webidl_wrapper.h +++ b/src/draco/javascript/emscripten/decoder_webidl_wrapper.h @@ -146,6 +146,14 @@ class Decoder { static long GetTriangleStripsFromMesh(const draco::Mesh &m, DracoInt32Array *strip_values); + // Returns all faces as triangles. Fails if there are non-triangle faces, + // indices exceed the data range (in particular for uint16), or the + // output array size does not match + static bool GetTrianglesUInt16Array(const draco::Mesh &m, void *out_values, + int out_size); + static bool GetTrianglesUInt32Array(const draco::Mesh &m, void *out_values, + int out_size); + // Returns float attribute values in |out_values| from |entry_index| index. static bool GetAttributeFloat( const draco::PointAttribute &pa, @@ -158,6 +166,12 @@ class Decoder { const draco::PointAttribute &pa, 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 GetAttributeFloatArrayForAllPoints( + const draco::PointCloud &pc, const draco::PointAttribute &pa, + void *out_values, int out_size); + // Returns int8_t 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 GetAttributeInt8ForAllPoints(const draco::PointCloud &pc, @@ -170,6 +184,12 @@ class Decoder { const draco::PointAttribute &pa, DracoUInt8Array *out_values); + // Returns uint8_t 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 GetAttributeUInt8ArrayForAllPoints( + const draco::PointCloud &pc, const draco::PointAttribute &pa, + void *out_values, int out_size); + // Returns int16_t 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 GetAttributeInt16ForAllPoints(const draco::PointCloud &pc, @@ -182,6 +202,12 @@ class Decoder { const draco::PointAttribute &pa, DracoUInt16Array *out_values); + // Returns uint16_t 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 GetAttributeUInt16ArrayForAllPoints( + const draco::PointCloud &pc, const draco::PointAttribute &pa, + void *out_values, int out_size); + // Returns int32_t 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 GetAttributeInt32ForAllPoints(const draco::PointCloud &pc, @@ -199,6 +225,12 @@ class Decoder { const draco::PointAttribute &pa, DracoUInt32Array *out_values); + // Returns uint32_t 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 GetAttributeUInt32ArrayForAllPoints( + const draco::PointCloud &pc, const draco::PointAttribute &pa, + void *out_values, int out_size); + // 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); @@ -243,6 +275,41 @@ class Decoder { return true; } + template + static bool GetAttributeDataArrayForAllPoints(const draco::PointCloud &pc, + const draco::PointAttribute &pa, + const draco::DataType type, + void *out_values, + const int out_size) { + const int components = pa.num_components(); + const int num_points = pc.num_points(); + const int num_entries = num_points * components; + if (num_entries != out_size) + return false; + + if (pa.data_type() == type && pa.is_mapping_identity()) { + // Copy values directly to the output vector. + const auto ptr = pa.GetAddress(draco::AttributeValueIndex(0)); + ::memcpy(out_values, ptr, num_entries * sizeof(T)); + return true; + } + + // Copy values one by one. + std::vector values(components); + int entry_id = 0; + + T *typed_output = reinterpret_cast(out_values); + for (draco::PointIndex i(0); i < num_points; ++i) { + const draco::AttributeValueIndex val_index = pa.mapped_index(i); + if (!pa.ConvertValue(val_index, values.data())) + return false; + for (int j = 0; j < components; ++j) { + typed_output[entry_id++] = values[j]; + } + } + return true; + } + draco::Decoder decoder_; draco::Status last_status_; }; diff --git a/src/draco/javascript/emscripten/draco_web_decoder.idl b/src/draco/javascript/emscripten/draco_web_decoder.idl index 125bf07..fb62618 100644 --- a/src/draco/javascript/emscripten/draco_web_decoder.idl +++ b/src/draco/javascript/emscripten/draco_web_decoder.idl @@ -117,42 +117,49 @@ interface DracoFloat32Array { void DracoFloat32Array(); float GetValue(long index); long size(); + boolean GetArray(VoidPtr out_values, long out_size); }; interface DracoInt8Array { void DracoInt8Array(); byte GetValue(long index); long size(); + boolean GetArray(VoidPtr out_values, long out_size); }; interface DracoUInt8Array { void DracoUInt8Array(); octet GetValue(long index); long size(); + boolean GetArray(VoidPtr out_values, long out_size); }; interface DracoInt16Array { void DracoInt16Array(); short GetValue(long index); long size(); + boolean GetArray(VoidPtr out_values, long out_size); }; interface DracoUInt16Array { void DracoUInt16Array(); unsigned short GetValue(long index); long size(); + boolean GetArray(VoidPtr out_values, long out_size); }; interface DracoInt32Array { void DracoInt32Array(); long GetValue(long index); long size(); + boolean GetArray(VoidPtr out_values, long out_size); }; interface DracoUInt32Array { void DracoUInt32Array(); unsigned long GetValue(long index); long size(); + boolean GetArray(VoidPtr out_values, long out_size); }; interface MetadataQuerier { @@ -202,6 +209,11 @@ interface Decoder { long GetTriangleStripsFromMesh([Ref, Const] Mesh m, DracoInt32Array strip_values); + boolean GetTrianglesUInt16Array([Ref, Const] Mesh m, + VoidPtr out_values, long out_size); + boolean GetTrianglesUInt32Array([Ref, Const] Mesh m, + VoidPtr out_values, long out_size); + boolean GetAttributeFloat([Ref, Const] PointAttribute pa, long att_index, DracoFloat32Array out_values); @@ -209,6 +221,9 @@ interface Decoder { boolean GetAttributeFloatForAllPoints([Ref, Const] PointCloud pc, [Ref, Const] PointAttribute pa, DracoFloat32Array out_values); + boolean GetAttributeFloatArrayForAllPoints([Ref, Const] PointCloud pc, + [Ref, Const] PointAttribute pa, + VoidPtr out_values, long out_size); // Deprecated, use GetAttributeInt32ForAllPoints instead. boolean GetAttributeIntForAllPoints([Ref, Const] PointCloud pc, @@ -221,18 +236,27 @@ interface Decoder { boolean GetAttributeUInt8ForAllPoints([Ref, Const] PointCloud pc, [Ref, Const] PointAttribute pa, DracoUInt8Array out_values); + boolean GetAttributeUInt8ArrayForAllPoints([Ref, Const] PointCloud pc, + [Ref, Const] PointAttribute pa, + VoidPtr out_values, long out_size); boolean GetAttributeInt16ForAllPoints([Ref, Const] PointCloud pc, [Ref, Const] PointAttribute pa, DracoInt16Array out_values); boolean GetAttributeUInt16ForAllPoints([Ref, Const] PointCloud pc, [Ref, Const] PointAttribute pa, DracoUInt16Array out_values); + boolean GetAttributeUInt16ArrayForAllPoints([Ref, Const] PointCloud pc, + [Ref, Const] PointAttribute pa, + VoidPtr out_values, long out_size); boolean GetAttributeInt32ForAllPoints([Ref, Const] PointCloud pc, [Ref, Const] PointAttribute pa, DracoInt32Array out_values); boolean GetAttributeUInt32ForAllPoints([Ref, Const] PointCloud pc, [Ref, Const] PointAttribute pa, DracoUInt32Array out_values); + boolean GetAttributeUInt32ArrayForAllPoints([Ref, Const] PointCloud pc, + [Ref, Const] PointAttribute pa, + VoidPtr out_values, long out_size); void SkipAttributeTransform(draco_GeometryAttribute_Type att_type); };