2017-04-12 01:23:07 +09:00

263 lines
4.9 KiB
C#

using UnityEngine;
using System.Collections.Generic;
public static class D2D_SplitCalculator
{
class Fill
{
public List<int> Indices = new List<int>();
public List<Color32> Colours = new List<Color32>();
public int Count;
public int XMin;
public int XMax;
public int YMin;
public int YMax;
public bool Valid;
}
class Spread
{
public int i;
public int x;
public int y;
}
private static D2D_Destructible target;
private static List<bool> cells = new List<bool>();
private static List<Fill> fills = new List<Fill>();
private static List<Spread> spreads = new List<Spread>();
private static int spreadCount;
private static Fill currentFill;
private static Color32[] pixels;
private static Texture2D tex;
private static int width;
private static int height;
private static int total;
public static bool Generate(D2D_Destructible destructible, D2D_SpriteSplitOrder splitOrder)
{
cells.Clear();
if (destructible != null && destructible.AlphaTex != null)
{
target = destructible;
tex = target.AlphaTex;
width = tex.width;
height = tex.height;
total = width * height;
pixels = tex.GetPixels32();
if (cells.Capacity < total)
{
cells.Capacity = total;
}
var threshold = (byte)(target.SplitThreshold * 255.0f);
for (var i = 0; i < total; i++)
{
cells.Add(pixels[i].a >= threshold);
}
fills.Clear();
var validFillCount = 0;
for (var i = 0; i < total; i++)
{
if (cells[i] == true)
{
currentFill = new Fill(); fills.Add(currentFill);
currentFill.XMin = currentFill.XMax = i % width;
currentFill.YMin = currentFill.YMax = i / width;
BeginFloodFill(i, currentFill.XMin, currentFill.YMin);
// Skip the first floodfill
if (currentFill.Count >= target.SplitMinPixels)
{
currentFill.Valid = true; validFillCount += 1;
}
}
}
// Can we split?
if (validFillCount > 1)
{
var firstSet = false;
switch (splitOrder)
{
case D2D_SpriteSplitOrder.KeepLargest: fills.Sort((a, b) => b.Count.CompareTo(a.Count)); break;
case D2D_SpriteSplitOrder.KeepSmallest: fills.Sort((a, b) => a.Count.CompareTo(b.Count)); break;
}
foreach (var fill in fills)
{
if (fill.Valid == true)
{
if (firstSet == false)
{
firstSet = true;
Split(destructible, fill, false);
}
else
{
var clonedGameObject = D2D_Helper.CloneGameObject(destructible.gameObject, destructible.transform.parent);
var clonedDestructible = clonedGameObject.GetComponent<D2D_Destructible>();
Split(clonedDestructible, fill, true);
}
}
}
return true;
}
if (validFillCount == 0)
{
D2D_Helper.Destroy(destructible.gameObject);
}
}
return false;
}
private static void Split(D2D_Destructible destructible, Fill fill, bool isClone)
{
var clear = new Color32(0, 0, 0, 0);
for (var i = 0; i < total; i++)
{
pixels[i] = clear;
}
for (var i = 0; i < fill.Count; i++)
{
pixels[fill.Indices[i]] = fill.Colours[i];
}
destructible.ReplaceAlphaWith(width, height, pixels);
// Split notification
destructible.BroadcastMessage("OnSpriteSplit", isClone, SendMessageOptions.DontRequireReceiver);
}
private static void BeginFloodFill(int i, int x, int y)
{
var oldSpreadCount = spreadCount = 0;
SpreadTo(i, x, y);
// Non-recursive floodfill
while (spreadCount != oldSpreadCount)
{
var start = oldSpreadCount;
var end = oldSpreadCount = spreadCount;
for (var j = start; j < end; j++)
{
var spread = spreads[j];
FloodFill(spread.i, spread.x, spread.y);
}
}
}
private static void SpreadTo(int i, int x, int y)
{
cells[i] = false;
var spread = default(Spread);
if (spreadCount >= spreads.Count)
{
spread = new Spread(); spreads.Add(spread);
}
else
{
spread = spreads[spreadCount];
}
spread.i = i;
spread.x = x;
spread.y = y;
spreadCount += 1;
}
private static void FloodFill(int i, int x, int y)
{
currentFill.Count += 1;
currentFill.Indices.Add(i);
currentFill.Colours.Add(pixels[i]);
currentFill.XMin = Mathf.Min(currentFill.XMin, x);
currentFill.XMax = Mathf.Max(currentFill.XMax, x);
currentFill.YMin = Mathf.Min(currentFill.YMin, y);
currentFill.YMax = Mathf.Max(currentFill.YMax, y);
// Left
if (x > 0)
{
var n = i - 1;
if (cells[n] == true)
{
SpreadTo(n, x - 1, y);
}
}
// Right
if (x < width - 1)
{
var n = i + 1;
if (cells[n] == true)
{
SpreadTo(n, x + 1, y);
}
}
// Bottom
if (y > 0)
{
var n = i - width;
if (cells[n] == true)
{
SpreadTo(n, x, y - 1);
}
}
// Top
if (y < height - 1)
{
var n = i + width;
if (cells[n] == true)
{
SpreadTo(n, x, y + 1);
}
}
}
}