1 // Copyright 2017 The Draco Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 #ifndef DRACO_JAVASCRIPT_EMSCRIPTEN_DECODER_WEBIDL_WRAPPER_H_ 16 #define DRACO_JAVASCRIPT_EMSCRIPTEN_DECODER_WEBIDL_WRAPPER_H_ 17 18 #include <vector> 19 20 #include "draco/attributes/attribute_transform_type.h" 21 #include "draco/attributes/point_attribute.h" 22 #include "draco/compression/config/compression_shared.h" 23 #include "draco/compression/decode.h" 24 #include "draco/core/decoder_buffer.h" 25 #include "draco/mesh/mesh.h" 26 27 typedef draco::AttributeTransformType draco_AttributeTransformType; 28 typedef draco::GeometryAttribute draco_GeometryAttribute; 29 typedef draco_GeometryAttribute::Type draco_GeometryAttribute_Type; 30 typedef draco::EncodedGeometryType draco_EncodedGeometryType; 31 typedef draco::Status draco_Status; 32 typedef draco::Status::Code draco_StatusCode; 33 typedef draco::DataType draco_DataType; 34 35 // To generate Draco JavaScript bindings you must have emscripten installed. 36 // Then run make -f Makefile.emcc jslib. 37 template <typename T> 38 class DracoArray { 39 public: GetValue(int index)40 T GetValue(int index) const { return values_[index]; } 41 Resize(int size)42 void Resize(int size) { values_.resize(size); } MoveData(std::vector<T> && values)43 void MoveData(std::vector<T> &&values) { values_ = std::move(values); } 44 45 // Directly sets a value for a specific index. The array has to be already 46 // allocated at this point (using Resize() method). SetValue(int index,T val)47 void SetValue(int index, T val) { values_[index] = val; } 48 size()49 int size() const { return values_.size(); } 50 51 private: 52 std::vector<T> values_; 53 }; 54 55 using DracoFloat32Array = DracoArray<float>; 56 using DracoInt8Array = DracoArray<int8_t>; 57 using DracoUInt8Array = DracoArray<uint8_t>; 58 using DracoInt16Array = DracoArray<int16_t>; 59 using DracoUInt16Array = DracoArray<uint16_t>; 60 using DracoInt32Array = DracoArray<int32_t>; 61 using DracoUInt32Array = DracoArray<uint32_t>; 62 63 class MetadataQuerier { 64 public: 65 MetadataQuerier(); 66 67 bool HasEntry(const draco::Metadata &metadata, const char *entry_name) const; 68 69 // This function does not guarantee that entry's type is long. 70 long GetIntEntry(const draco::Metadata &metadata, 71 const char *entry_name) const; 72 73 // This function does not guarantee that entry types are long. 74 void GetIntEntryArray(const draco::Metadata &metadata, const char *entry_name, 75 DracoInt32Array *out_values) const; 76 77 // This function does not guarantee that entry's type is double. 78 double GetDoubleEntry(const draco::Metadata &metadata, 79 const char *entry_name) const; 80 81 // This function does not guarantee that entry's type is char*. 82 const char *GetStringEntry(const draco::Metadata &metadata, 83 const char *entry_name); 84 85 long NumEntries(const draco::Metadata &metadata) const; 86 const char *GetEntryName(const draco::Metadata &metadata, int entry_id); 87 88 private: 89 // Cached values for metadata entries. 90 std::vector<std::string> entry_names_; 91 const draco::Metadata *entry_names_metadata_; 92 93 // Cached value for GetStringEntry() to avoid scoping issues. 94 std::string last_string_returned_; 95 }; 96 97 // Class used by emscripten WebIDL Binder [1] to wrap calls to decode Draco 98 // data. 99 // [1]http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.html 100 class Decoder { 101 public: 102 Decoder(); 103 104 // Returns the geometry type stored in the |in_buffer|. Return values can be 105 // INVALID_GEOMETRY_TYPE, POINT_CLOUD, or MESH. 106 // Deprecated: Use decoder.GetEncodedGeometryType(array), where |array| is 107 // an Int8Array containing the encoded data. 108 static draco_EncodedGeometryType GetEncodedGeometryType_Deprecated( 109 draco::DecoderBuffer *in_buffer); 110 111 // Decodes a point cloud from the provided buffer. 112 // Deprecated: Use DecodeArrayToPointCloud. 113 const draco::Status *DecodeBufferToPointCloud( 114 draco::DecoderBuffer *in_buffer, draco::PointCloud *out_point_cloud); 115 116 // Decodes a point cloud from the provided array. 117 const draco::Status *DecodeArrayToPointCloud( 118 const char *data, size_t data_size, draco::PointCloud *out_point_cloud); 119 120 // Decodes a triangular mesh from the provided buffer. 121 // Deprecated: Use DecodeArrayToMesh. 122 const draco::Status *DecodeBufferToMesh(draco::DecoderBuffer *in_buffer, 123 draco::Mesh *out_mesh); 124 125 // Decodes a mesh from the provided array. 126 const draco::Status *DecodeArrayToMesh(const char *data, size_t data_size, 127 draco::Mesh *out_mesh); 128 129 // Returns an attribute id for the first attribute of a given type. 130 long GetAttributeId(const draco::PointCloud &pc, 131 draco_GeometryAttribute_Type type) const; 132 133 // Returns an attribute id of an attribute that contains a valid metadata 134 // entry "name" with value |attribute_name|. 135 static long GetAttributeIdByName(const draco::PointCloud &pc, 136 const char *attribute_name); 137 138 // Returns an attribute id of an attribute with a specified metadata pair 139 // <|metadata_name|, |metadata_value|>. 140 static long GetAttributeIdByMetadataEntry(const draco::PointCloud &pc, 141 const char *metadata_name, 142 const char *metadata_value); 143 144 // Returns an attribute id of an attribute that has the unique id. 145 static const draco::PointAttribute *GetAttributeByUniqueId( 146 const draco::PointCloud &pc, long unique_id); 147 148 // Returns a PointAttribute pointer from |att_id| index. 149 static const draco::PointAttribute *GetAttribute(const draco::PointCloud &pc, 150 long att_id); 151 152 // Returns Mesh::Face values in |out_values| from |face_id| index. 153 static bool GetFaceFromMesh(const draco::Mesh &m, 154 draco::FaceIndex::ValueType face_id, 155 DracoInt32Array *out_values); 156 157 // Returns triangle strips for mesh |m|. If there's multiple strips, 158 // the strips will be separated by degenerate faces. 159 static long GetTriangleStripsFromMesh(const draco::Mesh &m, 160 DracoInt32Array *strip_values); 161 162 // Returns all faces as triangles. Fails if indices exceed the data range (in 163 // particular for uint16), or the output array size does not match. 164 // |out_size| is the size in bytes of |out_values|. |out_values| must be 165 // allocated before calling this function. 166 static bool GetTrianglesUInt16Array(const draco::Mesh &m, int out_size, 167 void *out_values); 168 static bool GetTrianglesUInt32Array(const draco::Mesh &m, int out_size, 169 void *out_values); 170 171 // Returns float attribute values in |out_values| from |entry_index| index. 172 static bool GetAttributeFloat( 173 const draco::PointAttribute &pa, 174 draco::AttributeValueIndex::ValueType entry_index, 175 DracoFloat32Array *out_values); 176 177 // Returns float attribute values for all point ids of the point cloud. 178 // I.e., the |out_values| is going to contain m.num_points() entries. 179 static bool GetAttributeFloatForAllPoints(const draco::PointCloud &pc, 180 const draco::PointAttribute &pa, 181 DracoFloat32Array *out_values); 182 183 // Returns float attribute values for all point ids of the point cloud. 184 // I.e., the |out_values| is going to contain m.num_points() entries. 185 static bool GetAttributeFloatArrayForAllPoints( 186 const draco::PointCloud &pc, const draco::PointAttribute &pa, 187 int out_size, void *out_values); 188 189 // Returns int8_t attribute values for all point ids of the point cloud. 190 // I.e., the |out_values| is going to contain m.num_points() entries. 191 static bool GetAttributeInt8ForAllPoints(const draco::PointCloud &pc, 192 const draco::PointAttribute &pa, 193 DracoInt8Array *out_values); 194 195 // Returns uint8_t attribute values for all point ids of the point cloud. 196 // I.e., the |out_values| is going to contain m.num_points() entries. 197 static bool GetAttributeUInt8ForAllPoints(const draco::PointCloud &pc, 198 const draco::PointAttribute &pa, 199 DracoUInt8Array *out_values); 200 201 // Returns int16_t attribute values for all point ids of the point cloud. 202 // I.e., the |out_values| is going to contain m.num_points() entries. 203 static bool GetAttributeInt16ForAllPoints(const draco::PointCloud &pc, 204 const draco::PointAttribute &pa, 205 DracoInt16Array *out_values); 206 207 // Returns uint16_t attribute values for all point ids of the point cloud. 208 // I.e., the |out_values| is going to contain m.num_points() entries. 209 static bool GetAttributeUInt16ForAllPoints(const draco::PointCloud &pc, 210 const draco::PointAttribute &pa, 211 DracoUInt16Array *out_values); 212 213 // Returns int32_t attribute values for all point ids of the point cloud. 214 // I.e., the |out_values| is going to contain m.num_points() entries. 215 static bool GetAttributeInt32ForAllPoints(const draco::PointCloud &pc, 216 const draco::PointAttribute &pa, 217 DracoInt32Array *out_values); 218 219 // Deprecated: Use GetAttributeInt32ForAllPoints() instead. 220 static bool GetAttributeIntForAllPoints(const draco::PointCloud &pc, 221 const draco::PointAttribute &pa, 222 DracoInt32Array *out_values); 223 224 // Returns uint32_t attribute values for all point ids of the point cloud. 225 // I.e., the |out_values| is going to contain m.num_points() entries. 226 static bool GetAttributeUInt32ForAllPoints(const draco::PointCloud &pc, 227 const draco::PointAttribute &pa, 228 DracoUInt32Array *out_values); 229 230 // Returns |data_type| attribute values for all point ids of the point cloud. 231 // I.e., the |out_values| is going to contain m.num_points() entries. 232 // |out_size| is the size in bytes of |out_values|. |out_values| must be 233 // allocated before calling this function. 234 static bool GetAttributeDataArrayForAllPoints(const draco::PointCloud &pc, 235 const draco::PointAttribute &pa, 236 draco_DataType data_type, 237 int out_size, void *out_values); 238 239 // Tells the decoder to skip an attribute transform (e.g. dequantization) for 240 // an attribute of a given type. 241 void SkipAttributeTransform(draco_GeometryAttribute_Type att_type); 242 243 const draco::Metadata *GetMetadata(const draco::PointCloud &pc) const; 244 const draco::Metadata *GetAttributeMetadata(const draco::PointCloud &pc, 245 long att_id) const; 246 247 private: 248 template <class DracoArrayT, class ValueTypeT> GetAttributeDataForAllPoints(const draco::PointCloud & pc,const draco::PointAttribute & pa,draco::DataType draco_signed_type,draco::DataType draco_unsigned_type,DracoArrayT * out_values)249 static bool GetAttributeDataForAllPoints(const draco::PointCloud &pc, 250 const draco::PointAttribute &pa, 251 draco::DataType draco_signed_type, 252 draco::DataType draco_unsigned_type, 253 DracoArrayT *out_values) { 254 const int components = pa.num_components(); 255 const int num_points = pc.num_points(); 256 const int num_entries = num_points * components; 257 258 if ((pa.data_type() == draco_signed_type || 259 pa.data_type() == draco_unsigned_type) && 260 pa.is_mapping_identity()) { 261 // Copy values directly to the output vector. 262 const ValueTypeT *ptr = reinterpret_cast<const ValueTypeT *>( 263 pa.GetAddress(draco::AttributeValueIndex(0))); 264 out_values->MoveData({ptr, ptr + num_entries}); 265 return true; 266 } 267 268 // Copy values one by one. 269 std::vector<ValueTypeT> values(components); 270 int entry_id = 0; 271 272 out_values->Resize(num_entries); 273 for (draco::PointIndex i(0); i < num_points; ++i) { 274 const draco::AttributeValueIndex val_index = pa.mapped_index(i); 275 if (!pa.ConvertValue<ValueTypeT>(val_index, &values[0])) { 276 return false; 277 } 278 for (int j = 0; j < components; ++j) { 279 out_values->SetValue(entry_id++, values[j]); 280 } 281 } 282 return true; 283 } 284 285 template <class T> GetAttributeDataArrayForAllPoints(const draco::PointCloud & pc,const draco::PointAttribute & pa,const draco::DataType type,int out_size,void * out_values)286 static bool GetAttributeDataArrayForAllPoints(const draco::PointCloud &pc, 287 const draco::PointAttribute &pa, 288 const draco::DataType type, 289 int out_size, 290 void *out_values) { 291 const int components = pa.num_components(); 292 const int num_points = pc.num_points(); 293 const int data_size = num_points * components * sizeof(T); 294 if (data_size != out_size) { 295 return false; 296 } 297 const bool requested_type_matches = pa.data_type() == type; 298 if (requested_type_matches && pa.is_mapping_identity()) { 299 // Copy values directly to the output vector. 300 const auto ptr = pa.GetAddress(draco::AttributeValueIndex(0)); 301 ::memcpy(out_values, ptr, data_size); 302 return true; 303 } 304 305 // Copy values one by one. 306 std::vector<T> values(components); 307 int entry_id = 0; 308 309 T *const typed_output = reinterpret_cast<T *>(out_values); 310 for (draco::PointIndex i(0); i < num_points; ++i) { 311 const draco::AttributeValueIndex val_index = pa.mapped_index(i); 312 if (requested_type_matches) { 313 pa.GetValue(val_index, values.data()); 314 } else { 315 if (!pa.ConvertValue<T>(val_index, values.data())) { 316 return false; 317 } 318 } 319 for (int j = 0; j < components; ++j) { 320 typed_output[entry_id++] = values[j]; 321 } 322 } 323 return true; 324 } 325 326 draco::Decoder decoder_; 327 draco::Status last_status_; 328 }; 329 330 #endif // DRACO_JAVASCRIPT_EMSCRIPTEN_DECODER_WEBIDL_WRAPPER_H_ 331