From eaa6864fa38e4d40233489c96011d9ef4a42f77b Mon Sep 17 00:00:00 2001 From: JohnCorby Date: Wed, 19 Jul 2023 20:42:17 -0700 Subject: [PATCH] draft out some code. this is my therapy --- .../Utility/Files/NHTexture/CanvasScale.cs | 43 +++++++++++++ .../Files/NHTexture/ITextureOperation.cs | 9 +++ .../Utility/Files/NHTexture/LerpGreyscale.cs | 33 ++++++++++ NewHorizons/Utility/Files/NHTexture/Load.cs | 44 ++++++++++++++ .../Utility/Files/NHTexture/MakeClear.cs | 37 ++++++++++++ .../Utility/Files/NHTexture/NHTexture.cs | 59 ++++++++++++++++++ .../Utility/Files/NHTexture/Outline.cs | 60 +++++++++++++++++++ .../Utility/Files/NHTexture/SlideInvert.cs | 38 ++++++++++++ NewHorizons/Utility/Files/NHTexture/Tint.cs | 31 ++++++++++ 9 files changed, 354 insertions(+) create mode 100644 NewHorizons/Utility/Files/NHTexture/CanvasScale.cs create mode 100644 NewHorizons/Utility/Files/NHTexture/ITextureOperation.cs create mode 100644 NewHorizons/Utility/Files/NHTexture/LerpGreyscale.cs create mode 100644 NewHorizons/Utility/Files/NHTexture/Load.cs create mode 100644 NewHorizons/Utility/Files/NHTexture/MakeClear.cs create mode 100644 NewHorizons/Utility/Files/NHTexture/NHTexture.cs create mode 100644 NewHorizons/Utility/Files/NHTexture/Outline.cs create mode 100644 NewHorizons/Utility/Files/NHTexture/SlideInvert.cs create mode 100644 NewHorizons/Utility/Files/NHTexture/Tint.cs diff --git a/NewHorizons/Utility/Files/NHTexture/CanvasScale.cs b/NewHorizons/Utility/Files/NHTexture/CanvasScale.cs new file mode 100644 index 00000000..c0b2602d --- /dev/null +++ b/NewHorizons/Utility/Files/NHTexture/CanvasScale.cs @@ -0,0 +1,43 @@ +using UnityEngine; + +namespace NewHorizons.Utility.Files.NHTexture; + +public class CanvasScale : ITextureOperation +{ + private readonly int _width; + private readonly int _height; + + public CanvasScale(int width, int height) + { + _width = width; + _height = height; + } + + public string Description => $"canvas scale {_width} {_height}"; + + public Texture2D Apply(Texture2D src) + { + var dest = new Texture2D(_width, _height, src.format, src.mipmapCount != 1); + dest.name = Description; + var fillPixels = new Color[dest.width * dest.height]; + for (int i = 0; i < dest.width; i++) + { + for (int j = 0; j < dest.height; j++) + { + var x = i + (dest.width - _width) / 2; + var y = j + (dest.height - _height) / 2; + + var colour = Color.black; + if (x < dest.width && y < dest.height) colour = dest.GetPixel(i, j); + + fillPixels[i + j * dest.width] = colour; + } + } + dest.SetPixels(fillPixels); + dest.Apply(); + + dest.wrapMode = dest.wrapMode; + + return dest; + } +} diff --git a/NewHorizons/Utility/Files/NHTexture/ITextureOperation.cs b/NewHorizons/Utility/Files/NHTexture/ITextureOperation.cs new file mode 100644 index 00000000..19e59e46 --- /dev/null +++ b/NewHorizons/Utility/Files/NHTexture/ITextureOperation.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +namespace NewHorizons.Utility.Files.NHTexture; + +public interface ITextureOperation +{ + public string Description { get; } + public Texture2D Apply(Texture2D src); +} \ No newline at end of file diff --git a/NewHorizons/Utility/Files/NHTexture/LerpGreyscale.cs b/NewHorizons/Utility/Files/NHTexture/LerpGreyscale.cs new file mode 100644 index 00000000..fc4fe32c --- /dev/null +++ b/NewHorizons/Utility/Files/NHTexture/LerpGreyscale.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +namespace NewHorizons.Utility.Files.NHTexture; + +public class LerpGreyscale : ITextureOperation +{ + private readonly Color _lightTint; + private readonly Color _darkTint; + + public LerpGreyscale(Color lightTint, Color darkTint) + { + _lightTint = lightTint; + _darkTint = darkTint; + } + + public string Description => $"lerp greyscale {_lightTint} {_darkTint}"; + + public Texture2D Apply(Texture2D src) + { + var pixels = src.GetPixels(); + for (int i = 0; i < pixels.Length; i++) + { + pixels[i].r = Mathf.Lerp(_darkTint.r, _lightTint.r, pixels[i].r); + pixels[i].g = Mathf.Lerp(_darkTint.g, _lightTint.g, pixels[i].g); + pixels[i].b = Mathf.Lerp(_darkTint.b, _lightTint.b, pixels[i].b); + } + + src.SetPixels(pixels); + src.Apply(); + + return null; + } +} diff --git a/NewHorizons/Utility/Files/NHTexture/Load.cs b/NewHorizons/Utility/Files/NHTexture/Load.cs new file mode 100644 index 00000000..736b64ab --- /dev/null +++ b/NewHorizons/Utility/Files/NHTexture/Load.cs @@ -0,0 +1,44 @@ +using OWML.Common; +using System.IO; +using UnityEngine; + +namespace NewHorizons.Utility.Files.NHTexture; + +public class Load : ITextureOperation +{ + private readonly IModBehaviour _mod; + private readonly string _filename; + private readonly bool _useMipmaps; + private readonly bool _wrap; + private readonly bool _linear; + + public Load(IModBehaviour mod, string filename, bool useMipmaps = true, bool wrap = false, bool linear = false) + { + _mod = mod; + _filename = filename; + _useMipmaps = useMipmaps; + _wrap = wrap; + _linear = linear; + + var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, filename); + var key = GetKey(path); + Description = $"load {key} {useMipmaps} {wrap} {linear}"; + } + + public string Description { get; } + + public Texture2D Apply(Texture2D src) + { + var path = Path.Combine(_mod.ModHelper.Manifest.ModFolderPath, _filename); + + var data = File.ReadAllBytes(path); + var dest = new Texture2D(2, 2, TextureFormat.RGBA32, _useMipmaps, _linear); + dest.name = Description; + dest.wrapMode = _wrap ? TextureWrapMode.Repeat : TextureWrapMode.Clamp; + dest.LoadImage(data); + + return dest; + } + + private static string GetKey(string path) => path.Substring(Main.Instance.ModHelper.OwmlConfig.ModsPath.Length); +} diff --git a/NewHorizons/Utility/Files/NHTexture/MakeClear.cs b/NewHorizons/Utility/Files/NHTexture/MakeClear.cs new file mode 100644 index 00000000..9c07b960 --- /dev/null +++ b/NewHorizons/Utility/Files/NHTexture/MakeClear.cs @@ -0,0 +1,37 @@ +using UnityEngine; + +namespace NewHorizons.Utility.Files.NHTexture; + +public class MakeClear : ITextureOperation +{ + private readonly int _width; + private readonly int _height; + private readonly bool _wrap; + + public MakeClear(int width, int height, bool wrap = false) + { + _width = width; + _height = height; + _wrap = wrap; + } + + public string Description => $"clear {_width} {_height} {_wrap}"; + + public Texture2D Apply(Texture2D src) + { + var dest = new Texture2D(1, 1, TextureFormat.ARGB32, false); + dest.name = Description; + var fillColor = Color.clear; + var fillPixels = new Color[dest.width * dest.height]; + for (int i = 0; i < fillPixels.Length; i++) + { + fillPixels[i] = fillColor; + } + dest.SetPixels(fillPixels); + dest.Apply(); + + dest.wrapMode = _wrap ? TextureWrapMode.Repeat : TextureWrapMode.Clamp; + + return dest; + } +} diff --git a/NewHorizons/Utility/Files/NHTexture/NHTexture.cs b/NewHorizons/Utility/Files/NHTexture/NHTexture.cs new file mode 100644 index 00000000..6e60939f --- /dev/null +++ b/NewHorizons/Utility/Files/NHTexture/NHTexture.cs @@ -0,0 +1,59 @@ +using HarmonyLib; +using NewHorizons.Utility.OWML; +using System; +using System.Collections.Generic; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace NewHorizons.Utility.Files.NHTexture; + +public class NHTexture +{ + private static readonly Dictionary _cache = new(); + + private readonly List _operations = new(); + + public void AddOperation(ITextureOperation operation) + { + _operations.Add(operation); + } + + public Texture2D Apply() + { + var cacheKey = _operations.Join(x => x.Description, " > "); + if (_cache.TryGetValue(cacheKey, out var texture)) + { + return texture; + } + + ITextureOperation operation = null; + try + { + for (var i = 0; i < _operations.Count; i++) + { + operation = _operations[i]; + var src = texture; + var dest = operation.Apply(src); + if (dest != null) + { + // makes new texture. destroy the old one + Object.DestroyImmediate(src); + texture = dest; + } + else + { + // mutates src. keep it around + texture = src; + } + } + } + catch (Exception e) + { + NHLogger.LogVerbose($"Exception thrown while performing NHTexture operation {(operation != null ? operation.Description : "NULL")} on texture {(texture != null ? texture.name : "NULL")}:\n{e}"); + return null; + } + + _cache.Add(cacheKey, texture); + return texture; + } +} diff --git a/NewHorizons/Utility/Files/NHTexture/Outline.cs b/NewHorizons/Utility/Files/NHTexture/Outline.cs new file mode 100644 index 00000000..529394c6 --- /dev/null +++ b/NewHorizons/Utility/Files/NHTexture/Outline.cs @@ -0,0 +1,60 @@ +using UnityEngine; + +namespace NewHorizons.Utility.Files.NHTexture; + +public class Outline : ITextureOperation +{ + private readonly Color _color; + private readonly int _thickness; + + public Outline(Color color, int thickness) + { + _color = color; + _thickness = thickness; + } + + public string Description => $"outline {_color} {_thickness}"; + + public Texture2D Apply(Texture2D src) + { + var outlinePixels = new Color[src.width * src.height]; + var pixels = src.GetPixels(); + + for (int x = 0; x < src.width; x++) + { + for (int y = 0; y < src.height; y++) + { + var fillColor = new Color(0, 0, 0, 0); + + if (pixels[x + y * src.width].a == 1 && CloseToTransparent(pixels, src.width, src.height, x, y, _thickness)) + { + fillColor = _color; + } + outlinePixels[x + y * src.width] = fillColor; + } + } + + src.SetPixels(outlinePixels); + src.Apply(); + + return null; + } + + private static bool CloseToTransparent(Color[] pixels, int width, int height, int x, int y, int thickness) + { + // Check nearby + var minX = Mathf.Max(0, x - thickness / 2); + var minY = Mathf.Max(0, y - thickness / 2); + var maxX = Mathf.Min(width, x + thickness / 2); + var maxY = Mathf.Min(height, y + thickness / 2); + + for (int i = minX; i < maxX; i++) + { + for (int j = minY; j < maxY; j++) + { + if (pixels[i + j * width].a < 1) return true; + } + } + return false; + } +} diff --git a/NewHorizons/Utility/Files/NHTexture/SlideInvert.cs b/NewHorizons/Utility/Files/NHTexture/SlideInvert.cs new file mode 100644 index 00000000..1c427ba4 --- /dev/null +++ b/NewHorizons/Utility/Files/NHTexture/SlideInvert.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace NewHorizons.Utility.Files.NHTexture; + +public class SlideInvert : ITextureOperation +{ + public string Description => "slide invert"; + + public Texture2D Apply(Texture2D src) + { + var pixels = src.GetPixels(); + for (var i = 0; i < pixels.Length; i++) + { + var x = i % src.width; + var y = i / src.height; + + // Needs a black border + if (x == 0 || y == 0 || x == src.width - 1 || y == src.height - 1) + { + pixels[i].r = 1; + pixels[i].g = 1; + pixels[i].b = 1; + pixels[i].a = 1; + } + else + { + pixels[i].r = 1f - pixels[i].r; + pixels[i].g = 1f - pixels[i].g; + pixels[i].b = 1f - pixels[i].b; + } + } + + src.SetPixels(pixels); + src.Apply(); + + return null; + } +} diff --git a/NewHorizons/Utility/Files/NHTexture/Tint.cs b/NewHorizons/Utility/Files/NHTexture/Tint.cs new file mode 100644 index 00000000..cec99343 --- /dev/null +++ b/NewHorizons/Utility/Files/NHTexture/Tint.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +namespace NewHorizons.Utility.Files.NHTexture; + +public class Tint : ITextureOperation +{ + private readonly Color _tint; + + public Tint(Color tint) + { + _tint = tint; + } + + public string Description => $"tint {_tint}"; + + public Texture2D Apply(Texture2D src) + { + var pixels = src.GetPixels(); + for (int i = 0; i < pixels.Length; i++) + { + pixels[i].r *= _tint.r; + pixels[i].g *= _tint.g; + pixels[i].b *= _tint.b; + } + + src.SetPixels(pixels); + src.Apply(); + + return null; + } +}