1 module ft.adaptors.vmc;
2 import ft.adaptor;
3 import ft.data;
4 import osc;
5 import std.conv : to;
6 import std.socket;
7 import gl3n.linalg;
8 
9 class VMCAdaptor : Adaptor {
10 private:
11     Server server;
12     ushort port = 39540;
13     string bind = "0.0.0.0";
14 
15 public:
16 
17     override
18     void start(string[string] options = string[string].init) {
19         if ("port" in options) {
20             port = to!ushort(options["port"]);
21         }
22 
23         if ("address" in options) {
24             bind = options["address"];
25         }
26 
27         server = new Server(new InternetAddress(bind, port));
28     }
29 
30     override
31     void stop() {
32         server.close();
33         server = null;
34     }
35 
36     override
37     void poll() {
38         const(Message)[] msgs = server.popMessages();
39         foreach(const(Message) msg; msgs) {
40             if (msg.addressPattern.length < 3) continue;
41             if (msg.addressPattern[0].toString != "/VMC" && msg.addressPattern[1].toString != "/Ext") continue;
42             switch(msg.addressPattern[2].toString) {
43                 case "/Bone":
44                     if (msg.arg!string(0) !in bones) {
45                         bones[msg.arg!string(0)] = Bone(
46                             vec3.init,
47                             quat.identity
48                         );
49                     }
50 
51                     this.bones[msg.arg!string(0)].position = vec3(
52                         msg.arg!float(1),
53                         msg.arg!float(2),
54                         msg.arg!float(3)
55                     );
56                     
57                     this.bones[msg.arg!string(0)].rotation = quat(
58                         msg.arg!float(7), 
59                         msg.arg!float(4), 
60                         msg.arg!float(5), 
61                         msg.arg!float(6)
62                     );
63                     break;
64                 case "/Blend":
65                     if (msg.addressPattern[3].toString == "/Apply") break;
66                     this.blendshapes[msg.arg!string(0)] = msg.arg!float(1);
67                     break;
68                 default: break;
69             }
70         }
71     }
72 
73     override
74     string[] getOptionNames() {
75         return [
76             "port", 
77             "address"
78         ];
79     }
80 }