261 lines
6.6 KiB
C#
261 lines
6.6 KiB
C#
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using UnityEngine;
|
|
|
|
namespace uGIF
|
|
{
|
|
public class Image
|
|
{
|
|
public int width;
|
|
public int height;
|
|
public Color32[] pixels;
|
|
|
|
public Image (Texture2D f)
|
|
{
|
|
pixels = f.GetPixels32 ();
|
|
width = f.width;
|
|
height = f.height;
|
|
}
|
|
|
|
public Image (Image image)
|
|
{
|
|
pixels = image.pixels.Clone () as Color32[];
|
|
width = image.width;
|
|
height = image.height;
|
|
}
|
|
|
|
public Image (int width, int height)
|
|
{
|
|
this.width = width;
|
|
this.height = height;
|
|
pixels = new Color32[width * height];
|
|
}
|
|
|
|
public void DrawImage (Image image, int i, int i2)
|
|
{
|
|
throw new System.NotImplementedException ();
|
|
}
|
|
|
|
public Color32 GetPixel (int tw, int th)
|
|
{
|
|
var index = (th * width) + tw;
|
|
return pixels [index];
|
|
}
|
|
|
|
public void Flip ()
|
|
{
|
|
if (pixels == null || pixels.Length == 0 || width <= 0 || height <= 1)
|
|
return;
|
|
|
|
using (var source = new NativeArray<Color32>(pixels, Allocator.TempJob))
|
|
using (var destination = new NativeArray<Color32>(pixels.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory))
|
|
{
|
|
new FlipVerticalJob
|
|
{
|
|
Source = source,
|
|
Destination = destination,
|
|
Width = width,
|
|
Height = height
|
|
}.Schedule(pixels.Length, 256).Complete();
|
|
|
|
destination.CopyTo(pixels);
|
|
}
|
|
}
|
|
|
|
public void Resize (int scale)
|
|
{
|
|
if (scale <= 1)
|
|
return;
|
|
var newWidth = width / scale;
|
|
var newHeight = height / scale;
|
|
if (newWidth <= 0 || newHeight <= 0)
|
|
return;
|
|
|
|
var newColors = new Color32[newWidth * newHeight];
|
|
using (var source = new NativeArray<Color32>(pixels, Allocator.TempJob))
|
|
using (var destination = new NativeArray<Color32>(newColors.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory))
|
|
{
|
|
new PointResizeJob
|
|
{
|
|
Source = source,
|
|
Destination = destination,
|
|
SourceWidth = width,
|
|
DestinationWidth = newWidth,
|
|
Scale = scale
|
|
}.Schedule(newColors.Length, 256).Complete();
|
|
|
|
destination.CopyTo(newColors);
|
|
}
|
|
|
|
pixels = newColors;
|
|
height = newHeight;
|
|
width = newWidth;
|
|
}
|
|
|
|
public void ResizeBilinear (int newWidth, int newHeight)
|
|
{
|
|
if (newWidth == width && newHeight == height)
|
|
return;
|
|
if (newWidth <= 0 || newHeight <= 0 || width <= 0 || height <= 0)
|
|
return;
|
|
if (width == 1 || height == 1)
|
|
{
|
|
ResizeNearest(newWidth, newHeight);
|
|
return;
|
|
}
|
|
|
|
var texColors = pixels;
|
|
var newColors = new Color32[newWidth * newHeight];
|
|
var ratioX = 1.0f / ((float)newWidth / (width - 1));
|
|
var ratioY = 1.0f / ((float)newHeight / (height - 1));
|
|
|
|
using (var source = new NativeArray<Color32>(texColors, Allocator.TempJob))
|
|
using (var destination = new NativeArray<Color32>(newColors.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory))
|
|
{
|
|
new BilinearResizeJob
|
|
{
|
|
Source = source,
|
|
Destination = destination,
|
|
SourceWidth = width,
|
|
SourceHeight = height,
|
|
DestinationWidth = newWidth,
|
|
RatioX = ratioX,
|
|
RatioY = ratioY
|
|
}.Schedule(newColors.Length, 256).Complete();
|
|
|
|
destination.CopyTo(newColors);
|
|
}
|
|
|
|
pixels = newColors;
|
|
height = newHeight;
|
|
width = newWidth;
|
|
}
|
|
|
|
private void ResizeNearest(int newWidth, int newHeight)
|
|
{
|
|
var newColors = new Color32[newWidth * newHeight];
|
|
using (var source = new NativeArray<Color32>(pixels, Allocator.TempJob))
|
|
using (var destination = new NativeArray<Color32>(newColors.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory))
|
|
{
|
|
new NearestResizeJob
|
|
{
|
|
Source = source,
|
|
Destination = destination,
|
|
SourceWidth = width,
|
|
SourceHeight = height,
|
|
DestinationWidth = newWidth,
|
|
DestinationHeight = newHeight
|
|
}.Schedule(newColors.Length, 256).Complete();
|
|
|
|
destination.CopyTo(newColors);
|
|
}
|
|
|
|
pixels = newColors;
|
|
width = newWidth;
|
|
height = newHeight;
|
|
}
|
|
|
|
[BurstCompile]
|
|
private struct FlipVerticalJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<Color32> Source;
|
|
[WriteOnly] public NativeArray<Color32> Destination;
|
|
public int Width;
|
|
public int Height;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
int y = index / Width;
|
|
int x = index - y * Width;
|
|
Destination[index] = Source[(Height - 1 - y) * Width + x];
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
private struct PointResizeJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<Color32> Source;
|
|
[WriteOnly] public NativeArray<Color32> Destination;
|
|
public int SourceWidth;
|
|
public int DestinationWidth;
|
|
public int Scale;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
int y = index / DestinationWidth;
|
|
int x = index - y * DestinationWidth;
|
|
Destination[index] = Source[(y * Scale) * SourceWidth + x * Scale];
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
private struct NearestResizeJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<Color32> Source;
|
|
[WriteOnly] public NativeArray<Color32> Destination;
|
|
public int SourceWidth;
|
|
public int SourceHeight;
|
|
public int DestinationWidth;
|
|
public int DestinationHeight;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
int y = index / DestinationWidth;
|
|
int x = index - y * DestinationWidth;
|
|
int sourceX = x * SourceWidth / DestinationWidth;
|
|
int sourceY = y * SourceHeight / DestinationHeight;
|
|
Destination[index] = Source[sourceY * SourceWidth + sourceX];
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
private struct BilinearResizeJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<Color32> Source;
|
|
[WriteOnly] public NativeArray<Color32> Destination;
|
|
public int SourceWidth;
|
|
public int SourceHeight;
|
|
public int DestinationWidth;
|
|
public float RatioX;
|
|
public float RatioY;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
int y = index / DestinationWidth;
|
|
int x = index - y * DestinationWidth;
|
|
float sourceX = x * RatioX;
|
|
float sourceY = y * RatioY;
|
|
int xFloor = (int)sourceX;
|
|
int yFloor = (int)sourceY;
|
|
|
|
if (xFloor >= SourceWidth - 1)
|
|
xFloor = SourceWidth - 2;
|
|
if (yFloor >= SourceHeight - 1)
|
|
yFloor = SourceHeight - 2;
|
|
|
|
float xLerp = sourceX - xFloor;
|
|
float yLerp = sourceY - yFloor;
|
|
int row0 = yFloor * SourceWidth;
|
|
int row1 = (yFloor + 1) * SourceWidth;
|
|
|
|
Color32 top = LerpColor32(Source[row0 + xFloor], Source[row0 + xFloor + 1], xLerp);
|
|
Color32 bottom = LerpColor32(Source[row1 + xFloor], Source[row1 + xFloor + 1], xLerp);
|
|
Destination[index] = LerpColor32(top, bottom, yLerp);
|
|
}
|
|
|
|
private static Color32 LerpColor32(Color32 a, Color32 b, float t)
|
|
{
|
|
Color colorA = a;
|
|
Color colorB = b;
|
|
return new Color(
|
|
colorA.r + (colorB.r - colorA.r) * t,
|
|
colorA.g + (colorB.g - colorA.g) * t,
|
|
colorA.b + (colorB.b - colorA.b) * t,
|
|
colorA.a + (colorB.a - colorA.a) * t);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|