mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-12-17 19:42:22 -05:00
515 lines
11 KiB
Haxe
515 lines
11 KiB
Haxe
package animate;
|
|
|
|
import haxe.format.JsonParser;
|
|
import openfl.Assets;
|
|
import openfl.geom.Matrix3D;
|
|
import openfl.geom.Matrix;
|
|
import sys.io.File;
|
|
|
|
/**
|
|
* Generally designed / written in a way that can be easily taken out of FNF and used elsewhere
|
|
* I don't think it even has ties to OpenFL? Could probably just use it for ANY haxe
|
|
* project if needed, DOES NEED A LOT OF CLEANUP THOUGH!
|
|
*/
|
|
class ParseAnimate
|
|
{
|
|
// make list of frames needed to render (with ASI)
|
|
// make GIANT list of all the frames ever and have them in order?
|
|
public static var symbolMap:Map<String, Symbol> = new Map();
|
|
public static var actualSprites:Map<String, Sprite> = new Map();
|
|
|
|
private var _atlas:Map<String, Sprite>;
|
|
private var _symbolData:Map<String, Symbol>;
|
|
private var _defaultSymbolName:String;
|
|
|
|
public function new(data:AnimJson, atlas:Spritemap)
|
|
{
|
|
// bitmap data could prob be instead
|
|
// this code is mostly nabbed from https://github.com/miltoncandelero/OpenFLAnimateAtlas/blob/master/Source/animateatlas/displayobject/SpriteAnimationLibrary.hx
|
|
parseAnimationData(data);
|
|
parseAtlasData(atlas);
|
|
}
|
|
|
|
private function parseAnimationData(data:AnimJson):Void
|
|
{
|
|
_symbolData = new Map();
|
|
|
|
var symbols = data.SD.S;
|
|
for (symbol in symbols)
|
|
_symbolData[symbol.SN] = preprocessSymbolData(symbol);
|
|
|
|
var defaultSymbol:Symbol = preprocessSymbolData(data.AN);
|
|
_defaultSymbolName = defaultSymbol.SN;
|
|
_symbolData.set(_defaultSymbolName, defaultSymbol);
|
|
}
|
|
|
|
// at little redundant, does exactly the same thing as genSpritemap()
|
|
private function parseAtlasData(atlas:Spritemap):Void
|
|
{
|
|
_atlas = new Map<String, Sprite>();
|
|
if (atlas.ATLAS != null && atlas.ATLAS.SPRITES != null)
|
|
{
|
|
for (s in atlas.ATLAS.SPRITES)
|
|
_atlas.set(s.SPRITE.name, s.SPRITE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Not used, was used for testing stuff though!
|
|
*/
|
|
public static function init()
|
|
{
|
|
// Main.gids
|
|
var folder:String = 'tightestBars';
|
|
|
|
// var spritemap:Spritemap =
|
|
// var spritemap:Spritemap = genSpritemap('test/$folder/spritemap1.json');
|
|
|
|
actualSprites = genSpritemap('test/$folder/spritemap1.json');
|
|
|
|
var animation:AnimJson = cast CoolUtil.coolJSON(Assets.getText('src/$folder/Animation.json'));
|
|
|
|
generateSymbolmap(animation.SD.S);
|
|
|
|
trace("\n\nANIMATION SHIT\n");
|
|
|
|
var timelineLength:Int = 0;
|
|
for (lyr in animation.AN.TL.L)
|
|
timelineLength = Std.int(Math.max(lyr.FR.length, timelineLength));
|
|
|
|
var content:String = animation.AN.TL.L[0].LN;
|
|
content += "TOTAL FRAMES NEEDED: " + timelineLength + "\n";
|
|
|
|
for (frm in 0...timelineLength)
|
|
{
|
|
trace('FRAME NUMBER ' + frm);
|
|
try
|
|
{
|
|
parseTimeline(animation.AN.TL, 1, frm);
|
|
content += 'Good write on frame: ' + frm + "\n";
|
|
}
|
|
catch (e)
|
|
{
|
|
content += "BAD WRITE : " + frm + "\n";
|
|
content += "\t" + e + "\n";
|
|
trace(e);
|
|
}
|
|
|
|
// File.saveContent("output.txt", content);
|
|
}
|
|
|
|
parseTimeline(animation.AN.TL, 1, 0);
|
|
trace(actualSprites);
|
|
}
|
|
|
|
/**
|
|
* a MAP of SPRITES, not to be confused with Spritemap... lol
|
|
*/
|
|
public static function genSpritemap(json:String):Map<String, Sprite>
|
|
{
|
|
var sprShitty:Spritemap = cast CoolUtil.coolJSON(json);
|
|
var sprMap:Map<String, Sprite> = new Map();
|
|
|
|
for (spr in sprShitty.ATLAS.SPRITES)
|
|
sprMap.set(spr.SPRITE.name, spr.SPRITE);
|
|
return sprMap;
|
|
}
|
|
|
|
// should change dis to all private?
|
|
public static function generateSymbolmap(symbols:Array<Symbol>)
|
|
{
|
|
for (symbol in symbols)
|
|
{
|
|
// trace(symbol.SN + "has: " + symbol.TL.L.length + " LAYERS");
|
|
|
|
symbolMap.set(symbol.SN, symbol);
|
|
// parseTimeline(symbol.TL);
|
|
}
|
|
}
|
|
|
|
public static function preprocessSymbolData(anim:Symbol):Symbol
|
|
{
|
|
var timelineData:Timeline = anim.TL;
|
|
var layerData:Array<Layer> = timelineData.L;
|
|
|
|
if (!timelineData.sortedForRender)
|
|
{
|
|
timelineData.sortedForRender = true;
|
|
layerData.reverse();
|
|
}
|
|
|
|
for (layerStuff in layerData)
|
|
{
|
|
var frames:Array<Frame> = layerStuff.FR;
|
|
|
|
for (frame in frames)
|
|
{
|
|
var elements:Array<Element> = frame.E;
|
|
for (e in 0...elements.length)
|
|
{
|
|
var element:Element = elements[e];
|
|
if (element.ASI != null)
|
|
{
|
|
element = elements[e] = {
|
|
SI: {
|
|
SN: "ATLAS_SYMBOL_SPRITE",
|
|
LP: "LP",
|
|
TRP: {x: 0, y: 0},
|
|
M3D: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
|
FF: 0,
|
|
ST: "G",
|
|
ASI: element.ASI
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return anim;
|
|
}
|
|
|
|
public static var curLoopType:String;
|
|
|
|
/**
|
|
* Stuff for debug parsing
|
|
*/
|
|
public static var depthTypeBeat:String = "";
|
|
|
|
/**
|
|
* Array of bullshit that will eventually be RENDERED by whoever wanna use it!
|
|
*/
|
|
public static var frameList:Array<Array<VALIDFRAME>> = [];
|
|
|
|
// for loop stuf
|
|
|
|
/**
|
|
* Similar to frameList, keeps track of shit according to framess?
|
|
* That amount of arrays within arrays is fuckin dumb
|
|
* but innermost array is basically just x and y value, cuz im dum
|
|
*/
|
|
public static var matrixHelp:Array<Array<Array<Float>>> = [];
|
|
|
|
public static var trpHelpIDK:Array<Array<Array<Float>>> = [];
|
|
|
|
public static var loopedFrameShit:Int = 0;
|
|
|
|
public static var funnyMatrix:Matrix = new Matrix();
|
|
public static var matrixFlipper:Array<Matrix> = [];
|
|
|
|
// clean up all the crazy ass arrays
|
|
|
|
public static function resetFrameList()
|
|
{
|
|
// funnyMatrix.identity();
|
|
|
|
frameList = [];
|
|
frameList.push([]);
|
|
matrixHelp = [];
|
|
matrixHelp.push([]);
|
|
|
|
trpHelpIDK = [];
|
|
trpHelpIDK.push([]);
|
|
}
|
|
|
|
public static var isFlipped:Bool = false;
|
|
|
|
public static function parseTimeline(TL:Timeline, tabbed:Int = 0, ?frameInput:Int)
|
|
{
|
|
var strTab:String = "";
|
|
for (i in 0...tabbed)
|
|
strTab += '\t';
|
|
|
|
for (layer in TL.L)
|
|
{
|
|
var frameArray:Array<Int> = [];
|
|
var frameMap:Map<Int, Frame> = new Map();
|
|
|
|
for (frms in layer.FR)
|
|
{
|
|
for (i in 0...frms.DU)
|
|
frameArray.push(frms.I);
|
|
|
|
frameMap.set(frms.I, frms);
|
|
}
|
|
|
|
if (frameInput == null)
|
|
frameInput = 0;
|
|
|
|
var oldFrm:Int = frameInput;
|
|
/*
|
|
if (curLoopType == "SF")
|
|
{
|
|
trace(layer.LN);
|
|
|
|
trace(frameArray);
|
|
trace(frameInput);
|
|
trace(curLoopType);
|
|
}*/
|
|
|
|
if (curLoopType == "LP")
|
|
frameInput = frameArray[frameInput % frameArray.length];
|
|
else if (curLoopType == "SF")
|
|
{
|
|
frameInput = frameArray[loopedFrameShit];
|
|
|
|
// see what happens when something has more than 2 layer?
|
|
// single frame stuff isn't fully implemented
|
|
}
|
|
else
|
|
frameInput = frameArray[frameInput];
|
|
|
|
// trace(frameMap.get(frameInput));
|
|
|
|
var frame:Frame = frameMap.get(frameInput);
|
|
|
|
// get somethin sorted per element list, which would essentially be per symbol things properly sorted
|
|
// seperate data types if symbol or atlassymbolinstance? would probably be maybe slightly less memory intensive? i dunno
|
|
|
|
// goes thru each layer, and then each element
|
|
// after it gets thru each element it adds to the layer frame stuff.
|
|
// make somethin that works recursively, maybe thats the symbol dictionary type shit?
|
|
|
|
for (element in frame.E)
|
|
{
|
|
if (Reflect.hasField(element, "ASI"))
|
|
{
|
|
matrixHelp[matrixHelp.length - 1].push(element.ASI.M3D);
|
|
|
|
var m3D = element.ASI.M3D;
|
|
var lilMatrix:Matrix = new Matrix(m3D[0], m3D[1], m3D[4], m3D[5], m3D[12], m3D[13]);
|
|
matrixFlipper.push(lilMatrix);
|
|
|
|
// matrixFlipper.reverse();
|
|
|
|
// funnyMatrix.identity();
|
|
|
|
// for (m in matrixFlipper)
|
|
// funnyMatrix.concat(m);
|
|
|
|
if (isFlipped)
|
|
{
|
|
trace("MORE FLIPPED SHIT");
|
|
trace("MORE FLIPPED SHIT");
|
|
trace("MORE FLIPPED SHIT");
|
|
trace(funnyMatrix);
|
|
trace(matrixFlipper);
|
|
}
|
|
|
|
// trace(funnyMatrix);
|
|
|
|
funnyMatrix.concat(lilMatrix);
|
|
// trace(funnyMatrix);
|
|
|
|
frameList[frameList.length - 1].push({
|
|
frameName: element.ASI.N,
|
|
depthString: depthTypeBeat,
|
|
matrixArray: matrixHelp[matrixHelp.length - 1],
|
|
trpArray: trpHelpIDK[trpHelpIDK.length - 1],
|
|
fullMatrix: funnyMatrix.clone()
|
|
});
|
|
|
|
// flips the matrix once?? I cant remember exactly why it needs to be flipped
|
|
// matrixHelp[matrixHelp.length - 1].reverse();
|
|
|
|
// trpHelpIDK = [];
|
|
|
|
// push the matrix array after each symbol?
|
|
|
|
funnyMatrix.identity();
|
|
matrixFlipper = [];
|
|
|
|
depthTypeBeat = "";
|
|
curLoopType = "";
|
|
loopedFrameShit = 0;
|
|
|
|
isFlipped = false;
|
|
}
|
|
else
|
|
{
|
|
var m3D = element.SI.M3D;
|
|
var lilMatrix:Matrix = new Matrix(m3D[0], m3D[1], m3D[4], m3D[5], m3D[12], m3D[13]);
|
|
|
|
if (lilMatrix.a == -1)
|
|
{
|
|
isFlipped = true;
|
|
|
|
trace('IS THE NEGATIVE ONE');
|
|
}
|
|
|
|
if (isFlipped)
|
|
trace(lilMatrix);
|
|
|
|
funnyMatrix.concat(lilMatrix);
|
|
matrixFlipper.push(lilMatrix);
|
|
// trace(funnyMatrix);
|
|
|
|
matrixHelp[matrixHelp.length - 1].push(element.SI.M3D);
|
|
trpHelpIDK[trpHelpIDK.length - 1].push([element.SI.TRP.x, element.SI.TRP.y]); // trpHelpIDK.push();
|
|
depthTypeBeat += "->" + element.SI.SN;
|
|
curLoopType = element.SI.LP;
|
|
|
|
var inputFrame:Int = element.SI.FF;
|
|
|
|
// JANKY FIX, MAY NOT ACCOUNT FOR ALL SCENARIOS OF SINGLE FRAME ANIMATIONS!!
|
|
if (curLoopType == "SF")
|
|
{
|
|
// trace("LOOP SHIT: " + inputFrame);
|
|
loopedFrameShit = inputFrame;
|
|
}
|
|
|
|
// condense the animation code, so it automatically already fills up animation shit per symbol
|
|
|
|
parseTimeline(symbolMap.get(element.SI.SN).TL, tabbed + 1, inputFrame);
|
|
}
|
|
|
|
// idk if this should go per layer or per element / object?
|
|
|
|
matrixHelp.push([]);
|
|
trpHelpIDK.push([]);
|
|
}
|
|
|
|
if (tabbed == 0)
|
|
{
|
|
frameList[frameList.length - 1].reverse();
|
|
frameList.push([]); // new layer essentially
|
|
}
|
|
}
|
|
|
|
frameList.reverse();
|
|
}
|
|
}
|
|
|
|
typedef VALIDFRAME =
|
|
{
|
|
frameName:String,
|
|
depthString:String,
|
|
matrixArray:Array<Array<Float>>,
|
|
trpArray:Array<Array<Float>>,
|
|
fullMatrix:Matrix
|
|
}
|
|
|
|
typedef AnimJson =
|
|
{
|
|
AN:Animation,
|
|
SD:SymbolDictionary,
|
|
MD:MetaData
|
|
}
|
|
|
|
typedef Animation =
|
|
{
|
|
N:String,
|
|
SN:String,
|
|
TL:Timeline
|
|
}
|
|
|
|
typedef SymbolDictionary =
|
|
{
|
|
S:Array<Symbol>
|
|
}
|
|
|
|
typedef Symbol =
|
|
{
|
|
/**Symbol name*/
|
|
SN:String,
|
|
|
|
TL:Timeline
|
|
}
|
|
|
|
typedef Timeline =
|
|
{
|
|
?sortedForRender:Bool,
|
|
L:Array<Layer>
|
|
}
|
|
|
|
typedef Layer =
|
|
{
|
|
LN:String,
|
|
FR:Array<Frame>
|
|
}
|
|
|
|
typedef Frame =
|
|
{
|
|
E:Array<Element>,
|
|
I:Int,
|
|
DU:Int
|
|
// maybe need to implement names if it has frame labels?
|
|
}
|
|
|
|
typedef Element =
|
|
{
|
|
SI:SymbolInstance,
|
|
?ASI:AlsoSymbolInstance
|
|
// lmfao idk what ASI stands for lmfaoo, i dont think its "also"
|
|
}
|
|
|
|
typedef SymbolInstance =
|
|
{
|
|
SN:String,
|
|
ASI:AlsoSymbolInstance,
|
|
|
|
/**Symbol type, prob either G (graphic), or movie clip?*/ ST:String,
|
|
|
|
/**First frame*/ FF:Int,
|
|
|
|
/**Loop type, loop ping pong, etc.*/ LP:String,
|
|
|
|
/**3D matrix*/ M3D:Array<Float>,
|
|
|
|
TRP:
|
|
{
|
|
x:Float, y:Float
|
|
}
|
|
}
|
|
|
|
typedef AlsoSymbolInstance =
|
|
{
|
|
N:String,
|
|
M3D:Array<Float>
|
|
}
|
|
|
|
typedef MetaData =
|
|
{
|
|
/**
|
|
* Framerate
|
|
*/
|
|
FRT:Int
|
|
}
|
|
|
|
// SPRITEMAP BULLSHIT
|
|
typedef Spritemap =
|
|
{
|
|
ATLAS:
|
|
{
|
|
SPRITES:Array<SpriteBullshit>
|
|
},
|
|
meta:Meta
|
|
}
|
|
|
|
typedef SpriteBullshit =
|
|
{
|
|
SPRITE:Sprite
|
|
}
|
|
|
|
typedef Sprite =
|
|
{
|
|
name:String,
|
|
x:Int,
|
|
y:Int,
|
|
w:Int,
|
|
h:Int,
|
|
rotated:Bool
|
|
}
|
|
|
|
typedef Meta =
|
|
{
|
|
app:String,
|
|
verstion:String,
|
|
image:String,
|
|
format:String,
|
|
size:
|
|
{
|
|
w:Int, h:Float
|
|
},
|
|
resolution:Float
|
|
}
|