138namespace Threedim::LiveLink
141constexpr uint16_t default_port = 9877;
145constexpr uint32_t max_frame_size = 512u * 1024u * 1024u;
147enum class frame_type : uint8_t
167constexpr int protocol_version = 1;
170inline constexpr std::string_view accepted_frames[] = {
171 "scene",
"patch",
"remove",
"transforms",
"joints",
172 "weights",
"visibility",
"lights",
"cameras",
"materials",
173 "environment",
"active_camera",
"mesh",
"image",
"native_scene"};
180 std::endian::native == std::endian::little,
181 "the live link wire format is read in place as little-endian");
187 template <
typename T>
188 bool operator()(T& out)
noexcept
190 if(in.size() <
sizeof(T))
192 std::memcpy(&out, in.data(),
sizeof(T));
193 in.remove_prefix(
sizeof(T));
197 template <
typename T, std::
size_t N>
198 bool operator()(T (&out)[N])
noexcept
206 bool operator()(std::string& out)
209 if(!(*
this)(len) || in.size() < len)
211 out.assign(in.data(), len);
212 in.remove_prefix(len);
221 template <
typename T>
222 void operator()(
const T& v)
225 std::memcpy(buf, &v,
sizeof(T));
226 out.append(buf,
sizeof(T));
229 template <
typename T, std::
size_t N>
230 void operator()(
const T (&v)[N])
232 for(
const auto& x : v)
236 void operator()(
const std::string& s)
238 const auto len = uint16_t(std::min<std::size_t>(s.size(), 0xFFFF));
240 out.append(s.data(), len);
248 float translation[3]{0.f, 0.f, 0.f};
249 float rotation[4]{0.f, 0.f, 0.f, 1.f};
250 float scale[3]{1.f, 1.f, 1.f};
252 static constexpr std::size_t min_size = 2 + 10 *
sizeof(float);
255 return r(name) && r(translation) && r(rotation) && r(scale);
259 w(name), w(translation), w(rotation), w(scale);
265 std::string armature;
266 std::vector<transform_record> bones;
268 static constexpr std::size_t min_size = 2 + 4;
272 if(!r(armature) || !r(count) || count > r.in.size() / transform_record::min_size)
282 w(armature), w(uint32_t(bones.size()));
283 for(
const auto& b : bones)
291 std::vector<float> weights;
293 static constexpr std::size_t min_size = 2 + 2;
297 if(!r(name) || !r(n) || r.in.size() < n *
sizeof(
float))
300 for(
float& f : weights)
306 w(name), w(uint16_t(weights.size()));
307 for(
float f : weights)
317 static constexpr std::size_t min_size = 2 + 1;
324 enum : uint8_t { directional = 0, point = 1, spot = 2 };
328 float color[3]{1.f, 1.f, 1.f};
329 float intensity{1.f};
331 float inner_cone{0.f};
332 float outer_cone{0.7853981f};
334 static constexpr std::size_t min_size = 2 + 1 + 7 *
sizeof(float);
337 return r(name) && r(type) && r(color) && r(intensity) && r(
range)
338 && r(inner_cone) && r(outer_cone);
342 w(name), w(type), w(color), w(intensity), w(
range), w(inner_cone), w(outer_cone);
348 enum : uint8_t { perspective = 0, orthographic = 1 };
351 uint8_t projection{perspective};
352 float yfov{0.7853981f};
359 static constexpr std::size_t min_size = 2 + 1 + 6 *
sizeof(float);
362 return r(name) && r(projection) && r(yfov) && r(aspect) && r(znear) && r(zfar)
363 && r(xmag) && r(ymag);
367 w(name), w(projection), w(yfov), w(aspect), w(znear), w(zfar), w(xmag), w(ymag);
377 base_color_rgb = 1u << 0,
379 metallic_field = 1u << 2,
380 roughness_field = 1u << 3,
386 float base_color[4]{1.f, 1.f, 1.f, 1.f};
388 float roughness{1.f};
389 float emissive_factor[3]{0.f, 0.f, 0.f};
390 float emissive_strength{1.f};
392 static constexpr std::size_t min_size = 2 + 4 + 10 *
sizeof(float);
395 return r(name) && r(fields) && r(base_color) && r(metallic) && r(roughness)
396 && r(emissive_factor) && r(emissive_strength);
400 w(name), w(fields), w(base_color), w(metallic), w(roughness), w(emissive_factor),
401 w(emissive_strength);
410 static constexpr std::size_t min_size = 2;
418 float ambient[3]{0.f, 0.f, 0.f};
421 static constexpr std::size_t min_size = 2 + 4 *
sizeof(float);
422 bool read(
detail::reader& r) {
return r(name) && r(ambient) && r(strength); }
423 void write(
detail::writer& w)
const { w(name), w(ambient), w(strength); }
432template <
typename Record>
436 std::vector<Record> records;
443 uint32_t vertex_count{};
444 std::shared_ptr<std::vector<float>> positions, normals, texcoords, texcoords1, colors;
445 std::shared_ptr<std::vector<uint16_t>> joints;
446 std::shared_ptr<std::vector<float>> weights;
447 std::shared_ptr<std::vector<uint32_t>> indices;
450 std::shared_ptr<std::vector<float>> positions, normals;
452 std::vector<morph> targets;
459 std::vector<native_primitive> primitives;
466 std::string mime_type;
467 std::shared_ptr<std::vector<uint8_t>> bytes;
478inline std::optional<scene_message> parse_scene(std::string_view body)
486 if(r.in.size() < 12 || r.in.substr(0, 4) !=
"glTF")
488 m.glb.assign(r.in.data(), r.in.size());
495bool read_array(reader& r, std::size_t count, std::shared_ptr<std::vector<T>>& out)
498 if(count > r.in.size() /
sizeof(T))
500 out = std::make_shared<std::vector<T>>(count);
501 std::memcpy(out->data(), r.in.data(), count *
sizeof(T));
502 r.in.remove_prefix(count *
sizeof(T));
507enum mesh_attribute : uint8_t
516inline std::optional<mesh_message> parse_mesh(std::string_view body)
519 detail::reader r{body};
521 if(!r(m.seq) || !r(m.key) || !r(count))
523 m.primitives.resize(count);
524 for(
auto& p : m.primitives)
529 if(!r(p.vertex_count) || !r(indices) || !r(attrs) || !r(targets))
531 const std::size_t v = p.vertex_count;
532 if(!detail::read_array(r, 3 * v, p.positions))
534 if((attrs & mesh_normal) && !detail::read_array(r, 3 * v, p.normals))
536 if((attrs & mesh_texcoord0) && !detail::read_array(r, 2 * v, p.texcoords))
538 if((attrs & mesh_texcoord1) && !detail::read_array(r, 2 * v, p.texcoords1))
540 if((attrs & mesh_color0) && !detail::read_array(r, 4 * v, p.colors))
542 if((attrs & mesh_skin)
543 && (!detail::read_array(r, 4 * v, p.joints) || !detail::read_array(r, 4 * v, p.weights)))
547 if(!detail::read_array(r, indices, p.indices))
549 for(uint32_t i : *p.indices)
550 if(i >= p.vertex_count)
557 p.targets.resize(targets);
558 for(
auto& t : p.targets)
563 if((which & 1) && !detail::read_array(r, 3 * v, t.positions))
565 if((which & 2) && !detail::read_array(r, 3 * v, t.normals))
574inline std::optional<image_message> parse_image(std::string_view body)
577 detail::reader r{body};
578 if(!r(m.seq) || !r(m.key) || !r(m.mime_type) || r.in.empty())
580 m.bytes = std::make_shared<std::vector<uint8_t>>(
581 (
const uint8_t*)r.in.data(), (
const uint8_t*)r.in.data() + r.in.size());
585inline std::optional<native_scene_message> parse_native_scene(std::string_view body)
587 native_scene_message m;
588 detail::reader r{body};
590 if(!r(m.seq) || !r(reset))
592 m.reset = reset != 0;
593 m.json.assign(r.in.data(), r.in.size());
599template <
typename Record>
600std::optional<records_message<Record>> parse_records(std::string_view body)
602 records_message<Record> m;
603 detail::reader r{body};
605 if(!r(m.seq) || !r(count))
609 if(count > r.in.size() / Record::min_size)
612 m.records.resize(count);
613 for(
auto& rec : m.records)
621inline std::optional<transforms_message> parse_transforms(std::string_view body)
623 return parse_records<transform_record>(body);
627inline std::string encode_frame(frame_type t, std::string_view body)
630 out.reserve(5 + body.size());
631 detail::writer{out}(uint32_t(body.size() + 1));
632 out.push_back(
char(t));
638encode_scene(uint64_t seq, std::string_view glb, frame_type t = frame_type::scene)
641 detail::writer{body}(seq);
643 return encode_frame(t, body);
646inline std::string encode_mesh(
647 uint64_t seq,
const std::string& key,
const std::vector<native_primitive>& prims)
650 detail::writer w{body};
651 w(seq), w(key), w(uint16_t(prims.size()));
652 auto put = [&](
const auto& v) {
654 body.append((
const char*)v->data(), v->size() *
sizeof((*v)[0]));
656 for(
const auto& p : prims)
658 const uint8_t attrs = (p.normals ? mesh_normal : 0) | (p.texcoords ? mesh_texcoord0 : 0)
659 | (p.texcoords1 ? mesh_texcoord1 : 0) | (p.colors ? mesh_color0 : 0)
660 | (p.joints && p.weights ? mesh_skin : 0);
661 w(p.vertex_count), w(uint32_t(p.indices ? p.indices->size() : 0)), w(attrs),
662 w(uint16_t(p.targets.size()));
663 put(p.positions), put(p.normals), put(p.texcoords), put(p.texcoords1), put(p.colors);
664 if(p.joints && p.weights)
665 put(p.joints), put(p.weights);
667 for(
const auto& t : p.targets)
669 w(uint8_t((t.positions ? 1 : 0) | (t.normals ? 2 : 0)));
670 put(t.positions), put(t.normals);
673 return encode_frame(frame_type::mesh, body);
676inline std::string encode_image(
677 uint64_t seq,
const std::string& key,
const std::string& mime, std::string_view bytes)
680 detail::writer w{body};
681 w(seq), w(key), w(mime);
683 return encode_frame(frame_type::image, body);
686inline std::string encode_native_scene(uint64_t seq,
bool reset, std::string_view json)
689 detail::writer w{body};
690 w(seq), w(uint8_t(reset ? 1 : 0));
692 return encode_frame(frame_type::native_scene, body);
695template <
typename Record>
696std::string encode_records(frame_type t, uint64_t seq,
const std::vector<Record>& records)
699 detail::writer w{body};
700 w(seq), w(uint32_t(records.size()));
701 for(
const auto& rec : records)
703 return encode_frame(t, body);
707encode_transforms(uint64_t seq,
const std::vector<transform_record>& records)
709 return encode_records(frame_type::transforms, seq, records);
719 template <
typename F>
720 bool feed(std::string_view bytes, F&& on_frame)
724 m_buffer.append(bytes);
727 while(m_buffer.size() - pos >= 4)
730 std::memcpy(&len, m_buffer.data() + pos, 4);
731 if(len == 0 || len > max_frame_size)
737 if(m_buffer.size() - pos - 4 < len)
740 const auto type = frame_type(uint8_t(m_buffer[pos + 4]));
741 on_frame(type, std::string_view{m_buffer.data() + pos + 5, len - 1});
744 m_buffer.erase(0, pos);
748 bool failed()
const noexcept {
return m_failed; }
749 std::size_t buffered()
const noexcept {
return m_buffer.size(); }
752 std::string m_buffer;
753 bool m_failed{
false};
Definition Protocol.hpp:717
Definition Protocol.hpp:264
Definition Protocol.hpp:347
Definition Protocol.hpp:184
Definition Protocol.hpp:218
Definition Protocol.hpp:416
Definition Protocol.hpp:463
Definition Protocol.hpp:323
Definition Protocol.hpp:372
Definition Protocol.hpp:456
Definition Protocol.hpp:449
Definition Protocol.hpp:442
Definition Protocol.hpp:471
Definition Protocol.hpp:407
Definition Protocol.hpp:434
Definition Protocol.hpp:427
Definition Protocol.hpp:313
Definition Protocol.hpp:289
Definition MIDISync.hpp:149