This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,380 @@
using UnityEngine;
using UnityEditor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using AnimationImporter.Boomlagoon.JSON;
namespace AnimationImporter.PyxelEdit
{
[InitializeOnLoad]
public class PyxelEditImporter : IAnimationImporterPlugin
{
private static PyxelEditData _latestData = null;
// ================================================================================
// static constructor, registering plugin
// --------------------------------------------------------------------------------
static PyxelEditImporter()
{
PyxelEditImporter importer = new PyxelEditImporter();
AnimationImporter.RegisterImporter(importer, "pyxel");
}
public ImportedAnimationSheet Import(AnimationImportJob job, AnimationImporterSharedConfig config)
{
if (ImportImageAndMetaInfo(job))
{
AssetDatabase.Refresh();
return GetAnimationInfo(_latestData);
}
return null;
}
public bool IsValid()
{
return IonicZipDllIsPresent();
}
public bool IsConfigured()
{
return true;
}
private static bool ImportImageAndMetaInfo(AnimationImportJob job)
{
_latestData = null;
var zipFilePath = GetFileSystemPath(job.assetDirectory + "/" + job.fileName);
var files = GetContentsFromZipFile(zipFilePath);
if (files.ContainsKey("docData.json"))
{
string jsonData = System.Text.Encoding.UTF8.GetString(files["docData.json"]);
PyxelEditData pyxelEditData = ReadJson(jsonData);
List<Layer> allLayers = new List<Layer>();
foreach (var item in pyxelEditData.canvas.layers)
{
Layer layer = item.Value;
string layerName = "layer" + item.Key.ToString() + ".png";
layer.texture = LoadTexture(files[layerName]);
allLayers.Add(layer);
}
Texture2D image = CreateBlankTexture(new Color(0f, 0f, 0f, 0), pyxelEditData.canvas.width, pyxelEditData.canvas.height);
for (int i = allLayers.Count - 1; i >= 0; i--)
{
Layer layer = allLayers[i];
if (!layer.hidden)
{
float maxAlpha = layer.alpha / 255f;
image = CombineTextures(image, layer.texture, maxAlpha);
}
}
if (!Directory.Exists(job.directoryPathForSprites))
{
Directory.CreateDirectory(job.directoryPathForSprites);
}
SaveTextureToAssetPath(image, job.imageAssetFilename);
_latestData = pyxelEditData;
return true;
}
else
{
return false;
}
}
private static ImportedAnimationSheet GetAnimationInfo(PyxelEditData data)
{
if (data == null)
{
return null;
}
int tileWidth = data.tileset.tileWidth;
int tileHeight = data.tileset.tileHeight;
int maxTileIndex = 0;
ImportedAnimationSheet animationSheet = new ImportedAnimationSheet();
animationSheet.width = data.canvas.width;
animationSheet.height = data.canvas.height;
// animations
animationSheet.animations = new List<ImportedAnimation>();
for (int i = 0; i < data.animations.Count; i++)
{
var animationData = data.animations[i];
ImportedAnimation importAnimation = new ImportedAnimation();
importAnimation.name = animationData.name;
importAnimation.firstSpriteIndex = animationData.baseTile;
importAnimation.lastSpriteIndex = animationData.baseTile + animationData.length - 1;
maxTileIndex = Mathf.Max(maxTileIndex, importAnimation.lastSpriteIndex);
ImportedAnimationFrame[] frames = new ImportedAnimationFrame[animationData.length];
for (int frameIndex = 0; frameIndex < animationData.length; frameIndex++)
{
ImportedAnimationFrame frame = new ImportedAnimationFrame();
frame.duration = animationData.frameDuration;
if (animationData.frameDurationMultipliers[frameIndex] != 100)
{
frame.duration *= (int)(animationData.frameDurationMultipliers[frameIndex] / 100f);
}
int tileIndex = animationData.baseTile + frameIndex;
int columnCount = data.canvas.width / tileWidth;
int column = tileIndex % columnCount;
int row = tileIndex / columnCount;
frame.x = column * tileWidth;
frame.y = animationSheet.height - (row + 1) * tileHeight;
frame.width = tileWidth;
frame.height = tileHeight;
frames[frameIndex] = frame;
}
importAnimation.frames = frames;
animationSheet.animations.Add(importAnimation);
}
// gather all frames used by animations for the sprite sheet
animationSheet.frames = new List<ImportedAnimationFrame>();
foreach (var anim in animationSheet.animations)
{
foreach (var frame in anim.frames)
{
animationSheet.frames.Add(frame);
}
}
return animationSheet;
}
private static PyxelEditData ReadJson(string jsonData)
{
PyxelEditData data = new PyxelEditData();
JSONObject obj = JSONObject.Parse(jsonData);
if (obj.ContainsKey("name"))
{
data.name = obj["name"].Str;
}
if (obj.ContainsKey("tileset"))
{
data.tileset.tileWidth = (int)obj["tileset"].Obj["tileWidth"].Number;
data.tileset.tileHeight = (int)obj["tileset"].Obj["tileHeight"].Number;
data.tileset.tilesWide = (int)obj["tileset"].Obj["tilesWide"].Number;
data.tileset.fixedWidth = obj["tileset"].Obj["fixedWidth"].Boolean;
data.tileset.numTiles = (int)obj["tileset"].Obj["numTiles"].Number;
}
if (obj.ContainsKey("animations"))
{
foreach (var item in obj["animations"].Obj)
{
data.animations[int.Parse(item.Key)] = new Animation(item.Value.Obj);
}
}
if (obj.ContainsKey("canvas"))
{
data.canvas.width = (int)obj["canvas"].Obj["width"].Number;
data.canvas.height = (int)obj["canvas"].Obj["height"].Number;
data.canvas.tileWidth = (int)obj["canvas"].Obj["tileWidth"].Number;
data.canvas.tileHeight = (int)obj["canvas"].Obj["tileHeight"].Number;
data.canvas.numLayers = (int)obj["canvas"].Obj["numLayers"].Number;
foreach (var item in obj["canvas"].Obj["layers"].Obj)
{
data.canvas.layers[int.Parse(item.Key)] = new Layer(item.Value.Obj);
}
}
return data;
}
public static string GetFileSystemPath(string path)
{
string basePath = Application.dataPath;
// if the path already begins with the Assets folder, remove that one from the base
if (path.StartsWith("Assets") || path.StartsWith("/Assets"))
{
basePath = basePath.Replace("/Assets", "");
}
return Path.Combine(basePath, path);
}
public static void SaveTextureToAssetPath(Texture2D texture, string assetPath)
{
string path = Application.dataPath + "/../" + assetPath;
File.WriteAllBytes(path, texture.EncodeToPNG());
}
public static Texture2D CreateBlankTexture(
Color color, int width = 2, int height = -1, TextureFormat format = TextureFormat.RGBA32,
bool mipmap = false, bool linear = false)
{
if (height < 0)
{
height = width;
}
// create empty texture
Texture2D texture = new Texture2D(width, height, format, mipmap, linear);
// get all pixels as an array
var cols = texture.GetPixels();
for (int i = 0; i < cols.Length; i++)
{
cols[i] = color;
}
// important steps to save changed pixel values
texture.SetPixels(cols);
texture.Apply();
texture.hideFlags = HideFlags.HideAndDontSave;
return texture;
}
static Texture2D LoadTexture(byte[] imageData)
{
var w = ReadInt32FromImageData(imageData, 3 + 15);
var h = ReadInt32FromImageData(imageData, 3 + 15 + 2 + 2);
var texture = new Texture2D(w, h, TextureFormat.ARGB32, false);
texture.hideFlags = HideFlags.HideAndDontSave;
texture.filterMode = FilterMode.Point;
texture.LoadImage(imageData);
return texture;
}
static int ReadInt32FromImageData(byte[] imageData, int offset)
{
return (imageData[offset] << 8) | imageData[offset + 1];
}
public static Texture2D CombineTextures(Texture2D aBaseTexture, Texture2D aToCopyTexture, float maxAlpha)
{
int aWidth = aBaseTexture.width;
int aHeight = aBaseTexture.height;
Texture2D aReturnTexture = new Texture2D(aWidth, aHeight, TextureFormat.RGBA32, false);
Color[] aBaseTexturePixels = aBaseTexture.GetPixels();
Color[] aCopyTexturePixels = aToCopyTexture.GetPixels();
Color[] aColorList = new Color[aBaseTexturePixels.Length];
int aPixelLength = aBaseTexturePixels.Length;
for (int p = 0; p < aPixelLength; p++)
{
float minA = aBaseTexturePixels[p].a;
float alpha = aCopyTexturePixels[p].a * maxAlpha;
aColorList[p] = Color.Lerp(aBaseTexturePixels[p], aCopyTexturePixels[p], alpha);
aColorList[p].a = Mathf.Lerp(minA, 1f, alpha);
}
aReturnTexture.SetPixels(aColorList);
aReturnTexture.Apply(false);
return aReturnTexture;
}
// ================================================================================
// extracting from zip file
// --------------------------------------------------------------------------------
private static Type zipFileClass = null;
private static System.Reflection.MethodInfo readZipFileMethod = null;
private static System.Reflection.MethodInfo extractMethod = null;
public static Dictionary<string, byte[]> GetContentsFromZipFile(string fileName)
{
Dictionary<string, byte[]> files = new Dictionary<string, byte[]>();
if (zipFileClass == null)
{
InitZipMethods();
}
if (zipFileClass != null)
{
using (var zipFile = readZipFileMethod.Invoke(null, new object[] { fileName }) as IDisposable)
{
var zipFileAsEnumeration = zipFile as IEnumerable;
foreach (var entry in zipFileAsEnumeration)
{
MemoryStream stream = new MemoryStream();
extractMethod.Invoke(entry, new object[] { stream });
files.Add(entry.ToString().Replace("ZipEntry::", ""), stream.ToArray());
}
}
}
return files;
}
private static void InitZipMethods()
{
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in allAssemblies)
{
zipFileClass = assembly.GetType("Ionic.Zip.ZipFile");
if (zipFileClass != null)
{
readZipFileMethod = zipFileClass.GetMethod("Read", new Type[] { typeof(string) });
Type zipEntryClass = assembly.GetType("Ionic.Zip.ZipEntry");
extractMethod = zipEntryClass.GetMethod("Extract", new Type[] { typeof(MemoryStream) });
return;
}
}
}
private static bool IonicZipDllIsPresent()
{
if (zipFileClass != null)
{
return true;
}
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in allAssemblies)
{
var zipClass = assembly.GetType("Ionic.Zip.ZipFile");
if (zipClass != null)
{
return true;
}
}
return false;
}
}
}