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