1 /*
2     Copyright © 2020, Inochi2D Project
3     Distributed under the 2-Clause BSD License, see LICENSE file.
4     
5     Authors: Luna Nielsen
6 */
7 module creator.panels.tracking;
8 import creator.core;
9 import creator.viewport.test;
10 import creator.panels;
11 import creator.windows;
12 import creator.widgets;
13 import creator;
14 import bindbc.imgui;
15 import inochi2d;
16 import std.conv;
17 import i18n;
18 import std.string;
19 
20 /**
21     The textures frame
22 */
23 class TrackingPanel : Panel {
24 private:
25     string[string] optionValues;
26 
27     bool trackingModeCheckbox(string receiverName, string tooltip, TrackingMode mode) {
28         bool track = incTestGetTrackingMode() == mode;
29 
30         // Appended to the name of a face tracking receiver
31         // in the Tracking settings panel
32         const(char)* recvName = _("%s Receiver").format(receiverName).toStringz;
33 
34         if (igCheckbox(recvName, &track)) {
35             incTestSetTrackingMode(track ? mode : TrackingMode.None);
36             incTestRestartTracker();
37         }
38         incTooltip(tooltip);
39         return track;
40     }
41 
42     bool canParseAddr(string addr) {
43         import std.socket : parseAddress;
44         try {
45             parseAddress(addr);
46             return true;
47         } catch (Exception ex) {
48             return false;
49         }
50     }
51 
52 protected:
53     override
54     debug(InExperimental)
55     void onUpdate() {
56 
57         if (incEditMode == EditMode.ModelTest) {
58             ImVec2 avail = incAvailableSpace();
59 
60             if (trackingModeCheckbox("VMC", _("A reciever which uses your phone and associated app to track your body"), TrackingMode.VMC)) {
61                 auto adaptorOptions = incTestGetAdaptorOptions();
62 
63                 string bindingIP = incSettingsGet("vmc_bind_ip", "0.0.0.0");
64                 if (incInputText(_("Bind Address"), avail.x/2, bindingIP, ImGuiInputTextFlags.None)) {
65                     incSettingsSet("vmc_bind_ip", bindingIP);
66 
67                     if (this.canParseAddr(bindingIP)) {
68                         incSettingsSave();
69                         adaptorOptions["address"] = bindingIP;
70                         incTestRestartTracker();
71                     }
72                 }
73                 incTooltip(_("The IP address that the VMC binding server should listen on, default 0.0.0.0"));
74 
75                 int bindingPort = incSettingsGet("vmc_bind_port", 39540);
76                 if (igInputInt(__("Port"), &bindingPort)) {
77                     incSettingsSet("vmc_bind_port", bindingPort);
78 
79                     if (bindingPort > 1 && bindingPort < ushort.max) {
80                         incSettingsSave();
81                         optionValues["port"] = bindingPort.text;
82                         incTestRestartTracker();
83                     }
84                 }
85                 incTooltip(_("The port that the VMC binding server should listen on, default 39540"));
86             }
87 
88             if (trackingModeCheckbox("VTube Studio", _("A reciever which uses the VTubeStudio iOS app"), TrackingMode.VTS)) {
89                 
90                 string bindingIP = incSettingsGet!string("vts_phone_ip");
91                 if (incInputText("iPhoneIP", _("iPhone IP"), avail.x/2, bindingIP, ImGuiInputTextFlags.None)) {
92                     incSettingsSet("vts_phone_ip", bindingIP);
93 
94                     if (this.canParseAddr(bindingIP)) {
95                         incSettingsSave();
96                         optionValues["phoneIP"] = bindingIP;
97                         incTestRestartTracker();
98                     }
99                 }
100                 incTooltip(_("The IP Address of your iPhone,\nYou can find it in the VSeeFace Config panel in VTube Studio"));
101             }
102 
103             if (trackingModeCheckbox("OpenSeeFace", _("A receiver which uses OpenSeeFace application"), TrackingMode.OSF)) {
104                 string bindingIP = incSettingsGet("osf_bind_ip", "0.0.0.0");
105                 if (incInputText("osfBindAddress", _("OSF Bind Address"), avail.x/2, bindingIP, ImGuiInputTextFlags.None)) {
106                     incSettingsSet("osf_bind_ip", bindingIP);
107 
108                     if (this.canParseAddr(bindingIP)) {
109                         incSettingsSave();
110                         optionValues["osf_bind_ip"] = bindingIP;
111                         incTestRestartTracker();
112                     }
113                 }
114 
115                 int bindingPort = incSettingsGet("osf_bind_port", 11573);
116                 if (igInputInt(__("OSF Listen Port"), &bindingPort)) {
117                     incSettingsSet("osf_bind_port", bindingPort);
118 
119                     if (bindingPort > 1 && bindingPort < ushort.max) {
120                         incSettingsSave();
121                         optionValues["osf_bind_port"] = bindingPort.text;
122                         incTestRestartTracker();
123                     }
124                 }
125             }
126 
127 
128             if (igCollapsingHeader(__("Tracking Bindings"), ImGuiTreeNodeFlags.DefaultOpen)) {
129                 if (igBeginListBox("###BINDINGS")) {
130                     foreach(i, binding; incTestGetTrackingBindings()) {
131                         igPushID(cast(int)i);
132 
133                             const(char)* nm = _("%s bound to %s").format(binding.key, binding.param.name).toStringz;
134                             if (igSelectable(nm)) {
135                                 incTestRemoveTrackingBinding(binding);
136                             }
137 
138                         igPopID();
139                     }
140                     igEndListBox();
141                 }
142 
143                 if (igButton("", ImVec2(0, 32))) {
144                     incPushWindowList(new TrackingBindingWindow(incViewportTestGetCurrBindable()));
145                 }
146             }
147         } else {
148             incLabelOver(_("Not in Test Mode..."), ImVec2(0, 0), true);
149         }
150     }
151 
152 public:
153     this() {
154         super("Tracking", _("Tracking"), false);
155     }
156 }
157 
158 /**
159     Generate tracking panel frame
160 */
161 debug(InExperimental) mixin incPanel!TrackingPanel;
162 
163