Initial bread2unity commit
This commit is contained in:
parent
b68e9cd967
commit
5021c83afa
205
Assets/Editor/bread2unity/AnimationCreator.cs
Normal file
205
Assets/Editor/bread2unity/AnimationCreator.cs
Normal file
|
@ -0,0 +1,205 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Bread2Unity;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Animation = Bread2Unity.Animation;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public static class AnimationCreator
|
||||
{
|
||||
private class BccadCurve : AnimationCurve
|
||||
{
|
||||
private float _prev;
|
||||
|
||||
public new void AddKey(float time, float value)
|
||||
{
|
||||
if (keys.Length != 0 && !(Math.Abs(value - _prev) > 0.000001)) return;
|
||||
AddKey(new Keyframe(time, value, float.PositiveInfinity, float.PositiveInfinity));
|
||||
_prev = value;
|
||||
}
|
||||
|
||||
public void CopyLastKey(float time)
|
||||
{
|
||||
Keyframe lastKey = keys.LastOrDefault();
|
||||
|
||||
base.AddKey(time, keys.Length > 0 ? lastKey.value : 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CreateAnimation(BccadPrefab bccadPrefab, BCCAD bccad, PrefabData prefabData,
|
||||
List<Sprite> sprites)
|
||||
{
|
||||
var gameObject = bccadPrefab.ParentObject;
|
||||
var rootPrefabName = gameObject.transform.parent.gameObject.name;
|
||||
var spritesFolderPath =
|
||||
$"Assets\\Resources\\Sprites\\Games\\{char.ToUpperInvariant(rootPrefabName[0]) + rootPrefabName.Substring(1)}";
|
||||
|
||||
var animationsFolderPath = spritesFolderPath + $"/anim/{prefabData.Name}";
|
||||
if (!Directory.Exists(animationsFolderPath))
|
||||
{
|
||||
Directory.CreateDirectory(animationsFolderPath);
|
||||
}
|
||||
|
||||
var controller =
|
||||
AnimatorController.CreateAnimatorControllerAtPath(
|
||||
AssetDatabase.GenerateUniqueAssetPath(
|
||||
$"{animationsFolderPath}/{prefabData.Name}Controller.controller"));
|
||||
var bccadSprites = bccad.sprites;
|
||||
|
||||
//get all of the parts associated with the game object
|
||||
var steps = prefabData.Animations.SelectMany(animation => animation.Steps);
|
||||
var bccadSpritesOfPrefab = steps.Select(step => step.BccadSprite).ToList();
|
||||
|
||||
|
||||
foreach (var animation in prefabData.Animations)
|
||||
{
|
||||
var clip = CreateAnimationClip(bccadPrefab, animation, sprites, bccadSpritesOfPrefab);
|
||||
|
||||
AssetDatabase.CreateAsset(clip,
|
||||
AssetDatabase.GenerateUniqueAssetPath(
|
||||
$"{animationsFolderPath}/{animation.Name}.anim"));
|
||||
controller.AddMotion(clip);
|
||||
}
|
||||
|
||||
var animator = gameObject.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
}
|
||||
|
||||
private static AnimationClip CreateAnimationClip(BccadPrefab bccadPrefab, Animation animation,
|
||||
List<Sprite> sprites,
|
||||
IReadOnlyCollection<BccadSprite> spritesAssociatedWithPrefab)
|
||||
{
|
||||
var animationClip = new AnimationClip();
|
||||
var prefab = bccadPrefab.ParentObject;
|
||||
for (int childIndex = 0; childIndex < prefab.transform.childCount; childIndex++)
|
||||
{
|
||||
var child = prefab.transform.GetChild(childIndex).gameObject;
|
||||
|
||||
var partsOfGameObject = spritesAssociatedWithPrefab.SelectMany(sprite => sprite.parts)
|
||||
.Where(part => bccadPrefab.RegionToChild[part.RegionIndex] == child).ToList();
|
||||
|
||||
var enabledCurve = new BccadCurve();
|
||||
|
||||
var xTransformCurve = new BccadCurve();
|
||||
var yTransformCurve = new BccadCurve();
|
||||
var zTransformCurve = new BccadCurve();
|
||||
|
||||
var rotationCurve = new BccadCurve();
|
||||
|
||||
var flipXCurve = new BccadCurve();
|
||||
var flipYCurve = new BccadCurve();
|
||||
|
||||
var scaleXCurve = new BccadCurve();
|
||||
var scaleYCurve = new BccadCurve();
|
||||
|
||||
var spriteFrames = new List<ObjectReferenceKeyframe>();
|
||||
|
||||
var currentTime = 0f;
|
||||
|
||||
for (int stepIndex = 0; stepIndex < animation.Steps.Count; stepIndex++)
|
||||
{
|
||||
var currentStep = animation.Steps[stepIndex];
|
||||
var bccadSprite = currentStep.BccadSprite;
|
||||
// Find the index of part of the game object
|
||||
var partIndex = bccadSprite.parts.Select((value, index) => new { value, index })
|
||||
.Where(pair => bccadPrefab.RegionToChild[pair.value.RegionIndex] == child)
|
||||
.Select(pair => pair.index).DefaultIfEmpty(-1)
|
||||
.FirstOrDefault();
|
||||
|
||||
enabledCurve.AddKey(currentTime, partIndex == -1 ? 0 : 1);
|
||||
|
||||
if (partIndex != -1)
|
||||
{
|
||||
var bccadSpritePart = bccadSprite.parts[partIndex];
|
||||
|
||||
var sprite = sprites[bccadSpritePart.RegionIndex.Index];
|
||||
var width = bccadSpritePart.StretchX / bccadPrefab.WidthRatio;
|
||||
var height = bccadSpritePart.StretchY / bccadPrefab.HeightRatio;
|
||||
var x = (bccadSpritePart.PosX - 512f) /
|
||||
SpriteCreator.PixelsPerUnit + sprite.bounds.size.x * 0.5f * width;
|
||||
var y = -(bccadSpritePart.PosY - 512f) / SpriteCreator.PixelsPerUnit -
|
||||
sprite.bounds.size.y * 0.5f * height;
|
||||
var z = -0.00001f * partIndex;
|
||||
|
||||
xTransformCurve.AddKey(currentTime, x);
|
||||
yTransformCurve.AddKey(currentTime, y);
|
||||
zTransformCurve.AddKey(currentTime, z);
|
||||
|
||||
scaleXCurve.AddKey(currentTime, width);
|
||||
scaleYCurve.AddKey(currentTime, height);
|
||||
|
||||
if (spriteFrames.Count == 0 || spriteFrames.Last().value != sprite)
|
||||
{
|
||||
var spriteKeyframe = new ObjectReferenceKeyframe
|
||||
{
|
||||
time = currentTime,
|
||||
value = sprite
|
||||
};
|
||||
spriteFrames.Add(spriteKeyframe);
|
||||
}
|
||||
|
||||
flipXCurve.AddKey(currentTime, bccadSpritePart.FlipX ? 1 : 0);
|
||||
flipYCurve.AddKey(currentTime, bccadSpritePart.FlipY ? 1 : 0);
|
||||
|
||||
rotationCurve.AddKey(currentTime, -bccadSpritePart.Rotation);
|
||||
}
|
||||
|
||||
// Increase the time for the next frame
|
||||
currentTime += currentStep.Delay / 30f;
|
||||
}
|
||||
|
||||
if (childIndex == 0)
|
||||
{
|
||||
enabledCurve.CopyLastKey(currentTime);
|
||||
}
|
||||
|
||||
var spriteBinding = new EditorCurveBinding
|
||||
{
|
||||
type = typeof(SpriteRenderer),
|
||||
propertyName = "m_Sprite",
|
||||
path = $"{prefab.name} {childIndex}"
|
||||
};
|
||||
|
||||
var animateActive = childIndex == 0 || spritesAssociatedWithPrefab.Any(sprite =>
|
||||
sprite.parts.All(part => bccadPrefab.RegionToChild[part.RegionIndex] != child));
|
||||
if (animateActive)
|
||||
animationClip.SetCurve(child.name, typeof(GameObject), "m_IsActive", enabledCurve);
|
||||
if ((from part in partsOfGameObject select part.FlipX).Distinct().Count() > 1)
|
||||
animationClip.SetCurve(child.name, typeof(SpriteRenderer), "m_FlipX", flipXCurve);
|
||||
if ((from part in partsOfGameObject select part.FlipY).Distinct().Count() > 1)
|
||||
animationClip.SetCurve(child.name, typeof(SpriteRenderer), "m_FlipY", flipYCurve);
|
||||
if ((from part in partsOfGameObject select part.RegionIndex.Index).Distinct().Count() > 1)
|
||||
AnimationUtility.SetObjectReferenceCurve(animationClip, spriteBinding, spriteFrames.ToArray());
|
||||
if ((from part in partsOfGameObject select part.PosX).Distinct().Count() > 1 ||
|
||||
(from part in partsOfGameObject select part.PosY).Distinct().Count() > 1)
|
||||
{
|
||||
animationClip.SetCurve(child.name, typeof(Transform), "localPosition.x", xTransformCurve);
|
||||
animationClip.SetCurve(child.name, typeof(Transform), "localPosition.y", yTransformCurve);
|
||||
animationClip.SetCurve(child.name, typeof(Transform), "localPosition.z", zTransformCurve);
|
||||
}
|
||||
|
||||
if ((from part in partsOfGameObject select part.Rotation).Distinct().Count() > 1)
|
||||
{
|
||||
animationClip.SetCurve(child.name, typeof(Transform), "localEulerAngles.z", rotationCurve);
|
||||
}
|
||||
|
||||
if ((from part in partsOfGameObject select part.StretchX).Distinct().Count() > 1 ||
|
||||
(from part in partsOfGameObject select part.StretchY).Distinct().Count() > 1)
|
||||
{
|
||||
animationClip.SetCurve(child.name, typeof(Transform), "localScale.x", scaleXCurve);
|
||||
animationClip.SetCurve(child.name, typeof(Transform), "localScale.y", scaleYCurve);
|
||||
}
|
||||
}
|
||||
|
||||
animationClip.frameRate = 30; //fps
|
||||
animationClip.name = animation.Name;
|
||||
|
||||
return animationClip;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d4aae79bea7b7234f9ce059ade5fce08
|
||||
guid: c8ef7864bd34c1f46b262e15cfff32c9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
381
Assets/Editor/bread2unity/AnimationFixer.cs
Normal file
381
Assets/Editor/bread2unity/AnimationFixer.cs
Normal file
|
@ -0,0 +1,381 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.IO;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public static class AnimationFixer
|
||||
{
|
||||
private static int CurveCounter = 0;
|
||||
static System.DateTime StartTime;
|
||||
private const float TangentDegreeDifferent = 10;
|
||||
|
||||
[MenuItem("AnimationTool/ProcessForConstant %e")]
|
||||
static void Execute()
|
||||
{
|
||||
CurveCounter = 0;
|
||||
StartTime = System.DateTime.Now;
|
||||
|
||||
UnityEngine.Object[] selectedObjects = Selection.GetFiltered<UnityEngine.Object>(SelectionMode.DeepAssets);
|
||||
|
||||
foreach (UnityEngine.Object selectedObj in selectedObjects)
|
||||
{
|
||||
string path = AssetDatabase.GetAssetPath(selectedObj);
|
||||
if (selectedObj is AnimationClip)
|
||||
{
|
||||
Debug.Log("is AnimationClip");
|
||||
ProcessCurveForConstant(path);
|
||||
CurveCounter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (path.ToLower().EndsWith(".fbx", System.StringComparison.Ordinal))
|
||||
{
|
||||
Object[] fbxObjects = AssetDatabase.LoadAllAssetsAtPath(path);
|
||||
foreach (var subObj in fbxObjects)
|
||||
{
|
||||
if (subObj is AnimationClip
|
||||
&& !subObj.name.StartsWith("__preview__", System.StringComparison.Ordinal))
|
||||
{
|
||||
Debug.Log("Copy animation clip : " + path + " clip name: " +
|
||||
(subObj as AnimationClip).name);
|
||||
string newClipPath = CopyAnimation(subObj as AnimationClip);
|
||||
ProcessCurveForConstant(newClipPath);
|
||||
CurveCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
Debug.Log("Cruve sum: " + CurveCounter + " Time: " +
|
||||
((System.DateTime.Now - StartTime).TotalMilliseconds / 1000) + "s.");
|
||||
}
|
||||
|
||||
static string CopyAnimation(AnimationClip sourceClip)
|
||||
{
|
||||
string path = AssetDatabase.GetAssetPath(sourceClip);
|
||||
path = Path.Combine(Path.GetDirectoryName(path), sourceClip.name) + ".anim";
|
||||
string newPath = AssetDatabase.GenerateUniqueAssetPath(path);
|
||||
|
||||
AnimationClip newClip = new AnimationClip();
|
||||
EditorUtility.CopySerialized(sourceClip, newClip);
|
||||
AssetDatabase.CreateAsset(newClip, newPath);
|
||||
//AssetDatabase.Refresh();
|
||||
Debug.Log("CopyAnimation: " + newPath);
|
||||
return newPath;
|
||||
}
|
||||
|
||||
static void ProcessCurveForConstant(string clipPath)
|
||||
{
|
||||
Debug.Log("Processing : " + clipPath);
|
||||
ProcessCurveForConstant(AssetDatabase.LoadAssetAtPath<AnimationClip>(clipPath));
|
||||
}
|
||||
|
||||
public static void ProcessCurveForConstant(AnimationClip animationClip)
|
||||
{
|
||||
AnimationUtility.GetCurveBindings(animationClip);
|
||||
EditorUtility.SetDirty(animationClip);
|
||||
|
||||
var soClip = new SerializedObject(animationClip);
|
||||
float sampleRate = soClip.FindProperty("m_SampleRate").floatValue;
|
||||
float oneKeyframeTime = (float)((int)((1.0f / sampleRate) * 1000)) / 1000 + 0.001f;
|
||||
|
||||
string[] editorCurveSetNames = new string[] { "m_EditorCurves", "m_EulerEditorCurves" };
|
||||
//string[] editorCurveSetNames = new string[] { "m_EditorCurves" };
|
||||
|
||||
foreach (var editorCurveSetName in editorCurveSetNames)
|
||||
{
|
||||
var curCurveSet = soClip.FindProperty(editorCurveSetName);
|
||||
int curCurveSetLenght = curCurveSet.arraySize;
|
||||
if (curCurveSetLenght == 0)
|
||||
{
|
||||
Debug.Log("Can not fine editor curves in " + editorCurveSetName);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int curveSetIndex = 0; curveSetIndex < curCurveSetLenght; curveSetIndex++)
|
||||
{
|
||||
var curCurveInfo = curCurveSet.GetArrayElementAtIndex(curveSetIndex);
|
||||
Debug.Log(editorCurveSetName + " index : " + curveSetIndex + " attribute: " +
|
||||
curCurveInfo.FindPropertyRelative("attribute").stringValue);
|
||||
|
||||
var curCurve = curCurveInfo.FindPropertyRelative("curve");
|
||||
var curCurveData = curCurve.FindPropertyRelative("m_Curve");
|
||||
int curCurveDatalength = curCurveData.arraySize;
|
||||
Debug.Log("curve lenght:" + curCurveDatalength);
|
||||
|
||||
for (int curveDataIndex = 3; curveDataIndex < curCurveDatalength; curveDataIndex++)
|
||||
{
|
||||
ProcessOneKeyframeOfEditorCurve(curveDataIndex, curCurveData, oneKeyframeTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string[] curveSetNames = new string[]
|
||||
{ "m_PositionCurves", "m_RotationCurves", "m_ScaleCurves", "m_FloatCurves" };
|
||||
|
||||
foreach (var curveSetName in curveSetNames)
|
||||
{
|
||||
var curCurveSet = soClip.FindProperty(curveSetName);
|
||||
int curCurveSetLenght = curCurveSet.arraySize;
|
||||
if (curCurveSetLenght == 0)
|
||||
{
|
||||
Debug.Log("Can not fine curves in " + curveSetName);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isHaveAttribute = curveSetName == "m_FloatCurves";
|
||||
|
||||
for (int curveSetIndex = 0; curveSetIndex < curCurveSetLenght; curveSetIndex++)
|
||||
{
|
||||
var curCurveInfo = curCurveSet.GetArrayElementAtIndex(curveSetIndex);
|
||||
if (isHaveAttribute)
|
||||
{
|
||||
Debug.Log(curveSetName + " index : " + curveSetIndex + " attribute: " +
|
||||
curCurveInfo.FindPropertyRelative("attribute").stringValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log(curveSetName + " index : " + curveSetIndex);
|
||||
}
|
||||
|
||||
var curCurve = curCurveInfo.FindPropertyRelative("curve");
|
||||
var curCurveData = curCurve.FindPropertyRelative("m_Curve");
|
||||
int curCurveDatalength = curCurveData.arraySize;
|
||||
Debug.Log("curve lenght:" + curCurveDatalength);
|
||||
|
||||
for (int curveDataIndex = 3; curveDataIndex < curCurveDatalength; curveDataIndex++)
|
||||
{
|
||||
ProcessOneKeyframeCurve(curveDataIndex, curCurveData, oneKeyframeTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
soClip.ApplyModifiedProperties();
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
const int kBrokenMask = 1 << 0;
|
||||
const int kLeftTangentMask = 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4;
|
||||
const int kRightTangentMask = 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8;
|
||||
|
||||
static void SetKeyBroken(SerializedProperty keyframeInfo, bool broken)
|
||||
{
|
||||
var tangentModeProp = keyframeInfo.FindPropertyRelative("tangentMode");
|
||||
if (broken)
|
||||
tangentModeProp.intValue |= kBrokenMask;
|
||||
else
|
||||
tangentModeProp.intValue &= ~kBrokenMask;
|
||||
}
|
||||
|
||||
static void SetKeyLeftTangentMode(SerializedProperty keyframeInfo, AnimationUtility.TangentMode tangentMode)
|
||||
{
|
||||
var tangentModeProp = keyframeInfo.FindPropertyRelative("tangentMode");
|
||||
tangentModeProp.intValue &= ~kLeftTangentMask;
|
||||
tangentModeProp.intValue |= (int)tangentMode << 1;
|
||||
}
|
||||
|
||||
static void SetKeyRightTangentMode(SerializedProperty keyframeInfo, AnimationUtility.TangentMode tangentMode)
|
||||
{
|
||||
var tangentModeProp = keyframeInfo.FindPropertyRelative("tangentMode");
|
||||
tangentModeProp.intValue &= ~kRightTangentMask;
|
||||
tangentModeProp.intValue |= (int)tangentMode << 5;
|
||||
}
|
||||
|
||||
static float CalculateLinearTangent(SerializedProperty keyframeInfo, SerializedProperty toKeyframeInfo)
|
||||
{
|
||||
float curTime = keyframeInfo.FindPropertyRelative("time").floatValue;
|
||||
float toTime = toKeyframeInfo.FindPropertyRelative("time").floatValue;
|
||||
float curValue = keyframeInfo.FindPropertyRelative("value").floatValue;
|
||||
float toValue = toKeyframeInfo.FindPropertyRelative("value").floatValue;
|
||||
|
||||
float dt = toTime - curTime;
|
||||
if (Mathf.Abs(dt) < float.Epsilon)
|
||||
return 0.0f;
|
||||
|
||||
return (toValue - curValue) / dt;
|
||||
}
|
||||
|
||||
static void ProcessOneKeyframeOfEditorCurve(int curveDataIndex, SerializedProperty curCurveData,
|
||||
float oneKeyframeTime)
|
||||
{
|
||||
var keyframe1 = curCurveData.GetArrayElementAtIndex(curveDataIndex - 3);
|
||||
var keyframe2 = curCurveData.GetArrayElementAtIndex(curveDataIndex - 2);
|
||||
var keyframe3 = curCurveData.GetArrayElementAtIndex(curveDataIndex - 1);
|
||||
var keyframe4 = curCurveData.GetArrayElementAtIndex(curveDataIndex);
|
||||
|
||||
float time1 = keyframe1.FindPropertyRelative("time").floatValue;
|
||||
float time2 = keyframe2.FindPropertyRelative("time").floatValue;
|
||||
float time3 = keyframe3.FindPropertyRelative("time").floatValue;
|
||||
float time4 = keyframe4.FindPropertyRelative("time").floatValue;
|
||||
|
||||
SerializedProperty outSlope1 = keyframe1.FindPropertyRelative("outSlope");
|
||||
SerializedProperty inSlope2 = keyframe2.FindPropertyRelative("inSlope");
|
||||
SerializedProperty outSlope2 = keyframe2.FindPropertyRelative("outSlope");
|
||||
SerializedProperty inSlope3 = keyframe3.FindPropertyRelative("inSlope");
|
||||
SerializedProperty outSlope3 = keyframe3.FindPropertyRelative("outSlope");
|
||||
SerializedProperty inSlope4 = keyframe4.FindPropertyRelative("inSlope");
|
||||
|
||||
float outTangetDegree1 = Mathf.Rad2Deg * Mathf.Atan(outSlope1.floatValue * oneKeyframeTime);
|
||||
float inTangetDegree2 = Mathf.Rad2Deg * Mathf.Atan(inSlope2.floatValue * oneKeyframeTime);
|
||||
float outTangetDegree3 = Mathf.Rad2Deg * Mathf.Atan(outSlope3.floatValue * oneKeyframeTime);
|
||||
float inTangetDegree4 = Mathf.Rad2Deg * Mathf.Atan(inSlope4.floatValue * oneKeyframeTime);
|
||||
|
||||
float AngleDiff1 = Mathf.Abs(outTangetDegree1 - inTangetDegree2);
|
||||
float AngleDiff2 = Mathf.Abs(outTangetDegree3 - inTangetDegree4);
|
||||
//check constant keyframe
|
||||
if ((time2 - time1 <= oneKeyframeTime)
|
||||
&& (time3 - time2 <= oneKeyframeTime)
|
||||
&& (time4 - time3 <= oneKeyframeTime)
|
||||
&& AngleDiff1 > TangentDegreeDifferent
|
||||
&& AngleDiff2 > TangentDegreeDifferent)
|
||||
{
|
||||
Debug.Log(string.Format("index:{0},{1},{2},{3}", curveDataIndex - 3, curveDataIndex - 2,
|
||||
curveDataIndex - 1, curveDataIndex));
|
||||
|
||||
var keyframeValue = keyframe1.FindPropertyRelative("value");
|
||||
switch (keyframeValue.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.Float:
|
||||
{
|
||||
SetKeyBroken(keyframe1, true);
|
||||
SetKeyRightTangentMode(keyframe1, AnimationUtility.TangentMode.Linear);
|
||||
|
||||
SetKeyBroken(keyframe2, true);
|
||||
SetKeyLeftTangentMode(keyframe2, AnimationUtility.TangentMode.Linear);
|
||||
SetKeyRightTangentMode(keyframe2, AnimationUtility.TangentMode.Constant);
|
||||
inSlope2.floatValue = CalculateLinearTangent(keyframe2, keyframe1);
|
||||
outSlope2.floatValue = float.PositiveInfinity;
|
||||
|
||||
SetKeyBroken(keyframe3, true);
|
||||
SetKeyLeftTangentMode(keyframe3, AnimationUtility.TangentMode.Constant);
|
||||
SetKeyRightTangentMode(keyframe3, AnimationUtility.TangentMode.Linear);
|
||||
inSlope3.floatValue = float.PositiveInfinity;
|
||||
outSlope3.floatValue = CalculateLinearTangent(keyframe3, keyframe4);
|
||||
|
||||
SetKeyBroken(keyframe4, true);
|
||||
SetKeyLeftTangentMode(keyframe4, AnimationUtility.TangentMode.Linear);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Vector3 ConstantVector3 =
|
||||
new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
|
||||
|
||||
static Vector4 ConstantVector4 = new Vector4(float.PositiveInfinity, float.PositiveInfinity,
|
||||
float.PositiveInfinity, float.PositiveInfinity);
|
||||
|
||||
static Quaternion ConstantQuaternion =
|
||||
new Quaternion(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 1);
|
||||
|
||||
static void ProcessOneKeyframeCurve(int curveDataIndex, SerializedProperty curCurveData, float oneKeyframeTime)
|
||||
{
|
||||
var keyframe1 = curCurveData.GetArrayElementAtIndex(curveDataIndex - 3);
|
||||
var keyframe2 = curCurveData.GetArrayElementAtIndex(curveDataIndex - 2);
|
||||
var keyframe3 = curCurveData.GetArrayElementAtIndex(curveDataIndex - 1);
|
||||
var keyframe4 = curCurveData.GetArrayElementAtIndex(curveDataIndex);
|
||||
|
||||
float time1 = keyframe1.FindPropertyRelative("time").floatValue;
|
||||
float time2 = keyframe2.FindPropertyRelative("time").floatValue;
|
||||
float time3 = keyframe3.FindPropertyRelative("time").floatValue;
|
||||
float time4 = keyframe4.FindPropertyRelative("time").floatValue;
|
||||
|
||||
SerializedProperty outSlope1 = keyframe1.FindPropertyRelative("outSlope");
|
||||
SerializedProperty inSlope2 = keyframe2.FindPropertyRelative("inSlope");
|
||||
SerializedProperty outSlope2 = keyframe2.FindPropertyRelative("outSlope");
|
||||
SerializedProperty inSlope3 = keyframe3.FindPropertyRelative("inSlope");
|
||||
SerializedProperty outSlope3 = keyframe3.FindPropertyRelative("outSlope");
|
||||
SerializedProperty inSlope4 = keyframe4.FindPropertyRelative("inSlope");
|
||||
|
||||
//check constant keyframe
|
||||
if ((time2 - time1 <= oneKeyframeTime)
|
||||
&& (time3 - time2 <= oneKeyframeTime)
|
||||
&& (time4 - time3 <= oneKeyframeTime)
|
||||
)
|
||||
{
|
||||
var keyframeValue = keyframe1.FindPropertyRelative("value");
|
||||
|
||||
Debug.Log(string.Format("index:{0},{1},{2},{3}", curveDataIndex - 3, curveDataIndex - 2,
|
||||
curveDataIndex - 1, curveDataIndex));
|
||||
|
||||
switch (keyframeValue.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.Float:
|
||||
inSlope2.floatValue = float.PositiveInfinity;
|
||||
outSlope2.floatValue = float.PositiveInfinity;
|
||||
inSlope3.floatValue = float.PositiveInfinity;
|
||||
outSlope3.floatValue = float.PositiveInfinity;
|
||||
break;
|
||||
case SerializedPropertyType.Vector3:
|
||||
inSlope2.vector3Value = ConstantVector3;
|
||||
outSlope2.vector3Value = ConstantVector3;
|
||||
inSlope3.vector3Value = ConstantVector3;
|
||||
outSlope3.vector3Value = ConstantVector3;
|
||||
break;
|
||||
case SerializedPropertyType.Vector4:
|
||||
inSlope2.vector4Value = ConstantVector4;
|
||||
outSlope2.vector4Value = ConstantVector4;
|
||||
inSlope3.vector4Value = ConstantVector4;
|
||||
outSlope3.vector4Value = ConstantVector4;
|
||||
break;
|
||||
case SerializedPropertyType.Quaternion:
|
||||
inSlope2.quaternionValue = ConstantQuaternion;
|
||||
outSlope2.quaternionValue = ConstantQuaternion;
|
||||
inSlope3.quaternionValue = ConstantQuaternion;
|
||||
outSlope3.quaternionValue = ConstantQuaternion;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void MyFix(AnimationClip clip)
|
||||
{
|
||||
var soClip = new SerializedObject(clip);
|
||||
|
||||
string[] editorCurveSetNames = new string[] { "m_EditorCurves", "m_EulerEditorCurves", "m_RotationCurves" };
|
||||
//string[] editorCurveSetNames = new string[] { "m_EditorCurves" };
|
||||
|
||||
foreach (var editorCurveSetName in editorCurveSetNames)
|
||||
{
|
||||
var curCurveSet = soClip.FindProperty(editorCurveSetName);
|
||||
|
||||
for (int curveSetIndex = 0; curveSetIndex < curCurveSet.arraySize; curveSetIndex++)
|
||||
{
|
||||
var curCurveInfo = curCurveSet.GetArrayElementAtIndex(curveSetIndex);
|
||||
var curCurve = curCurveInfo.FindPropertyRelative("curve");
|
||||
var curCurveData = curCurve.FindPropertyRelative("m_Curve");
|
||||
int curCurveDataLength = curCurveData.arraySize;
|
||||
Debug.Log("curve lenght:" + curCurveDataLength);
|
||||
for (int index = 0; index < curCurveDataLength; index++)
|
||||
{
|
||||
var keyframe = curCurveData.GetArrayElementAtIndex(index);
|
||||
if (editorCurveSetName.Equals("m_RotationCurves"))
|
||||
{
|
||||
var infiniteQuaternion = new Quaternion(
|
||||
float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity,
|
||||
float.PositiveInfinity);
|
||||
keyframe.FindPropertyRelative("inSlope").quaternionValue = infiniteQuaternion;
|
||||
keyframe.FindPropertyRelative("outSlope").quaternionValue = infiniteQuaternion;
|
||||
}
|
||||
else if (keyframe.FindPropertyRelative("attribute")
|
||||
.stringValue.Contains("m_LocalRotation"))
|
||||
{
|
||||
keyframe.FindPropertyRelative("inSlope").floatValue = float.PositiveInfinity;
|
||||
keyframe.FindPropertyRelative("outSlope").floatValue = float.PositiveInfinity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
soClip.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c33bcfd692627dd4a97ac1cd1d930420
|
||||
guid: c5f9faab3428c1a479eecff16161bafa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
|
@ -1,65 +1,131 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Bread2Unity;
|
||||
using UnityEngine;
|
||||
using Animation = Bread2Unity.Animation;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class BCCAD : IDataModel
|
||||
public class BCCAD : DataModel
|
||||
{
|
||||
|
||||
public BCCAD Read(byte[] bytes)
|
||||
public static BCCAD Read(byte[] bytes)
|
||||
{
|
||||
sheetW = BitConverter.ToUInt16(bytes, 4);
|
||||
sheetH = BitConverter.ToUInt16(bytes, 6);
|
||||
|
||||
|
||||
// int max = (bytes[8] * 2) + 12;
|
||||
int max = 64 * bytes[8] + 12;
|
||||
|
||||
// note this doesn't account for empty sprites, but I'll get there when i get there
|
||||
for (int i = 12; i < max; i += 2) // 16 bit bytes, skip every 2nd byte
|
||||
BCCAD bccad = new BCCAD();
|
||||
var byteBuffer = new ByteBuffer(bytes);
|
||||
byteBuffer.ReadInt(); //timestamp
|
||||
bccad.sheetW = byteBuffer.ReadUShort();
|
||||
bccad.sheetH = byteBuffer.ReadUShort();
|
||||
// Sprites
|
||||
var spritesNum = byteBuffer.ReadInt();
|
||||
for (int i = 0; i < spritesNum; i++)
|
||||
{
|
||||
ISprite spriteParts_ = new ISprite();
|
||||
int compare = 0;
|
||||
for (int j = 0; j < bytes[i]; j++)
|
||||
BccadSprite bccadSprite = new BccadSprite();
|
||||
var partsNum = byteBuffer.ReadInt();
|
||||
for (int j = 0; j < partsNum; j++)
|
||||
{
|
||||
int ind = i + 4 + (64 * j);
|
||||
|
||||
ISpritePart part = new ISpritePart();
|
||||
part.regionX = BitConverter.ToUInt16(bytes, ind + 0);
|
||||
part.regionY = BitConverter.ToUInt16(bytes, ind + 2);
|
||||
part.regionW = BitConverter.ToUInt16(bytes, ind + 4);
|
||||
part.regionH = BitConverter.ToUInt16(bytes, ind + 6);
|
||||
part.posX = BitConverter.ToInt16(bytes, ind + 8);
|
||||
part.posY = BitConverter.ToInt16(bytes, ind + 10);
|
||||
part.stretchX = BitConverter.ToSingle(bytes, ind + 12);
|
||||
part.stretchY = BitConverter.ToSingle(bytes, ind + 14);
|
||||
part.rotation = BitConverter.ToSingle(bytes, ind + 16);
|
||||
part.flipX = bytes[ind + 18] != (byte)0;
|
||||
part.flipY = bytes[ind + 20] != (byte)0;
|
||||
// im sure the values between 20 and 28 are important so remind me to come back to these
|
||||
part.opacity = bytes[ind + 28];
|
||||
|
||||
Debug.Log("offset: " + ind + ", val: " + part.regionX);
|
||||
|
||||
spriteParts_.parts.Add(part);
|
||||
|
||||
compare += 64;
|
||||
}
|
||||
|
||||
sprites.Add(spriteParts_);
|
||||
|
||||
i += compare;
|
||||
|
||||
}
|
||||
|
||||
return new BCCAD()
|
||||
SpritePart part = new SpritePart();
|
||||
var region = new Region
|
||||
{
|
||||
regionX = byteBuffer.ReadUShort(),
|
||||
regionY = byteBuffer.ReadUShort(),
|
||||
regionW = byteBuffer.ReadUShort(),
|
||||
regionH = byteBuffer.ReadUShort()
|
||||
};
|
||||
var result = bccad.regions.FindIndex(x => Equals(x, region));
|
||||
if (result == -1)
|
||||
{
|
||||
bccad.regions.Add(region);
|
||||
part.RegionIndex = new RegionIndex(bccad.regions.Count - 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var repeatedNumber = bccadSprite.parts.Count(p => p.RegionIndex.Index == result);
|
||||
part.RegionIndex = new RegionIndex(result, repeatedNumber);
|
||||
|
||||
}
|
||||
part.PosX = byteBuffer.ReadShort();
|
||||
part.PosY = byteBuffer.ReadShort();
|
||||
part.StretchX = byteBuffer.ReadFloat();
|
||||
part.StretchY = byteBuffer.ReadFloat();
|
||||
part.Rotation = byteBuffer.ReadFloat();
|
||||
part.FlipX = byteBuffer.ReadByte() != 0;
|
||||
part.FlipY = byteBuffer.ReadByte() != 0;
|
||||
//Multicolor and screen color
|
||||
part.Multicolor = new Color(Convert.ToInt32(byteBuffer.ReadByte() & 0xff) / 255f,
|
||||
Convert.ToInt32(byteBuffer.ReadByte() & 0xff) / 255f,
|
||||
Convert.ToInt32(byteBuffer.ReadByte() & 0xff) / 255f);
|
||||
part.ScreenColor = new Color(Convert.ToInt32(byteBuffer.ReadByte() & 0xff) / 255f,
|
||||
Convert.ToInt32(byteBuffer.ReadByte() & 0xff) / 255f,
|
||||
Convert.ToInt32(byteBuffer.ReadByte() & 0xff) / 255f);
|
||||
|
||||
part.Opacity = byteBuffer.ReadByte();
|
||||
for (int k = 0; k < 12; k++)
|
||||
{
|
||||
byteBuffer.ReadByte();
|
||||
}
|
||||
|
||||
part.designation = byteBuffer.ReadByte();
|
||||
part.unknown = byteBuffer.ReadShort();
|
||||
part.tlDepth = byteBuffer.ReadFloat();
|
||||
part.blDepth = byteBuffer.ReadFloat();
|
||||
part.trDepth = byteBuffer.ReadFloat();
|
||||
part.brDepth = byteBuffer.ReadFloat();
|
||||
bccadSprite.parts.Add(part);
|
||||
}
|
||||
|
||||
/// sprites length bytes start = 12
|
||||
bccad.sprites.Add(bccadSprite);
|
||||
}
|
||||
|
||||
// Animations
|
||||
var animationsNum = byteBuffer.ReadInt();
|
||||
for (int i = 0; i < animationsNum; i++)
|
||||
{
|
||||
var anim = new Animation();
|
||||
var nameBuilder = new StringBuilder();
|
||||
var length = Convert.ToInt32(byteBuffer.ReadByte());
|
||||
for (int j = 0; j < length; j++)
|
||||
{
|
||||
nameBuilder.Append(Convert.ToChar(byteBuffer.ReadByte()));
|
||||
}
|
||||
|
||||
for (int j = 0; j < 4 - ((length + 1) % 4); j++)
|
||||
{
|
||||
byteBuffer.ReadByte();
|
||||
}
|
||||
|
||||
anim.Name = nameBuilder.ToString();
|
||||
anim.InterpolationInt = byteBuffer.ReadInt();
|
||||
var stepsNum = byteBuffer.ReadInt();
|
||||
for (int j = 0; j < stepsNum; j++)
|
||||
{
|
||||
var spriteIndex = byteBuffer.ReadUShort();
|
||||
var step = new AnimationStep
|
||||
{
|
||||
Delay = byteBuffer.ReadUShort(),
|
||||
TranslateX = byteBuffer.ReadShort(),
|
||||
TranslateY = byteBuffer.ReadShort(),
|
||||
Depth = byteBuffer.ReadFloat(),
|
||||
StretchX = byteBuffer.ReadFloat(),
|
||||
StretchY = byteBuffer.ReadFloat(),
|
||||
Rotation = byteBuffer.ReadFloat(),
|
||||
Color = new Color(Convert.ToInt32(byteBuffer.ReadByte() & 0xff) / 255f,
|
||||
Convert.ToInt32(byteBuffer.ReadByte() & 0xff) / 255f,
|
||||
Convert.ToInt32(byteBuffer.ReadByte() & 0xff) / 255f),
|
||||
BccadSprite = bccad.sprites[spriteIndex]
|
||||
};
|
||||
byteBuffer.ReadByte();
|
||||
byteBuffer.ReadByte();
|
||||
byteBuffer.ReadByte();
|
||||
step.Opacity = Convert.ToByte(Convert.ToInt32(byteBuffer.ReadShort()) & 0xFF);
|
||||
anim.Steps.Add(step);
|
||||
}
|
||||
|
||||
bccad.animations.Add(anim);
|
||||
}
|
||||
|
||||
return bccad;
|
||||
}
|
||||
}
|
||||
}
|
134
Assets/Editor/bread2unity/BccadPrefab.cs
Normal file
134
Assets/Editor/bread2unity/BccadPrefab.cs
Normal file
|
@ -0,0 +1,134 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Bread2Unity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class BccadPrefab
|
||||
{
|
||||
public GameObject ParentObject { get; }
|
||||
public readonly Dictionary<RegionIndex, GameObject> RegionToChild = new Dictionary<RegionIndex, GameObject>();
|
||||
private readonly List<GameObject> _children = new List<GameObject>();
|
||||
private readonly PrefabData _data;
|
||||
private readonly BCCAD _bccad;
|
||||
public float HeightRatio { get; }
|
||||
public float WidthRatio { get; }
|
||||
|
||||
public BccadPrefab(PrefabData data, BCCAD bccad, Texture2D texture)
|
||||
{
|
||||
ParentObject = new GameObject(data.Name);
|
||||
_data = data;
|
||||
HeightRatio = (float)texture.height / bccad.sheetH;
|
||||
WidthRatio = (float)texture.width / bccad.sheetW;
|
||||
_bccad = bccad;
|
||||
CalculateParts();
|
||||
}
|
||||
|
||||
private void CalculateParts()
|
||||
{
|
||||
var defaultSprite = _bccad.sprites[_data.SpriteIndex];
|
||||
if (_data.Animations.Count == 0)
|
||||
{
|
||||
for (var index = 0; index < defaultSprite.parts.Count; index++)
|
||||
{
|
||||
var part = defaultSprite.parts[index];
|
||||
var child = new GameObject($"{_data.Name} {index}");
|
||||
child.transform.SetParent(ParentObject.transform);
|
||||
_children.Add(child);
|
||||
RegionToChild.Add(part.RegionIndex, child);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Get all regions
|
||||
var anim = _data.Animations;
|
||||
var bccadSprites = anim.SelectMany(a => a.Steps).Select(step => step.BccadSprite).Distinct().ToList();
|
||||
var availableRegions = bccadSprites.SelectMany(sprite => sprite.parts).Select(part => part.RegionIndex)
|
||||
.Distinct().ToList();
|
||||
|
||||
var childIndex = 0;
|
||||
while (availableRegions.Count > 0)
|
||||
{
|
||||
var child = new GameObject($"{_data.Name} {childIndex}");
|
||||
child.transform.SetParent(ParentObject.transform);
|
||||
_children.Add(child);
|
||||
var nextRegion = availableRegions[0];
|
||||
availableRegions.RemoveAt(0);
|
||||
var regionsList = new List<RegionIndex> { nextRegion };
|
||||
while (true)
|
||||
{
|
||||
var notAdjacentRegions = FindNotAdjacentRegions(regionsList, bccadSprites, availableRegions);
|
||||
var maybeNotAdjacentRegion = availableRegions.Select(reg => (RegionIndex?)reg)
|
||||
.FirstOrDefault(region => notAdjacentRegions.Contains((RegionIndex)region));
|
||||
if (maybeNotAdjacentRegion is { } notAdjacentRegion)
|
||||
{
|
||||
availableRegions.Remove(notAdjacentRegion);
|
||||
regionsList.Add(notAdjacentRegion);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var r in regionsList)
|
||||
{
|
||||
RegionToChild.Add(r, child);
|
||||
}
|
||||
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<RegionIndex> FindNotAdjacentRegions(List<RegionIndex> regions, List<BccadSprite> sprites, List<RegionIndex> availableRegions)
|
||||
{
|
||||
var notAdjacentRegions = new List<RegionIndex>(availableRegions);
|
||||
foreach (var sprite in sprites)
|
||||
{
|
||||
var regionsOfSprite = sprite.parts.Select(part => part.RegionIndex).ToArray();
|
||||
if (regionsOfSprite.Intersect(regions).Any())
|
||||
{
|
||||
foreach (var r in regionsOfSprite)
|
||||
{
|
||||
notAdjacentRegions.Remove(r);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return notAdjacentRegions;
|
||||
}
|
||||
|
||||
public List<Tuple<int, SpritePart, GameObject>> GetHiddenParts()
|
||||
{
|
||||
var sprite = _bccad.sprites[_data.SpriteIndex];
|
||||
var pairs = new List<Tuple<int, SpritePart, GameObject>>();
|
||||
var gameObjects = new List<GameObject>(_children);
|
||||
foreach (var part in sprite.parts)
|
||||
{
|
||||
var child = RegionToChild[part.RegionIndex];
|
||||
gameObjects.Remove(child);
|
||||
}
|
||||
|
||||
foreach (var gameObject in gameObjects)
|
||||
{
|
||||
//find a random part associated with the game object
|
||||
var region = RegionToChild.FirstOrDefault(keyValuePair => keyValuePair.Value == gameObject)
|
||||
.Key;
|
||||
var parts = _data.Animations.SelectMany(anim => anim.Steps).Select(s => s.BccadSprite)
|
||||
.SelectMany(bccadSprite => bccadSprite.parts);
|
||||
|
||||
var partIndexPair = parts
|
||||
.Select((value, index) => new { value, index })
|
||||
.First(pair => pair.value.RegionIndex.Equals(region));
|
||||
var index = partIndexPair.index;
|
||||
var part = partIndexPair.value;
|
||||
pairs.Add(new Tuple<int, SpritePart, GameObject>(index, part, gameObject));
|
||||
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ddf1fd563dabc6040a863537a081843a
|
||||
guid: 7be9a40b9a8419b43aa454fa09e9ce78
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
61
Assets/Editor/bread2unity/BccadTest.cs
Normal file
61
Assets/Editor/bread2unity/BccadTest.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public static class BccadTest
|
||||
{
|
||||
public static void TestBccad()
|
||||
{
|
||||
const string folderPath =
|
||||
"C:\\Users\\Eliya\\games\\3DS\\PackEnglishV12\\PackEnglishV12\\PackHack\\ExtractedRomFS\\cellanim";
|
||||
var allFiles = Directory.GetFiles(folderPath, "*.bccad", SearchOption.AllDirectories);
|
||||
var problematicFiles = new HashSet<string>();
|
||||
foreach (var file in allFiles)
|
||||
{
|
||||
var bccad = BCCAD.Read(File.ReadAllBytes(file));
|
||||
var name = Path.GetFileName(file);
|
||||
for (var spriteIndex = 0; spriteIndex < bccad.sprites.Count; spriteIndex++)
|
||||
{
|
||||
var sprite = bccad.sprites[spriteIndex];
|
||||
/*for (var partIndex = 0; partIndex < sprite.parts.Count; partIndex++)
|
||||
{
|
||||
var part = sprite.parts[partIndex];
|
||||
if (part.Multicolor != Color.white)
|
||||
Debug.Log($"multycolor not white at {name} sprite: {spriteIndex} part: {partIndex}");
|
||||
|
||||
if (part.ScreenColor != Color.black)
|
||||
Debug.Log($"screen color not black at {name} sprite: {spriteIndex} part: {partIndex}");
|
||||
}*/
|
||||
var v = sprite.parts.GroupBy(p => p.FlipX)
|
||||
.Any(a => a.Select(part => part.RegionIndex.Index).Distinct().Count() < a.Count());
|
||||
// if (sprite.parts.Select(part => part.Region).Distinct().Count() < sprite.parts.Count)
|
||||
if(v)
|
||||
// Debug.Log($"duplicate regions {name} sprite: {spriteIndex}");
|
||||
problematicFiles.Add(name);
|
||||
}
|
||||
|
||||
/*for (var animIndex = 0; animIndex < bccad.animations.Count; animIndex++)
|
||||
{
|
||||
var anim = bccad.animations[animIndex];
|
||||
if (anim.Interpolated) Debug.Log($"interpolated {name} anim: {animIndex}");
|
||||
for (var stepIndex = 0; stepIndex < anim.Steps.Count; stepIndex++)
|
||||
{
|
||||
var step = anim.Steps[stepIndex];
|
||||
if(step.Color != Color.white)
|
||||
Debug.Log($"step color not white at {name} anim: {animIndex} step: {stepIndex}");
|
||||
if (step.Opacity != 255)
|
||||
Debug.Log($"step opacity not 255 at {name} anim: {animIndex} step: {stepIndex}");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
foreach (var filename in problematicFiles)
|
||||
{
|
||||
Debug.Log(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Editor/bread2unity/BccadTest.cs.meta
Normal file
11
Assets/Editor/bread2unity/BccadTest.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: af00b07ba074d9c44ab931b3b98e5605
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,47 +1,131 @@
|
|||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
using Starpelly;
|
||||
using Bread2Unity;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class Bread2Unity : EditorWindow
|
||||
public class Bread2UnityGUI : EditorWindow
|
||||
{
|
||||
public const string editorFolderName = "bread2unity";
|
||||
public const string EditorFolderName = "bread2unity";
|
||||
private GameObject _prefab;
|
||||
private DataModel animation;
|
||||
private List<PrefabData> _prefabDataList = new List<PrefabData>();
|
||||
private List<string> _animationsIndexes;
|
||||
private Vector2 _scrollPosition;
|
||||
|
||||
|
||||
[MenuItem("Tools/bread2unity")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
EditorWindow.GetWindow<Bread2Unity>("bread2unity");
|
||||
GetWindow<Bread2UnityGUI>("bread2unity");
|
||||
}
|
||||
|
||||
public void CreateGUI()
|
||||
{
|
||||
_animationsIndexes = new List<string>();
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
Texture logo = (Texture)AssetDatabase.LoadAssetAtPath($"Assets/Editor/{editorFolderName}/logo.png", typeof(Texture));
|
||||
GUILayout.Box(logo, new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.Height(60) });
|
||||
Texture logo =
|
||||
(Texture)AssetDatabase.LoadAssetAtPath($"Assets/Editor/{EditorFolderName}/logo.png", typeof(Texture));
|
||||
GUILayout.Box(logo, GUILayout.ExpandWidth(true), GUILayout.Height(60));
|
||||
GUILayout.Space(30);
|
||||
|
||||
GUIStyle desc = EditorStyles.label;
|
||||
desc.wordWrap = true;
|
||||
desc.fontStyle = FontStyle.BoldAndItalic;
|
||||
|
||||
GUILayout.Box("bread2unity is a tool built with the purpose of converting RH Megamix and Fever animations to unity. And to generally speed up development by a lot." +
|
||||
"\nCreated by Starpelly.", desc);
|
||||
GUILayout.Box(
|
||||
"bread2unity is a tool built with the purpose of converting RH Megamix animations to unity. And to generally speed up development by a lot.",
|
||||
desc);
|
||||
|
||||
GUILayout.Space(120);
|
||||
GUILayout.Space(60);
|
||||
EditorGUIUtility.labelWidth = 100;
|
||||
|
||||
if (GUILayout.Button("Test"))
|
||||
GUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PrefixLabel("Prefab");
|
||||
_prefab = (GameObject)EditorGUILayout.ObjectField(_prefab, typeof(GameObject), false);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, GUILayout.MaxHeight(60));
|
||||
var plusGuiStyle = new GUIStyle(GUI.skin.button)
|
||||
{
|
||||
string path = EditorUtility.OpenFilePanel("Open BCCAD File", null, "bccad");
|
||||
if (path.Length != 0)
|
||||
fontSize = 35,
|
||||
alignment = TextAnchor.MiddleCenter
|
||||
};
|
||||
var minusGuiStyle = new GUIStyle(GUI.skin.button)
|
||||
{
|
||||
var fileContent = File.ReadAllBytes(path);
|
||||
new BCCAD().Read(fileContent);
|
||||
fontSize = 35,
|
||||
alignment = TextAnchor.MiddleCenter
|
||||
};
|
||||
for (var i = 0; i < _prefabDataList.Count; i++)
|
||||
{
|
||||
var prefabData = _prefabDataList[i];
|
||||
GUILayout.BeginHorizontal();
|
||||
prefabData.Name = EditorGUILayout.TextField("Name", prefabData.Name);
|
||||
_animationsIndexes[i] = EditorGUILayout.TextField("Animations", _animationsIndexes[i]);
|
||||
prefabData.SpriteIndex =
|
||||
EditorGUILayout.IntField("Sprite Index", prefabData.SpriteIndex);
|
||||
if (GUILayout.Button("-", minusGuiStyle, GUILayout.Height(15), GUILayout.Width(15)))
|
||||
{
|
||||
_prefabDataList.RemoveAt(i);
|
||||
_animationsIndexes.RemoveAt(i);
|
||||
Repaint();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
if (GUILayout.Button("+", plusGuiStyle, GUILayout.Height(40), GUILayout.Width(40)))
|
||||
{
|
||||
_prefabDataList.Add(new PrefabData("", 0));
|
||||
_animationsIndexes.Add("");
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
if (GUILayout.Button("Create Prefabs (WIP)") && _prefab != null)
|
||||
{
|
||||
//Choose png and bccad files
|
||||
var bccadFilePath = EditorUtility.OpenFilePanel("Open BCCAD File", null, "bccad");
|
||||
var bccadFileFolder = Path.GetDirectoryName(bccadFilePath);
|
||||
var pngFilePath = EditorUtility.OpenFilePanel("Open Texture File", bccadFileFolder, "png");
|
||||
if (bccadFilePath != null && pngFilePath != null)
|
||||
{
|
||||
var bccad = BCCAD.Read(File.ReadAllBytes(bccadFilePath));
|
||||
var spriteTexture = SpriteCreator.ComputeSprites(bccad, pngFilePath, _prefab.name);
|
||||
//Create prefab from prefab data
|
||||
for (int i = 0; i < _prefabDataList.Count; i++)
|
||||
{
|
||||
List<int> animationIndexes;
|
||||
var prefabData = _prefabDataList[i];
|
||||
if (_animationsIndexes[i].Equals(""))
|
||||
animationIndexes = new List<int>();
|
||||
else
|
||||
animationIndexes = _animationsIndexes[i].Split(',').Select(int.Parse).ToList();
|
||||
prefabData.Animations =
|
||||
animationIndexes.Select(index => bccad.animations[index]).ToList();
|
||||
}
|
||||
|
||||
PrefabCreator.CreatePrefab(_prefab, bccad, _prefabDataList, spriteTexture);
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("bccad test"))
|
||||
{
|
||||
BccadTest.TestBccad();
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
|
@ -49,6 +133,7 @@ namespace Bread2Unity
|
|||
{
|
||||
Application.OpenURL("https://github.com/rhmodding/bread");
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
|
52
Assets/Editor/bread2unity/ByteBuffer.cs
Normal file
52
Assets/Editor/bread2unity/ByteBuffer.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class ByteBuffer
|
||||
{
|
||||
private readonly byte[] _bytes;
|
||||
|
||||
public int ReadPoint{ get; private set; }
|
||||
|
||||
public ByteBuffer(byte[] bytes)
|
||||
{
|
||||
_bytes = bytes;
|
||||
ReadPoint = 0;
|
||||
}
|
||||
|
||||
public ushort ReadUShort()
|
||||
{
|
||||
var result = BitConverter.ToUInt16(_bytes, ReadPoint);
|
||||
ReadPoint += sizeof(ushort);
|
||||
return result;
|
||||
}
|
||||
|
||||
public short ReadShort()
|
||||
{
|
||||
var result = BitConverter.ToInt16(_bytes, ReadPoint);
|
||||
ReadPoint += sizeof(short);
|
||||
return result;
|
||||
}
|
||||
|
||||
public float ReadFloat()
|
||||
{
|
||||
float result = BitConverter.ToSingle(_bytes, ReadPoint);
|
||||
ReadPoint += sizeof(float);
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
byte result = _bytes[ReadPoint];
|
||||
ReadPoint += sizeof(byte);
|
||||
return result;
|
||||
}
|
||||
|
||||
public int ReadInt()
|
||||
{
|
||||
int result = BitConverter.ToInt32(_bytes, ReadPoint);
|
||||
ReadPoint += sizeof(int);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Editor/bread2unity/ByteBuffer.cs.meta
Normal file
11
Assets/Editor/bread2unity/ByteBuffer.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1883cd0d74b590740936a6ffc3580eb6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
35
Assets/Editor/bread2unity/Model/Animation.cs
Normal file
35
Assets/Editor/bread2unity/Model/Animation.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class Animation
|
||||
{
|
||||
public List<AnimationStep> Steps = new List<AnimationStep>();
|
||||
public string Name;
|
||||
public int InterpolationInt = 0;
|
||||
|
||||
public bool Interpolated => (InterpolationInt & 0b1) > 0;
|
||||
}
|
||||
|
||||
public class AnimationStep
|
||||
{
|
||||
public ushort Delay;
|
||||
|
||||
public BccadSprite BccadSprite;
|
||||
|
||||
public short TranslateX;
|
||||
public short TranslateY;
|
||||
|
||||
public float Depth;
|
||||
|
||||
public float StretchX;
|
||||
public float StretchY;
|
||||
|
||||
public float Rotation;
|
||||
|
||||
public byte Opacity;
|
||||
public Color Color;
|
||||
}
|
||||
}
|
11
Assets/Editor/bread2unity/Model/Animation.cs.meta
Normal file
11
Assets/Editor/bread2unity/Model/Animation.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 994f68ab1a3b68b49a0ae01b0bf37f0c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
70
Assets/Editor/bread2unity/Model/BCCADSprite.cs
Normal file
70
Assets/Editor/bread2unity/Model/BCCADSprite.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class BccadSprite
|
||||
{
|
||||
public List<SpritePart> parts = new List<SpritePart>();
|
||||
}
|
||||
|
||||
public class SpritePart
|
||||
{
|
||||
public RegionIndex RegionIndex;
|
||||
|
||||
public short PosX;
|
||||
public short PosY;
|
||||
|
||||
public float StretchX;
|
||||
public float StretchY;
|
||||
|
||||
public float Rotation;
|
||||
|
||||
public bool FlipX;
|
||||
public bool FlipY;
|
||||
|
||||
public byte Opacity;
|
||||
|
||||
public byte designation;
|
||||
public short unknown;
|
||||
public float tlDepth;
|
||||
public float blDepth;
|
||||
public float trDepth;
|
||||
public float brDepth;
|
||||
public Color Multicolor;
|
||||
public Color ScreenColor;
|
||||
public Color GetColor() => new Color(Multicolor.r, Multicolor.g, Multicolor.b, Opacity / 255f);
|
||||
}
|
||||
|
||||
public struct RegionIndex
|
||||
{
|
||||
public int Index { get; }
|
||||
public int RepeatedNumber { get; }
|
||||
|
||||
public RegionIndex(int index, int repeatedNumber)
|
||||
{
|
||||
RepeatedNumber = repeatedNumber;
|
||||
Index = index;
|
||||
}
|
||||
|
||||
public bool Equals(RegionIndex other)
|
||||
{
|
||||
return Index == other.Index && RepeatedNumber == other.RepeatedNumber;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is RegionIndex other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 23;
|
||||
hash = hash * 31 + Index;
|
||||
hash = hash * 31 + RepeatedNumber;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Editor/bread2unity/Model/BCCADSprite.cs.meta
Normal file
11
Assets/Editor/bread2unity/Model/BCCADSprite.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ea35991e78a2918439cc249d1e4e293e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
52
Assets/Editor/bread2unity/Model/DataModel.cs
Normal file
52
Assets/Editor/bread2unity/Model/DataModel.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class DataModel
|
||||
{
|
||||
public List<Region> regions = new List<Region>();
|
||||
public List<BccadSprite> sprites = new List<BccadSprite>();
|
||||
public List<Animation> animations = new List<Animation>();
|
||||
public int sheetW;
|
||||
public int sheetH;
|
||||
}
|
||||
|
||||
public class Region
|
||||
{
|
||||
public ushort regionX;
|
||||
public ushort regionY;
|
||||
public ushort regionW;
|
||||
public ushort regionH;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"regionX: {regionX} regionY: {regionY} regionW: {regionW} regionH: {regionH}";
|
||||
}
|
||||
|
||||
protected bool Equals(Region other)
|
||||
{
|
||||
return regionX == other.regionX && regionY == other.regionY && regionW == other.regionW &&
|
||||
regionH == other.regionH;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((Region)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 23;
|
||||
hash = hash * 31 + regionX;
|
||||
hash = hash * 31 + regionY;
|
||||
hash = hash * 31 + regionW;
|
||||
hash = hash * 31 + regionH;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Editor/bread2unity/Model/DataModel.cs.meta
Normal file
11
Assets/Editor/bread2unity/Model/DataModel.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c90d75428898ac74e819c39b7249f133
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,24 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class IAnimation
|
||||
{
|
||||
public List<IAnimationStep> steps;
|
||||
}
|
||||
|
||||
public class IAnimationStep
|
||||
{
|
||||
public ushort spriteIndex;
|
||||
public ushort delay;
|
||||
|
||||
public float stretchX;
|
||||
public float stretchY;
|
||||
|
||||
public float rotation;
|
||||
|
||||
public byte opacity;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class IDataModel
|
||||
{
|
||||
public List<ISprite> sprites = new List<ISprite>();
|
||||
public List<IAnimation> animations = new List<IAnimation>();
|
||||
public int sheetW;
|
||||
public int sheetH;
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class ISprite
|
||||
{
|
||||
public List<ISpritePart> parts = new List<ISpritePart>();
|
||||
}
|
||||
|
||||
public class ISpritePart
|
||||
{
|
||||
public ushort regionX;
|
||||
public ushort regionY;
|
||||
public ushort regionW;
|
||||
public ushort regionH;
|
||||
|
||||
public short posX;
|
||||
public short posY;
|
||||
|
||||
public float stretchX;
|
||||
public float stretchY;
|
||||
|
||||
public float rotation;
|
||||
|
||||
public bool flipX;
|
||||
public bool flipY;
|
||||
|
||||
public byte opacity;
|
||||
}
|
||||
}
|
83
Assets/Editor/bread2unity/PrefabCreator.cs
Normal file
83
Assets/Editor/bread2unity/PrefabCreator.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Bread2Unity;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Animation = Bread2Unity.Animation;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public static class PrefabCreator
|
||||
{
|
||||
public static void CreatePrefab(GameObject prefab, BCCAD bccad,
|
||||
List<PrefabData> prefabDataList, Texture2D texture)
|
||||
{
|
||||
var prefabName = prefab.name;
|
||||
var spritesFolderPath =
|
||||
$"Sprites\\Games\\{char.ToUpperInvariant(prefabName[0]) + prefabName.Substring(1)}";
|
||||
var prefabAssetPath = AssetDatabase.GetAssetPath(prefab);
|
||||
var root = PrefabUtility.LoadPrefabContents(prefabAssetPath);
|
||||
foreach (var prefabData in prefabDataList)
|
||||
{
|
||||
var defaultSprite = bccad.sprites[prefabData.SpriteIndex];
|
||||
var bccadPrefab = new BccadPrefab(prefabData, bccad, texture);
|
||||
var newPrefab = bccadPrefab.ParentObject;
|
||||
newPrefab.transform.SetParent(root.transform);
|
||||
var sprites = Resources.LoadAll<Sprite>(spritesFolderPath).ToList()
|
||||
.FindAll(s => s.name.Contains(texture.name));
|
||||
for (var index = 0; index < defaultSprite.parts.Count; index++)
|
||||
{
|
||||
var spritePart = defaultSprite.parts[index];
|
||||
var gameObjectPart = bccadPrefab.RegionToChild[spritePart.RegionIndex];
|
||||
ApplySpriteSettingsFromBccad(gameObjectPart, spritePart, bccadPrefab,
|
||||
sprites[spritePart.RegionIndex.Index],
|
||||
index);
|
||||
}
|
||||
|
||||
foreach (var (partIndex, spritePart, hiddenGameObject) in bccadPrefab.GetHiddenParts())
|
||||
{
|
||||
hiddenGameObject.SetActive(false);
|
||||
ApplySpriteSettingsFromBccad(hiddenGameObject, spritePart, bccadPrefab,
|
||||
sprites[spritePart.RegionIndex.Index], partIndex);
|
||||
}
|
||||
|
||||
if (prefabData.Animations.Count > 0)
|
||||
AnimationCreator.CreateAnimation(bccadPrefab, bccad, prefabData, sprites);
|
||||
|
||||
PrefabUtility.SaveAsPrefabAsset(root, AssetDatabase.GetAssetPath(prefab));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplySpriteSettingsFromBccad(GameObject gameObjectPart, SpritePart spritePart,
|
||||
BccadPrefab prefab, Sprite sprite, int index)
|
||||
{
|
||||
var spriteRenderer = (SpriteRenderer)gameObjectPart.AddComponent(typeof(SpriteRenderer));
|
||||
|
||||
spriteRenderer.sprite = sprite;
|
||||
spriteRenderer.color = spritePart.GetColor();
|
||||
spriteRenderer.flipX = spritePart.FlipX;
|
||||
spriteRenderer.flipY = spritePart.FlipY;
|
||||
spriteRenderer.enabled = true;
|
||||
gameObjectPart.transform.SetParent(prefab.ParentObject.transform);
|
||||
|
||||
// Bread draws sprites from the edge, and unity from the middle.
|
||||
var width = spritePart.StretchX / prefab.WidthRatio;
|
||||
var height = spritePart.StretchY / prefab.HeightRatio;
|
||||
// var pixelsPerUnit = 73;
|
||||
|
||||
var position =
|
||||
new Vector3(
|
||||
(spritePart.PosX - 512f) /
|
||||
SpriteCreator.PixelsPerUnit + sprite.bounds.size.x * 0.5f * width,
|
||||
-(spritePart.PosY - 512f) / SpriteCreator.PixelsPerUnit -
|
||||
sprite.bounds.size.y * 0.5f * height,
|
||||
-0.00001f * index);
|
||||
var rotation = Quaternion.AngleAxis(spritePart.Rotation, new Vector3(0, 0, -1));
|
||||
gameObjectPart.transform.localPosition = position;
|
||||
gameObjectPart.transform.localRotation = rotation;
|
||||
gameObjectPart.transform.localScale = new Vector3(width, height, 1f);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Editor/bread2unity/PrefabCreator.cs.meta
Normal file
11
Assets/Editor/bread2unity/PrefabCreator.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 59809bd6fc62dce4aab4eb333ffbdc64
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
18
Assets/Editor/bread2unity/PrefabData.cs
Normal file
18
Assets/Editor/bread2unity/PrefabData.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System.Collections.Generic;
|
||||
using Bread2Unity;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class PrefabData
|
||||
{
|
||||
public string Name;
|
||||
public List<Animation> Animations;
|
||||
public int SpriteIndex;
|
||||
|
||||
public PrefabData(string name, int spriteIndex)
|
||||
{
|
||||
Name = name;
|
||||
SpriteIndex = spriteIndex;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Editor/bread2unity/PrefabData.cs.meta
Normal file
11
Assets/Editor/bread2unity/PrefabData.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6807e41eb8dc0ae46b2e5b728af55e2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
103
Assets/Editor/bread2unity/SpriteCreator.cs
Normal file
103
Assets/Editor/bread2unity/SpriteCreator.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
using Bread2Unity;
|
||||
|
||||
namespace Bread2Unity
|
||||
{
|
||||
public class SpriteCreator : MonoBehaviour
|
||||
{
|
||||
public const int PixelsPerUnit = 100;
|
||||
public static Texture2D ComputeSprites(BCCAD bccad, string texturePath, string prefabName)
|
||||
{
|
||||
var textureName = Path.GetFileName(texturePath);
|
||||
var spritesFolder =
|
||||
$"Assets\\Resources\\Sprites\\Games\\{char.ToUpperInvariant(prefabName[0]) + prefabName.Substring(1)}\\";
|
||||
if (!Directory.Exists(spritesFolder))
|
||||
{
|
||||
Directory.CreateDirectory(spritesFolder);
|
||||
}
|
||||
|
||||
var destTexturePath =
|
||||
spritesFolder +
|
||||
$"{textureName}";
|
||||
var newTexture = new Texture2D(bccad.sheetW, bccad.sheetH);
|
||||
newTexture.LoadImage(File.ReadAllBytes(texturePath));
|
||||
var rotatedTexture = RotateTexture(newTexture);
|
||||
rotatedTexture.name = textureName.Substring(0, textureName.Length - ".png".Length);
|
||||
File.WriteAllBytes(destTexturePath, rotatedTexture.EncodeToPNG());
|
||||
AssetDatabase.ImportAsset(destTexturePath);
|
||||
var ti = AssetImporter.GetAtPath(destTexturePath) as TextureImporter;
|
||||
|
||||
if (ti != null)
|
||||
{
|
||||
ti.isReadable = true;
|
||||
// constants
|
||||
ti.textureType = TextureImporterType.Sprite;
|
||||
ti.spriteImportMode = SpriteImportMode.Multiple;
|
||||
ti.spritePixelsPerUnit = PixelsPerUnit;
|
||||
ti.filterMode = FilterMode.Point;
|
||||
ti.textureCompression = TextureImporterCompression.Uncompressed;
|
||||
var newData = new List<SpriteMetaData>();
|
||||
var rectCtr = 0;
|
||||
var heightRatio = (float)rotatedTexture.height / bccad.sheetH;
|
||||
var widthRatio = (float)rotatedTexture.width / bccad.sheetW;
|
||||
foreach (var r in bccad.regions)
|
||||
{
|
||||
var smd = new SpriteMetaData
|
||||
{
|
||||
pivot = new Vector2(0.5f, 0.5f),
|
||||
alignment = 0,
|
||||
name = rotatedTexture.name + "_" + rectCtr,
|
||||
rect = new Rect(r.regionX * widthRatio,
|
||||
rotatedTexture.height - (r.regionH + r.regionY) * heightRatio, r.regionW * widthRatio,
|
||||
r.regionH * heightRatio)
|
||||
};
|
||||
|
||||
newData.Add(smd);
|
||||
rectCtr++;
|
||||
}
|
||||
|
||||
ti.spritesheet = newData.ToArray();
|
||||
}
|
||||
|
||||
AssetDatabase.ImportAsset(destTexturePath, ImportAssetOptions.ForceUpdate);
|
||||
return rotatedTexture;
|
||||
}
|
||||
|
||||
public static Texture2D RotateTexture(Texture2D image)
|
||||
{
|
||||
Texture2D
|
||||
target = new Texture2D(image.height, image.width, image.format,
|
||||
false); //flip image width<>height, as we rotated the image, it might be a rect. not a square image
|
||||
|
||||
Color32[] pixels = image.GetPixels32(0);
|
||||
pixels = RotateTextureGrid(pixels, image.width, image.height);
|
||||
target.SetPixels32(pixels);
|
||||
target.Apply();
|
||||
|
||||
//flip image width<>height, as we rotated the image, it might be a rect. not a square image
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
private static Color32[] RotateTextureGrid(Color32[] tex, int wid, int hi)
|
||||
{
|
||||
Color32[] ret = new Color32[wid * hi]; //reminder we are flipping these in the target
|
||||
|
||||
for (int y = 0; y < hi; y++)
|
||||
{
|
||||
for (int x = 0; x < wid; x++)
|
||||
{
|
||||
ret[(hi - 1) - y + x * hi] = tex[x + y * wid]; //juggle the pixels around
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Editor/bread2unity/SpriteCreator.cs.meta
Normal file
11
Assets/Editor/bread2unity/SpriteCreator.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3a4430af4dfb91f4f9720962a6eef059
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in a new issue