diff --git a/art/flashFiles/Alphabet_Bold.fla b/art/flashFiles/Alphabet_Bold.fla index a4bb2f4b..7a2559f9 100644 Binary files a/art/flashFiles/Alphabet_Bold.fla and b/art/flashFiles/Alphabet_Bold.fla differ diff --git a/assets/data/alphabet.xml b/assets/data/alphabet.xml index 281b7f18..a265c95a 100644 --- a/assets/data/alphabet.xml +++ b/assets/data/alphabet.xml @@ -28,6 +28,7 @@ + diff --git a/assets/images/menus/alphabet-bold.png b/assets/images/menus/alphabet-bold.png index ecc22cae..73e7110d 100644 Binary files a/assets/images/menus/alphabet-bold.png and b/assets/images/menus/alphabet-bold.png differ diff --git a/assets/images/menus/alphabet-bold.xml b/assets/images/menus/alphabet-bold.xml index 481bc3a4..742b3b86 100644 --- a/assets/images/menus/alphabet-bold.xml +++ b/assets/images/menus/alphabet-bold.xml @@ -2,108 +2,112 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/buildnumber.txt b/buildnumber.txt index 1f3f6d91..721b63db 100644 --- a/buildnumber.txt +++ b/buildnumber.txt @@ -1 +1 @@ -2582 \ No newline at end of file +2596 \ No newline at end of file diff --git a/source/animateatlas/displayobject/SpriteAnimationLibrary.hx b/source/animateatlas/displayobject/SpriteAnimationLibrary.hx index 2f835ab4..6eab5ae2 100644 --- a/source/animateatlas/displayobject/SpriteAnimationLibrary.hx +++ b/source/animateatlas/displayobject/SpriteAnimationLibrary.hx @@ -100,7 +100,6 @@ class SpriteAnimationLibrary { } // # region Pooling - // todo migrate this to lime pool @:access(animateatlas) @:allow(AtlasFrameMaker) diff --git a/source/animateatlas/displayobject/SpriteSymbol.hx b/source/animateatlas/displayobject/SpriteSymbol.hx index 42ea0273..a433fdc6 100644 --- a/source/animateatlas/displayobject/SpriteSymbol.hx +++ b/source/animateatlas/displayobject/SpriteSymbol.hx @@ -307,7 +307,7 @@ class SpriteSymbol extends Sprite { 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 :( + transform.matrix = sMatrix.clone(); } private function setColor(data:ColorData):Void { diff --git a/source/animateatlas/tilecontainer/TileAnimationLibrary.hx b/source/animateatlas/tilecontainer/TileAnimationLibrary.hx index 008f0e36..62490962 100644 --- a/source/animateatlas/tilecontainer/TileAnimationLibrary.hx +++ b/source/animateatlas/tilecontainer/TileAnimationLibrary.hx @@ -102,7 +102,6 @@ class TileAnimationLibrary { } // # region Pooling - // todo migrate this to lime pool @:access(animateatlas) private function getSymbol(name:String):TileContainerSymbol { diff --git a/source/flxanimate/frames/FlxAnimateFrames.hx b/source/flxanimate/frames/FlxAnimateFrames.hx new file mode 100644 index 00000000..b61a3282 --- /dev/null +++ b/source/flxanimate/frames/FlxAnimateFrames.hx @@ -0,0 +1,619 @@ +package flxanimate.frames; +import flixel.graphics.frames.FlxFramesCollection; +import flxanimate.data.AnimationData.OneOfTwo; +import openfl.geom.Rectangle; +import flxanimate.data.SpriteMapData.Meta; +import haxe.io.Bytes; +import flxanimate.zip.Zip; +import haxe.io.BytesInput; +import flixel.math.FlxMatrix; +import flixel.FlxG; +import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxAtlasFrames; +import flixel.graphics.frames.FlxFrame.FlxFrameAngle; +import flixel.math.FlxPoint; +import flixel.math.FlxRect; +import flxanimate.data.SpriteMapData.AnimateAtlas; +import flxanimate.data.SpriteMapData.AnimateSpriteData; +import openfl.Assets; +import openfl.display.BitmapData; +import flixel.system.FlxAssets.FlxGraphicAsset; +#if haxe4 +import haxe.xml.Access; +#else +import haxe.xml.Fast as Access; +#end +import flixel.graphics.frames.FlxFrame; + +class FlxAnimateFrames extends FlxAtlasFrames +{ + public function new() + { + super(null); + parents = []; + } + static var data:AnimateAtlas = null; + static var zip:Null>; + + public var parents:Array; + /** + * Parses the spritemaps into small sprites to use in the animation. + * + * @param Path Where the Sprites are, normally you use it once when calling FlxAnimate already + * @return new sliced limbs for you to use ;) + */ + public static function fromTextureAtlas(Path:String):FlxAtlasFrames + { + var frames:FlxAnimateFrames = new FlxAnimateFrames(); + + if (zip != null || haxe.io.Path.extension(Path) == "zip") + { + #if html5 + FlxG.log.error("Zip Stuff isn't supported on Html5 since it can't transform bytes into an image"); + return null; + #end + var imagemap:Map = new Map(); + var jsonMap:Map = new Map(); + var thing = (zip != null) ? zip : Zip.unzip(Zip.readZip(Assets.getBytes(Path))); + for (list in thing) + { + if (haxe.io.Path.extension(list.fileName) == "json") + { + jsonMap.set(list.fileName,haxe.Json.parse(StringTools.replace(list.data.toString(), String.fromCharCode(0xFEFF), ""))); + } + else if (haxe.io.Path.extension(list.fileName) == "png") + { + var name = list.fileName.split("/"); + imagemap.set(name[name.length - 1], list.data); + } + } + // Assuming the json has the same stuff as the image stuff + for (curJson in jsonMap) + { + var curImage = BitmapData.fromBytes(imagemap[curJson.meta.image]); + if (curImage != null) + { + for (sprites in curJson.ATLAS.SPRITES) + { + frames.pushFrame(textureAtlasHelper(curImage, sprites.SPRITE, curJson.meta)); + } + } + else + FlxG.log.error('the Image called "${curJson.meta.image}" isnt in this zip file!'); + } + zip == null; + } + else + { + if (Assets.exists('$Path/spritemap.json')) + { + var curJson:AnimateAtlas = haxe.Json.parse(StringTools.replace(Assets.getText('$Path/spritemap.json'), String.fromCharCode(0xFEFF), "")); + var graphic = FlxG.bitmap.add('$Path/${curJson.meta.image}'); + if (graphic != null) + { + var spritemapFrames = new FlxAnimateFrames(); + spritemapFrames.parent = graphic; + for (curSprite in curJson.ATLAS.SPRITES) + spritemapFrames.pushFrame(textureAtlasHelper(graphic.bitmap,curSprite.SPRITE, curJson.meta)); + graphic.addFrameCollection(spritemapFrames); + frames.concat(spritemapFrames); + } + else + FlxG.log.error('the image called "${curJson.meta.image}" does not exist in Path $Path, maybe you changed the image Path somewhere else?'); + } + var i = 1; + while (Assets.exists('$Path/spritemap$i.json')) + { + var curJson:AnimateAtlas = haxe.Json.parse(StringTools.replace(Assets.getText('$Path/spritemap$i.json'), String.fromCharCode(0xFEFF), "")); + var graphic = FlxG.bitmap.add('$Path/${curJson.meta.image}'); + if (graphic != null) + { + var spritemapFrames = new FlxAnimateFrames(); + spritemapFrames.parent = graphic; + for (curSprite in curJson.ATLAS.SPRITES) + spritemapFrames.pushFrame(textureAtlasHelper(graphic.bitmap,curSprite.SPRITE, curJson.meta)); + graphic.addFrameCollection(spritemapFrames); + frames.concat(spritemapFrames); + } + else + FlxG.log.error('the image called "${curJson.meta.image}" does not exist in Path $Path, maybe you changed the image Path somewhere else?'); + i++; + } + } + if (frames.frames == []) + { + FlxG.log.error("the Frames parsing couldn't parse any of the frames, it's completely empty! \n Maybe you misspelled the Path?"); + return null; + } + return frames; + } + public function concat(frames:FlxFramesCollection) + { + if (parents.indexOf(frames.parent) == -1) + parents.push(frames.parent); + for (frame in frames.frames) + { + this.frames.push(frame); + framesHash.set(frame.name, frame); + } + } + /** + * Sparrow spritesheet format parser with support of both of the versions and making the image completely optional to you. + * @param Path The direction of the Xml you want to parse. + * @param Image (Optional) the image of the Xml. + * @return A new instance of `FlxAtlasFrames` + */ + public static function fromSparrow(Path:FlxSparrow, ?Image:FlxGraphicAsset):FlxAtlasFrames + { + if ((Path is String) && !Assets.exists(Path)) + return null; + + var data:Access = new Access((Path is String) ? Xml.parse(Assets.getText(Path)).firstElement() : Path.firstElement()); + if (Image == null) + { + if ((Path is String)) + { + var splitDir = Path.split("/"); + splitDir.pop(); + splitDir.push(data.att.imagePath); + Image = splitDir.join("/"); + } + else + return null; + } + var graphic:FlxGraphic = FlxG.bitmap.add(Image); + if (graphic == null) + return null; + + // No need to parse data again + var frames:FlxAtlasFrames = FlxAtlasFrames.findFrame(graphic); + if (frames != null) + return frames; + + frames = new FlxAtlasFrames(graphic); + + for (texture in data.nodes.SubTexture) + { + var version2 = texture.has.width; + var name = texture.att.name; + var trimmed = texture.has.frameX; + var width = (version2) ? texture.att.width : texture.att.w; + var height = (version2) ? texture.att.height : texture.att.h; + var rotated = (texture.has.rotated && texture.att.rotated == "true"); + var flipX = (texture.has.flipX && texture.att.flipX == "true"); + var flipY = (texture.has.flipY && texture.att.flipY == "true"); + + var rect = FlxRect.get(Std.parseFloat(texture.att.x), Std.parseFloat(texture.att.y), Std.parseFloat(width), + Std.parseFloat(height)); + + var size = (trimmed) ? new FlxRect(Std.parseInt(texture.att.frameX), Std.parseInt(texture.att.frameY), Std.parseInt(texture.att.frameWidth), + Std.parseInt(texture.att.frameHeight)) : new FlxRect(0, 0, rect.width, rect.height); + + var angle = rotated ? FlxFrameAngle.ANGLE_NEG_90 : FlxFrameAngle.ANGLE_0; + + var offset = FlxPoint.get(-size.left, -size.top); + var ImageSize = FlxPoint.get(size.width, size.height); + + if (rotated && !trimmed) + ImageSize.set(size.height, size.width); + + frames.addAtlasFrame(rect, ImageSize, offset, name, angle, flipX, flipY); + } + + return frames; + } + /** + * + * @param Path the Json in specific, can be the path of it or the actual json + * @param Image the image which the file is referencing **WARNING:** if you set the path as a json, it's obligatory to set the image! + * @return A new instance of `FlxAtlasFrames` + */ + public static function fromJson(Path:FlxJson, ?Image:FlxGraphicAsset):FlxAtlasFrames + { + if ((Path is String) && !Assets.exists(Path)) + return null; + var data:JsonNormal = (Path is String) ? haxe.Json.parse(Assets.getText(Path)) : Path; + if (Image == null) + { + if ((Path is String)) + { + var splitDir = Path.split("/"); + splitDir.pop(); + splitDir.push(data.meta.image); + Image = splitDir.join("/"); + } + else + { + FlxG.log.error("The Path isn't a String but a Json, you need to set an image if you use Jsons!"); + return null; + } + } + + var graphic:FlxGraphic = FlxG.bitmap.add(Image); + if (graphic == null) + return null; + + // No need to parse data again + var frames:FlxAtlasFrames = FlxAtlasFrames.findFrame(graphic); + if (frames != null) + return frames; + + frames = new FlxAtlasFrames(graphic); + + // JSON-Array + if ((data.frames is Array)) + { + for (frame in Lambda.array(data.frames)) + { + texturePackerHelper(frame.filename, frame, frames); + } + } + // JSON-Hash + else + { + for (frameName in Reflect.fields(data.frames)) + { + texturePackerHelper(frameName, Reflect.field(data.frames, frameName), frames); + } + } + + return frames; + } + /** + * Edge Animate + * @param Path the Path of the .eas + * @param Image (Optional) the Image + * @return Cute little Frames to use ;) + */ + public static function fromEdgeAnimate(Path:String, ?Image:FlxGraphicAsset):FlxAtlasFrames + { + return fromJson((StringTools.startsWith(Path, "{")) ? haxe.Json.parse(Path) : Path, Image); + } + /** + * Starling spritesheet format parser which uses a preference list from Mac computer shit + * @param Path the dir of the preference list + * @param Image (Optional) the Image + * @return Some recently cooked Frames for you ;) + */ + public static function fromStarling(Path:FlxPropertyList, ?Image:FlxGraphicAsset):FlxAtlasFrames + { + if ((Path is String) && !Assets.exists(Path)) + return null; + var data:Plist = (Path is String) ? PropertyList.parse(Assets.getText(Path)) : Path; + if (Image == null) + { + if ((Path is String)) + { + var splitDir = Path.split("/"); + splitDir.pop(); + splitDir.push(data.metadata.textureFileName); + Image = splitDir.join("/"); + } + else + { + return null; + } + } + + + var graphic:FlxGraphic = FlxG.bitmap.add(Image, false); + if (graphic == null) + return null; + + // No need to parse data again + var frames:FlxAtlasFrames = FlxAtlasFrames.findFrame(graphic); + if (frames != null) + return frames; + + frames = new FlxAtlasFrames(graphic); + + for (frameName in Reflect.fields(data.frames)) + { + starlingHelper(frameName, Reflect.field(data.frames, frameName), frames); + } + + return frames; + } + /** + * Cocos2D spritesheet format parser, which basically has 2 versions, + * One is basically Starling (2v) and the other one which is a more fucky and weird (3v) + * @param Path the Path of the plist + * @param Image (Optional) the image + * @return Recently made Frames for your dispose ;) + */ + public static function fromCocos2D(Path:String, ?Image:FlxGraphicAsset):FlxAtlasFrames + { + if (!Assets.exists(Path)) + return null; + var data:Plist = PropertyList.parse(Assets.getText(Path)); + if (data.metadata.format == 2) + { + return fromStarling(Path, Image); + } + else + { + if (Image == null) + { + if ((Path is String)) + { + var splitDir = Path.split("/"); + splitDir.pop(); + splitDir.push(data.metadata.target.name); + Image = splitDir.join("/"); + } + else + { + return null; + } + } + var graphic:FlxGraphic = FlxG.bitmap.add(Image); + if (graphic == null) + return null; + + // No need to parse data again + var frames:FlxAtlasFrames = FlxAtlasFrames.findFrame(graphic); + if (frames != null) + return frames; + + frames = new FlxAtlasFrames(graphic); + + for (frameName in Reflect.fields(data.frames)) + { + cocosHelper(frameName, Reflect.field(data.frames, frameName), frames); + } + + return frames; + } + } + /** + * EaselJS spritesheet format parser, pretty weird stuff. + * @param Path The Path of the jsFile + * @param Image (optional) the Path of the image + * @return New frames made for you to use ;) + */ + public static function fromEaselJS(Path:String, ?Image:FlxGraphicAsset):FlxAtlasFrames + { + var hugeFrames:FlxAtlasFrames = new FlxAtlasFrames(null); + var separatedJS = Assets.getText(Path).split("\n"); + var lines:Array = []; + for (line in separatedJS) + { + if (StringTools.contains(line, "new createjs.SpriteSheet({")) + lines.push(line); + } + var names:Array = []; + var jsons:Array = []; + for (line in lines) + { + names.push(StringTools.replace(line.split(".")[0], "_", " ")); + var curJson = StringTools.replace(StringTools.replace(line.split("(")[1], ")", ""), ";", ""); + var parsedJson = haxe.Json.parse(~/({|,\s*)(\S+)(\s*:)/g.replace(curJson, '$1\"$2"$3')); + jsons.push(parsedJson); + } + var prevName = ""; + var imagePath = Path.split("/"); + imagePath.pop(); + for (i in 0...names.length) + { + var times = 0; + var name = names[i]; + var json = jsons[i]; + var bitmap = FlxG.bitmap.add((Image == null) ? '${imagePath.join("/")}/${json.images[0]}' : Image); + var frames = new FlxAtlasFrames(bitmap); + for (frame in json.frames) + { + var frameRect:FlxRect = new FlxRect(frame[0], frame[1], frame[2], frame[3]); + var sourceSize:FlxPoint = new FlxPoint(frameRect.width, frameRect.height); + var offset = new FlxPoint(-frame[5], -frame[6]); + frames.addAtlasFrame(frameRect, sourceSize, offset, name + Std.string(times)); + times++; + } + for (frame in frames.frames) + { + hugeFrames.pushFrame(frame); + } + } + return hugeFrames; + } + + static function cocosHelper(FrameName:String, FrameData:Dynamic, Frames:FlxAtlasFrames) + { + var rotated:Bool = FrameData.textureRotated; + var name:String = FrameName; + var sourceSize:FlxPoint = FlxPoint.get(Std.parseFloat(FrameData.spriteSourceSize[0]), Std.parseFloat(FrameData.spriteSourceSize[1])); + var offset:FlxPoint = FlxPoint.get(-Std.parseFloat(FrameData.spriteOffset[0]), -Std.parseFloat(FrameData.spriteOffset[1])); + var angle:FlxFrameAngle = FlxFrameAngle.ANGLE_0; + var frameRect:FlxRect = null; + + var frame = FrameData.textureRect; + if (rotated) + { + frameRect = FlxRect.get(Std.parseFloat(frame[0]), Std.parseFloat(frame[1]), Std.parseFloat(frame[3]), Std.parseFloat(frame[2])); + angle = FlxFrameAngle.ANGLE_NEG_90; + } + else + { + frameRect = FlxRect.get(Std.parseFloat(frame[0]), Std.parseFloat(frame[1]), Std.parseFloat(frame[2]), Std.parseFloat(frame[3])); + } + + Frames.addAtlasFrame(frameRect, sourceSize, offset, name, angle); + } + + static function starlingHelper(FrameName:String, FrameData:Dynamic, Frames:FlxAtlasFrames):Void + { + var rotated:Bool = FrameData.rotated; + var name:String = FrameName; + var sourceSize:FlxPoint = FlxPoint.get(Std.parseFloat(FrameData.sourceSize[0]), Std.parseFloat(FrameData.sourceSize[1])); + var offset:FlxPoint = FlxPoint.get(-Std.parseFloat(FrameData.offset[0]), -Std.parseFloat(FrameData.offset[1])); + var angle:FlxFrameAngle = FlxFrameAngle.ANGLE_0; + var frameRect:FlxRect = null; + + var frame = FrameData.frame; + if (rotated) + { + frameRect = FlxRect.get(Std.parseFloat(frame[0]), Std.parseFloat(frame[1]), Std.parseFloat(frame[3]), Std.parseFloat(frame[2])); + angle = FlxFrameAngle.ANGLE_NEG_90; + } + else + { + frameRect = FlxRect.get(Std.parseFloat(frame[0]), Std.parseFloat(frame[1]), Std.parseFloat(frame[2]), Std.parseFloat(frame[3])); + } + + Frames.addAtlasFrame(frameRect, sourceSize, offset, name, angle); + } + + static function textureAtlasHelper(SpriteMap:BitmapData, limb:AnimateSpriteData, curMeta:Meta) + { + var width = (limb.rotated) ? limb.h : limb.w; + var height = (limb.rotated) ? limb.w : limb.h; + var sprite = new BitmapData(width, height, true, 0); + var matrix = new FlxMatrix(1,0,0,1,-limb.x,-limb.y); + if (limb.rotated) + { + matrix.rotateByNegative90(); + matrix.translate(0, height); + } + sprite.draw(SpriteMap, matrix); + + @:privateAccess + var curFrame = new FlxFrame(FlxG.bitmap.add(sprite)); + curFrame.name = limb.name; + curFrame.sourceSize.set(width, height); + curFrame.frame = new FlxRect(0,0, width, height); + return curFrame; + } + + static function texturePackerHelper(FrameName:String, FrameData:Dynamic, Frames:FlxAtlasFrames):Void + { + var rotated:Bool = FrameData.rotated; + var name:String = FrameName; + var sourceSize:FlxPoint = FlxPoint.get(FrameData.sourceSize.w, FrameData.sourceSize.h); + var offset:FlxPoint = FlxPoint.get(FrameData.spriteSourceSize.x, FrameData.spriteSourceSize.y); + var angle:FlxFrameAngle = FlxFrameAngle.ANGLE_0; + var frameRect:FlxRect = null; + + if (rotated) + { + frameRect = FlxRect.get(FrameData.frame.x, FrameData.frame.y, FrameData.frame.h, FrameData.frame.w); + angle = FlxFrameAngle.ANGLE_NEG_90; + } + else + { + frameRect = FlxRect.get(FrameData.frame.x, FrameData.frame.y, FrameData.frame.w, FrameData.frame.h); + } + + Frames.addAtlasFrame(frameRect, sourceSize, offset, name, angle); + } + static function max(a:Int, b:Int):Int + return a < b ? b : a; +} +// code made by noonat 11 years ago, not mine lol +class PropertyList +{ + static var _dateRegex:EReg = ~/(\d{4}-\d{2}-\d{2})(?:T(\d{2}:\d{2}:\d{2})Z)?/; + + /** + * Parse an Apple property list XML file into a dynamic object. If + * the property list is empty, an empty object will be returned. + * @param text Text contents of the property list file. + */ + static public function parse(text:String):Dynamic + { + var fast = new Access(Xml.parse(text).firstElement()); + return fast.hasNode.dict ? parseDict(fast.node.dict) : {}; + } + + static function parseDate(text:String):Date + { + if (!_dateRegex.match(text)) + { + throw 'Invalid date "' + text + '" (only yyyy-mm-dd and yyyy-mm-ddThh:mm:ssZ supported)'; + } + text = _dateRegex.matched(1); + if (_dateRegex.matched(2) != null) + { + text += ' ' + _dateRegex.matched(2); + } + return Date.fromString(text); + } + + static function parseDict(node:Access):Dynamic + { + var key:String = null; + var result:Dynamic = {}; + for (childNode in node.elements) + { + if (childNode.name == 'key') + { + key = childNode.innerData; + } else if (key != null) + { + Reflect.setField(result, key, parseValue(childNode)); + } + } + return result; + } + + static function parseValue(node:Access):Dynamic + { + var value:Dynamic = null; + switch (node.name) + { + case 'array': + value = new Array(); + for (childNode in node.elements) + { + value.push(parseValue(childNode)); + } + + case 'dict': + value = parseDict(node); + + case 'date': + value = parseDate(node.innerData); + + case 'string': + var thing:Dynamic = node.innerData; + if (thing.charAt(0) == "{") + { + thing = StringTools.replace(thing, "{", ""); + thing = StringTools.replace(thing, "}", ""); + thing = thing.split(","); + } + value = thing; + case 'data': + value = node.innerData; + + case 'true': + value = true; + + case 'false': + value = false; + + case 'real': + value = Std.parseFloat(node.innerData); + + case 'integer': + value = Std.parseInt(node.innerData); + } + return value; + } +} +typedef JSJson = +{ + var images:Array; + var frames:Array>; +} +typedef FlxSparrow = OneOfTwo; +typedef FlxJson = OneOfTwo; +typedef FlxPropertyList = OneOfTwo; +typedef JsonNormal = +{ + frames:Dynamic, + meta:Meta +} +typedef Plist = +{ + frames:Dynamic, + metadata:Dynamic +} \ No newline at end of file diff --git a/source/funkin/chart/BaseGameParser.hx b/source/funkin/chart/BaseGameParser.hx index c111822b..85abbdd0 100644 --- a/source/funkin/chart/BaseGameParser.hx +++ b/source/funkin/chart/BaseGameParser.hx @@ -87,8 +87,13 @@ class BaseGameParser { } if (section.changeBPM && section.bpm != curBPM) { - // TODO: BPM CHANGE EVENT curCrochet = ((60 / (curBPM = section.bpm)) * 1000); + + result.events.push({ + time: curTime, + type: BPM_CHANGE, + params: [section.bpm] + }); } curTime += curCrochet * beatsPerMesure; diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 514fb674..2fee02a3 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -94,7 +94,6 @@ class Note extends FlxSprite { super(); - // TODO: Sustain note this.prevNote = strumLine.notes.members.last(); this.noteTypeID = noteData.type.getDefault(0); this.isSustainNote = sustain; diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index d26e9df3..5a702456 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -561,7 +561,6 @@ class PlayState extends MusicBeatState generateSong(SONG); - trace(SONG.noteTypes); for(noteType in SONG.noteTypes) { var scriptPath = Paths.script('data/notes/${noteType}'); if (Assets.exists(scriptPath) && !scripts.contains(scriptPath)) { diff --git a/source/funkin/options/OptionsMenu.hx b/source/funkin/options/OptionsMenu.hx index 8736b4c9..6f743065 100644 --- a/source/funkin/options/OptionsMenu.hx +++ b/source/funkin/options/OptionsMenu.hx @@ -18,17 +18,17 @@ class OptionsMenu extends TreeMenu { substate: funkin.options.keybinds.KeybindsOptions }, { - name: 'Gameplay', + name: 'Gameplay >', desc: 'Change Gameplay options such as Downscroll, Scroll Speed, Naughtyness...', state: GameplayOptions }, { - name: 'Appearance', + name: 'Appearance >', desc: 'Change Appearance options such as Flashing menus...', state: AppearanceOptions }, { - name: 'Miscellaneous', + name: 'Miscellaneous >', desc: 'Use this menu to reset save data or engine settings.', state: MiscOptions } @@ -112,7 +112,7 @@ class OptionsMenu extends TreeMenu { } options.push(new Checkbox(name, desc, node.att.id, FlxG.save.data)); case "menu": - options.push(new TextOption(name, desc, function() { + options.push(new TextOption(name + " >", desc, function() { optionsTree.add(new OptionsScreen(name, desc, parseOptionsFromXML(node))); })); } diff --git a/source/funkin/system/Conductor.hx b/source/funkin/system/Conductor.hx index d15591ae..6cb1fe60 100644 --- a/source/funkin/system/Conductor.hx +++ b/source/funkin/system/Conductor.hx @@ -15,7 +15,7 @@ import flixel.util.FlxSignal.FlxTypedSignal; typedef BPMChangeEvent = { - var stepTime:Int; + var stepTime:Float; var songTime:Float; var bpm:Float; } @@ -115,37 +115,35 @@ class Conductor public static function setupSong(SONG:ChartData) { reset(); - // mapBPMChanges(SONG); // TODO!!! + mapBPMChanges(SONG); changeBPM(SONG.meta.bpm, cast SONG.meta.beatsPerMesure.getDefault(4), cast SONG.meta.stepsPerBeat.getDefault(4)); } /** * Maps BPM changes from a song. * @param song Song to map BPM changes from. */ - public static function mapBPMChanges(song:SwagSong) + public static function mapBPMChanges(song:ChartData) { bpmChangeMap = []; - var curBPM:Float = song.bpm; - var totalSteps:Int = 0; - var totalPos:Float = 0; - for (i=>notes in song.notes) - { - if (notes == null) continue; - if (notes.changeBPM && notes.bpm != curBPM) - { - curBPM = notes.bpm; - var event:BPMChangeEvent = { - stepTime: totalSteps, - songTime: totalPos, - bpm: curBPM - }; - bpmChangeMap.push(event); - } + if (song.events == null) return; - var deltaSteps:Int = notes.lengthInSteps; - totalSteps += deltaSteps; - totalPos += ((60 / curBPM) * 1000 / 4) * deltaSteps; + var curBPM:Float = song.meta.bpm; + var songTime:Float = 0; + var stepTime:Float = 0; + + for(e in song.events) if (e.type == BPM_CHANGE && e.params != null && e.params[0] is Float) { + if (e.params[0] == curBPM) continue; + var steps = (e.time - songTime) / ((60 / curBPM) * 1000 / 4); + stepTime += steps; + songTime = e.time; + curBPM = e.params[0]; + + bpmChangeMap.push({ + stepTime: stepTime, + songTime: songTime, + bpm: curBPM + }); } } diff --git a/source/funkin/system/FlxAnimate.hx b/source/funkin/system/FlxAnimate.hx index b126187e..2e472945 100644 --- a/source/funkin/system/FlxAnimate.hx +++ b/source/funkin/system/FlxAnimate.hx @@ -1,5 +1,6 @@ package funkin.system; +import flixel.graphics.frames.FlxFramesCollection; import openfl.geom.ColorTransform; import flixel.math.FlxMatrix; import flixel.math.FlxAngle; @@ -8,6 +9,21 @@ import flixel.graphics.frames.FlxFrame; import flixel.math.FlxPoint; class FlxAnimate extends flxanimate.FlxAnimate { + public static var loadedPaths:Array = []; + public override function loadAtlas(Path:String) { + super.loadAtlas(Path); + loadedPaths.push(Path); + } + + public static function init() { + FlxG.signals.preStateSwitch.add(onSwitch); + } + + private static function onSwitch() { + for(p in loadedPaths) { + Assets.cache.clear(p); + } + } override function drawLimb(limb:FlxFrame, _matrix:FlxMatrix, ?colorTransform:ColorTransform) { if (alpha == 0 || colorTransform != null && (colorTransform.alphaMultiplier == 0 || colorTransform.alphaOffset == -255) || limb == null || limb.type == EMPTY) diff --git a/source/funkin/system/FunkinSprite.hx b/source/funkin/system/FunkinSprite.hx index 90339e0e..aada8ed8 100644 --- a/source/funkin/system/FunkinSprite.hx +++ b/source/funkin/system/FunkinSprite.hx @@ -152,8 +152,8 @@ class FunkinSprite extends FlxSprite implements IBeatReceiver implements IOffset } public override function destroy() { - super.destroy(); - animateAtlas = FlxDestroyUtil.destroy(animateAtlas); + animateAtlas = FlxDestroyUtil.destroy(animateAtlas); + super.destroy(); } #end diff --git a/source/funkin/system/Main.hx b/source/funkin/system/Main.hx index d1e105f8..7e87d42b 100644 --- a/source/funkin/system/Main.hx +++ b/source/funkin/system/Main.hx @@ -158,6 +158,7 @@ class Main extends Sprite #if GLOBAL_SCRIPT funkin.scripting.GlobalScript.init(); #end + funkin.system.FlxAnimate.init(); #if sys if (startedFromSource = Sys.args().contains("-livereload")) { diff --git a/source/lime/system/System.hx b/source/lime/system/System.hx index 6d3fe425..549adf70 100644 --- a/source/lime/system/System.hx +++ b/source/lime/system/System.hx @@ -424,8 +424,6 @@ class System #if sys private static function __parseArguments(attributes:WindowAttributes):Void { - // TODO: Handle default arguments, like --window-fps=60 - var arguments = Sys.args(); var stripQuotes = ~/^['"](.*)['"]$/; var equals, argValue, parameters = null; diff --git a/source/openfl/display3D/Context3D.hx b/source/openfl/display3D/Context3D.hx index d81ac241..0da9190c 100644 --- a/source/openfl/display3D/Context3D.hx +++ b/source/openfl/display3D/Context3D.hx @@ -271,7 +271,7 @@ import lime.math.Vector2; @:noCompletion private var __enableErrorChecking:Bool; @:noCompletion private var __fragmentConstants:Float32Array; @:noCompletion private var __frontBufferTexture:RectangleTexture; - @:noCompletion private var __positionScale:Float32Array; // TODO: Better approach? + @:noCompletion private var __positionScale:Float32Array; @:noCompletion private var __present:Bool; @:noCompletion private var __programs:Map; @:noCompletion private var __quadIndexBuffer:IndexBuffer3D; @@ -1000,8 +1000,6 @@ import lime.math.Vector2; **/ public function dispose(recreate:Bool = true):Void { - // TODO: Dispose all related buffers - gl = null; __dispose(); } @@ -1073,9 +1071,6 @@ import lime.math.Vector2; __flushGLFramebuffer(); __flushGLViewport(); - - // TODO: Read less pixels if srcRect is smaller - //! EDITED BY NE_EO TO REDUCE GARBAGE MEMORY var buffer = UInt8Buff.get(backBufferWidth * backBufferHeight * 4); // new UInt8Array(backBufferWidth * backBufferHeight * 4); var data = buffer.buffer; @@ -1177,14 +1172,12 @@ import lime.math.Vector2; #if !openfl_disable_display_render if (__state.renderToTexture == null) { - // TODO: Make sure state is correct for this? if (__stage.context3D == this && !__stage.__renderer.__cleared) { __stage.__renderer.__clear(); } else if (!__cleared) { - // TODO: Throw error if error reporting is enabled? clear(0, 0, 0, 0, 1, 0, Context3DClearMask.COLOR); } } @@ -1230,7 +1223,7 @@ import lime.math.Vector2; if (!__cleared) { // Make sure texture is initialized - // TODO: Throw error if error reporting is enabled? + // BASE-TODO: Throw error if error reporting is enabled? clear(0, 0, 0, 0, 1, 0, Context3DClearMask.COLOR); } @@ -1291,7 +1284,7 @@ import lime.math.Vector2; __state.blendSourceAlphaFactor = sourceAlphaFactor; __state.blendDestinationAlphaFactor = destinationAlphaFactor; - // TODO: Better way to handle this? + // BASE-TODO: Better way to handle this? __setGLBlendEquation(gl.FUNC_ADD); } @@ -1370,7 +1363,7 @@ import lime.math.Vector2; public function setProgram(program:Program3D):Void { __state.program = program; - __state.shader = null; // TODO: Merge this logic + __state.shader = null; // BASE-TODO: Merge this logic if (program != null) { @@ -1414,11 +1407,11 @@ import lime.math.Vector2; if (__state.program != null && __state.program.__format == GLSL) { - // TODO + // BASE-TODO } else { - // TODO: Cleanup? + // BASE-TODO: Cleanup? if (numRegisters == -1) { @@ -1472,7 +1465,7 @@ import lime.math.Vector2; { __flushGLProgram(); - // TODO: Cache value, prevent need to copy + // BASE-TODO: Cache value, prevent need to copy var data = new Float32Array(16); for (i in 0...16) { @@ -1937,7 +1930,7 @@ import lime.math.Vector2; @:noCompletion private function __bindGLTexture2D(texture:GLTexture):Void { - // TODO: Need to consider activeTexture ID + // BASE-TODO: Need to consider activeTexture ID // if (#if openfl_disable_context_cache true #else __contextState.__currentGLTexture2D != texture #end) { @@ -1949,7 +1942,7 @@ import lime.math.Vector2; @:noCompletion private function __bindGLTextureCubeMap(texture:GLTexture):Void { - // TODO: Need to consider activeTexture ID + // BASE-TODO: Need to consider activeTexture ID // if (#if openfl_disable_context_cache true #else __contextState.__currentGLTextureCubeMap != texture #end) { @@ -1988,14 +1981,14 @@ import lime.math.Vector2; #if !openfl_disable_display_render if (__state.renderToTexture == null) { - // TODO: Make sure state is correct for this? + // BASE-TODO: Make sure state is correct for this? if (__stage.context3D == this && !__stage.__renderer.__cleared) { __stage.__renderer.__clear(); } else if (!__cleared) { - // TODO: Throw error if error reporting is enabled? + // BASE-TODO: Throw error if error reporting is enabled? clear(0, 0, 0, 0, 1, 0, Context3DClearMask.COLOR); } } @@ -2191,7 +2184,7 @@ import lime.math.Vector2; if (#if openfl_disable_context_cache true #else __contextState.shader != shader #end) { - // TODO: Merge this logic + // BASE-TODO: Merge this logic if (__contextState.shader != null) { @@ -2319,7 +2312,7 @@ import lime.math.Vector2; { // if (#if openfl_disable_context_cache true #else texture != __contextState.textures[i] #end) { - // TODO: Cleaner approach? + // BASE-TODO: Cleaner approach? if (texture.__textureTarget == gl.TEXTURE_2D) { __bindGLTexture2D(texture.__getTexture()); @@ -2330,7 +2323,7 @@ import lime.math.Vector2; } #if (desktop && !html5) - // TODO: Cache? + // BASE-TODO: Cache? gl.enable(gl.TEXTURE_2D); #end @@ -2364,7 +2357,7 @@ import lime.math.Vector2; gl.uniform1i(__state.program.__agalAlphaSamplerEnabled[sampler].location, 1); #if (desktop && !html5) - // TODO: Cache? + // BASE-TODO: Cache? gl.enable(gl.TEXTURE_2D); #end } @@ -2384,7 +2377,7 @@ import lime.math.Vector2; @:noCompletion private function __flushGLViewport():Void { - // TODO: Cache + // BASE-TODO: Cache if (__state.renderToTexture == null) { @@ -2403,7 +2396,7 @@ import lime.math.Vector2; { var width = 0, height = 0; - // TODO: Avoid use of Std.is + // BASE-TODO: Avoid use of Std.is if ((__state.renderToTexture is Texture)) { var texture2D:Texture = cast __state.renderToTexture; @@ -2467,7 +2460,7 @@ import lime.math.Vector2; case GREATER: gl.GREATER; case GREATER_EQUAL: gl.GEQUAL; case LESS: gl.LESS; - case LESS_EQUAL: gl.LEQUAL; // TODO : wrong value + case LESS_EQUAL: gl.LEQUAL; // BASE-TODO : wrong value case NEVER: gl.NEVER; case NOT_EQUAL: gl.NOTEQUAL; default: gl.EQUAL; @@ -2662,7 +2655,7 @@ import lime.math.Vector2; { if (__glMemoryCurrentAvailable != -1) { - // TODO: Return amount used by this application only + // BASE-TODO: Return amount used by this application only var current = gl.getParameter(__glMemoryCurrentAvailable); var total = gl.getParameter(__glMemoryTotalAvailable);