|
@@ -512,17 +512,191 @@ namespace BansheeEditor
|
|
|
{
|
|
{
|
|
|
curves.Clear();
|
|
curves.Clear();
|
|
|
selectedFields.Clear();
|
|
selectedFields.Clear();
|
|
|
|
|
+ guiFieldDisplay.SetFields(new string[0]);
|
|
|
|
|
|
|
|
clipIsImported = IsClipImported(clip);
|
|
clipIsImported = IsClipImported(clip);
|
|
|
|
|
|
|
|
AnimationCurves clipCurves = clip.Curves;
|
|
AnimationCurves clipCurves = clip.Curves;
|
|
|
- foreach (var curve in clipCurves.PositionCurves)
|
|
|
|
|
|
|
+ EditorCurveData editorCurveData = null;
|
|
|
|
|
+
|
|
|
|
|
+ string resourcePath = ProjectLibrary.GetPath(clip);
|
|
|
|
|
+ if (!string.IsNullOrEmpty(resourcePath))
|
|
|
|
|
+ {
|
|
|
|
|
+ LibraryEntry entry = ProjectLibrary.GetEntry(resourcePath);
|
|
|
|
|
+ string clipName = PathEx.GetTail(resourcePath);
|
|
|
|
|
+
|
|
|
|
|
+ if (entry != null && entry.Type == LibraryEntryType.File)
|
|
|
|
|
+ {
|
|
|
|
|
+ FileEntry fileEntry = (FileEntry)entry;
|
|
|
|
|
+ ResourceMeta[] metas = fileEntry.ResourceMetas;
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < metas.Length; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (clipName == metas[i].SubresourceName)
|
|
|
|
|
+ {
|
|
|
|
|
+ editorCurveData = metas[i].EditorData as EditorCurveData;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(editorCurveData == null)
|
|
|
|
|
+ editorCurveData = new EditorCurveData();
|
|
|
|
|
+
|
|
|
|
|
+ Action<NamedVector3Curve[], EditorVector3CurveTangents[], string> loadVector3Curve =
|
|
|
|
|
+ (curves, tangents, subPath) =>
|
|
|
|
|
+ {
|
|
|
|
|
+ foreach (var curveEntry in curves)
|
|
|
|
|
+ {
|
|
|
|
|
+ TangentMode[] tangentsX = null;
|
|
|
|
|
+ TangentMode[] tangentsY = null;
|
|
|
|
|
+ TangentMode[] tangentsZ = null;
|
|
|
|
|
+ foreach (var tangentEntry in tangents)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (tangentEntry.name == curveEntry.Name)
|
|
|
|
|
+ {
|
|
|
|
|
+ tangentsX = tangentEntry.tangentsX;
|
|
|
|
|
+ tangentsY = tangentEntry.tangentsY;
|
|
|
|
|
+ tangentsZ = tangentEntry.tangentsZ;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ FieldCurves fieldCurves = new FieldCurves();
|
|
|
|
|
+ fieldCurves.type = SerializableProperty.FieldType.Vector3;
|
|
|
|
|
+ fieldCurves.curves = new EdAnimationCurve[3];
|
|
|
|
|
+
|
|
|
|
|
+ fieldCurves.curves[0] = new EdAnimationCurve(curveEntry.X, tangentsX);
|
|
|
|
|
+ fieldCurves.curves[1] = new EdAnimationCurve(curveEntry.Y, tangentsY);
|
|
|
|
|
+ fieldCurves.curves[2] = new EdAnimationCurve(curveEntry.Z, tangentsZ);
|
|
|
|
|
+
|
|
|
|
|
+ string curvePath = curveEntry.Name.TrimEnd('/') + subPath;
|
|
|
|
|
+ guiFieldDisplay.AddField(curvePath);
|
|
|
|
|
+ this.curves[curvePath] = fieldCurves;
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ loadVector3Curve(clipCurves.PositionCurves, editorCurveData.positionCurves, "/Position");
|
|
|
|
|
+ loadVector3Curve(clipCurves.RotationCurves, editorCurveData.rotationCurves, "/Rotation");
|
|
|
|
|
+ loadVector3Curve(clipCurves.ScaleCurves, editorCurveData.scaleCurves, "/Scale");
|
|
|
|
|
+
|
|
|
|
|
+ // Find which individual float curves belong to the same field
|
|
|
|
|
+ Dictionary<string, Tuple<int, bool>> suffixToIdxMapping = new Dictionary<string, Tuple<int, bool>>();
|
|
|
|
|
+ suffixToIdxMapping[".x"] = Tuple.Create(0, true);
|
|
|
|
|
+ suffixToIdxMapping[".y"] = Tuple.Create(1, true);
|
|
|
|
|
+ suffixToIdxMapping[".z"] = Tuple.Create(2, true);
|
|
|
|
|
+ suffixToIdxMapping[".w"] = Tuple.Create(3, true);
|
|
|
|
|
+ suffixToIdxMapping[".r"] = Tuple.Create(0, false);
|
|
|
|
|
+ suffixToIdxMapping[".g"] = Tuple.Create(1, false);
|
|
|
|
|
+ suffixToIdxMapping[".b"] = Tuple.Create(2, false);
|
|
|
|
|
+ suffixToIdxMapping[".a"] = Tuple.Create(3, false);
|
|
|
|
|
+
|
|
|
|
|
+ Dictionary<string, Tuple<int, int, bool>[]> floatCurveMapping = new Dictionary<string, Tuple<int, int, bool>[]>();
|
|
|
|
|
+ {
|
|
|
|
|
+ int curveIdx = 0;
|
|
|
|
|
+ foreach (var curveEntry in clipCurves.FloatCurves)
|
|
|
|
|
+ {
|
|
|
|
|
+ string path = curveEntry.Name;
|
|
|
|
|
+ string pathNoSuffix = null;
|
|
|
|
|
+
|
|
|
|
|
+ string pathSuffix;
|
|
|
|
|
+ if (path.Length >= 2)
|
|
|
|
|
+ {
|
|
|
|
|
+ pathSuffix = path.Substring(path.Length - 2, 2);
|
|
|
|
|
+ pathNoSuffix = path.Substring(0, path.Length - 2);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ pathSuffix = "";
|
|
|
|
|
+
|
|
|
|
|
+ int tangentIdx = -1;
|
|
|
|
|
+ int currentTangentIdx = 0;
|
|
|
|
|
+ foreach (var tangentEntry in editorCurveData.floatCurves)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (tangentEntry.name == curveEntry.Name)
|
|
|
|
|
+ {
|
|
|
|
|
+ tangentIdx = currentTangentIdx;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ currentTangentIdx++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Tuple<int, bool> suffixInfo;
|
|
|
|
|
+ if (suffixToIdxMapping.TryGetValue(pathSuffix, out suffixInfo))
|
|
|
|
|
+ {
|
|
|
|
|
+ Tuple<int, int, bool>[] curveInfo;
|
|
|
|
|
+ if (!floatCurveMapping.TryGetValue(pathNoSuffix, out curveInfo))
|
|
|
|
|
+ curveInfo = new Tuple<int, int, bool>[4];
|
|
|
|
|
+
|
|
|
|
|
+ curveInfo[suffixInfo.Item1] = Tuple.Create(curveIdx, tangentIdx, suffixInfo.Item2);
|
|
|
|
|
+ floatCurveMapping[pathNoSuffix] = curveInfo;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Tuple<int, int, bool>[] curveInfo = new Tuple<int, int, bool>[4];
|
|
|
|
|
+ curveInfo[0] = Tuple.Create(curveIdx, tangentIdx, suffixInfo.Item2);
|
|
|
|
|
+
|
|
|
|
|
+ floatCurveMapping[path] = curveInfo;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ curveIdx++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ foreach (var KVP in floatCurveMapping)
|
|
|
{
|
|
{
|
|
|
- // TODO (don't forget tangents)
|
|
|
|
|
|
|
+ int numCurves = 0;
|
|
|
|
|
+ for (int i = 0; i < 4; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (KVP.Value[i] == null)
|
|
|
|
|
+ continue;
|
|
|
|
|
|
|
|
- // TODO - Trim last / if needed
|
|
|
|
|
|
|
+ numCurves++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (numCurves == 0)
|
|
|
|
|
+ continue; // Invalid curve
|
|
|
|
|
+
|
|
|
|
|
+ FieldCurves fieldCurves = new FieldCurves();
|
|
|
|
|
+
|
|
|
|
|
+ // Deduce type (note that all single value types are assumed to be float even if their source type is int or bool)
|
|
|
|
|
+ if (numCurves == 1)
|
|
|
|
|
+ fieldCurves.type = SerializableProperty.FieldType.Float;
|
|
|
|
|
+ else if (numCurves == 2)
|
|
|
|
|
+ fieldCurves.type = SerializableProperty.FieldType.Vector2;
|
|
|
|
|
+ else if (numCurves == 3)
|
|
|
|
|
+ fieldCurves.type = SerializableProperty.FieldType.Vector3;
|
|
|
|
|
+ else // 4 curves
|
|
|
|
|
+ {
|
|
|
|
|
+ bool isVector = KVP.Value[0].Item3;
|
|
|
|
|
+ if (isVector)
|
|
|
|
|
+ fieldCurves.type = SerializableProperty.FieldType.Vector4;
|
|
|
|
|
+ else
|
|
|
|
|
+ fieldCurves.type = SerializableProperty.FieldType.Color;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fieldCurves.curves = new EdAnimationCurve[numCurves];
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < numCurves; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ int curveIdx = KVP.Value[i].Item1;
|
|
|
|
|
+ int tangentIdx = KVP.Value[i].Item2;
|
|
|
|
|
+
|
|
|
|
|
+ TangentMode[] tangents = null;
|
|
|
|
|
+ if (tangentIdx != -1)
|
|
|
|
|
+ tangents = editorCurveData.floatCurves[tangentIdx].tangents;
|
|
|
|
|
+
|
|
|
|
|
+ fieldCurves.curves[i] = new EdAnimationCurve(clipCurves.FloatCurves[curveIdx].Curve, tangents);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ string curvePath = KVP.Key;
|
|
|
|
|
+
|
|
|
|
|
+ guiFieldDisplay.AddField(curvePath);
|
|
|
|
|
+ curves[curvePath] = fieldCurves;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Add events
|
|
|
events.AddRange(clip.Events);
|
|
events.AddRange(clip.Events);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -588,16 +762,51 @@ namespace BansheeEditor
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- NamedFloatCurve curve = new NamedFloatCurve(kvp.Key,
|
|
|
|
|
- new AnimationCurve(kvp.Value.curves[0].KeyFrames));
|
|
|
|
|
|
|
+ Action<int, string> addCurve = (idx, subPath) =>
|
|
|
|
|
+ {
|
|
|
|
|
+ string path = kvp.Key + subPath;
|
|
|
|
|
|
|
|
- EditorFloatCurveTangents tangents = new EditorFloatCurveTangents();
|
|
|
|
|
- tangents.name = kvp.Key;
|
|
|
|
|
- tangents.tangents = kvp.Value.curves[0].TangentModes;
|
|
|
|
|
|
|
+ NamedFloatCurve curve = new NamedFloatCurve(path,
|
|
|
|
|
+ new AnimationCurve(kvp.Value.curves[idx].KeyFrames));
|
|
|
|
|
|
|
|
- floatCurves.Add(curve);
|
|
|
|
|
- floatTangents.Add(tangents);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ EditorFloatCurveTangents tangents = new EditorFloatCurveTangents();
|
|
|
|
|
+ tangents.name = path;
|
|
|
|
|
+ tangents.tangents = kvp.Value.curves[idx].TangentModes;
|
|
|
|
|
+
|
|
|
|
|
+ floatCurves.Add(curve);
|
|
|
|
|
+ floatTangents.Add(tangents);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ switch (kvp.Value.type)
|
|
|
|
|
+ {
|
|
|
|
|
+ case SerializableProperty.FieldType.Vector2:
|
|
|
|
|
+ addCurve(0, ".x");
|
|
|
|
|
+ addCurve(1, ".y");
|
|
|
|
|
+ break;
|
|
|
|
|
+ case SerializableProperty.FieldType.Vector3:
|
|
|
|
|
+ addCurve(0, ".x");
|
|
|
|
|
+ addCurve(1, ".y");
|
|
|
|
|
+ addCurve(2, ".z");
|
|
|
|
|
+ break;
|
|
|
|
|
+ case SerializableProperty.FieldType.Vector4:
|
|
|
|
|
+ addCurve(0, ".x");
|
|
|
|
|
+ addCurve(1, ".y");
|
|
|
|
|
+ addCurve(2, ".z");
|
|
|
|
|
+ addCurve(3, ".w");
|
|
|
|
|
+ break;
|
|
|
|
|
+ case SerializableProperty.FieldType.Color:
|
|
|
|
|
+ addCurve(0, ".r");
|
|
|
|
|
+ addCurve(1, ".g");
|
|
|
|
|
+ addCurve(2, ".b");
|
|
|
|
|
+ addCurve(3, ".a");
|
|
|
|
|
+ break;
|
|
|
|
|
+ case SerializableProperty.FieldType.Bool:
|
|
|
|
|
+ case SerializableProperty.FieldType.Int:
|
|
|
|
|
+ case SerializableProperty.FieldType.Float:
|
|
|
|
|
+ addCurve(0, "");
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
AnimationCurves newClipCurves = new AnimationCurves();
|
|
AnimationCurves newClipCurves = new AnimationCurves();
|