- Aldebaran documentation |
- C++ Libraries |
- index

libalmath 2.8.7.4

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gltf.h
Go to the documentation of this file.
1 /*
2 * Copyright 2017 Softbank Robotics. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the COPYING file.
5 */
6
7 // glTF-related utilities
8 //
9 // See https://github.com/KhronosGroup/glTF/ for a description of glTF.
10 //
11 // In brief:
12 //
13 // A glTF asset consists of a JSON file describing the structure and
14 // composition of a scene (possibly with animations) by
15 // referring to buffer-based binary data (geometry, texture, skinning
16 // and animation data are binary).
17 //
18 // The buffers can be:
19 // * contained in the JSON, as base64-encoded strings,
20 // * stored externaly at some URIs,
21 // * combined with the JSON in a single binary glTF file.
22 //
23 // A glTF binary buffer is a sequence of bytes, using a little-endian
24 // layout.
25 // The "accessor" element is used to describe the data type
26 // (eg. 4-tuple of floats) of a buffer view.
27 //
28 // The relevant elements are:
29 // * buffer: "uri", "byteLength"
30 // * buffeView: "buffer", "byteLength", ["byteOffset", "byteStride", "target"]
31 // * accessor: "bufferView", "count", "min", "max", "componentType", "type", ["byteOffset"]
32
33 // with componentType in
34 // * 5120 (GL_BYTE)
35 // * 5121 (GL_UNSIGNED_BYTE)
36 // * 5122 (GL_SHORT)
37 // * 5123 (GL_UNSIGNED_SHORT)
38 // * 5125 (GL_UNSIGNED_INT)
39 // * 5126 (GL_FLOAT)
40 //
41 // and type in:
42 // * "SCALAR"
43 // * "VEC2"
44 // * "VEC3"
45 // * "VEC4"
46 // * "MAT2"
47 // * "MAT3"
48 // * "MAT4"
49 //
50 // Beware, the byteStride suggests that one can interleave bufferViews,
51 // but I cound not get working.
52 //
53 // In C++, binary buffers are typically modeled as stream of char.
54 //
55 // Writing C++ types (eg. float) into a binary buffer can be done with:
56 // 1. a function writing into a ostream:
57 // void buffer_put(float, ostream &)
58 // 2. a function writing into an OutputIterator to char:
59 // template<typename OutputIterator>
60 // void buffer_put(float, OutputIterator it)
61 // 3. a custom InputIterator adaptor, converting a sequence of floats into a
62 // sequence of char.
63 //
64 // Here we use the first technique, with the buffer_put family of
65 // functions.
66 #ifndef LIB_ALMATH_SCENEGRAPH_GLTF_H
67 #define LIB_ALMATH_SCENEGRAPH_GLTF_H
68
69 #include <cstdint>
70 #include <limits>
71 #include <sstream>
72 #include <type_traits>
73 #include <boost/config.hpp>
74 #include <boost/lexical_cast.hpp>
75 #include <boost/optional.hpp>
76 #include <boost/archive/iterators/binary_from_base64.hpp>
77 #include <boost/archive/iterators/base64_from_binary.hpp>
78 #include <boost/archive/iterators/transform_width.hpp>
79 #include <boost/endian/buffers.hpp>
80 #include <boost/algorithm/string/join.hpp>
81 #include <boost/range/adaptor/transformed.hpp>
82
83 #include <almath/types/alposition2d.h>
84 #include <almath/types/alpose2d.h>
85 #include <Eigen/Geometry>
86
87 namespace AL {
88 namespace Math {
89 namespace glTF {
90
91 enum struct ComponentType {
92 GL_BYTE = 5120,
93 GL_UNSIGNED_BYTE = 5121,
94 GL_SHORT = 5122,
95 GL_UNSIGNED_SHORT = 5123,
96 GL_UNSIGNED_INT = 5125,
97 GL_FLOAT = 5126
98 };
99
100 enum struct DataType {
101 SCALAR,
102 VEC3,
103 VEC4,
104 MAT2,
105 MAT3,
106 MAT4
107 };
108
109
110 template< DataType element>
111 struct data_type_traits {
112 //BOOST_STATIC_CONSTEXPR size_t number_of_components;
113 //static BOOST_CONSTEXPR const char *cstr();
114 };
115
116 template<>
117 struct data_type_traits<DataType::SCALAR> {
118 BOOST_STATIC_CONSTEXPR size_t number_of_components = 1u;
119 static BOOST_CONSTEXPR const char *cstr() {return "SCALAR";}
120 };
121
122 template<>
123 struct data_type_traits<DataType::VEC3> {
124 BOOST_STATIC_CONSTEXPR size_t number_of_components = 3u;
125 static BOOST_CONSTEXPR const char *cstr() {return "VEC3";}
126 };
127
128 template<>
129 struct data_type_traits<DataType::VEC4> {
130 BOOST_STATIC_CONSTEXPR size_t number_of_components = 4u;
131 static BOOST_CONSTEXPR const char *cstr() {return "VEC4";}
132 };
133
134 template<>
135 struct data_type_traits<DataType::MAT2> {
136 BOOST_STATIC_CONSTEXPR size_t number_of_components = 4u;
137 static BOOST_CONSTEXPR const char *cstr() {return "MAT2";}
138 };
139
140 // todo: add the other specializations, MAT3, ...
141
142 enum struct Mode {
143 LINE_STRIP = 3
144 };
145
146 // writes a GL_BYTE (5120) value to a binary stream,
147 // in the format expected by glTF: 1 byte.
148 inline void buffer_put(std::ostream &os, char val) {
149 static_assert(sizeof(char) == 1u,
150 "error: the native char type is not 1 byte wide");
151 os.put(val);
152 }
153
154 // writes a GL_UNSIGNED_BYTE (5121) value to a binary stream,
155 // in the format expected by glTF: 1 byte.
156 inline void buffer_put(std::ostream &os, unsigned char val) {
157 static_assert(sizeof(unsigned char) == 1u,
158 "error: the native char type is not 1 byte wide");
159 os.put(static_cast<char>(val));
160 }
161
162 // writes a GL_SHORT (5122) value to a binary stream,
163 // in the format expected by glTF: 2 bytes, little-endian.
164 inline void buffer_put(std::ostream &os, std::int16_t val) {
165 const boost::endian::little_int16_buf_t tmp{val};
166 os.write(tmp.data(), sizeof(tmp));
167 }
168
169 // writes a GL_UNSIGNED_SHORT (5123) value to a binary stream,
170 // in the format expected by glTF: 2 bytes, little-endian
171 inline void buffer_put(std::ostream &os, std::uint16_t val) {
172 const boost::endian::little_uint16_buf_t tmp{val};
173 os.write(tmp.data(), sizeof(tmp));
174 }
175
176 // writes a GL_UNSIGNED_INT (5125) value to a binary stream,
177 // in the format expected by glTF: 4 bytes, little-endian
178 inline void buffer_put(std::ostream &os, std::uint32_t val) {
179 const boost::endian::little_uint32_buf_t tmp{val};
180 os.write(tmp.data(), sizeof(tmp));
181 }
182
183 // writes a GL_FLOAT (5126) value to a binary stream,
184 // in the format expected by glTF: 4 bytes, little-endian, single precision
185 // IEEE-754 number.
186 inline void buffer_put(std::ostream &os, float val) {
187 static_assert(std::numeric_limits<float>::is_iec559,
188 "error: the native float type is not IEEE-754-compliant");
189 static_assert(sizeof(float) == 4u,
190 "error: the native float type is not 4 bytes wide");
191 // Thanks to thoses assertions, we know that float is a single-precision
192 // IEEE-754 number.
193 // However we don't know
194 // * if float is little-endian or big-endian
195 // * if float endianness is the same as int endiannes
196 //
197 // Yet, we'll assume that float endianness and int endianness are
198 // identical.
199 //
200 // Some details from
201 // https://en.wikipedia.org/wiki/Endianness#Floating_point:
202 //
203 // Theoretically, this means that even standard IEEE floating-point data
204 // written by one machine might not be readable by another.
205 // However, on modern standard computers (i.e., implementing IEEE 754),
206 // one may in practice safely assume that the endianness is the same for
207 // floating-point numbers as for integers, making the conversion
208 // straightforward regardless of data type.
209 // (Small embedded systems using special floating-point formats may be
210 // another matter however).
211 //
212 // Linux implementation can be checked in:
213 // /usr/include/x86_64-linux-gnu/ieee754.h
214
215 #ifdef BOOST_LITTLE_ENDIAN
216 // "optimized" version
217 os.write(reinterpret_cast<const char *>(&val), 4);
218 #else
219 // portable version: works for little and big endian architectures
220 const boost::endian::little_uint32_buf_t tmp{
221 *reinterpret_cast<const uint32_t*>(&val)};
222 os.write(tmp.data, sizeof(tmp));
223 #endif
224 }
225
226 // Helper class which writes N components (of type T) at a time,
227 // while also storing the metadata that will be needed to fill the
228 // glTF accessor to the data.
229 template <typename T, size_t N>
230 class BufferAccessor {
231 public:
232 using value_type = std::array<T, N>;
233 value_type min;
234 value_type max;
235 size_t count;
236 std::ostream &os;
237 BufferAccessor(std::ostream &os) : count(0u), os(os) {
238 std::fill(min.begin(), min.end(), std::numeric_limits<T>::max());
239 std::fill(max.begin(), max.end(), std::numeric_limits<T>::lowest());
240 }
241 void put(value_type val) {
242 for (auto i = 0u; i < val.size(); ++i) {
243 min[i] = std::min(min[i], val[i]);
244 max[i] = std::max(max[i], val[i]);
245 buffer_put(os, val[i]);
246 }
247 ++count;
248 }
249 };
250
251 // http://www.boost.org/doc/libs/1_59_0/libs/serialization/doc/dataflow.html
252 // https://stackoverflow.com/questions/7053538/how-do-i-encode-a-string-to-base64-using-only-boost
253 inline std::string encode64(const std::string &val) {
254 using namespace boost::archive::iterators;
255 using It = base64_from_binary<transform_width<std::string::const_iterator, 6, 8>>;
256 auto tmp = std::string(It(std::begin(val)), It(std::end(val)));
257 return tmp.append((3 - val.size() % 3) % 3, '=');
258 }
259
260 template <typename T>
261 std::string toJSON(T val) {
262 static_assert(std::is_arithmetic<T>::value,
263 "toJSON requires T to be an integer,"
264 " floating point and boolean type");
265 // TODO: support std::string, with escaping.
266 // TODO: use SFINAE rather than assertion
267 // we use boost::lexical_cast because it handles the stream precision
268 return boost::lexical_cast<std::string>(val);
269 }
270
271 // a proxy object to stream a range as a JSON array
272 template <typename T, typename IT>
273 class AsJSONArray {
274 private:
275 const IT _begin;
276 const IT _end;
277
278 public:
279 AsJSONArray(IT b, IT e) : _begin(b), _end(e) {}
280
281 friend std::ostream &operator<<(std::ostream &os, const AsJSONArray &a) {
282 // Here is an alternate implementation:
283 // os << '['
284 // << boost::join(boost::adaptors::transform(v.min, toJSON<float>), ",")
285 // << ']';
286 // A better one would be to use
287 // http://en.cppreference.com/w/cpp/experimental/ostream_joiner
288 os.put('[');
289 auto it = a._begin;
290 auto write = [&os](const T &value) mutable {
291 os << toJSON(value);
292 };
293 if (it != a._end) {
294 write(*it);
295 while (++it != a._end) {
296 os.put(',');
297 write(*it);
298 }
299 }
300 os.put(']');
301 return os;
302 }
303 };
304
305 // helper to deduce iterator type.
306 template<typename T, typename IT>
307 AsJSONArray<T, IT> asJSONArray(IT b, IT e) {
308 return AsJSONArray<T, IT>(b, e);
309 }
310
311 // helper to deduce iterator type.
312 template<typename T, typename R, typename IT=typename R::const_iterator>
313 AsJSONArray<T, IT> asJSONArray(const R &range) {
314 using std::begin;
315 using std::end;
316 return AsJSONArray<T, IT>(begin(range), end(range));
317 }
318
319 struct Buffer {
320 size_t byteLength;
321 std::string uri;
322 };
323
324 inline
325 Buffer make_base64_Buffer(const std::string &binbuffer) {
326 return Buffer{binbuffer.size(),
327 std::string("data:application/octet-stream;base64,") +\
328 encode64(binbuffer)};
329 }
330
331 inline
332 std::ostream &operator<<(std::ostream &os, const Buffer &v) {
333 os << "{\"byteLength\":" << v.byteLength
334 << ",\"uri\":\"" << v.uri << "\""
335 << "}";
336 return os;
337 }
338
339 struct BufferView {
340 size_t buffer;
341 size_t byteLength;
342 boost::optional<size_t> byteOffset;
343 boost::optional<size_t> byteStride;
344 // target
345 };
346
347 inline
348 std::ostream &operator<<(std::ostream &os, const BufferView &v) {
349 os << "{\"buffer\":" << v.buffer
350 << ",\"byteLength\":" << v.byteLength;
351 if (v.byteOffset)
352 os << ",\"byteOffset\":" << *v.byteOffset;
353 if (v.byteStride)
354 os << ",\"byteStride\":" << *v.byteStride;
355 os << "}";
356 return os;
357 }
358
359 template <typename T, DataType DTYPE>
360 struct Accessor {
361 size_t bufferView;
362 ComponentType componentType; // redundant with T
363 size_t count;
364 static const DataType type = DTYPE;
365 std::array<T, data_type_traits<DTYPE>::number_of_components> min, max;// TODO: shall go in a union/variant, maybe depending on DataType?
366 boost::optional<size_t> byteOffset;
367 };
368
369 template <typename T, DataType _type>
370 std::ostream &operator<<(std::ostream &os, const Accessor<T, _type> &v) {
371
372 auto to_cstr = [](DataType type) {
373 switch (type) {
374 case DataType::SCALAR:
375 return "SCALAR";
376 case DataType::VEC3:
377 return "VEC3";
378 case DataType::VEC4:
379 return "VEC4";
380 case DataType::MAT2:
381 return "MAT2";
382 case DataType::MAT3:
383 return "MAT3";
384 case DataType::MAT4:
385 return "MAT4";
386 }
387 std::abort();
388 return "";
389 };
390 os << "{\"bufferView\":" << v.bufferView
391 << ",\"componentType\":"<< static_cast<int>(v.componentType)
392 << ",\"count\":" << toJSON(v.count)
393 << ",\"type\":\"" << to_cstr(v.type) << "\""
394 << ",\"min\":["
395 << boost::join(boost::adaptors::transform(v.min, toJSON<float>), ",")
396 << "]"
397 << ",\"max\":" << asJSONArray<T>(v.max);
398 if (v.byteOffset)
399 os << ",\"byteOffset\":" << *v.byteOffset;
400 os << "}";
401 return os;
402 }
403
404 struct Mesh {
405 // TODO: maybe create a struct for primitives too
406 std::vector<std::string> primitives;
407 boost::optional<std::string> name;
408 };
409
410 inline
411 std::ostream &operator<<(std::ostream &os, const Mesh &v) {
412 os << "{\"primitives\":["
413 << boost::join(v.primitives, ",") << "]";
414 if (v.name)
415 os << ",\"name\":\"" << *v.name << "\"";
416 os << "}";
417 return os;
418 }
419
420 struct rst {
421 // TODO: find a better way, which should support a full matrix
422 boost::optional<Eigen::Quaternionf> rotation;
423 boost::optional<Eigen::Vector3f> scale;
424 boost::optional<Eigen::Vector3f> translation;
425 };
426
427 struct Node {
428 std::vector<size_t> children;
429 boost::optional<std::string> name;
430 boost::optional<size_t> mesh;
431 boost::optional<size_t> camera;
432 boost::optional<rst> matrix;
433 //
434 // rotation, scale, translation
435 // matrix
436
437 };
438
439 inline
440 std::ostream &operator<<(std::ostream &os, const Node &v) {
441 auto prefix = '{';
442 if (!v.children.empty()) {
443 os << prefix << "\"children\":" << asJSONArray<size_t>(v.children);
444 prefix = ',';
445 }
446 if (v.name) {
447 os << prefix << "\"name\":\"" << *v.name << "\"";
448 prefix = ',';
449 }
450 if (v.mesh) {
451 os << prefix << "\"mesh\":" << toJSON(*v.mesh);
452 prefix = ',';
453 }
454 if (v.camera) {
455 os << prefix << "\"camera\":" << toJSON(*v.camera);
456 prefix = ',';
457 }
458 if (v.matrix) {
459 if (v.matrix->rotation) {
460 const auto q = *(v.matrix->rotation);
461 os << prefix << "\"rotation\":"
462 << asJSONArray<float>(
463 std::array<float,4>{{q.x(), q.y(), q.z(), q.w()}});
464 prefix = ',';
465 }
466 // TODO: support scale
467 if (v.matrix->translation) {
468 const auto vec3 = *(v.matrix->translation);
469 os << prefix << "\"translation\":"
470 << asJSONArray<float>(
471 std::array<float,3>{{vec3[0], vec3[1], vec3[2]}});
472 prefix = ',';
473 }
474 }
475 if (prefix == '{')
476 os << '{';
477 os << "}";
478 return os;
479 }
480
481 struct Scene {
482 std::vector<size_t> nodes;
483 boost::optional<std::string> name;
484 };
485
486 inline
487 std::ostream &operator<<(std::ostream &os, const Scene &v) {
488 os << "{\"nodes\":" << asJSONArray<size_t>(v.nodes);
489 if (v.name)
490 os << ",\"name\":\"" << *v.name << "\"";
491 os << "}";
492 return os;
493 }
494
495
496 enum struct Interpolation {
497 LINEAR
498 };
499
500 inline std::string to_string(Interpolation val) {
501 switch (val) {
502 case (Interpolation::LINEAR):
503 return "LINEAR";
504 }
505 std::abort();
506 }
507
508 struct Sampler {
509 size_t input;
510 size_t output;
511 Interpolation interpolation;
512 };
513
514 inline
515 std::ostream &operator<<(std::ostream &os, const Sampler &v) {
516 os << "{\"input\":" << toJSON(v.input)
517 << ",\"output\":"<< toJSON(v.output)
518 << ",\"interpolation\":\"" << to_string(v.interpolation) << "\""
519 << "}";
520 return os;
521 }
522
523 struct Target {
524 enum struct Path {
525 translation,
526 rotation
527 };
528
529 size_t node;
530 Path path;
531 };
532
533 inline
534 std::string to_string(Target::Path path) {
535 switch (path) {
536 case Target::Path::translation:
537 return "translation";
538 case Target::Path::rotation:
539 return "rotation";
540 }
541 std::abort();
542 }
543
544 inline
545 std::ostream &operator<<(std::ostream &os, const Target &v) {
546 os << "{\"node\":" << toJSON(v.node)
547 << ",\"path\":\"" << to_string(v.path) << "\"}";
548 return os;
549 }
550
551 struct Channel {
552 size_t sampler;
553 Target target;
554 };
555
556 inline
557 std::ostream &operator<<(std::ostream &os, const Channel &v) {
558 os << "{\"sampler\":" << toJSON(v.sampler)
559 << ",\"target\":" << v.target << "}";
560 return os;
561
562 }
563
564 struct Animation {
565 // channel/samplers
566 struct Indexes {
567 size_t translation;
568 size_t rotation;
569 };
570 boost::optional<std::string> name;
571 std::vector<Sampler> samplers;
572 std::vector<Channel> channels;
573 size_t add_sampler(const Sampler &v) {
574 samplers.push_back(v);
575 return samplers.size() - 1u;
576 }
577 size_t add_channel(const Channel &v) {
578 channels.push_back(v);
579 return channels.size() - 1u;
580 }
581 /*
582 Indexes addSamplers(size_t time_accessor,
583 size_t translation_accessor,
584 size_t rotation_accessor);
585 Indexes addChannels(Indexes, size_t target_node);
586 void toJSON(std::ostream &os) const;
587 */ //TODO rm?
588 };
589
590 inline
591 std::ostream &operator<<(std::ostream &os, const Animation &v) {
592
593 {
594 std::vector<std::string> tmp;
595 for (const auto &a: v.samplers) {
596 tmp.push_back(boost::lexical_cast<std::string>(a));
597 }
598 os << "{\"samplers\":[" << boost::join(tmp, ",") << "]";
599 }
600 {
601 std::vector<std::string> tmp;
602 for (const auto &a: v.channels) {
603 tmp.push_back(boost::lexical_cast<std::string>(a));
604 }
605 os << ",\"channels\":[" << boost::join(tmp, ",") << "]";
606 }
607 os << "}";
608 return os;
609 }
610
611 class Document {
612 private:
613 template <typename T>
614 size_t _add(std::vector<std::string> &vec, const T &val) {
615 vec.push_back(boost::lexical_cast<std::string>(val));
616 return vec.size() - 1u;
617 }
618 public:
619 std::vector<std::string> buffers;
620 std::vector<std::string> bufferViews;
621 std::vector<std::string> accessors;
622 std::vector<std::string> materials;
623 std::vector<std::string> meshes;
624 std::vector<std::string> cameras;
625 std::vector<std::string> nodes;
626 std::vector<std::string> scenes;
627 std::vector<Animation> animations;
628 boost::optional<size_t> scene;
629 size_t add(const Buffer &v) {return _add(buffers, v);}
630
631 size_t add(const BufferView &v) {return _add(bufferViews, v);}
632
633 template<typename T, DataType DTYPE>
634 size_t add(const Accessor<T, DTYPE> &v) {return _add(accessors, v);}
635
636 size_t add(const Mesh &v) {return _add(meshes, v);}
637
638 size_t add(const Node &v) {return _add(nodes, v);}
639
640 size_t add(const Scene &v) {return _add(scenes, v);}
641
642 size_t add(const Animation &v) {
643 animations.push_back(v);
644 return animations.size() - 1u;
645 }
646
647 void writeJSON(std::ostream &os) const {
648 os << "{\"asset\": {\"version\": \"2.0\"}"
649 << "\n,\"buffers\":\n ["
650 << boost::join(buffers, "\n ,")
651 << "]\n,\"bufferViews\":\n ["
652 << boost::join(bufferViews, "\n ,")
653 << "]\n,\"accessors\":\n ["
654 << boost::join(accessors, "\n ,")
655 << "]\n,\"meshes\":\n ["
656 << boost::join(meshes, "\n ,") << "]\n";
657 if (!materials.empty()) {
658 os << ",\"materials\":\n ["
659 << boost::join(materials, "\n ,") << "]\n";
660 } if (!cameras.empty()) {
661 os << ",\"cameras\":\n ["
662 << boost::join(cameras, "\n ,") << "]\n";
663 } if (!nodes.empty()) {
664 os << ",\"nodes\":\n ["
665 << boost::join(nodes, "\n ,") << "]\n";
666 } if (!scenes.empty()) {
667 os << ",\"scenes\":\n ["
668 << boost::join(scenes, "\n ,") << "]\n";
669 } if (scene) {
670 os << ",\"scene\":" << toJSON(*scene) << "\n";
671 } if (!animations.empty()) {
672 std::vector<std::string> anims;
673 for (const auto &a: animations)
674 anims.push_back(boost::lexical_cast<std::string>(a));
675 os << ",\"animations\":\n ["
676 << boost::join(anims, "\n ,") << "]\n";
677 }
678 os << "\n}";
679 }
680 };
681
682
683
684
685 // TODO: move somewhere else
686
687 inline
688 size_t add_base64_bva(glTF::Document &doc,
689 const std::vector<float> &vecs) {
690 std::ostringstream bs;
691 glTF::BufferAccessor<float, 1> ba(bs);
692 for (const auto &vec: vecs) {
693 ba.put({vec});
694 }
695 const auto binbuffer = bs.str();
696 const auto binbuffer_length = binbuffer.size();
697 const auto b0 = doc.add(glTF::make_base64_Buffer(binbuffer));
698 const auto bv0 = doc.add(glTF::BufferView{b0, binbuffer_length});
699 const auto a0 = doc.add(glTF::Accessor<float, glTF::DataType::SCALAR>{
700 bv0, glTF::ComponentType::GL_FLOAT,
701 ba.count, ba.min, ba.max});
702 return a0;
703 }
704
705 inline
706 size_t add_base64_bva(glTF::Document &doc,
707 const std::vector<std::array<float, 3>> &vecs) {
708 std::ostringstream bs;
709 glTF::BufferAccessor<float, 3> ba(bs);
710 for (const auto &vec: vecs) {
711 ba.put(vec);
712 }
713 const auto binbuffer = bs.str();
714 const auto binbuffer_length = binbuffer.size();
715 const auto b0 = doc.add(glTF::make_base64_Buffer(binbuffer));
716 const auto bv0 = doc.add(glTF::BufferView{b0, binbuffer_length});
717 const auto a0 = doc.add(glTF::Accessor<float, glTF::DataType::VEC3>{
718 bv0, glTF::ComponentType::GL_FLOAT,
719 ba.count, ba.min, ba.max});
720 return a0;
721 }
722
723 inline
724 size_t add_path(glTF::Document &doc,
725 const std::vector<std::array<float, 3>> &verts,
726 boost::optional<std::string> node_name) {
727 const auto a0 = add_base64_bva(doc, verts);
728 std::stringstream ps;
729 ps << "{\"mode\":" << static_cast<int>(glTF::Mode::LINE_STRIP);
730 //if (material)
731 // ps << ",\"material\":" << *material;
732 ps << ",\"attributes\":{\"POSITION\":" << a0 << "}"
733 << "}";
734 const auto m0 = doc.add(glTF::Mesh{{ps.str()}});
735 const auto n0 = doc.add(glTF::Node{{},
736 node_name,
737 m0});
738 return n0;
739 }
740
741 inline
742 size_t add_path(glTF::Document &doc,
743 const std::vector<Math::Position2D> &path,
744 boost::optional<std::string> node_name) {
745 std::vector<std::array<float, 3>> verts;
746 verts.reserve(path.size());
747 for (const auto &p: path) {
748 verts.push_back({p.x, p.y, 0.f});
749 }
750 return add_path(doc, verts, node_name);
751 }
752
753 inline
754 void animate(glTF::Document &doc,
755 size_t node,
756 size_t animation,
757 const std::vector<std::pair<float, Math::Pose2D>> &traj) {
758 auto &anim = doc.animations.at(animation);
759 std::ostringstream time_stream, translation_stream, rotation_stream;
760 glTF::BufferAccessor<float, 1> time_ba(time_stream);
761 glTF::BufferAccessor<float, 3> translation_ba(translation_stream);
762 glTF::BufferAccessor<float, 4> rotation_ba(rotation_stream);
763 for (const auto &el: traj) {
764 time_ba.put({el.first});
765 translation_ba.put({el.second.x, el.second.y, 0.f});
766 Eigen::Quaternionf q;
767 q = Eigen::AngleAxisf(el.second.theta, Eigen::Vector3f::UnitZ());
768 rotation_ba.put({q.x(), q.y(), q.z(), q.w()});
769 }
770
771 auto binbuffer = time_stream.str();
772 auto binbuffer_length = binbuffer.size();
773 auto b = doc.add(make_base64_Buffer(binbuffer));
774 auto bv = doc.add(glTF::BufferView{b, binbuffer_length});
775 const auto time_accessor = doc.add(
776 glTF::Accessor<float, glTF::DataType::SCALAR>{
777 bv, glTF::ComponentType::GL_FLOAT,
778 time_ba.count, time_ba.min, time_ba.max});
779
780 binbuffer = translation_stream.str();
781 binbuffer_length = binbuffer.size();
782 b = doc.add(make_base64_Buffer(binbuffer));
783 bv = doc.add(glTF::BufferView{b, binbuffer_length});
784 const auto translation_accessor = doc.add(
785 glTF::Accessor<float, glTF::DataType::VEC3>{
786 bv, glTF::ComponentType::GL_FLOAT,
787 translation_ba.count, translation_ba.min, translation_ba.max});
788
789 binbuffer = rotation_stream.str();
790 binbuffer_length = binbuffer.size();
791 b = doc.add(make_base64_Buffer(binbuffer));
792 bv = doc.add(glTF::BufferView{b, binbuffer_length});
793 const auto rotation_accessor = doc.add(
794 glTF::Accessor<float, glTF::DataType::VEC4>{
795 bv, glTF::ComponentType::GL_FLOAT,
796 rotation_ba.count, rotation_ba.min, rotation_ba.max});
797
798 const auto translation_sampler =
799 anim.add_sampler(glTF::Sampler{
800 time_accessor,
801 translation_accessor,
802 glTF::Interpolation::LINEAR});
803 anim.add_channel(
804 glTF::Channel{translation_sampler,
805 glTF::Target{node,
806 glTF::Target::Path::translation}});
807
808 const auto rotation_sampler =
809 anim.add_sampler(glTF::Sampler{
810 time_accessor,
811 rotation_accessor,
812 glTF::Interpolation::LINEAR});
813 anim.add_channel(
814 glTF::Channel{rotation_sampler,
815 glTF::Target{node,
816 glTF::Target::Path::rotation}});
817 }
818
819
820 }
821 }
822 }
823
824 #endif
AL::Math::glTF::BufferView::byteStride
boost::optional< size_t > byteStride
Definition: gltf.h:343
AL::Math::glTF::AsJSONArray
Definition: gltf.h:273
AL::Math::glTF::Document::scene
boost::optional< size_t > scene
Definition: gltf.h:628
AL::Math::glTF::Sampler::interpolation
Interpolation interpolation
Definition: gltf.h:511
AL::Math::glTF::BufferAccessor::value_type
std::array< T, N > value_type
Definition: gltf.h:232
AL::Math::glTF::Accessor::type
static const DataType type
Definition: gltf.h:364
AL::Math::glTF::rst::translation
boost::optional< Eigen::Vector3f > translation
Definition: gltf.h:424
AL::Math::glTF::Accessor::max
std::array< T, data_type_traits< DTYPE >::number_of_components > max
Definition: gltf.h:365
AL::Math::glTF::Accessor::componentType
ComponentType componentType
Definition: gltf.h:362
AL::Math::glTF::Animation::Indexes::translation
size_t translation
Definition: gltf.h:567
AL::Math::glTF::ComponentType::GL_UNSIGNED_BYTE
AL::Math::glTF::Mesh::primitives
std::vector< std::string > primitives
Definition: gltf.h:406
AL::Math::glTF::BufferView::byteLength
size_t byteLength
Definition: gltf.h:341
AL::Math::glTF::Node
Definition: gltf.h:427
AL::Math::glTF::asJSONArray
AsJSONArray< T, IT > asJSONArray(IT b, IT e)
Definition: gltf.h:307
AL::Math::glTF::DataType::VEC3
AL::Math::glTF::Mode::LINE_STRIP
AL::Math::glTF::Scene
Definition: gltf.h:481
AL::Math::glTF::Document::add
size_t add(const Mesh &v)
Definition: gltf.h:636
AL::Math::glTF::Document::materials
std::vector< std::string > materials
Definition: gltf.h:622
AL::Math::glTF::rst::rotation
boost::optional< Eigen::Quaternionf > rotation
Definition: gltf.h:422
AL::Math::glTF::Channel::target
Target target
Definition: gltf.h:553
AL::Math::glTF::Channel
Definition: gltf.h:551
AL::Math::glTF::ComponentType
ComponentType
Definition: gltf.h:91
AL::Math::glTF::BufferAccessor::max
value_type max
Definition: gltf.h:234
AL::Math::glTF::Target::Path::translation
AL::Math::glTF::Node::camera
boost::optional< size_t > camera
Definition: gltf.h:431
AL::Math::glTF::Animation::Indexes::rotation
size_t rotation
Definition: gltf.h:568
AL::Math::glTF::Sampler
Definition: gltf.h:508
AL::Math::glTF::Scene::name
boost::optional< std::string > name
Definition: gltf.h:483
AL::Math::glTF::Accessor::bufferView
size_t bufferView
Definition: gltf.h:361
AL::Math::glTF::Target::node
size_t node
Definition: gltf.h:529
AL::Math::glTF::Interpolation::LINEAR
AL::Math::glTF::DataType::SCALAR
AL::Math::glTF::to_string
std::string to_string(Interpolation val)
Definition: gltf.h:500
AL::Math::glTF::data_type_traits< DataType::MAT2 >::cstr
static BOOST_CONSTEXPR const char * cstr()
Definition: gltf.h:137
AL::Math::glTF::Document::writeJSON
void writeJSON(std::ostream &os) const
Definition: gltf.h:647
AL::Math::glTF::buffer_put
void buffer_put(std::ostream &os, char val)
Definition: gltf.h:148
AL::Math::glTF::Document::add
size_t add(const Accessor< T, DTYPE > &v)
Definition: gltf.h:634
AL::Math::glTF::ComponentType::GL_SHORT
AL::Math::glTF::Animation::name
boost::optional< std::string > name
Definition: gltf.h:570
AL::Math::glTF::Node::children
std::vector< size_t > children
Definition: gltf.h:428
AL::Math::glTF::Target::Path
Path
Definition: gltf.h:524
AL::Math::glTF::DataType
DataType
Definition: gltf.h:100
AL::Math::glTF::Animation::channels
std::vector< Channel > channels
Definition: gltf.h:572
AL::Math::glTF::add_path
size_t add_path(glTF::Document &doc, const std::vector< std::array< float, 3 >> &verts, boost::optional< std::string > node_name)
Definition: gltf.h:724
AL::Math::glTF::Animation::samplers
std::vector< Sampler > samplers
Definition: gltf.h:571
AL::Math::glTF::Node::name
boost::optional< std::string > name
Definition: gltf.h:429
AL::Math::glTF::Node::matrix
boost::optional< rst > matrix
Definition: gltf.h:432
AL::Math::glTF::Document::scenes
std::vector< std::string > scenes
Definition: gltf.h:626
AL::Math::glTF::Target::Path::rotation
AL::Math::glTF::Document::accessors
std::vector< std::string > accessors
Definition: gltf.h:621
AL::Math::glTF::AsJSONArray::AsJSONArray
AsJSONArray(IT b, IT e)
Definition: gltf.h:279
AL::Math::glTF::Document::animations
std::vector< Animation > animations
Definition: gltf.h:627
AL::Math::glTF::Accessor::byteOffset
boost::optional< size_t > byteOffset
Definition: gltf.h:366
AL::Math::glTF::data_type_traits< DataType::VEC3 >::cstr
static BOOST_CONSTEXPR const char * cstr()
Definition: gltf.h:125
AL::Math::glTF::Accessor
Definition: gltf.h:360
AL::Math::glTF::Buffer
Definition: gltf.h:319
AL::Math::glTF::Buffer::uri
std::string uri
Definition: gltf.h:321
AL::Math::glTF::Document::add
size_t add(const Animation &v)
Definition: gltf.h:642
AL::Math::glTF::data_type_traits< DataType::VEC4 >::cstr
static BOOST_CONSTEXPR const char * cstr()
Definition: gltf.h:131
AL::Math::glTF::operator<<
std::ostream & operator<<(std::ostream &os, const Buffer &v)
Definition: gltf.h:332
AL::Math::glTF::rst::scale
boost::optional< Eigen::Vector3f > scale
Definition: gltf.h:423
AL::Math::glTF::Document::add
size_t add(const Node &v)
Definition: gltf.h:638
AL::Math::glTF::Node::mesh
boost::optional< size_t > mesh
Definition: gltf.h:430
AL::Math::glTF::Document::add
size_t add(const Scene &v)
Definition: gltf.h:640
AL::Math::glTF::Document::bufferViews
std::vector< std::string > bufferViews
Definition: gltf.h:620
AL::Math::glTF::DataType::MAT2
AL::Math::glTF::DataType::MAT3
AL::Math::glTF::BufferAccessor::os
std::ostream & os
Definition: gltf.h:236
AL::Math::glTF::ComponentType::GL_UNSIGNED_INT
alpose2d.h
AL::Math::glTF::Target::path
Path path
Definition: gltf.h:530
AL::Math::glTF::Document::cameras
std::vector< std::string > cameras
Definition: gltf.h:624
AL::Math::glTF::BufferAccessor::min
value_type min
Definition: gltf.h:233
AL::Math::glTF::Interpolation
Interpolation
Definition: gltf.h:496
AL::Math::glTF::Sampler::output
size_t output
Definition: gltf.h:510
AL::Math::glTF::BufferView::byteOffset
boost::optional< size_t > byteOffset
Definition: gltf.h:342
AL::Math::glTF::BufferAccessor::put
void put(value_type val)
Definition: gltf.h:241
AL::Math::glTF::add_base64_bva
size_t add_base64_bva(glTF::Document &doc, const std::vector< float > &vecs)
Definition: gltf.h:688
AL::Math::glTF::Accessor::count
size_t count
Definition: gltf.h:363
AL::Math::glTF::BufferAccessor
Definition: gltf.h:230
AL::Math::glTF::data_type_traits
Definition: gltf.h:111
AL::Math::glTF::Accessor::min
std::array< T, data_type_traits< DTYPE >::number_of_components > min
Definition: gltf.h:365
AL::Math::glTF::make_base64_Buffer
Buffer make_base64_Buffer(const std::string &binbuffer)
Definition: gltf.h:325
AL::Math::glTF::animate
void animate(glTF::Document &doc, size_t node, size_t animation, const std::vector< std::pair< float, Math::Pose2D >> &traj)
Definition: gltf.h:754
AL::Math::glTF::ComponentType::GL_FLOAT
AL::Math::glTF::data_type_traits< DataType::SCALAR >::cstr
static BOOST_CONSTEXPR const char * cstr()
Definition: gltf.h:119
AL::Math::glTF::Buffer::byteLength
size_t byteLength
Definition: gltf.h:320
AL::Math::glTF::Document::add
size_t add(const BufferView &v)
Definition: gltf.h:631
AL::Math::glTF::Sampler::input
size_t input
Definition: gltf.h:509
AL::Math::glTF::Document::nodes
std::vector< std::string > nodes
Definition: gltf.h:625
AL::Math::glTF::rst
Definition: gltf.h:420
AL::Math::glTF::BufferView
Definition: gltf.h:339
alposition2d.h
AL::Math::glTF::Animation::add_sampler
size_t add_sampler(const Sampler &v)
Definition: gltf.h:573
AL::Math::glTF::toJSON
std::string toJSON(T val)
Definition: gltf.h:261
AL::Math::glTF::Mesh
Definition: gltf.h:404
AL::Math::glTF::encode64
std::string encode64(const std::string &val)
Definition: gltf.h:253
AL::Math::glTF::Animation::add_channel
size_t add_channel(const Channel &v)
Definition: gltf.h:577
AL::Math::glTF::Animation::Indexes
Definition: gltf.h:566
AL::Math::glTF::Mode
Mode
Definition: gltf.h:142
AL::Math::glTF::DataType::MAT4
AL::Math::glTF::Mesh::name
boost::optional< std::string > name
Definition: gltf.h:407
AL::Math::glTF::Channel::sampler
size_t sampler
Definition: gltf.h:552
AL::Math::glTF::ComponentType::GL_UNSIGNED_SHORT
AL::Math::glTF::Target
Definition: gltf.h:523
AL::Math::glTF::BufferAccessor::count
size_t count
Definition: gltf.h:235
AL::Math::glTF::Animation
Definition: gltf.h:564
AL::Math::glTF::Document
Definition: gltf.h:611
AL::Math::glTF::ComponentType::GL_BYTE
AL::Math::glTF::Document::add
size_t add(const Buffer &v)
Definition: gltf.h:629
AL::Math::glTF::DataType::VEC4
AL::Math::glTF::BufferAccessor::BufferAccessor
BufferAccessor(std::ostream &os)
Definition: gltf.h:237
AL::Math::glTF::AsJSONArray::operator<<
friend std::ostream & operator<<(std::ostream &os, const AsJSONArray &a)
Definition: gltf.h:281
AL::Math::glTF::BufferView::buffer
size_t buffer
Definition: gltf.h:340
AL::Math::glTF::Document::buffers
std::vector< std::string > buffers
Definition: gltf.h:619
AL::Math::glTF::Scene::nodes
std::vector< size_t > nodes
Definition: gltf.h:482
AL::Math::glTF::Document::meshes
std::vector< std::string > meshes
Definition: gltf.h:623