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);
}
}
}