diff --git a/MonoNet.cs b/MonoNet.cs index 7697e3e..93ff017 100644 --- a/MonoNet.cs +++ b/MonoNet.cs @@ -6,53 +6,50 @@ using System.Threading; using System.Threading.Tasks; public class MonoNet { - public MonoNet() { + public Mono mono; + public MonoNet(Mono mono) { + this.mono = mono; Random rnd = new Random(); me = new Peer(rnd.Next(1, 256)); // temp, until unique usernames } public Socket socket; - byte[] data; - int head; + int bufferSize = 1024; + byte[] rData; int rHead; + byte[] wData; int wHead; public Peer me; public Peer[] peers; - public async void Start() { - string publicIP, localIP; - // GetIPs(); - void GetIPs() - { - using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0)) - { - socket.Connect("8.8.8.8", 65530); - IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint; - localIP = endPoint.Address.ToString(); - } - // Console.WriteLine("Your local IP is: " + localIP); - publicIP = new WebClient().DownloadString("https://ipv4.icanhazip.com/").TrimEnd(); - // Console.WriteLine("Your IP is: " + publicIP); - } - + public void Start() { socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); string ip = "192.168.1.70"; // ip = "139.177.201.219"; EndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(ip), 1234); socket.Connect(serverEndPoint); - data = new byte[1024]; + rData = new byte[bufferSize]; + wData = new byte[bufferSize]; peers = new Peer[64]; Thread.Sleep(1000); // useful? + Thread readThread = new Thread(Read); + readThread.Start(); + Thread writeThread = new Thread(Write); + writeThread.Start(); + + // socket.Close(); + } + + void Read() { bool running = true; while (running) { while (socket.Available > 0) { - try {socket.Receive(data, 0, data.Length, SocketFlags.None);} - catch (Exception e) { + try { socket.Receive(rData, 0, bufferSize, SocketFlags.None); } catch (Exception e) { Console.WriteLine($"can't connect to the server: {e}"); return; } - - head = 0; + + rHead = 0; int id = ReadInt(); if (id != 0) { int index = -1; @@ -72,66 +69,88 @@ public class MonoNet { Console.WriteLine("too many peers"); return; } - peers[index].cursor = ReadVec3(); + peers[index].cursorA = ReadVec3(); + peers[index].cursorB = ReadVec3(); + peers[index].cursorC = ReadVec3(); + peers[index].cursorD = ReadVec3(); peers[index].headset = ReadPose(); peers[index].offHand = ReadPose(); peers[index].mainHand = ReadPose(); } } + } + } - data = new byte[1024]; - head = 0; + void Write() { + bool running = true; + while (running) { + wHead = 0; WriteInt(me.id); - WriteVec3(me.cursor); + WriteVec3(me.cursorA); + WriteVec3(me.cursorB); + WriteVec3(me.cursorC); + WriteVec3(me.cursorD); WritePose(me.headset); WritePose(me.offHand); WritePose(me.mainHand); - socket.Send(data); + socket.Send(wData); - await Task.Delay(1); + Thread.Sleep(60); } - socket.Close(); } int ReadInt() { - int value = BitConverter.ToInt32(data, head); - head += 4; + int value = BitConverter.ToInt32(rData, rHead); + rHead += 4; return value; - } void WriteInt(int value) { - BitConverter.GetBytes(value).CopyTo(data, head); - head += 4; + } + void WriteInt(int value) { + BitConverter.GetBytes(value).CopyTo(wData, wHead); + wHead += 4; + } + + float ReadFloat() { + float value = BitConverter.ToSingle(rData, rHead); + rHead += 4; + return value; + } + void WriteFloat(float value) { + BitConverter.GetBytes(value).CopyTo(wData, wHead); + wHead += 4; } Vec3 ReadVec3() { Vec3 value = new Vec3( - BitConverter.ToSingle(data, head), - BitConverter.ToSingle(data, head + 4), - BitConverter.ToSingle(data, head + 8) + BitConverter.ToSingle(rData, rHead), + BitConverter.ToSingle(rData, rHead + 4), + BitConverter.ToSingle(rData, rHead + 8) ); - head += 12; + rHead += 12; return value; - } void WriteVec3(Vec3 vec) { - BitConverter.GetBytes(vec.x).CopyTo(data, head); - BitConverter.GetBytes(vec.y).CopyTo(data, head + 4); - BitConverter.GetBytes(vec.z).CopyTo(data, head + 8); - head += 12; + } + void WriteVec3(Vec3 vec) { + BitConverter.GetBytes(vec.x).CopyTo(wData, wHead); + BitConverter.GetBytes(vec.y).CopyTo(wData, wHead + 4); + BitConverter.GetBytes(vec.z).CopyTo(wData, wHead + 8); + wHead += 12; } Quat ReadQuat() { Quat value = new Quat( - BitConverter.ToSingle(data, head), - BitConverter.ToSingle(data, head + 4), - BitConverter.ToSingle(data, head + 8), - BitConverter.ToSingle(data, head + 12) + BitConverter.ToSingle(rData, rHead), + BitConverter.ToSingle(rData, rHead + 4), + BitConverter.ToSingle(rData, rHead + 8), + BitConverter.ToSingle(rData, rHead + 12) ); - head += 16; + rHead += 16; return value; - } void WriteQuat(Quat quat) { - BitConverter.GetBytes(quat.x).CopyTo(data, head); - BitConverter.GetBytes(quat.y).CopyTo(data, head + 4); - BitConverter.GetBytes(quat.z).CopyTo(data, head + 8); - BitConverter.GetBytes(quat.w).CopyTo(data, head + 12); - head += 16; + } + void WriteQuat(Quat quat) { + BitConverter.GetBytes(quat.x).CopyTo(wData, wHead); + BitConverter.GetBytes(quat.y).CopyTo(wData, wHead + 4); + BitConverter.GetBytes(quat.z).CopyTo(wData, wHead + 8); + BitConverter.GetBytes(quat.w).CopyTo(wData, wHead + 12); + wHead += 16; } Pose ReadPose() { @@ -139,27 +158,42 @@ public class MonoNet { ReadVec3(), ReadQuat() ); - } void WritePose(Pose pose) { + } + void WritePose(Pose pose) { WriteVec3(pose.position); WriteQuat(pose.orientation); } + string localIP, publicIP; + void GetIPs() { + using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0)) { + socket.Connect("8.8.8.8", 65530); + IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint; + localIP = endPoint.Address.ToString(); + } + publicIP = new WebClient().DownloadString("https://ipv4.icanhazip.com/").TrimEnd(); + } + Mesh meshCube = Default.MeshCube; Material matCube = Default.Material; public void Cubee(Matrix m) { meshCube.Draw(matCube, m); } - public class Peer - { + public class Peer { public int id; - public Vec3 cursor; + public Vec3 cursorA, cursorB, cursorC, cursorD; public Pose headset; public Pose offHand; public Pose mainHand; + public Sound voice; + public SoundInst voiceInst; // update position public Peer(int id) { this.id = id; + + // voice = Sound.CreateStream(0.5f); + // voiceInst = voice.Play(Vec3.Zero, 0.5f); } } } diff --git a/Program.cs b/Program.cs index 1c9e6c5..3509e50 100644 --- a/Program.cs +++ b/Program.cs @@ -2,64 +2,73 @@ using StereoKit; using System; class Program { - static void Main(string[] args) { + static void Main(string[] args) { SKSettings settings = new SKSettings { appName = "oriels", assetsFolder = "Assets", }; - if (!SK.Initialize(settings)) + if (!SK.Initialize(settings)) Environment.Exit(1); // TextStyle style = Text.MakeStyle(Font.FromFile("DMMono-Regular.ttf"), 0.1f, Color.White); - Mono.Run(); - } + Mono mono = new Mono(); + mono.Run(); + } } -public static class Mono { +public class Mono { + public Mic mic; + public Controller offHand, mainHand; - public static Controller offHand, mainHand; + public void Run() { + // mic = new Mic(); - public static void Run() { - MonoNet net = new MonoNet(); + MonoNet net = new MonoNet(this); net.Start(); + // StretchCursor stretchCursor = new StretchCursor(); + CubicFlow cubicFlow = new CubicFlow(); + // ReachCursor reachCursor = new ReachCursor(); + // SupineCursor supineCursor = new SupineCursor(); + // ClawCursor clawCursor = new ClawCursor(); + + Oriel oriel = new Oriel(); + oriel.Start(); + // ColorCube cube = new ColorCube(); // OrbitalView.strength = 4; // OrbitalView.distance = 0.4f; // cube.thickness = 0.01f; - StretchCursor stretchCursor = new StretchCursor(); - // ReachCursor reachCursor = new ReachCursor(); - // SupineCursor supineCursor = new SupineCursor(); - // ClawCursor clawCursor = new ClawCursor(); - - // Oriel oriel = new Oriel(); - // oriel.Start(); - // Lerper lerper = new Lerper(); while (SK.Step(() => { offHand = Input.Controller(Handed.Left); mainHand = Input.Controller(Handed.Right); - // mainHand.aim = Input.Hand(Handed.Right).palm; - - stretchCursor.Step(offHand.aim, mainHand.aim); - net.me.cursor = stretchCursor.pos; - // net.me.cursor = Vec3.Up * (float)Math.Sin(Time.Total); + cubicFlow.Step(offHand.aim, mainHand.aim); + cubicFlow.DrawSelf(); + net.me.cursorA = cubicFlow.p0; + net.me.cursorB = cubicFlow.p1; + net.me.cursorC = cubicFlow.p2; + net.me.cursorD = cubicFlow.p3; + // net.me.cursorA = Vec3.Up * (float)Math.Sin(Time.Total); net.me.headset = Input.Head; net.me.offHand = offHand.aim; net.me.mainHand = mainHand.aim; for (int i = 0; i < net.peers.Length; i++) { MonoNet.Peer peer = net.peers[i]; if (peer != null) { - net.Cubee(Matrix.TRS(peer.cursor, Quat.Identity, Vec3.One * 0.05f)); + net.Cubee(Matrix.TRS(peer.cursorA, Quat.Identity, Vec3.One * 0.05f)); net.Cubee(peer.headset.ToMatrix(Vec3.One * 0.3f)); net.Cubee(peer.offHand.ToMatrix(Vec3.One * 0.1f)); net.Cubee(peer.mainHand.ToMatrix(Vec3.One * 0.1f)); + cubicFlow.Draw(peer.cursorA, peer.cursorB, peer.cursorC, peer.cursorD); } - } + } + + oriel.Step(); // domHand subHand ?? :3 @@ -85,49 +94,161 @@ public static class Mono { // new Pose(mainHand.aim.position, mainHand.aim.orientation), // mainHand.IsStickClicked // ); - - // oriel.Step(); // cursor.Draw(Matrix.S(0.1f)); - })); + })) ; SK.Shutdown(); } } -public class DrawKey { - public int x, y; - public Key key; - public DrawKey(int x, int y, Key key) { - this.x = x; - this.y = y; - this.key = key; +public class Mic { + public float[] bufferRaw = new float[0]; + public int bufferRawSize = 0; + + public int comp = 8; + public float[] buffer = new float[0]; + public int bufferSize = 0; + + FilterButterworth filter; + public void Step() { + if (Microphone.IsRecording) { + // Ensure our buffer of samples is large enough to contain all the + // data the mic has ready for us this frame + if (Microphone.Sound.UnreadSamples > bufferRaw.Length) { + bufferRaw = new float[Microphone.Sound.UnreadSamples]; + buffer = new float[Microphone.Sound.UnreadSamples / comp]; + } + + // Read data from the microphone stream into our buffer, and track + // how much was actually read. Since the mic data collection runs in + // a separate thread, this will often be a little inconsistent. Some + // frames will have nothing ready, and others may have a lot! + bufferRawSize = Microphone.Sound.ReadSamples(ref bufferRaw); + bufferSize = bufferRawSize / comp; + + if (bufferSize > 0) { + // LowPassFilter lowpass = new LowPassFilter(48000 / comp / 2, 2, 48000); + for (int i = 0; i < bufferRawSize; i++) { + // bufferRaw[i] = (float)lowpass.compute(bufferRaw[i]); + filter.Update(bufferRaw[i]); + bufferRaw[i] = filter.Value; + } + // voice.WriteSamples(bufferRaw); + + buffer[0] = bufferRaw[0]; + for (int i = 1; i < bufferSize; i++) { + buffer[i] = bufferRaw[i * comp - 1]; + } + + // upsample + float[] upsampled = new float[bufferSize * comp]; + for (int i = 0; i < bufferSize - 1; i++) { + upsampled[Math.Max(i * comp - 1, 0)] = buffer[i]; + for (int j = 1; j < comp; j++) { + upsampled[i * comp - 1 + j] = SKMath.Lerp(buffer[i], buffer[i + 1], (float)j / (float)comp); + } + } + voice.WriteSamples(upsampled); + } + } else { + Microphone.Start(); + voice = Sound.CreateStream(0.5f); + voiceInst = voice.Play(Vec3.Zero, 0.5f); + filter = new FilterButterworth(48000 / comp / 2, 48000, FilterButterworth.PassType.Lowpass, (float)Math.Sqrt(2)); + } } + public Sound voice; + public SoundInst voiceInst; // update position + + public class FilterButterworth { + /// + /// rez amount, from sqrt(2) to ~ 0.1 + /// + private readonly float resonance; + + private readonly float frequency; + private readonly int sampleRate; + private readonly PassType passType; + + private readonly float c, a1, a2, a3, b1, b2; + + /// + /// Array of input values, latest are in front + /// + private float[] inputHistory = new float[2]; + + /// + /// Array of output values, latest are in front + /// + private float[] outputHistory = new float[3]; + + public FilterButterworth(float frequency, int sampleRate, PassType passType, float resonance) { + this.resonance = resonance; + this.frequency = frequency; + this.sampleRate = sampleRate; + this.passType = passType; + + switch (passType) { + case PassType.Lowpass: + c = 1.0f / (float)Math.Tan(Math.PI * frequency / sampleRate); + a1 = 1.0f / (1.0f + resonance * c + c * c); + a2 = 2f * a1; + a3 = a1; + b1 = 2.0f * (1.0f - c * c) * a1; + b2 = (1.0f - resonance * c + c * c) * a1; + break; + case PassType.Highpass: + c = (float)Math.Tan(Math.PI * frequency / sampleRate); + a1 = 1.0f / (1.0f + resonance * c + c * c); + a2 = -2f * a1; + a3 = a1; + b1 = 2.0f * (c * c - 1.0f) * a1; + b2 = (1.0f - resonance * c + c * c) * a1; + break; + } + } + + public enum PassType { + Highpass, + Lowpass, + } + + public void Update(float newInput) { + float newOutput = a1 * newInput + a2 * this.inputHistory[0] + a3 * this.inputHistory[1] - b1 * this.outputHistory[0] - b2 * this.outputHistory[1]; + + this.inputHistory[1] = this.inputHistory[0]; + this.inputHistory[0] = newInput; + + this.outputHistory[2] = this.outputHistory[1]; + this.outputHistory[1] = this.outputHistory[0]; + this.outputHistory[0] = newOutput; + } + + public float Value { + get { return this.outputHistory[0]; } + } + } + } -public class Lerper -{ +public class Lerper { public float t = 0; public float spring = 1; public float dampen = 1; float vel; - public void Step(float to = 1, bool bounce = false) - { + public void Step(float to = 1, bool bounce = false) { float dir = to - t; vel += dir * spring * Time.Elapsedf; - if (Math.Sign(vel) != Math.Sign(dir)) - { + if (Math.Sign(vel) != Math.Sign(dir)) { vel *= 1 - (dampen * Time.Elapsedf); - } - else - { + } else { vel *= 1 - (dampen * 0.33f * Time.Elapsedf); } float newt = t + vel * Time.Elapsedf; - if (bounce && (newt < 0 || newt > 1)) - { + if (bounce && (newt < 0 || newt > 1)) { vel *= -0.5f; newt = Math.Clamp(newt, 0, 1); } @@ -135,47 +256,54 @@ public class Lerper t = newt; } - public void Reset() - { + public void Reset() { t = vel = 0; } } - public class Oriel { public Bounds bounds; - - // render - // Model model = Model.FromFile("oriel.glb", Shader.FromFile("oriel.hlsl")); Material mat = new Material(Shader.FromFile("oriel.hlsl")); Mesh mesh = Default.MeshCube; + Mesh quad = Default.MeshQuad; Vec3 _dimensions; public void Start() { bounds = new Bounds(Vec3.Zero, new Vec3(1f, 0.5f, 0.5f)); _dimensions = bounds.dimensions; } - + public void Step() { // circle around center // bounds.center = Quat.FromAngles(0, 0, Time.Totalf * 60) * Vec3.Up * 0.3f; - - // bounds.dimensions = _dimensions * (1f + (MathF.Sin(Time.Totalf * 3) * 0.3f)); - + mat.Transparency = Transparency.Blend; - // mat.FaceCull = Cull.Front; mat.SetFloat("_height", bounds.dimensions.y); mat.SetFloat("_ypos", bounds.center.y); + // mat.FaceCull = Cull.None; mesh.Draw(mat, Matrix.TRS(bounds.center, Quat.Identity, bounds.dimensions)); + Pose head = Input.Head; + Vec3 quadPos = head.position + head.Forward * 0.04f; + if (bounds.Contains(head.position, quadPos)) { + quad.Draw(mat, Matrix.TRS(quadPos, Quat.LookAt(quadPos, head.position), Vec3.One * 0.5f)); + } } } public class Bitting { - - Tex tex = new Tex(TexType.Image, TexFormat.Rgba32); + public class DrawKey { + public int x, y; + public Key key; + public DrawKey(int x, int y, Key key) { + this.x = x; + this.y = y; + this.key = key; + } + } + Tex tex = new Tex(TexType.Image, TexFormat.Rgba32); Material material = Default.Material; Mesh quad = Default.MeshQuad; - int [,] bitchar = new int[,] { + int[,] bitchar = new int[,] { {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, @@ -202,7 +330,7 @@ public class Bitting { lastKey = null; } - for (int i = 0; i < drawKeys.Length; i++){ + for (int i = 0; i < drawKeys.Length; i++) { DrawKey drawKey = drawKeys[i]; if (Input.Key(drawKey.key).IsJustActive()) { bitchar[drawKey.x, drawKey.y] = 1; @@ -252,9 +380,9 @@ public static class PullRequest { Vec3 ds = b.dimensions; for (int i = 0; i < 4; i++) { Quat q = Quat.FromAngles(i * 90, 0, 0); - Lines.Add(q * (new Vec3(0, 0, 0) - c) * ds, q * (new Vec3(0, 1, 0) - c) * ds, color, color, thickness); - Lines.Add(q * (new Vec3(0, 1, 0) - c) * ds, q * (new Vec3(1, 1, 0) - c) * ds, color, color, thickness); - Lines.Add(q * (new Vec3(1, 1, 0) - c) * ds, q * (new Vec3(1, 0, 0) - c) * ds, color, color, thickness); + Lines.Add(q * (new Vec3(0, 0, 0) - c) * ds, q * (new Vec3(0, 1, 0) - c) * ds, color, color, thickness); + Lines.Add(q * (new Vec3(0, 1, 0) - c) * ds, q * (new Vec3(1, 1, 0) - c) * ds, color, color, thickness); + Lines.Add(q * (new Vec3(1, 1, 0) - c) * ds, q * (new Vec3(1, 0, 0) - c) * ds, color, color, thickness); // convert to linepoints } diff --git a/SpatialCursor.cs b/SpatialCursor.cs index 72d86b1..56b1ae3 100644 --- a/SpatialCursor.cs +++ b/SpatialCursor.cs @@ -37,12 +37,46 @@ public class ReachCursor : SpatialCursor { } public class TwistCursor : SpatialCursor { - public void Step(Vec3 mainPos, Quat mainQuat) { + public void Step(Vec3 mainPos, Quat mainQuat, float str = 1) { Quat rel = Quat.LookAt(Vec3.Zero, mainQuat * Vec3.Forward); float twist = (Vec3.Dot(rel * -Vec3.Right, mainQuat * Vec3.Up) + 1) / 2; - pos = mainPos + mainQuat * Vec3.Forward * twist; + pos = mainPos + mainQuat * Vec3.Forward * twist * str; - model.Draw(Matrix.TS(pos, 0.06f)); + model.Draw(Matrix.TS(pos, 0.02f)); + } +} + +public class CubicFlow { + public Vec3 p0, p1, p2, p3; + public TwistCursor offTwist = new TwistCursor(); + public TwistCursor mainTwist = new TwistCursor(); + public void Step(Pose offPose, Pose mainPose) { + offTwist.Step(offPose.position, offPose.orientation, 3); + mainTwist.Step(mainPose.position, mainPose.orientation, 3); + + p0 = offPose.position; + p1 = offTwist.pos; + p2 = mainTwist.pos; + p3 = mainPose.position; + + // if toggle + } + + public void DrawSelf() { + Draw(this.p0, this.p1, this.p2, this.p3); + } + + LinePoint[] bezier = new LinePoint[64]; + public void Draw(Vec3 p0, Vec3 p1, Vec3 p2, Vec3 p3) { + for (int i = 0; i < bezier.Length; i++) { + float t = i / ((float)bezier.Length - 1); + Vec3 a = Vec3.Lerp(p0, p1, t); + Vec3 b = Vec3.Lerp(p1, p2, t); + Vec3 c = Vec3.Lerp(p2, p3, t); + Vec3 pos = Vec3.Lerp(Vec3.Lerp(a, b, t), Vec3.Lerp(b, c, t), t); + bezier[i] = new LinePoint(pos, Color.White, 0.01f); + } + Lines.Add(bezier); } } diff --git a/omnisharp.json b/omnisharp.json new file mode 100644 index 0000000..5ba78f8 --- /dev/null +++ b/omnisharp.json @@ -0,0 +1,16 @@ +{ + "FormattingOptions": { + "NewLinesForBracesInLambdaExpressionBody": false, + "NewLinesForBracesInAnonymousMethods": false, + "NewLinesForBracesInAnonymousTypes": false, + "NewLinesForBracesInControlBlocks": false, + "NewLinesForBracesInTypes": false, + "NewLinesForBracesInMethods": false, + "NewLinesForBracesInProperties": false, + "NewLinesForBracesInObjectCollectionArrayInitializers": false, + "NewLinesForBracesInAccessors": false, + "NewLineForElse": false, + "NewLineForCatch": false, + "NewLineForFinally": false + } +} \ No newline at end of file