v0.80.30
This commit is contained in:
@@ -2,9 +2,9 @@ using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using AssetStudio.PInvoke;
|
||||
|
||||
namespace ACL
|
||||
namespace ACLLibs
|
||||
{
|
||||
public static class ACL
|
||||
public static partial class ACL
|
||||
{
|
||||
private const string DLL_NAME = "acl";
|
||||
static ACL()
|
||||
@@ -27,20 +27,20 @@ namespace ACL
|
||||
|
||||
#region importfunctions
|
||||
|
||||
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void DecompressAll(IntPtr data, out IntPtr pValues, out int numValues, out IntPtr pTimes, out int numTimes);
|
||||
[LibraryImport(DLL_NAME)]
|
||||
private static partial void DecompressAll(IntPtr data, out IntPtr pValues, out int numValues, out IntPtr pTimes, out int numTimes);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class SRACL
|
||||
public static partial class SRACL
|
||||
{
|
||||
private const string DLL_NAME = "sracl";
|
||||
static SRACL()
|
||||
{
|
||||
DllLoader.PreloadDll(DLL_NAME);
|
||||
}
|
||||
public static void DecompressAll(uint[] data, out float[] values, out float[] times)
|
||||
public static void DecompressAll(byte[] data, out float[] values, out float[] times)
|
||||
{
|
||||
var pinned = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
var pData = pinned.AddrOfPinnedObject();
|
||||
@@ -56,8 +56,8 @@ namespace ACL
|
||||
|
||||
#region importfunctions
|
||||
|
||||
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void DecompressAll(IntPtr data, out IntPtr pValues, out int numValues, out IntPtr pTimes, out int numTimes);
|
||||
[LibraryImport(DLL_NAME)]
|
||||
private static partial void DecompressAll(IntPtr data, out IntPtr pValues, out int numValues, out IntPtr pTimes, out int numTimes);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
namespace AssetStudio
|
||||
using ACLLibs;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class ACLExtensions
|
||||
{
|
||||
public static void Process(this ACLClip m_ACLClip, out float[] values, out float[] times) => ACL.ACL.DecompressAll(m_ACLClip.m_ClipData, out values, out times);
|
||||
public static void ProcessSR(this ACLClip m_ACLClip, out float[] values, out float[] times) => ACL.SRACL.DecompressAll(m_ACLClip.m_ClipDataUint, out values, out times);
|
||||
public static void Process(this ACLClip m_ACLClip, out float[] values, out float[] times) => ACL.DecompressAll(m_ACLClip.m_ClipData, out values, out times);
|
||||
public static void ProcessSR(this ACLClip m_ACLClip, out float[] values, out float[] times) => SRACL.DecompressAll(m_ACLClip.m_ClipData, out values, out times);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,499 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AnimationClipConverter
|
||||
{
|
||||
private readonly AnimationClip animationClip;
|
||||
|
||||
public static readonly Regex UnknownPathRegex = new Regex($@"^path_[0-9]{{1,10}}$", RegexOptions.Compiled);
|
||||
|
||||
private readonly Dictionary<Vector3Curve, List<Keyframe<Vector3>>> m_translations = new Dictionary<Vector3Curve, List<Keyframe<Vector3>>>();
|
||||
private readonly Dictionary<QuaternionCurve, List<Keyframe<Quaternion>>> m_rotations = new Dictionary<QuaternionCurve, List<Keyframe<Quaternion>>>();
|
||||
private readonly Dictionary<Vector3Curve, List<Keyframe<Vector3>>> m_scales = new Dictionary<Vector3Curve, List<Keyframe<Vector3>>>();
|
||||
private readonly Dictionary<Vector3Curve, List<Keyframe<Vector3>>> m_eulers = new Dictionary<Vector3Curve, List<Keyframe<Vector3>>>();
|
||||
private readonly Dictionary<FloatCurve, List<Keyframe<Float>>> m_floats = new Dictionary<FloatCurve, List<Keyframe<Float>>>();
|
||||
private readonly Dictionary<PPtrCurve, List<PPtrKeyframe>> m_pptrs = new Dictionary<PPtrCurve, List<PPtrKeyframe>>();
|
||||
|
||||
public Vector3Curve[] Translations { get; private set; }
|
||||
public QuaternionCurve[] Rotations { get; private set; }
|
||||
public Vector3Curve[] Scales { get; private set; }
|
||||
public Vector3Curve[] Eulers { get; private set; }
|
||||
public FloatCurve[] Floats { get; private set; }
|
||||
public PPtrCurve[] PPtrs { get; private set; }
|
||||
|
||||
public Game Game;
|
||||
|
||||
public AnimationClipConverter(AnimationClip clip, Game game)
|
||||
{
|
||||
animationClip = clip;
|
||||
Game = game;
|
||||
}
|
||||
|
||||
public static AnimationClipConverter Process(AnimationClip clip, Game game)
|
||||
{
|
||||
var converter = new AnimationClipConverter(clip, game);
|
||||
converter.ProcessInner();
|
||||
return converter;
|
||||
}
|
||||
private void ProcessInner()
|
||||
{
|
||||
var m_Clip = animationClip.m_MuscleClip.m_Clip;
|
||||
var bindings = animationClip.m_ClipBindingConstant;
|
||||
var tos = animationClip.FindTOS();
|
||||
|
||||
var streamedFrames = m_Clip.m_StreamedClip.ReadData();
|
||||
var lastDenseFrame = m_Clip.m_DenseClip.m_FrameCount / m_Clip.m_DenseClip.m_SampleRate;
|
||||
var lastSampleFrame = streamedFrames.Count > 1 ? streamedFrames[streamedFrames.Count - 2].time : 0.0f;
|
||||
var lastFrame = Math.Max(lastDenseFrame, lastSampleFrame);
|
||||
|
||||
if (m_Clip.m_ACLClip.IsSet && Game.Name != "SR_CB2" && Game.Name != "SR_CB3")
|
||||
{
|
||||
var lastACLFrame = ProcessACLClip(m_Clip, bindings, tos);
|
||||
lastFrame = Math.Max(lastFrame, lastACLFrame);
|
||||
}
|
||||
ProcessStreams(streamedFrames, bindings, tos, m_Clip.m_DenseClip.m_SampleRate);
|
||||
ProcessDenses(m_Clip, bindings, tos);
|
||||
if (m_Clip.m_ACLClip.IsSet && (Game.Name == "SR_CB2" || Game.Name == "SR_CB3"))
|
||||
{
|
||||
var lastACLFrame = ProcessACLClip(m_Clip, bindings, tos);
|
||||
lastFrame = Math.Max(lastFrame, lastACLFrame);
|
||||
}
|
||||
if (m_Clip.m_ConstantClip != null)
|
||||
{
|
||||
ProcessConstant(m_Clip, bindings, tos, lastFrame);
|
||||
}
|
||||
CreateCurves();
|
||||
}
|
||||
|
||||
private void CreateCurves()
|
||||
{
|
||||
Translations = m_translations.Select(t => new Vector3Curve(t.Key, t.Value)).ToArray();
|
||||
Rotations = m_rotations.Select(t => new QuaternionCurve(t.Key, t.Value)).ToArray();
|
||||
Scales = m_scales.Select(t => new Vector3Curve(t.Key, t.Value)).ToArray();
|
||||
Eulers = m_eulers.Select(t => new Vector3Curve(t.Key, t.Value)).ToArray();
|
||||
Floats = m_floats.Select(t => new FloatCurve(t.Key, t.Value)).ToArray();
|
||||
PPtrs = m_pptrs.Select(t => new PPtrCurve(t.Key, t.Value)).ToArray();
|
||||
}
|
||||
|
||||
private void ProcessStreams(List<StreamedClip.StreamedFrame> streamFrames, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos, float sampleRate)
|
||||
{
|
||||
var curveValues = new float[4];
|
||||
var inSlopeValues = new float[4];
|
||||
var outSlopeValues = new float[4];
|
||||
var interval = 1.0f / sampleRate;
|
||||
|
||||
// first (index [0]) stream frame is for slope calculation for the first real frame (index [1])
|
||||
// last one (index [count - 1]) is +Infinity
|
||||
// it is made for slope processing, but we don't need them
|
||||
for (var frameIndex = 1; frameIndex < streamFrames.Count - 1; frameIndex++)
|
||||
{
|
||||
var frame = streamFrames[frameIndex];
|
||||
for (var curveIndex = 0; curveIndex < frame.keyList.Length;)
|
||||
{
|
||||
var curve = frame.keyList[curveIndex];
|
||||
var index = curve.index;
|
||||
if (animationClip.m_MuscleClip.m_Clip.m_ACLClip.IsSet && Game.Name != "SR_CB2" && Game.Name != "SR_CB3")
|
||||
index += (int)animationClip.m_MuscleClip.m_Clip.m_ACLClip.m_CurveCount;
|
||||
var binding = bindings.FindBinding(index);
|
||||
|
||||
var path = GetCurvePath(tos, binding.path);
|
||||
if (binding.typeID == ClassIDType.Transform)
|
||||
{
|
||||
GetPreviousFrame(streamFrames, curve.index, frameIndex, out var prevFrameIndex, out var prevCurveIndex);
|
||||
var dimension = binding.GetDimension();
|
||||
for (int key = 0; key < dimension; key++)
|
||||
{
|
||||
var keyCurve = frame.keyList[curveIndex];
|
||||
var prevFrame = streamFrames[prevFrameIndex];
|
||||
var prevKeyCurve = prevFrame.keyList[prevCurveIndex + key];
|
||||
var deltaTime = frame.time - prevFrame.time;
|
||||
curveValues[key] = keyCurve.value;
|
||||
inSlopeValues[key] = prevKeyCurve.CalculateNextInSlope(deltaTime, keyCurve);
|
||||
outSlopeValues[key] = keyCurve.outSlope;
|
||||
curveIndex = GetNextCurve(frame, curveIndex);
|
||||
}
|
||||
|
||||
AddTransformCurve(frame.time, binding.attribute, curveValues, inSlopeValues, outSlopeValues, 0, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (binding.customType == 8)
|
||||
{
|
||||
AddAnimatorMuscleCurve(binding, frame.time, frame.keyList[curveIndex].value);
|
||||
}
|
||||
else if (binding.customType == 20)
|
||||
{
|
||||
AddBlendShapeCurve(binding, path, frame.time, frame.keyList[curveIndex].value);
|
||||
}
|
||||
curveIndex = GetNextCurve(frame, curveIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDenses(Clip clip, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos)
|
||||
{
|
||||
var dense = clip.m_DenseClip;
|
||||
var streamCount = clip.m_StreamedClip.curveCount;
|
||||
var slopeValues = new float[4]; // no slopes - 0 values
|
||||
for (var frameIndex = 0; frameIndex < dense.m_FrameCount; frameIndex++)
|
||||
{
|
||||
var time = frameIndex / dense.m_SampleRate;
|
||||
var frameOffset = frameIndex * (int)dense.m_CurveCount;
|
||||
for (var curveIndex = 0; curveIndex < dense.m_CurveCount;)
|
||||
{
|
||||
var index = (int)streamCount + curveIndex;
|
||||
if (clip.m_ACLClip.IsSet && Game.Name != "SR_CB2" && Game.Name != "SR_CB3")
|
||||
index += (int)clip.m_ACLClip.m_CurveCount;
|
||||
var binding = bindings.FindBinding(index);
|
||||
var path = GetCurvePath(tos, binding.path);
|
||||
var framePosition = frameOffset + curveIndex;
|
||||
if (binding.typeID == ClassIDType.Transform)
|
||||
{
|
||||
AddTransformCurve(time, binding.attribute, dense.m_SampleArray, slopeValues, slopeValues, framePosition, path);
|
||||
curveIndex += binding.GetDimension();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (binding.customType == 8)
|
||||
{
|
||||
AddAnimatorMuscleCurve(binding, time, dense.m_SampleArray[framePosition]);
|
||||
}
|
||||
else if (binding.customType == 20)
|
||||
{
|
||||
AddBlendShapeCurve(binding, path, time, dense.m_SampleArray[framePosition]);
|
||||
}
|
||||
curveIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private float ProcessACLClip(Clip clip, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos)
|
||||
{
|
||||
float[] values;
|
||||
float[] times;
|
||||
var acl = clip.m_ACLClip;
|
||||
if (Game.Name != "SR_CB2" && Game.Name != "SR_CB3")
|
||||
{
|
||||
acl.Process(out values, out times);
|
||||
}
|
||||
else
|
||||
{
|
||||
acl.ProcessSR(out values, out times);
|
||||
}
|
||||
float[] slopeValues = new float[4]; // no slopes - 0 values
|
||||
|
||||
int frameCount = times.Length;
|
||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
|
||||
{
|
||||
float time = times[frameIndex];
|
||||
int frameOffset = frameIndex * (int)acl.m_CurveCount;
|
||||
for (int curveIndex = 0; curveIndex < acl.m_CurveCount;)
|
||||
{
|
||||
var index = curveIndex;
|
||||
if (Game.Name == "SR_CB2" || Game.Name == "SR_CB3")
|
||||
index += (int)(clip.m_StreamedClip.curveCount + clip.m_DenseClip.m_CurveCount);
|
||||
GenericBinding binding = bindings.FindBinding(index);
|
||||
string path = GetCurvePath(tos, binding.path);
|
||||
int framePosition = frameOffset + curveIndex;
|
||||
if (binding.typeID == ClassIDType.Transform)
|
||||
{
|
||||
AddTransformCurve(time, binding.attribute, values, slopeValues, slopeValues, framePosition, path);
|
||||
curveIndex += binding.GetDimension();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (binding.customType == 8)
|
||||
{
|
||||
AddAnimatorMuscleCurve(binding, time, values[framePosition]);
|
||||
}
|
||||
else if (binding.customType == 20)
|
||||
{
|
||||
AddBlendShapeCurve(binding, path, time, values[framePosition]);
|
||||
}
|
||||
curveIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return times[frameCount - 1];
|
||||
}
|
||||
private void ProcessConstant(Clip clip, AnimationClipBindingConstant bindings, Dictionary<uint, string> tos, float lastFrame)
|
||||
{
|
||||
var constant = clip.m_ConstantClip;
|
||||
var streamCount = clip.m_StreamedClip.curveCount;
|
||||
var denseCount = clip.m_DenseClip.m_CurveCount;
|
||||
var slopeValues = new float[4]; // no slopes - 0 values
|
||||
|
||||
// only first and last frames
|
||||
var time = 0.0f;
|
||||
for (var i = 0; i < 2; i++, time += lastFrame)
|
||||
{
|
||||
for (var curveIndex = 0; curveIndex < constant.data.Length;)
|
||||
{
|
||||
var index = (int)(streamCount + denseCount + curveIndex);
|
||||
if (clip.m_ACLClip.IsSet)
|
||||
index += (int)clip.m_ACLClip.m_CurveCount;
|
||||
GenericBinding binding = bindings.FindBinding(index);
|
||||
string path = GetCurvePath(tos, binding.path);
|
||||
if (binding.typeID == ClassIDType.Transform)
|
||||
{
|
||||
AddTransformCurve(time, binding.attribute, constant.data, slopeValues, slopeValues, curveIndex, path);
|
||||
curveIndex += binding.GetDimension();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (binding.customType == 8)
|
||||
{
|
||||
AddAnimatorMuscleCurve(binding, time, constant.data[curveIndex]);
|
||||
}
|
||||
else if (binding.customType == 20)
|
||||
{
|
||||
AddBlendShapeCurve(binding, path, time, constant.data[curveIndex]);
|
||||
}
|
||||
curveIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddTransformCurve(float time, uint transType, float[] curveValues,
|
||||
float[] inSlopeValues, float[] outSlopeValues, int offset, string path)
|
||||
{
|
||||
switch (transType)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
Vector3Curve curve = new Vector3Curve(path);
|
||||
if (!m_translations.TryGetValue(curve, out List<Keyframe<Vector3>> transCurve))
|
||||
{
|
||||
transCurve = new List<Keyframe<Vector3>>();
|
||||
m_translations.Add(curve, transCurve);
|
||||
}
|
||||
|
||||
float x = curveValues[offset + 0];
|
||||
float y = curveValues[offset + 1];
|
||||
float z = curveValues[offset + 2];
|
||||
|
||||
float inX = inSlopeValues[0];
|
||||
float inY = inSlopeValues[1];
|
||||
float inZ = inSlopeValues[2];
|
||||
|
||||
float outX = outSlopeValues[0];
|
||||
float outY = outSlopeValues[1];
|
||||
float outZ = outSlopeValues[2];
|
||||
|
||||
Vector3 value = new Vector3(x, y, z);
|
||||
Vector3 inSlope = new Vector3(inX, inY, inZ);
|
||||
Vector3 outSlope = new Vector3(outX, outY, outZ);
|
||||
Keyframe<Vector3> transKey = new Keyframe<Vector3>(time, value, inSlope, outSlope, Keyframe<Vector3>.DefaultVector3Weight);
|
||||
transCurve.Add(transKey);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
QuaternionCurve curve = new QuaternionCurve(path);
|
||||
if (!m_rotations.TryGetValue(curve, out List<Keyframe<Quaternion>> rotCurve))
|
||||
{
|
||||
rotCurve = new List<Keyframe<Quaternion>>();
|
||||
m_rotations.Add(curve, rotCurve);
|
||||
}
|
||||
|
||||
float x = curveValues[offset + 0];
|
||||
float y = curveValues[offset + 1];
|
||||
float z = curveValues[offset + 2];
|
||||
float w = curveValues[offset + 3];
|
||||
|
||||
float inX = inSlopeValues[0];
|
||||
float inY = inSlopeValues[1];
|
||||
float inZ = inSlopeValues[2];
|
||||
float inW = inSlopeValues[3];
|
||||
|
||||
float outX = outSlopeValues[0];
|
||||
float outY = outSlopeValues[1];
|
||||
float outZ = outSlopeValues[2];
|
||||
float outW = outSlopeValues[3];
|
||||
|
||||
Quaternion value = new Quaternion(x, y, z, w);
|
||||
Quaternion inSlope = new Quaternion(inX, inY, inZ, inW);
|
||||
Quaternion outSlope = new Quaternion(outX, outY, outZ, outW);
|
||||
Keyframe<Quaternion> rotKey = new Keyframe<Quaternion>(time, value, inSlope, outSlope, Keyframe<Quaternion>.DefaultQuaternionWeight);
|
||||
rotCurve.Add(rotKey);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
Vector3Curve curve = new Vector3Curve(path);
|
||||
if (!m_scales.TryGetValue(curve, out List<Keyframe<Vector3>> scaleCurve))
|
||||
{
|
||||
scaleCurve = new List<Keyframe<Vector3>>();
|
||||
m_scales.Add(curve, scaleCurve);
|
||||
}
|
||||
|
||||
float x = curveValues[offset + 0];
|
||||
float y = curveValues[offset + 1];
|
||||
float z = curveValues[offset + 2];
|
||||
|
||||
float inX = inSlopeValues[0];
|
||||
float inY = inSlopeValues[1];
|
||||
float inZ = inSlopeValues[2];
|
||||
|
||||
float outX = outSlopeValues[0];
|
||||
float outY = outSlopeValues[1];
|
||||
float outZ = outSlopeValues[2];
|
||||
|
||||
Vector3 value = new Vector3(x, y, z);
|
||||
Vector3 inSlope = new Vector3(inX, inY, inZ);
|
||||
Vector3 outSlope = new Vector3(outX, outY, outZ);
|
||||
Keyframe<Vector3> scaleKey = new Keyframe<Vector3>(time, value, inSlope, outSlope, Keyframe<Vector3>.DefaultVector3Weight);
|
||||
scaleCurve.Add(scaleKey);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
Vector3Curve curve = new Vector3Curve(path);
|
||||
if (!m_eulers.TryGetValue(curve, out List<Keyframe<Vector3>> eulerCurve))
|
||||
{
|
||||
eulerCurve = new List<Keyframe<Vector3>>();
|
||||
m_eulers.Add(curve, eulerCurve);
|
||||
}
|
||||
|
||||
float x = curveValues[offset + 0];
|
||||
float y = curveValues[offset + 1];
|
||||
float z = curveValues[offset + 2];
|
||||
|
||||
float inX = inSlopeValues[0];
|
||||
float inY = inSlopeValues[1];
|
||||
float inZ = inSlopeValues[2];
|
||||
|
||||
float outX = outSlopeValues[0];
|
||||
float outY = outSlopeValues[1];
|
||||
float outZ = outSlopeValues[2];
|
||||
|
||||
Vector3 value = new Vector3(x, y, z);
|
||||
Vector3 inSlope = new Vector3(inX, inY, inZ);
|
||||
Vector3 outSlope = new Vector3(outX, outY, outZ);
|
||||
Keyframe<Vector3> eulerKey = new Keyframe<Vector3>(time, value, inSlope, outSlope, Keyframe<Vector3>.DefaultVector3Weight);
|
||||
eulerCurve.Add(eulerKey);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException(transType.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void AddAnimatorMuscleCurve(GenericBinding binding, float time, float value)
|
||||
{
|
||||
FloatCurve curve = new FloatCurve(string.Empty, binding.GetClipMuscle(), ClassIDType.Animator, new PPtr<MonoScript>(0, 0, null));
|
||||
AddFloatKeyframe(curve, time, value);
|
||||
}
|
||||
|
||||
private void AddBlendShapeCurve(GenericBinding binding, string path, float time, float value)
|
||||
{
|
||||
var attribute = "";
|
||||
const string Prefix = "blendShape.";
|
||||
if (UnknownPathRegex.IsMatch(path))
|
||||
{
|
||||
attribute = Prefix + binding.attribute;
|
||||
}
|
||||
|
||||
foreach (GameObject root in animationClip.FindRoots().ToArray())
|
||||
{
|
||||
Transform rootTransform = root.GetTransform();
|
||||
Transform child = rootTransform.FindChild(path);
|
||||
if (child == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
SkinnedMeshRenderer skin = null;
|
||||
if (child.m_GameObject.TryGet(out var gameObject))
|
||||
{
|
||||
skin = gameObject.FindComponent<SkinnedMeshRenderer>();
|
||||
}
|
||||
if (skin == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!skin.m_Mesh.TryGet(out var mesh))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string shapeName = mesh.FindBlendShapeNameByCRC(binding.attribute);
|
||||
if (shapeName == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
attribute = Prefix + shapeName;
|
||||
}
|
||||
attribute = Prefix + attribute;
|
||||
|
||||
FloatCurve curve = new FloatCurve(path, attribute, binding.typeID, binding.script.CastTo<MonoScript>());
|
||||
AddFloatKeyframe(curve, time, value);
|
||||
}
|
||||
|
||||
private void AddFloatKeyframe(FloatCurve curve, float time, float value)
|
||||
{
|
||||
if (!m_floats.TryGetValue(curve, out List<Keyframe<Float>> floatCurve))
|
||||
{
|
||||
floatCurve = new List<Keyframe<Float>>();
|
||||
m_floats.Add(curve, floatCurve);
|
||||
}
|
||||
|
||||
Keyframe<Float> floatKey = new Keyframe<Float>(time, value, Keyframe<Float>.DefaultFloatWeight);
|
||||
floatCurve.Add(floatKey);
|
||||
}
|
||||
|
||||
private void GetPreviousFrame(List<StreamedClip.StreamedFrame> streamFrames, int curveID, int currentFrame, out int frameIndex, out int curveIndex)
|
||||
{
|
||||
for (frameIndex = currentFrame - 1; frameIndex >= 0; frameIndex--)
|
||||
{
|
||||
var frame = streamFrames[frameIndex];
|
||||
for (curveIndex = 0; curveIndex < frame.keyList.Length; curveIndex++)
|
||||
{
|
||||
var curve = frame.keyList[curveIndex];
|
||||
if (curve.index == curveID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Exception($"There is no curve with index {curveID} in any of previous frames");
|
||||
}
|
||||
|
||||
private int GetNextCurve(StreamedClip.StreamedFrame frame, int currentCurve)
|
||||
{
|
||||
var curve = frame.keyList[currentCurve];
|
||||
int i = currentCurve + 1;
|
||||
for (; i < frame.keyList.Length; i++)
|
||||
{
|
||||
if (frame.keyList[i].index != curve.index)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private static string GetCurvePath(Dictionary<uint, string> tos, uint hash)
|
||||
{
|
||||
if (tos.TryGetValue(hash, out string path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"path_{hash}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class AnimationClipExtensions
|
||||
{
|
||||
public static string Convert(this AnimationClip animationClip, Game game)
|
||||
{
|
||||
var converter = AnimationClipConverter.Process(animationClip, game);
|
||||
animationClip.m_RotationCurves = converter.Rotations.Union(animationClip.m_RotationCurves).ToArray();
|
||||
animationClip.m_EulerCurves = converter.Eulers.Union(animationClip.m_EulerCurves).ToArray();
|
||||
animationClip.m_PositionCurves = converter.Translations.Union(animationClip.m_PositionCurves).ToArray();
|
||||
animationClip.m_ScaleCurves = converter.Scales.Union(animationClip.m_ScaleCurves).ToArray();
|
||||
animationClip.m_FloatCurves = converter.Floats.Union(animationClip.m_FloatCurves).ToArray();
|
||||
animationClip.m_PPtrCurves = converter.PPtrs.Union(animationClip.m_PPtrCurves).ToArray();
|
||||
return ConvertSerializedAnimationClip(animationClip);
|
||||
}
|
||||
|
||||
public static string ConvertSerializedAnimationClip(AnimationClip animationClip)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
using (var stringWriter = new StringWriter(sb))
|
||||
{
|
||||
YAMLWriter writer = new YAMLWriter();
|
||||
YAMLDocument doc = ExportYAMLDocument(animationClip);
|
||||
writer.AddDocument(doc);
|
||||
writer.Write(stringWriter);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static YAMLDocument ExportYAMLDocument(AnimationClip animationClip)
|
||||
{
|
||||
YAMLDocument document = new YAMLDocument();
|
||||
YAMLMappingNode root = document.CreateMappingRoot();
|
||||
root.Tag = ((int)ClassIDType.AnimationClip).ToString();
|
||||
root.Anchor = ((int)ClassIDType.AnimationClip * 100000).ToString();
|
||||
YAMLMappingNode node = (YAMLMappingNode)animationClip.ExportYAML();
|
||||
root.Add(ClassIDType.AnimationClip.ToString(), node);
|
||||
return document;
|
||||
}
|
||||
public static string GetClipMuscle(this GenericBinding genericBinding) => ClipMuscles[genericBinding.attribute] ?? $"unknown_{genericBinding.attribute}";
|
||||
|
||||
public static string[] ClipMuscles =
|
||||
{
|
||||
"MotionT.x",
|
||||
"MotionT.y",
|
||||
"MotionT.z",
|
||||
"MotionQ.x",
|
||||
"MotionQ.y",
|
||||
"MotionQ.z",
|
||||
"MotionQ.w",
|
||||
"RootT.x",
|
||||
"RootT.y",
|
||||
"RootT.z",
|
||||
"RootQ.x",
|
||||
"RootQ.y",
|
||||
"RootQ.z",
|
||||
"RootQ.w",
|
||||
"LeftFootT.x",
|
||||
"LeftFootT.y",
|
||||
"LeftFootT.z",
|
||||
"LeftFootQ.x",
|
||||
"LeftFootQ.y",
|
||||
"LeftFootQ.z",
|
||||
"LeftFootQ.w",
|
||||
"RightFootT.x",
|
||||
"RightFootT.y",
|
||||
"RightFootT.z",
|
||||
"RightFootQ.x",
|
||||
"RightFootQ.y",
|
||||
"RightFootQ.z",
|
||||
"RightFootQ.w",
|
||||
"LeftHandT.x",
|
||||
"LeftHandT.y",
|
||||
"LeftHandT.z",
|
||||
"LeftHandQ.x",
|
||||
"LeftHandQ.y",
|
||||
"LeftHandQ.z",
|
||||
"LeftHandQ.w",
|
||||
"RightHandT.x",
|
||||
"RightHandT.y",
|
||||
"RightHandT.z",
|
||||
"RightHandQ.x",
|
||||
"RightHandQ.y",
|
||||
"RightHandQ.z",
|
||||
"RightHandQ.w",
|
||||
"Spine Front-Back",
|
||||
"Spine Left-Right",
|
||||
"Spine Twist Left-Right",
|
||||
"Chest Front-Back",
|
||||
"Chest Left-Right",
|
||||
"Chest Twist Left-Right",
|
||||
"UpperChest Front-Back",
|
||||
"UpperChest Left-Right",
|
||||
"UpperChest Twist Left-Right",
|
||||
"Neck Nod Down-Up",
|
||||
"Neck Tilt Left-Right",
|
||||
"Neck Turn Left-Right",
|
||||
"Head Nod Down-Up",
|
||||
"Head Tilt Left-Right",
|
||||
"Head Turn Left-Right",
|
||||
"Left Eye Down-Up",
|
||||
"Left Eye In-Out",
|
||||
"Right Eye Down-Up",
|
||||
"Right Eye In-Out",
|
||||
"Jaw Close",
|
||||
"Jaw Left-Right",
|
||||
"Left Upper Leg Front-Back",
|
||||
"Left Upper Leg In-Out",
|
||||
"Left Upper Leg Twist In-Out",
|
||||
"Left Lower Leg Stretch",
|
||||
"Left Lower Leg Twist In-Out",
|
||||
"Left Foot Up-Down",
|
||||
"Left Foot Twist In-Out",
|
||||
"Left Toes Up-Down",
|
||||
"Right Upper Leg Front-Back",
|
||||
"Right Upper Leg In-Out",
|
||||
"Right Upper Leg Twist In-Out",
|
||||
"Right Lower Leg Stretch",
|
||||
"Right Lower Leg Twist In-Out",
|
||||
"Right Foot Up-Down",
|
||||
"Right Foot Twist In-Out",
|
||||
"Right Toes Up-Down",
|
||||
"Left Shoulder Down-Up",
|
||||
"Left Shoulder Front-Back",
|
||||
"Left Arm Down-Up",
|
||||
"Left Arm Front-Back",
|
||||
"Left Arm Twist In-Out",
|
||||
"Left Forearm Stretch",
|
||||
"Left Forearm Twist In-Out",
|
||||
"Left Hand Down-Up",
|
||||
"Left Hand In-Out",
|
||||
"Right Shoulder Down-Up",
|
||||
"Right Shoulder Front-Back",
|
||||
"Right Arm Down-Up",
|
||||
"Right Arm Front-Back",
|
||||
"Right Arm Twist In-Out",
|
||||
"Right Forearm Stretch",
|
||||
"Right Forearm Twist In-Out",
|
||||
"Right Hand Down-Up",
|
||||
"Right Hand In-Out",
|
||||
"LeftHand.Thumb.1 Stretched",
|
||||
"LeftHand.Thumb.Spread",
|
||||
"LeftHand.Thumb.2 Stretched",
|
||||
"LeftHand.Thumb.3 Stretched",
|
||||
"LeftHand.Index.1 Stretched",
|
||||
"LeftHand.Index.Spread",
|
||||
"LeftHand.Index.2 Stretched",
|
||||
"LeftHand.Index.3 Stretched",
|
||||
"LeftHand.Middle.1 Stretched",
|
||||
"LeftHand.Middle.Spread",
|
||||
"LeftHand.Middle.2 Stretched",
|
||||
"LeftHand.Middle.3 Stretched",
|
||||
"LeftHand.Ring.1 Stretched",
|
||||
"LeftHand.Ring.Spread",
|
||||
"LeftHand.Ring.2 Stretched",
|
||||
"LeftHand.Ring.3 Stretched",
|
||||
"LeftHand.Little.1 Stretched",
|
||||
"LeftHand.Little.Spread",
|
||||
"LeftHand.Little.2 Stretched",
|
||||
"LeftHand.Little.3 Stretched",
|
||||
"RightHand.Thumb.1 Stretched",
|
||||
"RightHand.Thumb.Spread",
|
||||
"RightHand.Thumb.2 Stretched",
|
||||
"RightHand.Thumb.3 Stretched",
|
||||
"RightHand.Index.1 Stretched",
|
||||
"RightHand.Index.Spread",
|
||||
"RightHand.Index.2 Stretched",
|
||||
"RightHand.Index.3 Stretched",
|
||||
"RightHand.Middle.1 Stretched",
|
||||
"RightHand.Middle.Spread",
|
||||
"RightHand.Middle.2 Stretched",
|
||||
"RightHand.Middle.3 Stretched",
|
||||
"RightHand.Ring.1 Stretched",
|
||||
"RightHand.Ring.Spread",
|
||||
"RightHand.Ring.2 Stretched",
|
||||
"RightHand.Ring.3 Stretched",
|
||||
"RightHand.Little.1 Stretched",
|
||||
"RightHand.Little.Spread",
|
||||
"RightHand.Little.2 Stretched",
|
||||
"RightHand.Little.3 Stretched",
|
||||
"SpineTDOF.x",
|
||||
"SpineTDOF.y",
|
||||
"SpineTDOF.z",
|
||||
"ChestTDOF.x",
|
||||
"ChestTDOF.y",
|
||||
"ChestTDOF.z",
|
||||
"UpperChestTDOF.x",
|
||||
"UpperChestTDOF.y",
|
||||
"UpperChestTDOF.z",
|
||||
"NeckTDOF.x",
|
||||
"NeckTDOF.y",
|
||||
"NeckTDOF.z",
|
||||
"HeadTDOF.x",
|
||||
"HeadTDOF.y",
|
||||
"HeadTDOF.z",
|
||||
"LeftUpperLegTDOF.x",
|
||||
"LeftUpperLegTDOF.y",
|
||||
"LeftUpperLegTDOF.z",
|
||||
"LeftLowerLegTDOF.x",
|
||||
"LeftLowerLegTDOF.y",
|
||||
"LeftLowerLegTDOF.z",
|
||||
"LeftFootTDOF.x",
|
||||
"LeftFootTDOF.y",
|
||||
"LeftFootTDOF.z",
|
||||
"LeftToesTDOF.x",
|
||||
"LeftToesTDOF.y",
|
||||
"LeftToesTDOF.z",
|
||||
"RightUpperLegTDOF.x",
|
||||
"RightUpperLegTDOF.y",
|
||||
"RightUpperLegTDOF.z",
|
||||
"RightLowerLegTDOF.x",
|
||||
"RightLowerLegTDOF.y",
|
||||
"RightLowerLegTDOF.z",
|
||||
"RightFootTDOF.x",
|
||||
"RightFootTDOF.y",
|
||||
"RightFootTDOF.z",
|
||||
"RightToesTDOF.x",
|
||||
"RightToesTDOF.y",
|
||||
"RightToesTDOF.z",
|
||||
"LeftShoulderTDOF.x",
|
||||
"LeftShoulderTDOF.y",
|
||||
"LeftShoulderTDOF.z",
|
||||
"LeftUpperArmTDOF.x",
|
||||
"LeftUpperArmTDOF.y",
|
||||
"LeftUpperArmTDOF.z",
|
||||
"LeftLowerArmTDOF.x",
|
||||
"LeftLowerArmTDOF.y",
|
||||
"LeftLowerArmTDOF.z",
|
||||
"LeftHandTDOF.x",
|
||||
"LeftHandTDOF.y",
|
||||
"LeftHandTDOF.z",
|
||||
"RightShoulderTDOF.x",
|
||||
"RightShoulderTDOF.y",
|
||||
"RightShoulderTDOF.z",
|
||||
"RightUpperArmTDOF.x",
|
||||
"RightUpperArmTDOF.y",
|
||||
"RightUpperArmTDOF.z",
|
||||
"RightLowerArmTDOF.x",
|
||||
"RightLowerArmTDOF.y",
|
||||
"RightLowerArmTDOF.z",
|
||||
"RightHandTDOF.x",
|
||||
"RightHandTDOF.y",
|
||||
"RightHandTDOF.z",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>0.18.60</Version>
|
||||
<AssemblyVersion>0.18.60</AssemblyVersion>
|
||||
<FileVersion>0.18.60</FileVersion>
|
||||
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Version>0.80.30</Version>
|
||||
<AssemblyVersion>0.80.30</AssemblyVersion>
|
||||
<FileVersion>0.80.30</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
|
||||
<PackageReference Include="Kyaru.Texture2DDecoder" Version="0.17.0" />
|
||||
<PackageReference Include="Kyaru.Texture2DDecoder.Windows" Version="0.1.0" />
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -18,7 +21,6 @@
|
||||
<ProjectReference Include="..\AssetStudio.PInvoke\AssetStudio.PInvoke.csproj" />
|
||||
<ProjectReference Include="..\AssetStudioFBXWrapper\AssetStudioFBXWrapper.csproj" />
|
||||
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
|
||||
<ProjectReference Include="..\Texture2DDecoderWrapper\Texture2DDecoderWrapper.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace AssetStudio
|
||||
var result = Factory.System_Create(out var system);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
result = system.init(1, INITFLAGS.NORMAL, IntPtr.Zero);
|
||||
result = system.init(1, INITFLAGS.NORMAL, nint.Zero);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
exinfo.cbsize = Marshal.SizeOf(exinfo);
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class ConsoleHelper
|
||||
public static partial class ConsoleHelper
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool AllocConsole();
|
||||
public static partial bool AllocConsole();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[LibraryImport("kernel32.dll", EntryPoint = "SetConsoleTitleA", SetLastError = true, StringMarshalling = StringMarshalling.Utf8)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool SetConsoleTitle(string lpConsoleTitle);
|
||||
public static partial bool SetConsoleTitle(string lpConsoleTitle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GetConsoleWindow();
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
public static partial nint GetConsoleWindow();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[LibraryImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
public static partial bool ShowWindow(nint hWnd, int nCmdShow);
|
||||
|
||||
public const int SW_HIDE = 0;
|
||||
public const int SW_SHOW = 5;
|
||||
|
||||
10
AssetStudioUtility/FontHelper.cs
Normal file
10
AssetStudioUtility/FontHelper.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static partial class FontHelper
|
||||
{
|
||||
[LibraryImport("gdi32.dll")]
|
||||
public static partial nint AddFontMemResourceEx(nint pbFont, uint cbFont, nint pdv, ref uint pcFonts);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using SevenZip;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -15,6 +14,7 @@ namespace AssetStudio
|
||||
public List<ImportedKeyframedAnimation> AnimationList { get; protected set; } = new List<ImportedKeyframedAnimation>();
|
||||
public List<ImportedMorph> MorphList { get; protected set; } = new List<ImportedMorph>();
|
||||
|
||||
private Game Game;
|
||||
private ImageFormat imageFormat;
|
||||
private Avatar avatar;
|
||||
private HashSet<AnimationClip> animationClipHashSet = new HashSet<AnimationClip>();
|
||||
@@ -23,18 +23,17 @@ namespace AssetStudio
|
||||
private Dictionary<Texture2D, string> textureNameDictionary = new Dictionary<Texture2D, string>();
|
||||
private Dictionary<Transform, ImportedFrame> transformDictionary = new Dictionary<Transform, ImportedFrame>();
|
||||
Dictionary<uint, string> morphChannelNames = new Dictionary<uint, string>();
|
||||
private Game Game;
|
||||
|
||||
public ModelConverter(GameObject m_GameObject, ImageFormat imageFormat, Game game, AnimationClip[] animationList = null, bool ignoreController = true)
|
||||
public ModelConverter(GameObject m_GameObject, ImageFormat imageFormat, Game game, bool collectAnimations, AnimationClip[] animationList = null)
|
||||
{
|
||||
Game = game;
|
||||
this.imageFormat = imageFormat;
|
||||
if (m_GameObject.m_Animator != null)
|
||||
{
|
||||
InitWithAnimator(m_GameObject.m_Animator);
|
||||
if (animationList == null)
|
||||
if (animationList == null && collectAnimations)
|
||||
{
|
||||
CollectAnimationClip(m_GameObject.m_Animator, ignoreController);
|
||||
CollectAnimationClip(m_GameObject.m_Animator);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -51,16 +50,16 @@ namespace AssetStudio
|
||||
ConvertAnimations();
|
||||
}
|
||||
|
||||
public ModelConverter(string rootName, List<GameObject> m_GameObjects, ImageFormat imageFormat, Game game, AnimationClip[] animationList = null, bool ignoreController = true)
|
||||
public ModelConverter(string rootName, List<GameObject> m_GameObjects, ImageFormat imageFormat, Game game, bool collectAnimations, AnimationClip[] animationList = null)
|
||||
{
|
||||
Game = game;
|
||||
this.imageFormat = imageFormat;
|
||||
RootFrame = CreateFrame(rootName, Vector3.Zero, new Quaternion(0, 0, 0, 0), Vector3.One);
|
||||
foreach (var m_GameObject in m_GameObjects)
|
||||
{
|
||||
if (m_GameObject.m_Animator != null && animationList == null)
|
||||
if (m_GameObject.m_Animator != null && animationList == null && collectAnimations)
|
||||
{
|
||||
CollectAnimationClip(m_GameObject.m_Animator, ignoreController);
|
||||
CollectAnimationClip(m_GameObject.m_Animator);
|
||||
}
|
||||
|
||||
var m_Transform = m_GameObject.m_Transform;
|
||||
@@ -82,14 +81,14 @@ namespace AssetStudio
|
||||
ConvertAnimations();
|
||||
}
|
||||
|
||||
public ModelConverter(Animator m_Animator, ImageFormat imageFormat, Game game, AnimationClip[] animationList = null, bool ignoreController = true)
|
||||
public ModelConverter(Animator m_Animator, ImageFormat imageFormat, Game game, bool collectAnimations, AnimationClip[] animationList = null)
|
||||
{
|
||||
Game = game;
|
||||
this.imageFormat = imageFormat;
|
||||
InitWithAnimator(m_Animator);
|
||||
if (animationList == null)
|
||||
if (animationList == null && collectAnimations)
|
||||
{
|
||||
CollectAnimationClip(m_Animator, ignoreController);
|
||||
CollectAnimationClip(m_Animator);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -185,9 +184,9 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
private void CollectAnimationClip(Animator m_Animator, bool ignoreController)
|
||||
private void CollectAnimationClip(Animator m_Animator)
|
||||
{
|
||||
if (m_Animator.m_Controller.TryGet(out var m_Controller) && !ignoreController)
|
||||
if (m_Animator.m_Controller.TryGet(out var m_Controller))
|
||||
{
|
||||
switch (m_Controller)
|
||||
{
|
||||
@@ -512,7 +511,10 @@ namespace AssetStudio
|
||||
var shapeChannel = mesh.m_Shapes.channels[i];
|
||||
|
||||
var blendShapeName = "blendShape." + shapeChannel.name;
|
||||
morphChannelNames[CRC.CalculateDigestUTF8(blendShapeName)] = blendShapeName;
|
||||
var crc = new SevenZip.CRC();
|
||||
var bytes = Encoding.UTF8.GetBytes(blendShapeName);
|
||||
crc.Update(bytes, 0, (uint)bytes.Length);
|
||||
morphChannelNames[crc.GetDigest()] = blendShapeName;
|
||||
|
||||
channel.Name = shapeChannel.name.Split('.').Last();
|
||||
channel.KeyframeList = new List<ImportedMorphKeyframe>(shapeChannel.frameCount);
|
||||
@@ -796,7 +798,7 @@ namespace AssetStudio
|
||||
foreach (var m_CompressedRotationCurve in animationClip.m_CompressedRotationCurves)
|
||||
{
|
||||
var track = iAnim.FindTrack(FixBonePath(animationClip, m_CompressedRotationCurve.m_Path));
|
||||
|
||||
|
||||
var numKeys = m_CompressedRotationCurve.m_Times.m_NumItems;
|
||||
var data = m_CompressedRotationCurve.m_Times.UnpackInts();
|
||||
var times = new float[numKeys];
|
||||
@@ -807,7 +809,7 @@ namespace AssetStudio
|
||||
times[i] = t * 0.01f;
|
||||
}
|
||||
var quats = m_CompressedRotationCurve.m_Values.UnpackQuats();
|
||||
|
||||
|
||||
for (int i = 0; i < numKeys; i++)
|
||||
{
|
||||
var quat = quats[i];
|
||||
@@ -861,7 +863,7 @@ namespace AssetStudio
|
||||
{
|
||||
channelName = channelName.Substring(dotPos + 1);
|
||||
}
|
||||
|
||||
|
||||
var path = FixBonePath(animationClip, m_FloatCurve.path);
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
@@ -884,7 +886,7 @@ namespace AssetStudio
|
||||
var m_ClipBindingConstant = animationClip.m_ClipBindingConstant ?? m_Clip.ConvertValueArrayToGenericBinding();
|
||||
var m_ACLClip = m_Clip.m_ACLClip;
|
||||
var aclCount = m_ACLClip.m_CurveCount;
|
||||
if (m_ACLClip.m_CurveCount != 0 && Game.Name != "SR_CB2" && Game.Name != "SR_CB3")
|
||||
if (!m_ACLClip.m_ClipData.IsNullOrEmpty() && !Game.Type.IsSRGroup())
|
||||
{
|
||||
m_ACLClip.Process(out var values, out var times);
|
||||
for (int frameIndex = 0; frameIndex < times.Length; frameIndex++)
|
||||
@@ -896,7 +898,7 @@ namespace AssetStudio
|
||||
var index = curveIndex;
|
||||
ReadCurveData(iAnim, m_ClipBindingConstant, index, time, values, (int)frameOffset, ref curveIndex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
for (int frameIndex = 1; frameIndex < streamedFrames.Count - 1; frameIndex++)
|
||||
@@ -906,9 +908,9 @@ namespace AssetStudio
|
||||
for (int curveIndex = 0; curveIndex < frame.keyList.Length;)
|
||||
{
|
||||
var index = frame.keyList[curveIndex].index;
|
||||
if (Game.Name != "SR_CB2" && Game.Name != "SR_CB3")
|
||||
if (!Game.Type.IsSRGroup())
|
||||
index += (int)aclCount;
|
||||
ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, frame.time, streamedValues, 0, ref curveIndex);
|
||||
ReadCurveData(iAnim, m_ClipBindingConstant, index, frame.time, streamedValues, 0, ref curveIndex);
|
||||
}
|
||||
}
|
||||
var m_DenseClip = m_Clip.m_DenseClip;
|
||||
@@ -920,12 +922,12 @@ namespace AssetStudio
|
||||
for (int curveIndex = 0; curveIndex < m_DenseClip.m_CurveCount;)
|
||||
{
|
||||
var index = streamCount + curveIndex;
|
||||
if (Game.Name != "SR_CB2" && Game.Name != "SR_CB3")
|
||||
index += aclCount;
|
||||
if (!Game.Type.IsSRGroup())
|
||||
index += (int)aclCount;
|
||||
ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, time, m_DenseClip.m_SampleArray, (int)frameOffset, ref curveIndex);
|
||||
}
|
||||
}
|
||||
if (m_ACLClip.m_CurveCount != 0 && Game.Name == "SR_CB2" && Game.Name != "SR_CB3")
|
||||
if (!m_ACLClip.m_ClipData.IsNullOrEmpty() && Game.Type.IsSRGroup())
|
||||
{
|
||||
m_ACLClip.ProcessSR(out var values, out var times);
|
||||
for (int frameIndex = 0; frameIndex < times.Length; frameIndex++)
|
||||
@@ -1037,6 +1039,7 @@ namespace AssetStudio
|
||||
curveIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetPathFromHash(uint hash)
|
||||
{
|
||||
bonePathHash.TryGetValue(hash, out var boneName);
|
||||
@@ -1054,12 +1057,18 @@ namespace AssetStudio
|
||||
private void CreateBonePathHash(Transform m_Transform)
|
||||
{
|
||||
var name = GetTransformPathByFather(m_Transform);
|
||||
bonePathHash[CRC.CalculateDigestUTF8(name)] = name;
|
||||
var crc = new SevenZip.CRC();
|
||||
var bytes = Encoding.UTF8.GetBytes(name);
|
||||
crc.Update(bytes, 0, (uint)bytes.Length);
|
||||
bonePathHash[crc.GetDigest()] = name;
|
||||
int index;
|
||||
while ((index = name.IndexOf("/", StringComparison.Ordinal)) >= 0)
|
||||
{
|
||||
name = name.Substring(index + 1);
|
||||
bonePathHash[CRC.CalculateDigestUTF8(name)] = name;
|
||||
crc = new SevenZip.CRC();
|
||||
bytes = Encoding.UTF8.GetBytes(name);
|
||||
crc.Update(bytes, 0, (uint)bytes.Length);
|
||||
bonePathHash[crc.GetDigest()] = name;
|
||||
}
|
||||
foreach (var pptr in m_Transform.m_Children)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace AssetStudio
|
||||
{
|
||||
var decompressedBytes = new byte[shader.decompressedSize];
|
||||
LZ4Codec.Decode(shader.m_SubProgramBlob, decompressedBytes);
|
||||
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
||||
using (var blobReader = new EndianBinaryReader(new MemoryStream(decompressedBytes), EndianType.LittleEndian))
|
||||
{
|
||||
var program = new ShaderProgram(blobReader, shader.version);
|
||||
program.Read(blobReader, 0);
|
||||
@@ -44,7 +44,7 @@ namespace AssetStudio
|
||||
var compressedLength = shader.compressedLengths[i][j];
|
||||
var decompressedLength = shader.decompressedLengths[i][j];
|
||||
var decompressedBytes = new byte[decompressedLength];
|
||||
if (game.Name == "GI" || game.Name == "GI_CB2" || game.Name == "GI_CB3")
|
||||
if (game.Type.IsGISubGroup())
|
||||
{
|
||||
Buffer.BlockCopy(shader.compressedBlob, (int)offset, decompressedBytes, 0, (int)decompressedLength);
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace AssetStudio
|
||||
{
|
||||
LZ4Codec.Decode(shader.compressedBlob, (int)offset, (int)compressedLength, decompressedBytes, 0, (int)decompressedLength);
|
||||
}
|
||||
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
||||
using (var blobReader = new EndianBinaryReader(new MemoryStream(decompressedBytes), EndianType.LittleEndian))
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
@@ -878,7 +878,7 @@ namespace AssetStudio
|
||||
public int Length;
|
||||
public int Segment;
|
||||
|
||||
public ShaderSubProgramEntry(BinaryReader reader, int[] version)
|
||||
public ShaderSubProgramEntry(EndianBinaryReader reader, int[] version)
|
||||
{
|
||||
Offset = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
@@ -894,7 +894,7 @@ namespace AssetStudio
|
||||
public ShaderSubProgramEntry[] entries;
|
||||
public ShaderSubProgram[] m_SubPrograms;
|
||||
|
||||
public ShaderProgram(BinaryReader reader, int[] version)
|
||||
public ShaderProgram(EndianBinaryReader reader, int[] version)
|
||||
{
|
||||
var subProgramsCapacity = reader.ReadInt32();
|
||||
entries = new ShaderSubProgramEntry[subProgramsCapacity];
|
||||
@@ -905,7 +905,7 @@ namespace AssetStudio
|
||||
m_SubPrograms = new ShaderSubProgram[subProgramsCapacity];
|
||||
}
|
||||
|
||||
public void Read(BinaryReader reader, int segment)
|
||||
public void Read(EndianBinaryReader reader, int segment)
|
||||
{
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
@@ -938,7 +938,7 @@ namespace AssetStudio
|
||||
public string[] m_LocalKeywords;
|
||||
public byte[] m_ProgramCode;
|
||||
|
||||
public ShaderSubProgram(BinaryReader reader)
|
||||
public ShaderSubProgram(EndianBinaryReader reader)
|
||||
{
|
||||
//LoadGpuProgramFromData
|
||||
//201509030 - Unity 5.3
|
||||
@@ -1049,7 +1049,7 @@ namespace AssetStudio
|
||||
}
|
||||
case ShaderGpuProgramType.MetalVS:
|
||||
case ShaderGpuProgramType.MetalFS:
|
||||
using (var reader = new BinaryReader(new MemoryStream(m_ProgramCode)))
|
||||
using (var reader = new EndianBinaryReader(new MemoryStream(m_ProgramCode), EndianType.LittleEndian))
|
||||
{
|
||||
var fourCC = reader.ReadUInt32();
|
||||
if (fourCC == 0xf00dcafe)
|
||||
|
||||
@@ -139,9 +139,9 @@ namespace AssetStudio
|
||||
var m_VertexData = m_RD.m_VertexData;
|
||||
var m_Channel = m_VertexData.m_Channels[0]; //kShaderChannelVertex
|
||||
var m_Stream = m_VertexData.m_Streams[m_Channel.stream];
|
||||
using (var vertexReader = new BinaryReader(new MemoryStream(m_VertexData.m_DataSize)))
|
||||
using (var vertexReader = new EndianBinaryReader(new MemoryStream(m_VertexData.m_DataSize), EndianType.LittleEndian))
|
||||
{
|
||||
using (var indexReader = new BinaryReader(new MemoryStream(m_RD.m_IndexBuffer)))
|
||||
using (var indexReader = new EndianBinaryReader(new MemoryStream(m_RD.m_IndexBuffer), EndianType.LittleEndian))
|
||||
{
|
||||
foreach (var subMesh in m_RD.m_SubMeshes)
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace AssetStudio
|
||||
private TextureFormat m_TextureFormat;
|
||||
private int[] version;
|
||||
private BuildTarget platform;
|
||||
private int outputSize;
|
||||
private int outPutSize;
|
||||
|
||||
public Texture2DConverter(Texture2D m_Texture2D)
|
||||
{
|
||||
@@ -22,7 +22,7 @@ namespace AssetStudio
|
||||
m_TextureFormat = m_Texture2D.m_TextureFormat;
|
||||
version = m_Texture2D.version;
|
||||
platform = m_Texture2D.platform;
|
||||
outputSize = m_Width * m_Height * 4;
|
||||
outPutSize = m_Width * m_Height * 4;
|
||||
}
|
||||
|
||||
public bool DecodeTexture2D(byte[] bytes)
|
||||
@@ -57,7 +57,7 @@ namespace AssetStudio
|
||||
flag = DecodeRGB565(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.R16: //test pass
|
||||
case TextureFormat.R16_2: //test pass
|
||||
case TextureFormat.R16_Alt: //test pass
|
||||
flag = DecodeR16(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.DXT1: //test pass
|
||||
@@ -272,7 +272,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGBA32(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = image_data[i + 2];
|
||||
buff[i + 1] = image_data[i + 1];
|
||||
@@ -284,7 +284,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeARGB32(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = image_data[i + 3];
|
||||
buff[i + 1] = image_data[i + 2];
|
||||
@@ -351,7 +351,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeBGRA32(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = image_data[i];
|
||||
buff[i + 1] = image_data[i + 1];
|
||||
@@ -363,7 +363,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRHalf(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0;
|
||||
buff[i + 1] = 0;
|
||||
@@ -375,7 +375,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGHalf(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0;
|
||||
buff[i + 1] = (byte)Math.Round(Half.ToHalf(image_data, i + 2) * 255f);
|
||||
@@ -387,7 +387,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGBAHalf(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = (byte)Math.Round(Half.ToHalf(image_data, i * 2 + 4) * 255f);
|
||||
buff[i + 1] = (byte)Math.Round(Half.ToHalf(image_data, i * 2 + 2) * 255f);
|
||||
@@ -399,7 +399,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRFloat(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0;
|
||||
buff[i + 1] = 0;
|
||||
@@ -411,7 +411,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGFloat(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0;
|
||||
buff[i + 1] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 2 + 4) * 255f);
|
||||
@@ -423,7 +423,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGBAFloat(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 4 + 8) * 255f);
|
||||
buff[i + 1] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 4 + 4) * 255f);
|
||||
@@ -471,7 +471,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGB9e5Float(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
var n = BitConverter.ToInt32(image_data, i);
|
||||
var scale = n >> 27 & 0x1f;
|
||||
@@ -594,7 +594,7 @@ namespace AssetStudio
|
||||
private bool DecodeRG16(byte[] image_data, byte[] buff)
|
||||
{
|
||||
var size = m_Width * m_Height;
|
||||
for (var i = 0; i < size; i += 2)
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
buff[i * 4] = 0; //B
|
||||
buff[i * 4 + 1] = image_data[i * 2 + 1];//G
|
||||
@@ -617,49 +617,6 @@ namespace AssetStudio
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte DownScaleFrom16BitTo8Bit(ushort component)
|
||||
{
|
||||
return (byte)(((component * 255) + 32895) >> 16);
|
||||
}
|
||||
|
||||
private bool DecodeRG32(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
{
|
||||
buff[i] = 0; //b
|
||||
buff[i + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i + 2)); //g
|
||||
buff[i + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i)); //r
|
||||
buff[i + 3] = byte.MaxValue; //a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DecodeRGB48(byte[] image_data, byte[] buff)
|
||||
{
|
||||
var size = m_Width * m_Height;
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
buff[i * 4] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6 + 4)); //b
|
||||
buff[i * 4 + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6 + 2)); //g
|
||||
buff[i * 4 + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6)); //r
|
||||
buff[i * 4 + 3] = byte.MaxValue; //a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DecodeRGBA64(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outputSize; i += 4)
|
||||
{
|
||||
buff[i] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 4)); //b
|
||||
buff[i + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 2)); //g
|
||||
buff[i + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2)); //r
|
||||
buff[i + 3] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 6)); //a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DecodeETC1Crunched(byte[] image_data, byte[] buff)
|
||||
{
|
||||
if (UnpackCrunch(image_data, out var result))
|
||||
@@ -684,6 +641,49 @@ namespace AssetStudio
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte DownScaleFrom16BitTo8Bit(ushort component)
|
||||
{
|
||||
return (byte)(((component * 255) + 32895) >> 16);
|
||||
}
|
||||
|
||||
private bool DecodeRG32(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0; //b
|
||||
buff[i + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i + 2)); //g
|
||||
buff[i + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i)); //r
|
||||
buff[i + 3] = byte.MaxValue; //a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DecodeRGB48(byte[] image_data, byte[] buff)
|
||||
{
|
||||
var size = m_Width * m_Height;
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
buff[i * 4] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6 + 4)); //b
|
||||
buff[i * 4 + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6 + 2)); //g
|
||||
buff[i * 4 + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6)); //r
|
||||
buff[i * 4 + 3] = byte.MaxValue; //a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DecodeRGBA64(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 4)); //b
|
||||
buff[i + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 2)); //g
|
||||
buff[i + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2)); //r
|
||||
buff[i + 3] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 6)); //a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool UnpackCrunch(byte[] image_data, out byte[] result)
|
||||
{
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3) //2017.3 and up
|
||||
|
||||
Reference in New Issue
Block a user