From ae89e0259a70bf50d2829a6fe56c10f7170a92ee Mon Sep 17 00:00:00 2001 From: Yoshman29 <81191621+YoshiCrafter29@users.noreply.github.com> Date: Wed, 21 Jan 2026 18:20:39 +0100 Subject: [PATCH] Animate Atlas character editor previews --- source/funkin/backend/system/Flags.hx | 3 +- .../editors/character/CharacterAnimButton.hx | 11 ++-- .../editors/character/CharacterAnimsWindow.hx | 50 ++++++++++++++++--- .../editors/character/CharacterGhost.hx | 3 ++ .../character/CharacterPropertiesWindow.hx | 2 +- 5 files changed, 52 insertions(+), 17 deletions(-) diff --git a/source/funkin/backend/system/Flags.hx b/source/funkin/backend/system/Flags.hx index 0eb17d06..df73b06d 100644 --- a/source/funkin/backend/system/Flags.hx +++ b/source/funkin/backend/system/Flags.hx @@ -332,8 +332,9 @@ class Flags { if (!(parsed = parse(name, value))) customFlags.set(name, value); if (!overridenFlags.exists(name)) overridenFlags.set(name, parsed); } - + #if MODCHARTING_FEATURES Options.modchartingHoldSubdivisions = DEFAULT_MODCHART_HOLD_SUBDIVISIONS; + #end } /** diff --git a/source/funkin/editors/character/CharacterAnimButton.hx b/source/funkin/editors/character/CharacterAnimButton.hx index d834434e..6d522cb6 100644 --- a/source/funkin/editors/character/CharacterAnimButton.hx +++ b/source/funkin/editors/character/CharacterAnimButton.hx @@ -8,6 +8,7 @@ import openfl.geom.Rectangle; import funkin.backend.utils.XMLUtil.AnimData; import flixel.math.FlxPoint; import flixel.util.FlxColor; +import funkin.editors.character.CharacterAnimsWindow; using StringTools; @@ -242,7 +243,7 @@ class CharacterAnimButton extends UIButton { parent.character.animOffsets.remove(anim); parent.character.animOffsets.set(newName, animOffset); - var displayFrame:{scale:Float, animBounds:Rectangle, frame:Int} = parent.displayAnimsFramesList[anim]; + var displayFrame:DisplayAnimFrameEntry = parent.displayAnimsFramesList[anim]; parent.displayAnimsFramesList.remove(anim); parent.displayAnimsFramesList.set(newName, displayFrame); @@ -396,12 +397,9 @@ class CharacterAnimButton extends UIButton { updateButtonsPos(); super.draw(); - if (parent.character.isAnimate) // TODO: displayWindowSprite for atlases - return; - if (!closed && parent.displayAnimsFramesList.exists(anim)) { - var displayData:{frame:Int, scale:Float, animBounds:Rectangle} = parent.displayAnimsFramesList.get(anim); - parent.displayWindowSprite.frame = parent.displayWindowSprite.frames.frames[displayData.frame]; + var displayData:DisplayAnimFrameEntry = parent.displayAnimsFramesList.get(anim); + parent.displayWindowSprite.frame = displayData.frame; parent.displayWindowSprite.scale.x = parent.displayWindowSprite.scale.y = displayData.scale; parent.displayWindowSprite.updateHitbox(); @@ -476,7 +474,6 @@ class CharacterAnimButton extends UIButton { @:noCompletion function __refreshAnimation() @:privateAccess { refreshAnimation(__getFlxAnimation(), data); - // TODO: displayWindowSprite for atlases if (valid) { parent.buildAnimDisplay(anim, data); animationDisplayBG.alpha = 1; diff --git a/source/funkin/editors/character/CharacterAnimsWindow.hx b/source/funkin/editors/character/CharacterAnimsWindow.hx index af731a18..8d76aeab 100644 --- a/source/funkin/editors/character/CharacterAnimsWindow.hx +++ b/source/funkin/editors/character/CharacterAnimsWindow.hx @@ -8,15 +8,24 @@ import openfl.geom.Rectangle; import flixel.graphics.frames.FlxFrame; import funkin.game.Character; import flixel.animation.FlxPrerotatedAnimation; +import animate.internal.RenderTexture; +import flixel.graphics.frames.FlxFrame; +import funkin.backend.system.Logs; using funkin.backend.utils.BitmapUtil; +typedef DisplayAnimFrameEntry = { + scale:Float, + frame:FlxFrame, + renderTexture:RenderTexture +} + class CharacterAnimsWindow extends UIButtonList { public var character:CharacterGhost; public var displayWindowSprite:FlxSprite; public var displayWindowGraphic:FlxGraphic; - public var displayAnimsFramesList:Map}> = []; + public var displayAnimsFramesList:Map = []; public var animButtons:Map = []; public var animsList:Array = []; @@ -70,22 +79,47 @@ class CharacterAnimsWindow extends UIButtonList { public function buildAnimDisplay(name:String, anim:AnimData) @:privateAccess { var anim:FlxAnimation = character.animation._animations[anim.name]; - if (anim == null || anim.frames.length <= 0) return; + if (anim == null) return; - var frameIndex:Int = anim.frames.getDefault([0])[0]; - var frame:FlxFrame = displayWindowSprite.frames.frames[frameIndex]; + if (character.isAnimate) { + var renderTex = character.generateRenderTextureForAnim(name); + var frame = renderTex.graphic.imageFrame.frame; - var frameRect:Rectangle = new Rectangle(frame.offset.x, frame.offset.y, frame.sourceSize.x, frame.sourceSize.y); - var animBounds:Rectangle = displayWindowGraphic != null ? displayWindowGraphic.bitmap.bounds(frameRect) : frameRect; + trace('Created anim display for ${name} with size ${frame.frame.width}, ${frame.frame.height} (${renderTex.graphic.width}, ${renderTex.graphic.height})'); + + displayAnimsFramesList.set(name, { + frame: frame, + scale: 104/Math.max(frame.frame.width, frame.frame.height), + renderTexture: renderTex + }); + } else { + var frameIndex:Int = anim.frames.getDefault([0])[0]; + var frame:FlxFrame = displayWindowSprite.frames.frames[frameIndex]; + + var frameRect:Rectangle = new Rectangle(frame.offset.x, frame.offset.y, frame.sourceSize.x, frame.sourceSize.y); + var animBounds:Rectangle = displayWindowGraphic != null ? displayWindowGraphic.bitmap.bounds(frameRect) : frameRect; + + displayAnimsFramesList.set(name, { + frame: character.frames.frames[anim.frames.getDefault([0])[0]], + scale: 104/Math.max(animBounds.width, animBounds.height), + renderTexture: null + }); + } - displayAnimsFramesList.set(name, {frame: anim.frames.getDefault([0])[0], scale: 104/Math.max(animBounds.width, animBounds.height), animBounds: animBounds}); } public function removeAnimDisplay(name:String) { - + if (displayAnimsFramesList.exists(name)) + displayAnimsFramesList[name].renderTexture?.destroy(); displayAnimsFramesList.remove(name); } + public function clearDisplayAnims() { + for(k=>e in displayAnimsFramesList) + e.renderTexture?.destroy(); + displayAnimsFramesList.clear(); + } + public function deleteAnimation(button:CharacterAnimButton, addToUndo:Bool = true) { FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_DELETE_SOUND)); if (buttons.members.length <= 1) return; diff --git a/source/funkin/editors/character/CharacterGhost.hx b/source/funkin/editors/character/CharacterGhost.hx index 94cad23a..02092984 100644 --- a/source/funkin/editors/character/CharacterGhost.hx +++ b/source/funkin/editors/character/CharacterGhost.hx @@ -84,9 +84,11 @@ class CharacterGhost extends Character { var oldRenderTexture:RenderTexture = this._renderTexture; var oldRenderTextureDirty = _renderTextureDirty; + var oldAlpha = alpha; this._renderTexture = null; this._renderTextureDirty = true; + this.alpha = 256.0/257.0; animation.play(anim, true, false, 0); @@ -96,6 +98,7 @@ class CharacterGhost extends Character { this._renderTexture = oldRenderTexture; this._renderTextureDirty = oldRenderTextureDirty; + this.alpha = oldAlpha; if (wasInvalidFrame) { colorTransform.color = 0xFFEF0202; diff --git a/source/funkin/editors/character/CharacterPropertiesWindow.hx b/source/funkin/editors/character/CharacterPropertiesWindow.hx index 15a3a960..b8777432 100644 --- a/source/funkin/editors/character/CharacterPropertiesWindow.hx +++ b/source/funkin/editors/character/CharacterPropertiesWindow.hx @@ -183,7 +183,7 @@ class CharacterPropertiesWindow extends UISliceSprite { character.sprite = sprite; animsWindow.displayWindowSprite.animation.reset(); - animsWindow.displayAnimsFramesList.clear(); + animsWindow.clearDisplayAnims(); if (animsWindow.displayWindowGraphic != null) animsWindow.displayWindowGraphic.destroy();