-
Notifications
You must be signed in to change notification settings - Fork 42
/
TextureUtils.cs
196 lines (162 loc) · 7.37 KB
/
TextureUtils.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
using System;
using UnityEngine;
namespace KKAPI.Utilities
{
/// <summary>
/// Utility methods for working with texture objects.
/// </summary>
public static class TextureUtils
{
/// <summary>
/// Copy this texture inside a new editable Texture2D.
/// </summary>
/// <param name="tex">Texture to copy</param>
/// <param name="format">Format of the copy</param>
/// <param name="mipMaps">Copy has mipmaps</param>
public static Texture2D ToTexture2D(this Texture tex, TextureFormat format = TextureFormat.ARGB32, bool mipMaps = false)
{
var rt = RenderTexture.GetTemporary(tex.width, tex.height);
var prev = RenderTexture.active;
RenderTexture.active = rt;
GL.Clear(true, true, Color.clear);
Graphics.Blit(tex, rt);
var t = new Texture2D(tex.width, tex.height, format, mipMaps);
t.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
t.Apply(false);
RenderTexture.active = prev;
RenderTexture.ReleaseTemporary(rt);
return t;
}
/// <summary>
/// Create texture from an image stored in a byte array, for example a png file read from disk.
/// </summary>
public static Texture2D LoadTexture(this byte[] texBytes, TextureFormat format = TextureFormat.ARGB32, bool mipMaps = false)
{
if (texBytes == null) throw new ArgumentNullException(nameof(texBytes));
var tex = new Texture2D(2, 2, format, mipMaps);
tex.LoadImage(texBytes);
return tex;
}
/// <summary>
/// Create a sprite based on this texture.
/// </summary>
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));
}
/// <summary>
/// Filtering to use when resizing a texture
/// </summary>
public enum ImageFilterMode
{
/// <summary>
/// Nearest pixel, fastest but gets aliased
/// </summary>
Nearest = 0,
/// <summary>
/// Use bilinear scaling
/// </summary>
Biliner = 1,
/// <summary>
/// Average of all nearby pixels
/// </summary>
Average = 2
}
/// <summary>
/// Create a resized copy of this texture.
/// http://blog.collectivemass.com/2014/03/resizing-textures-in-unity/
/// </summary>
/// <param name="pSource">Texture to resize</param>
/// <param name="pFilterMode">How to resize</param>
/// <param name="pScale">New scale</param>
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;
}
}
}