Loading...
Searching...
No Matches
Server.hpp
1#pragma once
2#include <Threedim/LiveLink/Protocol.hpp>
3
4#include <cstdint>
5#include <memory>
6#include <optional>
7#include <string>
8#include <string_view>
9#include <unordered_map>
10#include <vector>
11
12namespace Threedim::LiveLink
13{
14
15// A bone of an armature; bone names are only unique within their armature.
17{
18 std::string armature;
20};
21
22template <typename Record>
23struct stamped
24{
25 uint64_t seq{};
26 Record record;
27};
28
29// Newest record of each key (a node, material or bone name).
30template <typename Record>
31using latest = std::unordered_map<std::string, stamped<Record>>;
32
33// A patch, a removal, or a native frame: changes to the scene's structure,
34// which, unlike values, must all be applied, in order.
36{
37 uint64_t seq{};
38 frame_type type{frame_type::patch};
39 std::string glb; // patch
40 std::vector<std::string> names; // remove
41 std::optional<mesh_message> mesh; // mesh
42 std::vector<std::shared_ptr<std::vector<float>>> tangents; // per primitive
43 std::optional<image_message> image; // image
44 std::optional<native_scene_message> scene; // native_scene
45
46 // A native scene with reset replaces the scene, as a scene frame does.
47 bool is_reset() const noexcept { return scene && scene->reset; }
48 // Kept by key, not shown: older ones are not made obsolete by a reset.
49 bool is_resource() const noexcept { return mesh || image; }
50};
51
52// Mesh primitives get the tangents the renderer's normal mapping needs, as
53// GltfParser gives meshes that have none (Threedim/TangentUtils.hpp).
54// One per primitive of `m`, null where it lacks normals or texcoords.
55std::vector<std::shared_ptr<std::vector<float>>> generate_tangents(const mesh_message& m);
56
57// What arrived since the last take(), coalesced: only the newest scene, and
58// only the newest record of each kind for each node, bone or material,
59// survive. The receiving node may tick far slower than the sender sends (or
60// not at all while nothing is rendered), and a stale intermediate value is of
61// no use to it. Structural messages are kept in order, except those older
62// than the newest scene, which contains them.
63struct inbox
64{
65 std::optional<scene_message> scene;
66 std::vector<structural_message> structural;
67 latest<environment_record> environment;
68 latest<node_name_record> active_camera;
69 latest<transform_record> transforms;
70 latest<joint_record> joints;
71 latest<weights_record> weights;
72 latest<visibility_record> visibility;
73 latest<light_record> lights;
74 latest<camera_record> cameras;
75 latest<material_record> materials;
76
77 // The sender's hello, as received (JSON); empty until one arrives.
78 std::string peer_hello;
79
80 // Bumped on every connection and disconnection, so the node can notice a
81 // DCC that came back without polling the socket state.
82 int64_t connection_events{};
83 bool connected{};
84
85 bool empty() const noexcept
86 {
87 return !scene && structural.empty() && environment.empty() && active_camera.empty()
88 && transforms.empty()
89 && joints.empty() && weights.empty() && visibility.empty() && lights.empty()
90 && cameras.empty() && materials.empty();
91 }
92};
93
94// Key of a joint in inbox::joints and wherever bones are looked up by name.
95inline std::string joint_key(std::string_view armature, std::string_view bone)
96{
97 std::string k;
98 k.reserve(armature.size() + 1 + bone.size());
99 k.append(armature);
100 k.push_back('\0');
101 k.append(bone);
102 return k;
103}
104
105// TCP listener for the live link, running its own network thread. The
106// newest connection is the one that is read from: a DCC that reconnects
107// replaces its own stale session instead of interleaving with it.
108//
109// Construction binds and listens, and throws (std::exception) when the
110// address cannot be bound, e.g. a port already in use. Destruction stops the
111// thread and closes every socket; it blocks until the thread has exited.
113{
114public:
115 server(const std::string& bind_address, uint16_t port);
116 ~server();
117 server(const server&) = delete;
118 server& operator=(const server&) = delete;
119
120 // Thread-safe. Moves out everything received so far.
121 inbox take();
122
123 uint16_t port() const noexcept;
124
125private:
126 struct impl;
127 std::unique_ptr<impl> m;
128};
129
130}
Definition TinyObj.hpp:27