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); }); }
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); }); }
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]); } }
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]); } }
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]); } }
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]); } }
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; } }