Skip to content

Commit

Permalink
Merge branch 'release/v0.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
nicloay committed Aug 22, 2014
2 parents 4d90dc4 + da3a3f3 commit 17234e0
Show file tree
Hide file tree
Showing 26 changed files with 624 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.Collections.Generic;
using LitJson;

namespace UnitySpineImporter{
public class SpineAnimation {
public Dictionary<string, SpineBoneAnimation> bones;
public Dictionary<string, SpineSlotAnimation> slots;
public List<SpineDrawOrderAnimation> draworder;

public Dictionary< string, SpineBoneAnimation > bones;
public Dictionary< string, SpineSlotAnimation > slots;
public List< SpineDrawOrderAnimation > draworder;
public List< JsonData > events;
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
using UnityEngine;
using System.Collections;
using LitJson;
namespace UnitySpineImporter {
public class SpineAnimationEvent {
public double time;
public string name;

public class SpineAnimationEvent : MonoBehaviour {

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,16 @@ void OnWizardCreate(){
Dictionary<string, Slot> slotByName;
List<Skin> skins;
AttachmentGOByNameBySlot attachmentGOByNameBySlot;

if (File.Exists(path)){
try{
SpineMultiatlas spineMultiAtlas = SpineMultiatlas.deserializeFromFile(atlasPath );
SpineData spineData = SpineData .deserializeFromFile(path);

SpineUtil.updateImporters(spineMultiAtlas, directory, pixelsPerUnit, out spriteByName);
GameObject rootGO = SpineUtil.buildSceleton(name, spineData, pixelsPerUnit, out boneGOByName, out slotByName);
GameObject rootGO = SpineUtil.buildSceleton(name, spineData, pixelsPerUnit, zStep, out boneGOByName, out slotByName);
rootGO.name = name;
SpineUtil.addAllAttahcmentsSlots(spineData, spriteByName, slotByName, zStep, pixelsPerUnit, out skins, out attachmentGOByNameBySlot);
SpineUtil.addAllAttahcmentsSlots(spineData, spriteByName, slotByName, pixelsPerUnit, out skins, out attachmentGOByNameBySlot);
SkinController sk = SpineUtil.addSkinController(rootGO, spineData, skins, slotByName);
if (animationImportType == AnimationImportType.MECANIM){
Animator animator = SpineUtil.addAnimator(rootGO);
Expand All @@ -74,8 +75,8 @@ void OnWizardCreate(){

ModelImporterAnimationType modelImporterAnimationType = getModelImporterAnimationType();
if (spineData.animations !=null && spineData.animations.Count > 0)
SpineUtil.addAnimation(rootGO, directory, spineData, boneGOByName, attachmentGOByNameBySlot,
pixelsPerUnit, modelImporterAnimationType, updateResources);
SpineUtil.addAnimation(rootGO, directory, spineData, boneGOByName, slotByName, attachmentGOByNameBySlot, skins,
pixelsPerUnit, zStep, modelImporterAnimationType, updateResources );
sk.showDefaulSlots();
SpineUtil.buildPrefab(rootGO, directory, name);
GameObject.DestroyImmediate(rootGO);
Expand Down
224 changes: 210 additions & 14 deletions Assets/UnitySpineImporter/Scripts/Editor/Util/SpineUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public static void swap2Float(ref float float1, ref float float2){
float2 = tmp;
}

public static GameObject buildSceleton(string name, SpineData data, int pixelsPerUnit, out Dictionary<string,GameObject> boneGOByName, out Dictionary<string, Slot> slotByName){
public static GameObject buildSceleton( string name, SpineData data, int pixelsPerUnit, float zStep, out Dictionary<string, GameObject> boneGOByName, out Dictionary<string, Slot> slotByName ) {
float ratio = 1.0f / (float)pixelsPerUnit;
boneGOByName = new Dictionary<string, GameObject>();
slotByName = new Dictionary<string, Slot>();
Expand Down Expand Up @@ -240,6 +240,8 @@ public static GameObject buildSceleton(string name, SpineData data, int pixelsPe
GameObject go = new GameObject(getSlotGOName(spineSlot.name));
go.transform.parent = boneGOByName[spineSlot.bone].transform;
resetLocalTRS(go);
int drawOrder = data.slotOrder[ spineSlot.name ];
go.transform.localPosition = new Vector3( 0, 0, (- drawOrder ) * zStep );
Slot slot = new Slot();
slot.bone = spineSlot.bone;
slot.name = spineSlot.name;
Expand All @@ -261,7 +263,7 @@ public static void resetLocalTRS(GameObject go){
go.transform.localScale = Vector3.one;
}

public static void addAllAttahcmentsSlots(SpineData spineData, SpritesByName spriteByName, Dictionary<string, Slot> slotByName, float zStep, int pixelsPerUnit, out List<Skin> skins, out AttachmentGOByNameBySlot attachmentGOByNameBySlot){
public static void addAllAttahcmentsSlots(SpineData spineData, SpritesByName spriteByName, Dictionary<string, Slot> slotByName, int pixelsPerUnit, out List<Skin> skins, out AttachmentGOByNameBySlot attachmentGOByNameBySlot){
float ratio = 1.0f / (float) pixelsPerUnit;
skins = new List<Skin>();
attachmentGOByNameBySlot= new AttachmentGOByNameBySlot();
Expand All @@ -277,7 +279,7 @@ public static void addAllAttahcmentsSlots(SpineData spineData, SpritesByName spr
GameObject slotGO = slotByName[slotName].gameObject;

Slot slot = slotByName[slotName];

string spritePath = spineData.slotPathByName[ slotName ] + "/";


SkinSlot skinSlot = new SkinSlot();
Expand All @@ -294,14 +296,14 @@ public static void addAllAttahcmentsSlots(SpineData spineData, SpritesByName spr
// - create skined object or direct GO for default skin
Sprite sprite;
spriteByName.TryGetValue(spineAttachment.name, out sprite);
int drawOrder = spineData.slotOrder[slotName];

GameObject parentGO;
GameObject spriteGO;
string fixedName = attachmenName.Replace("/",SLASH_REPLACEMENT);
if (isDefault){
parentGO = slotGO;
spriteGO = new GameObject(fixedName);
spritePath += fixedName;
Attachment a = new Attachment(attachmenName, AttachmentType.SINGLE_SPRITE, spriteGO);
slot.addAttachment(a);
} else {
Expand All @@ -315,19 +317,21 @@ public static void addAllAttahcmentsSlots(SpineData spineData, SpritesByName spr
a = new Attachment(attachmenName, AttachmentType.SKINED_SPRITE, attachmentGO);
slot.addAttachment(a);
}

spritePath += fixedName + "/" + skinName;
parentGO = a.gameObject;
}

attachment.gameObject = spriteGO;
attachment.ObPath = spritePath;
spriteGO.transform.parent = parentGO.gameObject.transform;
// -
if (spineAttachment.type.Equals("region")){
SpriteRenderer sr = spriteGO.AddComponent<SpriteRenderer>();
sr.sprite = sprite;
spriteGO.transform.localPosition = getAttachmentPosition(spineAttachment, ratio,-( drawOrder * zStep));
spriteGO.transform.localPosition = getAttachmentPosition(spineAttachment, ratio, 0);
spriteGO.transform.localRotation = getAttachmentRotation(spineAttachment, spriteByName.rotatedSprites.Contains(sprite));
spriteGO.transform.localScale = getAttachmentScale(spineAttachment);
attachment.sprite = sr;
} else if (spineAttachment.type.Equals("boundingbox")) {
PolygonCollider2D collider = spriteGO.AddComponent<PolygonCollider2D>();
resetLocalTRS(spriteGO);
Expand Down Expand Up @@ -384,8 +388,11 @@ public static void addAnimation(GameObject rootGO,
string rootDirectory,
SpineData spineData,
Dictionary<string, GameObject> boneGOByName,
Dictionary<string, Slot> slotByName,
AttachmentGOByNameBySlot attachmentGOByNameBySlot,
List<Skin> skinList,
int pixelsPerUnit,
float zStep,
ModelImporterAnimationType modelImporterAnimationType,
bool updateResources)
{
Expand All @@ -411,10 +418,12 @@ public static void addAnimation(GameObject rootGO,
if (spineAnimation.bones!=null)
addBoneAnimationToClip(animationClip,spineAnimation.bones, spineData, boneGOByName, ratio);
if (spineAnimation.slots!=null)
addSlotAnimationToClip(animationClip, spineAnimation.slots, spineData, attachmentGOByNameBySlot);
if (spineAnimation.draworder!=null)
Debug.LogWarning("draworder animation implemented yet");
addSlotAnimationToClip(animationClip, spineAnimation.slots, spineData, skinList, attachmentGOByNameBySlot);

if ( spineAnimation.events != null )
AddEvents( animationClip, spineAnimation.events, animationName );
if (spineAnimation.draworder!=null)
addDrawOrderAnimation( animationClip, spineAnimation.draworder, spineData, zStep, animationName, slotByName );

if (updateCurve){
EditorUtility.SetDirty(animationClip);
Expand All @@ -434,6 +443,68 @@ public static void addAnimation(GameObject rootGO,
}
}

static void AddEvents( AnimationClip clip,
List< JsonData > events,
string animName )
{
List< UnityEngine.AnimationEvent > unityEvents = new List<UnityEngine.AnimationEvent>( );
foreach ( JsonData entry in events ) {
if ( !entry.IsObject )
Debug.LogError( "JSON data is wrong. Event is not an Object??!!" );
IDictionary entry_dict = entry as IDictionary;

UnityEngine.AnimationEvent ev = new UnityEngine.AnimationEvent( );

if ( entry_dict.Contains( "name" ) )
ev.functionName = ( ( string ) entry[ "name" ] );
else
Debug.LogError( "JSON data is wrong. Missing Name in event data: " + animName );

if ( entry_dict.Contains( "time" ) )
ev.time = getNumberData( entry[ "time" ], animName );
else
Debug.LogError( "JSON data is wrong. Missing Time in event data: " + animName + " EVENT_NAME: " + ev.functionName );

bool ParamAdded = false;
if ( entry_dict.Contains( "int" ) ) {
ev.intParameter = ( int ) entry[ "int" ];
ParamAdded = true;
}

if ( entry_dict.Contains( "float" ) ) {
if ( ParamAdded )
Debug.LogError( "JSON data is wrong. Unity Supports only one event parameter!!!! CLIP NAME: " + animName + " EVENT_NAME: " + entry.ToJson( ) );
ev.floatParameter = getNumberData( entry[ "float" ], animName );
ParamAdded = true;
}

if ( entry_dict.Contains( "string" ) ) {
if ( ParamAdded )
Debug.LogError( "JSON data is wrong. Unity Supports only one event parameter!!!! CLIP NAME: " + animName + " EVENT_NAME: " + entry.ToJson( ) );
ev.stringParameter = ( string ) entry[ "string" ];
}

ev.messageOptions = SendMessageOptions.RequireReceiver;

unityEvents.Add( ev );
}

AnimationUtility.SetAnimationEvents( clip, unityEvents.ToArray( ) );
}

static float getNumberData( JsonData data, string animName ) {

if ( data.IsDouble )
return ( float )( ( double )data );

if ( data.IsInt )
return ( float )( ( int )data );

Debug.LogError( "JSON data is wrong. Unrecognizable number format!!!! CLIP NAME: " + animName + " JsonData: " + data.ToJson( ) );

return 0.0f;
}

static void AddClipToLegacyAnimationComponent(GameObject rootGO, AnimationClip animationClip){
Animation animation = rootGO.GetComponent<Animation>();
if (animation == null)
Expand All @@ -456,9 +527,85 @@ public static string getFirstAttachmentName(SpineSlotAnimation spineSlotAnimatio
return "";
}

public static void addDrawOrderAnimation( AnimationClip clip,
List<SpineDrawOrderAnimation> orderAnimation,
SpineData spineData,
float zStep,
string animName,
Dictionary<string, Slot> slotNameByName )
{
string[] BaseSlotOrder = new string[ spineData.slotOrder.Count ];

Dictionary< string, AnimationCurve > Curvs = new Dictionary<string, AnimationCurve>( );

foreach ( KeyValuePair<string, int> p in spineData.slotOrder ) {
BaseSlotOrder[ p.Value ] = p.Key;
AnimationCurve Curv = new AnimationCurve();
Keyframe keyFrame = new Keyframe( 0.0f, ( - p.Value ) * zStep );
Curv.AddKey( keyFrame );
Curvs[ p.Key ] = Curv;
}

foreach ( SpineDrawOrderAnimation orderAnim in orderAnimation ) {
string[] NewSlotOrder = null;
if ( orderAnim.offsets != null ) {
NewSlotOrder = new string[ BaseSlotOrder.Length ];
string[] BaseOrder_Copy = BaseSlotOrder.Clone( ) as string[];

for ( int i = 0; i != orderAnim.offsets.Length; i++ ) {
SpineDrawOrderAnimationSlot slot = orderAnim.offsets[ i ];
int newIdx = spineData.slotOrder[ slot.slot ] + slot.offset;
NewSlotOrder[ newIdx ] = slot.slot;
int base_idx = Array.IndexOf( BaseOrder_Copy, slot.slot );
BaseOrder_Copy[ base_idx ] = null;
}

int pos = 0;
for ( int i = 0; i != NewSlotOrder.Length; i++ ) {
if ( NewSlotOrder[ i ] == null ) {
bool found = false;
for ( ; pos != BaseOrder_Copy.Length; ) {
if ( BaseOrder_Copy[ pos ] != null ) {
found = true;
NewSlotOrder[ i ] = BaseOrder_Copy[ pos ];
pos++;
break;
} else pos++;
}

if ( !found ) Debug.LogError( "Can't create new draw order" );
}
}
} else NewSlotOrder = BaseSlotOrder;

for ( int j = 0; j != NewSlotOrder.Length; j++ ) {
float t = ( float )orderAnim.time;
float val = ( - j ) * zStep;
AnimationCurve curv = Curvs[ NewSlotOrder[ j ] ];
float priv_val = curv.Evaluate( t );
if ( t > 0.0f ) {
Keyframe keyFrameY_help = new Keyframe( t - 0.00001f, priv_val );
Keyframe keyFrameY = new Keyframe( t, val );
curv.AddKey( keyFrameY_help );
curv.AddKey( keyFrameY );
} else {
Keyframe keyFrameY = new Keyframe( t, val );
curv.AddKey( keyFrameY );
}
}
}

for ( int i = 0; i != BaseSlotOrder.Length; i++ ) {
string slotpath = spineData.slotPathByName[ BaseSlotOrder[ i ] ];
AnimationCurve curv = Curvs[ BaseSlotOrder[ i ] ];
AnimationUtility.SetEditorCurve( clip, EditorCurveBinding.FloatCurve( slotpath, typeof( Transform ), "m_LocalPosition.z" ), curv );
}
}

public static void addSlotAnimationToClip(AnimationClip clip,
Dictionary<string, SpineSlotAnimation> slotsAnimation,
SpineData spineData,
Dictionary<string, SpineSlotAnimation> slotsAnimation,
SpineData spineData,
List<Skin> skinList,
AttachmentGOByNameBySlot attachmentGOByNameBySlot)
{
foreach(KeyValuePair<string, SpineSlotAnimation> kvp in slotsAnimation){
Expand Down Expand Up @@ -529,6 +676,57 @@ public static void addSlotAnimationToClip(AnimationClip
}

if (slotAnimation.color != null && slotAnimation.color.Count >0){
AnimationCurve Curv_R = new AnimationCurve( );
AnimationCurve Curv_G = new AnimationCurve( );
AnimationCurve Curv_B = new AnimationCurve( );
AnimationCurve Curv_A = new AnimationCurve( );
Keyframe startKeyFrame = new Keyframe( 0.0f, 1.0f );
Curv_R.AddKey( startKeyFrame );
Curv_G.AddKey( startKeyFrame );
Curv_B.AddKey( startKeyFrame );
Curv_A.AddKey( startKeyFrame );

JsonData[] curveData = new JsonData[ slotAnimation.color.Count ];
for( int i = 0 ; i != slotAnimation.color.Count ;i++ ) {
SpineSlotColorAnimation color = slotAnimation.color[ i ];
uint col = Convert.ToUInt32( color.color, 16 );
uint r = ( col ) >> 24;
uint g = (col & 0xff0000) >> 16;
uint b = (col & 0xff00) >> 8;
uint a = (col & 0xff);
float t = ( (float) (color.time) );
Keyframe keyFrame_R = new Keyframe( t, r / 255.0f );
Keyframe keyFrame_G = new Keyframe( t, g / 255.0f );
Keyframe keyFrame_B = new Keyframe( t, b / 255.0f );
Keyframe keyFrame_A = new Keyframe( t, a / 255.0f );
Curv_R.AddKey( keyFrame_R );
Curv_G.AddKey( keyFrame_G );
Curv_B.AddKey( keyFrame_B );
Curv_A.AddKey( keyFrame_A );
curveData[ i ] = color.curve;
}

setTangents( Curv_R, curveData );
setTangents( Curv_G, curveData );
setTangents( Curv_B, curveData );
setTangents( Curv_A, curveData );

for ( int i = 0; i != skinList.Count; i++ ) {
if ( skinList[ i ].containsSlot( slotName ) ) {
SkinSlot skinSlot = skinList[ i ][ slotName ];
for ( int j = 0; j != skinSlot.attachments.Length; j++ ) {
SpriteRenderer sprite = skinSlot.attachments[ j ].sprite;
if ( sprite != null ) {
string spritePath = skinSlot.attachments[ j ].ObPath;
AnimationUtility.SetEditorCurve( clip, EditorCurveBinding.FloatCurve( spritePath, typeof( SpriteRenderer ), "m_Color.r" ), Curv_R );
AnimationUtility.SetEditorCurve( clip, EditorCurveBinding.FloatCurve( spritePath, typeof( SpriteRenderer ), "m_Color.g" ), Curv_G );
AnimationUtility.SetEditorCurve( clip, EditorCurveBinding.FloatCurve( spritePath, typeof( SpriteRenderer ), "m_Color.b" ), Curv_B );
AnimationUtility.SetEditorCurve( clip, EditorCurveBinding.FloatCurve( spritePath, typeof( SpriteRenderer ), "m_Color.a" ), Curv_A );
}
}
}
}

Debug.LogWarning("slot color animation is not supported yet");
}
}
Expand Down Expand Up @@ -840,9 +1038,7 @@ public static void addBoneAnimationToClip(AnimationClip clip, Dictionary<string,
static void fixAngles(AnimationCurve curve, JsonData[] curveData){
if (curve.keys.Length <3)
return;
int fullTurn = 0;
bool forward = true;
float currValue, previousValue, diff;
float currValue, previousValue;
for (int previousI=0, i = 1; i < curve.keys.Length; previousI= i++) {
if (curveData[previousI] != null && curveData[previousI].IsString && ((string)curveData[previousI]).Equals("stepped"))
continue;
Expand Down
Loading

0 comments on commit 17234e0

Please sign in to comment.