Jeremy Pritts 3006d48010 Update source gen dll and code:
* Fix issues building recent commits
* AssetList.CopyTo(Span)
* Utf8String.IsEmpty
* Resolve #692
2023-06-11 20:03:43 -04:00

352 lines
11 KiB
C#

using AssetRipper.Assets.Generics;
using AssetRipper.Numerics;
using AssetRipper.SourceGenerated.Classes.ClassID_213;
using AssetRipper.SourceGenerated.Classes.ClassID_687078895;
using AssetRipper.SourceGenerated.Enums;
using AssetRipper.SourceGenerated.Subclasses.SpriteAtlasData;
using AssetRipper.SourceGenerated.Subclasses.SpriteBone;
using AssetRipper.SourceGenerated.Subclasses.SpriteMetaData;
using AssetRipper.SourceGenerated.Subclasses.SpriteRenderData;
using AssetRipper.SourceGenerated.Subclasses.SpriteVertex;
using AssetRipper.SourceGenerated.Subclasses.SubMesh;
using AssetRipper.SourceGenerated.Subclasses.Vector2f;
using System.Buffers.Binary;
using System.Drawing;
using System.Numerics;
namespace AssetRipper.SourceGenerated.Extensions
{
public static class SpriteMetaDataExtensions
{
public static SpriteAlignment GetAlignment(this ISpriteMetaData data)
{
return (SpriteAlignment)data.Alignment;
}
public static void FillSpriteMetaData(this ISpriteMetaData instance, ISprite sprite, ISpriteAtlas? atlas)
{
sprite.GetSpriteCoordinatesInAtlas(atlas, out RectangleF rect, out Vector2 pivot, out Vector4 border);
instance.NameString = sprite.NameString;
instance.Rect.CopyValues(rect);
instance.Alignment = (int)SpriteAlignment.Custom;
instance.Pivot.CopyValues(pivot);
instance.Border?.CopyValues(border);
if (instance.Has_Outline())
{
GenerateOutline(sprite, atlas, rect, pivot, instance.Outline);
}
if (instance.Has_PhysicsShape() && sprite.Has_PhysicsShape_C213())
{
GeneratePhysicsShape(sprite, atlas, rect, pivot, instance.PhysicsShape);
}
instance.TessellationDetail = 0;
if (instance.Has_Bones() && sprite.Has_Bones_C213() && instance.Has_SpriteID())
{
// Scale bones based off of the sprite's PPU
foreach (ISpriteBone bone in sprite.Bones_C213)
{
bone.Position.Scale(sprite.PixelsToUnits_C213);
bone.Length *= sprite.PixelsToUnits_C213;
// Set root bone position
if (bone.ParentId == -1)
{
bone.Position.X += sprite.Rect_C213.Width / 2;
bone.Position.Y += sprite.Rect_C213.Height / 2;
}
}
instance.Bones.Clear();
instance.Bones.Capacity = sprite.Bones_C213.Count;
foreach (ISpriteBone bone in sprite.Bones_C213)
{
instance.Bones.AddNew().CopyValues(bone);
}
// NOTE: sprite ID is generated by sprite binary content, but we just generate a random value
instance.SpriteID = Guid.NewGuid().ToString("N");
instance.SetBoneGeometry(sprite);
}
}
private static void SetBoneGeometry(this ISpriteMetaData instance, ISprite origin)
{
Vector3[]? vertices = null;
BoneWeight4[]? skin = null;
origin.RD_C213.VertexData?.ReadData(origin.Collection.Version, origin.Collection.EndianType, null,
out vertices,
out Vector3[]? _,//normals,
out Vector4[]? _,//tangents,
out ColorFloat[]? _,//colors,
out skin,
out Vector2[]? _,//uv0,
out Vector2[]? _,//uv1,
out Vector2[]? _,//uv2,
out Vector2[]? _,//uv3,
out Vector2[]? _,//uv4,
out Vector2[]? _,//uv5,
out Vector2[]? _,//uv6,
out Vector2[]? _);//uv7);
if (instance.Has_Vertices())
{
instance.Vertices.Clear();
// Convert Vector3f into Vector2f
if (vertices is null)
{
instance.Vertices.Capacity = 0;
}
else
{
instance.Vertices.Capacity = vertices.Length;
for (int i = 0; i < vertices.Length; i++)
{
Vector2f vertex = instance.Vertices.AddNew();
// Scale and translate vertices properly
vertex.X = vertices[i].X * origin.PixelsToUnits_C213 + origin.Rect_C213.Width / 2;
vertex.Y = vertices[i].Y * origin.PixelsToUnits_C213 + origin.Rect_C213.Height / 2;
}
}
}
if (instance.Has_Indices())
{
instance.Indices.Clear();
if (origin.RD_C213.Has_IndexBuffer() && origin.RD_C213.IndexBuffer.Length != 0)
{
instance.Indices.Capacity = origin.RD_C213.IndexBuffer.Length / 2;
for (int i = 0, j = 0; i < origin.RD_C213.IndexBuffer.Length / 2; i++, j += 2)
{
//Endianness might matter here
instance.Indices.Add(BinaryPrimitives.ReadInt16LittleEndian(origin.RD_C213.IndexBuffer.AsSpan(j, 2)));
}
}
}
#warning TODO: SpriteConverter does not generate instance.Edges
if (instance.Has_Weights())
{
instance.Weights.Clear();
if (skin is not null)
{
instance.Weights.EnsureCapacity(skin.Length);
for (int i = 0; i < skin.Length; i++)
{
instance.Weights.Add((Subclasses.BoneWeights4.BoneWeights4_2017_1_0)skin[i]);
}
}
}
}
private static void GeneratePhysicsShape(
ISprite sprite,
ISpriteAtlas? atlas,
RectangleF rect,
Vector2 pivot,
AssetList<AssetList<Vector2f>> shape)
{
if (sprite.Has_PhysicsShape_C213() && sprite.PhysicsShape_C213.Count > 0)
{
shape.Clear();
shape.Capacity = sprite.PhysicsShape_C213.Count;
float pivotShiftX = rect.Width * pivot.X - rect.Width * 0.5f;
float pivotShiftY = rect.Height * pivot.Y - rect.Height * 0.5f;
Vector2 pivotShift = new Vector2(pivotShiftX, pivotShiftY);
for (int i = 0; i < sprite.PhysicsShape_C213.Count; i++)
{
shape.Add(new AssetList<Vector2f>(sprite.PhysicsShape_C213[i].Count));
for (int j = 0; j < sprite.PhysicsShape_C213[i].Count; j++)
{
Vector2 point = (Vector2)sprite.PhysicsShape_C213[i][j] * sprite.PixelsToUnits_C213;
shape[i].Add((Vector2f)(point + pivotShift));
}
}
FixRotation(sprite, atlas, shape);
}
}
private static void FixRotation(ISprite sprite, ISpriteAtlas? atlas, AssetList<AssetList<Vector2f>> outlines)
{
GetPacking(sprite, atlas, out bool isPacked, out SpritePackingRotation rotation);
if (isPacked)
{
switch (rotation)
{
case SpritePackingRotation.FlipHorizontal:
{
foreach (AssetList<Vector2f> outline in outlines)
{
for (int i = 0; i < outline.Count; i++)
{
Vector2f vertex = outline[i];
outline[i].SetValues(-vertex.X, vertex.Y);
}
}
}
break;
case SpritePackingRotation.FlipVertical:
{
foreach (AssetList<Vector2f> outline in outlines)
{
for (int i = 0; i < outline.Count; i++)
{
Vector2f vertex = outline[i];
outline[i].SetValues(vertex.X, -vertex.Y);
}
}
}
break;
case SpritePackingRotation.Rotate90:
{
foreach (AssetList<Vector2f> outline in outlines)
{
for (int i = 0; i < outline.Count; i++)
{
Vector2f vertex = outline[i];
outline[i].SetValues(vertex.Y, vertex.X);
}
}
}
break;
case SpritePackingRotation.Rotate180:
{
foreach (AssetList<Vector2f> outline in outlines)
{
for (int i = 0; i < outline.Count; i++)
{
Vector2f vertex = outline[i];
outline[i].SetValues(-vertex.X, -vertex.Y);
}
}
}
break;
}
}
}
/// <summary>
/// Pure
/// </summary>
/// <param name="sprite"></param>
/// <param name="atlas"></param>
/// <param name="isPacked"></param>
/// <param name="rotation"></param>
private static void GetPacking(ISprite sprite, ISpriteAtlas? atlas, out bool isPacked, out SpritePackingRotation rotation)
{
if (atlas is not null && sprite.Has_RenderDataKey_C213())
{
ISpriteAtlasData atlasData = atlas.RenderDataMap_C687078895[sprite.RenderDataKey_C213];
isPacked = atlasData.IsPacked();
rotation = atlasData.GetPackingRotation();
}
else
{
isPacked = sprite.RD_C213.IsPacked();
rotation = sprite.RD_C213.GetPackingRotation();
}
}
private static void GenerateOutline(
ISprite sprite,
ISpriteAtlas? atlas,
RectangleF rect,
Vector2 pivot,
AssetList<AssetList<Vector2f>> outlines)
{
GenerateOutline(sprite.RD_C213, sprite.Collection.Version, outlines);
float pivotShiftX = rect.Width * pivot.X - rect.Width * 0.5f;
float pivotShiftY = rect.Height * pivot.Y - rect.Height * 0.5f;
Vector2 pivotShift = new Vector2(pivotShiftX, pivotShiftY);
foreach (AssetList<Vector2f> outline in outlines)
{
for (int i = 0; i < outline.Count; i++)
{
Vector2 point = (Vector2)outline[i] * sprite.PixelsToUnits_C213;
outline[i].CopyValues(point + pivotShift);
}
}
FixRotation(sprite, atlas, outlines);
}
private static void GenerateOutline(
ISpriteRenderData spriteRenderData,
UnityVersion version,
AssetList<AssetList<Vector2f>> outlines)
{
outlines.Clear();
if (spriteRenderData.Has_VertexData() && spriteRenderData.SubMeshes!.Count != 0)
{
for (int i = 0; i < spriteRenderData.SubMeshes.Count; i++)
{
Vector3[] vertices = spriteRenderData.VertexData.GenerateVertices(version, spriteRenderData.SubMeshes[i]);
List<Vector2[]> vectorArrayList = VertexDataToOutline(spriteRenderData.IndexBuffer, vertices, spriteRenderData.SubMeshes[i]);
outlines.AddRanges(vectorArrayList);
}
}
else if (spriteRenderData.Has_Vertices() && spriteRenderData.Vertices.Count != 0)
{
List<Vector2[]> vectorArrayList = VerticesToOutline(spriteRenderData.Vertices, spriteRenderData.Indices);
outlines.Capacity = vectorArrayList.Count;
outlines.AddRanges(vectorArrayList);
}
}
private static List<Vector2[]> VerticesToOutline(AccessListBase<ISpriteVertex> spriteVertexList, AssetList<ushort> spriteIndexArray)
{
Vector3[] vertices = new Vector3[spriteVertexList.Count];
for (int i = 0; i < vertices.Length; i++)
{
vertices[i] = spriteVertexList[i].Pos;
}
Vector3i[] triangles = new Vector3i[spriteIndexArray.Count / 3];
for (int i = 0, j = 0; i < triangles.Length; i++)
{
int x = spriteIndexArray[j++];
int y = spriteIndexArray[j++];
int z = spriteIndexArray[j++];
triangles[i] = new Vector3i(x, y, z);
}
MeshOutlineGenerator outlineGenerator = new MeshOutlineGenerator(vertices, triangles);
return outlineGenerator.GenerateOutlines();
}
private static List<Vector2[]> VertexDataToOutline(byte[] indexBuffer, Vector3[] vertices, ISubMesh submesh)
{
Vector3i[] triangles = new Vector3i[submesh.IndexCount / 3];
for (int o = (int)submesh.FirstByte, ti = 0; ti < triangles.Length; o += 6, ti++)
{
int x = BitConverter.ToUInt16(indexBuffer, o + 0);
int y = BitConverter.ToUInt16(indexBuffer, o + 2);
int z = BitConverter.ToUInt16(indexBuffer, o + 4);
triangles[ti] = new Vector3i(x, y, z);
}
MeshOutlineGenerator outlineGenerator = new MeshOutlineGenerator(vertices, triangles);
return outlineGenerator.GenerateOutlines();
}
private static void AddRanges(this AssetList<AssetList<Vector2f>> instance, List<Vector2[]> vectorArrayList)
{
foreach (Vector2[] vectorArray in vectorArrayList)
{
AssetList<Vector2f> assetList = new AssetList<Vector2f>(vectorArray.Length);
instance.Add(assetList);
foreach (Vector2 v in vectorArray)
{
assetList.Add((Vector2f)v);
}
}
}
}
}