package GraphicExport { import Defs.GraphicDef; import flash.display.MovieClip; import djarts.utils.*; import djarts.display.GraphicFactory; import CharacterExport.*; import flash.utils.ByteArray; import Packer.SpriteSheet; import flash.utils.Endian; import Packer.GraphicPacker; import Packer.AsyncGraphicPacker; import flash.net.FileReference; import flash.display.Bitmap; import com.adobe.serialization.json.JSON; import flash.geom.Matrix; public class ScenePacker { protected var doneCallback; protected var callbackParam; protected var holder:MovieClip; protected var sheets:Array = new Array(); protected var output:ByteArray = new ByteArray(); public function ScenePacker(callback, callbackParam, holder:MovieClip, outputFormat = "binary") { this.doneCallback = callback; this.callbackParam = callbackParam; this.holder = holder; this.outputFormat = outputFormat; graphicPacker.outputFormat = outputFormat; } var currentDef:GraphicDef = null; public function ExportDef(def:GraphicDef) { this.currentDef = def; graphicPacker.outputAssetName = def.Name+"_graphics"; var graphic = GraphicFactory.Instance().GetGraphicByID(def.ID, null, SceneGraphicLoaded); if (GraphicFactory.Instance().LoadedOK(graphic)) SceneGraphicLoaded(null, graphic); } var clipData:Array; protected function SceneGraphicLoaded(c, g:MovieClip) { // read out the clips and transform data for the items on the graphic. clipData = new Array(); //Need to find any drawing objects that are not movie clips and give them thier own clip so they process correctly. var gSymbols:MovieClip = new MovieClip(); var symbolsToMove = new Array(); for (var i = 0; i < g.numChildren; i++) { var child = g.getChildAt(i) as MovieClip; if (child is MovieClip) symbolsToMove.push(child); } for (var i = 0; i < symbolsToMove.length; i++) gSymbols.addChild(symbolsToMove[i]); //if there are still drawing objects that were not movie clips add them as the background. if (g.width > 0) gSymbols.addChildAt(g, 0); //This reorganized clip is now the clip to export. g = gSymbols; //Chunk Large Children... This breaks up clips that are large than 1024 into smaller pieces. //This helps with large backgrounds and doesn't require 2048x2048 textures which end up wasting a lot of space. for (var i = 0; i < g.numChildren; i++) { var child = g.getChildAt(i) as MovieClip; if (child is MovieClip && (child.width > 1024 || child.height > 1024)) { var chunkedChild = new ChunkedGraphic(child, 500); _strace("Chunked child graphic, added "+chunkedChild.numChildren+" chunks!"); g.removeChildAt(i); var chunkID = 0; var toAdd = chunkedChild.numChildren; while(chunkedChild.numChildren > 0) { var chunkedChildChunk = chunkedChild.getChildAt(0); chunkedChildChunk.name = child.name +"_chunk"+chunkID++; var m1:Matrix = chunkedChildChunk.transform.matrix.clone(); //var m2:Matrix = child.transform.matrix.clone(); m1.concat(child.transform.matrix); //m2.concat(chunkedChildChunk.transform.matrix); chunkedChildChunk.transform.matrix = m1; /* // since the scale information is removed (by exporting the sprite sheet at scale) // we only need the corrected x/y components here chunkedChildChunk.x = m1.tx; chunkedChildChunk.y = m1.ty; */ //chunkedChildChunk.x += chunkedChild.x; //chunkedChildChunk.y += chunkedChild.y; g.addChildAt(chunkedChildChunk, i); } i += Math.max(0, toAdd - 1); } } for (var i = 0; i < g.numChildren; i++) { if (g.getChildAt(i) is MovieClip) { var child:MovieClip = g.getChildAt(i) as MovieClip; var frameCount = GetLongestSequenceLength(child); var type = GraphicDef.EXPORT_FORMAT_SPRITESHEET; if (frameCount > 1) { type = GraphicDef.EXPORT_FORMAT_SKELANIM; } var name = child.name; var transformData = CharacterExporter.Decompose(child.transform.matrix); //var childData = {"clip":child, "index":i, "type":type, "name":name, "x":child.x, "y": child.y, "scaleX":transformData.sx, "scaleY":transformData.sy, "rotation":transformData.rot}; var childData = {"clip":child, "index":i, "type":type, "name":name, "x":child.x, "y": child.y, "scaleX":1, "scaleY":1, "rotation":transformData.rot}; clipData.push(childData); var str = ""; for(var key in childData) { str += key + " => " + childData[key] + " "; } _strace(str); } } ExportNext(); } var clipIndex:int = 0; protected function ExportNext() { if (clipIndex < clipData.length) { var data = clipData[clipIndex++]; switch(data.type) { case GraphicDef.EXPORT_FORMAT_SKELANIM : AddSkeletalClip(data.clip, Math.max(data.scaleX, data.scaleY) ); break; case GraphicDef.EXPORT_FORMAT_SPRITESHEET : AddGraphicClip(data.clip); break; } } else { ProcessGraphicExporter(); } } protected function ProcessGraphicExporter() { //actually does the writing to sprite sheets and creating the output bytes. graphicPacker.ExportClips(graphicExporterClipList, ProcessGraphicExporterDone); this.holder.AddClip(new Bitmap(graphicPacker.GetSheets()[0].GetBitmap() ) ); } protected function ProcessGraphicExporterDone(output) { Done(); } protected var skelExporters:Array = new Array(); var library:PieceLibrary = new PieceLibrary(); protected function AddSkeletalClip(clip:MovieClip, upscale:Number) { var characterExporterPreviewClip = new MovieClip(); this.holder.AddClip(characterExporterPreviewClip); var exporter:CharacterExporter = new CharacterExporter(characterExporterPreviewClip); skelExporters.push(exporter); exporter.Upscale = upscale; exporter.GraphicName = clip.name; exporter.ProcessFromClip(clip, ExportNext, library); } var graphicExporterClipList:Array = new Array(); protected var graphicPacker:AsyncGraphicPacker = new AsyncGraphicPacker(); protected function AddGraphicClip(clip:MovieClip) { graphicExporterClipList.push(clip); ExportNext(); } protected function GetLongestSequenceLength(clip:MovieClip, count:int = 1):int { if (clip.totalFrames > count) count = clip.totalFrames; for (var i = 0; i < clip.numChildren; i++) { if (clip.getChildAt(i) is MovieClip) { count = GetLongestSequenceLength(clip.getChildAt(i) as MovieClip, count); } } return count; } var outputFormat = "binary"; protected function Done() { this.library.EnsureAllUsedPiecesHaveNames(); var exporter:ExportBuilder = new ExportBuilder(skelExporters, -1, -1, library); if (outputFormat == "json_png_set") { var fileExportSet = new FileExportSet(); var skelPNGSet = exporter.GetJSONPNGSet(); var graphicPNGSet = graphicPacker.GetJSONPNGSet(); skelPNGSet.AssetName = this.currentDef.Name+"_skel"; graphicPNGSet.AssetName = this.currentDef.Name+"_graphics"; //graphicPNGSet.JSONData.meta.image = this.currentDef.Name+"_graphics.png"; var jsonOutput = {}; jsonOutput.name = currentDef.Name; jsonOutput.format = "scene"; if (skelPNGSet.PNGSheets.length > 0) jsonOutput.skeletal_asset = this.currentDef.Name + "_skel.json"; jsonOutput.graphic_asset = this.currentDef.Name + "_graphics.json"; jsonOutput.clips = []; for(var i = 0; i < clipData.length; i++) { var jsonClipData = {}; jsonClipData.type = clipData[i].type; jsonClipData.name = clipData[i].name; jsonClipData.x = clipData[i].x; jsonClipData.y = clipData[i].y; jsonClipData.sx = clipData[i].scaleX; jsonClipData.sy = clipData[i].scaleY; jsonClipData.rot = clipData[i].rotation; jsonOutput.clips.push(jsonClipData); } var jsonDataOutput = com.adobe.serialization.json.JSON.encode(jsonOutput); fileExportSet.Add(currentDef.Name+".json", jsonDataOutput); fileExportSet.AddJSONPNGSet(graphicPNGSet); if (skelPNGSet.PNGSheets.length > 0) fileExportSet.AddJSONPNGSet(skelPNGSet); if (doneCallback) doneCallback(fileExportSet, callbackParam); } else { var skelData:ByteArray = exporter.Output; var graphicData:ByteArray = graphicPacker.GetOutput(); var output:ByteArray = new ByteArray(); output.endian = Endian.LITTLE_ENDIAN; output.writeUnsignedInt(currentDef.Name.length); output.writeMultiByte(currentDef.Name, "us-ascii"); output.writeUnsignedInt(clipData.length); for(var i = 0; i < clipData.length; i++) { output.writeUnsignedInt(clipData[i].type); output.writeUnsignedInt(clipData[i].name.length); output.writeMultiByte(clipData[i].name, "us-ascii"); output.writeInt(clipData[i].x); output.writeInt(clipData[i].y); output.writeDouble(clipData[i].scaleX); output.writeDouble(clipData[i].scaleY); output.writeDouble(clipData[i].rotation); } output.writeUnsignedInt(skelData.length); output.writeBytes(skelData); output.writeUnsignedInt(graphicData.length); output.writeBytes(graphicData); if (doneCallback) doneCallback(output, callbackParam); } //Clear the Preview //while(this.holder.numChildren > 0) holder.removeChildAt(0); } } }