using System.Security.AccessControl; namespace Main; public class Mono { private static readonly Lazy lazy = new(() => new Mono()); public static Mono inst { get { return lazy.Value; } } public static readonly bool dev = Environment.CommandLine.Contains("--dev"); public MonoNet monoNet = new(); public Rig rig = new(); public Mat mat = new(); Mesh mesh_floor = Mesh.Quad; Material mat_room = new (Shader.FromFile("shaders/room.hlsl")); Model model_room = Model.FromFile("room.glb"); Mesh mesh_room = Mesh.Quad; // key:(char) value:(int[] dots) Dictionary char_cell = new Dictionary { { ' ', new int[] { 0, 0, 0, 0, 0, 0 } }, { '\n', new int[] { 1, 1, 1, 1, 1, 1 } }, { 'a', new int[] { 1, 0, 0, 0, 0, 0 } }, { 'b', new int[] { 1, 0, 1, 0, 0, 0 } }, { 'c', new int[] { 1, 1, 0, 0, 0, 0 } }, { 'd', new int[] { 1, 1, 0, 1, 0, 0 } }, { 'e', new int[] { 1, 0, 0, 1, 0, 0 } }, { 'f', new int[] { 1, 1, 1, 0, 0, 0 } }, { 'g', new int[] { 1, 1, 1, 1, 0, 0 } }, { 'h', new int[] { 1, 0, 1, 1, 0, 0 } }, { 'i', new int[] { 0, 1, 1, 0, 0, 0 } }, { 'j', new int[] { 0, 1, 1, 1, 0, 0 } }, { 'k', new int[] { 1, 0, 0, 0, 1, 0 } }, { 'l', new int[] { 1, 0, 1, 0, 1, 0 } }, { 'm', new int[] { 1, 1, 0, 0, 1, 0 } }, { 'n', new int[] { 1, 1, 0, 1, 1, 0 } }, { 'o', new int[] { 1, 0, 0, 1, 1, 0 } }, { 'p', new int[] { 1, 1, 1, 0, 1, 0 } }, { 'q', new int[] { 1, 1, 1, 1, 1, 0 } }, { 'r', new int[] { 1, 0, 1, 1, 1, 0 } }, { 's', new int[] { 0, 1, 1, 0, 1, 0 } }, { 't', new int[] { 0, 1, 1, 1, 1, 0 } }, { 'u', new int[] { 1, 0, 0, 0, 1, 1 } }, { 'v', new int[] { 1, 0, 1, 0, 1, 1 } }, { 'w', new int[] { 0, 1, 1, 1, 0, 1 } }, { 'x', new int[] { 1, 1, 0, 0, 1, 1 } }, { 'y', new int[] { 1, 1, 0, 1, 1, 1 } }, { 'z', new int[] { 1, 0, 0, 1, 1, 1 } }, { ',', new int[] { 0, 0, 1, 0, 0, 0 } }, { '.', new int[] { 0, 0, 1, 1, 0, 1 } }, { '/', new int[] { 0, 1, 0, 0, 1, 0 } }, { ';', new int[] { 0, 0, 1, 0, 1, 0 } }, }; // enum of layouts public enum Layout { Qwerty, Colemak } Dictionary layouts = new Dictionary { { Layout.Colemak, new char[] { 'q', 'w', 'f', 'p', 'g', 'j', 'l', 'u', 'y', ';', 'a', 'r', 's', 't', 'd', 'h', 'n', 'e', 'i', 'o', 'z', 'x', 'c', 'v', 'b', 'k', 'm', ',', '.', '/', } }, { Layout.Qwerty, new char[] { 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', } }, }; public char KeyToChar(int index) { return layouts[Layout.Colemak][index]; } Matrix keyboard_m4 = Matrix.Identity; Rig.Btn keyboard_btn = new(); Vec3 index_pos = Vec3.Zero; int index_i = 0; int last_index_i = 0; string txt = "hello "; public void Init() { rig.Init(); mat.Init(); mesh_floor = Mesh.GenerateCircle(1, 64); mat_room.SetTexture("diffuse", Tex.FromFile("bake.png")); mesh_room = model_room.Nodes.First(n => n.Name == "Room").Mesh; keyboard_btn.held = true; } public void Run() { rig.Run(); keyboard_m4 = Matrix.TRS( V.XYZ(-0.18f, 1.15f, -0.5f), Quat.FromAngles(0, 180, 0) * Quat.FromAngles(40, 0, 0), V.XYZ(-1, -1, 1) * 0.04f ); // thumb extension // Matrix palm_ori = rig.hand_1.palm.ToMatrix(); // Vec3 thumb_tip = palm_ori.Inverse * rig.hand_1.Get(FingerId.Thumb, JointId.Tip).position; // Vec3 thumb_minor = palm_ori.Inverse * rig.hand_1.Get(FingerId.Thumb, JointId.KnuckleMinor).position; // if (thumb_tip.x < thumb_minor.x - 0f * U.cm) { // // Log.Info("thumb is out"); // xi = 0; // } for (int i = 0; i < keb_keys.Length-1; i++) { if (Input.Key(keb_keys[i].key).IsJustActive()) { txt += keb_keys[i].char_; monoNet.value = keb_keys[i].char_; monoNet.send = true; } } Vec3 index_tip = keyboard_m4.Inverse * rig.hand_1.Get(FingerId.Index, JointId.Tip).position; // press index_pos.z = Math.Clamp(index_tip.z, -0.3f, 0.1f); keyboard_btn.Frame(index_pos.z > 0.0f, index_pos.z < -0.2f); if (!keyboard_btn.held) { // snap to grid index_pos.x = (float)Math.Clamp(Math.Round(index_tip.x), 0, 10-1); index_pos.y = (float)Math.Clamp(Math.Round(index_tip.y), 0, 3-1); index_i = (int)(index_pos.y * 10 + index_pos.x); if (index_i != last_index_i) { last_index_i = index_i; // Log.Info($"index_i: {index_i}"); monoNet.value = KeyToChar(index_i); monoNet.send = true; } } if (keyboard_btn.frameDown) { // send haptic input for input confirmation txt += KeyToChar(index_i); } // RENDER RENDER RENDER // keyboard Hierarchy.Push(keyboard_m4); // 3 rows of 10 keys for (int y = 0; y < 3; y++) { for (int x = 0; x < 10; x++) { Vec3 pos = V.XYZ(x, y, 0); // background quad Mesh.Quad.Draw( mat.unlit_clear, Matrix.TS(pos, 0.9f), Color.Hex(0x00000040) ); int index = y * 10 + x; char keychar = KeyToChar(index); Text.Add( keychar.ToString(), Matrix.TS( pos + V.XYZ(-0.3f, -0.3f, 0), V.XYZ(-1, -1, 0) * 8.0f ), TextAlign.Center, TextAlign.Center, 0, 0, 0 ); // show the braille dots(spheres) above the text for (int k = 0; k < 6; k++) { float spacing = 0.2f; float x_offset = (k % 2) * spacing; float y_offset = (k / 2) * -spacing; if (char_cell[keychar][k] == 1) { Mesh.Sphere.Draw( mat.unlit_clear, Matrix.TS( V.XYZ(pos.x + x_offset, pos.y - y_offset, 0) + V.XYZ(-0.1f, -0.18f, 0), 0.1f ), Color.Hex(0xFFFFFFFF) ); } } } } Hierarchy.Pop(); // keyboard button Mesh.Cube.Draw( mat.unlit_clear, Matrix.TS( index_pos * V.XYZ(1, 1, 0.25f), V.XYZ(0.8f, 0.8f, -index_pos.z * 0.5f) ) * keyboard_m4, keyboard_btn.held ? Color.Hex(0x00000090) : Color.Hex(0x80808090) ); // text // show over the keyboard Text.Add( txt, Matrix.TS( V.XYZ(0, -1, 0), V.XYZ(-1, -1, 0) * 20.0f ) * keyboard_m4, TextAlign.CenterLeft, TextAlign.CenterLeft, 0, 0, 0 ); // WORLD mesh_room.Draw( mat_room, Matrix.T(V.XYZ(0, 0, 0)) ); mesh_floor.Draw( mat.unlit, Matrix.TS( V.XYZ(0, 0, 0), 1*U.cm ), Color.Hex(0x666666FF) ); Vec3[] offsets = new Vec3[] { V.XYZ(-2, -2f, -2f) * U.cm, V.XYZ(2, 2f, 2f) * U.cm, V.XYZ(0, 0, 0) }; mat.Run(); } KebKey[] keb_keys = new KebKey[] { new() { key = Key.Space, char_ = ' ' }, new() { key = Key.Return, char_ = '\n' }, new() { key = Key.A, char_ = 'a' }, new() { key = Key.B, char_ = 'b' }, new() { key = Key.C, char_ = 'c' }, new() { key = Key.D, char_ = 'd' }, new() { key = Key.E, char_ = 'e' }, new() { key = Key.F, char_ = 'f' }, new() { key = Key.G, char_ = 'g' }, new() { key = Key.H, char_ = 'h' }, new() { key = Key.I, char_ = 'i' }, new() { key = Key.J, char_ = 'j' }, new() { key = Key.K, char_ = 'k' }, new() { key = Key.L, char_ = 'l' }, new() { key = Key.M, char_ = 'm' }, new() { key = Key.N, char_ = 'n' }, new() { key = Key.O, char_ = 'o' }, new() { key = Key.P, char_ = 'p' }, new() { key = Key.Q, char_ = 'q' }, new() { key = Key.R, char_ = 'r' }, new() { key = Key.S, char_ = 's' }, new() { key = Key.T, char_ = 't' }, new() { key = Key.U, char_ = 'u' }, new() { key = Key.V, char_ = 'v' }, new() { key = Key.W, char_ = 'w' }, new() { key = Key.X, char_ = 'x' }, new() { key = Key.Y, char_ = 'y' }, new() { key = Key.Z, char_ = 'z' }, }; public struct KebKey { public Key key; public char char_; } }