diff --git a/scripts/Tools.hx b/scripts/Tools.hx index 28f2895..a5368d0 100644 --- a/scripts/Tools.hx +++ b/scripts/Tools.hx @@ -292,11 +292,14 @@ class Tools { className = "openfl.display.BitmapData"; } - else if (#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (childSymbol, TagDefineShape) - || #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (childSymbol, TagDefineMorphShape)) + else if (#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (childSymbol, TagDefineShape)) { className = "openfl.display.Shape"; } + else if (#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (childSymbol, TagDefineMorphShape)) + { + className = "swf.exporters.animate.AnimateMorphShape"; + } else if (#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (childSymbol, TagDefineText) || #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (childSymbol, TagDefineEditText)) { diff --git a/src/swf/data/SWFMorphFillStyle.hx b/src/swf/data/SWFMorphFillStyle.hx index 56412e8..2fba066 100644 --- a/src/swf/data/SWFMorphFillStyle.hx +++ b/src/swf/data/SWFMorphFillStyle.hx @@ -82,12 +82,14 @@ class SWFMorphFillStyle { case 0x00: fillStyle.rgb = ColorUtils.interpolate(startColor, endColor, ratio); - case 0x10, 0x12: + case 0x10, 0x12, 0x13: fillStyle.gradientMatrix = MatrixUtils.interpolate(startGradientMatrix, endGradientMatrix, ratio); fillStyle.gradient = gradient.getMorphedGradient(ratio); case 0x40, 0x41, 0x42, 0x43: fillStyle.bitmapId = bitmapId; fillStyle.bitmapMatrix = MatrixUtils.interpolate(startBitmapMatrix, endBitmapMatrix, ratio); + default: + throw(new Error("Unknown fill style type: 0x" + StringTools.hex(type))); } return fillStyle; } diff --git a/src/swf/exporters/AnimateLibraryExporter.hx b/src/swf/exporters/AnimateLibraryExporter.hx index 48608ca..e7bdbdb 100644 --- a/src/swf/exporters/AnimateLibraryExporter.hx +++ b/src/swf/exporters/AnimateLibraryExporter.hx @@ -6,7 +6,18 @@ import swf.data.consts.BitmapFormat; import swf.data.consts.BlendMode; import swf.data.filters.IFilter; import swf.data.SWFButtonRecord; +import swf.data.SWFMatrix; +import swf.data.SWFMorphFillStyle; +import swf.data.SWFMorphFocalGradient; +import swf.data.SWFMorphGradient; +import swf.data.SWFMorphLineStyle; +import swf.data.SWFMorphLineStyle2; import swf.data.SWFSymbol; +import swf.data.SWFShape; +import swf.data.SWFShapeRecord; +import swf.data.SWFShapeRecordCurvedEdge; +import swf.data.SWFShapeRecordStraightEdge; +import swf.data.SWFShapeRecordStyleChange; import swf.exporters.ShapeBitmapExporter; import swf.exporters.ShapeCommandExporter; import swf.tags.IDefinitionTag; @@ -20,6 +31,7 @@ import swf.tags.TagDefineEditText; import swf.tags.TagDefineFont; import swf.tags.TagDefineFont2; import swf.tags.TagDefineFont4; +import swf.tags.TagDefineMorphShape; import swf.tags.TagDefineScalingGrid; import swf.tags.TagDefineShape; import swf.tags.TagDefineSound; @@ -30,6 +42,7 @@ import swf.tags.TagSymbolClass; import swf.SWFRoot; import swf.SWFTimelineContainer; import haxe.Template; +import haxe.rtti.Rtti; import hxp.Haxelib; import hxp.Log; import hxp.Path; @@ -212,11 +225,7 @@ class AnimateLibraryExporter if (object.placeMatrix != null) { - var matrix = object.placeMatrix.matrix.clone(); - matrix.tx *= (1 / 20); - matrix.ty *= (1 / 20); - - frameObject.matrix = serializeMatrix(matrix); + frameObject.matrix = serializeSWFMatrix(object.placeMatrix); } if (object.colorTransform != null) @@ -573,86 +582,36 @@ class AnimateLibraryExporter symbol.type = SWFSymbolType.SHAPE; symbol.id = tag.characterId; - var commands:Array = []; - - for (command in handler.commands) - { - switch (command) - { - case LineStyle(thickness, color, alpha, pixelHinting, scaleMode, startCaps, joints, miterLimit): - if (thickness == null && color == null && alpha == null) - { - commands.push(SWFShapeCommandType.CLEAR_LINE_STYLE); - } - else - { - commands = commands.concat([ - SWFShapeCommandType.LINE_STYLE, - thickness, - color, - alpha, - pixelHinting, - scaleMode, - startCaps, - joints, - miterLimit - ]); - } - - case BeginFill(color, alpha): - commands = commands.concat([SWFShapeCommandType.BEGIN_FILL, color, alpha]); - - case BeginGradientFill(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): - commands = commands.concat([ - SWFShapeCommandType.BEGIN_GRADIENT_FILL, - type, - colors, - alphas, - ratios, - serializeMatrix(matrix), - spreadMethod, - interpolationMethod, - focalPointRatio - ]); - - case BeginBitmapFill(bitmapID, matrix, repeat, smooth): - commands = commands.concat([ - SWFShapeCommandType.BEGIN_BITMAP_FILL, - bitmapID, - serializeMatrix(matrix), - repeat, - smooth - ]); - processTag(cast swfData.getCharacter(bitmapID)); - - case EndFill: - commands.push(SWFShapeCommandType.END_FILL); - - case MoveTo(x, y): - commands = commands.concat([SWFShapeCommandType.MOVE_TO, twip(x), twip(y)]); - - case LineTo(x, y): - commands = commands.concat([SWFShapeCommandType.LINE_TO, twip(x), twip(y)]); - - case CurveTo(controlX, controlY, anchorX, anchorY): - commands = commands.concat([ - SWFShapeCommandType.CURVE_TO, - twip(controlX), - twip(controlY), - twip(anchorX), - twip(anchorY) - ]); - - default: - } - } - - symbol.commands = commands; + symbol.commands = serializeShape(handler); libraryData.symbols.set(symbol.id, symbol); return symbol; } } + private function addMorphShape(tag:TagDefineMorphShape):Dynamic + { + var symbol:Dynamic = {}; + symbol.type = SWFSymbolType.MORPH_SHAPE; + symbol.id = tag.characterId; + + var handler = new ShapeCommandExporter(swfData); + tag.exportHandler = handler; + tag.export(0); + symbol.startCommands = serializeShape(handler); + + var handler = new ShapeCommandExporter(swfData); + tag.exportHandler = handler; + tag.export(1.0); + symbol.endCommands = serializeShape(handler); + + if (symbol.startCommands.length != symbol.endCommands.length) { + throw "Morph shape edges don't have the same number of commands: " + symbol.startCommands.length + " != " + symbol.endCommands.length; + } + + libraryData.symbols.set(symbol.id, symbol); + return symbol; + } + private function addSprite(tag:SWFTimelineContainer, root:Bool = false):Dynamic { var symbol:Dynamic = {}; @@ -725,11 +684,7 @@ class AnimateLibraryExporter if (placeTag.matrix != null) { - var matrix = placeTag.matrix.matrix.clone(); - matrix.tx *= (1 / 20); - matrix.ty *= (1 / 20); - - frameObject.matrix = serializeMatrix(matrix); + frameObject.matrix = serializeSWFMatrix(placeTag.matrix); } if (placeTag.colorTransform != null) @@ -761,6 +716,11 @@ class AnimateLibraryExporter frameObject.cacheAsBitmap = placeTag.bitmapCache != 0; } + if (placeTag.hasRatio) + { + frameObject.ratio = placeTag.ratio; + } + lastModified.set(object.placedAtIndex, object.lastModifiedAtIndex); if (frame.objects == null) @@ -1038,12 +998,7 @@ class AnimateLibraryExporter } symbol.records = records; - - var matrix = tag.textMatrix.matrix.clone(); - matrix.tx *= (1 / 20); - matrix.ty *= (1 / 20); - - symbol.matrix = serializeMatrix(matrix); + symbol.matrix = serializeSWFMatrix(tag.textMatrix); libraryData.symbols.set(symbol.id, symbol); @@ -1293,9 +1248,9 @@ class AnimateLibraryExporter if (className != null) { - objectReferences[object.name] = true; - classProperties.push({name: object.name, type: className, hidden: true}); - } + objectReferences[object.name] = true; + classProperties.push({name: object.name, type: className, hidden: true}); + } } } } @@ -1383,6 +1338,10 @@ class AnimateLibraryExporter { return addShape(cast tag); } + else if (#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (tag, TagDefineMorphShape)) + { + return addMorphShape(cast tag); + } else if (#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (tag, TagDefineFont) || #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (tag, TagDefineFont4)) { @@ -1415,6 +1374,85 @@ class AnimateLibraryExporter ]; } + private function serializeShape(handler: ShapeCommandExporter) : Array + { + var commands = new Array(); + + for (command in handler.commands) + { + switch (command) + { + case LineStyle(thickness, color, alpha, pixelHinting, scaleMode, startCaps, joints, miterLimit): + if (thickness == null && color == null && alpha == null) + { + commands.push(SWFShapeCommandType.CLEAR_LINE_STYLE); + } + else + { + commands = commands.concat([ + SWFShapeCommandType.LINE_STYLE, + thickness, + color, + alpha, + pixelHinting, + scaleMode, + startCaps, + joints, + miterLimit + ]); + } + + case BeginFill(color, alpha): + commands = commands.concat([SWFShapeCommandType.BEGIN_FILL, color, alpha]); + + case BeginGradientFill(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio): + commands = commands.concat([ + SWFShapeCommandType.BEGIN_GRADIENT_FILL, + type, + colors, + alphas, + ratios, + serializeMatrix(matrix), + spreadMethod, + interpolationMethod, + focalPointRatio + ]); + + case BeginBitmapFill(bitmapID, matrix, repeat, smooth): + commands = commands.concat([ + SWFShapeCommandType.BEGIN_BITMAP_FILL, + bitmapID, + serializeMatrix(matrix), + repeat, + smooth + ]); + processTag(cast swfData.getCharacter(bitmapID)); + + case EndFill: + commands.push(SWFShapeCommandType.END_FILL); + + case MoveTo(x, y): + commands = commands.concat([SWFShapeCommandType.MOVE_TO, twip(x), twip(y)]); + + case LineTo(x, y): + commands = commands.concat([SWFShapeCommandType.LINE_TO, twip(x), twip(y)]); + + case CurveTo(controlX, controlY, anchorX, anchorY): + commands = commands.concat([ + SWFShapeCommandType.CURVE_TO, + twip(controlX), + twip(controlY), + twip(anchorX), + twip(anchorY) + ]); + + default: + } + } + + return commands; + } + private function serializeFilters(filters:Array):Array> { if (filters == null || filters.length == 0) return null; @@ -1465,108 +1503,118 @@ class AnimateLibraryExporter return [matrix.a, matrix.b, matrix.c, matrix.d, twip(matrix.tx), twip(matrix.ty)]; } - private function serializeRect(rect:Rectangle):Array + private function serializeSWFMatrix(swfMatrix:SWFMatrix):Array { - return [twip(rect.x), twip(rect.y), twip(rect.width), twip(rect.height)]; + var matrix = swfMatrix.matrix.clone(); + matrix.tx *= (1 / 20); + matrix.ty *= (1 / 20); + + return serializeMatrix(matrix); } - private inline function twip(value:Float):Int + private function serializeRect(rect:Rectangle):Array { - return Math.round(value * 20); + return [twip(rect.x), twip(rect.y), twip(rect.width), twip(rect.height)]; } + + private inline function twip(value:Float):Int + { + return Math.round(value * 20); + } } private enum BitmapType { - PNG; - JPEG_ALPHA; - JPEG; + PNG; + JPEG_ALPHA; + JPEG; } private enum SoundType { - UNCOMPRESSED_NATIVE_ENDIAN; - ADPCM; - MP3; - UNCOMPRESSED_LITTLE_ENDIAN; - NELLYMOSER_16_KHZ; - NELLYMOSER_8_KHZ; - NELLYMOSER; - SPEEX; + UNCOMPRESSED_NATIVE_ENDIAN; + ADPCM; + MP3; + UNCOMPRESSED_LITTLE_ENDIAN; + NELLYMOSER_16_KHZ; + NELLYMOSER_8_KHZ; + NELLYMOSER; + SPEEX; } private class SWFDocument { - public var frameRate:Float; - public var uuid:String; - public var root:Dynamic; - public var symbols:Map; - - // public var version:Int; - - public function new() - { - symbols = new Map(); - } - - public function serialize():Dynamic - { - var output:Dynamic = {}; - output.frameRate = frameRate; - output.uuid = uuid; - output.root = 0; - output.version = 0.1; - - var symbolArray = new Array(); - symbolArray.push(root); - - for (key in symbols.keys()) - { - symbolArray.push(symbols.get(key)); - } - - output.symbols = symbolArray; - - return Json.stringify(output); - } + public var frameRate:Float; + public var uuid:String; + public var root:Dynamic; + public var symbols:Map; + + // public var version:Int; + + public function new() + { + symbols = new Map(); + } + + public function serialize():Dynamic + { + var output:Dynamic = {}; + output.frameRate = frameRate; + output.uuid = uuid; + output.root = 0; + output.version = 0.1; + + var symbolArray = new Array(); + symbolArray.push(root); + + for (key in symbols.keys()) + { + symbolArray.push(symbols.get(key)); + } + + output.symbols = symbolArray; + + return Json.stringify(output); + } } @:enum private abstract SWFFrameObjectType(Int) from Int to Int -{ - public var CREATE = 0; - public var UPDATE = 1; - public var DESTROY = 2; + { + public var CREATE = 0; + public var UPDATE = 1; + public var DESTROY = 2; } @:enum private abstract SWFShapeCommandType(Int) from Int to Int -{ - public var BEGIN_BITMAP_FILL = 0; - public var BEGIN_FILL = 1; - public var BEGIN_GRADIENT_FILL = 2; - public var CLEAR_LINE_STYLE = 3; - public var CURVE_TO = 4; - public var END_FILL = 5; - public var LINE_STYLE = 6; - public var LINE_TO = 7; - public var MOVE_TO = 8; + { + public var BEGIN_BITMAP_FILL = 0; + public var BEGIN_FILL = 1; + public var BEGIN_GRADIENT_FILL = 2; + public var CLEAR_LINE_STYLE = 3; + public var CURVE_TO = 4; + public var END_FILL = 5; + public var LINE_STYLE = 6; + public var LINE_TO = 7; + public var MOVE_TO = 8; } @:enum private abstract SWFSymbolType(Int) from Int to Int -{ - public var BITMAP = 0; - public var BUTTON = 1; - public var DYNAMIC_TEXT = 2; - public var FONT = 3; - public var SHAPE = 4; - public var SPRITE = 5; - public var STATIC_TEXT = 6; + { + public var BITMAP = 0; + public var BUTTON = 1; + public var DYNAMIC_TEXT = 2; + public var FONT = 3; + public var SHAPE = 4; + public var SPRITE = 5; + public var STATIC_TEXT = 6; + public var MORPH_SHAPE = 7; } @:enum private abstract SWFFilterType(Int) from Int to Int -{ - public var BLUR = 0; - public var COLOR_MATRIX = 1; - public var DROP_SHADOW = 2; - public var GLOW = 3; - // TODO: More + { + public var BLUR = 0; + public var COLOR_MATRIX = 1; + public var DROP_SHADOW = 2; + public var GLOW = 3; + // TODO: More } diff --git a/src/swf/exporters/animate/AnimateFrameObject.hx b/src/swf/exporters/animate/AnimateFrameObject.hx index 2ce57ec..5f8b206 100644 --- a/src/swf/exporters/animate/AnimateFrameObject.hx +++ b/src/swf/exporters/animate/AnimateFrameObject.hx @@ -23,6 +23,7 @@ class AnimateFrameObject public var symbol:Int; public var type:AnimateFrameObjectType; public var visible:Null; + public var ratio:Null; public function new() {} } diff --git a/src/swf/exporters/animate/AnimateLibrary.hx b/src/swf/exporters/animate/AnimateLibrary.hx index faf4227..d7f03bf 100644 --- a/src/swf/exporters/animate/AnimateLibrary.hx +++ b/src/swf/exporters/animate/AnimateLibrary.hx @@ -267,6 +267,8 @@ import openfl.filters.GlowFilter; symbol = spriteSymbol; case STATIC_TEXT: symbol = __parseStaticText(data); + case MORPH_SHAPE: + symbol = __parseMorphShape(data); default: } @@ -668,6 +670,75 @@ import openfl.filters.GlowFilter; return symbol; } + private function __parseMorphShape(data:Dynamic):AnimateMorphShapeSymbol + { + var symbol = new AnimateMorphShapeSymbol(); + symbol.id = data.id; + symbol.commands = []; + + var startData:Array = data.startCommands; + var endData:Array = data.endCommands; + var commands = symbol.commands; + var i = 0; + + while (i < startData.length) + { + switch (startData[i]) + { + case BEGIN_BITMAP_FILL: + commands.push(BeginBitmapFill(startData[i + 1], + __parseMatrix(startData[i + 2]), __parseMatrix(endData[i + 2]), + startData[i + 3], startData[i + 4])); + i += 5; + case BEGIN_FILL: + commands.push(BeginFill(startData[i + 1], endData[i + 1], + startData[i + 2], endData[i + 2])); + i += 3; + case BEGIN_GRADIENT_FILL: + commands.push(BeginGradientFill(startData[i + 1], + startData[i + 2], endData[i + 2], + startData[i + 3], endData[i + 3], + startData[i + 4], endData[i + 4], + __parseMatrix(startData[i + 5]), __parseMatrix(endData[i + 5]), + startData[i + 6], + startData[i + 7], + startData[i + 8])); + i += 9; + case CLEAR_LINE_STYLE: + commands.push(LineStyle(null, null, null, null, null, null, null, null, null, null, null)); + i++; + case CURVE_TO: + commands.push(CurveTo(__pixel(startData[i + 1]), __pixel(startData[i + 2]), __pixel(startData[i + 3]), __pixel(startData[i + 4]), + __pixel(endData[i + 1]), __pixel(endData[i + 2]), __pixel(endData[i + 3]), __pixel(endData[i + 4]))); + i += 5; + case END_FILL: + commands.push(EndFill); + i++; + case LINE_STYLE: + commands.push(LineStyle(startData[i + 1], endData[i + 1], + startData[i + 2], endData[i + 2], + startData[i + 3], endData[i + 3], + startData[i + 4], + startData[i + 5], + startData[i + 6], + startData[i + 7], + startData[i + 8])); + i += 9; + case LINE_TO: + commands.push(LineTo(__pixel(startData[i + 1]), __pixel(startData[i + 2]), + __pixel(endData[i + 1]), __pixel(endData[i + 2]))); + i += 3; + case MOVE_TO: + commands.push(MoveTo(__pixel(startData[i + 1]), __pixel(startData[i + 2]), + __pixel(endData[i + 1]), __pixel(endData[i + 2]))); + i += 3; + default: + i++; + } + } + return symbol; + } + private function __parseSprite(data:Dynamic):AnimateSpriteSymbol { if (data == null) return null; @@ -720,6 +791,7 @@ import openfl.filters.GlowFilter; object.symbol = objectData.symbol; object.type = objectData.type; object.visible = objectData.visible; + object.ratio = objectData.ratio; frame.objects.push(object); } } @@ -765,4 +837,5 @@ import openfl.filters.GlowFilter; public var SHAPE = 4; public var SPRITE = 5; public var STATIC_TEXT = 6; + public var MORPH_SHAPE = 7; } diff --git a/src/swf/exporters/animate/AnimateMorphShape.hx b/src/swf/exporters/animate/AnimateMorphShape.hx new file mode 100644 index 0000000..35a20b7 --- /dev/null +++ b/src/swf/exporters/animate/AnimateMorphShape.hx @@ -0,0 +1,165 @@ +package swf.exporters.animate; + +import openfl.display.BitmapData; +import openfl.display.CapsStyle; +import openfl.display.JointStyle; +import openfl.display.LineScaleMode; +import openfl.display.Shape; +import openfl.geom.Matrix; +import swf.utils.ColorUtils; + +@:access(swf.exporters.animate.AnimateLibrary) +@:access(openfl.display.CapsStyle) +@:access(openfl.display.GradientType) +@:access(openfl.display.InterpolationMethod) +@:access(openfl.display.JointStyle) +@:access(openfl.display.LineScaleMode) +@:access(openfl.display.SpreadMethod) +class AnimateMorphShape extends openfl.display.Shape +{ + public var ratio(default, null): Int; + + private var symbol: AnimateMorphShapeSymbol; + private var library: AnimateLibrary; + + private var __colors: Array = []; + private var __alphas: Array = []; + private var __ratios: Array = []; + private var __matrix = new Matrix(); + + public function new(symbol: AnimateMorphShapeSymbol, library: AnimateLibrary, ratio: Int = 0) + { + super(); + + this.symbol = symbol; + this.library = library; + this.ratio = ratio; + + render(this.ratio); + } + + public function render(ratio:Int = 0) + { + this.ratio = ratio; + graphics.clear(); + + if (symbol.rendered.exists(ratio)) { + graphics.copyFrom(symbol.rendered[ratio].graphics); + return; + } + + var b = ratio / 65535.0; + var a = 1.0 - b; + + for (command in symbol.commands) + { + switch (command) + { + case BeginFill(startColor, endColor, startAlpha, endAlpha): + graphics.beginFill(ColorUtils.interpolate(startColor, endColor, a), lerpf(startAlpha, endAlpha, a, b)); + + case BeginBitmapFill(bitmapID, startMatrix, endMatrix, repeat, smooth): + #if lime + var bitmapSymbol:AnimateBitmapSymbol = cast library.symbols.get(bitmapID); + var bitmap = library.getImage(bitmapSymbol.path); + + if (bitmap != null) + { + graphics.beginBitmapFill(BitmapData.fromImage(bitmap), + lerpMatrix(startMatrix, endMatrix, a, b), + repeat, smooth); + } + #end + + case BeginGradientFill(fillType, startColors, endColors, startAlphas, endAlphas, startRatios, endRatios, startMatrix, endMatrix, + spreadMethod, interpolationMethod, focalPointRatio): + // #if flash + // var colors:Array = cast colors; + // #end + + graphics.beginGradientFill(GradientType.fromInt(fillType), + lerpColors(startColors, endColors, a, b), + lerpAlphas(startAlphas, endAlphas, a, b), + lerpRatios(startRatios, endRatios, a, b), + lerpMatrix(startMatrix, endMatrix, a, b), + SpreadMethod.fromInt(spreadMethod), + InterpolationMethod.fromInt(interpolationMethod), + focalPointRatio); + + case CurveTo(startControlX, startControlY, startAnchorX, startAnchorY, endControlX, endControlY, endAnchorX, endAnchorY): + graphics.curveTo(lerpf(startControlX, endControlX, a, b), + lerpf(startControlY, endControlY, a, b), + lerpf(startAnchorX, endAnchorX, a, b), + lerpf(startAnchorY, endAnchorY, a, b)); + + case EndFill: + graphics.endFill(); + + case LineStyle(startThickness, endThickness, startColor, endColor, startAlpha, endAlpha, pixelHinting, scaleMode, caps, joints, miterLimit): + if (startThickness != null) + { + graphics.lineStyle(lerpf(startThickness, endThickness, a, b), + ColorUtils.interpolate(startColor, endColor, a), + lerpf(startAlpha, endAlpha, a, b), + pixelHinting, + LineScaleMode.fromInt(scaleMode), + CapsStyle.fromInt(caps), + JointStyle.fromInt(joints), + miterLimit); + } + else + { + graphics.lineStyle(); + } + + case LineTo(startX, startY, endX, endY): + graphics.lineTo(lerpf(startX, endX, a, b), lerpf(startY, endY, a, b)); + + case MoveTo(startX, startY, endX, endY): + graphics.moveTo(lerpf(startX, endX, a, b), lerpf(startY, endY, a, b)); + } + } + + var rendered = new Shape(); + rendered.graphics.copyFrom(graphics); + symbol.rendered[ratio] = rendered; + } + + private inline function lerpf(start:Float, end:Float, a:Float, b:Float): Float { + return start * a + end * b; + } + + private inline function lerpColors(start:Array, end:Array, a:Float, b:Float): Array { + __colors.resize(start.length); + for (i in 0...start.length) { + __colors[i] = ColorUtils.interpolate(start[i], end[i], a); + } + return __colors; + } + + private inline function lerpAlphas(start:Array, end:Array, a:Float, b:Float): Array { + __alphas.resize(start.length); + for (i in 0...start.length) { + __alphas[i] = lerpf(start[i], end[i], a, b); + } + return __alphas; + } + + private inline function lerpRatios(start:Array, end:Array, a:Float, b:Float): Array { + __ratios.resize(start.length); + for (i in 0...start.length) { + __ratios[i] = Std.int(lerpf(start[i], end[i], a, b)); + } + return __ratios; + } + + private inline function lerpMatrix(matrix1:Matrix, matrix2:Matrix, a:Float, b:Float): Matrix { + __matrix.a = matrix1.a * a + matrix2.a * b; + __matrix.b = matrix1.b * a + matrix2.b * b; + __matrix.c = matrix1.c * a + matrix2.c * b; + __matrix.d = matrix1.d * a + matrix2.d * b; + __matrix.tx = Std.int(matrix1.tx * a + matrix2.tx * b); + __matrix.ty = Std.int(matrix1.ty * a + matrix2.ty * b); + return __matrix; + } +} diff --git a/src/swf/exporters/animate/AnimateMorphShapeCommand.hx b/src/swf/exporters/animate/AnimateMorphShapeCommand.hx new file mode 100644 index 0000000..b9597d8 --- /dev/null +++ b/src/swf/exporters/animate/AnimateMorphShapeCommand.hx @@ -0,0 +1,43 @@ +package swf.exporters.animate; + +import openfl.geom.Matrix; + +enum AnimateMorphShapeCommand +{ + BeginBitmapFill(bitmap:Int, + startMatrix:Matrix, endMatrix: Matrix, + repeat:Bool, + smooth:Bool); + BeginFill(startColor:Int, endColor:Int, + startAlpha:Float, endAlpha:Float); + BeginGradientFill(fillType:Null /*GradientType*/, + beginColors:Array, endColors:Array, + beginAlphas:Array, endAlphas:Array, + beginRatios:Array, endRatios:Array, + beginMatrix:Matrix, endMatrix:Matrix, + spreadMethod:Null /*SpreadMethod*/, + interpolationMethod:Null /*InterpolationMethod*/, + focalPointRatio:Float); + // CubicCurveTo (controlX1:Float, controlY1:Float, controlX2:Float, controlY2:Float, anchorX:Float, anchorY:Float); + CurveTo(beginControlX:Float, beginControlY:Float, + beginAnchorX:Float, beginAnchorY:Float, + endControlX:Float, endControlY:Float, + endAnchorX:Float, endAnchorY:Float); + // DrawCircle (x:Float, y:Float, radius:Float); + // DrawEllipse (x:Float, y:Float, width:Float, height:Float); + // DrawRect (x:Float, y:Float, width:Float, height:Float); + // DrawRoundRect (x:Float, y:Float, width:Float, height:Float, rx:Float, ry:Float); + // DrawTiles (sheet:Tilesheet, tileData:Array, smooth:Bool, flags:Int, count:Int); + // DrawTriangles (vertices:Vector, indices:Vector, uvtData:Vector, culling:TriangleCulling); + EndFill; + LineStyle(beginThickness:Null, endThickness:Null, + beginColor:Null, endColor:Null, + beginAlpha:Null, endAlpha:Null, + pixelHinting:Null, + scaleMode:Null /*LineScaleMode*/, + caps:Null /*CapsStyle*/, + joints:Null /*JointStyle*/, + miterLimit:Null); + LineTo(beginX:Float, beginY:Float, endX:Float, endY:Float); + MoveTo(beginX:Float, beginY:Float, endX:Float, endY:Float); +} diff --git a/src/swf/exporters/animate/AnimateMorphShapeSymbol.hx b/src/swf/exporters/animate/AnimateMorphShapeSymbol.hx new file mode 100644 index 0000000..85cf509 --- /dev/null +++ b/src/swf/exporters/animate/AnimateMorphShapeSymbol.hx @@ -0,0 +1,37 @@ +package swf.exporters.animate; + +import openfl.display.BitmapData; +import openfl.display.CapsStyle; +import openfl.display.GradientType; +import openfl.display.InterpolationMethod; +import openfl.display.JointStyle; +import openfl.display.LineScaleMode; +import openfl.display.Shape; +import openfl.display.SpreadMethod; + +#if !openfl_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(swf.exporters.animate.AnimateLibrary) +@:access(openfl.display.CapsStyle) +@:access(openfl.display.GradientType) +@:access(openfl.display.InterpolationMethod) +@:access(openfl.display.JointStyle) +@:access(openfl.display.LineScaleMode) +@:access(openfl.display.SpreadMethod) +class AnimateMorphShapeSymbol extends AnimateSymbol +{ + public var commands:Array = []; + public var rendered:Map = new Map(); + + public function new() + { + super(); + } + + private override function __createObject(library:AnimateLibrary):Shape + { + return new AnimateMorphShape(this, library); + } +} diff --git a/src/swf/exporters/animate/AnimateTimeline.hx b/src/swf/exporters/animate/AnimateTimeline.hx index b021779..f43f181 100644 --- a/src/swf/exporters/animate/AnimateTimeline.hx +++ b/src/swf/exporters/animate/AnimateTimeline.hx @@ -18,6 +18,7 @@ import openfl.filters.DisplacementMapFilter; import openfl.filters.DropShadowFilter; import openfl.filters.GlowFilter; import openfl.geom.ColorTransform; +import haxe.rtti.Rtti; #if hscript import hscript.Interp; import hscript.Parser; @@ -51,6 +52,7 @@ class AnimateTimeline extends Timeline @:noCompletion private var __previousFrame:Int; @:noCompletion private var __sprite:Sprite; @:noCompletion private var __symbol:AnimateSpriteSymbol; + @:noCompletion private var __fieldNameToType:Map; public function new(library:AnimateLibrary, symbol:AnimateSpriteSymbol) { @@ -345,12 +347,29 @@ class AnimateTimeline extends Timeline __currentInstancesByFrameObjectID = new Map(); __lastUpdated = new Map(); - var frame:Int; - var frameData:AnimateFrame; - var instance:FrameSymbolInstance; - var duplicate:Bool; - var symbol:AnimateSymbol; - var displayObject:DisplayObject; + __fieldNameToType = new Map(); + + switch Type.typeof(__sprite) { + case TClass(c): + if (Rtti.hasRtti(c)) { + var rtti = Rtti.getRtti(c); + for (field in rtti.fields) { + switch (field.type) { + case CClass(cname, params): + __fieldNameToType.set(field.name, cname); + default: + } + } + } + default: + } + + var frame:Int; + var frameData:AnimateFrame; + var instance:FrameSymbolInstance; + var duplicate:Bool; + var symbol:AnimateSymbol; + var displayObject:DisplayObject; // TODO: Create later? @@ -394,7 +413,11 @@ class AnimateTimeline extends Timeline if (symbol != null) { - displayObject = symbol.__createObject(__library); + if (frameObject.name != null && __fieldNameToType.exists(frameObject.name)) { + symbol.className = __fieldNameToType.get(frameObject.name); + } + + displayObject = symbol.__createObject(__library); if (displayObject != null) { @@ -522,6 +545,10 @@ class AnimateTimeline extends Timeline displayObject.cacheAsBitmap = frameObject.cacheAsBitmap; } + if (frameObject.ratio != null && #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (displayObject, AnimateMorphShape)) { + cast(displayObject, AnimateMorphShape).render(frameObject.ratio); + } + #if openfljs Reflect.setField(__sprite, displayObject.name, displayObject); #end @@ -539,7 +566,7 @@ class AnimateTimeline extends Timeline var child = __sprite.getChildAt(i); if (child.name == field) { - Reflect.setField(__sprite, field, child); + Reflect.setField(__sprite, field, child); break; } } diff --git a/src/swf/timeline/Frame.hx b/src/swf/timeline/Frame.hx index 3e1df56..d780787 100644 --- a/src/swf/timeline/Frame.hx +++ b/src/swf/timeline/Frame.hx @@ -92,7 +92,7 @@ class Frame else { // No character defined at specified depth. Create one. - objects.set(tag.depth, new FrameObject(tag.depth, tag.clipDepth, tag.characterId, tag.className, tagIndex, 0, true)); + objects.set(tag.depth, new FrameObject(tag.depth, tag.clipDepth, tag.characterId, tag.className, tagIndex, 0, true, tag.ratio)); } _objectsSortedByDepth = null; } diff --git a/src/swf/timeline/FrameObject.hx b/src/swf/timeline/FrameObject.hx index cd488d8..a77bf5a 100644 --- a/src/swf/timeline/FrameObject.hx +++ b/src/swf/timeline/FrameObject.hx @@ -21,8 +21,10 @@ class FrameObject public var isKeyframe:Bool; // The index of the layer this object resides on public var layer:Int = -1; + // The ratio of this object if it's a MorphShape + public var ratio:Int = 0; - public function new(depth:Int, clipDepth:Int, characterId:Int, className:String, placedAtIndex:Int, lastModifiedAtIndex:Int = 0, isKeyframe:Bool = false) + public function new(depth:Int, clipDepth:Int, characterId:Int, className:String, placedAtIndex:Int, lastModifiedAtIndex:Int = 0, isKeyframe:Bool = false, ratio:Int = 0) { this.depth = depth; this.clipDepth = clipDepth; @@ -32,11 +34,12 @@ class FrameObject this.lastModifiedAtIndex = lastModifiedAtIndex; this.isKeyframe = isKeyframe; this.layer = -1; + this.ratio = ratio; } public function clone():FrameObject { - return new FrameObject(depth, clipDepth, characterId, className, placedAtIndex, lastModifiedAtIndex, false); + return new FrameObject(depth, clipDepth, characterId, className, placedAtIndex, lastModifiedAtIndex, false, ratio); } public function toString( /*indent:Int = 0*/):String