Exemplo n.º 1
0
    public void FixedListInt128ToFixedListInt64()
    {
        var a = new FixedListInt128();

        for (var i = 0; i < 31; ++i)
        {
            a.Add((int)i);
        }
        Assert.Throws <IndexOutOfRangeException> (() => { var b = new FixedListInt64(a); });
    }
Exemplo n.º 2
0
    public void FixedListInt128HasExpectedCapacity()
    {
        var list             = new FixedListInt128();
        var expectedCapacity = 31;

        for (int i = 0; i < expectedCapacity; ++i)
        {
            list.Add((int)i);
        }
        Assert.Throws <IndexOutOfRangeException> (() => { list.Add((int)expectedCapacity); });
    }
Exemplo n.º 3
0
    public void FixedListInt128Sort()
    {
        var list = new FixedListInt128();

        for (var i = 0; i < 5; ++i)
        {
            list.Add((int)(4 - i));
        }
        list.Sort();
        for (var i = 0; i < 5; ++i)
        {
            Assert.AreEqual(i, list[i]);
        }
    }
Exemplo n.º 4
0
    public void FixedListInt128RemoveRange()
    {
        var list = new FixedListInt128();

        list.Add(0);
        list.Add(3);
        list.Add(3);
        list.Add(1);
        list.Add(2);
        list.RemoveRange(1, 2);
        for (var i = 0; i < 3; ++i)
        {
            Assert.AreEqual(i, list[i]);
        }
    }
Exemplo n.º 5
0
    public void FixedListInt128InsertRange()
    {
        var list = new FixedListInt128();

        list.Add(0);
        list.Add(3);
        list.Add(4);
        list.InsertRange(1, 2);
        list[1] = 1;
        list[2] = 2;
        for (var i = 0; i < 5; ++i)
        {
            Assert.AreEqual(i, list[i]);
        }
    }
Exemplo n.º 6
0
    public void FixedListInt64ToFixedListInt128()
    {
        var a = new FixedListInt64();

        for (var i = 0; i < 15; ++i)
        {
            a.Add((int)i);
        }
        var b = new FixedListInt128(a);

        for (var i = 0; i < 15; ++i)
        {
            Assert.AreEqual((int)i, b[i]);
        }
    }
Exemplo n.º 7
0
    public void FixedListInt128HasExpectedLayout()
    {
        var actual = new FixedListInt128();

        for (var i = 0; i < 31; ++i)
        {
            actual.Add((int)i);
        }
        unsafe
        {
            var e = stackalloc byte[128];
            e[0] = (byte)((31 >> 0) & 0xFF);
            e[1] = (byte)((31 >> 8) & 0xFF);
            for (var i = 0; i < 31; ++i)
            {
                var s = (int)i;
                UnsafeUtility.MemCpy(e + 2 + sizeof(int) * i, &s, sizeof(int));
            }
            Assert.AreEqual(0, UnsafeUtility.MemCmp(e, &actual.length, 128));
        }
    }
        private static void ComputeWeights(ref Weights weights, EmitterParameters emitter, ListenerWithTransform listener, NativeList <float4> scratchCache)
        {
            float volume = emitter.volume * listener.listener.volume;

            var emitterInListenerSpace    = math.mul(math.inverse(listener.transform), emitter.transform);
            var emitterPositionNormalized = math.normalizesafe(emitterInListenerSpace.pos, float3.zero);

            //attenuation
            {
                float d     = math.length(emitterInListenerSpace.pos);
                float atten = 1f;
                if (d > emitter.innerRange)
                {
                    if (emitter.innerRange <= 0f)
                    {
                        //The offset is the distance from the innerRange minus 1 unit clamped between the innerRange and the margin.
                        //The minus one offset ensures the falloff is always 1 or larger, making the transition betweem the innerRange
                        //and the falloff region continuous (by calculus terminology).
                        float falloff = math.min(d, emitter.outerRange - emitter.rangeFadeMargin) - (emitter.innerRange - 1f);
                        atten = math.saturate(math.rcp(falloff * falloff));
                    }
                    else
                    {
                        float falloff = math.min(d, emitter.outerRange - emitter.rangeFadeMargin) / emitter.innerRange;
                        atten = math.saturate(math.rcp(falloff * falloff));
                    }
                }
                if (d > emitter.outerRange - emitter.rangeFadeMargin)
                {
                    float factor = (d - (emitter.outerRange - emitter.rangeFadeMargin)) / emitter.rangeFadeMargin;
                    factor = math.saturate(factor);
                    atten  = math.lerp(atten, 0f, factor);
                }

                if (emitter.useCone)
                {
                    float cosine = math.dot(math.forward(emitterInListenerSpace.rot), -emitterPositionNormalized);
                    if (cosine <= emitter.cone.cosOuterAngle)
                    {
                        atten *= emitter.cone.outerAngleAttenuation;
                    }
                    else if (cosine < emitter.cone.cosInnerAngle)
                    {
                        float factor = math.unlerp(emitter.cone.cosOuterAngle, emitter.cone.cosInnerAngle, cosine);
                        atten *= math.lerp(emitter.cone.outerAngleAttenuation, 1f, factor);
                    }
                }
                volume *= atten;
            }

            //ITD
            {
                float itd = (math.dot(emitterPositionNormalized, math.right()) * 0.5f + 0.5f) * weights.itdWeights.Length;
                //float frac                    = math.modf(itd, out float integer);
                //int   indexLow                = math.clamp((int)integer, 0, weights.itdWeights.Length - 1);
                //int   indexHigh               = math.clamp(indexLow + 1, 0, weights.itdWeights.Length - 1);
                //weights.itdWeights[indexLow]  = volume * frac;
                //weights.itdWeights[indexHigh] = volume * (1f - frac);
                int index = math.clamp((int)math.round(itd), 0, weights.itdWeights.Length - 1);
                weights.itdWeights[index] = volume;
            }

            //ILD
            {
                ref var profile = ref listener.listener.ildProfile.Value;

                float2 xz     = math.normalizesafe(emitterPositionNormalized.xz, new float2(0f, 1f));
                float2 angles = default;
                angles.x = math.atan2(xz.y, xz.x);
                float2 yz = math.normalizesafe(emitterPositionNormalized.yz, new float2(1f, 0f));
                angles.y = math.atan2(yz.y, yz.x);

                //Left
                //First, find if there is a perfect match
                bool perfectMatch = false;
                for (int i = 0; i < profile.anglesPerLeftChannel.Length; i++)
                {
                    perfectMatch = math.all(((angles >= profile.anglesPerLeftChannel[i].xz) &
                                             (angles <= profile.anglesPerLeftChannel[i].yw)) |
                                            ((angles + 2f * math.PI >= profile.anglesPerLeftChannel[i].xz) &
                                             (angles + 2f * math.PI <= profile.anglesPerLeftChannel[i].yw)));
                    if (perfectMatch)
                    {
                        weights.channelWeights[i] = 1f;
                        perfectMatch = true;
                        break;
                    }
                }

                if (!perfectMatch)
                {
                    //No perfect match.
                    int4              bestMinMaxXYIndices = default;  //This should always be overwritten
                    float4            bestAngleDeltas     = new float4(2f * math.PI, -2f * math.PI, 2f * math.PI, -2f * math.PI);
                    FixedListInt128   candidateChannels   = default;
                    FixedListFloat128 candidateDistances  = default;

                    //Find our limits
                    scratchCache.Clear();
                    scratchCache.AddRangeFromBlob(ref profile.anglesPerLeftChannel);
                    var leftChannelDeltas = scratchCache.AsArray();
                    FixedList512 <bool2> leftChannelInsides = default;

                    for (int i = 0; i < leftChannelDeltas.Length; i++)
                    {
                        var delta = leftChannelDeltas[i] - angles.xxyy;
                        var temp  = delta;
                        delta += math.select(0f, new float4(2f * math.PI, -2f * math.PI, 2f * math.PI, -2f * math.PI), delta * new float4(1f, -1f, 1f, -1f) < 0f);
                        delta -= math.select(0f,
                                             new float4(2f * math.PI, -2f * math.PI, 2f * math.PI, -2f * math.PI),
                                             delta * new float4(1f, -1f, 1f, -1f) >= 2f * math.PI);
                        temp -= math.select(0f, 2f * math.PI, temp.xxzz > 0f);
                        bool2 inside = temp.yw >= 0f;
                        leftChannelDeltas[i] = delta;
                        leftChannelInsides.Add(inside);
                    }
                    //By this point, any delta should be (positive, negative, positive, negative)

                    //Find our search region
                    for (int i = 0; i < leftChannelDeltas.Length; i++)
                    {
                        bool2 inside = leftChannelInsides[i];
                        var   delta  = leftChannelDeltas[i];
                        if (inside.x)
                        {
                            //above
                            if (delta.z <= bestAngleDeltas.z)
                            {
                                bestAngleDeltas.z     = delta.z;
                                bestMinMaxXYIndices.z = i;
                            }
                            //below
                            if (delta.w >= bestAngleDeltas.w)
                            {
                                bestAngleDeltas.w     = delta.w;
                                bestMinMaxXYIndices.w = i;
                            }
                        }
                        if (inside.y)
                        {
                            //right
                            if (delta.x <= bestAngleDeltas.x)
                            {
                                bestAngleDeltas.x     = delta.x;
                                bestMinMaxXYIndices.x = i;
                            }
                            //left
                            if (delta.y >= bestAngleDeltas.y)
                            {
                                bestAngleDeltas.y     = delta.y;
                                bestMinMaxXYIndices.y = i;
                            }
                        }
                    }

                    //Add our constraining indices to the pot
                    var bestAngleDistances = math.abs(bestAngleDeltas);
                    candidateChannels.Add(bestMinMaxXYIndices.x);
                    candidateDistances.Add(bestAngleDistances.x);
                    if (bestMinMaxXYIndices.x != bestMinMaxXYIndices.y)
                    {
                        candidateChannels.Add(bestMinMaxXYIndices.y);
                        candidateDistances.Add(bestAngleDistances.y);
                    }
                    else
                    {
                        candidateDistances[0] = math.min(candidateDistances[0], bestAngleDistances.y);
                    }

                    if (math.all(bestMinMaxXYIndices.xy != bestMinMaxXYIndices.z))
                    {
                        candidateChannels.Add(bestMinMaxXYIndices.z);
                        candidateDistances.Add(bestAngleDistances.z);
                    }
                    else if (bestMinMaxXYIndices.x == bestMinMaxXYIndices.z)
                    {
                        candidateDistances[0] = math.min(candidateDistances[0], bestAngleDistances.z);
                    }
                    else
                    {
                        candidateDistances[1] = math.min(candidateDistances[1], bestAngleDistances.z);
                    }

                    if (math.all(bestMinMaxXYIndices.xyz != bestMinMaxXYIndices.w))
                    {
                        candidateChannels.Add(bestMinMaxXYIndices.w);
                        candidateDistances.Add(bestAngleDistances.w);
                    }
                    else if (bestMinMaxXYIndices.x == bestMinMaxXYIndices.w)
                    {
                        candidateDistances[0] = math.min(candidateDistances[0], bestAngleDistances.w);
                    }
                    else if (bestMinMaxXYIndices.y == bestMinMaxXYIndices.w)
                    {
                        candidateDistances[1] = math.min(candidateDistances[1], bestAngleDistances.w);
                    }
                    else
                    {
                        candidateDistances[candidateDistances.Length - 1] = math.min(candidateDistances[candidateDistances.Length - 1], bestAngleDistances.w);
                    }

                    //Add additional candidates
                    for (int i = 0; i < leftChannelDeltas.Length; i++)
                    {
                        if (math.any(i == bestMinMaxXYIndices))
                        {
                            continue;
                        }

                        float4 delta = leftChannelDeltas[i];
                        bool   added = false;
                        int    c     = candidateDistances.Length;
                        if (math.all(delta.xz < bestAngleDeltas.xz))
                        {
                            candidateChannels.Add(i);
                            candidateDistances.Add(math.length(delta.xz));
                            added = true;
                        }
                        if (delta.y > bestAngleDeltas.y && delta.z < bestAngleDeltas.z)
                        {
                            if (added)
                            {
                                candidateDistances[c] = math.min(candidateDistances[c], math.length(delta.yz));
                            }
                            else
                            {
                                candidateChannels.Add(i);
                                candidateDistances.Add(math.length(delta.yz));
                                added = true;
                            }
                        }
                        if (delta.x < bestAngleDeltas.x && delta.w < bestAngleDeltas.w)
                        {
                            if (added)
                            {
                                candidateDistances[c] = math.min(candidateDistances[c], math.length(delta.xw));
                            }
                            else
                            {
                                candidateChannels.Add(i);
                                candidateDistances.Add(math.length(delta.xw));
                                added = true;
                            }
                        }
                        if (math.all(delta.yw > bestAngleDeltas.yw))
                        {
                            if (added)
                            {
                                candidateDistances[c] = math.min(candidateDistances[c], math.length(delta.yw));
                            }
                            else
                            {
                                candidateChannels.Add(i);
                                candidateDistances.Add(math.length(delta.yw));
                            }
                        }
                    }

                    //Compute weights
                    float sum = 0f;
                    for (int i = 0; i < candidateDistances.Length; i++)
                    {
                        candidateDistances[i] = 1f / candidateDistances[i];
                        sum += candidateDistances[i];
                    }
                    for (int i = 0; i < candidateDistances.Length; i++)
                    {
                        weights.channelWeights[candidateChannels[i]] = candidateDistances[i] / sum;
                    }
                }

                //Right
                //First, find if there is a perfect match
                perfectMatch = false;
                for (int i = 0; i < profile.anglesPerRightChannel.Length; i++)
                {
                    perfectMatch = math.all(((angles >= profile.anglesPerRightChannel[i].xz) &
                                             (angles <= profile.anglesPerRightChannel[i].yw)) |
                                            ((angles + 2f * math.PI >= profile.anglesPerRightChannel[i].xz) &
                                             (angles + 2f * math.PI <= profile.anglesPerRightChannel[i].yw)));
                    if (perfectMatch)
                    {
                        weights.channelWeights[i + profile.anglesPerLeftChannel.Length] = 1f;
                        perfectMatch = true;
                        break;
                    }
                }

                if (!perfectMatch)
                {
                    //No perfect match.
                    int4              bestMinMaxXYIndices = default;  //This should always be overwritten
                    float4            bestAngleDeltas     = new float4(2f * math.PI, -2f * math.PI, 2f * math.PI, -2f * math.PI);
                    FixedListInt128   candidateChannels   = default;
                    FixedListFloat128 candidateDistances  = default;

                    //Find our limits
                    scratchCache.Clear();
                    scratchCache.AddRangeFromBlob(ref profile.anglesPerRightChannel);
                    var rightChannelDeltas = scratchCache.AsArray();
                    FixedList512 <bool2> rightChannelInsides = default;

                    for (int i = 0; i < rightChannelDeltas.Length; i++)
                    {
                        var delta = rightChannelDeltas[i] - angles.xxyy;
                        var temp  = delta;
                        delta += math.select(0f, new float4(2f * math.PI, -2f * math.PI, 2f * math.PI, -2f * math.PI), delta * new float4(1f, -1f, 1f, -1f) < 0f);
                        delta -= math.select(0f,
                                             new float4(2f * math.PI, -2f * math.PI, 2f * math.PI, -2f * math.PI),
                                             delta * new float4(1f, -1f, 1f, -1f) >= 2f * math.PI);
                        temp -= math.select(0f, 2f * math.PI, temp.xxzz > 0f);
                        bool2 inside = temp.yw >= 0f;
                        rightChannelDeltas[i] = delta;
                        rightChannelInsides.Add(inside);
                    }
                    //By this point, any delta should be (positive, negative, positive, negative)

                    //Find our search region
                    for (int i = 0; i < rightChannelDeltas.Length; i++)
                    {
                        bool2 inside = rightChannelInsides[i];
                        var   delta  = rightChannelDeltas[i];
                        if (inside.x)
                        {
                            //above
                            if (delta.z <= bestAngleDeltas.z)
                            {
                                bestAngleDeltas.z     = delta.z;
                                bestMinMaxXYIndices.z = i;
                            }
                            //below
                            if (delta.w >= bestAngleDeltas.w)
                            {
                                bestAngleDeltas.w     = delta.w;
                                bestMinMaxXYIndices.w = i;
                            }
                        }
                        if (inside.y)
                        {
                            //right
                            if (delta.x <= bestAngleDeltas.x)
                            {
                                bestAngleDeltas.x     = delta.x;
                                bestMinMaxXYIndices.x = i;
                            }
                            //left
                            if (delta.y >= bestAngleDeltas.y)
                            {
                                bestAngleDeltas.y     = delta.y;
                                bestMinMaxXYIndices.y = i;
                            }
                        }
                    }

                    //Add our constraining indices to the pot
                    var bestAngleDistances = math.abs(bestAngleDeltas);
                    candidateChannels.Add(bestMinMaxXYIndices.x);
                    candidateDistances.Add(bestAngleDistances.x);
                    if (bestMinMaxXYIndices.x != bestMinMaxXYIndices.y)
                    {
                        candidateChannels.Add(bestMinMaxXYIndices.y);
                        candidateDistances.Add(bestAngleDistances.y);
                    }
                    else
                    {
                        candidateDistances[0] = math.min(candidateDistances[0], bestAngleDistances.y);
                    }

                    if (math.all(bestMinMaxXYIndices.xy != bestMinMaxXYIndices.z))
                    {
                        candidateChannels.Add(bestMinMaxXYIndices.z);
                        candidateDistances.Add(bestAngleDistances.z);
                    }
                    else if (bestMinMaxXYIndices.x == bestMinMaxXYIndices.z)
                    {
                        candidateDistances[0] = math.min(candidateDistances[0], bestAngleDistances.z);
                    }
                    else
                    {
                        candidateDistances[1] = math.min(candidateDistances[1], bestAngleDistances.z);
                    }

                    if (math.all(bestMinMaxXYIndices.xyz != bestMinMaxXYIndices.w))
                    {
                        candidateChannels.Add(bestMinMaxXYIndices.w);
                        candidateDistances.Add(bestAngleDistances.w);
                    }
                    else if (bestMinMaxXYIndices.x == bestMinMaxXYIndices.w)
                    {
                        candidateDistances[0] = math.min(candidateDistances[0], bestAngleDistances.w);
                    }
                    else if (bestMinMaxXYIndices.y == bestMinMaxXYIndices.w)
                    {
                        candidateDistances[1] = math.min(candidateDistances[1], bestAngleDistances.w);
                    }
                    else
                    {
                        candidateDistances[candidateDistances.Length - 1] = math.min(candidateDistances[candidateDistances.Length - 1], bestAngleDistances.w);
                    }

                    //Add additional candidates
                    for (int i = 0; i < rightChannelDeltas.Length; i++)
                    {
                        if (math.any(i == bestMinMaxXYIndices))
                        {
                            continue;
                        }

                        float4 delta = rightChannelDeltas[i];
                        bool   added = false;
                        int    c     = candidateDistances.Length;
                        if (math.all(delta.xz < bestAngleDeltas.xz))
                        {
                            candidateChannels.Add(i);
                            candidateDistances.Add(math.length(delta.xz));
                            added = true;
                        }
                        if (delta.y > bestAngleDeltas.y && delta.z < bestAngleDeltas.z)
                        {
                            if (added)
                            {
                                candidateDistances[c] = math.min(candidateDistances[c], math.length(delta.yz));
                            }
                            else
                            {
                                candidateChannels.Add(i);
                                candidateDistances.Add(math.length(delta.yz));
                                added = true;
                            }
                        }
                        if (delta.x < bestAngleDeltas.x && delta.w < bestAngleDeltas.w)
                        {
                            if (added)
                            {
                                candidateDistances[c] = math.min(candidateDistances[c], math.length(delta.xw));
                            }
                            else
                            {
                                candidateChannels.Add(i);
                                candidateDistances.Add(math.length(delta.xw));
                                added = true;
                            }
                        }
                        if (math.all(delta.yw > bestAngleDeltas.yw))
                        {
                            if (added)
                            {
                                candidateDistances[c] = math.min(candidateDistances[c], math.length(delta.yw));
                            }
                            else
                            {
                                candidateChannels.Add(i);
                                candidateDistances.Add(math.length(delta.yw));
                            }
                        }
                    }

                    //Compute weights
                    float sum = 0f;
                    for (int i = 0; i < candidateDistances.Length; i++)
                    {
                        candidateDistances[i] = 1f / candidateDistances[i];
                        sum += candidateDistances[i];
                    }
                    for (int i = 0; i < candidateDistances.Length; i++)
                    {
                        weights.channelWeights[candidateChannels[i] + profile.anglesPerLeftChannel.Length] = candidateDistances[i] / sum;
                    }
                }

                //Combine left and right
                float combinedWeightSum = 0f;
                for (int i = 0; i < profile.anglesPerLeftChannel.Length; i++)
                {
                    weights.channelWeights[i] *= profile.filterVolumesPerLeftChannel[i] * (1f - profile.passthroughFractionsPerLeftChannel[i]) +
                                                 profile.passthroughVolumesPerLeftChannel[i] * profile.passthroughFractionsPerLeftChannel[i];
                    combinedWeightSum += weights.channelWeights[i];
                }
                for (int i = 0; i < profile.anglesPerRightChannel.Length; i++)
                {
                    weights.channelWeights[i + profile.anglesPerLeftChannel.Length] *= profile.filterVolumesPerRightChannel[i] *
                                                                                       (1f - profile.passthroughFractionsPerRightChannel[i]) +
                                                                                       profile.passthroughVolumesPerRightChannel[i] *
                                                                                       profile.passthroughFractionsPerRightChannel[i];
                    combinedWeightSum += weights.channelWeights[i + profile.anglesPerLeftChannel.Length];
                }
                for (int i = 0; i < weights.channelWeights.Length; i++)
                {
                    weights.channelWeights[i] /= combinedWeightSum;
                }
            }