diff --git a/doc/KKAPI.Utilities.md b/doc/KKAPI.Utilities.md index 1a7ecb9..692db51 100644 --- a/doc/KKAPI.Utilities.md +++ b/doc/KKAPI.Utilities.md @@ -288,6 +288,7 @@ Static Methods | Type | Name | Summary | | --- | --- | --- | | `Texture2D` | LoadTexture(this `Byte[]` texBytes, `TextureFormat` format = ARGB32, `Boolean` mipMaps = False) | Create texture from an image stored in a byte array, for example a png file read from disk. | +| `Texture2D` | ResizeTexture(this `Texture2D` pSource, `ImageFilterMode` pFilterMode, `Single` pScale) | Create a resized copy of this texture. http://blog.collectivemass.com/2014/03/resizing-textures-in-unity/ | | `Sprite` | ToSprite(this `Texture2D` texture) | Create a sprite based on this texture. | | `Texture2D` | ToTexture2D(this `Texture` tex, `TextureFormat` format = ARGB32, `Boolean` mipMaps = False) | Copy this texture inside a new editable Texture2D. | diff --git a/src/Shared.Core/Utilities/TextureUtils.cs b/src/Shared.Core/Utilities/TextureUtils.cs index b4b25f2..c4865aa 100644 --- a/src/Shared.Core/Utilities/TextureUtils.cs +++ b/src/Shared.Core/Utilities/TextureUtils.cs @@ -53,5 +53,144 @@ public static Sprite ToSprite(this Texture2D texture) if (texture == null) throw new ArgumentNullException(nameof(texture)); return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f)); } + + /// + /// Filtering to use when resizing a texture + /// + public enum ImageFilterMode + { + /// + /// Nearest pixel, fastest but gets aliased + /// + Nearest = 0, + /// + /// Use bilinear scaling + /// + Biliner = 1, + /// + /// Average of all nearby pixels + /// + Average = 2 + } + + /// + /// Create a resized copy of this texture. + /// http://blog.collectivemass.com/2014/03/resizing-textures-in-unity/ + /// + /// Texture to resize + /// How to resize + /// New scale + public static Texture2D ResizeTexture(this Texture2D pSource, ImageFilterMode pFilterMode, float pScale) + { + //*** Variables + int i; + + //*** Get All the source pixels + Color[] aSourceColor = pSource.GetPixels(0); + Vector2 vSourceSize = new Vector2(pSource.width, pSource.height); + + //*** Calculate New Size + float xWidth = Mathf.RoundToInt((float)pSource.width * pScale); + float xHeight = Mathf.RoundToInt((float)pSource.height * pScale); + + //*** Make New + Texture2D oNewTex = new Texture2D((int)xWidth, (int)xHeight, TextureFormat.RGBA32, false); + + //*** Make destination array + int xLength = (int)xWidth * (int)xHeight; + Color[] aColor = new Color[xLength]; + + Vector2 vPixelSize = new Vector2(vSourceSize.x / xWidth, vSourceSize.y / xHeight); + + //*** Loop through destination pixels and process + Vector2 vCenter = new Vector2(); + for (i = 0; i < xLength; i++) + { + + //*** Figure out x&y + float xX = (float)i % xWidth; + float xY = Mathf.Floor((float)i / xWidth); + + //*** Calculate Center + vCenter.x = (xX / xWidth) * vSourceSize.x; + vCenter.y = (xY / xHeight) * vSourceSize.y; + + //*** Do Based on mode + //*** Nearest neighbour (testing) + if (pFilterMode == ImageFilterMode.Nearest) + { + + //*** Nearest neighbour (testing) + vCenter.x = Mathf.Round(vCenter.x); + vCenter.y = Mathf.Round(vCenter.y); + + //*** Calculate source index + int xSourceIndex = (int)((vCenter.y * vSourceSize.x) + vCenter.x); + + //*** Copy Pixel + aColor[i] = aSourceColor[xSourceIndex]; + } + + //*** Bilinear + else if (pFilterMode == ImageFilterMode.Biliner) + { + + //*** Get Ratios + float xRatioX = vCenter.x - Mathf.Floor(vCenter.x); + float xRatioY = vCenter.y - Mathf.Floor(vCenter.y); + + //*** Get Pixel index's + int xIndexTL = (int)((Mathf.Floor(vCenter.y) * vSourceSize.x) + Mathf.Floor(vCenter.x)); + int xIndexTR = (int)((Mathf.Floor(vCenter.y) * vSourceSize.x) + Mathf.Ceil(vCenter.x)); + int xIndexBL = (int)((Mathf.Ceil(vCenter.y) * vSourceSize.x) + Mathf.Floor(vCenter.x)); + int xIndexBR = (int)((Mathf.Ceil(vCenter.y) * vSourceSize.x) + Mathf.Ceil(vCenter.x)); + + //*** Calculate Color + aColor[i] = Color.Lerp( + Color.Lerp(aSourceColor[xIndexTL], aSourceColor[xIndexTR], xRatioX), + Color.Lerp(aSourceColor[xIndexBL], aSourceColor[xIndexBR], xRatioX), + xRatioY + ); + } + + //*** Average + else if (pFilterMode == ImageFilterMode.Average) + { + + //*** Calculate grid around point + int xXFrom = (int)Mathf.Max(Mathf.Floor(vCenter.x - (vPixelSize.x * 0.5f)), 0); + int xXTo = (int)Mathf.Min(Mathf.Ceil(vCenter.x + (vPixelSize.x * 0.5f)), vSourceSize.x); + int xYFrom = (int)Mathf.Max(Mathf.Floor(vCenter.y - (vPixelSize.y * 0.5f)), 0); + int xYTo = (int)Mathf.Min(Mathf.Ceil(vCenter.y + (vPixelSize.y * 0.5f)), vSourceSize.y); + + //*** Loop and accumulate + Vector4 oColorTotal = new Vector4(); + Color oColorTemp = new Color(); + float xGridCount = 0; + for (int iy = xYFrom; iy < xYTo; iy++) + { + for (int ix = xXFrom; ix < xXTo; ix++) + { + + //*** Get Color + oColorTemp += aSourceColor[(int)(((float)iy * vSourceSize.x) + ix)]; + + //*** Sum + xGridCount++; + } + } + + //*** Average Color + aColor[i] = oColorTemp / (float)xGridCount; + } + } + + //*** Set Pixels + oNewTex.SetPixels(aColor); + oNewTex.Apply(); + + //*** Return + return oNewTex; + } } }