using System.Collections.Generic;
using UnityEngine;
namespace Ashfall.Runtime
{
public sealed class SpriteLibrary : System.IDisposable
{
private readonly Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>();
public Material Lit { get; }
public Material Unlit { get; }
public SpriteLibrary()
{
var lit = Shader.Find("Universal Render Pipeline/2D/Sprite-Lit-Default");
var unlit = Shader.Find("Universal Render Pipeline/2D/Sprite-Unlit-Default");
Lit = new Material(lit != null ? lit : Shader.Find("Sprites/Default"));
Unlit = new Material(unlit != null ? unlit : Shader.Find("Sprites/Default"));
AddAtlas("ExpeditionAtlas", "human", 0, true);
AddAtlas("ExpeditionAtlas", "adult", 1, true);
AddAtlas("ExpeditionAtlas", "crawler", 2, false);
AddAtlas("ExpeditionAtlas", "prop", 3, false);
AddAtlas("LifeformsAtlas", "worm", 0, false);
AddAtlas("LifeformsAtlas", "beast", 1, false);
AddAtlas("LifeformsAtlas", "ark", 2, false);
AddAtlas("LifeformsAtlas", "extra", 3, false);
sprites["white"] = MakeTile("white", false, false);
sprites["soil"] = MakeTile("soil", true, false);
sprites["metal"] = MakeTile("metal", true, true);
sprites["shadow"] = MakeShadow();
}
public Sprite Get(string key) => sprites.TryGetValue(key, out var sprite) ? sprite : sprites["white"];
public void Dispose()
{
foreach (var pair in sprites)
{
if (pair.Key == "white" || pair.Key == "soil" || pair.Key == "metal" || pair.Key == "shadow") Object.Destroy(pair.Value.texture);
Object.Destroy(pair.Value);
}
sprites.Clear(); Object.Destroy(Lit); Object.Destroy(Unlit);
}
public Sprite Direction(string name, float heading)
{
int column = Mathf.RoundToInt(Mathf.Repeat(-heading, 360) / 90) % 4;
return Get(name + column);
}
private void AddAtlas(string file, string name, int row, bool feet)
{
var texture = Resources.Load<Texture2D>("Art/" + file); if (texture == null) return;
float cellW = texture.width / 4f, cellH = texture.height / 4f;
for (int column = 0; column < 4; column++)
sprites[name + column] = Sprite.Create(texture, new Rect(column * cellW, (3 - row) * cellH, cellW, cellH),
new Vector2(.5f, feet ? .12f : .5f), cellW, 0, SpriteMeshType.FullRect);
}
private static Sprite MakeTile(string name, bool noise, bool seams)
{
const int n = 64; var tex = new Texture2D(n, n, TextureFormat.RGBA32, false) { name = "Procedural " + name, filterMode = FilterMode.Bilinear, wrapMode = TextureWrapMode.Repeat };
var pixels = new Color[n * n];
for (int y = 0; y < n; y++) for (int x = 0; x < n; x++)
{
uint h = unchecked((uint)(x * 374761393 + y * 668265263 + 71)); h = (h ^ (h >> 13)) * 1274126177;
float v = noise ? .74f + (h & 255) / 255f * .22f : 1;
if (seams && (x < 2 || y < 2)) v *= .48f;
if (seams && x > 4 && x < 8 && y > 4 && y < 8) v *= .7f;
pixels[y * n + x] = new Color(v, v, v, 1);
}
tex.SetPixels(pixels); tex.Apply(); return Sprite.Create(tex, new Rect(0, 0, n, n), new Vector2(.5f, .5f), n);
}
private static Sprite MakeShadow()
{
const int n = 64; var tex = new Texture2D(n, n, TextureFormat.RGBA32, false) { name = "Contact shadow", filterMode = FilterMode.Bilinear };
var pixels = new Color[n * n];
for (int y = 0; y < n; y++) for (int x = 0; x < n; x++)
{ float d = Vector2.Distance(new Vector2(x, y), new Vector2(31.5f, 31.5f)) / 31.5f; pixels[y * n + x] = new Color(0, 0, 0, Mathf.Pow(Mathf.Clamp01(1 - d), .7f) * .7f); }
tex.SetPixels(pixels); tex.Apply(); return Sprite.Create(tex, new Rect(0, 0, n, n), new Vector2(.5f, .5f), n);
}
}
}
using System.Collections.Generic;
using UnityEngine;
namespace Ashfall.Runtime
{
public sealed class SpriteLibrary : System.IDisposable
{
private readonly Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>();
public Material Lit { get; }
public Material Unlit { get; }
public SpriteLibrary()
{
var lit = Shader.Find("Universal Render Pipeline/2D/Sprite-Lit-Default");
var unlit = Shader.Find("Universal Render Pipeline/2D/Sprite-Unlit-Default");
Lit = new Material(lit != null ? lit : Shader.Find("Sprites/Default"));
Unlit = new Material(unlit != null ? unlit : Shader.Find("Sprites/Default"));
AddAtlas("ExpeditionAtlas", "human", 0, true);
AddAtlas("ExpeditionAtlas", "adult", 1, true);
AddAtlas("ExpeditionAtlas", "crawler", 2, false);
AddAtlas("ExpeditionAtlas", "prop", 3, false);
AddAtlas("LifeformsAtlas", "worm", 0, false);
AddAtlas("LifeformsAtlas", "beast", 1, false);
AddAtlas("LifeformsAtlas", "ark", 2, false);
AddAtlas("LifeformsAtlas", "extra", 3, false);
sprites["white"] = MakeTile("white", false, false);
sprites["soil"] = MakeTile("soil", true, false);
sprites["metal"] = MakeTile("metal", true, true);
sprites["shadow"] = MakeShadow();
}
public Sprite Get(string key) => sprites.TryGetValue(key, out var sprite) ? sprite : sprites["white"];
public void Dispose()
{
foreach (var pair in sprites)
{
if (pair.Key == "white" || pair.Key == "soil" || pair.Key == "metal" || pair.Key == "shadow") Object.Destroy(pair.Value.texture);
Object.Destroy(pair.Value);
}
sprites.Clear(); Object.Destroy(Lit); Object.Destroy(Unlit);
}
public Sprite Direction(string name, float heading)
{
int column = Mathf.RoundToInt(Mathf.Repeat(-heading, 360) / 90) % 4;
return Get(name + column);
}
private void AddAtlas(string file, string name, int row, bool feet)
{
var texture = Resources.Load<Texture2D>("Art/" + file); if (texture == null) return;
float cellW = texture.width / 4f, cellH = texture.height / 4f;
for (int column = 0; column < 4; column++)
sprites[name + column] = Sprite.Create(texture, new Rect(column * cellW, (3 - row) * cellH, cellW, cellH),
new Vector2(.5f, feet ? .12f : .5f), cellW, 0, SpriteMeshType.FullRect);
}
private static Sprite MakeTile(string name, bool noise, bool seams)
{
const int n = 64; var tex = new Texture2D(n, n, TextureFormat.RGBA32, false) { name = "Procedural " + name, filterMode = FilterMode.Bilinear, wrapMode = TextureWrapMode.Repeat };
var pixels = new Color[n * n];
for (int y = 0; y < n; y++) for (int x = 0; x < n; x++)
{
uint h = unchecked((uint)(x * 374761393 + y * 668265263 + 71)); h = (h ^ (h >> 13)) * 1274126177;
float v = noise ? .74f + (h & 255) / 255f * .22f : 1;
if (seams && (x < 2 || y < 2)) v *= .48f;
if (seams && x > 4 && x < 8 && y > 4 && y < 8) v *= .7f;
pixels[y * n + x] = new Color(v, v, v, 1);
}
tex.SetPixels(pixels); tex.Apply(); return Sprite.Create(tex, new Rect(0, 0, n, n), new Vector2(.5f, .5f), n);
}
private static Sprite MakeShadow()
{
const int n = 64; var tex = new Texture2D(n, n, TextureFormat.RGBA32, false) { name = "Contact shadow", filterMode = FilterMode.Bilinear };
var pixels = new Color[n * n];
for (int y = 0; y < n; y++) for (int x = 0; x < n; x++)
{ float d = Vector2.Distance(new Vector2(x, y), new Vector2(31.5f, 31.5f)) / 31.5f; pixels[y * n + x] = new Color(0, 0, 0, Mathf.Pow(Mathf.Clamp01(1 - d), .7f) * .7f); }
tex.SetPixels(pixels); tex.Apply(); return Sprite.Create(tex, new Rect(0, 0, n, n), new Vector2(.5f, .5f), n);
}
}
}