animate atlas stuff todo
This commit is contained in:
@@ -74,6 +74,7 @@
|
||||
<!-- _______________________________ Libraries ______________________________ -->
|
||||
|
||||
<haxelib name="hxCodec"/>
|
||||
<haxelib name="Flixel-TextureAtlas"/>
|
||||
<haxelib name="flixel-yc29" rename="flixel" />
|
||||
<haxedev set='webgl' />
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package animateatlas;
|
||||
import flixel.util.FlxDestroyUtil;
|
||||
import openfl.geom.Rectangle;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.math.FlxRect;
|
||||
import openfl.Assets;
|
||||
import haxe.Json;
|
||||
import openfl.display.BitmapData;
|
||||
import animateatlas.JSONData.AtlasData;
|
||||
import animateatlas.JSONData.AnimationData;
|
||||
import animateatlas.displayobject.SpriteAnimationLibrary;
|
||||
import animateatlas.displayobject.SpriteMovieClip;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.graphics.frames.FlxFramesCollection;
|
||||
import flixel.graphics.frames.FlxFrame;
|
||||
using StringTools;
|
||||
class AtlasFrameMaker extends FlxFramesCollection{
|
||||
|
||||
|
||||
//public static var widthoffset:Int = 0;
|
||||
//public static var heightoffset:Int = 0;
|
||||
//public static var excludeArray:Array<String>;
|
||||
/**
|
||||
|
||||
* Creates Frames from TextureAtlas(very early and broken ok) Originally made for FNF HD by Smokey and Rozebud
|
||||
*
|
||||
* @param key The file path.
|
||||
* @param _excludeArray Use this to only create selected animations. Keep null to create all of them.
|
||||
*
|
||||
*/
|
||||
|
||||
public static function construct(key:String,?_excludeArray:Array<String> = null):FlxFramesCollection{
|
||||
|
||||
// widthoffset = _widthoffset;
|
||||
// heightoffset = _heightoffset;
|
||||
|
||||
|
||||
|
||||
var frameCollection:FlxFramesCollection;
|
||||
var frameArray:Array<Array<FlxFrame>> = [];
|
||||
var animationData:AnimationData = Json.parse(Assets.getText(key + "/Animation.json"));
|
||||
var atlasData:AtlasData = Json.parse(Assets.getText(key + "/spritemap.json").replace("\uFEFF", ""));//FIXED UTF8 w/ BOM error
|
||||
var bitmapData:BitmapData = Assets.getBitmapData(key + "/spritemap.png");
|
||||
var ss = new SpriteAnimationLibrary(animationData, atlasData, bitmapData);
|
||||
var t = ss.createAnimation();
|
||||
if(_excludeArray == null){
|
||||
_excludeArray = t.getFrameLabels();
|
||||
}
|
||||
frameCollection = new FlxFramesCollection(FlxGraphic.fromBitmapData(bitmapData),FlxFrameCollectionType.IMAGE);
|
||||
|
||||
|
||||
for(x in t.getFrameLabels()){
|
||||
|
||||
frameArray.push(getFramesArray(t, x,_excludeArray));
|
||||
|
||||
|
||||
}
|
||||
|
||||
for(x in frameArray){
|
||||
for(y in x){
|
||||
frameCollection.pushFrame(y);
|
||||
}
|
||||
}
|
||||
|
||||
return frameCollection;
|
||||
|
||||
}
|
||||
|
||||
@:noCompletion static function getFramesArray(t:SpriteMovieClip,animation:String,_excludeArray:Array<String>):Array<FlxFrame>
|
||||
{
|
||||
var sizeInfo:Rectangle = new Rectangle(0,0);
|
||||
t.currentLabel = animation;
|
||||
var bitMapArray:Array<BitmapData> = [];
|
||||
var daFramez:Array<FlxFrame> = [];
|
||||
var firstPass = true;
|
||||
var frameSize:FlxPoint = new FlxPoint(0,0);
|
||||
|
||||
for (i in t.getFrame(animation)...t.numFrames){
|
||||
t.currentFrame = i;
|
||||
if (t.currentLabel == animation){
|
||||
if (_excludeArray.contains(animation)){
|
||||
sizeInfo = t.getBounds(t);
|
||||
|
||||
var bitmapShit:BitmapData = new BitmapData(
|
||||
Std.int(sizeInfo.width + Math.abs(sizeInfo.x)),Std.int(sizeInfo.height +Math.abs(sizeInfo.y)),true,0);
|
||||
|
||||
bitmapShit.draw(t,null,null,null,null,true);
|
||||
bitMapArray.push(bitmapShit);
|
||||
|
||||
if (firstPass){
|
||||
frameSize.set(bitmapShit.width,bitmapShit.height);
|
||||
firstPass = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
for (i in 0...bitMapArray.length){
|
||||
var b = FlxGraphic.fromBitmapData(bitMapArray[i]);
|
||||
var theFrame = new FlxFrame(b);
|
||||
theFrame.parent = b;
|
||||
theFrame.name = animation + i;
|
||||
theFrame.sourceSize.set(frameSize.x,frameSize.y);
|
||||
theFrame.frame = new FlxRect(0, 0, bitMapArray[i].width, bitMapArray[i].height);
|
||||
daFramez.push(theFrame);
|
||||
|
||||
//trace(daFramez);
|
||||
}
|
||||
return daFramez;
|
||||
}
|
||||
|
||||
/*public static function renderTest(key:String, animation:String, ?frame:Int = 0):Void
|
||||
{
|
||||
var animationData:AnimationData = Json.parse(Assets.getText(key + "/Animation.json"));
|
||||
var atlasData:AtlasData = Json.parse(Assets.getText(key + "/spritemap.json"));
|
||||
var bitmapData:BitmapData = Assets.getBitmapData(key + "/spritemap.png");
|
||||
var ss = new SpriteAnimationLibrary(animationData, atlasData, bitmapData);
|
||||
var t = ss.createAnimation();
|
||||
var bitMapArray:Array<BitmapData> = [];
|
||||
|
||||
for (i in 0...t.numFrames){
|
||||
t.currentFrame = i;
|
||||
if (t.currentLabel == animation){
|
||||
//trace(t.currentFrame);
|
||||
var bitmapShit:BitmapData = new BitmapData(Std.int(t.width),Std.int(t.height),true,0);
|
||||
//bitmapShit.drawWithQuality(t,null,null,null,null,true);
|
||||
bitmapShit.draw(t, new Matrix(1, 0, 0, 1, t.width/2, t.height/2), null, null, null, false);
|
||||
bitMapArray.push(bitmapShit);
|
||||
}
|
||||
}
|
||||
|
||||
saveImage(bitMapArray[frame]);
|
||||
|
||||
}
|
||||
|
||||
public static function saveImage(bitmapData:BitmapData)
|
||||
{
|
||||
var b:ByteArray = new ByteArray();
|
||||
b = bitmapData.encode(bitmapData.rect, new PNGEncoderOptions(true), b);
|
||||
new FileDialog().save(b, "png", null, "file");
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package animateatlas;
|
||||
|
||||
enum abstract LoopMode(String) from String to String {
|
||||
public static inline var LOOP:String = "loop";
|
||||
public static inline var PLAY_ONCE:String = "playonce";
|
||||
public static inline var SINGLE_FRAME:String = "singleframe";
|
||||
|
||||
public static function isValid(value:String):Bool {
|
||||
return value == LOOP || value == PLAY_ONCE || value == SINGLE_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
enum abstract SymbolType(String) from String to String {
|
||||
public static inline var GRAPHIC:String = "graphic";
|
||||
public static inline var MOVIE_CLIP:String = "movieclip";
|
||||
public static inline var BUTTON:String = "button";
|
||||
|
||||
public static function isValid(value:String):Bool {
|
||||
return value == GRAPHIC || value == MOVIE_CLIP || value == BUTTON;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package animateatlas;
|
||||
|
||||
/**
|
||||
* All data needed for the json importer + some extra for after parsing.
|
||||
* Stolen mostly from https://github.com/TomByrne/Starling-Extension-Adobe-Animate-Hx/blob/master/hx/src/starling/extensions/animate/AnimationAtlasData.hx
|
||||
*/
|
||||
typedef AnimationData = {
|
||||
?ANIMATION:SymbolData,
|
||||
?SYMBOL_DICTIONARY:{
|
||||
Symbols:Array<SymbolData>
|
||||
},
|
||||
?metadata:{
|
||||
?framerate:Null<Int>
|
||||
}
|
||||
}
|
||||
|
||||
typedef AtlasData = {
|
||||
?ATLAS:{
|
||||
SPRITES:Array<SpriteDummy>
|
||||
},
|
||||
?meta:{
|
||||
app:String,
|
||||
version:String,
|
||||
image:String,
|
||||
format:String,
|
||||
size:{w:Int, h:Int},
|
||||
scale:String,
|
||||
}
|
||||
}
|
||||
|
||||
typedef SpriteDummy = {
|
||||
SPRITE:SpriteData
|
||||
}
|
||||
|
||||
typedef SpriteData = {
|
||||
name:String,
|
||||
x:Int,
|
||||
y:Int,
|
||||
w:Int,
|
||||
h:Int,
|
||||
rotated:Bool
|
||||
}
|
||||
|
||||
typedef SymbolData = {
|
||||
?name:String,
|
||||
SYMBOL_name:String,
|
||||
?TIMELINE:SymbolTimelineData
|
||||
}
|
||||
|
||||
typedef SymbolTimelineData = {
|
||||
?sortedForRender:Bool,
|
||||
LAYERS:Array<LayerData>
|
||||
}
|
||||
|
||||
typedef LayerData = {
|
||||
Layer_name:String,
|
||||
Frames:Array<LayerFrameData>,
|
||||
FrameMap:Map<Int, LayerFrameData>
|
||||
}
|
||||
|
||||
typedef LayerFrameData = {
|
||||
index:Int,
|
||||
?name:String,
|
||||
duration:Int,
|
||||
elements:Array<ElementData>
|
||||
}
|
||||
|
||||
typedef ElementData = {
|
||||
?ATLAS_SPRITE_instance:Dynamic,
|
||||
?SYMBOL_Instance:SymbolInstanceData
|
||||
}
|
||||
|
||||
typedef SymbolInstanceData = {
|
||||
SYMBOL_name:String,
|
||||
Instance_Name:String,
|
||||
bitmap:BitmapPosData,
|
||||
symbolType:String,
|
||||
transformationPoint:PointData,
|
||||
Matrix3D:Matrix3DData,
|
||||
?DecomposedMatrix:Decomposed3DData,
|
||||
?color:ColorData,
|
||||
|
||||
?loop:String,
|
||||
firstFrame:Int,
|
||||
?filters:FilterData
|
||||
}
|
||||
|
||||
typedef ColorData = {
|
||||
mode:String,
|
||||
|
||||
?RedMultiplier:Float,
|
||||
?greenMultiplier:Float,
|
||||
?blueMultiplier:Float,
|
||||
?alphaMultiplier:Float,
|
||||
?redOffset:Float,
|
||||
?greenOffset:Float,
|
||||
?blueOffset:Float,
|
||||
?AlphaOffset:Float,
|
||||
?tintColor:String,
|
||||
?tintMultiplier:Float
|
||||
}
|
||||
|
||||
typedef BitmapPosData = {
|
||||
name:String,
|
||||
Position:PointData,
|
||||
}
|
||||
|
||||
typedef PointData = {
|
||||
x:Int,
|
||||
y:Int
|
||||
}
|
||||
|
||||
typedef Matrix3DData = {
|
||||
m00:Float,
|
||||
m01:Float,
|
||||
m02:Float,
|
||||
m03:Float,
|
||||
m10:Float,
|
||||
m11:Float,
|
||||
m12:Float,
|
||||
m13:Float,
|
||||
m20:Float,
|
||||
m21:Float,
|
||||
m22:Float,
|
||||
m23:Float,
|
||||
m30:Float,
|
||||
m31:Float,
|
||||
m32:Float,
|
||||
m33:Float,
|
||||
}
|
||||
//tryna add more support gimme a sec
|
||||
typedef FilterData = {
|
||||
?BlurFilter: {
|
||||
blurX:Float,
|
||||
blurY:Float,
|
||||
quality:Int
|
||||
},
|
||||
|
||||
?GlowFilter: {
|
||||
blurX: Float,
|
||||
blurY: Float,
|
||||
color: Int,
|
||||
alpha: Int,
|
||||
quality: Int,
|
||||
strength: Int,
|
||||
knockout: Bool,
|
||||
inner: Bool
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
typedef Decomposed3DData = {
|
||||
Position:{x:Float, y:Float, z:Float},
|
||||
Rotation:{x:Float, y:Float, z:Float},
|
||||
Scaling:{x:Float, y:Float, z:Float},
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package;
|
||||
|
||||
import animateatlas.JSONData.AtlasData;
|
||||
import openfl.display.BitmapData;
|
||||
import animateatlas.JSONData.AnimationData;
|
||||
import openfl.display.FPS;
|
||||
import openfl.Lib;
|
||||
import openfl.events.MouseEvent;
|
||||
import animateatlas.HelperEnums.LoopMode;
|
||||
import openfl.events.Event;
|
||||
import openfl.display.Tilemap;
|
||||
import openfl.display.Tileset;
|
||||
import openfl.Assets;
|
||||
import haxe.Json;
|
||||
import animateatlas.tilecontainer.TileAnimationLibrary;
|
||||
import animateatlas.tilecontainer.TileContainerMovieClip;
|
||||
import animateatlas.displayobject.SpriteAnimationLibrary;
|
||||
import animateatlas.displayobject.SpriteMovieClip;
|
||||
import openfl.display.Sprite;
|
||||
|
||||
class Main extends Sprite {
|
||||
var aa:TileAnimationLibrary;
|
||||
var ss:SpriteAnimationLibrary;
|
||||
|
||||
//
|
||||
var tileSymbols:Array<TileContainerMovieClip>;
|
||||
|
||||
var spriteSymbols:Array<SpriteMovieClip>;
|
||||
|
||||
var renderer:Tilemap;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
graphics.beginFill(0x333333);
|
||||
graphics.drawRect(0, 0, Lib.current.stage.stageWidth, Lib.current.stage.stageHeight);
|
||||
|
||||
var animationData:AnimationData = Json.parse(Assets.getText("assets/TEST/Animation.json"));
|
||||
var atlasData:AtlasData = Json.parse(Assets.getText("assets/TEST/spritemap.json"));
|
||||
var bitmapData:BitmapData = Assets.getBitmapData("assets/TEST/spritemap.png");
|
||||
|
||||
aa = new TileAnimationLibrary(animationData, atlasData, bitmapData);
|
||||
ss = new SpriteAnimationLibrary(animationData, atlasData, bitmapData);
|
||||
|
||||
renderer = new Tilemap(Lib.current.stage.stageWidth, Lib.current.stage.stageHeight, null, true);
|
||||
|
||||
renderer.tileAlphaEnabled = false;
|
||||
renderer.tileBlendModeEnabled = false;
|
||||
renderer.tileColorTransformEnabled = false;
|
||||
|
||||
addChild(renderer);
|
||||
addChild(new FPS(10, 10, 0xFFFFFF));
|
||||
|
||||
tileSymbols = [];
|
||||
spriteSymbols = [];
|
||||
|
||||
addEventListener(Event.ENTER_FRAME, update);
|
||||
// addEventListener(MouseEvent.CLICK, addSpriteGirl);
|
||||
addEventListener(MouseEvent.CLICK, addTileGirl);
|
||||
}
|
||||
|
||||
var prev:Int = 0;
|
||||
var dt:Int = 0;
|
||||
var curr:Int = 0;
|
||||
|
||||
public function update(_) {
|
||||
// making a dt
|
||||
curr = Lib.getTimer();
|
||||
dt = curr - prev;
|
||||
prev = curr;
|
||||
|
||||
for (symbol in tileSymbols) {
|
||||
symbol.update(dt);
|
||||
}
|
||||
for (symbol in spriteSymbols) {
|
||||
symbol.update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
public function addSpriteGirl(_) {
|
||||
for (i in 0...1) {
|
||||
var t = ss.createAnimation();
|
||||
t.x = mouseX + i * 20 * (-1 * i % 2);
|
||||
t.y = mouseY + i * 20 * (-1 * i % 2);
|
||||
|
||||
addChild(t);
|
||||
t.loopMode = LoopMode.SINGLE_FRAME;
|
||||
|
||||
t.currentLabel = t.getFrameLabels()[Std.random(t.getFrameLabels().length)];
|
||||
spriteSymbols.push(t);
|
||||
trace(spriteSymbols.length);
|
||||
}
|
||||
}
|
||||
|
||||
public function addTileGirl(_) {
|
||||
for (i in 0...1) {
|
||||
var t = aa.createAnimation();
|
||||
t.x = mouseX + i * 5 * (-1 * i % 2);
|
||||
t.y = mouseY + i * 5 * (-1 * i % 2);
|
||||
|
||||
renderer.addTile(t);
|
||||
t.loopMode = LoopMode.SINGLE_FRAME;
|
||||
|
||||
t.currentLabel = t.getFrameLabels()[Std.random(t.getFrameLabels().length)];
|
||||
tileSymbols.push(t);
|
||||
|
||||
trace(tileSymbols.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package animateatlas.displayobject;
|
||||
|
||||
import openfl.display.BitmapData;
|
||||
import animateatlas.JSONData.AnimationData;
|
||||
import animateatlas.JSONData.ElementData;
|
||||
import animateatlas.JSONData.LayerFrameData;
|
||||
import animateatlas.JSONData.LayerData;
|
||||
import animateatlas.JSONData.SymbolTimelineData;
|
||||
import animateatlas.JSONData.Matrix3DData;
|
||||
import animateatlas.JSONData.AtlasData;
|
||||
import animateatlas.JSONData.SymbolData;
|
||||
import animateatlas.JSONData.SpriteData;
|
||||
import animateatlas.HelperEnums.LoopMode;
|
||||
import animateatlas.HelperEnums.SymbolType;
|
||||
import openfl.errors.ArgumentError;
|
||||
|
||||
/**
|
||||
* Performance will be REALLY BAD.
|
||||
* Consider using TileAnimationLibrary whenever possible.
|
||||
*/
|
||||
class SpriteAnimationLibrary {
|
||||
public var frameRate:Float;
|
||||
|
||||
private var _atlas:Map<String, SpriteData>;
|
||||
private var _symbolData:Map<String, SymbolData>;
|
||||
private var _symbolPool:Map<String, Array<SpriteSymbol>>;
|
||||
private var _defaultSymbolName:String;
|
||||
private var _texture:BitmapData;
|
||||
|
||||
public static inline var BITMAP_SYMBOL_NAME:String = "___atlas_sprite___";
|
||||
|
||||
private static var STD_MATRIX3D_DATA:Matrix3DData = {
|
||||
m00: 1,
|
||||
m01: 0,
|
||||
m02: 0,
|
||||
m03: 0,
|
||||
m10: 0,
|
||||
m11: 1,
|
||||
m12: 0,
|
||||
m13: 0,
|
||||
m20: 0,
|
||||
m21: 0,
|
||||
m22: 1,
|
||||
m23: 0,
|
||||
m30: 0,
|
||||
m31: 0,
|
||||
m32: 0,
|
||||
m33: 1
|
||||
};
|
||||
|
||||
public function new(data:AnimationData, atlas:AtlasData, texture:BitmapData) {
|
||||
parseAnimationData(data);
|
||||
parseAtlasData(atlas);
|
||||
_texture = texture;
|
||||
_symbolPool = new Map();
|
||||
}
|
||||
|
||||
public function hasAnimation(name:String):Bool {
|
||||
return hasSymbol(name);
|
||||
}
|
||||
|
||||
public function createAnimation(symbol:String = null):SpriteMovieClip {
|
||||
symbol = (symbol != null) ? symbol : _defaultSymbolName;
|
||||
if (!hasSymbol(symbol)) {
|
||||
throw new ArgumentError("Symbol not found: " + symbol);
|
||||
}
|
||||
return new SpriteMovieClip(getSymbol(symbol));
|
||||
}
|
||||
|
||||
public function getAnimationNames(prefix:String = ""):Array<String> {
|
||||
var out = new Array<String>();
|
||||
|
||||
for (name in _symbolData.keys()) {
|
||||
if (name != BITMAP_SYMBOL_NAME && name.indexOf(prefix) == 0) {
|
||||
out.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
// but... why?
|
||||
out.sort(function(a1, a2):Int {
|
||||
a1 = a1.toLowerCase();
|
||||
a2 = a2.toLowerCase();
|
||||
if (a1 < a2) {
|
||||
return -1;
|
||||
} else if (a1 > a2) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
private function getSpriteData(name:String):SpriteData {
|
||||
return _atlas.get(name);
|
||||
}
|
||||
|
||||
private function hasSymbol(name:String):Bool {
|
||||
return _symbolData.exists(name);
|
||||
}
|
||||
|
||||
// # region Pooling
|
||||
// todo migrate this to lime pool
|
||||
|
||||
@:access(animateatlas)
|
||||
@:allow(AtlasFrameMaker)
|
||||
private function getSymbol(name:String):SpriteSymbol {
|
||||
var pool:Array<SpriteSymbol> = getSymbolPool(name);
|
||||
if (pool.length == 0) {
|
||||
return new SpriteSymbol(getSymbolData(name), this, _texture);
|
||||
} else {
|
||||
return pool.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private function putSymbol(symbol:SpriteSymbol):Void {
|
||||
symbol.reset();
|
||||
var pool:Array<SpriteSymbol> = getSymbolPool(symbol.symbolName);
|
||||
pool.push(symbol);
|
||||
symbol.currentFrame = 0;
|
||||
}
|
||||
|
||||
private function getSymbolPool(name:String):Array<SpriteSymbol> {
|
||||
var pool:Array<SpriteSymbol> = _symbolPool.get(name);
|
||||
if (pool == null) {
|
||||
pool = [];
|
||||
_symbolPool.set(name, pool);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
// # end region
|
||||
// # region helpers
|
||||
private function parseAnimationData(data:AnimationData):Void {
|
||||
var metaData = data.metadata;
|
||||
|
||||
if (metaData != null && metaData.framerate != null && metaData.framerate > 0) {
|
||||
frameRate = (metaData.framerate);
|
||||
} else {
|
||||
frameRate = 24;
|
||||
}
|
||||
|
||||
_symbolData = new Map();
|
||||
|
||||
// the actual symbol dictionary
|
||||
var symbols = data.SYMBOL_DICTIONARY.Symbols;
|
||||
for (symbolData in symbols) {
|
||||
_symbolData[symbolData.SYMBOL_name] = preprocessSymbolData(symbolData);
|
||||
}
|
||||
|
||||
// the main animation
|
||||
var defaultSymbolData:SymbolData = preprocessSymbolData(data.ANIMATION);
|
||||
_defaultSymbolName = defaultSymbolData.SYMBOL_name;
|
||||
_symbolData.set(_defaultSymbolName, defaultSymbolData);
|
||||
|
||||
// a purely internal symbol for bitmaps - simplifies their handling
|
||||
_symbolData.set(BITMAP_SYMBOL_NAME, {
|
||||
SYMBOL_name: BITMAP_SYMBOL_NAME,
|
||||
TIMELINE: {
|
||||
LAYERS: []
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function preprocessSymbolData(symbolData:SymbolData):SymbolData {
|
||||
var timeLineData:SymbolTimelineData = symbolData.TIMELINE;
|
||||
var layerDates:Array<LayerData> = timeLineData.LAYERS;
|
||||
|
||||
// In Animate CC, layers are sorted front to back.
|
||||
// In Starling, it's the other way round - so we simply reverse the layer data.
|
||||
|
||||
if (!timeLineData.sortedForRender) {
|
||||
timeLineData.sortedForRender = true;
|
||||
layerDates.reverse();
|
||||
}
|
||||
|
||||
// We replace all "ATLAS_SPRITE_instance" elements with symbols of the same contents.
|
||||
// That way, we are always only dealing with symbols.
|
||||
|
||||
for (layerData in layerDates) {
|
||||
var frames:Array<LayerFrameData> = layerData.Frames;
|
||||
|
||||
for (frame in frames) {
|
||||
var elements:Array<ElementData> = frame.elements;
|
||||
for (e in 0...elements.length) {
|
||||
var element:ElementData = elements[e];
|
||||
if (element.ATLAS_SPRITE_instance != null) {
|
||||
element = elements[e] = {
|
||||
SYMBOL_Instance: {
|
||||
SYMBOL_name: BITMAP_SYMBOL_NAME,
|
||||
Instance_Name: "InstName",
|
||||
bitmap: element.ATLAS_SPRITE_instance,
|
||||
symbolType: SymbolType.GRAPHIC,
|
||||
firstFrame: 0,
|
||||
loop: LoopMode.LOOP,
|
||||
transformationPoint: {
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
Matrix3D: STD_MATRIX3D_DATA
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return symbolData;
|
||||
}
|
||||
|
||||
private function parseAtlasData(atlas:AtlasData):Void {
|
||||
_atlas = new Map<String, SpriteData>();
|
||||
if (atlas.ATLAS != null && atlas.ATLAS.SPRITES != null) {
|
||||
for (s in atlas.ATLAS.SPRITES) {
|
||||
_atlas.set(s.SPRITE.name, s.SPRITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getSymbolData(name:String):SymbolData {
|
||||
return _symbolData.get(name);
|
||||
}
|
||||
|
||||
// # end region
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package animateatlas.displayobject;
|
||||
|
||||
import openfl.display.Sprite;
|
||||
import animateatlas.HelperEnums.LoopMode;
|
||||
import animateatlas.HelperEnums.SymbolType;
|
||||
|
||||
@:access(animateatlas.displayobject.SpriteSymbol)
|
||||
class SpriteMovieClip extends Sprite {
|
||||
public var framerate(get, set):Float;
|
||||
public var currentLabel(get, set):String;
|
||||
public var currentFrame(get, set):Int;
|
||||
public var type(get, set):String;
|
||||
public var loopMode(get, set):String;
|
||||
public var symbolName(get, never):String;
|
||||
public var numLayers(get, never):Int;
|
||||
public var numFrames(get, never):Int;
|
||||
public var layers(get, never):Array<Sprite>; // ! Dangerous AF.
|
||||
|
||||
private var symbol:SpriteSymbol;
|
||||
private var _framerate:Null<Float> = null;
|
||||
|
||||
private var frameElapsed:Float = 0;
|
||||
|
||||
public function new(symbol:SpriteSymbol) {
|
||||
super();
|
||||
this.symbol = symbol;
|
||||
addChild(this.symbol);
|
||||
}
|
||||
|
||||
public function update(dt:Int) {
|
||||
//
|
||||
var frameDuration:Float = 1000 / framerate;
|
||||
frameElapsed += dt;
|
||||
|
||||
while (frameElapsed > frameDuration) {
|
||||
frameElapsed -= frameDuration;
|
||||
symbol.nextFrame();
|
||||
}
|
||||
while (frameElapsed < -frameDuration) {
|
||||
frameElapsed += frameDuration;
|
||||
symbol.prevFrame();
|
||||
}
|
||||
}
|
||||
|
||||
public function getFrameLabels():Array<String> {
|
||||
return symbol.getFrameLabels();
|
||||
}
|
||||
|
||||
public function getFrame(label:String):Int {
|
||||
return symbol.getFrame(label);
|
||||
}
|
||||
|
||||
// # region Property setter and getter
|
||||
|
||||
private function set_currentLabel(value:String):String {
|
||||
symbol.currentFrame = symbol.getFrame(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_currentLabel():String {
|
||||
return symbol.currentLabel;
|
||||
}
|
||||
|
||||
|
||||
private function set_currentFrame(value:Int):Int {
|
||||
symbol.currentFrame = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_currentFrame():Int {
|
||||
return symbol.currentFrame;
|
||||
}
|
||||
|
||||
private function set_type(value:SymbolType):SymbolType {
|
||||
symbol.type = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_type():SymbolType {
|
||||
return symbol.type;
|
||||
}
|
||||
|
||||
private function set_loopMode(value:LoopMode):LoopMode {
|
||||
symbol.loopMode = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_loopMode():LoopMode {
|
||||
return symbol.loopMode;
|
||||
}
|
||||
|
||||
private function get_symbolName():String {
|
||||
return symbol.symbolName;
|
||||
}
|
||||
|
||||
private function get_numLayers():Int {
|
||||
return symbol.numLayers;
|
||||
}
|
||||
|
||||
private function get_numFrames():Int {
|
||||
return symbol.numFrames;
|
||||
}
|
||||
|
||||
private function get_layers():Array<Sprite> {
|
||||
return symbol._layers;
|
||||
}
|
||||
|
||||
private function set_framerate(value:Float):Float {
|
||||
return _framerate = value;
|
||||
}
|
||||
|
||||
private function get_framerate():Float {
|
||||
return _framerate == null ? symbol._library.frameRate : _framerate;
|
||||
}
|
||||
|
||||
// # end region
|
||||
}
|
||||
@@ -0,0 +1,540 @@
|
||||
package animateatlas.displayobject;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import openfl.filters.GlowFilter;
|
||||
import openfl.filters.BlurFilter;
|
||||
import openfl.display.PixelSnapping;
|
||||
import openfl.geom.Point;
|
||||
import openfl.display.BitmapData;
|
||||
import openfl.display.Bitmap;
|
||||
import openfl.display.Sprite;
|
||||
import openfl.errors.ArgumentError;
|
||||
import openfl.geom.Rectangle;
|
||||
import openfl.errors.Error;
|
||||
import animateatlas.JSONData.ElementData;
|
||||
import animateatlas.HelperEnums.LoopMode;
|
||||
import animateatlas.HelperEnums.SymbolType;
|
||||
import openfl.display.FrameLabel;
|
||||
import animateatlas.JSONData.SymbolData;
|
||||
import animateatlas.JSONData.SymbolInstanceData;
|
||||
import animateatlas.JSONData.LayerData;
|
||||
import animateatlas.JSONData.BitmapPosData;
|
||||
import animateatlas.JSONData.Matrix3DData;
|
||||
import animateatlas.JSONData.LayerFrameData;
|
||||
import animateatlas.JSONData.ColorData;
|
||||
import openfl.geom.Matrix;
|
||||
import openfl.geom.ColorTransform;
|
||||
import animateatlas.JSONData.FilterData;
|
||||
|
||||
class SpriteSymbol extends Sprite {
|
||||
public var currentLabel(get, never):String;
|
||||
public var currentFrame(get, set):Int;
|
||||
public var type(get, set):String;
|
||||
public var loopMode(get, set):String;
|
||||
public var symbolName(get, never):String;
|
||||
public var numLayers(get, never):Int;
|
||||
public var numFrames(get, never):Int;
|
||||
|
||||
private var _data:SymbolData;
|
||||
private var _library:SpriteAnimationLibrary;
|
||||
private var _symbolName:String;
|
||||
private var _type:String;
|
||||
private var _loopMode:String;
|
||||
|
||||
private var _currentFrame:Int;
|
||||
private var _composedFrame:Int;
|
||||
private var _bitmap:Bitmap;
|
||||
private var _numFrames:Int;
|
||||
private var _numLayers:Int;
|
||||
private var _frameLabels:Array<FrameLabel>;
|
||||
private var _colorTransform:ColorTransform;
|
||||
private var _layers:Array<Sprite>;
|
||||
private var _texture:BitmapData;
|
||||
private var _tempRect = new Rectangle();
|
||||
private var _zeroPoint = new Point(0, 0);
|
||||
private var filterHelper:BitmapData;
|
||||
public var smoothing:Bool = true;
|
||||
|
||||
private static var sMatrix:Matrix = new Matrix();
|
||||
|
||||
private function new(data:SymbolData, library:SpriteAnimationLibrary, texture:BitmapData) {
|
||||
super();
|
||||
_data = data;
|
||||
_library = library;
|
||||
_composedFrame = -1;
|
||||
_numLayers = data.TIMELINE.LAYERS.length;
|
||||
_numFrames = getNumFrames();
|
||||
_frameLabels = _getFrameLabels();
|
||||
_symbolName = data.SYMBOL_name;
|
||||
_type = SymbolType.GRAPHIC;
|
||||
_loopMode = LoopMode.LOOP;
|
||||
_texture = texture;
|
||||
|
||||
createLayers();
|
||||
|
||||
// Create FrameMap caches if don't exist
|
||||
for (layer in data.TIMELINE.LAYERS) {
|
||||
if (layer.FrameMap != null)
|
||||
return;
|
||||
|
||||
var map = new Map();
|
||||
|
||||
for (i in 0...layer.Frames.length) {
|
||||
var frame = layer.Frames[i];
|
||||
for (j in 0...frame.duration) {
|
||||
map.set(i + j, frame);
|
||||
}
|
||||
}
|
||||
|
||||
layer.FrameMap = map;
|
||||
}
|
||||
}
|
||||
|
||||
public function reset():Void {
|
||||
sMatrix.identity();
|
||||
transform.matrix = sMatrix.clone();
|
||||
alpha = 1.0;
|
||||
_currentFrame = 0;
|
||||
_composedFrame = -1;
|
||||
}
|
||||
|
||||
public function nextFrame():Void {
|
||||
if (_loopMode != LoopMode.SINGLE_FRAME) {
|
||||
currentFrame += 1;
|
||||
}
|
||||
|
||||
moveMovieclip_MovieClips(1);
|
||||
}
|
||||
|
||||
public function prevFrame():Void {
|
||||
if (_loopMode != LoopMode.SINGLE_FRAME) {
|
||||
currentFrame -= 1;
|
||||
}
|
||||
|
||||
moveMovieclip_MovieClips(-1);
|
||||
}
|
||||
|
||||
/** Moves all movie clips n frames, recursively. */
|
||||
private function moveMovieclip_MovieClips(direction:Int = 1):Void {
|
||||
if (_type == SymbolType.MOVIE_CLIP) {
|
||||
currentFrame += direction;
|
||||
}
|
||||
|
||||
for (l in 0..._numLayers) {
|
||||
var layer:Sprite = getLayer(l);
|
||||
var numElements:Int = layer.numChildren;
|
||||
|
||||
for (e in 0...numElements) {
|
||||
(try cast(layer.getChildAt(e), SpriteSymbol) catch (e:Dynamic) null).moveMovieclip_MovieClips(direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function update():Void {
|
||||
for (i in 0..._numLayers) {
|
||||
updateLayer(i);
|
||||
}
|
||||
|
||||
_composedFrame = _currentFrame;
|
||||
}
|
||||
|
||||
@:access(animateatlas)
|
||||
private function updateLayer(layerIndex:Int):Void {
|
||||
var layer:Sprite = getLayer(layerIndex);
|
||||
var frameData:LayerFrameData = getFrameData(layerIndex, _currentFrame);
|
||||
var elements:Array<ElementData> = (frameData != null) ? frameData.elements : null;
|
||||
var numElements:Int = (elements != null) ? elements.length : 0;
|
||||
for (i in 0...numElements) {
|
||||
var elementData:SymbolInstanceData = elements[i].SYMBOL_Instance;
|
||||
|
||||
if (elementData == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// this is confusing but needed :(
|
||||
var oldSymbol:SpriteSymbol = (layer.numChildren > i) ? try
|
||||
cast(layer.getChildAt(i), SpriteSymbol)
|
||||
catch (e:Dynamic)
|
||||
null : null;
|
||||
|
||||
var newSymbol:SpriteSymbol = null;
|
||||
|
||||
var symbolName:String = elementData.SYMBOL_name;
|
||||
|
||||
if (!_library.hasSymbol(symbolName)) {
|
||||
symbolName = SpriteAnimationLibrary.BITMAP_SYMBOL_NAME;
|
||||
}
|
||||
|
||||
if (oldSymbol != null && oldSymbol._symbolName == symbolName) {
|
||||
newSymbol = oldSymbol;
|
||||
} else {
|
||||
if (oldSymbol != null) {
|
||||
if (oldSymbol.parent != null)
|
||||
oldSymbol.removeChild(oldSymbol);
|
||||
_library.putSymbol(oldSymbol);
|
||||
}
|
||||
|
||||
newSymbol = cast(_library.getSymbol(symbolName));
|
||||
layer.addChildAt(newSymbol, i);
|
||||
}
|
||||
|
||||
newSymbol.setTransformationMatrix(elementData.Matrix3D);
|
||||
newSymbol.setBitmap(elementData.bitmap);
|
||||
newSymbol.setFilterData(elementData.filters);
|
||||
newSymbol.setColor(elementData.color);
|
||||
newSymbol.setLoop(elementData.loop);
|
||||
newSymbol.setType(elementData.symbolType);
|
||||
|
||||
|
||||
|
||||
if (newSymbol.type == SymbolType.GRAPHIC) {
|
||||
var firstFrame:Int = elementData.firstFrame;
|
||||
var frameAge:Int = Std.int(_currentFrame - frameData.index);
|
||||
|
||||
if (newSymbol.loopMode == LoopMode.SINGLE_FRAME) {
|
||||
newSymbol.currentFrame = firstFrame;
|
||||
} else if (newSymbol.loopMode == LoopMode.LOOP) {
|
||||
newSymbol.currentFrame = (firstFrame + frameAge) % newSymbol._numFrames;
|
||||
} else {
|
||||
newSymbol.currentFrame = firstFrame + frameAge;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var numObsoleteSymbols:Int = (layer.numChildren - numElements);
|
||||
|
||||
for (i in 0...numObsoleteSymbols) {
|
||||
try {
|
||||
var oldSymbol = cast(layer.removeChildAt(numElements), SpriteSymbol);
|
||||
if (oldSymbol != null)
|
||||
_library.putSymbol(oldSymbol);
|
||||
} catch (e:Dynamic) {};
|
||||
}
|
||||
}
|
||||
|
||||
private function createLayers():Void {
|
||||
// todo safety check for not initialiing twice
|
||||
if (_layers != null) {
|
||||
throw new Error("You must not call this twice");
|
||||
}
|
||||
_layers = new Array<Sprite>();
|
||||
|
||||
if (_numLayers <= 1) {
|
||||
_layers.push(this);
|
||||
} else {
|
||||
for (i in 0..._numLayers) {
|
||||
var layer:Sprite = new Sprite();
|
||||
layer.name = getLayerData(i).Layer_name;
|
||||
addChild(layer);
|
||||
_layers.push(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@:access(animateatlas)
|
||||
public function setBitmap(data:BitmapPosData):Void {
|
||||
if (data != null) {
|
||||
var spriteData = _library.getSpriteData(data.name + "");
|
||||
|
||||
if (_bitmap == null) {
|
||||
_bitmap = new Bitmap(new BitmapData(1, 1), PixelSnapping.AUTO, smoothing);
|
||||
addChild(_bitmap);
|
||||
}
|
||||
|
||||
if (_tempRect.x != spriteData.x || _tempRect.y != spriteData.y || _tempRect.width != spriteData.w || _tempRect.height != spriteData.h) {
|
||||
var clippedTexture = new BitmapData(spriteData.w, spriteData.h);
|
||||
_tempRect.setTo(spriteData.x, spriteData.y, spriteData.w, spriteData.h);
|
||||
clippedTexture.copyPixels(_texture, _tempRect, _zeroPoint);
|
||||
_bitmap.bitmapData = clippedTexture;
|
||||
_bitmap.smoothing = smoothing;
|
||||
|
||||
|
||||
}
|
||||
// aditional checks for rotation
|
||||
if (spriteData.rotated) {
|
||||
_bitmap.rotation = -90;
|
||||
_bitmap.x = data.Position.x;
|
||||
_bitmap.y = data.Position.y + spriteData.w;
|
||||
} else {
|
||||
_bitmap.rotation = 0;
|
||||
_bitmap.x = data.Position.x;
|
||||
_bitmap.y = data.Position.y;
|
||||
}
|
||||
|
||||
addChildAt(_bitmap, 0);
|
||||
} else if (_bitmap != null) {
|
||||
if (_bitmap.parent != null)
|
||||
_bitmap.parent.removeChild(_bitmap);
|
||||
}
|
||||
}
|
||||
@:access(animateatlas)
|
||||
private function setFilterData(data:FilterData):Void{
|
||||
var blur:BlurFilter;
|
||||
var glow:GlowFilter;
|
||||
if (data != null){
|
||||
if (data.BlurFilter != null){
|
||||
blur = new BlurFilter();
|
||||
blur.blurX = data.BlurFilter.blurX;
|
||||
blur.blurY = data.BlurFilter.blurY;
|
||||
blur.quality = data.BlurFilter.quality;
|
||||
//_bitmap.bitmapData.applyFilter(_bitmap.bitmapData,new Rectangle(0,0,_bitmap.bitmapData.width,_bitmap.bitmapData.height),new Point(0,0),blur);
|
||||
//filters.push(blur);
|
||||
}
|
||||
if (data.GlowFilter != null){
|
||||
//trace('GLOW' + data.GlowFilter);
|
||||
//glow = new GlowFilter();
|
||||
//glow.blurX = data.GlowFilter.blurX;
|
||||
//glow.blurY = data.GlowFilter.blurY;
|
||||
//glow.color = data.GlowFilter.color;
|
||||
//glow.alpha = data.GlowFilter.alpha;
|
||||
//glow.quality = data.GlowFilter.quality;
|
||||
//glow.strength = data.GlowFilter.strength;
|
||||
//glow.knockout = data.GlowFilter.knockout;
|
||||
//glow.inner = data.GlowFilter.inner;
|
||||
//filters.push(glow);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function setTransformationMatrix(data:Matrix3DData):Void {
|
||||
sMatrix.setTo(data.m00, data.m01, data.m10, data.m11, data.m30, data.m31);
|
||||
if (sMatrix.a != transform.matrix.a || sMatrix.b != transform.matrix.b || sMatrix.c != transform.matrix.c || sMatrix.d != transform.matrix.d
|
||||
|| sMatrix.tx != transform.matrix.tx || sMatrix.ty != transform.matrix.ty)
|
||||
transform.matrix = sMatrix.clone(); // todo stop the cloning :(
|
||||
}
|
||||
|
||||
private function setColor(data:ColorData):Void {
|
||||
var newTransform = new ColorTransform();
|
||||
if (data != null) {
|
||||
newTransform.redOffset = (data.redOffset == null ? 0 : data.redOffset);
|
||||
newTransform.greenOffset = (data.greenOffset == null ? 0 : data.greenOffset);
|
||||
newTransform.blueOffset = (data.blueOffset == null ? 0 : data.blueOffset);
|
||||
newTransform.alphaOffset = (data.AlphaOffset == null ? 0 : data.AlphaOffset);
|
||||
|
||||
newTransform.redMultiplier = (data.RedMultiplier == null ? 1 : data.RedMultiplier);
|
||||
newTransform.greenMultiplier = (data.greenMultiplier == null ? 1 : data.greenMultiplier);
|
||||
newTransform.blueMultiplier = (data.blueMultiplier == null ? 1 : data.blueMultiplier);
|
||||
newTransform.alphaMultiplier = (data.alphaMultiplier == null ? 1 : data.alphaMultiplier);
|
||||
|
||||
|
||||
if (data.mode == "Tint"){//Tint color effect
|
||||
var color:FlxColor = Std.parseInt(StringTools.replace(data.tintColor, "#", "0xFF"));
|
||||
|
||||
|
||||
newTransform.redMultiplier = 0;
|
||||
newTransform.greenMultiplier = 0;//(data.greenMultiplier == null ? 1 : data.greenMultiplier);
|
||||
newTransform.blueMultiplier = 0;//(data.blueMultiplier == null ? 1 : data.blueMultiplier);
|
||||
newTransform.redOffset = color.red*data.tintMultiplier;
|
||||
newTransform.greenOffset = color.green * data.tintMultiplier;//(data.greenMultiplier == null ? 1 : data.greenMultiplier);
|
||||
newTransform.blueOffset = color.blue * data.tintMultiplier;//(data.blueMultiplier == null ? 1 : data.blueMultiplier);
|
||||
}
|
||||
|
||||
}
|
||||
transform.colorTransform = newTransform;
|
||||
|
||||
}
|
||||
|
||||
private function setLoop(data:String):Void {
|
||||
if (data != null) {
|
||||
_loopMode = data;
|
||||
} else {
|
||||
_loopMode = LoopMode.LOOP;
|
||||
}
|
||||
}
|
||||
|
||||
private function setType(data:String):Void {
|
||||
if (data != null) {
|
||||
_type = data;
|
||||
}
|
||||
}
|
||||
|
||||
private function getNumFrames():Int {
|
||||
var numFrames:Int = 0;
|
||||
|
||||
for (i in 0..._numLayers) {
|
||||
var layer = getLayerData(i);
|
||||
var frameDates:Array<LayerFrameData> = (layer == null ? [] : layer.Frames);
|
||||
var numFrameDates:Int = (frameDates != null) ? frameDates.length : 0;
|
||||
var layerNumFrames:Int = (numFrameDates != 0) ? frameDates[0].index : 0;
|
||||
|
||||
for (j in 0...numFrameDates) {
|
||||
layerNumFrames += frameDates[j].duration;
|
||||
}
|
||||
|
||||
if (layerNumFrames > numFrames) {
|
||||
numFrames = layerNumFrames;
|
||||
}
|
||||
}
|
||||
|
||||
return numFrames == 0 ? 1 : numFrames;
|
||||
}
|
||||
|
||||
private function _getFrameLabels():Array<FrameLabel> {
|
||||
var labels:Array<FrameLabel> = [];
|
||||
|
||||
for (i in 0..._numLayers) {
|
||||
var layer = getLayerData(i);
|
||||
var frameDates:Array<LayerFrameData> = (layer == null ? [] : layer.Frames);
|
||||
var numFrameDates:Int = (frameDates != null) ? frameDates.length : 0;
|
||||
|
||||
for (j in 0...numFrameDates) {
|
||||
var frameData:LayerFrameData = frameDates[j];
|
||||
if (frameData.name != null) {
|
||||
labels.push(new FrameLabel(frameData.name, frameData.index));
|
||||
}
|
||||
}
|
||||
}
|
||||
labels.sort(sortLabels);
|
||||
return labels;
|
||||
}
|
||||
|
||||
public function getFrameLabels():Array<String> {
|
||||
return _frameLabels.map(f -> f.name); // Inlining. I feel a js
|
||||
}
|
||||
|
||||
|
||||
|
||||
function sortLabels(i1:FrameLabel, i2:FrameLabel):Int {
|
||||
var f1 = i1.frame;
|
||||
var f2 = i2.frame;
|
||||
if (f1 < f2) {
|
||||
return -1;
|
||||
} else if (f1 > f2) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private function getLayer(layerIndex:Int):Sprite {
|
||||
return _layers[layerIndex];
|
||||
}
|
||||
|
||||
public function getTexture():BitmapData{
|
||||
//THIS GETS THE ENTIRE THING I'M RETARDED LOL
|
||||
return _texture;
|
||||
}
|
||||
|
||||
public function getNextLabel(afterLabel:String = null):String {
|
||||
var numLabels:Int = _frameLabels.length;
|
||||
var startFrame:Int = getFrame(afterLabel == null ? currentLabel : afterLabel);
|
||||
|
||||
for (i in 0...numLabels) {
|
||||
var label:FrameLabel = _frameLabels[i];
|
||||
if (label.frame > startFrame) {
|
||||
return label.name;
|
||||
}
|
||||
}
|
||||
|
||||
return (_frameLabels != null) ? _frameLabels[0].name : null;
|
||||
}
|
||||
|
||||
private function get_currentLabel():String {
|
||||
var numLabels:Int = _frameLabels.length;
|
||||
var highestLabel:FrameLabel = (numLabels != 0) ? _frameLabels[0] : null;
|
||||
|
||||
for (i in 1...numLabels) {
|
||||
var label:FrameLabel = _frameLabels[i];
|
||||
|
||||
if (label.frame <= _currentFrame) {
|
||||
highestLabel = label;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (highestLabel != null) ? highestLabel.name : null;
|
||||
}
|
||||
|
||||
public function getFrame(label:String):Int {
|
||||
var numLabels:Int = _frameLabels.length;
|
||||
for (i in 0...numLabels) {
|
||||
var frameLabel:FrameLabel = _frameLabels[i];
|
||||
if (frameLabel.name == label) {
|
||||
return frameLabel.frame;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private function get_currentFrame():Int {
|
||||
return _currentFrame;
|
||||
}
|
||||
|
||||
private function set_currentFrame(value:Int):Int {
|
||||
while (value < 0) {
|
||||
value += _numFrames;
|
||||
}
|
||||
|
||||
if (_loopMode == LoopMode.PLAY_ONCE) {
|
||||
_currentFrame = Std.int(Math.min(Math.max(value, 0), _numFrames - 1));
|
||||
} else {
|
||||
_currentFrame = Std.int(Math.abs(value % _numFrames));
|
||||
}
|
||||
|
||||
if (_composedFrame != _currentFrame) {
|
||||
update();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_type():String {
|
||||
return _type;
|
||||
}
|
||||
|
||||
private function set_type(value:String):String {
|
||||
if (SymbolType.isValid(value)) {
|
||||
_type = value;
|
||||
} else {
|
||||
throw new ArgumentError("Invalid symbol type: " + value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_loopMode():String {
|
||||
return _loopMode;
|
||||
}
|
||||
|
||||
private function set_loopMode(value:String):String {
|
||||
if (LoopMode.isValid(value)) {
|
||||
_loopMode = value;
|
||||
} else {
|
||||
throw new ArgumentError("Invalid loop mode: " + value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_symbolName():String {
|
||||
return _symbolName;
|
||||
}
|
||||
|
||||
private function get_numLayers():Int {
|
||||
return _numLayers;
|
||||
}
|
||||
|
||||
private function get_numFrames():Int {
|
||||
return _numFrames;
|
||||
}
|
||||
|
||||
// data access
|
||||
|
||||
private function getLayerData(layerIndex:Int):LayerData {
|
||||
return _data.TIMELINE.LAYERS[layerIndex];
|
||||
}
|
||||
|
||||
private function getFrameData(layerIndex:Int, frameIndex:Int):LayerFrameData {
|
||||
var layer = getLayerData(layerIndex);
|
||||
if (layer == null)
|
||||
return null;
|
||||
|
||||
return layer.FrameMap.get(frameIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
package animateatlas.tilecontainer;
|
||||
|
||||
import openfl.display.Tileset;
|
||||
import haxe.Constraints.Constructible;
|
||||
import openfl.display.BitmapData;
|
||||
import animateatlas.JSONData.AnimationData;
|
||||
import animateatlas.JSONData.ElementData;
|
||||
import animateatlas.JSONData.LayerFrameData;
|
||||
import animateatlas.JSONData.LayerData;
|
||||
import animateatlas.JSONData.SymbolTimelineData;
|
||||
import animateatlas.JSONData.Matrix3DData;
|
||||
import animateatlas.JSONData.AtlasData;
|
||||
import animateatlas.JSONData.SymbolData;
|
||||
import animateatlas.JSONData.SpriteData;
|
||||
import animateatlas.HelperEnums.LoopMode;
|
||||
import animateatlas.HelperEnums.SymbolType;
|
||||
import openfl.errors.ArgumentError;
|
||||
|
||||
/**
|
||||
* Since we can extract symbols from the exported timeline and instance them separatedly, this keeps track of all symbols.
|
||||
* Also, this is a "more readable" way of understanding the AnimationData
|
||||
*/
|
||||
class TileAnimationLibrary {
|
||||
public var frameRate:Float;
|
||||
|
||||
private var _atlas:Map<String, SpriteData>;
|
||||
private var _symbolData:Map<String, SymbolData>;
|
||||
private var _symbolPool:Map<String, Array<TileContainerSymbol>>;
|
||||
private var _defaultSymbolName:String;
|
||||
private var _texture:Tileset;
|
||||
|
||||
public static inline var BITMAP_SYMBOL_NAME:String = "___atlas_sprite___";
|
||||
|
||||
private static var STD_MATRIX3D_DATA:Matrix3DData = {
|
||||
m00: 1,
|
||||
m01: 0,
|
||||
m02: 0,
|
||||
m03: 0,
|
||||
m10: 0,
|
||||
m11: 1,
|
||||
m12: 0,
|
||||
m13: 0,
|
||||
m20: 0,
|
||||
m21: 0,
|
||||
m22: 1,
|
||||
m23: 0,
|
||||
m30: 0,
|
||||
m31: 0,
|
||||
m32: 0,
|
||||
m33: 1
|
||||
};
|
||||
|
||||
public function new(data:AnimationData, atlas:AtlasData, texture:BitmapData) {
|
||||
parseAnimationData(data);
|
||||
parseAtlasData(atlas);
|
||||
_texture = new Tileset(texture);
|
||||
_symbolPool = new Map();
|
||||
}
|
||||
|
||||
public function hasAnimation(name:String):Bool {
|
||||
return hasSymbol(name);
|
||||
}
|
||||
|
||||
public function createAnimation(symbol:String = null):TileContainerMovieClip {
|
||||
symbol = (symbol != null) ? symbol : _defaultSymbolName;
|
||||
if (!hasSymbol(symbol)) {
|
||||
throw new ArgumentError("Symbol not found: " + symbol);
|
||||
}
|
||||
return new TileContainerMovieClip(getSymbol(symbol));
|
||||
}
|
||||
|
||||
public function getAnimationNames(prefix:String = ""):Array<String> {
|
||||
var out = new Array<String>();
|
||||
|
||||
for (name in _symbolData.keys()) {
|
||||
if (name != BITMAP_SYMBOL_NAME && name.indexOf(prefix) == 0) {
|
||||
out.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
// but... why?
|
||||
out.sort(function(a1, a2):Int {
|
||||
a1 = a1.toLowerCase();
|
||||
a2 = a2.toLowerCase();
|
||||
if (a1 < a2) {
|
||||
return -1;
|
||||
} else if (a1 > a2) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
private function getSpriteData(name:String):SpriteData {
|
||||
return _atlas.get(name);
|
||||
}
|
||||
|
||||
private function hasSymbol(name:String):Bool {
|
||||
return _symbolData.exists(name);
|
||||
}
|
||||
|
||||
// # region Pooling
|
||||
// todo migrate this to lime pool
|
||||
|
||||
@:access(animateatlas)
|
||||
private function getSymbol(name:String):TileContainerSymbol {
|
||||
var pool:Array<TileContainerSymbol> = getSymbolPool(name);
|
||||
if (pool.length == 0) {
|
||||
return new TileContainerSymbol(getSymbolData(name), this, _texture);
|
||||
} else {
|
||||
return pool.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private function putSymbol(symbol:TileContainerSymbol):Void {
|
||||
symbol.reset();
|
||||
var pool:Array<TileContainerSymbol> = getSymbolPool(symbol.symbolName);
|
||||
pool.push(symbol);
|
||||
symbol.currentFrame = 0;
|
||||
}
|
||||
|
||||
private function getSymbolPool(name:String):Array<TileContainerSymbol> {
|
||||
var pool:Array<TileContainerSymbol> = _symbolPool.get(name);
|
||||
if (pool == null) {
|
||||
pool = [];
|
||||
_symbolPool.set(name, pool);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
// # end region
|
||||
// # region helpers
|
||||
private function parseAnimationData(data:AnimationData):Void {
|
||||
var metaData = data.metadata;
|
||||
|
||||
if (metaData != null && metaData.framerate != null && metaData.framerate > 0) {
|
||||
frameRate = (metaData.framerate);
|
||||
} else {
|
||||
frameRate = 24;
|
||||
}
|
||||
|
||||
_symbolData = new Map();
|
||||
|
||||
// the actual symbol dictionary
|
||||
var symbols = data.SYMBOL_DICTIONARY.Symbols;
|
||||
for (symbolData in symbols) {
|
||||
_symbolData[symbolData.SYMBOL_name] = preprocessSymbolData(symbolData);
|
||||
}
|
||||
|
||||
// the main animation
|
||||
var defaultSymbolData:SymbolData = preprocessSymbolData(data.ANIMATION);
|
||||
_defaultSymbolName = defaultSymbolData.SYMBOL_name;
|
||||
_symbolData.set(_defaultSymbolName, defaultSymbolData);
|
||||
|
||||
// a purely internal symbol for bitmaps - simplifies their handling
|
||||
_symbolData.set(BITMAP_SYMBOL_NAME, {
|
||||
SYMBOL_name: BITMAP_SYMBOL_NAME,
|
||||
TIMELINE: {
|
||||
LAYERS: []
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function preprocessSymbolData(symbolData:SymbolData):SymbolData {
|
||||
var timeLineData:SymbolTimelineData = symbolData.TIMELINE;
|
||||
var layerDates:Array<LayerData> = timeLineData.LAYERS;
|
||||
|
||||
// In Animate CC, layers are sorted front to back.
|
||||
// In Starling, it's the other way round - so we simply reverse the layer data.
|
||||
|
||||
if (!timeLineData.sortedForRender) {
|
||||
timeLineData.sortedForRender = true;
|
||||
layerDates.reverse();
|
||||
}
|
||||
|
||||
// We replace all "ATLAS_SPRITE_instance" elements with symbols of the same contents.
|
||||
// That way, we are always only dealing with symbols.
|
||||
|
||||
for (layerData in layerDates) {
|
||||
var frames:Array<LayerFrameData> = layerData.Frames;
|
||||
|
||||
for (frame in frames) {
|
||||
var elements:Array<ElementData> = frame.elements;
|
||||
for (e in 0...elements.length) {
|
||||
var element:ElementData = elements[e];
|
||||
if (element.ATLAS_SPRITE_instance != null) {
|
||||
element = elements[e] = {
|
||||
SYMBOL_Instance: {
|
||||
SYMBOL_name: BITMAP_SYMBOL_NAME,
|
||||
Instance_Name: "InstName",
|
||||
bitmap: element.ATLAS_SPRITE_instance,
|
||||
symbolType: SymbolType.GRAPHIC,
|
||||
firstFrame: 0,
|
||||
loop: LoopMode.LOOP,
|
||||
transformationPoint: {
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
Matrix3D: STD_MATRIX3D_DATA
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return symbolData;
|
||||
}
|
||||
|
||||
private function parseAtlasData(atlas:AtlasData):Void {
|
||||
_atlas = new Map<String, SpriteData>();
|
||||
if (atlas.ATLAS != null && atlas.ATLAS.SPRITES != null) {
|
||||
for (s in atlas.ATLAS.SPRITES) {
|
||||
_atlas.set(s.SPRITE.name, s.SPRITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getSymbolData(name:String):SymbolData {
|
||||
return _symbolData.get(name);
|
||||
}
|
||||
|
||||
// # end region
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package animateatlas.tilecontainer;
|
||||
|
||||
import animateatlas.HelperEnums.LoopMode;
|
||||
import animateatlas.HelperEnums.SymbolType;
|
||||
import openfl.display.TileContainer;
|
||||
|
||||
@:access(animateatlas.tilecontainer.TileContainerSymbol)
|
||||
class TileContainerMovieClip extends TileContainer {
|
||||
public var framerate(get, set):Float;
|
||||
public var currentLabel(get, set):String;
|
||||
public var currentFrame(get, set):Int;
|
||||
public var type(get, set):String;
|
||||
public var loopMode(get, set):String;
|
||||
public var symbolName(get, never):String;
|
||||
public var numLayers(get, never):Int;
|
||||
public var numFrames(get, never):Int;
|
||||
public var layers(get, never):Array<TileContainer>; // ! Dangerous AF.
|
||||
|
||||
private var symbol:TileContainerSymbol;
|
||||
private var _framerate:Null<Float> = null;
|
||||
|
||||
private var frameElapsed:Float = 0;
|
||||
|
||||
public function new(symbol:TileContainerSymbol) {
|
||||
super();
|
||||
this.symbol = symbol;
|
||||
addTile(this.symbol);
|
||||
}
|
||||
|
||||
public function update(dt:Int) {
|
||||
var frameDuration:Float = 1000 / framerate;
|
||||
frameElapsed += dt;
|
||||
|
||||
while (frameElapsed > frameDuration) {
|
||||
frameElapsed -= frameDuration;
|
||||
symbol.nextFrame();
|
||||
}
|
||||
while (frameElapsed < -frameDuration) {
|
||||
frameElapsed += frameDuration;
|
||||
symbol.prevFrame();
|
||||
}
|
||||
}
|
||||
|
||||
public function getFrameLabels():Array<String> {
|
||||
return symbol.getFrameLabels();
|
||||
}
|
||||
|
||||
public function getFrame(label:String):Int {
|
||||
return symbol.getFrame(label);
|
||||
}
|
||||
public function getFramesofAnim(label:String):Int {
|
||||
var framesArray:Array<Int>;
|
||||
var uncalculatedArray:Array<Int> = [];
|
||||
var uncalculatedFrames:Int = 0;
|
||||
|
||||
for (i in 0...getFrameLabels().length){
|
||||
uncalculatedArray.push(getFrame(getFrameLabels()[i]));
|
||||
}
|
||||
|
||||
|
||||
uncalculatedFrames = uncalculatedArray[0]+uncalculatedArray.length;
|
||||
|
||||
return uncalculatedFrames;
|
||||
}
|
||||
|
||||
// # region Property setter and getter
|
||||
|
||||
private function set_currentLabel(value:String):String {
|
||||
symbol.currentFrame = symbol.getFrame(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_currentLabel():String {
|
||||
return symbol.currentLabel;
|
||||
}
|
||||
|
||||
private function set_currentFrame(value:Int):Int {
|
||||
symbol.currentFrame = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
public function get_animFrames():Int{
|
||||
return symbol.get_numFrames();
|
||||
}
|
||||
|
||||
|
||||
private function get_currentFrame():Int {
|
||||
return symbol.currentFrame;
|
||||
}
|
||||
|
||||
private function set_type(value:SymbolType):SymbolType {
|
||||
symbol.type = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_type():SymbolType {
|
||||
return symbol.type;
|
||||
}
|
||||
|
||||
private function set_loopMode(value:LoopMode):LoopMode {
|
||||
symbol.loopMode = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_loopMode():LoopMode {
|
||||
return symbol.loopMode;
|
||||
}
|
||||
|
||||
private function get_symbolName():String {
|
||||
return symbol.symbolName;
|
||||
}
|
||||
|
||||
public function get_numLayers():Int {
|
||||
return symbol.numLayers;
|
||||
}
|
||||
|
||||
private function get_numFrames():Int {
|
||||
return symbol.numFrames;
|
||||
}
|
||||
|
||||
|
||||
public function get_layers():Array<TileContainer> {
|
||||
return symbol._layers;
|
||||
}
|
||||
|
||||
private function set_framerate(value:Float):Float {
|
||||
return _framerate = value;
|
||||
}
|
||||
|
||||
private function get_framerate():Float {
|
||||
return _framerate == null ? symbol._library.frameRate : _framerate;
|
||||
}
|
||||
|
||||
// # end region
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
package animateatlas.tilecontainer;
|
||||
|
||||
import openfl.display.Tileset;
|
||||
import animateatlas.JSONData.PointData;
|
||||
import openfl.errors.ArgumentError;
|
||||
import openfl.geom.Rectangle;
|
||||
import openfl.errors.Error;
|
||||
import animateatlas.JSONData.ElementData;
|
||||
import animateatlas.HelperEnums.LoopMode;
|
||||
import animateatlas.HelperEnums.SymbolType;
|
||||
import openfl.display.FrameLabel;
|
||||
import animateatlas.JSONData.SymbolData;
|
||||
import animateatlas.JSONData.SymbolInstanceData;
|
||||
import animateatlas.JSONData.LayerData;
|
||||
import animateatlas.JSONData.BitmapPosData;
|
||||
import animateatlas.JSONData.Matrix3DData;
|
||||
import animateatlas.JSONData.LayerFrameData;
|
||||
import animateatlas.JSONData.ColorData;
|
||||
import openfl.geom.Matrix;
|
||||
import openfl.geom.ColorTransform;
|
||||
import openfl.display.DisplayObjectContainer;
|
||||
import openfl.display.TileContainer;
|
||||
import openfl.display.Tile;
|
||||
|
||||
class TileContainerSymbol extends TileContainer {
|
||||
public var currentLabel(get, never):String;
|
||||
public var currentFrame(get, set):Int;
|
||||
public var type(get, set):String;
|
||||
public var loopMode(get, set):String;
|
||||
public var symbolName(get, never):String;
|
||||
public var numLayers(get, never):Int;
|
||||
public var numFrames(get, never):Int;
|
||||
|
||||
private var _data:SymbolData;
|
||||
private var _library:TileAnimationLibrary;
|
||||
private var _symbolName:String;
|
||||
private var _type:String;
|
||||
private var _loopMode:String;
|
||||
private var _currentFrame:Int;
|
||||
private var _composedFrame:Int;
|
||||
private var _bitmap:Tile;
|
||||
private var _numFrames:Int;
|
||||
private var _numLayers:Int;
|
||||
private var _frameLabels:Array<FrameLabel>;
|
||||
private var _colorTransform:ColorTransform;
|
||||
private var _layers:Array<TileContainer>;
|
||||
|
||||
private function new(data:SymbolData, library:TileAnimationLibrary, tileset:Tileset) {
|
||||
super();
|
||||
this.tileset = tileset;
|
||||
_data = data;
|
||||
_library = library;
|
||||
_composedFrame = -1;
|
||||
_numLayers = data.TIMELINE.LAYERS.length;
|
||||
_numFrames = getNumFrames();
|
||||
_frameLabels = _getFrameLabels();
|
||||
_symbolName = data.SYMBOL_name;
|
||||
_type = SymbolType.GRAPHIC;
|
||||
_loopMode = LoopMode.LOOP;
|
||||
|
||||
createLayers();
|
||||
|
||||
// Create FrameMap caches if don't exist
|
||||
for (layer in data.TIMELINE.LAYERS) {
|
||||
if (layer.FrameMap != null)
|
||||
return;
|
||||
|
||||
var map = new Map();
|
||||
|
||||
for (i in 0...layer.Frames.length) {
|
||||
var frame = layer.Frames[i];
|
||||
for (j in 0...frame.duration) {
|
||||
map.set(i + j, frame);
|
||||
}
|
||||
}
|
||||
|
||||
layer.FrameMap = map;
|
||||
}
|
||||
}
|
||||
|
||||
public function reset():Void {
|
||||
matrix.identity();
|
||||
|
||||
// copied from the setter for tile so we don't create a new matrix.
|
||||
__rotation = null;
|
||||
__scaleX = null;
|
||||
__scaleY = null;
|
||||
__setRenderDirty();
|
||||
|
||||
alpha = 1.0;
|
||||
_currentFrame = 0;
|
||||
_composedFrame = -1;
|
||||
}
|
||||
|
||||
public function nextFrame():Void {
|
||||
if (_loopMode != LoopMode.SINGLE_FRAME) {
|
||||
currentFrame += 1;
|
||||
}
|
||||
|
||||
moveMovieclip_MovieClips(1);
|
||||
}
|
||||
|
||||
public function prevFrame():Void {
|
||||
if (_loopMode != LoopMode.SINGLE_FRAME) {
|
||||
currentFrame -= 1;
|
||||
}
|
||||
|
||||
moveMovieclip_MovieClips(-1);
|
||||
}
|
||||
|
||||
/** Moves all movie clips n frames, recursively. */
|
||||
private function moveMovieclip_MovieClips(direction:Int = 1):Void {
|
||||
if (_type == SymbolType.MOVIE_CLIP) {
|
||||
currentFrame += direction;
|
||||
}
|
||||
|
||||
for (l in 0..._numLayers) {
|
||||
var layer:TileContainer = getLayer(l);
|
||||
var numElements:Int = layer.numTiles;
|
||||
|
||||
for (e in 0...numElements) {
|
||||
(try cast(layer.getTileAt(e), TileContainerSymbol) catch (e:Dynamic) null).moveMovieclip_MovieClips(direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function update():Void {
|
||||
for (i in 0..._numLayers) {
|
||||
updateLayer(i);
|
||||
}
|
||||
|
||||
_composedFrame = _currentFrame;
|
||||
}
|
||||
|
||||
@:access(animateatlas)
|
||||
private function updateLayer(layerIndex:Int):Void {
|
||||
var layer:TileContainer = getLayer(layerIndex);
|
||||
var frameData:LayerFrameData = getFrameData(layerIndex, _currentFrame);
|
||||
var elements:Array<ElementData> = (frameData != null) ? frameData.elements : null;
|
||||
var numElements:Int = (elements != null) ? elements.length : 0;
|
||||
for (i in 0...numElements) {
|
||||
var elementData:SymbolInstanceData = elements[i].SYMBOL_Instance;
|
||||
if (elementData == null) {
|
||||
continue;
|
||||
}
|
||||
// this is confusing but needed :(
|
||||
var oldSymbol:TileContainerSymbol = (layer.numTiles > i) ? try
|
||||
cast(layer.getTileAt(i), TileContainerSymbol)
|
||||
catch (e:Dynamic)
|
||||
null : null;
|
||||
|
||||
var newSymbol:TileContainerSymbol = null;
|
||||
var symbolName:String = elementData.SYMBOL_name;
|
||||
|
||||
if (!_library.hasSymbol(symbolName)) {
|
||||
symbolName = TileAnimationLibrary.BITMAP_SYMBOL_NAME;
|
||||
}
|
||||
|
||||
if (oldSymbol != null && oldSymbol._symbolName == symbolName) {
|
||||
newSymbol = oldSymbol;
|
||||
} else {
|
||||
if (oldSymbol != null) {
|
||||
if (oldSymbol.parent != null)
|
||||
oldSymbol.removeTile(oldSymbol);
|
||||
_library.putSymbol(oldSymbol);
|
||||
}
|
||||
|
||||
newSymbol = cast(_library.getSymbol(symbolName));
|
||||
layer.addTileAt(newSymbol, i);
|
||||
}
|
||||
|
||||
newSymbol.setTransformationMatrix(elementData.Matrix3D);
|
||||
newSymbol.setBitmap(elementData.bitmap);
|
||||
newSymbol.setColor(elementData.color);
|
||||
newSymbol.setLoop(elementData.loop);
|
||||
newSymbol.setType(elementData.symbolType);
|
||||
|
||||
if (newSymbol.type == SymbolType.GRAPHIC) {
|
||||
var firstFrame:Int = elementData.firstFrame;
|
||||
var frameAge:Int = Std.int(_currentFrame - frameData.index);
|
||||
|
||||
if (newSymbol.loopMode == LoopMode.SINGLE_FRAME) {
|
||||
newSymbol.currentFrame = firstFrame;
|
||||
} else if (newSymbol.loopMode == LoopMode.LOOP) {
|
||||
newSymbol.currentFrame = (firstFrame + frameAge) % newSymbol._numFrames;
|
||||
} else {
|
||||
newSymbol.currentFrame = firstFrame + frameAge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var numObsoleteSymbols:Int = (layer.numTiles - numElements);
|
||||
|
||||
for (i in 0...numObsoleteSymbols) {
|
||||
try {
|
||||
var oldSymbol = cast(layer.removeTileAt(numElements), TileContainerSymbol);
|
||||
if (oldSymbol != null)
|
||||
_library.putSymbol(oldSymbol);
|
||||
} catch (e:Dynamic) {};
|
||||
}
|
||||
}
|
||||
|
||||
private function createLayers():Void {
|
||||
// todo safety check for not initialiing twice
|
||||
if (_layers != null) {
|
||||
throw new Error("You must not call this twice");
|
||||
}
|
||||
_layers = new Array<TileContainer>();
|
||||
|
||||
if (_numLayers <= 1) {
|
||||
_layers.push(this);
|
||||
} else {
|
||||
for (i in 0..._numLayers) {
|
||||
var layer:TileContainer = new TileContainer();
|
||||
if (layer.data == null) {
|
||||
layer.data = {layerName: getLayerData(i).Layer_name};
|
||||
} else {
|
||||
layer.data.layerName = getLayerData(i).Layer_name;
|
||||
}
|
||||
addTile(layer);
|
||||
_layers.push(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@:access(animateatlas)
|
||||
public function setBitmap(data:BitmapPosData):Void {
|
||||
if (data != null) {
|
||||
var spriteData = _library.getSpriteData(data.name + "");
|
||||
|
||||
if (_bitmap == null) {
|
||||
_bitmap = new Tile(-1);
|
||||
_bitmap.rect = new Rectangle();
|
||||
addTile(_bitmap);
|
||||
}
|
||||
|
||||
_bitmap.rect.setTo(spriteData.x, spriteData.y, spriteData.w, spriteData.h);
|
||||
_bitmap.__setRenderDirty(); // setTo() doesn't trigger the renderdirty
|
||||
|
||||
// aditional checks for rotation
|
||||
if (spriteData.rotated) {
|
||||
_bitmap.rotation = -90;
|
||||
_bitmap.x = data.Position.x;
|
||||
_bitmap.y = data.Position.y + spriteData.w;
|
||||
} else {
|
||||
_bitmap.rotation = 0;
|
||||
_bitmap.x = data.Position.x;
|
||||
_bitmap.y = data.Position.y;
|
||||
}
|
||||
|
||||
addTileAt(_bitmap, 0);
|
||||
} else if (_bitmap != null) {
|
||||
if (_bitmap.parent != null)
|
||||
_bitmap.parent.removeTile(_bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
private function setTransformationMatrix(data:Matrix3DData):Void {
|
||||
if (data.m00 != matrix.a || data.m01 != matrix.b || data.m10 != matrix.c || data.m11 != matrix.d || data.m30 != matrix.tx || data.m31 != matrix.ty) {
|
||||
matrix.setTo(data.m00, data.m01, data.m10, data.m11, data.m30, data.m31);
|
||||
|
||||
// copied from the setter for tile so we don't create a new matrix.
|
||||
__rotation = null;
|
||||
__scaleX = null;
|
||||
__scaleY = null;
|
||||
__setRenderDirty();
|
||||
}
|
||||
}
|
||||
|
||||
private function setColor(data:ColorData):Void {
|
||||
var newTransform = new ColorTransform();
|
||||
if (data != null) {
|
||||
newTransform.redOffset = (data.redOffset == null ? 0 : data.redOffset);
|
||||
newTransform.greenOffset = (data.greenOffset == null ? 0 : data.greenOffset);
|
||||
newTransform.blueOffset = (data.blueOffset == null ? 0 : data.blueOffset);
|
||||
newTransform.alphaOffset = (data.AlphaOffset == null ? 0 : data.AlphaOffset);
|
||||
|
||||
newTransform.redMultiplier = (data.RedMultiplier == null ? 1 : data.RedMultiplier);
|
||||
newTransform.greenMultiplier = (data.greenMultiplier == null ? 1 : data.greenMultiplier);
|
||||
newTransform.blueMultiplier = (data.blueMultiplier == null ? 1 : data.blueMultiplier);
|
||||
newTransform.alphaMultiplier = (data.alphaMultiplier == null ? 1 : data.alphaMultiplier);
|
||||
}
|
||||
colorTransform = newTransform;
|
||||
}
|
||||
|
||||
private function setLoop(data:String):Void {
|
||||
if (data != null) {
|
||||
_loopMode = data;
|
||||
} else {
|
||||
_loopMode = LoopMode.LOOP;
|
||||
}
|
||||
}
|
||||
|
||||
private function setType(data:String):Void {
|
||||
if (data != null) {
|
||||
_type = data;
|
||||
}
|
||||
}
|
||||
|
||||
private function getNumFrames():Int {
|
||||
var numFrames:Int = 0;
|
||||
|
||||
for (i in 0..._numLayers) {
|
||||
var layer = getLayerData(i);
|
||||
var frameDates:Array<LayerFrameData> = (layer == null ? [] : layer.Frames);
|
||||
var numFrameDates:Int = (frameDates != null) ? frameDates.length : 0;
|
||||
var layerNumFrames:Int = (numFrameDates != 0) ? frameDates[0].index : 0;
|
||||
|
||||
for (j in 0...numFrameDates) {
|
||||
layerNumFrames += frameDates[j].duration;
|
||||
}
|
||||
|
||||
if (layerNumFrames > numFrames) {
|
||||
numFrames = layerNumFrames;
|
||||
}
|
||||
}
|
||||
|
||||
return numFrames == 0 ? 1 : numFrames;
|
||||
}
|
||||
|
||||
private function _getFrameLabels():Array<FrameLabel> {
|
||||
var labels:Array<FrameLabel> = [];
|
||||
|
||||
for (i in 0..._numLayers) {
|
||||
var layer = getLayerData(i);
|
||||
var frameDates:Array<LayerFrameData> = (layer == null ? [] : layer.Frames);
|
||||
var numFrameDates:Int = (frameDates != null) ? frameDates.length : 0;
|
||||
|
||||
for (j in 0...numFrameDates) {
|
||||
var frameData:LayerFrameData = frameDates[j];
|
||||
if (frameData.name != null) {
|
||||
labels.push(new FrameLabel(frameData.name, frameData.index));
|
||||
}
|
||||
}
|
||||
}
|
||||
labels.sort(sortLabels);
|
||||
return labels;
|
||||
}
|
||||
|
||||
public function getFrameLabels():Array<String> {
|
||||
return _frameLabels.map(f -> f.name); // Inlining. I feel a js
|
||||
}
|
||||
|
||||
function sortLabels(i1:FrameLabel, i2:FrameLabel):Int {
|
||||
var f1 = i1.frame;
|
||||
var f2 = i2.frame;
|
||||
if (f1 < f2) {
|
||||
return -1;
|
||||
} else if (f1 > f2) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private function getLayer(layerIndex:Int):TileContainer {
|
||||
return _layers[layerIndex];
|
||||
}
|
||||
|
||||
public function getNextLabel(afterLabel:String = null):String {
|
||||
var numLabels:Int = _frameLabels.length;
|
||||
var startFrame:Int = getFrame(afterLabel == null ? currentLabel : afterLabel);
|
||||
|
||||
for (i in 0...numLabels) {
|
||||
var label:FrameLabel = _frameLabels[i];
|
||||
if (label.frame > startFrame) {
|
||||
return label.name;
|
||||
}
|
||||
}
|
||||
|
||||
return (_frameLabels != null) ? _frameLabels[0].name : null;
|
||||
}
|
||||
|
||||
private function get_currentLabel():String {
|
||||
var numLabels:Int = _frameLabels.length;
|
||||
var highestLabel:FrameLabel = (numLabels != 0) ? _frameLabels[0] : null;
|
||||
|
||||
for (i in 1...numLabels) {
|
||||
var label:FrameLabel = _frameLabels[i];
|
||||
|
||||
if (label.frame <= _currentFrame) {
|
||||
highestLabel = label;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (highestLabel != null) ? highestLabel.name : null;
|
||||
}
|
||||
|
||||
public function getFrame(label:String):Int {
|
||||
var numLabels:Int = _frameLabels.length;
|
||||
for (i in 0...numLabels) {
|
||||
var frameLabel:FrameLabel = _frameLabels[i];
|
||||
if (frameLabel.name == label) {
|
||||
return frameLabel.frame;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private function get_currentFrame():Int {
|
||||
return _currentFrame;
|
||||
}
|
||||
|
||||
private function set_currentFrame(value:Int):Int {
|
||||
while (value < 0) {
|
||||
value += _numFrames;
|
||||
}
|
||||
|
||||
if (_loopMode == LoopMode.PLAY_ONCE) {
|
||||
_currentFrame = Std.int(Math.min(Math.max(value, 0), _numFrames - 1));
|
||||
} else {
|
||||
_currentFrame = Std.int(Math.abs(value % _numFrames));
|
||||
}
|
||||
|
||||
if (_composedFrame != _currentFrame) {
|
||||
update();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_type():String {
|
||||
return _type;
|
||||
}
|
||||
|
||||
private function set_type(value:String):String {
|
||||
if (SymbolType.isValid(value)) {
|
||||
_type = value;
|
||||
} else {
|
||||
throw new ArgumentError("Invalid symbol type: " + value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_loopMode():String {
|
||||
return _loopMode;
|
||||
}
|
||||
|
||||
private function set_loopMode(value:String):String {
|
||||
if (LoopMode.isValid(value)) {
|
||||
_loopMode = value;
|
||||
} else {
|
||||
throw new ArgumentError("Invalid loop mode: " + value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private function get_symbolName():String {
|
||||
return _symbolName;
|
||||
}
|
||||
|
||||
public function get_numLayers():Int {
|
||||
return _numLayers;
|
||||
}
|
||||
|
||||
public function get_numFrames():Int {
|
||||
return _numFrames;
|
||||
}
|
||||
|
||||
// data access
|
||||
|
||||
private function getLayerData(layerIndex:Int):LayerData {
|
||||
return _data.TIMELINE.LAYERS[layerIndex];
|
||||
}
|
||||
|
||||
private function getFrameData(layerIndex:Int, frameIndex:Int):LayerFrameData {
|
||||
var layer = getLayerData(layerIndex);
|
||||
if (layer == null)
|
||||
return null;
|
||||
|
||||
return layer.FrameMap.get(frameIndex);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package funkin.system;
|
||||
|
||||
import animateatlas.AtlasFrameMaker;
|
||||
import haxe.Json;
|
||||
import funkin.menus.StoryMenuState.WeekData;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
@@ -268,6 +269,11 @@ class CoolUtil
|
||||
public static function loadFrames(path:String, Unique:Bool = false, Key:String = null):FlxFramesCollection {
|
||||
var noExt = Path.withoutExtension(path);
|
||||
|
||||
if (Assets.exists('$noExt/Animation.json')
|
||||
&& Assets.exists('$noExt/spritemap.json')
|
||||
&& Assets.exists('$noExt/spritemap.png')) {
|
||||
// TODO: Credit Smokey555!!
|
||||
return AtlasFrameMaker.construct(noExt);
|
||||
if (Assets.exists('$noExt.xml')) {
|
||||
return Paths.getSparrowAtlasAlt(noExt);
|
||||
} else if (Assets.exists('$noExt.txt')) {
|
||||
|
||||
@@ -32,6 +32,8 @@ import funkin.mods.ModsFolder;
|
||||
|
||||
class Main extends Sprite
|
||||
{
|
||||
// TODO: CREDIT SMOKEY FOR ATLAS STUFF!!
|
||||
|
||||
var gameWidth:Int = 1280; // Width of the game in pixels (might be less / more in actual pixels depending on your zoom).
|
||||
var gameHeight:Int = 720; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom).
|
||||
var initialState:Class<FlxState> = TitleState; // The FlxState the game starts with.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
haxelib git flixel-yc29 https://www.github.com/YoshiCrafter29/flixel
|
||||
haxelib git hscript-improved https://www.github.com/YoshiCrafter29/hscript-improved
|
||||
haxelib git Flixel-TextureAtlas https://github.com/Smokey555/Flixel-TextureAtlas
|
||||
haxelib install hxCodec
|
||||
Reference in New Issue
Block a user