internal static bool Fetch( string path, out uint refScale, out Vector2I size, out TextureFormat format, out Vector2B wrapped, out Vector2I padding, out Vector2I blockPadding, out byte[] data ) { refScale = 0; size = Vector2I.Zero; format = TextureFormat.Color; wrapped = Vector2B.False; padding = Vector2I.Zero; blockPadding = Vector2I.Zero; data = null; if (Config.FileCache.Enabled && File.Exists(path)) { int retries = Config.FileCache.LockRetries; while (retries-- > 0) { if (SavingMap.TryGetValue(path, out var state) && state != SaveState.Saved) { Thread.Sleep(Config.FileCache.LockSleepMS); continue; }
public void TestEquals() { Vector2B a = new Vector2B(false, true); Vector2B b = new Vector2B(true, false); Vector2B c = new Vector2B(false, true); Assert.IsTrue(a.Equals(c)); Assert.IsTrue(c.Equals(a)); Assert.IsTrue(a == c); Assert.IsTrue(c == a); Assert.IsFalse(c != a); Assert.IsFalse(c != a); Assert.IsFalse(a.Equals(b)); Assert.IsFalse(b.Equals(a)); Assert.IsFalse(a == b); Assert.IsFalse(b == a); Assert.IsTrue(a != b); Assert.IsTrue(b != a); object objA = a; object objB = b; object objC = c; Assert.IsTrue(a.Equals(objA)); Assert.IsTrue(a.Equals(objC)); Assert.IsFalse(a.Equals(objB)); Assert.IsTrue(objA.Equals(objC)); Assert.IsFalse(objA.Equals(objB)); Assert.IsFalse(a.Equals(null)); Assert.IsFalse(a.Equals(5)); }
internal Config( Vector2B wrapped, bool hasAlpha = true, double luminanceWeight = 1.0, uint equalColorTolerance = 30, double dominantDirectionThreshold = 3.6, double steepDirectionThreshold = 2.2, double centerDirectionBias = 4.0, bool gammaCorrected = true, bool useRedmean = false ) : base( wrapped: wrapped, hasAlpha: hasAlpha, gammaCorrected: gammaCorrected ) { EqualColorTolerance = equalColorTolerance << 8; DominantDirectionThreshold = dominantDirectionThreshold; SteepDirectionThreshold = steepDirectionThreshold; CenterDirectionBias = centerDirectionBias; UseRedmean = useRedmean; var adjustedLuminanceWeight = luminanceWeight / (luminanceWeight + 1.0); LuminanceWeight = adjustedLuminanceWeight * 2.0; ChrominanceWeight = (1.0 - adjustedLuminanceWeight) * 2.0; }
public void TestGetHashCode() { Vector2B a = new Vector2B(false, true); Vector2B b = new Vector2B(true, false); Vector2B c = new Vector2B(false, true); Assert.AreEqual(a.GetHashCode(), c.GetHashCode()); Assert.AreNotEqual(a.GetHashCode(), b.GetHashCode()); }
protected Config( Vector2B wrapped, bool hasAlpha, bool gammaCorrected ) { Wrapped = wrapped; HasAlpha = hasAlpha; GammaCorrected = gammaCorrected; }
internal Results( Vector2B wrapped, Vector2B wrappedX, Vector2B wrappedY, Vector2B edgeX, Vector2B edgeY ) { Wrapped = wrapped; WrappedX = wrappedX; WrappedY = wrappedY; EdgeX = edgeX; EdgeY = edgeY; }
internal static bool Save( string path, int refScale, Vector2I size, TextureFormat format, Vector2B wrapped, Vector2I padding, Vector2I blockPadding, byte[] data ) { if (Config.Cache.Enabled) { if (!SavingMap.TryAdd(path, SaveState.Saving)) { return(false); } ThreadPool.QueueUserWorkItem((object dataItem) => { var data = (byte[])dataItem; try { using (var writer = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))) { new CacheHeader() { RefScale = refScale, Size = size, Format = format, Wrapped = wrapped, Padding = padding, BlockPadding = blockPadding, DataLength = (uint)data.Length, DataHash = data.HashXX() }.Write(writer); foreach (var v in data) { writer.Write(v); } } SavingMap.TryUpdate(path, SaveState.Saved, SaveState.Saving); } catch { try { File.Delete(path); } catch { } SavingMap.TryRemove(path, out var _); } }, data); } return(true); }
internal static Span <Color16> Enhance( ReadOnlySpan <Color16> data, Vector2I size, Vector2B wrapped, int?passes = null, int?threshold = null, int?blockSize = null ) { var context = new DeposterizeContext( size: size, wrapped: wrapped, passes: passes ?? Config.Resample.Deposterization.Passes, threshold: threshold ?? Config.Resample.Deposterization.Threshold, blockSize: blockSize ?? Config.Resample.Deposterization.BlockSize, useRedmean: Config.Resample.Deposterization.UseRedmean ); return(context.Execute(data)); }
internal LegacyResults( Vector2B wrapped, Vector2B repeatX, Vector2B repeatY, Vector2B edgeX, Vector2B edgeY, Vector2B gradientAxial, Vector2B gradientDiagonal, int maxChannelShades ) { Wrapped = wrapped; RepeatX = repeatX; RepeatY = repeatY; EdgeX = edgeX; EdgeY = edgeY; GradientAxial = gradientAxial; GradientDiagonal = gradientDiagonal; MaxChannelShades = maxChannelShades; }
internal Config( Vector2B wrapped, bool hasAlpha = true, double luminanceWeight = 1.0, bool gammaCorrected = true, uint equalColorTolerance = 30, bool useRedmean = false ) : base( wrapped: wrapped, hasAlpha: hasAlpha, gammaCorrected: gammaCorrected ) { EqualColorTolerance = equalColorTolerance << 8; UseRedmean = useRedmean; var adjustedLuminanceWeight = luminanceWeight / (luminanceWeight + 1.0); LuminanceWeight = adjustedLuminanceWeight * 2.0; ChrominanceWeight = (1.0 - adjustedLuminanceWeight) * 2.0; }
internal DeposterizeContext( Vector2I size, Vector2B wrapped, int passes, int threshold, int blockSize, bool useRedmean = false ) { Size = size; Wrapped = wrapped; Passes = passes; Threshold = threshold * 256; BlockSize = blockSize; UseRedmean = useRedmean; YccConfiguration = new() { LuminanceWeight = 1.0, ChrominanceWeight = 1.0 }; }
internal Config( Vector2B wrapped, bool hasAlpha = true, bool gammaCorrected = true, float edgeStrength = 2.0f, float weight = 1.0f, float edgeShape = 0.0f, float textureShape = 0.0f, float antiRinging = 1.0f ) : base( wrapped: wrapped, hasAlpha: hasAlpha, gammaCorrected: gammaCorrected ) { EdgeStrength = edgeStrength; Weight = weight; EdgeShape = edgeShape; TextureShape = textureShape; AntiRinging = antiRinging; }
static MyTileTexture() { Vector2B[] vectorbArray1 = new Vector2B[0x10]; vectorbArray1[0] = new Vector2B(0, 0); vectorbArray1[1] = new Vector2B(1, 0); vectorbArray1[2] = new Vector2B(2, 0); vectorbArray1[3] = new Vector2B(3, 0); vectorbArray1[4] = new Vector2B(0, 1); vectorbArray1[5] = new Vector2B(1, 1); vectorbArray1[6] = new Vector2B(2, 1); vectorbArray1[7] = new Vector2B(3, 1); vectorbArray1[8] = new Vector2B(0, 2); vectorbArray1[9] = new Vector2B(1, 2); vectorbArray1[10] = new Vector2B(2, 2); vectorbArray1[11] = new Vector2B(3, 2); vectorbArray1[12] = new Vector2B(0, 3); vectorbArray1[13] = new Vector2B(1, 3); vectorbArray1[14] = new Vector2B(2, 3); vectorbArray1[15] = new Vector2B(3, 3); MyTileTexture <TPixel> .s_baseCellCoords = vectorbArray1; MyTileTexture <TPixel> .Default = new MyTileTexture <TPixel>(); }
public Config( Vector2B wrapped, bool Gamma = true, bool HasAlpha = true, double luminanceWeight = 1.0, double equalColorTolerance = 30.0, double dominantDirectionThreshold = 3.6, double steepDirectionThreshold = 2.2, double centerDirectionBias = 4.0 ) { this.Wrapped = wrapped; this.Gamma = Gamma; this.HasAlpha = HasAlpha; this.LuminanceWeight = luminanceWeight; this.EqualColorTolerance = equalColorTolerance; this.DominantDirectionThreshold = dominantDirectionThreshold; this.SteepDirectionThreshold = steepDirectionThreshold; this.CenterDirectionBias = centerDirectionBias; this.EqualColorTolerancePow2 = Math.Pow(EqualColorTolerance, 2.0); }
public void ToVector2I() { Vector2B a = new Vector2B(false, true); Vector2I sA = a.ToVector2I(); Assert.AreEqual(0, sA.X); Assert.AreEqual(1, sA.Y); }
public void TestToString() { CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture; try { Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR"); Vector2B a = new Vector2B(false, true); Assert.AreEqual("(False, True)", a.ToString()); } finally { Thread.CurrentThread.CurrentCulture = originalCulture; } }
public void Construct() { Vector2B v = new Vector2B(false, true); Assert.IsFalse(v.X); Assert.IsTrue(v.Y); }
public void ToVector2F() { Vector2B a = new Vector2B(false, true); Vector2F sA = a.ToVector2F(); Assert.AreEqual(0.0f, sA.X, 1e-7); Assert.AreEqual(1.0f, sA.Y, 1e-7); }
internal static bool Fetch( string path, out int refScale, out Vector2I size, out TextureFormat format, out Vector2B wrapped, out Vector2I padding, out Vector2I blockPadding, out byte[] data ) { refScale = 0; size = Vector2I.Zero; format = TextureFormat.Color; wrapped = Vector2B.False; padding = Vector2I.Zero; blockPadding = Vector2I.Zero; data = null; if (Config.Cache.Enabled && File.Exists(path)) { int retries = Config.Cache.LockRetries; while (retries-- > 0) { if (SavingMap.TryGetValue(path, out var state) && state != SaveState.Saved) { Thread.Sleep(Config.Cache.LockSleepMS); continue; } // https://stackoverflow.com/questions/1304/how-to-check-for-file-lock bool WasLocked(in IOException ex) { var errorCode = Marshal.GetHRForException(ex) & ((1 << 16) - 1); return(errorCode == 32 || errorCode == 33); } try { using (var reader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))) { var header = CacheHeader.Read(reader); header.Validate(path); refScale = header.RefScale; size = header.Size; format = header.Format.Value; wrapped = header.Wrapped; padding = header.Padding; blockPadding = header.BlockPadding; var dataLength = header.DataLength; var dataHash = header.DataHash; var remainingSize = reader.BaseStream.Length - reader.BaseStream.Position; if (remainingSize < header.DataLength) { throw new EndOfStreamException("Cache File is corrupted"); } data = new byte[dataLength]; foreach (int i in 0..data.Length) { data[i] = reader.ReadByte(); } if (data.HashXX() != dataHash) { throw new IOException("Cache File is corrupted"); } } return(true); } catch (Exception ex) { switch (ex) { case FileNotFoundException _: case EndOfStreamException _: case IOException iox when !WasLocked(iox): default: ex.PrintWarning(); try { File.Delete(path); } catch { } return(false); case IOException iox when WasLocked(iox): Debug.TraceLn($"File was locked when trying to load cache file '{path}': {ex.Message} [{retries} retries]"); Thread.Sleep(Config.Cache.LockSleepMS); break; } } } } return(false); }
internal static unsafe LegacyResults AnalyzeLegacy(ReadOnlySpan <Color8> data, Bounds bounds, Vector2B wrapped, bool strict = true) { var boundsInverted = bounds.Invert; if (bounds.Width < 0 || bounds.Height < 0) { Debug.Error($"Inverted Sprite Bounds Value leaked to AnalyzeLegacy: {bounds}"); boundsInverted.X = bounds.Width < 0; boundsInverted.Y = bounds.Height < 0; bounds.Width = Math.Abs(bounds.Width); bounds.Height = Math.Abs(bounds.Height); } float edgeThreshold = Config.WrapDetection.EdgeThreshold; if (strict) { var ratio = (float)bounds.Extent.MaxOf / (float)bounds.Extent.MinOf; edgeThreshold = ratio >= 4.0f ? 2.0f : 0.8f; } var wrappedXY = wrapped; var repeatX = Vector2B.False; var repeatY = Vector2B.False; if (Config.WrapDetection.Enabled) { long numSamples = 0; if (!wrappedXY.All) { for (int y = 0; y < bounds.Height; ++y) { int offset = (y + bounds.Top) * bounds.Width + bounds.Left; for (int x = 0; x < bounds.Width; ++x) { int address = offset + x; var sample = data[address]; ++numSamples; } } } byte alphaThreshold = Config.WrapDetection.AlphaThreshold; // Count the fragments that are not alphad out completely on the edges. // Both edges must meet the threshold. if (!wrappedXY.X) { var samples = stackalloc int[] { 0, 0 }; for (int y = 0; y < bounds.Height; ++y) { int offset = (y + bounds.Top) * bounds.Width + bounds.Left; var sample0 = data[offset]; var sample1 = data[offset + (bounds.Width - 1)]; if (sample0.A.Value >= alphaThreshold) { samples[0]++; } if (sample1.A.Value >= alphaThreshold) { samples[1]++; } } int threshold = (bounds.Height * edgeThreshold).NearestInt(); var aboveThreshold = Vector2B.From(samples[0] >= threshold, samples[1] >= threshold); if (aboveThreshold.All) { wrappedXY.X = true; } else { repeatX = aboveThreshold; } } if (!wrappedXY.Y) { var samples = stackalloc int[] { 0, 0 }; var offsets = stackalloc int[] { bounds.Top *bounds.Width, (bounds.Bottom - 1) * bounds.Width }; int sampler = 0; for (int i = 0; i < 2; ++i) { var yOffset = offsets[i]; for (int x = 0; x < bounds.Width; ++x) { int offset = yOffset + x + bounds.Left; var sample = data[offset]; if (sample.A.Value >= alphaThreshold) { samples[sampler]++; } } sampler++; } int threshold = (bounds.Width * edgeThreshold).NearestInt(); var aboveThreshold = Vector2B.From(samples[0] >= threshold, samples[1] >= threshold); if (aboveThreshold.All) { wrappedXY.Y = true; } else { repeatY = aboveThreshold; } } } if (wrappedXY.Any) { // Perform tests against both sides of an edge to see if they match up. If they do not, convert // a wrapped edge into a repeat edge if (wrappedXY.X) { } if (wrappedXY.Y) { } } // Gradient analysis var gradientAxial = Vector2B.True; var gradientDiagonal = Vector2B.False; // Horizontal { for (int y = bounds.Top; gradientAxial.X && y < bounds.Bottom; ++y) { int offset = (y * bounds.Width) + bounds.Left; var prevColor = data[offset]; for (int x = 1; x < bounds.Width; ++x) { var currColor = data[offset + x]; //if (Config.Resample.Analysis.UseRedmean) var difference = prevColor.RedmeanDifference(currColor, linear: false, alpha: true); if (difference >= Config.Resample.Analysis.MaxGradientColorDifference) { gradientAxial.X = false; break; } prevColor = currColor; } } } // Vertical { int offset = (bounds.Top * bounds.Width) + bounds.Left; var prevColor = data[offset]; for (int y = 1; gradientAxial.Y && y < bounds.Height; ++y) { for (int x = 0; x < bounds.Width; ++x) { var currColor = data[offset + (y * bounds.Width) + x]; //if (Config.Resample.Analysis.UseRedmean) var difference = prevColor.RedmeanDifference(currColor, linear: false, alpha: true); if (difference >= Config.Resample.Analysis.MaxGradientColorDifference) { gradientAxial.Y = false; break; } prevColor = currColor; } } } // Diagonal // TODO : use Bresenham's Line Algorithm (https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm) Span <int> shadesR = stackalloc int[byte.MaxValue + 1]; shadesR.Fill(0); Span <int> shadesG = stackalloc int[byte.MaxValue + 1]; shadesG.Fill(0); Span <int> shadesB = stackalloc int[byte.MaxValue + 1]; shadesB.Fill(0); Span <int> shadesA = stackalloc int[byte.MaxValue + 1]; shadesA.Fill(0); foreach (var color in data) { ++shadesR[color.R.Value]; ++shadesG[color.G.Value]; ++shadesB[color.B.Value]; ++shadesA[color.A.Value]; }
public void ToVector2H() { Vector2B a = new Vector2B(false, true); Vector2H sA = a.ToVector2H(); Assert.AreEqual((Half)0.0, sA.X, 1e-7); Assert.AreEqual((Half)1.0, sA.Y, 1e-7); }