diff --git a/AnimatedSkeletonGenerator.as b/AnimatedSkeletonGenerator.as index 20fec88..c4b6409 100644 --- a/AnimatedSkeletonGenerator.as +++ b/AnimatedSkeletonGenerator.as @@ -10,12 +10,13 @@ { private var src:MovieClip; private var def:GraphicExportDef; + public function get Def():GraphicExportDef { return def; } private var callback; - private var pieces:Array; - private var pieceSequences:Array; + private var sequences:Array; + private var frames:Array; public function GetFrames():Array { - return []; + return frames; } public function GetData() { @@ -28,16 +29,13 @@ } private var library:PieceLibrary - private var currentSeq:int; public function Go(callback) { + sequences = new Array(); library = new PieceLibrary(); - pieces = new Array(); - pieceSequences = new Array(); this.callback = callback; for (var i = 0; i < src.totalFrames; i++) { - currentSeq = i; Utils.WeirdGotoFrame(src, i + 1); Utils.RecursivelyStop(src); @@ -46,512 +44,24 @@ var c = src.getChildAt(j); if (c is MovieClip) { - GetAnimation(c, i); + var s:Sequence = new Sequence(this, library, i, c); + s.GetAnimation(); + sequences.push(s); break; } } } + frames = library.GetAllUsedPieces().map( + function(p:Piece, i, arr) + { + return p.Frame; + } + ); + callback(true); } - private var currentSeqLength:int; - private function GetAnimation(m:MovieClip, seq:int) - { - currentSeqLength = m.totalFrames; - for (var i = 0; i < m.totalFrames; i++) - { - Utils.WeirdGotoFrame(m, i + 1); - Utils.RecursivelyStop(m); - - RecursePieces(m, m, i + 1, 0, new Matrix()); - } - } - - protected function RecursePieces(base:MovieClip, graphic:MovieClip, frame, depth, parentMatrix:Matrix) - { - //_strace(depth+" "+graphic.name+" frame:"+frame); - - var mat:Matrix = graphic.transform.matrix.clone(); - mat.concat(parentMatrix); - - var currentPieces:Array = []; - - var allChildren:Array = Utils.GetChildren(graphic); - for (var i = 0; i < allChildren.length; i++) - { - if (!allChildren[i].visible) continue; - if (allChildren[i] is MovieClip) - { - if (IsFullPiece(base, graphic, allChildren[i])) - { - currentPieces.push(allChildren[i]); - } else { - depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); - currentPieces.splice(0); - - depth = RecursePieces(base, allChildren[i], frame, depth, mat.clone()); - } - } else { - currentPieces.push(allChildren[i]); - } - } - - depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); - return depth; - } - - protected function GeneratePieceForClips(clips:Array, depth, frame, parentMatrix:Matrix) - { - if (clips.length > 0) - { - var l = clips.length; - var bounds:Rectangle = null; - - var invertMatrix:Matrix = clips[0].transform.matrix.clone(); - invertMatrix.invert(); - var i; - var m:Matrix; - var useMatrix:Array = []; - for (i = 0; i < clips.length; i++) - { - if (i == 0) - { - m = new Matrix(); - } else { - m = clips[i].transform.matrix.clone(); - m.concat(invertMatrix); - } - - var r:Rectangle = Utils.GetAccurateBounds(clips[i]); - Utils.TransformRect(r, m); - if (bounds == null) - { - bounds = r.clone(); - } else { - if (r.left < bounds.left) bounds.left = r.left; - if (r.top < bounds.top) bounds.top = r.top; - if (r.right > bounds.right) bounds.right = r.right; - if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; - } - - useMatrix.push(m); - } - - Utils.ScaleRect(bounds, def.scale); - Utils.RoundRect(bounds); - var bd:BitmapData = new BitmapData(Math.max(1, bounds.width), Math.max(1,bounds.height), true, 0x0); - - for (i = 0; i < clips.length; i++) - { - m = useMatrix[i]; - m.scale(def.scale, def.scale); - m.translate(-bounds.left, -bounds.top); - var ct:ColorTransform = clips[i] is Shape ? clips[i].parent.transform.colorTransform : clips[i].transform.colorTransform; - bd.draw(clips[i], m, ct, null, null, true); - } - - var center:Point = new Point(-bounds.left, -bounds.top); - - var piece:Piece = library.GetPieceFromBitmapData(bd, clips[0].parent.name, center); - if (piece) - { - var mat:Matrix = new Matrix(1/def.scale, 0, 0, 1/def.scale, center.x - piece.CenterPoint.x, center.y - piece.CenterPoint.y); - mat.concat(clips[0].transform.matrix); - mat.concat(parentMatrix); - - //mat.a /= exporter.Upscale; - //mat.d /= exporter.Upscale; - - var pieceSequence:PieceSequence = GetPieceSequence(piece, frame, clips[0], mat, depth); - var info:PieceFrameInfo = pieceSequence.GetFrame(frame); - if (info) - { - info.Present = true; - - info.Transform = mat; - - - - info.Depth = depth; - depth++; - } - } - } - return depth; - } - - protected function GetPieceSequence(piece:Piece, frame, clip:DisplayObject, newTransform:Matrix, newDepth) - { - if (this.pieces.indexOf(piece) == -1) this.pieces.push(piece); - var options:Array = []; - var i; - for (i in pieceSequences) - { - if (pieceSequences[i].GetPiece() == piece) - { - var frameInfo:PieceFrameInfo = pieceSequences[i].GetFrame(frame); - if (frameInfo && !frameInfo.Present) - { - if (pieceSequences[i].CheckMatches(clip)) - { - return pieceSequences[i]; - } else { - options.push(pieceSequences[i]); - } - } - } - } - - if (options.length == 0) - { - var s:PieceSequence = new PieceSequence(piece, this.currentSeqLength); - piece.AddUse(currentSeq); - pieceSequences.push(s); - return s; - } - - var scores:Array = []; - for (i = 0; i < options.length; i++) - { - var score = 0; - if (frame > 1) - { - var prevInfo:PieceFrameInfo = options[i].GetFrame(frame - 1); - if (prevInfo && prevInfo.Present) - { - score = ComputeTransformScore(prevInfo.Transform, prevInfo.Depth, newTransform, newDepth); - } - } - scores.push(score); - } - var sorted:Array = scores.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - return options[sorted[0]]; - } - - protected function ComputeTransformScore(transformA:Matrix, depthA, transformB:Matrix, depthB, posVal = 1, scaleVal = 15, rotVal = 20, depthVal = 10) - { - var deltaPos = Point.distance(new Point(transformA.tx, transformA.ty), new Point(transformB.tx, transformB.ty)); - deltaPos /= def.scale; - - var partsA = Utils.Decompose(transformA); - var partsB = Utils.Decompose(transformB); - - var rotA = partsA.rot; - var rotB = partsB.rot; - var deltaRot = Utils.GetAngleDiffAbs(rotA, rotB); - - var deltaScaleX = partsA.sx / partsB.sx; - if (deltaScaleX < 1) deltaScaleX = 1 / deltaScaleX; - var deltaScaleY = partsA.sy / partsB.sy; - if (deltaScaleY < 1) deltaScaleY = 1 / deltaScaleY; - var deltaScale = Math.max(deltaScaleX, deltaScaleY); - - var deltaDepth = Math.abs(depthA - depthB); - - return deltaPos * posVal + (deltaScale - 1) * scaleVal + deltaRot * rotVal + deltaDepth * depthVal; - } - - public static var ONLYCOMBINEADJACENT = true; - - protected function CombinePieces() - { - var i, j, info:PieceFrameInfo, index; - var sequenceByPresent = {}; - for (i in pieceSequences) - { - var str = ""; - for (j = 0; j < length; j++) - { - info = pieceSequences[i].GetFrame(j + 1); - str += (info && info.Present) ? "1" : "0"; - } - if (!(str in sequenceByPresent)) - { - sequenceByPresent[str] = []; - } - sequenceByPresent[str].push(pieceSequences[i]); - } - - for (var presentStr in sequenceByPresent) - { - var all:Array = sequenceByPresent[presentStr]; - - var firstFrame = ("" + presentStr).indexOf("1") + 1; - - var depths:Array = []; - for (i = 0; i < all.length; i++) - { - depths.push(all[i].GetFrame(firstFrame).Depth); - } - var sorted:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - - var groups:Array = []; - var lastGroup:Array = null; - for (i = 0; i < all.length; i++) - { - index = sorted[i]; - if (ONLYCOMBINEADJACENT) - { - if (lastGroup != null && SequenceMatches(lastGroup[0], all[index])) - { - lastGroup.push(all[index]); - } else { - lastGroup = []; - groups.push(lastGroup); - lastGroup.push(all[index]); - } - } else { - var foundGroup = false; - for (j in groups) - { - if (SequenceMatches(groups[j][0], all[index])) - { - groups[j].push(all[index]); - foundGroup = true; - break; - } - } - if (!foundGroup) - { - var g:Array = []; - g.push(all[index]); - groups.push(g); - } - } - } - } - - var p:Piece; - for (i in groups) - { - // recovering the original pieces... - // for now: render the bitmaps? (one will be transformed... but it would be transformed anyways, right?) - var group:Array = groups[i]; - if (group.length > 1) - { - var origSeq:PieceSequence = group[0]; - var invert:Matrix; - var firstPresent = null; - for (j = 0; j < length; j++) - { - info = origSeq.GetFrame(j + 1); - if (info && info.Present) - { - firstPresent = j + 1; - invert = info.Transform.clone(); - invert.invert(); - break; - } - } - var bounds:Rectangle = null; - var transforms:Array = []; - for (j = 0; j < group.length; j++) - { - p = group[j].GetPiece(); - p.RemoveUse(currentSeq); - var m:Matrix = new Matrix(); - if (j > 0) - { - //m.translate(-group[j].CenterPoint.x, -group[j].CenterPoint.y); - m.concat(invert); - m.concat(group[j].GetFrame(firstPresent).Transform); - //m.translate(origSeq.CenterPoint.x, origSeq.CenterPoint.y); - } - var r:Rectangle = p.FullData.rect.clone(); - Utils.TransformRect(r, m); - - if (bounds == null) - { - bounds = r; - } else { - if (r.left < bounds.left) bounds.left = r.left; - if (r.right > bounds.right) bounds.right = r.right; - if (r.top < bounds.top) bounds.top = r.top; - if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; - } - transforms.push(m); - } - Utils.RoundRect(bounds); - var bd:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x0); - for (j = 0; j < group.length; j++) - { - transforms[j].translate(-bounds.left, -bounds.top); - bd.draw(group[j].GetPiece().FullData, transforms[j], null, null, null, true); - } - - p = library.GetPieceFromBitmapData(bd, "CombinedPiece"); - var seq:PieceSequence = new PieceSequence(p, currentSeqLength); - p.AddUse(currentSeq); - seq.CopyTransformsFrom(origSeq, group[group.length - 1].GetFrame(firstPresent).Depth); - - this.pieceSequences.push(seq); - - this.pieces.push(p); - } - } - - for (i in groups) - { - if (groups[i].length > 1) - { - for (j in groups[i]) - { - index = this.pieceSequences.indexOf(groups[i][j]); - if (index == -1) - { - throw new Error("huh?"); - } else { - pieceSequences.splice(index, 1); - } - } - } - } - - - for (i = 0; i < pieces.length; i++) - { - if (pieces[i].GetUses(currentSeq) == 0) - { - pieces.splice(i, 1); - i--; - } - } - - } - - protected function SequenceMatches(a:PieceSequence, b:PieceSequence) - { - var relative:Matrix = null; - for (var i = 0; i < length; i++) - { - var infoA:PieceFrameInfo = a.GetFrame(i + 1); - var infoB:PieceFrameInfo = b.GetFrame(i + 1); - if (infoA && infoB && infoA.Present && infoB.Present) - { - var m:Matrix = Utils.GetTransform(infoA.Transform, infoB.Transform); - if (relative == null) - { - relative = m; - } else { - if (ComputeTransformScore(relative, 0, m, 0, 4, 15, 5, 0) > 4) return false; - } - } - } - return true; - } - - public function ProduceFrame(frame, excludeNames:Array = null):MovieClip - { - var i; - var depths:Array = []; - for (i = 0; i < pieceSequences.length; i++) - { - depths.push(pieceSequences[i].GetFrame(frame).Depth); - } - - var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - - var m:MovieClip = new MovieClip(); - for (i = 0; i < sorts.length; i++) - { - var ps:PieceSequence = pieceSequences[sorts[i]]; - var info:PieceFrameInfo = ps.GetFrame(frame); - if (info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) - { - var p:Piece = ps.GetPiece(); - var b:Bitmap = new Bitmap(p.FullData); - - var mat:Matrix = new Matrix(); - mat.translate(-p.CenterPoint.x, -p.CenterPoint.y); - mat.concat(info.Transform); - - //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); - - //b.smoothing = true; - b.transform.matrix = mat; - - m.addChild(b); - } - } - return m; - } - - public function ProduceFrameBitmapData(frame, excludeNames:Array = null) - { - var ps:PieceSequence; - var r:Rectangle = null; - var i; - var mat:Matrix; - for (i in pieceSequences) - { - ps = pieceSequences[i]; - var frameInfo:PieceFrameInfo = ps.GetFrame(frame); - if (frameInfo && frameInfo.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) - { - var piece:Piece = ps.GetPiece(); - var bounds:Rectangle = piece.FullData.rect; - bounds.x -= piece.CenterPoint.x; - bounds.y -= piece.CenterPoint.y; - mat = frameInfo.Transform.clone(); - //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); - Utils.TransformRect(bounds, mat); - - if (r == null) - { - r = bounds; - } else { - if (bounds.left < r.left) r.left = bounds.left; - if (bounds.top < r.top) r.top = bounds.top; - if (bounds.right > r.right) r.right = bounds.right; - if (bounds.bottom > r.bottom) r.bottom = bounds.bottom; - } - - } - } - - if (r == null) { - return {data:new BitmapData(1, 1, true, 0x0),center_point:new Point(0, 0)}; - } - - Utils.RoundRect(r); - var bd:BitmapData; - try { - bd = new BitmapData(Math.min(512, r.width), Math.min(512, r.height), true, 0x0); - } catch (e){ - //_strace("failed to create bitmap data"); - } - - var depths:Array = []; - for (i = 0; i < pieceSequences.length; i++) - { - depths.push(pieceSequences[i].GetFrame(frame).Depth); - } - - var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - - for (i = 0; i < sorts.length; i++) - { - ps = pieceSequences[sorts[i]]; - var info:PieceFrameInfo = ps.GetFrame(frame); - if (info && info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) - { - var p:Piece = ps.GetPiece(); - - mat = new Matrix(); - mat.translate(-ps.GetPiece().CenterPoint.x, -ps.GetPiece().CenterPoint.y); - mat.concat(info.Transform); - - //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); - - mat.translate(-r.left, -r.top); - - bd.draw(p.FullData, mat, null, null, null, true); - } - } - return {data:bd,center_point:new Point(-r.left, -r.top)}; - } - public static function IsFullPiece(baseClip:DisplayObject, parentClip:MovieClip, clip:DisplayObject) { //if (HasAnyNamedChildren(clip)) return false; @@ -577,4 +87,522 @@ return true; } } +} + +class Sequence +{ + import flash.display.*; + import flash.geom.*; + + private var pieces:Array = new Array(); + private var pieceSequences:Array = new Array(); + private var src:MovieClip; + private var seq:int; + private var seqLength:int; + private var library:PieceLibrary; + private var generator:AnimatedSkeletonGenerator; + + public function Sequence(generator:AnimatedSkeletonGenerator, library:PieceLibrary, seq:int, src:MovieClip) + { + this.generator = generator; + this.library = library; + this.seq = seq; + this.seqLength = src.totalFrames; + this.src = src; + } + + public function GetAnimation() + { + for (var i = 0; i < seqLength; i++) + { + Utils.WeirdGotoFrame(src, i + 1); + Utils.RecursivelyStop(src); + + RecursePieces(src, i + 1, 0, new Matrix()); + } + } + + protected function RecursePieces(graphic:MovieClip, frame, depth, parentMatrix:Matrix) + { + //_strace(depth+" "+graphic.name+" frame:"+frame); + + var mat:Matrix = graphic.transform.matrix.clone(); + mat.concat(parentMatrix); + + var currentPieces:Array = []; + + var allChildren:Array = Utils.GetChildren(graphic); + for (var i = 0; i < allChildren.length; i++) + { + if (!allChildren[i].visible) continue; + if (allChildren[i] is MovieClip) + { + if (AnimatedSkeletonGenerator.IsFullPiece(src, graphic, allChildren[i])) + { + currentPieces.push(allChildren[i]); + } else { + depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); + currentPieces.splice(0); + + depth = RecursePieces(allChildren[i], frame, depth, mat.clone()); + } + } else { + currentPieces.push(allChildren[i]); + } + } + + depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); + return depth; + } + + protected function GeneratePieceForClips(clips:Array, depth, frame, parentMatrix:Matrix) + { + if (clips.length > 0) + { + var l = clips.length; + var bounds:Rectangle = null; + + var invertMatrix:Matrix = clips[0].transform.matrix.clone(); + invertMatrix.invert(); + var i; + var m:Matrix; + var useMatrix:Array = []; + for (i = 0; i < clips.length; i++) + { + if (i == 0) + { + m = new Matrix(); + } else { + m = clips[i].transform.matrix.clone(); + m.concat(invertMatrix); + } + + var r:Rectangle = Utils.GetAccurateBounds(clips[i]); + Utils.TransformRect(r, m); + if (bounds == null) + { + bounds = r.clone(); + } else { + if (r.left < bounds.left) bounds.left = r.left; + if (r.top < bounds.top) bounds.top = r.top; + if (r.right > bounds.right) bounds.right = r.right; + if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; + } + + useMatrix.push(m); + } + + Utils.ScaleRect(bounds, generator.Def.scale); + Utils.RoundRect(bounds); + var bd:BitmapData = new BitmapData(Math.max(1, bounds.width), Math.max(1,bounds.height), true, 0x0); + + for (i = 0; i < clips.length; i++) + { + m = useMatrix[i]; + m.scale(generator.Def.scale, generator.Def.scale); + m.translate(-bounds.left, -bounds.top); + var ct:ColorTransform = clips[i] is Shape ? clips[i].parent.transform.colorTransform : clips[i].transform.colorTransform; + bd.draw(clips[i], m, ct, null, null, true); + } + + var center:Point = new Point(-bounds.left, -bounds.top); + + var piece:Piece = library.GetPieceFromBitmapData(bd, clips[0].parent.name, center); + if (piece) + { + var mat:Matrix = new Matrix(1 / generator.Def.scale, 0, 0, 1 / generator.Def.scale, center.x - piece.CenterPoint.x, center.y - piece.CenterPoint.y); + mat.concat(clips[0].transform.matrix); + mat.concat(parentMatrix); + + //mat.a /= exporter.Upscale; + //mat.d /= exporter.Upscale; + + var pieceSequence:PieceSequence = GetPieceSequence(piece, frame, clips[0], mat, depth); + var info:PieceFrameInfo = pieceSequence.GetFrame(frame); + if (info) + { + info.Present = true; + + info.Transform = mat; + + + + info.Depth = depth; + depth++; + } + } + } + return depth; + } + + protected function GetPieceSequence(piece:Piece, frame, clip:DisplayObject, newTransform:Matrix, newDepth) + { + if (this.pieces.indexOf(piece) == -1) this.pieces.push(piece); + var options:Array = []; + var i; + for (i in pieceSequences) + { + if (pieceSequences[i].GetPiece() == piece) + { + var frameInfo:PieceFrameInfo = pieceSequences[i].GetFrame(frame); + if (frameInfo && !frameInfo.Present) + { + if (pieceSequences[i].CheckMatches(clip)) + { + return pieceSequences[i]; + } else { + options.push(pieceSequences[i]); + } + } + } + } + + if (options.length == 0) + { + var s:PieceSequence = new PieceSequence(piece, seqLength); + piece.AddUse(seq); + pieceSequences.push(s); + return s; + } + + var scores:Array = []; + for (i = 0; i < options.length; i++) + { + var score = 0; + if (frame > 1) + { + var prevInfo:PieceFrameInfo = options[i].GetFrame(frame - 1); + if (prevInfo && prevInfo.Present) + { + score = ComputeTransformScore(prevInfo.Transform, prevInfo.Depth, newTransform, newDepth); + } + } + scores.push(score); + } + var sorted:Array = scores.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + return options[sorted[0]]; + } + + protected function ComputeTransformScore(transformA:Matrix, depthA, transformB:Matrix, depthB, posVal = 1, scaleVal = 15, rotVal = 20, depthVal = 10) + { + var deltaPos = Point.distance(new Point(transformA.tx, transformA.ty), new Point(transformB.tx, transformB.ty)); + deltaPos /= generator.Def.scale; + + var partsA = Utils.Decompose(transformA); + var partsB = Utils.Decompose(transformB); + + var rotA = partsA.rot; + var rotB = partsB.rot; + var deltaRot = Utils.GetAngleDiffAbs(rotA, rotB); + + var deltaScaleX = partsA.sx / partsB.sx; + if (deltaScaleX < 1) deltaScaleX = 1 / deltaScaleX; + var deltaScaleY = partsA.sy / partsB.sy; + if (deltaScaleY < 1) deltaScaleY = 1 / deltaScaleY; + var deltaScale = Math.max(deltaScaleX, deltaScaleY); + + var deltaDepth = Math.abs(depthA - depthB); + + return deltaPos * posVal + (deltaScale - 1) * scaleVal + deltaRot * rotVal + deltaDepth * depthVal; + } + + public static var ONLYCOMBINEADJACENT = true; + + protected function CombinePieces() + { + var i, j, info:PieceFrameInfo, index; + var sequenceByPresent = {}; + for (i in pieceSequences) + { + var str = ""; + for (j = 0; j < length; j++) + { + info = pieceSequences[i].GetFrame(j + 1); + str += (info && info.Present) ? "1" : "0"; + } + if (!(str in sequenceByPresent)) + { + sequenceByPresent[str] = []; + } + sequenceByPresent[str].push(pieceSequences[i]); + } + + for (var presentStr in sequenceByPresent) + { + var all:Array = sequenceByPresent[presentStr]; + + var firstFrame = ("" + presentStr).indexOf("1") + 1; + + var depths:Array = []; + for (i = 0; i < all.length; i++) + { + depths.push(all[i].GetFrame(firstFrame).Depth); + } + var sorted:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + + var groups:Array = []; + var lastGroup:Array = null; + for (i = 0; i < all.length; i++) + { + index = sorted[i]; + if (ONLYCOMBINEADJACENT) + { + if (lastGroup != null && SequenceMatches(lastGroup[0], all[index])) + { + lastGroup.push(all[index]); + } else { + lastGroup = []; + groups.push(lastGroup); + lastGroup.push(all[index]); + } + } else { + var foundGroup = false; + for (j in groups) + { + if (SequenceMatches(groups[j][0], all[index])) + { + groups[j].push(all[index]); + foundGroup = true; + break; + } + } + if (!foundGroup) + { + var g:Array = []; + g.push(all[index]); + groups.push(g); + } + } + } + } + + var p:Piece; + for (i in groups) + { + // recovering the original pieces... + // for now: render the bitmaps? (one will be transformed... but it would be transformed anyways, right?) + var group:Array = groups[i]; + if (group.length > 1) + { + var origSeq:PieceSequence = group[0]; + var invert:Matrix; + var firstPresent = null; + for (j = 0; j < length; j++) + { + info = origSeq.GetFrame(j + 1); + if (info && info.Present) + { + firstPresent = j + 1; + invert = info.Transform.clone(); + invert.invert(); + break; + } + } + var bounds:Rectangle = null; + var transforms:Array = []; + for (j = 0; j < group.length; j++) + { + p = group[j].GetPiece(); + p.RemoveUse(seq); + var m:Matrix = new Matrix(); + if (j > 0) + { + //m.translate(-group[j].CenterPoint.x, -group[j].CenterPoint.y); + m.concat(invert); + m.concat(group[j].GetFrame(firstPresent).Transform); + //m.translate(origSeq.CenterPoint.x, origSeq.CenterPoint.y); + } + var r:Rectangle = p.FullData.rect.clone(); + Utils.TransformRect(r, m); + + if (bounds == null) + { + bounds = r; + } else { + if (r.left < bounds.left) bounds.left = r.left; + if (r.right > bounds.right) bounds.right = r.right; + if (r.top < bounds.top) bounds.top = r.top; + if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; + } + transforms.push(m); + } + Utils.RoundRect(bounds); + var bd:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x0); + for (j = 0; j < group.length; j++) + { + transforms[j].translate(-bounds.left, -bounds.top); + bd.draw(group[j].GetPiece().FullData, transforms[j], null, null, null, true); + } + + p = library.GetPieceFromBitmapData(bd, "CombinedPiece"); + var seq:PieceSequence = new PieceSequence(p, seqLength); + p.AddUse(seq); + seq.CopyTransformsFrom(origSeq, group[group.length - 1].GetFrame(firstPresent).Depth); + + this.pieceSequences.push(seq); + + this.pieces.push(p); + } + } + + for (i in groups) + { + if (groups[i].length > 1) + { + for (j in groups[i]) + { + index = this.pieceSequences.indexOf(groups[i][j]); + if (index == -1) + { + throw new Error("huh?"); + } else { + pieceSequences.splice(index, 1); + } + } + } + } + + + for (i = 0; i < pieces.length; i++) + { + if (pieces[i].GetUses(seq) == 0) + { + pieces.splice(i, 1); + i--; + } + } + + } + + protected function SequenceMatches(a:PieceSequence, b:PieceSequence) + { + var relative:Matrix = null; + for (var i = 0; i < length; i++) + { + var infoA:PieceFrameInfo = a.GetFrame(i + 1); + var infoB:PieceFrameInfo = b.GetFrame(i + 1); + if (infoA && infoB && infoA.Present && infoB.Present) + { + var m:Matrix = Utils.GetTransform(infoA.Transform, infoB.Transform); + if (relative == null) + { + relative = m; + } else { + if (ComputeTransformScore(relative, 0, m, 0, 4, 15, 5, 0) > 4) return false; + } + } + } + return true; + } + + public function ProduceFrame(frame, excludeNames:Array = null):MovieClip + { + var i; + var depths:Array = []; + for (i = 0; i < pieceSequences.length; i++) + { + depths.push(pieceSequences[i].GetFrame(frame).Depth); + } + + var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + + var m:MovieClip = new MovieClip(); + for (i = 0; i < sorts.length; i++) + { + var ps:PieceSequence = pieceSequences[sorts[i]]; + var info:PieceFrameInfo = ps.GetFrame(frame); + if (info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) + { + var p:Piece = ps.GetPiece(); + var b:Bitmap = new Bitmap(p.FullData); + + var mat:Matrix = new Matrix(); + mat.translate(-p.CenterPoint.x, -p.CenterPoint.y); + mat.concat(info.Transform); + + //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); + + //b.smoothing = true; + b.transform.matrix = mat; + + m.addChild(b); + } + } + return m; + } + + public function ProduceFrameBitmapData(frame, excludeNames:Array = null) + { + var ps:PieceSequence; + var r:Rectangle = null; + var i; + var mat:Matrix; + for (i in pieceSequences) + { + ps = pieceSequences[i]; + var frameInfo:PieceFrameInfo = ps.GetFrame(frame); + if (frameInfo && frameInfo.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) + { + var piece:Piece = ps.GetPiece(); + var bounds:Rectangle = piece.FullData.rect; + bounds.x -= piece.CenterPoint.x; + bounds.y -= piece.CenterPoint.y; + mat = frameInfo.Transform.clone(); + //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); + Utils.TransformRect(bounds, mat); + + if (r == null) + { + r = bounds; + } else { + if (bounds.left < r.left) r.left = bounds.left; + if (bounds.top < r.top) r.top = bounds.top; + if (bounds.right > r.right) r.right = bounds.right; + if (bounds.bottom > r.bottom) r.bottom = bounds.bottom; + } + + } + } + + if (r == null) { + return {data:new BitmapData(1, 1, true, 0x0),center_point:new Point(0, 0)}; + } + + Utils.RoundRect(r); + var bd:BitmapData; + try { + bd = new BitmapData(Math.min(512, r.width), Math.min(512, r.height), true, 0x0); + } catch (e){ + //_strace("failed to create bitmap data"); + } + + var depths:Array = []; + for (i = 0; i < pieceSequences.length; i++) + { + depths.push(pieceSequences[i].GetFrame(frame).Depth); + } + + var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + + for (i = 0; i < sorts.length; i++) + { + ps = pieceSequences[sorts[i]]; + var info:PieceFrameInfo = ps.GetFrame(frame); + if (info && info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) + { + var p:Piece = ps.GetPiece(); + + mat = new Matrix(); + mat.translate(-ps.GetPiece().CenterPoint.x, -ps.GetPiece().CenterPoint.y); + mat.concat(info.Transform); + + //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); + + mat.translate(-r.left, -r.top); + + bd.draw(p.FullData, mat, null, null, null, true); + } + } + return {data:bd,center_point:new Point(-r.left, -r.top)}; + } } \ No newline at end of file diff --git a/AnimatedSkeletonGenerator.as b/AnimatedSkeletonGenerator.as index 20fec88..c4b6409 100644 --- a/AnimatedSkeletonGenerator.as +++ b/AnimatedSkeletonGenerator.as @@ -10,12 +10,13 @@ { private var src:MovieClip; private var def:GraphicExportDef; + public function get Def():GraphicExportDef { return def; } private var callback; - private var pieces:Array; - private var pieceSequences:Array; + private var sequences:Array; + private var frames:Array; public function GetFrames():Array { - return []; + return frames; } public function GetData() { @@ -28,16 +29,13 @@ } private var library:PieceLibrary - private var currentSeq:int; public function Go(callback) { + sequences = new Array(); library = new PieceLibrary(); - pieces = new Array(); - pieceSequences = new Array(); this.callback = callback; for (var i = 0; i < src.totalFrames; i++) { - currentSeq = i; Utils.WeirdGotoFrame(src, i + 1); Utils.RecursivelyStop(src); @@ -46,512 +44,24 @@ var c = src.getChildAt(j); if (c is MovieClip) { - GetAnimation(c, i); + var s:Sequence = new Sequence(this, library, i, c); + s.GetAnimation(); + sequences.push(s); break; } } } + frames = library.GetAllUsedPieces().map( + function(p:Piece, i, arr) + { + return p.Frame; + } + ); + callback(true); } - private var currentSeqLength:int; - private function GetAnimation(m:MovieClip, seq:int) - { - currentSeqLength = m.totalFrames; - for (var i = 0; i < m.totalFrames; i++) - { - Utils.WeirdGotoFrame(m, i + 1); - Utils.RecursivelyStop(m); - - RecursePieces(m, m, i + 1, 0, new Matrix()); - } - } - - protected function RecursePieces(base:MovieClip, graphic:MovieClip, frame, depth, parentMatrix:Matrix) - { - //_strace(depth+" "+graphic.name+" frame:"+frame); - - var mat:Matrix = graphic.transform.matrix.clone(); - mat.concat(parentMatrix); - - var currentPieces:Array = []; - - var allChildren:Array = Utils.GetChildren(graphic); - for (var i = 0; i < allChildren.length; i++) - { - if (!allChildren[i].visible) continue; - if (allChildren[i] is MovieClip) - { - if (IsFullPiece(base, graphic, allChildren[i])) - { - currentPieces.push(allChildren[i]); - } else { - depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); - currentPieces.splice(0); - - depth = RecursePieces(base, allChildren[i], frame, depth, mat.clone()); - } - } else { - currentPieces.push(allChildren[i]); - } - } - - depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); - return depth; - } - - protected function GeneratePieceForClips(clips:Array, depth, frame, parentMatrix:Matrix) - { - if (clips.length > 0) - { - var l = clips.length; - var bounds:Rectangle = null; - - var invertMatrix:Matrix = clips[0].transform.matrix.clone(); - invertMatrix.invert(); - var i; - var m:Matrix; - var useMatrix:Array = []; - for (i = 0; i < clips.length; i++) - { - if (i == 0) - { - m = new Matrix(); - } else { - m = clips[i].transform.matrix.clone(); - m.concat(invertMatrix); - } - - var r:Rectangle = Utils.GetAccurateBounds(clips[i]); - Utils.TransformRect(r, m); - if (bounds == null) - { - bounds = r.clone(); - } else { - if (r.left < bounds.left) bounds.left = r.left; - if (r.top < bounds.top) bounds.top = r.top; - if (r.right > bounds.right) bounds.right = r.right; - if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; - } - - useMatrix.push(m); - } - - Utils.ScaleRect(bounds, def.scale); - Utils.RoundRect(bounds); - var bd:BitmapData = new BitmapData(Math.max(1, bounds.width), Math.max(1,bounds.height), true, 0x0); - - for (i = 0; i < clips.length; i++) - { - m = useMatrix[i]; - m.scale(def.scale, def.scale); - m.translate(-bounds.left, -bounds.top); - var ct:ColorTransform = clips[i] is Shape ? clips[i].parent.transform.colorTransform : clips[i].transform.colorTransform; - bd.draw(clips[i], m, ct, null, null, true); - } - - var center:Point = new Point(-bounds.left, -bounds.top); - - var piece:Piece = library.GetPieceFromBitmapData(bd, clips[0].parent.name, center); - if (piece) - { - var mat:Matrix = new Matrix(1/def.scale, 0, 0, 1/def.scale, center.x - piece.CenterPoint.x, center.y - piece.CenterPoint.y); - mat.concat(clips[0].transform.matrix); - mat.concat(parentMatrix); - - //mat.a /= exporter.Upscale; - //mat.d /= exporter.Upscale; - - var pieceSequence:PieceSequence = GetPieceSequence(piece, frame, clips[0], mat, depth); - var info:PieceFrameInfo = pieceSequence.GetFrame(frame); - if (info) - { - info.Present = true; - - info.Transform = mat; - - - - info.Depth = depth; - depth++; - } - } - } - return depth; - } - - protected function GetPieceSequence(piece:Piece, frame, clip:DisplayObject, newTransform:Matrix, newDepth) - { - if (this.pieces.indexOf(piece) == -1) this.pieces.push(piece); - var options:Array = []; - var i; - for (i in pieceSequences) - { - if (pieceSequences[i].GetPiece() == piece) - { - var frameInfo:PieceFrameInfo = pieceSequences[i].GetFrame(frame); - if (frameInfo && !frameInfo.Present) - { - if (pieceSequences[i].CheckMatches(clip)) - { - return pieceSequences[i]; - } else { - options.push(pieceSequences[i]); - } - } - } - } - - if (options.length == 0) - { - var s:PieceSequence = new PieceSequence(piece, this.currentSeqLength); - piece.AddUse(currentSeq); - pieceSequences.push(s); - return s; - } - - var scores:Array = []; - for (i = 0; i < options.length; i++) - { - var score = 0; - if (frame > 1) - { - var prevInfo:PieceFrameInfo = options[i].GetFrame(frame - 1); - if (prevInfo && prevInfo.Present) - { - score = ComputeTransformScore(prevInfo.Transform, prevInfo.Depth, newTransform, newDepth); - } - } - scores.push(score); - } - var sorted:Array = scores.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - return options[sorted[0]]; - } - - protected function ComputeTransformScore(transformA:Matrix, depthA, transformB:Matrix, depthB, posVal = 1, scaleVal = 15, rotVal = 20, depthVal = 10) - { - var deltaPos = Point.distance(new Point(transformA.tx, transformA.ty), new Point(transformB.tx, transformB.ty)); - deltaPos /= def.scale; - - var partsA = Utils.Decompose(transformA); - var partsB = Utils.Decompose(transformB); - - var rotA = partsA.rot; - var rotB = partsB.rot; - var deltaRot = Utils.GetAngleDiffAbs(rotA, rotB); - - var deltaScaleX = partsA.sx / partsB.sx; - if (deltaScaleX < 1) deltaScaleX = 1 / deltaScaleX; - var deltaScaleY = partsA.sy / partsB.sy; - if (deltaScaleY < 1) deltaScaleY = 1 / deltaScaleY; - var deltaScale = Math.max(deltaScaleX, deltaScaleY); - - var deltaDepth = Math.abs(depthA - depthB); - - return deltaPos * posVal + (deltaScale - 1) * scaleVal + deltaRot * rotVal + deltaDepth * depthVal; - } - - public static var ONLYCOMBINEADJACENT = true; - - protected function CombinePieces() - { - var i, j, info:PieceFrameInfo, index; - var sequenceByPresent = {}; - for (i in pieceSequences) - { - var str = ""; - for (j = 0; j < length; j++) - { - info = pieceSequences[i].GetFrame(j + 1); - str += (info && info.Present) ? "1" : "0"; - } - if (!(str in sequenceByPresent)) - { - sequenceByPresent[str] = []; - } - sequenceByPresent[str].push(pieceSequences[i]); - } - - for (var presentStr in sequenceByPresent) - { - var all:Array = sequenceByPresent[presentStr]; - - var firstFrame = ("" + presentStr).indexOf("1") + 1; - - var depths:Array = []; - for (i = 0; i < all.length; i++) - { - depths.push(all[i].GetFrame(firstFrame).Depth); - } - var sorted:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - - var groups:Array = []; - var lastGroup:Array = null; - for (i = 0; i < all.length; i++) - { - index = sorted[i]; - if (ONLYCOMBINEADJACENT) - { - if (lastGroup != null && SequenceMatches(lastGroup[0], all[index])) - { - lastGroup.push(all[index]); - } else { - lastGroup = []; - groups.push(lastGroup); - lastGroup.push(all[index]); - } - } else { - var foundGroup = false; - for (j in groups) - { - if (SequenceMatches(groups[j][0], all[index])) - { - groups[j].push(all[index]); - foundGroup = true; - break; - } - } - if (!foundGroup) - { - var g:Array = []; - g.push(all[index]); - groups.push(g); - } - } - } - } - - var p:Piece; - for (i in groups) - { - // recovering the original pieces... - // for now: render the bitmaps? (one will be transformed... but it would be transformed anyways, right?) - var group:Array = groups[i]; - if (group.length > 1) - { - var origSeq:PieceSequence = group[0]; - var invert:Matrix; - var firstPresent = null; - for (j = 0; j < length; j++) - { - info = origSeq.GetFrame(j + 1); - if (info && info.Present) - { - firstPresent = j + 1; - invert = info.Transform.clone(); - invert.invert(); - break; - } - } - var bounds:Rectangle = null; - var transforms:Array = []; - for (j = 0; j < group.length; j++) - { - p = group[j].GetPiece(); - p.RemoveUse(currentSeq); - var m:Matrix = new Matrix(); - if (j > 0) - { - //m.translate(-group[j].CenterPoint.x, -group[j].CenterPoint.y); - m.concat(invert); - m.concat(group[j].GetFrame(firstPresent).Transform); - //m.translate(origSeq.CenterPoint.x, origSeq.CenterPoint.y); - } - var r:Rectangle = p.FullData.rect.clone(); - Utils.TransformRect(r, m); - - if (bounds == null) - { - bounds = r; - } else { - if (r.left < bounds.left) bounds.left = r.left; - if (r.right > bounds.right) bounds.right = r.right; - if (r.top < bounds.top) bounds.top = r.top; - if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; - } - transforms.push(m); - } - Utils.RoundRect(bounds); - var bd:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x0); - for (j = 0; j < group.length; j++) - { - transforms[j].translate(-bounds.left, -bounds.top); - bd.draw(group[j].GetPiece().FullData, transforms[j], null, null, null, true); - } - - p = library.GetPieceFromBitmapData(bd, "CombinedPiece"); - var seq:PieceSequence = new PieceSequence(p, currentSeqLength); - p.AddUse(currentSeq); - seq.CopyTransformsFrom(origSeq, group[group.length - 1].GetFrame(firstPresent).Depth); - - this.pieceSequences.push(seq); - - this.pieces.push(p); - } - } - - for (i in groups) - { - if (groups[i].length > 1) - { - for (j in groups[i]) - { - index = this.pieceSequences.indexOf(groups[i][j]); - if (index == -1) - { - throw new Error("huh?"); - } else { - pieceSequences.splice(index, 1); - } - } - } - } - - - for (i = 0; i < pieces.length; i++) - { - if (pieces[i].GetUses(currentSeq) == 0) - { - pieces.splice(i, 1); - i--; - } - } - - } - - protected function SequenceMatches(a:PieceSequence, b:PieceSequence) - { - var relative:Matrix = null; - for (var i = 0; i < length; i++) - { - var infoA:PieceFrameInfo = a.GetFrame(i + 1); - var infoB:PieceFrameInfo = b.GetFrame(i + 1); - if (infoA && infoB && infoA.Present && infoB.Present) - { - var m:Matrix = Utils.GetTransform(infoA.Transform, infoB.Transform); - if (relative == null) - { - relative = m; - } else { - if (ComputeTransformScore(relative, 0, m, 0, 4, 15, 5, 0) > 4) return false; - } - } - } - return true; - } - - public function ProduceFrame(frame, excludeNames:Array = null):MovieClip - { - var i; - var depths:Array = []; - for (i = 0; i < pieceSequences.length; i++) - { - depths.push(pieceSequences[i].GetFrame(frame).Depth); - } - - var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - - var m:MovieClip = new MovieClip(); - for (i = 0; i < sorts.length; i++) - { - var ps:PieceSequence = pieceSequences[sorts[i]]; - var info:PieceFrameInfo = ps.GetFrame(frame); - if (info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) - { - var p:Piece = ps.GetPiece(); - var b:Bitmap = new Bitmap(p.FullData); - - var mat:Matrix = new Matrix(); - mat.translate(-p.CenterPoint.x, -p.CenterPoint.y); - mat.concat(info.Transform); - - //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); - - //b.smoothing = true; - b.transform.matrix = mat; - - m.addChild(b); - } - } - return m; - } - - public function ProduceFrameBitmapData(frame, excludeNames:Array = null) - { - var ps:PieceSequence; - var r:Rectangle = null; - var i; - var mat:Matrix; - for (i in pieceSequences) - { - ps = pieceSequences[i]; - var frameInfo:PieceFrameInfo = ps.GetFrame(frame); - if (frameInfo && frameInfo.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) - { - var piece:Piece = ps.GetPiece(); - var bounds:Rectangle = piece.FullData.rect; - bounds.x -= piece.CenterPoint.x; - bounds.y -= piece.CenterPoint.y; - mat = frameInfo.Transform.clone(); - //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); - Utils.TransformRect(bounds, mat); - - if (r == null) - { - r = bounds; - } else { - if (bounds.left < r.left) r.left = bounds.left; - if (bounds.top < r.top) r.top = bounds.top; - if (bounds.right > r.right) r.right = bounds.right; - if (bounds.bottom > r.bottom) r.bottom = bounds.bottom; - } - - } - } - - if (r == null) { - return {data:new BitmapData(1, 1, true, 0x0),center_point:new Point(0, 0)}; - } - - Utils.RoundRect(r); - var bd:BitmapData; - try { - bd = new BitmapData(Math.min(512, r.width), Math.min(512, r.height), true, 0x0); - } catch (e){ - //_strace("failed to create bitmap data"); - } - - var depths:Array = []; - for (i = 0; i < pieceSequences.length; i++) - { - depths.push(pieceSequences[i].GetFrame(frame).Depth); - } - - var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - - for (i = 0; i < sorts.length; i++) - { - ps = pieceSequences[sorts[i]]; - var info:PieceFrameInfo = ps.GetFrame(frame); - if (info && info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) - { - var p:Piece = ps.GetPiece(); - - mat = new Matrix(); - mat.translate(-ps.GetPiece().CenterPoint.x, -ps.GetPiece().CenterPoint.y); - mat.concat(info.Transform); - - //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); - - mat.translate(-r.left, -r.top); - - bd.draw(p.FullData, mat, null, null, null, true); - } - } - return {data:bd,center_point:new Point(-r.left, -r.top)}; - } - public static function IsFullPiece(baseClip:DisplayObject, parentClip:MovieClip, clip:DisplayObject) { //if (HasAnyNamedChildren(clip)) return false; @@ -577,4 +87,522 @@ return true; } } +} + +class Sequence +{ + import flash.display.*; + import flash.geom.*; + + private var pieces:Array = new Array(); + private var pieceSequences:Array = new Array(); + private var src:MovieClip; + private var seq:int; + private var seqLength:int; + private var library:PieceLibrary; + private var generator:AnimatedSkeletonGenerator; + + public function Sequence(generator:AnimatedSkeletonGenerator, library:PieceLibrary, seq:int, src:MovieClip) + { + this.generator = generator; + this.library = library; + this.seq = seq; + this.seqLength = src.totalFrames; + this.src = src; + } + + public function GetAnimation() + { + for (var i = 0; i < seqLength; i++) + { + Utils.WeirdGotoFrame(src, i + 1); + Utils.RecursivelyStop(src); + + RecursePieces(src, i + 1, 0, new Matrix()); + } + } + + protected function RecursePieces(graphic:MovieClip, frame, depth, parentMatrix:Matrix) + { + //_strace(depth+" "+graphic.name+" frame:"+frame); + + var mat:Matrix = graphic.transform.matrix.clone(); + mat.concat(parentMatrix); + + var currentPieces:Array = []; + + var allChildren:Array = Utils.GetChildren(graphic); + for (var i = 0; i < allChildren.length; i++) + { + if (!allChildren[i].visible) continue; + if (allChildren[i] is MovieClip) + { + if (AnimatedSkeletonGenerator.IsFullPiece(src, graphic, allChildren[i])) + { + currentPieces.push(allChildren[i]); + } else { + depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); + currentPieces.splice(0); + + depth = RecursePieces(allChildren[i], frame, depth, mat.clone()); + } + } else { + currentPieces.push(allChildren[i]); + } + } + + depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); + return depth; + } + + protected function GeneratePieceForClips(clips:Array, depth, frame, parentMatrix:Matrix) + { + if (clips.length > 0) + { + var l = clips.length; + var bounds:Rectangle = null; + + var invertMatrix:Matrix = clips[0].transform.matrix.clone(); + invertMatrix.invert(); + var i; + var m:Matrix; + var useMatrix:Array = []; + for (i = 0; i < clips.length; i++) + { + if (i == 0) + { + m = new Matrix(); + } else { + m = clips[i].transform.matrix.clone(); + m.concat(invertMatrix); + } + + var r:Rectangle = Utils.GetAccurateBounds(clips[i]); + Utils.TransformRect(r, m); + if (bounds == null) + { + bounds = r.clone(); + } else { + if (r.left < bounds.left) bounds.left = r.left; + if (r.top < bounds.top) bounds.top = r.top; + if (r.right > bounds.right) bounds.right = r.right; + if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; + } + + useMatrix.push(m); + } + + Utils.ScaleRect(bounds, generator.Def.scale); + Utils.RoundRect(bounds); + var bd:BitmapData = new BitmapData(Math.max(1, bounds.width), Math.max(1,bounds.height), true, 0x0); + + for (i = 0; i < clips.length; i++) + { + m = useMatrix[i]; + m.scale(generator.Def.scale, generator.Def.scale); + m.translate(-bounds.left, -bounds.top); + var ct:ColorTransform = clips[i] is Shape ? clips[i].parent.transform.colorTransform : clips[i].transform.colorTransform; + bd.draw(clips[i], m, ct, null, null, true); + } + + var center:Point = new Point(-bounds.left, -bounds.top); + + var piece:Piece = library.GetPieceFromBitmapData(bd, clips[0].parent.name, center); + if (piece) + { + var mat:Matrix = new Matrix(1 / generator.Def.scale, 0, 0, 1 / generator.Def.scale, center.x - piece.CenterPoint.x, center.y - piece.CenterPoint.y); + mat.concat(clips[0].transform.matrix); + mat.concat(parentMatrix); + + //mat.a /= exporter.Upscale; + //mat.d /= exporter.Upscale; + + var pieceSequence:PieceSequence = GetPieceSequence(piece, frame, clips[0], mat, depth); + var info:PieceFrameInfo = pieceSequence.GetFrame(frame); + if (info) + { + info.Present = true; + + info.Transform = mat; + + + + info.Depth = depth; + depth++; + } + } + } + return depth; + } + + protected function GetPieceSequence(piece:Piece, frame, clip:DisplayObject, newTransform:Matrix, newDepth) + { + if (this.pieces.indexOf(piece) == -1) this.pieces.push(piece); + var options:Array = []; + var i; + for (i in pieceSequences) + { + if (pieceSequences[i].GetPiece() == piece) + { + var frameInfo:PieceFrameInfo = pieceSequences[i].GetFrame(frame); + if (frameInfo && !frameInfo.Present) + { + if (pieceSequences[i].CheckMatches(clip)) + { + return pieceSequences[i]; + } else { + options.push(pieceSequences[i]); + } + } + } + } + + if (options.length == 0) + { + var s:PieceSequence = new PieceSequence(piece, seqLength); + piece.AddUse(seq); + pieceSequences.push(s); + return s; + } + + var scores:Array = []; + for (i = 0; i < options.length; i++) + { + var score = 0; + if (frame > 1) + { + var prevInfo:PieceFrameInfo = options[i].GetFrame(frame - 1); + if (prevInfo && prevInfo.Present) + { + score = ComputeTransformScore(prevInfo.Transform, prevInfo.Depth, newTransform, newDepth); + } + } + scores.push(score); + } + var sorted:Array = scores.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + return options[sorted[0]]; + } + + protected function ComputeTransformScore(transformA:Matrix, depthA, transformB:Matrix, depthB, posVal = 1, scaleVal = 15, rotVal = 20, depthVal = 10) + { + var deltaPos = Point.distance(new Point(transformA.tx, transformA.ty), new Point(transformB.tx, transformB.ty)); + deltaPos /= generator.Def.scale; + + var partsA = Utils.Decompose(transformA); + var partsB = Utils.Decompose(transformB); + + var rotA = partsA.rot; + var rotB = partsB.rot; + var deltaRot = Utils.GetAngleDiffAbs(rotA, rotB); + + var deltaScaleX = partsA.sx / partsB.sx; + if (deltaScaleX < 1) deltaScaleX = 1 / deltaScaleX; + var deltaScaleY = partsA.sy / partsB.sy; + if (deltaScaleY < 1) deltaScaleY = 1 / deltaScaleY; + var deltaScale = Math.max(deltaScaleX, deltaScaleY); + + var deltaDepth = Math.abs(depthA - depthB); + + return deltaPos * posVal + (deltaScale - 1) * scaleVal + deltaRot * rotVal + deltaDepth * depthVal; + } + + public static var ONLYCOMBINEADJACENT = true; + + protected function CombinePieces() + { + var i, j, info:PieceFrameInfo, index; + var sequenceByPresent = {}; + for (i in pieceSequences) + { + var str = ""; + for (j = 0; j < length; j++) + { + info = pieceSequences[i].GetFrame(j + 1); + str += (info && info.Present) ? "1" : "0"; + } + if (!(str in sequenceByPresent)) + { + sequenceByPresent[str] = []; + } + sequenceByPresent[str].push(pieceSequences[i]); + } + + for (var presentStr in sequenceByPresent) + { + var all:Array = sequenceByPresent[presentStr]; + + var firstFrame = ("" + presentStr).indexOf("1") + 1; + + var depths:Array = []; + for (i = 0; i < all.length; i++) + { + depths.push(all[i].GetFrame(firstFrame).Depth); + } + var sorted:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + + var groups:Array = []; + var lastGroup:Array = null; + for (i = 0; i < all.length; i++) + { + index = sorted[i]; + if (ONLYCOMBINEADJACENT) + { + if (lastGroup != null && SequenceMatches(lastGroup[0], all[index])) + { + lastGroup.push(all[index]); + } else { + lastGroup = []; + groups.push(lastGroup); + lastGroup.push(all[index]); + } + } else { + var foundGroup = false; + for (j in groups) + { + if (SequenceMatches(groups[j][0], all[index])) + { + groups[j].push(all[index]); + foundGroup = true; + break; + } + } + if (!foundGroup) + { + var g:Array = []; + g.push(all[index]); + groups.push(g); + } + } + } + } + + var p:Piece; + for (i in groups) + { + // recovering the original pieces... + // for now: render the bitmaps? (one will be transformed... but it would be transformed anyways, right?) + var group:Array = groups[i]; + if (group.length > 1) + { + var origSeq:PieceSequence = group[0]; + var invert:Matrix; + var firstPresent = null; + for (j = 0; j < length; j++) + { + info = origSeq.GetFrame(j + 1); + if (info && info.Present) + { + firstPresent = j + 1; + invert = info.Transform.clone(); + invert.invert(); + break; + } + } + var bounds:Rectangle = null; + var transforms:Array = []; + for (j = 0; j < group.length; j++) + { + p = group[j].GetPiece(); + p.RemoveUse(seq); + var m:Matrix = new Matrix(); + if (j > 0) + { + //m.translate(-group[j].CenterPoint.x, -group[j].CenterPoint.y); + m.concat(invert); + m.concat(group[j].GetFrame(firstPresent).Transform); + //m.translate(origSeq.CenterPoint.x, origSeq.CenterPoint.y); + } + var r:Rectangle = p.FullData.rect.clone(); + Utils.TransformRect(r, m); + + if (bounds == null) + { + bounds = r; + } else { + if (r.left < bounds.left) bounds.left = r.left; + if (r.right > bounds.right) bounds.right = r.right; + if (r.top < bounds.top) bounds.top = r.top; + if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; + } + transforms.push(m); + } + Utils.RoundRect(bounds); + var bd:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x0); + for (j = 0; j < group.length; j++) + { + transforms[j].translate(-bounds.left, -bounds.top); + bd.draw(group[j].GetPiece().FullData, transforms[j], null, null, null, true); + } + + p = library.GetPieceFromBitmapData(bd, "CombinedPiece"); + var seq:PieceSequence = new PieceSequence(p, seqLength); + p.AddUse(seq); + seq.CopyTransformsFrom(origSeq, group[group.length - 1].GetFrame(firstPresent).Depth); + + this.pieceSequences.push(seq); + + this.pieces.push(p); + } + } + + for (i in groups) + { + if (groups[i].length > 1) + { + for (j in groups[i]) + { + index = this.pieceSequences.indexOf(groups[i][j]); + if (index == -1) + { + throw new Error("huh?"); + } else { + pieceSequences.splice(index, 1); + } + } + } + } + + + for (i = 0; i < pieces.length; i++) + { + if (pieces[i].GetUses(seq) == 0) + { + pieces.splice(i, 1); + i--; + } + } + + } + + protected function SequenceMatches(a:PieceSequence, b:PieceSequence) + { + var relative:Matrix = null; + for (var i = 0; i < length; i++) + { + var infoA:PieceFrameInfo = a.GetFrame(i + 1); + var infoB:PieceFrameInfo = b.GetFrame(i + 1); + if (infoA && infoB && infoA.Present && infoB.Present) + { + var m:Matrix = Utils.GetTransform(infoA.Transform, infoB.Transform); + if (relative == null) + { + relative = m; + } else { + if (ComputeTransformScore(relative, 0, m, 0, 4, 15, 5, 0) > 4) return false; + } + } + } + return true; + } + + public function ProduceFrame(frame, excludeNames:Array = null):MovieClip + { + var i; + var depths:Array = []; + for (i = 0; i < pieceSequences.length; i++) + { + depths.push(pieceSequences[i].GetFrame(frame).Depth); + } + + var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + + var m:MovieClip = new MovieClip(); + for (i = 0; i < sorts.length; i++) + { + var ps:PieceSequence = pieceSequences[sorts[i]]; + var info:PieceFrameInfo = ps.GetFrame(frame); + if (info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) + { + var p:Piece = ps.GetPiece(); + var b:Bitmap = new Bitmap(p.FullData); + + var mat:Matrix = new Matrix(); + mat.translate(-p.CenterPoint.x, -p.CenterPoint.y); + mat.concat(info.Transform); + + //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); + + //b.smoothing = true; + b.transform.matrix = mat; + + m.addChild(b); + } + } + return m; + } + + public function ProduceFrameBitmapData(frame, excludeNames:Array = null) + { + var ps:PieceSequence; + var r:Rectangle = null; + var i; + var mat:Matrix; + for (i in pieceSequences) + { + ps = pieceSequences[i]; + var frameInfo:PieceFrameInfo = ps.GetFrame(frame); + if (frameInfo && frameInfo.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) + { + var piece:Piece = ps.GetPiece(); + var bounds:Rectangle = piece.FullData.rect; + bounds.x -= piece.CenterPoint.x; + bounds.y -= piece.CenterPoint.y; + mat = frameInfo.Transform.clone(); + //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); + Utils.TransformRect(bounds, mat); + + if (r == null) + { + r = bounds; + } else { + if (bounds.left < r.left) r.left = bounds.left; + if (bounds.top < r.top) r.top = bounds.top; + if (bounds.right > r.right) r.right = bounds.right; + if (bounds.bottom > r.bottom) r.bottom = bounds.bottom; + } + + } + } + + if (r == null) { + return {data:new BitmapData(1, 1, true, 0x0),center_point:new Point(0, 0)}; + } + + Utils.RoundRect(r); + var bd:BitmapData; + try { + bd = new BitmapData(Math.min(512, r.width), Math.min(512, r.height), true, 0x0); + } catch (e){ + //_strace("failed to create bitmap data"); + } + + var depths:Array = []; + for (i = 0; i < pieceSequences.length; i++) + { + depths.push(pieceSequences[i].GetFrame(frame).Depth); + } + + var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + + for (i = 0; i < sorts.length; i++) + { + ps = pieceSequences[sorts[i]]; + var info:PieceFrameInfo = ps.GetFrame(frame); + if (info && info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) + { + var p:Piece = ps.GetPiece(); + + mat = new Matrix(); + mat.translate(-ps.GetPiece().CenterPoint.x, -ps.GetPiece().CenterPoint.y); + mat.concat(info.Transform); + + //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); + + mat.translate(-r.left, -r.top); + + bd.draw(p.FullData, mat, null, null, null, true); + } + } + return {data:bd,center_point:new Point(-r.left, -r.top)}; + } } \ No newline at end of file diff --git a/DebugExporter.swf b/DebugExporter.swf index aa11645..6ee2a87 100755 --- a/DebugExporter.swf +++ b/DebugExporter.swf Binary files differ diff --git a/AnimatedSkeletonGenerator.as b/AnimatedSkeletonGenerator.as index 20fec88..c4b6409 100644 --- a/AnimatedSkeletonGenerator.as +++ b/AnimatedSkeletonGenerator.as @@ -10,12 +10,13 @@ { private var src:MovieClip; private var def:GraphicExportDef; + public function get Def():GraphicExportDef { return def; } private var callback; - private var pieces:Array; - private var pieceSequences:Array; + private var sequences:Array; + private var frames:Array; public function GetFrames():Array { - return []; + return frames; } public function GetData() { @@ -28,16 +29,13 @@ } private var library:PieceLibrary - private var currentSeq:int; public function Go(callback) { + sequences = new Array(); library = new PieceLibrary(); - pieces = new Array(); - pieceSequences = new Array(); this.callback = callback; for (var i = 0; i < src.totalFrames; i++) { - currentSeq = i; Utils.WeirdGotoFrame(src, i + 1); Utils.RecursivelyStop(src); @@ -46,512 +44,24 @@ var c = src.getChildAt(j); if (c is MovieClip) { - GetAnimation(c, i); + var s:Sequence = new Sequence(this, library, i, c); + s.GetAnimation(); + sequences.push(s); break; } } } + frames = library.GetAllUsedPieces().map( + function(p:Piece, i, arr) + { + return p.Frame; + } + ); + callback(true); } - private var currentSeqLength:int; - private function GetAnimation(m:MovieClip, seq:int) - { - currentSeqLength = m.totalFrames; - for (var i = 0; i < m.totalFrames; i++) - { - Utils.WeirdGotoFrame(m, i + 1); - Utils.RecursivelyStop(m); - - RecursePieces(m, m, i + 1, 0, new Matrix()); - } - } - - protected function RecursePieces(base:MovieClip, graphic:MovieClip, frame, depth, parentMatrix:Matrix) - { - //_strace(depth+" "+graphic.name+" frame:"+frame); - - var mat:Matrix = graphic.transform.matrix.clone(); - mat.concat(parentMatrix); - - var currentPieces:Array = []; - - var allChildren:Array = Utils.GetChildren(graphic); - for (var i = 0; i < allChildren.length; i++) - { - if (!allChildren[i].visible) continue; - if (allChildren[i] is MovieClip) - { - if (IsFullPiece(base, graphic, allChildren[i])) - { - currentPieces.push(allChildren[i]); - } else { - depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); - currentPieces.splice(0); - - depth = RecursePieces(base, allChildren[i], frame, depth, mat.clone()); - } - } else { - currentPieces.push(allChildren[i]); - } - } - - depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); - return depth; - } - - protected function GeneratePieceForClips(clips:Array, depth, frame, parentMatrix:Matrix) - { - if (clips.length > 0) - { - var l = clips.length; - var bounds:Rectangle = null; - - var invertMatrix:Matrix = clips[0].transform.matrix.clone(); - invertMatrix.invert(); - var i; - var m:Matrix; - var useMatrix:Array = []; - for (i = 0; i < clips.length; i++) - { - if (i == 0) - { - m = new Matrix(); - } else { - m = clips[i].transform.matrix.clone(); - m.concat(invertMatrix); - } - - var r:Rectangle = Utils.GetAccurateBounds(clips[i]); - Utils.TransformRect(r, m); - if (bounds == null) - { - bounds = r.clone(); - } else { - if (r.left < bounds.left) bounds.left = r.left; - if (r.top < bounds.top) bounds.top = r.top; - if (r.right > bounds.right) bounds.right = r.right; - if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; - } - - useMatrix.push(m); - } - - Utils.ScaleRect(bounds, def.scale); - Utils.RoundRect(bounds); - var bd:BitmapData = new BitmapData(Math.max(1, bounds.width), Math.max(1,bounds.height), true, 0x0); - - for (i = 0; i < clips.length; i++) - { - m = useMatrix[i]; - m.scale(def.scale, def.scale); - m.translate(-bounds.left, -bounds.top); - var ct:ColorTransform = clips[i] is Shape ? clips[i].parent.transform.colorTransform : clips[i].transform.colorTransform; - bd.draw(clips[i], m, ct, null, null, true); - } - - var center:Point = new Point(-bounds.left, -bounds.top); - - var piece:Piece = library.GetPieceFromBitmapData(bd, clips[0].parent.name, center); - if (piece) - { - var mat:Matrix = new Matrix(1/def.scale, 0, 0, 1/def.scale, center.x - piece.CenterPoint.x, center.y - piece.CenterPoint.y); - mat.concat(clips[0].transform.matrix); - mat.concat(parentMatrix); - - //mat.a /= exporter.Upscale; - //mat.d /= exporter.Upscale; - - var pieceSequence:PieceSequence = GetPieceSequence(piece, frame, clips[0], mat, depth); - var info:PieceFrameInfo = pieceSequence.GetFrame(frame); - if (info) - { - info.Present = true; - - info.Transform = mat; - - - - info.Depth = depth; - depth++; - } - } - } - return depth; - } - - protected function GetPieceSequence(piece:Piece, frame, clip:DisplayObject, newTransform:Matrix, newDepth) - { - if (this.pieces.indexOf(piece) == -1) this.pieces.push(piece); - var options:Array = []; - var i; - for (i in pieceSequences) - { - if (pieceSequences[i].GetPiece() == piece) - { - var frameInfo:PieceFrameInfo = pieceSequences[i].GetFrame(frame); - if (frameInfo && !frameInfo.Present) - { - if (pieceSequences[i].CheckMatches(clip)) - { - return pieceSequences[i]; - } else { - options.push(pieceSequences[i]); - } - } - } - } - - if (options.length == 0) - { - var s:PieceSequence = new PieceSequence(piece, this.currentSeqLength); - piece.AddUse(currentSeq); - pieceSequences.push(s); - return s; - } - - var scores:Array = []; - for (i = 0; i < options.length; i++) - { - var score = 0; - if (frame > 1) - { - var prevInfo:PieceFrameInfo = options[i].GetFrame(frame - 1); - if (prevInfo && prevInfo.Present) - { - score = ComputeTransformScore(prevInfo.Transform, prevInfo.Depth, newTransform, newDepth); - } - } - scores.push(score); - } - var sorted:Array = scores.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - return options[sorted[0]]; - } - - protected function ComputeTransformScore(transformA:Matrix, depthA, transformB:Matrix, depthB, posVal = 1, scaleVal = 15, rotVal = 20, depthVal = 10) - { - var deltaPos = Point.distance(new Point(transformA.tx, transformA.ty), new Point(transformB.tx, transformB.ty)); - deltaPos /= def.scale; - - var partsA = Utils.Decompose(transformA); - var partsB = Utils.Decompose(transformB); - - var rotA = partsA.rot; - var rotB = partsB.rot; - var deltaRot = Utils.GetAngleDiffAbs(rotA, rotB); - - var deltaScaleX = partsA.sx / partsB.sx; - if (deltaScaleX < 1) deltaScaleX = 1 / deltaScaleX; - var deltaScaleY = partsA.sy / partsB.sy; - if (deltaScaleY < 1) deltaScaleY = 1 / deltaScaleY; - var deltaScale = Math.max(deltaScaleX, deltaScaleY); - - var deltaDepth = Math.abs(depthA - depthB); - - return deltaPos * posVal + (deltaScale - 1) * scaleVal + deltaRot * rotVal + deltaDepth * depthVal; - } - - public static var ONLYCOMBINEADJACENT = true; - - protected function CombinePieces() - { - var i, j, info:PieceFrameInfo, index; - var sequenceByPresent = {}; - for (i in pieceSequences) - { - var str = ""; - for (j = 0; j < length; j++) - { - info = pieceSequences[i].GetFrame(j + 1); - str += (info && info.Present) ? "1" : "0"; - } - if (!(str in sequenceByPresent)) - { - sequenceByPresent[str] = []; - } - sequenceByPresent[str].push(pieceSequences[i]); - } - - for (var presentStr in sequenceByPresent) - { - var all:Array = sequenceByPresent[presentStr]; - - var firstFrame = ("" + presentStr).indexOf("1") + 1; - - var depths:Array = []; - for (i = 0; i < all.length; i++) - { - depths.push(all[i].GetFrame(firstFrame).Depth); - } - var sorted:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - - var groups:Array = []; - var lastGroup:Array = null; - for (i = 0; i < all.length; i++) - { - index = sorted[i]; - if (ONLYCOMBINEADJACENT) - { - if (lastGroup != null && SequenceMatches(lastGroup[0], all[index])) - { - lastGroup.push(all[index]); - } else { - lastGroup = []; - groups.push(lastGroup); - lastGroup.push(all[index]); - } - } else { - var foundGroup = false; - for (j in groups) - { - if (SequenceMatches(groups[j][0], all[index])) - { - groups[j].push(all[index]); - foundGroup = true; - break; - } - } - if (!foundGroup) - { - var g:Array = []; - g.push(all[index]); - groups.push(g); - } - } - } - } - - var p:Piece; - for (i in groups) - { - // recovering the original pieces... - // for now: render the bitmaps? (one will be transformed... but it would be transformed anyways, right?) - var group:Array = groups[i]; - if (group.length > 1) - { - var origSeq:PieceSequence = group[0]; - var invert:Matrix; - var firstPresent = null; - for (j = 0; j < length; j++) - { - info = origSeq.GetFrame(j + 1); - if (info && info.Present) - { - firstPresent = j + 1; - invert = info.Transform.clone(); - invert.invert(); - break; - } - } - var bounds:Rectangle = null; - var transforms:Array = []; - for (j = 0; j < group.length; j++) - { - p = group[j].GetPiece(); - p.RemoveUse(currentSeq); - var m:Matrix = new Matrix(); - if (j > 0) - { - //m.translate(-group[j].CenterPoint.x, -group[j].CenterPoint.y); - m.concat(invert); - m.concat(group[j].GetFrame(firstPresent).Transform); - //m.translate(origSeq.CenterPoint.x, origSeq.CenterPoint.y); - } - var r:Rectangle = p.FullData.rect.clone(); - Utils.TransformRect(r, m); - - if (bounds == null) - { - bounds = r; - } else { - if (r.left < bounds.left) bounds.left = r.left; - if (r.right > bounds.right) bounds.right = r.right; - if (r.top < bounds.top) bounds.top = r.top; - if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; - } - transforms.push(m); - } - Utils.RoundRect(bounds); - var bd:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x0); - for (j = 0; j < group.length; j++) - { - transforms[j].translate(-bounds.left, -bounds.top); - bd.draw(group[j].GetPiece().FullData, transforms[j], null, null, null, true); - } - - p = library.GetPieceFromBitmapData(bd, "CombinedPiece"); - var seq:PieceSequence = new PieceSequence(p, currentSeqLength); - p.AddUse(currentSeq); - seq.CopyTransformsFrom(origSeq, group[group.length - 1].GetFrame(firstPresent).Depth); - - this.pieceSequences.push(seq); - - this.pieces.push(p); - } - } - - for (i in groups) - { - if (groups[i].length > 1) - { - for (j in groups[i]) - { - index = this.pieceSequences.indexOf(groups[i][j]); - if (index == -1) - { - throw new Error("huh?"); - } else { - pieceSequences.splice(index, 1); - } - } - } - } - - - for (i = 0; i < pieces.length; i++) - { - if (pieces[i].GetUses(currentSeq) == 0) - { - pieces.splice(i, 1); - i--; - } - } - - } - - protected function SequenceMatches(a:PieceSequence, b:PieceSequence) - { - var relative:Matrix = null; - for (var i = 0; i < length; i++) - { - var infoA:PieceFrameInfo = a.GetFrame(i + 1); - var infoB:PieceFrameInfo = b.GetFrame(i + 1); - if (infoA && infoB && infoA.Present && infoB.Present) - { - var m:Matrix = Utils.GetTransform(infoA.Transform, infoB.Transform); - if (relative == null) - { - relative = m; - } else { - if (ComputeTransformScore(relative, 0, m, 0, 4, 15, 5, 0) > 4) return false; - } - } - } - return true; - } - - public function ProduceFrame(frame, excludeNames:Array = null):MovieClip - { - var i; - var depths:Array = []; - for (i = 0; i < pieceSequences.length; i++) - { - depths.push(pieceSequences[i].GetFrame(frame).Depth); - } - - var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - - var m:MovieClip = new MovieClip(); - for (i = 0; i < sorts.length; i++) - { - var ps:PieceSequence = pieceSequences[sorts[i]]; - var info:PieceFrameInfo = ps.GetFrame(frame); - if (info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) - { - var p:Piece = ps.GetPiece(); - var b:Bitmap = new Bitmap(p.FullData); - - var mat:Matrix = new Matrix(); - mat.translate(-p.CenterPoint.x, -p.CenterPoint.y); - mat.concat(info.Transform); - - //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); - - //b.smoothing = true; - b.transform.matrix = mat; - - m.addChild(b); - } - } - return m; - } - - public function ProduceFrameBitmapData(frame, excludeNames:Array = null) - { - var ps:PieceSequence; - var r:Rectangle = null; - var i; - var mat:Matrix; - for (i in pieceSequences) - { - ps = pieceSequences[i]; - var frameInfo:PieceFrameInfo = ps.GetFrame(frame); - if (frameInfo && frameInfo.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) - { - var piece:Piece = ps.GetPiece(); - var bounds:Rectangle = piece.FullData.rect; - bounds.x -= piece.CenterPoint.x; - bounds.y -= piece.CenterPoint.y; - mat = frameInfo.Transform.clone(); - //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); - Utils.TransformRect(bounds, mat); - - if (r == null) - { - r = bounds; - } else { - if (bounds.left < r.left) r.left = bounds.left; - if (bounds.top < r.top) r.top = bounds.top; - if (bounds.right > r.right) r.right = bounds.right; - if (bounds.bottom > r.bottom) r.bottom = bounds.bottom; - } - - } - } - - if (r == null) { - return {data:new BitmapData(1, 1, true, 0x0),center_point:new Point(0, 0)}; - } - - Utils.RoundRect(r); - var bd:BitmapData; - try { - bd = new BitmapData(Math.min(512, r.width), Math.min(512, r.height), true, 0x0); - } catch (e){ - //_strace("failed to create bitmap data"); - } - - var depths:Array = []; - for (i = 0; i < pieceSequences.length; i++) - { - depths.push(pieceSequences[i].GetFrame(frame).Depth); - } - - var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); - - for (i = 0; i < sorts.length; i++) - { - ps = pieceSequences[sorts[i]]; - var info:PieceFrameInfo = ps.GetFrame(frame); - if (info && info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) - { - var p:Piece = ps.GetPiece(); - - mat = new Matrix(); - mat.translate(-ps.GetPiece().CenterPoint.x, -ps.GetPiece().CenterPoint.y); - mat.concat(info.Transform); - - //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); - - mat.translate(-r.left, -r.top); - - bd.draw(p.FullData, mat, null, null, null, true); - } - } - return {data:bd,center_point:new Point(-r.left, -r.top)}; - } - public static function IsFullPiece(baseClip:DisplayObject, parentClip:MovieClip, clip:DisplayObject) { //if (HasAnyNamedChildren(clip)) return false; @@ -577,4 +87,522 @@ return true; } } +} + +class Sequence +{ + import flash.display.*; + import flash.geom.*; + + private var pieces:Array = new Array(); + private var pieceSequences:Array = new Array(); + private var src:MovieClip; + private var seq:int; + private var seqLength:int; + private var library:PieceLibrary; + private var generator:AnimatedSkeletonGenerator; + + public function Sequence(generator:AnimatedSkeletonGenerator, library:PieceLibrary, seq:int, src:MovieClip) + { + this.generator = generator; + this.library = library; + this.seq = seq; + this.seqLength = src.totalFrames; + this.src = src; + } + + public function GetAnimation() + { + for (var i = 0; i < seqLength; i++) + { + Utils.WeirdGotoFrame(src, i + 1); + Utils.RecursivelyStop(src); + + RecursePieces(src, i + 1, 0, new Matrix()); + } + } + + protected function RecursePieces(graphic:MovieClip, frame, depth, parentMatrix:Matrix) + { + //_strace(depth+" "+graphic.name+" frame:"+frame); + + var mat:Matrix = graphic.transform.matrix.clone(); + mat.concat(parentMatrix); + + var currentPieces:Array = []; + + var allChildren:Array = Utils.GetChildren(graphic); + for (var i = 0; i < allChildren.length; i++) + { + if (!allChildren[i].visible) continue; + if (allChildren[i] is MovieClip) + { + if (AnimatedSkeletonGenerator.IsFullPiece(src, graphic, allChildren[i])) + { + currentPieces.push(allChildren[i]); + } else { + depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); + currentPieces.splice(0); + + depth = RecursePieces(allChildren[i], frame, depth, mat.clone()); + } + } else { + currentPieces.push(allChildren[i]); + } + } + + depth = GeneratePieceForClips(currentPieces, depth, frame, mat.clone()); + return depth; + } + + protected function GeneratePieceForClips(clips:Array, depth, frame, parentMatrix:Matrix) + { + if (clips.length > 0) + { + var l = clips.length; + var bounds:Rectangle = null; + + var invertMatrix:Matrix = clips[0].transform.matrix.clone(); + invertMatrix.invert(); + var i; + var m:Matrix; + var useMatrix:Array = []; + for (i = 0; i < clips.length; i++) + { + if (i == 0) + { + m = new Matrix(); + } else { + m = clips[i].transform.matrix.clone(); + m.concat(invertMatrix); + } + + var r:Rectangle = Utils.GetAccurateBounds(clips[i]); + Utils.TransformRect(r, m); + if (bounds == null) + { + bounds = r.clone(); + } else { + if (r.left < bounds.left) bounds.left = r.left; + if (r.top < bounds.top) bounds.top = r.top; + if (r.right > bounds.right) bounds.right = r.right; + if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; + } + + useMatrix.push(m); + } + + Utils.ScaleRect(bounds, generator.Def.scale); + Utils.RoundRect(bounds); + var bd:BitmapData = new BitmapData(Math.max(1, bounds.width), Math.max(1,bounds.height), true, 0x0); + + for (i = 0; i < clips.length; i++) + { + m = useMatrix[i]; + m.scale(generator.Def.scale, generator.Def.scale); + m.translate(-bounds.left, -bounds.top); + var ct:ColorTransform = clips[i] is Shape ? clips[i].parent.transform.colorTransform : clips[i].transform.colorTransform; + bd.draw(clips[i], m, ct, null, null, true); + } + + var center:Point = new Point(-bounds.left, -bounds.top); + + var piece:Piece = library.GetPieceFromBitmapData(bd, clips[0].parent.name, center); + if (piece) + { + var mat:Matrix = new Matrix(1 / generator.Def.scale, 0, 0, 1 / generator.Def.scale, center.x - piece.CenterPoint.x, center.y - piece.CenterPoint.y); + mat.concat(clips[0].transform.matrix); + mat.concat(parentMatrix); + + //mat.a /= exporter.Upscale; + //mat.d /= exporter.Upscale; + + var pieceSequence:PieceSequence = GetPieceSequence(piece, frame, clips[0], mat, depth); + var info:PieceFrameInfo = pieceSequence.GetFrame(frame); + if (info) + { + info.Present = true; + + info.Transform = mat; + + + + info.Depth = depth; + depth++; + } + } + } + return depth; + } + + protected function GetPieceSequence(piece:Piece, frame, clip:DisplayObject, newTransform:Matrix, newDepth) + { + if (this.pieces.indexOf(piece) == -1) this.pieces.push(piece); + var options:Array = []; + var i; + for (i in pieceSequences) + { + if (pieceSequences[i].GetPiece() == piece) + { + var frameInfo:PieceFrameInfo = pieceSequences[i].GetFrame(frame); + if (frameInfo && !frameInfo.Present) + { + if (pieceSequences[i].CheckMatches(clip)) + { + return pieceSequences[i]; + } else { + options.push(pieceSequences[i]); + } + } + } + } + + if (options.length == 0) + { + var s:PieceSequence = new PieceSequence(piece, seqLength); + piece.AddUse(seq); + pieceSequences.push(s); + return s; + } + + var scores:Array = []; + for (i = 0; i < options.length; i++) + { + var score = 0; + if (frame > 1) + { + var prevInfo:PieceFrameInfo = options[i].GetFrame(frame - 1); + if (prevInfo && prevInfo.Present) + { + score = ComputeTransformScore(prevInfo.Transform, prevInfo.Depth, newTransform, newDepth); + } + } + scores.push(score); + } + var sorted:Array = scores.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + return options[sorted[0]]; + } + + protected function ComputeTransformScore(transformA:Matrix, depthA, transformB:Matrix, depthB, posVal = 1, scaleVal = 15, rotVal = 20, depthVal = 10) + { + var deltaPos = Point.distance(new Point(transformA.tx, transformA.ty), new Point(transformB.tx, transformB.ty)); + deltaPos /= generator.Def.scale; + + var partsA = Utils.Decompose(transformA); + var partsB = Utils.Decompose(transformB); + + var rotA = partsA.rot; + var rotB = partsB.rot; + var deltaRot = Utils.GetAngleDiffAbs(rotA, rotB); + + var deltaScaleX = partsA.sx / partsB.sx; + if (deltaScaleX < 1) deltaScaleX = 1 / deltaScaleX; + var deltaScaleY = partsA.sy / partsB.sy; + if (deltaScaleY < 1) deltaScaleY = 1 / deltaScaleY; + var deltaScale = Math.max(deltaScaleX, deltaScaleY); + + var deltaDepth = Math.abs(depthA - depthB); + + return deltaPos * posVal + (deltaScale - 1) * scaleVal + deltaRot * rotVal + deltaDepth * depthVal; + } + + public static var ONLYCOMBINEADJACENT = true; + + protected function CombinePieces() + { + var i, j, info:PieceFrameInfo, index; + var sequenceByPresent = {}; + for (i in pieceSequences) + { + var str = ""; + for (j = 0; j < length; j++) + { + info = pieceSequences[i].GetFrame(j + 1); + str += (info && info.Present) ? "1" : "0"; + } + if (!(str in sequenceByPresent)) + { + sequenceByPresent[str] = []; + } + sequenceByPresent[str].push(pieceSequences[i]); + } + + for (var presentStr in sequenceByPresent) + { + var all:Array = sequenceByPresent[presentStr]; + + var firstFrame = ("" + presentStr).indexOf("1") + 1; + + var depths:Array = []; + for (i = 0; i < all.length; i++) + { + depths.push(all[i].GetFrame(firstFrame).Depth); + } + var sorted:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + + var groups:Array = []; + var lastGroup:Array = null; + for (i = 0; i < all.length; i++) + { + index = sorted[i]; + if (ONLYCOMBINEADJACENT) + { + if (lastGroup != null && SequenceMatches(lastGroup[0], all[index])) + { + lastGroup.push(all[index]); + } else { + lastGroup = []; + groups.push(lastGroup); + lastGroup.push(all[index]); + } + } else { + var foundGroup = false; + for (j in groups) + { + if (SequenceMatches(groups[j][0], all[index])) + { + groups[j].push(all[index]); + foundGroup = true; + break; + } + } + if (!foundGroup) + { + var g:Array = []; + g.push(all[index]); + groups.push(g); + } + } + } + } + + var p:Piece; + for (i in groups) + { + // recovering the original pieces... + // for now: render the bitmaps? (one will be transformed... but it would be transformed anyways, right?) + var group:Array = groups[i]; + if (group.length > 1) + { + var origSeq:PieceSequence = group[0]; + var invert:Matrix; + var firstPresent = null; + for (j = 0; j < length; j++) + { + info = origSeq.GetFrame(j + 1); + if (info && info.Present) + { + firstPresent = j + 1; + invert = info.Transform.clone(); + invert.invert(); + break; + } + } + var bounds:Rectangle = null; + var transforms:Array = []; + for (j = 0; j < group.length; j++) + { + p = group[j].GetPiece(); + p.RemoveUse(seq); + var m:Matrix = new Matrix(); + if (j > 0) + { + //m.translate(-group[j].CenterPoint.x, -group[j].CenterPoint.y); + m.concat(invert); + m.concat(group[j].GetFrame(firstPresent).Transform); + //m.translate(origSeq.CenterPoint.x, origSeq.CenterPoint.y); + } + var r:Rectangle = p.FullData.rect.clone(); + Utils.TransformRect(r, m); + + if (bounds == null) + { + bounds = r; + } else { + if (r.left < bounds.left) bounds.left = r.left; + if (r.right > bounds.right) bounds.right = r.right; + if (r.top < bounds.top) bounds.top = r.top; + if (r.bottom > bounds.bottom) bounds.bottom = r.bottom; + } + transforms.push(m); + } + Utils.RoundRect(bounds); + var bd:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x0); + for (j = 0; j < group.length; j++) + { + transforms[j].translate(-bounds.left, -bounds.top); + bd.draw(group[j].GetPiece().FullData, transforms[j], null, null, null, true); + } + + p = library.GetPieceFromBitmapData(bd, "CombinedPiece"); + var seq:PieceSequence = new PieceSequence(p, seqLength); + p.AddUse(seq); + seq.CopyTransformsFrom(origSeq, group[group.length - 1].GetFrame(firstPresent).Depth); + + this.pieceSequences.push(seq); + + this.pieces.push(p); + } + } + + for (i in groups) + { + if (groups[i].length > 1) + { + for (j in groups[i]) + { + index = this.pieceSequences.indexOf(groups[i][j]); + if (index == -1) + { + throw new Error("huh?"); + } else { + pieceSequences.splice(index, 1); + } + } + } + } + + + for (i = 0; i < pieces.length; i++) + { + if (pieces[i].GetUses(seq) == 0) + { + pieces.splice(i, 1); + i--; + } + } + + } + + protected function SequenceMatches(a:PieceSequence, b:PieceSequence) + { + var relative:Matrix = null; + for (var i = 0; i < length; i++) + { + var infoA:PieceFrameInfo = a.GetFrame(i + 1); + var infoB:PieceFrameInfo = b.GetFrame(i + 1); + if (infoA && infoB && infoA.Present && infoB.Present) + { + var m:Matrix = Utils.GetTransform(infoA.Transform, infoB.Transform); + if (relative == null) + { + relative = m; + } else { + if (ComputeTransformScore(relative, 0, m, 0, 4, 15, 5, 0) > 4) return false; + } + } + } + return true; + } + + public function ProduceFrame(frame, excludeNames:Array = null):MovieClip + { + var i; + var depths:Array = []; + for (i = 0; i < pieceSequences.length; i++) + { + depths.push(pieceSequences[i].GetFrame(frame).Depth); + } + + var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + + var m:MovieClip = new MovieClip(); + for (i = 0; i < sorts.length; i++) + { + var ps:PieceSequence = pieceSequences[sorts[i]]; + var info:PieceFrameInfo = ps.GetFrame(frame); + if (info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) + { + var p:Piece = ps.GetPiece(); + var b:Bitmap = new Bitmap(p.FullData); + + var mat:Matrix = new Matrix(); + mat.translate(-p.CenterPoint.x, -p.CenterPoint.y); + mat.concat(info.Transform); + + //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); + + //b.smoothing = true; + b.transform.matrix = mat; + + m.addChild(b); + } + } + return m; + } + + public function ProduceFrameBitmapData(frame, excludeNames:Array = null) + { + var ps:PieceSequence; + var r:Rectangle = null; + var i; + var mat:Matrix; + for (i in pieceSequences) + { + ps = pieceSequences[i]; + var frameInfo:PieceFrameInfo = ps.GetFrame(frame); + if (frameInfo && frameInfo.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) + { + var piece:Piece = ps.GetPiece(); + var bounds:Rectangle = piece.FullData.rect; + bounds.x -= piece.CenterPoint.x; + bounds.y -= piece.CenterPoint.y; + mat = frameInfo.Transform.clone(); + //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); + Utils.TransformRect(bounds, mat); + + if (r == null) + { + r = bounds; + } else { + if (bounds.left < r.left) r.left = bounds.left; + if (bounds.top < r.top) r.top = bounds.top; + if (bounds.right > r.right) r.right = bounds.right; + if (bounds.bottom > r.bottom) r.bottom = bounds.bottom; + } + + } + } + + if (r == null) { + return {data:new BitmapData(1, 1, true, 0x0),center_point:new Point(0, 0)}; + } + + Utils.RoundRect(r); + var bd:BitmapData; + try { + bd = new BitmapData(Math.min(512, r.width), Math.min(512, r.height), true, 0x0); + } catch (e){ + //_strace("failed to create bitmap data"); + } + + var depths:Array = []; + for (i = 0; i < pieceSequences.length; i++) + { + depths.push(pieceSequences[i].GetFrame(frame).Depth); + } + + var sorts:Array = depths.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY); + + for (i = 0; i < sorts.length; i++) + { + ps = pieceSequences[sorts[i]]; + var info:PieceFrameInfo = ps.GetFrame(frame); + if (info && info.Present && (excludeNames == null || excludeNames.indexOf(ps.GetPiece().Name) == -1)) + { + var p:Piece = ps.GetPiece(); + + mat = new Matrix(); + mat.translate(-ps.GetPiece().CenterPoint.x, -ps.GetPiece().CenterPoint.y); + mat.concat(info.Transform); + + //mat.scale(1 / exporter.Upscale, 1 / exporter.Upscale); + + mat.translate(-r.left, -r.top); + + bd.draw(p.FullData, mat, null, null, null, true); + } + } + return {data:bd,center_point:new Point(-r.left, -r.top)}; + } } \ No newline at end of file diff --git a/DebugExporter.swf b/DebugExporter.swf index aa11645..6ee2a87 100755 --- a/DebugExporter.swf +++ b/DebugExporter.swf Binary files differ diff --git a/Piece.as b/Piece.as index dc07fd2..aea2f74 100644 --- a/Piece.as +++ b/Piece.as @@ -6,13 +6,15 @@ public class Piece { protected var size:Point; - protected var fullData:BitmapData; + protected var frame:FrameInfo; protected var compareData:BitmapData; protected var centerPoint:Point; public function get CenterPoint():Point { return centerPoint; } - public function get FullData():BitmapData { return fullData; } + public function get FullData():BitmapData { return frame == null ? null : frame.frame; } + + public function get Frame():FrameInfo { return frame; } protected var valid = false; public function get Valid() { return valid; } @@ -70,9 +72,11 @@ m.translate(-bounds.left, -bounds.top); - fullData = new BitmapData(bounds.width, bounds.height, true, 0x0); + var fullData:BitmapData = new BitmapData(bounds.width, bounds.height, true, 0x0); fullData.draw(clip, m, clip is Shape && clip.parent ? clip.parent.transform.colorTransform : clip.transform.colorTransform, null, null, true); + frame = new FrameInfo(fullData, m, null); + compareData = GenerateCompareData(clip); centerPoint = new Point(-bounds.left, -bounds.top); @@ -87,7 +91,7 @@ valid = true; size = new Point(bd.width, bd.height); - fullData = bd; + frame = new FrameInfo(bd, null, null); compareData = bd.clone();