public override void Process(ImportContext ctx, Layer layer) { var eventFrames = new HashSet <int>(); var file = ctx.file; for (int i = 0; i < file.frames.Count; ++i) { bool isEvent = file.frames[i].cels.ContainsKey(layer.index); if (isEvent) { eventFrames.Add(i); } } LayerParamType paramType = layer.GetParamType(1); foreach (var frametag in file.frameTags) { var clip = ctx.generatedClips[frametag]; var events = new List <AnimationEvent>(clip.events); var time = 0.0f; for (int f = frametag.from; f <= frametag.to; ++f) { if (eventFrames.Contains(f)) { var evt = new AnimationEvent { time = time, functionName = layer.GetParamString(0), messageOptions = SendMessageOptions.DontRequireReceiver }; // Debug.Log(paramType + ", " + layer.metaInfo.ParamCount); if (paramType == LayerParamType.String) { evt.stringParameter = layer.GetParamString(1); } else if (paramType == LayerParamType.Number) { var fval = layer.GetParamFloat(1); if (fval == Math.Floor(fval)) { evt.intParameter = (int)fval; } else { evt.floatParameter = fval; } } events.Add(evt); } time += file.frames[f].duration * 1e-3f; } events.Sort((lhs, rhs) => lhs.time.CompareTo(rhs.time)); AnimationUtility.SetAnimationEvents(clip, events.ToArray()); EditorUtility.SetDirty(clip); } }
public static ASEFile Parse(byte[] bytes) { var stream = new MemoryStream(bytes); using (var reader = new BinaryReader(stream)) { var file = new ASEFile(); reader.ReadDWord(); // File size _CheckMagicNumber(reader.ReadWord(), 0xA5E0); var frameCount = reader.ReadWord(); file.width = reader.ReadWord(); file.height = reader.ReadWord(); var colorDepth = reader.ReadWord(); if (colorDepth != 32) { _Error("Non RGBA color mode isn't supported yet"); } reader.ReadDWord(); // Flags reader.ReadWord(); // Deprecated speed _CheckMagicNumber(reader.ReadDWord(), 0); _CheckMagicNumber(reader.ReadDWord(), 0); reader.ReadBytes(4); reader.ReadWord(); reader.ReadBytes(2); reader.ReadBytes(92); int readLayerIndex = 0; UserDataAcceptor lastUserdataAcceptor = null; for (int i = 0; i < frameCount; ++i) { var frame = new Frame(); frame.frameID = i; reader.ReadDWord(); // frameBytes _CheckMagicNumber(reader.ReadWord(), 0xF1FA); var chunkCount = reader.ReadWord(); frame.duration = reader.ReadWord(); reader.ReadBytes(6); for (int j = 0; j < chunkCount; ++j) { var chunkBytes = reader.ReadDWord(); // 4 var chunkType = reader.ReadWord(); // 2 switch (chunkType) { case CHUNK_LAYER: { var layer = new Layer(); var flags = reader.ReadWord(); layer.visible = (flags & 0x1) != 0; var layerType = reader.ReadWord(); reader.ReadWord(); // childLevel reader.ReadWord(); reader.ReadWord(); layer.blendMode = (BlendMode)reader.ReadWord(); layer.opacity = reader.ReadByte() / 255.0f; reader.ReadBytes(3); layer.layerName = reader.ReadUTF8(); if (layerType == 0 && layer.visible && !layer.layerName.StartsWith("//")) { layer.index = readLayerIndex; layer.type = layer.layerName.StartsWith("@") ? LayerType.Meta : LayerType.Content; if (layer.type == LayerType.Meta) { MetaLayerParser.Parse(layer); } file.layers.Add(layer); } ++readLayerIndex; lastUserdataAcceptor = layer; } break; case CHUNK_CEL: { var cel = new Cel(); cel.layerIndex = reader.ReadWord(); // 2 cel.x = reader.ReadInt16(); // 2 cel.y = reader.ReadInt16(); // 2 cel.opacity = reader.ReadByte() / 255.0f; // 1 cel.type = (CelType)reader.ReadWord(); // 2 reader.ReadBytes(7); // 7 switch (cel.type) { case CelType.Raw: { cel.width = reader.ReadWord(); // 2 cel.height = reader.ReadWord(); // 2 cel.colorBuffer = ToColorBufferRGBA(reader.ReadBytes(chunkBytes - 6 - 16 - 4)); _Assert(cel.width * cel.height == cel.colorBuffer.Length, "Color buffer size incorrect"); } break; case CelType.Linked: { cel.linkedCel = reader.ReadWord(); } break; case CelType.Compressed: { cel.width = reader.ReadWord(); cel.height = reader.ReadWord(); cel.colorBuffer = ToColorBufferRGBA( reader.ReadCompressedBytes(chunkBytes - 6 - 16 - 4)); _Assert(cel.width * cel.height == cel.colorBuffer.Length, "Color buffer size incorrect"); } break; } if (file.FindLayer(cel.layerIndex) != null) { frame.cels.Add(cel.layerIndex, cel); } lastUserdataAcceptor = cel; } break; case CHUNK_FRAME_TAGS: { var count = reader.ReadWord(); reader.ReadBytes(8); for (int c = 0; c < count; ++c) { var frameTag = new FrameTag(); frameTag.from = reader.ReadWord(); frameTag.to = reader.ReadWord(); reader.ReadByte(); reader.ReadBytes(8); reader.ReadBytes(3); reader.ReadByte(); frameTag.name = reader.ReadUTF8(); if (frameTag.name.StartsWith("//")) // Commented tags are ignored { continue; } var originalName = frameTag.name; var tagIdx = frameTag.name.IndexOf('#'); var nameInvalid = false; if (tagIdx != -1) { frameTag.name = frameTag.name.Substring(0, tagIdx).Trim(); var possibleProperties = originalName.Substring(tagIdx).Split(' '); foreach (var possibleProperty in possibleProperties) { if (possibleProperty.Length > 1 && possibleProperty[0] == '#') { frameTag.properties.Add(possibleProperty.Substring(1)); } else { nameInvalid = true; } } } if (nameInvalid) { Debug.LogWarning("Invalid name: " + originalName); } file.frameTags.Add(frameTag); } } break; case CHUNK_USERDATA: { var flags = reader.ReadDWord(); var hasText = (flags & 0x01) != 0; var hasColor = (flags & 0x02) != 0; if (hasText) { lastUserdataAcceptor.userData = reader.ReadUTF8(); } if (hasColor) { reader.ReadBytes(4); } } break; default: { reader.ReadBytes(chunkBytes - 6); } break; } } file.frames.Add(frame); } // Post process: eliminate reference cels for (int f = 0; f < file.frames.Count; ++f) { var frame = file.frames[f]; foreach (var pair in frame.cels) { var layerID = pair.Key; var cel = pair.Value; if (cel.type == CelType.Linked) { cel.type = CelType.Raw; var src = file.frames[cel.linkedCel].cels[layerID]; cel.x = src.x; cel.y = src.y; cel.width = src.width; cel.height = src.height; cel.colorBuffer = src.colorBuffer; cel.opacity = src.opacity; cel.userData = src.userData; } } } return(file); } }
static void _Parse(Lexer lexer, Layer layer) { layer.actionName = _Expect(lexer, TKN_ID); if (!_SkipSpaces(lexer)) { return; } if (lexer.Token != TKN_LEFT) { _ErrorUnexpected(lexer, TKN_LEFT); } while (true) { if (!_SkipSpaces(lexer)) { _ErrorEOF(lexer, TKN_RIGHT, TKN_NUMBER, TKN_STRING); } bool isParam = false; if (lexer.Token == TKN_STRING) { var param = new LayerParam(); param.type = LayerParamType.String; param.stringValue = lexer.TokenContents.Substring(1, lexer.TokenContents.Length - 2); layer.parameters.Add(param); isParam = true; } else if (lexer.Token == TKN_NUMBER) { var param = new LayerParam(); param.type = LayerParamType.Number; param.numberValue = double.Parse(lexer.TokenContents); layer.parameters.Add(param); isParam = true; } else if (lexer.Token == TKN_RIGHT) { break; } else { _ErrorUnexpected(lexer, TKN_RIGHT, TKN_NUMBER, TKN_STRING); } if (isParam) { if (!_SkipSpaces(lexer)) { _ErrorEOF(lexer, TKN_COMMA, TKN_RIGHT); } if (lexer.Token == TKN_RIGHT) { break; } if (lexer.Token != TKN_COMMA) { _ErrorUnexpected(lexer, TKN_COMMA, TKN_RIGHT); } } } if (_SkipSpaces(lexer)) { Debug.LogWarning("Invalid content after layer definition finished: " + lexer.Token + "/" + lexer.TokenContents); } }
public override void Process(ImportContext ctx, Layer layer) { // the name of the data variable should be the first parameter. eg @data("leg l") string dataName = layer.GetParamString(0); var file = ctx.file; var importer = AssetImporter.GetAtPath(ctx.atlasPath) as TextureImporter; var spriteSheet = importer.spritesheet; // each tag represents a different animation. look at each frame of each tag. store coordinates of any visible pixels. // these represent the data points. foreach (var tag in ctx.file.frameTags) { string animName = tag.name; Vector3 distance = Vector3.zero; var frameDataList = new FrameDataList { frames = new List <FrameData>() }; int numFrames = tag.to - tag.from + 1; for (int i = tag.from, j = 0; i <= tag.to; ++i, j++) { var frameData = new FrameData { frame = j, coords = new List <Vector2>() }; Cel cel; file.frames[i].cels.TryGetValue(layer.index, out cel); if (cel != null) { int pixelCount = 0; for (int y = 0; y < cel.height; ++y) { for (int x = 0; x < cel.width; ++x) { // tex coords relative to full texture boundaries int texX = cel.x + x; int texY = -(cel.y + y) + file.height - 1; // store position of any visible pixels var pxl = cel.GetPixelRaw(x, y); if (pxl.a > 0.1f) { // start the coordinate of the pixel on the layer (from bottom left corner) Vector2 coord = new Vector2(texX, texY); // default pixel origin is bottom left. if centered, add half a pixel in x and y directions if (ctx.settings.pixelOrigin == PixelOrigin.Center) { coord += new Vector2(0.5f, 0.5f); } // calculate position in relation to pivot Vector2 pivot = spriteSheet[i].pivot; Vector2 pivotPxl = new Vector2(pivot.x * spriteSheet[i].rect.width, pivot.y * spriteSheet[i].rect.height); // get coordinate relative to pivot coord -= ctx.spriteCropPositions[i]; coord -= pivotPxl; // if calculating "prev pivot" data, and this is first pixel (should only be one), then store its distance if (dataName == "prev pivot" && pixelCount == 0) { // coord is distance from pivot. negate to make positive, and round to get rid of float errors distance += new Vector3(-Mathf.Round(coord.x), -Mathf.Round(coord.y), 0); } // points are all relative to the sprite's bounding rectangle, which is 1 by 1 in both dimensions // regardless of sprite size. So (0.5, 0.5) would be the center of the sprite. // it's ok for points to be outside the bounding rectangle. they'll just be less than 0, or greater than 1. // WHY? so if the sprite is transformed, everything stays relative. You can multiply points by the transforms // to get their position relative to the transform. // NOTE: spriteSheet[i].rect.width/height are in pixels coord = new Vector2(coord.x / spriteSheet[i].rect.width, coord.y / spriteSheet[i].rect.height); frameData.coords.Add(coord); ++pixelCount; } } } if (pixelCount > 0) { frameDataList.frames.Add(frameData); } } } // if we've collected all the data for this animation, save it in appropriate dictionary spot if (frameDataList.frames.Count > 0) { if (ctx.animData.animDict.ContainsKey(animName)) { ctx.animData.animDict[animName].frameDict.Add(dataName, frameDataList); if (dataName == "prev pivot") { ctx.animData.animDict[animName].distance = distance; } } else { ctx.animData.animDict.Add(animName, new AnimList { numFrames = numFrames, distance = distance, frameDict = new FrameDictionary() { { dataName, frameDataList } } }); } // Debug.Log(ctx.animData.data["run e"]); } } // Debug.Log(data); }