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 }