diff options
author | bonmas14 <bonmas14@gmail.com> | 2023-10-29 21:03:26 +0300 |
---|---|---|
committer | bonmas14 <bonmas14@gmail.com> | 2023-10-29 21:03:26 +0300 |
commit | 79d8da74ac98166ec9e9dae7eff820cd9842edb3 (patch) | |
tree | bc359f214122236968f853e6aed7236a9e4905f9 | |
parent | 0ee008ae77fb76cbe9fe151cc6c4bc9f89cb98a5 (diff) | |
download | RayRoom-79d8da74ac98166ec9e9dae7eff820cd9842edb3.tar.gz RayRoom-79d8da74ac98166ec9e9dae7eff820cd9842edb3.zip |
basic functionality
+ compute bound
-rw-r--r-- | AudioTester/AudioTester.csproj | 2 | ||||
-rw-r--r-- | AudioTester/Core/RenderStreamer.cs | 32 | ||||
-rw-r--r-- | AudioTester/Program.cs | 88 | ||||
-rw-r--r-- | AudioTester/RayRoomSettings.cs | 3 | ||||
-rw-r--r-- | RayRoom.NAudio/AudioOut.cs | 95 | ||||
-rw-r--r-- | RayRoom.NAudio/AudioSampler.cs | 46 | ||||
-rw-r--r-- | RayRoom.NAudio/RayRoom.NAudioEngine.csproj | 17 | ||||
-rw-r--r-- | RayRoom.sln | 8 | ||||
-rw-r--r-- | RayRoom/Core/AudioSimulator.cs | 74 | ||||
-rw-r--r-- | RayRoom/Core/AudioSource.cs | 23 | ||||
-rw-r--r-- | RayRoom/Core/CastInfo.cs | 6 | ||||
-rw-r--r-- | RayRoom/Core/Circle.cs | 2 | ||||
-rw-r--r-- | RayRoom/Core/CollisionHelpers.cs | 23 | ||||
-rw-r--r-- | RayRoom/Core/Ray.cs | 9 | ||||
-rw-r--r-- | RayRoom/Core/RaySimulator.cs | 67 | ||||
-rw-r--r-- | RayRoom/Core/ResultContainer.cs | 28 | ||||
-rw-r--r-- | RayRoom/Core/Settings.cs | 7 | ||||
-rw-r--r-- | RayRoom/Core/Utils.cs | 15 | ||||
-rw-r--r-- | RayRoom/Structures/ShiftArray.cs | 26 |
19 files changed, 411 insertions, 160 deletions
diff --git a/AudioTester/AudioTester.csproj b/AudioTester/AudioTester.csproj index fc07b92..5549d83 100644 --- a/AudioTester/AudioTester.csproj +++ b/AudioTester/AudioTester.csproj @@ -9,7 +9,6 @@ <ItemGroup> <PackageReference Include="NAudio" Version="2.2.1" /> - <PackageReference Include="System.Drawing.Common" Version="7.0.0" /> </ItemGroup> <ItemGroup> <Content Include="Resources\*"> @@ -20,6 +19,7 @@ <None Remove="Resources\test.wav" /> </ItemGroup> <ItemGroup> + <ProjectReference Include="..\RayRoom.NAudio\RayRoom.NAudioEngine.csproj" /> <ProjectReference Include="..\RayRoom\RayRoom.csproj" /> </ItemGroup> </Project> diff --git a/AudioTester/Core/RenderStreamer.cs b/AudioTester/Core/RenderStreamer.cs index c7d2595..81be958 100644 --- a/AudioTester/Core/RenderStreamer.cs +++ b/AudioTester/Core/RenderStreamer.cs @@ -1,4 +1,5 @@ using NAudio.Wave; +using RayRoom.Core; namespace AudioTester.Core { @@ -6,37 +7,18 @@ namespace AudioTester.Core { public WaveFormat WaveFormat { get; } - private const int ReadBufferSize = 1024; - private int sample; - private Random rand; + private ISampleHandler provider; - private AudioFileReader streamReader; - private ISampleProvider provider; - - public RenderStreamer() + public RenderStreamer(ISampleHandler provider) { - rand = new Random(); - WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(44100, 2); - sample = 0; - - streamReader = new AudioFileReader(@"Resources\test.wav"); - - provider = streamReader.ToSampleProvider(); + this.provider = provider; + + WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(44100, 1); } public int Read(float[] buffer, int offset, int count) { - int length = provider.Read(buffer, offset, count); - - Console.WriteLine("i: {0}; o:{1}", count, length); - - if (length < count) - { - streamReader.Position = 0; - length += provider.Read(buffer, length, count - length); - } - - return length; + return provider.WriteTo(buffer, offset, count); } } } diff --git a/AudioTester/Program.cs b/AudioTester/Program.cs index 95d6049..c2a3a0b 100644 --- a/AudioTester/Program.cs +++ b/AudioTester/Program.cs @@ -1,47 +1,36 @@ using AudioTester.Core; -using AudioTester.Core.Extensions; +using NAudio.Mixer; using NAudio.Wave; using RayRoom.Core; -using System.Drawing; +using RayRoom.NAudioEngine; using System.Numerics; namespace AudioTester { internal class Program { - private const int width = 1280; - private const int height = 720; - private const float scale = 100; -#pragma warning disable CA1416 // Проверка совместимости платформы + [STAThread] static void Main(string[] args) { - AudioSimulator a = new AudioSimulator(new Settings(44100, 5, 330)); + var settings = new Settings(44100, 100, 330, 100f); + RaySimulator simulator = new RaySimulator(settings); - var array = a.Simulate(Vector2.Zero, 3600); - var bitmap = new Bitmap(width, height); + var sampler = new AudioSampler(@".\Resources\test.wav", true); - Matrix2x2 mat = new(Vector2.UnitX * scale, Vector2.UnitY * -scale); - - Pen foreground = new(Color.FromArgb(20, Color.White), 1); - - using (Graphics g = Graphics.FromImage(bitmap)) + List<ICastObject> structures = new List<ICastObject> { - g.Clear(Color.Black); - - Vector2 offset = new(width / 2, height / 2); - for (int i = 0; i < array.Length; i++) - { - g.DrawLine(foreground, - (array[i].a * mat + offset).GetPoint(), - (array[i].b * mat + offset).GetPoint()); - } - } - - bitmap.Save($"bitmap.png"); -#pragma warning restore CA1416 // Проверка совместимости платформы - return; - var device = new RenderStreamer(); + new AudioSource(new Vector2(0, 9), 10, sampler), + new Line(new Vector2(-2, 10), new Vector2(-2, -10)), + new Line(new Vector2(-1, 8), new Vector2(1, 8)), + new Line(new Vector2(2, 10), new Vector2(2, -10)), + new Line(new Vector2(-2, -10), new Vector2(2, -10)), + new Line(new Vector2(-2, 10), new Vector2(2, 10)), + }; + + var device = new AudioOut(settings); + device.Container = new ResultContainer(0, new AudioSourceCollision[0]); + Vector2 pos = new Vector2(0, 0); using (var wo = new WasapiOut(NAudio.CoreAudioApi.AudioClientShareMode.Shared, 150)) { wo.Init(device); @@ -49,10 +38,45 @@ namespace AudioTester while (wo.PlaybackState == PlaybackState.Playing) { - Thread.Sleep(100); - if (Console.KeyAvailable) - wo.Stop(); + { + var key = Console.ReadKey(); + + switch (key.Key) + { + case ConsoleKey.Q: + break; + case ConsoleKey.E: + break; + case ConsoleKey.W: + pos += new Vector2(0, 0.1f); + break; + case ConsoleKey.S: + pos += new Vector2(0, -0.1f); + break; + case ConsoleKey.A: + pos += new Vector2(-0.1f, 0); + break; + case ConsoleKey.D: + pos += new Vector2(0.1f, 0); + break; + case ConsoleKey.Escape: + wo.Stop(); + break; + default: + break; + } + Console.CursorLeft = 0; + Console.CursorTop = 0; + Console.WriteLine(" {0} ", pos.ToString("0.00")); + } + + var left = simulator.Simulate(structures, -Vector2.UnitX * 0.1f + pos, 0, 36); + var right = simulator.Simulate(structures, Vector2.UnitX * 0.1f + pos, 1, 36); + + var container = new ResultContainer(36, left.distances.Concat(right.distances).ToArray()); + + device.Container = container; } } } diff --git a/AudioTester/RayRoomSettings.cs b/AudioTester/RayRoomSettings.cs index 8b05bcd..5c2f25f 100644 --- a/AudioTester/RayRoomSettings.cs +++ b/AudioTester/RayRoomSettings.cs @@ -9,7 +9,8 @@ namespace AudioTester { return new Settings(format.SampleRate, baseSettings.maxRayReflections, - baseSettings.speedOfSound); + baseSettings.speedOfSound, + 5f); } } } diff --git a/RayRoom.NAudio/AudioOut.cs b/RayRoom.NAudio/AudioOut.cs new file mode 100644 index 0000000..79a3288 --- /dev/null +++ b/RayRoom.NAudio/AudioOut.cs @@ -0,0 +1,95 @@ +using NAudio.Wave; +using RayRoom.Core; +using RayRoom.Structures; + +namespace RayRoom.NAudioEngine +{ + public class AudioOut : ISampleProvider + { + public WaveFormat WaveFormat { get; } + + public ResultContainer Container + { + get => container; + + set + { + updatedPosition = value; + } + } + + private ResultContainer updatedPosition; + + private ShiftArray<float> leftBuffer; + private ShiftArray<float> rightBuffer; + private Settings settings; + + private Dictionary<ISampleHandler, List<AudioSourceCollision>> sources; + private ResultContainer container; + + public AudioOut(Settings settings) + { + this.settings = settings; + sources = new Dictionary<ISampleHandler, List<AudioSourceCollision>>(); + WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(settings.frequency, 2); + + leftBuffer = new ShiftArray<float>((int)(settings.frequency * (settings.maxDistanceMeters / settings.speedOfSound + 1))); + rightBuffer = new ShiftArray<float>((int)(settings.frequency * (settings.maxDistanceMeters / settings.speedOfSound + 1))); + } + + public int Read(float[] buffer, int offset, int count) + { + container = updatedPosition; + + float velocity = 1f / container.countOfRays; + + sources.Clear(); + + foreach (var collision in container.distances) + if (sources.ContainsKey(collision.source.Handler)) + sources[collision.source.Handler].Add(collision); + else + sources.Add(collision.source.Handler, new List<AudioSourceCollision>(10) { collision }); + + foreach (var source in sources) + { + float[] samples = new float[count / 2]; + + int read = source.Key.WriteTo(samples, 0, count / 2); + + foreach (var collision in source.Value) + { + int offsetSamples = settings.GetSamplesDelay(collision.distance) * 4; + Parallel.For(0, count / 2, i => + { + if (collision.channel == 0) + leftBuffer[i + offsetSamples] += samples[i] * velocity * (collision.source.Loudness / MathF.Pow(collision.distance, 2)); + else + rightBuffer[i + offsetSamples] += samples[i] * velocity * (collision.source.Loudness / MathF.Pow(collision.distance, 2)); + + }); + } + } + + Parallel.For(0, count, i => + { + if (i % 2 == 0) + { + buffer[i] = leftBuffer[i / 2]; + leftBuffer[i / 2] = 0; + } + else + { + buffer[i] = rightBuffer[(i - 1) / 2]; + rightBuffer[(i - 1) / 2] = 0; + } + + }); + + leftBuffer.Offset += count / 2; + rightBuffer.Offset += count / 2; + + return count; + } + } +} diff --git a/RayRoom.NAudio/AudioSampler.cs b/RayRoom.NAudio/AudioSampler.cs new file mode 100644 index 0000000..2aebcce --- /dev/null +++ b/RayRoom.NAudio/AudioSampler.cs @@ -0,0 +1,46 @@ +using NAudio.Wave; +using RayRoom.Core; + +namespace RayRoom.NAudioEngine +{ + public class AudioSampler : ISampleHandler, IDisposable + { + public bool Loop { get; set; } + + private bool disposed; + + private AudioFileReader reader; + private ISampleProvider provider; + + public AudioSampler(string file, bool looping = false) + { + disposed = false; + reader = new AudioFileReader(file); + Loop = looping; + + provider = reader.ToSampleProvider(); + provider = provider.ToMono(); + } + + public int WriteTo(float[] buffer, int offset, int count) + { + if (disposed) throw new ObjectDisposedException("AudioSampler is disposed"); + + int length = provider.Read(buffer, offset, count); + + if (Loop && length < count) + { + reader.Position = 0; + length += provider.Read(buffer, length, count - length); + } + + return length; + } + + public void Dispose() + { + reader.Close(); + reader.Dispose(); + } + } +}
\ No newline at end of file diff --git a/RayRoom.NAudio/RayRoom.NAudioEngine.csproj b/RayRoom.NAudio/RayRoom.NAudioEngine.csproj new file mode 100644 index 0000000..471fb68 --- /dev/null +++ b/RayRoom.NAudio/RayRoom.NAudioEngine.csproj @@ -0,0 +1,17 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net6.0</TargetFramework> + <ImplicitUsings>enable</ImplicitUsings> + <Nullable>enable</Nullable> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="NAudio" Version="2.2.1" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\RayRoom\RayRoom.csproj" /> + </ItemGroup> + +</Project> diff --git a/RayRoom.sln b/RayRoom.sln index 3c6a15a..d5f1090 100644 --- a/RayRoom.sln +++ b/RayRoom.sln @@ -7,7 +7,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RayRoom", "RayRoom\RayRoom. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AudioTester", "AudioTester\AudioTester.csproj", "{BDA8477C-5901-4849-98D7-134871412EF5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RayRoom.Tests", "RayRoom.Tests\RayRoom.Tests.csproj", "{B077A864-8279-4237-858B-37AA5A66C10D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RayRoom.Tests", "RayRoom.Tests\RayRoom.Tests.csproj", "{B077A864-8279-4237-858B-37AA5A66C10D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RayRoom.NAudioEngine", "RayRoom.NAudio\RayRoom.NAudioEngine.csproj", "{114D04B9-EAE7-4969-87A0-5F4652B4B088}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -27,6 +29,10 @@ Global {B077A864-8279-4237-858B-37AA5A66C10D}.Debug|Any CPU.Build.0 = Debug|Any CPU {B077A864-8279-4237-858B-37AA5A66C10D}.Release|Any CPU.ActiveCfg = Release|Any CPU {B077A864-8279-4237-858B-37AA5A66C10D}.Release|Any CPU.Build.0 = Release|Any CPU + {114D04B9-EAE7-4969-87A0-5F4652B4B088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {114D04B9-EAE7-4969-87A0-5F4652B4B088}.Debug|Any CPU.Build.0 = Debug|Any CPU + {114D04B9-EAE7-4969-87A0-5F4652B4B088}.Release|Any CPU.ActiveCfg = Release|Any CPU + {114D04B9-EAE7-4969-87A0-5F4652B4B088}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/RayRoom/Core/AudioSimulator.cs b/RayRoom/Core/AudioSimulator.cs deleted file mode 100644 index c5a913c..0000000 --- a/RayRoom/Core/AudioSimulator.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Numerics; - -namespace RayRoom.Core -{ - public class AudioSimulator - { - private Settings simulationSettings; - - public AudioSimulator(Settings simulationSettings) - { - this.simulationSettings = simulationSettings; - } - - public Line[] Simulate(Vector2 position, int count) - { - count += 1; - Ray[] startupRays = new Ray[count]; - for (int i = 0; i < count; i++) - { - float angle = i / (float)count * MathF.PI * 2f; - startupRays[i] = new Ray(position, UnitVectorFromAngle(angle)); - } - - List<ICastObject> structures = new List<ICastObject> - { - new Circle(new Vector2(0, -3), 2f), - new Circle(new Vector2(5, 3), 2f), - new Circle(new Vector2(-0.5f, 0.5f), 0.5f), - new Line(new Vector2(-10, -10), new Vector2(0, 10)), - new Line(new Vector2(5, 3), new Vector2(0, 10)), - new Line(new Vector2(-10, -10), new Vector2(0, -3)), - new Line(new Vector2(0, -3), new Vector2(5, 3)), - }; - - List<Ray> rays = new(startupRays); - - List<Line> output = new(count); - - int castCount = count * 10; - - while (rays.Count > 0 && castCount-- > 0) - { - var ray = rays[0]; - - rays.Remove(ray); - - if (ray.bounces >= simulationSettings.maxRayReflections) - continue; - - CastInfo closest = CastInfo.Default; - - foreach (var structure in structures) - { - if (structure.CastRay(ray, out CastInfo info)) - if (closest.distance > info.distance) - closest = info; - } - - if (closest.collided) - { - output.Add(new Line(ray.position, closest.point)); - rays.Add(new Ray(closest.point, ray.direction - 2 * Vector2.Dot(ray.direction, closest.normal) * closest.normal, closest.distance, ray.bounces + 1)); - } - } - - return output.ToArray(); - } - - private Vector2 UnitVectorFromAngle(float angle) - { - return new Vector2(MathF.Cos(angle), MathF.Sin(angle)); - } - } -} diff --git a/RayRoom/Core/AudioSource.cs b/RayRoom/Core/AudioSource.cs index ff5766f..78401f5 100644 --- a/RayRoom/Core/AudioSource.cs +++ b/RayRoom/Core/AudioSource.cs @@ -4,29 +4,36 @@ namespace RayRoom.Core { public interface ISampleHandler { - int Read(float[] buffer, int offset, int count); + int WriteTo(float[] buffer, int offset, int count); } public class AudioSource : ICastObject { - public const float size = 1.0f; + public const float size = 1f; public bool IsAudioSource => true; + public float Loudness => loudness; + public ISampleHandler Handler => handler; private Circle source; - private float strength; + private float loudness; + private ISampleHandler handler; - public AudioSource(Vector2 position, float strength) + public AudioSource(Vector2 position, float loudness, ISampleHandler handler) { - source = new Circle(position, strength); - this.strength = strength; + source = new Circle(position, size); + this.loudness = loudness; + this.handler = handler; } - public bool CastRay(Ray ray, out CastInfo info) { - return source.CastRay(ray, out info); + var result = CollisionHelpers.RaycastRayToCircle(source, ray, out info); + + info = new CastInfo(info.point, info.normal, info.distance, info.collided, this); + + return result; } } } diff --git a/RayRoom/Core/CastInfo.cs b/RayRoom/Core/CastInfo.cs index 9dde7e3..8b89886 100644 --- a/RayRoom/Core/CastInfo.cs +++ b/RayRoom/Core/CastInfo.cs @@ -8,15 +8,17 @@ namespace RayRoom.Core public readonly Vector2 normal; public readonly float distance; public readonly bool collided; + public readonly ICastObject? castObject; - public static CastInfo Default => new CastInfo(Vector2.Zero, Vector2.Zero, float.MaxValue, false); + public static CastInfo Default => new CastInfo(Vector2.Zero, Vector2.Zero, float.MaxValue, false, null); - public CastInfo(Vector2 point, Vector2 normal, float distance, bool collided) + public CastInfo(Vector2 point, Vector2 normal, float distance, bool collided, ICastObject? castObject) { this.point = point; this.normal = normal; this.distance = distance; this.collided = collided; + this.castObject = castObject; } public override string ToString() diff --git a/RayRoom/Core/Circle.cs b/RayRoom/Core/Circle.cs index 28aee45..cbb7424 100644 --- a/RayRoom/Core/Circle.cs +++ b/RayRoom/Core/Circle.cs @@ -17,7 +17,7 @@ namespace RayRoom.Core public bool CastRay(Ray ray, out CastInfo info) { - return CollisionHelpers.RaycastRayToSphere(this, ray, out info); + return CollisionHelpers.RaycastRayToCircle(this, ray, out info); } } }
\ No newline at end of file diff --git a/RayRoom/Core/CollisionHelpers.cs b/RayRoom/Core/CollisionHelpers.cs index d509a0b..94102da 100644 --- a/RayRoom/Core/CollisionHelpers.cs +++ b/RayRoom/Core/CollisionHelpers.cs @@ -4,7 +4,7 @@ namespace RayRoom.Core { public static class CollisionHelpers { - private static float minimalThreshold = 0.001f; + public static float minimalThreshold = 0.001f; public struct Distances { @@ -40,22 +40,28 @@ namespace RayRoom.Core Vector2 normal = GetClosestNormal(a.direction, b.direction); - info = new CastInfo(b.position + b.direction * v, normal, (v * b.direction).Length(), true); + info = new CastInfo(b.position + b.direction * v, normal, (v * b.direction).Length(), true, a); return new Distances(u, v); } public static Distances TestSphereToRay(Circle a, Ray b, out CastInfo info) { + info = CastInfo.Default; + Distances result = new Distances(0, 0); + + Vector2 position = b.position - a.center; + if (position.LengthSquared() < a.radius * a.radius) + return result; + float vb = 2 * b.direction.X * position.X + 2 * b.direction.Y * position.Y; float va = MathF.Pow(b.direction.X, 2) + MathF.Pow(b.direction.Y, 2); float vc = MathF.Pow(position.X, 2) + MathF.Pow(position.Y, 2) - MathF.Pow(a.radius, 2); float discr = MathF.Pow(vb, 2) - 4 * va * vc; - Distances result; if (discr >= 0) { @@ -71,14 +77,9 @@ namespace RayRoom.Core Vector2 normal = (b.position + b.direction * distance - a.center) / a.radius * -1f; - info = new CastInfo(b.position + b.direction * distance, normal, (b.direction * distance).Length(), true); + info = new CastInfo(b.position + b.direction * distance, normal, (b.direction * distance).Length(), true, a); result = new Distances(t0, t1); } - else - { - info = CastInfo.Default; - result = new Distances(0, 0); - } return result; } @@ -97,7 +98,7 @@ namespace RayRoom.Core return n1; } - public static bool RaycastRayToSphere(Circle sphere, Ray b, out CastInfo info) + public static bool RaycastRayToCircle(Circle sphere, Ray b, out CastInfo info) { var distances = TestSphereToRay(sphere, b, out info); @@ -112,7 +113,7 @@ namespace RayRoom.Core public static bool RaycastRayToLine(Line aLine, Ray b, out CastInfo info) { - Ray a = new Ray(aLine.a, aLine.b - aLine.a); + Ray a = new(aLine.a, aLine.b - aLine.a); var result = TestRays(a, b, out info); diff --git a/RayRoom/Core/Ray.cs b/RayRoom/Core/Ray.cs index 2650cec..75f3d97 100644 --- a/RayRoom/Core/Ray.cs +++ b/RayRoom/Core/Ray.cs @@ -2,7 +2,7 @@ namespace RayRoom.Core { - public class Ray + public class Ray : ICastObject { public readonly Vector2 position; public readonly Vector2 direction; @@ -17,6 +17,13 @@ namespace RayRoom.Core this.bounces = bounces; } + public bool IsAudioSource => false; + + public bool CastRay(Ray ray, out CastInfo info) + { + return CollisionHelpers.RaycastRayToRay(this, ray, out info); + } + public override string? ToString() { return string.Format("pos:{0} dir:{1} dist:{2}", position.ToString(), direction.ToString(), distance); diff --git a/RayRoom/Core/RaySimulator.cs b/RayRoom/Core/RaySimulator.cs new file mode 100644 index 0000000..267f4c0 --- /dev/null +++ b/RayRoom/Core/RaySimulator.cs @@ -0,0 +1,67 @@ +using System.Numerics; + +namespace RayRoom.Core +{ + public class RaySimulator + { + private Settings simulationSettings; + + public RaySimulator(Settings simulationSettings) + { + this.simulationSettings = simulationSettings; + } + + public ResultContainer Simulate(List<ICastObject> structures, Vector2 position, int channel, int count) + { + count += 1; + + Ray[] startupRays = new Ray[count]; + + for (int i = 0; i < count; i++) + { + float angle = i / (float)count * MathF.PI * 2f; + startupRays[i] = new Ray(position, UnitVectorFromAngle(angle)); + } + + List<Ray> rays = new(startupRays); + + List<AudioSourceCollision> distances = new(count); + + while (rays.Count > 0) + { + var ray = rays[0]; + + rays.Remove(ray); + + if (ray.bounces >= simulationSettings.maxRayReflections) + continue; + if (ray.distance >= simulationSettings.maxDistanceMeters) + continue; + + CastInfo closest = CastInfo.Default; + + foreach (var structure in structures) + if (structure.CastRay(ray, out CastInfo info) & closest.distance > info.distance) + closest = info; + + if (closest.collided) + { + if (closest.castObject == null) + throw new NullReferenceException("CastInfo collided but castObject is null"); + + if (closest.castObject.IsAudioSource) + distances.Add(new(closest.distance, (AudioSource)closest.castObject, channel)); + else + rays.Add(new Ray(closest.point, ray.direction - 2 * Vector2.Dot(ray.direction, closest.normal) * closest.normal, closest.distance, ray.bounces + 1)); + } + } + + return new ResultContainer(count, distances.ToArray()); + } + + private Vector2 UnitVectorFromAngle(float angle) + { + return new Vector2(MathF.Cos(angle), MathF.Sin(angle)); + } + } +} diff --git a/RayRoom/Core/ResultContainer.cs b/RayRoom/Core/ResultContainer.cs new file mode 100644 index 0000000..adecfd7 --- /dev/null +++ b/RayRoom/Core/ResultContainer.cs @@ -0,0 +1,28 @@ +namespace RayRoom.Core +{ + public struct ResultContainer + { + public readonly int countOfRays; + public AudioSourceCollision[] distances; + + public ResultContainer(int countOfRays, AudioSourceCollision[] distances) + { + this.countOfRays = countOfRays; + this.distances = distances; + } + } + + public struct AudioSourceCollision + { + public readonly float distance; + public readonly AudioSource source; + public readonly int channel; + + public AudioSourceCollision(float distance, AudioSource source, int channel) + { + this.distance = distance; + this.source = source; + this.channel = channel; + } + } +} diff --git a/RayRoom/Core/Settings.cs b/RayRoom/Core/Settings.cs index 72eaebc..d970d21 100644 --- a/RayRoom/Core/Settings.cs +++ b/RayRoom/Core/Settings.cs @@ -5,14 +5,15 @@ public readonly int frequency; public readonly int maxRayReflections; public readonly float speedOfSound; + public readonly float maxDistanceMeters; + public static Settings Default => new Settings(44100, 10, 330f, 10f); - public static Settings Default => new Settings(44100, 10, 330f); - - public Settings(int frequency, int maxRayReflections, float speedOfSound) + public Settings(int frequency, int maxRayReflections, float speedOfSound, float maxDistanceMeters) { this.frequency = frequency; this.maxRayReflections = maxRayReflections; this.speedOfSound = speedOfSound; + this.maxDistanceMeters = maxDistanceMeters; } public float GetSecoundsDelay(float distance) diff --git a/RayRoom/Core/Utils.cs b/RayRoom/Core/Utils.cs new file mode 100644 index 0000000..1561ac6 --- /dev/null +++ b/RayRoom/Core/Utils.cs @@ -0,0 +1,15 @@ +namespace RayRoom.Core +{ + public static class Utils + { + public static float VolumeToDB(float volume) + { + return 20 * MathF.Log10(volume); + } + + public static float DBToVolume(float db) + { + return MathF.Pow(10f, db / 20f); + } + } +} diff --git a/RayRoom/Structures/ShiftArray.cs b/RayRoom/Structures/ShiftArray.cs new file mode 100644 index 0000000..c837aa8 --- /dev/null +++ b/RayRoom/Structures/ShiftArray.cs @@ -0,0 +1,26 @@ +namespace RayRoom.Structures +{ + public class ShiftArray<T> + { + public T this[int index] + { + get + { + return items[(index + Offset) % items.Length]; + } + set + { + items[(index + Offset) % items.Length] = value; + } + } + + public int Offset { get; set; } + + private T[] items; + + public ShiftArray(int capacity) + { + items = new T[capacity]; + } + } +} |