From 008cfd07484c24bd59af8d43846258ac97e26d14 Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Sat, 13 Apr 2024 17:22:44 +0200 Subject: [PATCH 01/89] Initial Stage Editor Commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: ⍚~Nex <87421482+NexIsDumb@users.noreply.github.com> --- source/funkin/backend/system/NothingCamera.hx | 34 + source/funkin/backend/utils/MatrixUtil.hx | 33 + source/funkin/editors/EditorPicker.hx | 2 +- source/funkin/editors/stager/StageEditor.hx | 648 ++++++++++++++++++ .../funkin/editors/stager/StageInfoScreen.hx | 169 +++++ .../funkin/editors/stager/StageSelection.hx | 43 ++ .../stager/elements/StageCharacterButton.hx | 55 ++ .../stager/elements/StageElementButton.hx | 112 +++ .../stager/elements/StageSolidButton.hx | 16 + .../stager/elements/StageSpriteButton.hx | 54 ++ source/funkin/editors/ui/UIButtonList.hx | 6 +- source/funkin/editors/ui/UISliceSprite.hx | 43 +- source/funkin/editors/ui/UIWindow.hx | 16 + source/funkin/game/Stage.hx | 111 ++- 14 files changed, 1295 insertions(+), 47 deletions(-) create mode 100644 source/funkin/backend/system/NothingCamera.hx create mode 100644 source/funkin/backend/utils/MatrixUtil.hx create mode 100644 source/funkin/editors/stager/StageEditor.hx create mode 100644 source/funkin/editors/stager/StageInfoScreen.hx create mode 100644 source/funkin/editors/stager/StageSelection.hx create mode 100644 source/funkin/editors/stager/elements/StageCharacterButton.hx create mode 100644 source/funkin/editors/stager/elements/StageElementButton.hx create mode 100644 source/funkin/editors/stager/elements/StageSolidButton.hx create mode 100644 source/funkin/editors/stager/elements/StageSpriteButton.hx diff --git a/source/funkin/backend/system/NothingCamera.hx b/source/funkin/backend/system/NothingCamera.hx new file mode 100644 index 00000000..12917499 --- /dev/null +++ b/source/funkin/backend/system/NothingCamera.hx @@ -0,0 +1,34 @@ +package funkin.backend.system; + +import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxFrame; +import flixel.graphics.tile.FlxDrawTrianglesItem; +import flixel.math.FlxMatrix; +import flixel.math.FlxPoint; +import flixel.system.FlxAssets.FlxShader; +import openfl.display.BitmapData; +import openfl.display.BlendMode; +import openfl.geom.ColorTransform; +import openfl.geom.Point; +import openfl.geom.Rectangle; + +class NothingCamera extends FlxCamera { + public static final instance = new NothingCamera(); + + public function new() { + super(); + + visible = false; + } + + override function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader) { return null;} + override function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader) { return null;} + override function clearDrawStack() {} + override function render() {} + + public override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {} + public override function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {} + public override function drawTriangles(graphic:FlxGraphic, vertices:DrawData, indices:DrawData, uvtData:DrawData, ?colors:DrawData, ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader):Void {} + + public override function update(elapsed:Float) {} +} \ No newline at end of file diff --git a/source/funkin/backend/utils/MatrixUtil.hx b/source/funkin/backend/utils/MatrixUtil.hx new file mode 100644 index 00000000..65230b94 --- /dev/null +++ b/source/funkin/backend/utils/MatrixUtil.hx @@ -0,0 +1,33 @@ +package funkin.backend.utils; + +import flixel.FlxCamera; +import flixel.math.FlxPoint; +import flixel.util.typeLimit.OneOfTwo; + +class MatrixUtil { + public static function getMatrixPosition(sprite:FlxSprite, points:OneOfTwo>, ?camera:FlxCamera, _width:Float = 1, _height:Float = 1):Array + { + //if(_width == -1) _width = sprite.width; + //if(_height == -1) _height = sprite.height; + if(camera == null) camera = sprite.camera; + if(points is FlxBasePoint) points = [points]; + var nc = funkin.backend.system.NothingCamera.instance; + nc.scroll.set(camera.scroll.x, camera.scroll.y); + //nc.zoom = camera.zoom; // might not be needed + nc.pixelPerfectRender = camera.pixelPerfectRender; + @:privateAccess sprite.drawComplex(nc); + + var points:Array = cast points; + @:privateAccess for(point in points) { + var x = sprite._matrix.__transformX(point.x * _width, point.y * _height); + var y = sprite._matrix.__transformY(point.x * _width, point.y * _height); + + // reset to ingame coords + x += camera.scroll.x; + y += camera.scroll.y; + + point.set(x, y); + } + return points; + } +} \ No newline at end of file diff --git a/source/funkin/editors/EditorPicker.hx b/source/funkin/editors/EditorPicker.hx index 8a2ebd89..534ec538 100644 --- a/source/funkin/editors/EditorPicker.hx +++ b/source/funkin/editors/EditorPicker.hx @@ -20,7 +20,7 @@ class EditorPicker extends MusicBeatSubstate { { name: "Stage Editor", iconID: 2, - state: null + state: funkin.editors.stager.StageSelection }, { name: "UI Debug State", diff --git a/source/funkin/editors/stager/StageEditor.hx b/source/funkin/editors/stager/StageEditor.hx new file mode 100644 index 00000000..69776852 --- /dev/null +++ b/source/funkin/editors/stager/StageEditor.hx @@ -0,0 +1,648 @@ +package funkin.editors.stager; + +import flixel.math.FlxAngle; +import flixel.util.FlxColor; +import flixel.math.FlxPoint; +import funkin.backend.system.framerate.Framerate; +import funkin.backend.utils.XMLUtil.AnimData; +import funkin.editors.stager.elements.*; +import funkin.editors.ui.UIContextMenu.UIContextMenuOption; +import funkin.game.Character; +import funkin.game.Stage; +import haxe.xml.Access; +import haxe.xml.Printer; + +using funkin.backend.utils.MatrixUtil; + +class StageEditor extends UIState { + static var __stage:String; + public var stage:Stage; + + public static var instance(get, null):StageEditor; + + private static inline function get_instance() + return FlxG.state is StageEditor ? cast FlxG.state : null; + + public var topMenu:Array; + public var topMenuSpr:UITopMenu; + + public var uiGroup:FlxTypedGroup = new FlxTypedGroup(); + public var stageSpritesWindow:UIButtonList; + + public var xmlMap:Map = new Map(); + + public var chars:Array = []; + + public var stageCamera:FlxCamera; + public var guideCamera:FlxCamera; + public var uiCamera:FlxCamera; + + public var undos:UndoList = new UndoList(); + + public inline static function exID(id:String) { + return "stageEditor." + id; + } + + public function new(stage:String) { + super(); + if (stage != null) __stage = stage; + } + + public override function create() { + super.create(); + + WindowUtils.suffix = " (Stage Editor)"; + SaveWarning.selectionClass = StageSelection; + SaveWarning.saveFunc = () -> {_file_save(null);}; + + topMenu = [ + { + label: "File", + childs: [ + { + label: "New", + onSelect: _file_new, + }, + null, + { + label: "Save", + keybind: [CONTROL, S], + onSelect: _file_save, + }, + { + label: "Save As...", + keybind: [CONTROL, SHIFT, S], + onSelect: _file_saveas, + }, + null, + { + label: "Exit", + onSelect: _file_exit + } + ] + }, + /*{ + label: "Edit", + childs: [ + { + label: "Undo", + keybind: [CONTROL, Z], + onSelect: _edit_undo + }, + { + label: "Redo", + keybinds: [[CONTROL, Y], [CONTROL, SHIFT, Z]], + onSelect: _edit_redo + } + ] + },*/ + /*{ + label: "Character", + childs: [ + { + label: "New Animation", + keybind: [CONTROL, N], + onSelect: _char_add_anim, + }, + { + label: "Edit Animation", + onSelect: _char_edit_anim, + }, + { + label: "Delete Animation", + keybind: [DELETE], + onSelect: _char_remove_anim, + }, + null, + { + label: "Edit Info", + onSelect: _char_edit_info, + } + ] + }, + { + label: "Playback", + childs: [ + { + label: "Play Animation", + keybind: [SPACE], + onSelect: _playback_play_anim, + }, + { + label: "Stop Animation", + onSelect: _playback_stop_anim + } + ] + }, + { + label: "Offsets", + childs: [ + { + label: "Move Left", + keybind: [LEFT], + onSelect: _offsets_left, + }, + { + label: "Move Up", + keybind: [UP], + onSelect: _offsets_up, + }, + { + label: "Move Down", + keybind: [DOWN], + onSelect: _offsets_down, + }, + { + label: "Move Right", + keybind: [RIGHT], + onSelect: _offsets_right, + }, + null, + { + label: "Move Extra Left", + keybind: [SHIFT, LEFT], + onSelect: _offsets_extra_left, + }, + { + label: "Move Extra Up", + keybind: [SHIFT, UP], + onSelect: _offsets_extra_up, + }, + { + label: "Move Extra Down", + keybind: [SHIFT, DOWN], + onSelect: _offsets_extra_down, + }, + { + label: "Move Extra Right", + keybind: [SHIFT, RIGHT], + onSelect: _offsets_extra_right, + }, + null, + { + label: "Clear Offsets", + keybind: [CONTROL, R], + onSelect: _offsets_clear, + } + ] + },*/ + { + label: "View", + childs: [ + { + label: "Zoom in", + keybind: [CONTROL, NUMPADPLUS], + onSelect: _view_zoomin + }, + { + label: "Zoom out", + keybind: [CONTROL, NUMPADMINUS], + onSelect: _view_zoomout + }, + { + label: "Reset zoom", + keybind: [CONTROL, NUMPADZERO], + onSelect: _view_zoomreset + }, + + ] + }, + ]; + + stageCamera = FlxG.camera; + + guideCamera = new FlxCamera(); + guideCamera.bgColor = 0; + + uiCamera = new FlxCamera(); + uiCamera.bgColor = 0; + + FlxG.cameras.add(guideCamera, false); + FlxG.cameras.add(uiCamera, false); + + // Load from xml + var order:Array = []; + stage = new Stage(__stage, this, false); + stage.onXMLLoaded = function(xml:Access, elems:Array) { + return elems; + } + stage.onNodeLoaded = function(node:Access, sprite:Dynamic):Dynamic { + if(sprite is FunkinSprite) { + sprite.forceIsOnScreen = true; // hack + sprite.extra.set(exID("type"), node.name); + //sprite.active = false; + } + if(sprite is StageCharPos) { + var charPos:StageCharPos = cast sprite; + var charName = switch(charPos.name) { + case "boyfriend": "bf"; + case "girlfriend": "gf"; + default: charPos.name; + } + var char = new Character(0,0, charName, stage.isCharFlipped(charPos.name, charName == "bf")); + char.debugMode = true; + // Play first anim, and make it the last frame + var animToPlay = char.getAnimOrder()[0]; + char.playAnim(animToPlay, true, NONE); + var lastIndx = (char.animateAtlas != null) ? + char.animateAtlas.anim.length - 1 : + char.animation.curAnim.numFrames - 1; + char.playAnim(animToPlay, true, NONE, false, lastIndx); + char.stopAnimation(); + + // Add it to the stage + char.visible = true; + char.alpha = 0.5; + char.extra.set(exID("node"), node); + char.extra.set(exID("pos"), charPos); + charPos.extra.set(exID("char"), char); + chars.push(char); + } + order.push(sprite); + xmlMap.set(sprite, node); + return sprite; + } + stage.loadXml(stage.stageXML, true); + add(stage); + + for(char in chars) { + var charPos = char.extra.get(exID("pos")); + var node = char.extra.get(exID("node")); + + stage.applyCharStuff(char, charPos.name, 0); + } + + zoom = calculateZoom(stage.defaultZoom); + + topMenuSpr = new UITopMenu(topMenu); + topMenuSpr.cameras = uiGroup.cameras = [uiCamera]; + + final margin = 22; + final width = 470; + final TOP_MENU_HEIGHT = 25; + var buttonSize:FlxPoint = FlxPoint.get(width-margin*2, 32); + stageSpritesWindow = new UIButtonList(Std.int(FlxG.width - width), TOP_MENU_HEIGHT, width, Std.int(FlxG.height - TOP_MENU_HEIGHT), "Stage Sprites", buttonSize); + stageSpritesWindow.collapsable = true; + stageSpritesWindow.addButton.callback = () -> { + // TODO: implement this + } + for (i=>sprite in order) { + trace(sprite, Type.getClassName(Type.getClass(sprite))); + var xml = xmlMap.get(sprite); + if(xml != null) { + if(sprite is FunkinSprite) { + var type = sprite.extra.get(exID("type")); + stageSpritesWindow.add((type == "box" || type == "solid") ? new StageSolidButton(0,0, sprite, xml) : new StageSpriteButton(0,0, sprite, xml)); + } + else if(sprite is StageCharPos) { + stageSpritesWindow.add(new StageCharacterButton(0,0, sprite, xml)); + } + } + } + uiGroup.add(stageSpritesWindow); + + add(topMenuSpr); + add(uiGroup); + + if(Framerate.isLoaded) { + Framerate.fpsCounter.alpha = 0.4; + Framerate.memoryCounter.alpha = 0.4; + Framerate.codenameBuildField.alpha = 0.4; + } + + DiscordUtil.call("onEditorLoaded", ["Stage Editor", __stage]); + } + + override function destroy() { + super.destroy(); + nextScroll = FlxDestroyUtil.destroy(nextScroll); + if(Framerate.isLoaded) { + Framerate.fpsCounter.alpha = 1; + Framerate.memoryCounter.alpha = 1; + Framerate.codenameBuildField.alpha = 1; + } + } + + //private var movingCam:Bool = false; + //private var camDragSpeed:Float = 1.2; + + private var nextScroll:FlxPoint = FlxPoint.get(0,0); + + public override function update(elapsed:Float) { + super.update(elapsed); + + if (true) { + if(FlxG.keys.justPressed.ANY) + UIUtil.processShortcuts(topMenu); + } + + /*if (character != null) + characterPropertiresWindow.characterInfo.text = '${character.getNameList().length} Animations\nFlipped: ${character.flipX}\nSprite: ${character.sprite}\nAnim: ${character.getAnimName()}\nOffset: (${character.frameOffset.x}, ${character.frameOffset.y})'; + + if (!(characterPropertiresWindow.hovered || characterAnimsWindow.hovered) && !characterAnimsWindow.dragging) { + if (FlxG.mouse.wheel != 0) { + zoom += 0.25 * FlxG.mouse.wheel; + __camZoom = Math.pow(2, zoom); + } + + if (FlxG.mouse.justReleasedRight) { + closeCurrentContextMenu(); + openContextMenu(topMenu[2].childs); + } + if (FlxG.mouse.pressed) { + nextScroll.set(nextScroll.x - FlxG.mouse.deltaScreenX, nextScroll.y - FlxG.mouse.deltaScreenY); + currentCursor = HAND; + } else + currentCursor = ARROW; + } else if (!FlxG.mouse.pressed) + currentCursor = ARROW; + + characterBG.scale.set(FlxG.width/characterBG.width, FlxG.height/characterBG.height); + characterBG.scale.set(characterBG.scale.x / charCamera.zoom, characterBG.scale.y / charCamera.zoom);*/ + + if (true/*!(characterPropertiresWindow.hovered || characterAnimsWindow.hovered) && !characterAnimsWindow.dragging*/) { + if (FlxG.mouse.wheel != 0) { + zoom += 0.25 * FlxG.mouse.wheel; + updateZoom(); + } + + //if (FlxG.mouse.justReleasedRight) { + // closeCurrentContextMenu(); + // openContextMenu(topMenu[2].childs); + //} + if (FlxG.mouse.pressed) { + nextScroll.set(nextScroll.x - FlxG.mouse.deltaScreenX, nextScroll.y - FlxG.mouse.deltaScreenY); + currentCursor = HAND; + } else + currentCursor = ARROW; + } else if (!FlxG.mouse.pressed) + currentCursor = ARROW; + + stageCamera.scroll.set( + lerp(stageCamera.scroll.x, nextScroll.x, 0.35), + lerp(stageCamera.scroll.y, nextScroll.y, 0.35) + ); + + stageCamera.zoom = lerp(stageCamera.zoom, __camZoom, 0.125); + + WindowUtils.prefix = undos.unsaved ? "* " : ""; + SaveWarning.showWarning = undos.unsaved; + } + + // TOP MENU OPTIONS + #if REGION + function _file_exit(_) { + if (undos.unsaved) SaveWarning.triggerWarning(); + else FlxG.switchState(new StageSelection()); + } + + function _file_new(_) { + } + + function _file_save(_) { + #if sys + CoolUtil.safeSaveFile( + '${Paths.getAssetsRoot()}/data/stages/${stage.stageName}.xml', + buildStage() + ); + undos.save(); + #else + _file_saveas(_); + #end + } + + function _file_saveas(_) { + openSubState(new SaveSubstate(buildStage(), { + defaultSaveFile: '${stage.stageName}.xml' + })); + undos.save(); + } + + function buildStage():String { + /*if (character.isPlayer != character.playerOffsets) { + character.switchOffset('singLEFT', 'singRIGHT'); + character.switchOffset('singLEFTmiss', 'singRIGHTmiss'); + } + var charXML:Xml = character.buildXML([ + for (button in characterAnimsWindow.buttons.members) + button.anim + ]); + + // clean + if (charXML.exists("gameOverChar") && character.gameOverCharacter == "bf-dead") charXML.remove("gameOverChar"); + if (charXML.exists("camx") && character.cameraOffset.x == 0) charXML.remove("camx"); + if (charXML.exists("camy") && character.cameraOffset.y == 0) charXML.remove("camy"); + if (charXML.exists("holdTime") && character.holdTime == 4) charXML.remove("holdTime"); + if (charXML.exists("flipX") && !character.flipX) charXML.remove("flipX"); + if (charXML.exists("scale") && character.scale.x == 1) charXML.remove("scale"); + if (charXML.exists("antialiasing") && character.antialiasing) charXML.remove("antialiasing");*/ + + return "\n";// + Printer.print(charXML, true); + } + + /*function _edit_undo(_) { + var undo = undos.undo(); + switch(undo) { + case null: + // do nothing + case CEditInfo(oldInfo, newInfo): + editInfo(oldInfo, false); + case CCreateAnim(animID, animData): + deleteAnim(animData.name, false); + case CEditAnim(name, oldData, animData): + editAnim(name, oldData, false); + case CDeleteAnim(animID, animData): + createAnim(animData, animID, false); + case CChangeOffset(name, change): + changeOffset(name, change * -1, false); + case CResetOffsets(oldOffsets): + for (anim => offsets in oldOffsets) { + character.animOffsets.set(anim, offsets.clone()); + ghosts.setOffsets(anim, offsets.clone()); + } + + for (charButton in characterAnimsWindow.buttons.members) + charButton.updateInfo(charButton.anim, character.getAnimOffset(charButton.anim), ghosts.animGhosts[charButton.anim].visible); + + changeOffset(character.getAnimName(), FlxPoint.get(0, 0), false); // apply da new offsets + } + } + + function _edit_redo(_) { + var redo = undos.redo(); + switch(redo) { + case null: + // do nothing + case CEditInfo(oldInfo, newInfo): + editInfo(newInfo, false); + case CCreateAnim(animID, animData): + createAnim(animData, animID, false); + case CEditAnim(name, oldData, animData): + editAnim(oldData.name, animData, false); + case CDeleteAnim(animID, animData): + deleteAnim(animData.name, false); + case CChangeOffset(name, change): + changeOffset(name, change, false); + case CResetOffsets(oldOffsets): + clearOffsets(false); + } + }*/ + + public function editInfoWithUI() { + FlxG.state.openSubState(new StageInfoScreen(stage, (_) -> { + if (_ != null) editInfo(_); + })); + } + + public function editInfo(newInfo:Xml, addtoUndo:Bool = true) { + /*var oldInfo = stage.buildXML(); + stage.applyXML(new Access(newInfo)); + + if (addtoUndo) + undos.addToUndo(CEditInfo(oldInfo, newInfo));*/ + } + + var zoom(default, set):Float = 0; + var __camZoom(default, set):Float = 1; + function set_zoom(val:Float) { + return zoom = FlxMath.bound(val, -3.5, 1.75); // makes zooming not lag behind when continuing scrolling + } + function set___camZoom(val:Float) { + return __camZoom = FlxMath.bound(val, 0.1, 3); + } + + function _view_zoomin(_) { + zoom += 0.25; + updateZoom(); + } + function _view_zoomout(_) { + zoom -= 0.25; + updateZoom(); + } + function _view_zoomreset(_) { + zoom = 0; + updateZoom(); + } + + inline function updateZoom() { + __camZoom = Math.pow(2, zoom); + } + + inline function calculateZoom(zoom:Float) { + return Math.log(zoom) / Math.log(2); + } + #end + + override function draw() { + super.draw(); + + if(dot == null) { + dot = new FlxSprite().makeGraphic(10, 10, FlxColor.RED); + dot.camera = stageCamera; + dot.forceIsOnScreen = true; + } + //guideCamera.zoom = stageCamera.zoom; + //dot.scrollFactor.set(0, 0); + + /*for(member in members) { + if(member is FlxSprite) { + if(camera == null || camera == stageCamera) { + var sprite:FlxSprite = cast member; + @:privateAccess if(sprite._frame == null) continue; + if(sprite.visible) { + //trace("Drawing Guides for " + sprite); + drawGuides(sprite); + } + } + } + }*/ + for(sprite in stage.stageSprites) { + if(sprite.visible) { + @:privateAccess if(sprite._frame == null) continue; + drawGuides(sprite); + } + } + for(char in chars) { + if(char.visible) { + @:privateAccess if(char._frame == null) continue; + drawGuides(char); + } + } + } + + function drawGuides(sprite:FlxSprite) { + var oldWidth = sprite.width; + var oldHeight = sprite.height; + var oldOffset = sprite.offset.clone(FlxPoint.weak()); + var oldOrigin = sprite.origin.clone(FlxPoint.weak()); + sprite.updateHitbox(); + sprite.offset.copyFrom(oldOffset); + sprite.origin.copyFrom(oldOrigin); + + var corners = sprite.getMatrixPosition([ + // corners + FlxPoint.get(0, 0), + FlxPoint.get(1, 0), + FlxPoint.get(0, 1), + FlxPoint.get(1, 1), + // edges + FlxPoint.get(0, 0.5), + FlxPoint.get(1, 0.5), + FlxPoint.get(0.5, 1), + FlxPoint.get(0.5, 0), + // center + //FlxPoint.get(0.5, 0.5) + ], sprite.camera, sprite.width, sprite.height); + + //Logs.trace("Guide at " + corners[0].x + ", " + corners[0].y + " sprite at " + sprite.x + ", " + sprite.y); + + for(corner in corners) { + drawDot(corner.x, corner.y); + corner.put(); + } + + drawLine(corners[0], corners[1]); // tl - tr + drawLine(corners[0], corners[2]); // tl - bl + drawLine(corners[1], corners[3]); // tr - br + drawLine(corners[2], corners[3]); // bl - br + + // reset hitbox to old values + sprite.width = oldWidth; + sprite.height = oldHeight; + } + + inline function drawDot(x:Float, y:Float) { + dot.setPosition(x, y); + dot.scale.set(0.7/stageCamera.zoom, 0.7/stageCamera.zoom); + dot.x -= dot.width / 2; + dot.y -= dot.height / 2; + dot.draw(); + } + + function drawLine(point1:FlxPoint, point2:FlxPoint) { + var dx:Float = point2.x - point1.x; + var dy:Float = point2.y - point1.y; + + var angle:Float = Math.atan2(dy, dx); + var distance:Float = Math.sqrt(dx * dx + dy * dy); + + dot.setPosition(point1.x, point1.y); + dot.angle = angle * FlxAngle.TO_DEG; + dot.origin.set(0, dot.frameHeight / 2); + dot.scale.x = distance / dot.frameWidth; + dot.scale.y = 0.20/stageCamera.zoom; + //dot.x -= dot.width / 2; + dot.y -= dot.height / 2; + dot.draw(); + // Reset the angle and scale + dot.angle = 0; + dot.scale.x = dot.scale.y = 1; + dot.updateHitbox(); + } + + var dot:FlxSprite = null; +} + +enum StageChange { + CEditInfo(oldInfo:Xml, newInfo:Xml); +} \ No newline at end of file diff --git a/source/funkin/editors/stager/StageInfoScreen.hx b/source/funkin/editors/stager/StageInfoScreen.hx new file mode 100644 index 00000000..89b3cedf --- /dev/null +++ b/source/funkin/editors/stager/StageInfoScreen.hx @@ -0,0 +1,169 @@ +package funkin.editors.stager; + +import flixel.math.FlxPoint; +import funkin.editors.extra.PropertyButton; +import funkin.game.Stage; +import haxe.xml.Access; + +class StageInfoScreen extends UISubstateWindow { + public var stage:Stage; + + public var saveButton:UIButton; + public var closeButton:UIButton; + + public var onSave:(xml:Xml) -> Void = null; + + public function new(stage:Stage, ?onSave:(xml:Xml) -> Void) { + this.stage = stage; + this.onSave = onSave; + super(); + } + + public override function create() { + winTitle = "Editing Stage"; + winWidth = 1014; + winHeight = 600; + + super.create(); + + function addLabelOn(ui:UISprite, text:String) + add(new UIText(ui.x, ui.y - 24, 0, text)); + + /*var title:UIText; + add(title = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Sprite Data", 28)); + + spriteTextBox = new UITextBox(title.x, title.y + title.height + 38, character.sprite, 200); + add(spriteTextBox); + addLabelOn(spriteTextBox, "Sprite"); + + iconTextBox = new UITextBox(spriteTextBox.x + 200 + 26, spriteTextBox.y, character.getIcon(), 150); + iconTextBox.onChange = (newIcon:String) -> {updateIcon(newIcon);} + add(iconTextBox); + addLabelOn(iconTextBox, "Icon"); + + updateIcon(character.getIcon()); + + gameOverCharTextBox = new UITextBox(iconTextBox.x + 150 + (75 + 12), iconTextBox.y, character.gameOverCharacter, 200); + add(gameOverCharTextBox); + addLabelOn(gameOverCharTextBox, "Game Over Character"); + + antialiasingCheckbox = new UICheckbox(spriteTextBox.x, spriteTextBox.y + 10 + 32 + 28, "Antialiasing", character.antialiasing); + add(antialiasingCheckbox); + addLabelOn(antialiasingCheckbox, "Antialiased"); + + flipXCheckbox = new UICheckbox(antialiasingCheckbox.x + 172, spriteTextBox.y + 10 + 32 + 28, "FlipX", character.flipX); + add(flipXCheckbox); + addLabelOn(flipXCheckbox, "Flipped"); + + iconColorWheel = new UIColorwheel(gameOverCharTextBox.x + 200 + 20, gameOverCharTextBox.y, character.iconColor); + add(iconColorWheel); + addLabelOn(iconColorWheel, "Icon Color"); + + add(title = new UIText(spriteTextBox.x, spriteTextBox.y + 10 + 46 + 84, 0, "Character Data", 28)); + + positionXStepper = new UINumericStepper(title.x, title.y + title.height + 36, character.globalOffset.x, 0.001, 2, null, null, 84); + add(positionXStepper); + addLabelOn(positionXStepper, "Position (X,Y)"); + + add(new UIText(positionXStepper.x + 84 - 32 + 0, positionXStepper.y + 9, 0, ",", 22)); + + positionYStepper = new UINumericStepper(positionXStepper.x + 84 - 32 + 26, positionXStepper.y, character.globalOffset.y, 0.001, 2, null, null, 84); + add(positionYStepper); + + cameraXStepper = new UINumericStepper(positionYStepper.x + 36 + 84 - 32, positionYStepper.y, character.cameraOffset.x, 0.001, 2, null, null, 84); + add(cameraXStepper); + addLabelOn(cameraXStepper, "Camera Position (X,Y)"); + + add(new UIText(cameraXStepper.x + 84 - 32 + 0, cameraXStepper.y + 9, 0, ",", 22)); + + cameraYStepper = new UINumericStepper(cameraXStepper.x + 84 - 32 + 26, cameraXStepper.y, character.cameraOffset.y, 0.001, 2, null, null, 84); + add(cameraYStepper); + + scaleStepper = new UINumericStepper(cameraYStepper.x + 84 - 32 + 90, cameraYStepper.y, character.scale.x, 0.001, 2, null, null, 74); + add(scaleStepper); + addLabelOn(scaleStepper, "Scale"); + + singTimeStepper = new UINumericStepper(scaleStepper.x + 74 - 32 + 36, scaleStepper.y, character.holdTime, 0.001, 2, null, null, 74); + add(singTimeStepper); + addLabelOn(singTimeStepper, "Sing Duration (Steps)"); + + customPropertiesButtonList = new UIButtonList(singTimeStepper.x + singTimeStepper.width + 200, singTimeStepper.y, 290, 200, '', FlxPoint.get(280, 35), null, 5); + customPropertiesButtonList.frames = Paths.getFrames('editors/ui/inputbox'); + customPropertiesButtonList.cameraSpacing = 0; + customPropertiesButtonList.addButton.callback = function() { + customPropertiesButtonList.add(new PropertyButton("newProperty", "valueHere", customPropertiesButtonList)); + } + for (prop=>val in character.extra) + customPropertiesButtonList.add(new PropertyButton(prop, val, customPropertiesButtonList)); + add(customPropertiesButtonList); + addLabelOn(customPropertiesButtonList, "Custom Values (Advanced)"); + + isPlayerCheckbox = new UICheckbox(positionXStepper.x, positionXStepper.y + 10 + 32 + 28, "isPlayer", character.playerOffsets); + add(isPlayerCheckbox); + addLabelOn(isPlayerCheckbox, "Is Player"); + + isGFCheckbox = new UICheckbox(isPlayerCheckbox.x + 128, positionXStepper.y + 10 + 32 + 28, "isGF", character.isGF); + add(isGFCheckbox); + addLabelOn(isGFCheckbox, "Is GF"); + + for (checkbox in [isPlayerCheckbox, isGFCheckbox, antialiasingCheckbox, flipXCheckbox]) + {checkbox.y += 4; checkbox.x += 6;}*/ + + saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight- 20, "Save & Close", function() { + //saveCharacterInfo(); + close(); + }, 125); + saveButton.x -= saveButton.bWidth; + saveButton.y -= saveButton.bHeight; + + closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Close", function() { + if (onSave != null) onSave(null); + close(); + }, 125); + closeButton.x -= closeButton.bWidth; + closeButton.color = 0xFFFF0000; + add(closeButton); + add(saveButton); + } + + /*function saveCharacterInfo() { + for (stepper in [positionXStepper, positionYStepper, cameraXStepper, cameraYStepper, singTimeStepper, scaleStepper]) + @:privateAccess stepper.__onChange(stepper.label.text); + + var xml = Xml.createElement("character"); + xml.set("isPlayer", isPlayerCheckbox.checked ? "true" : "false"); + xml.set("isGF", isGFCheckbox.checked ? "true" : "false"); + xml.set("x", Std.string(positionXStepper.value)); + xml.set("y", Std.string(positionYStepper.value)); + xml.set("gameOverChar", gameOverCharTextBox.label.text); + xml.set("camx", Std.string(cameraXStepper.value)); + xml.set("camy", Std.string(cameraYStepper.value)); + xml.set("holdTime", Std.string(singTimeStepper.value)); + xml.set("flipX", Std.string(flipXCheckbox.checked)); + xml.set("icon", iconTextBox.label.text); + xml.set("scale", Std.string(scaleStepper.value)); + xml.set("antialiasing", antialiasingCheckbox.checked ? "true" : "false"); + xml.set("sprite", spriteTextBox.label.text); + if (iconColorWheel.colorChanged) + xml.set("color", iconColorWheel.curColor.toWebString()); + for (val in customPropertiesButtonList.buttons.members) + xml.set(val.propertyText.label.text, val.valueText.label.text); + + for (anim in character.animDatas) + { + var animXml:Xml = Xml.createElement('anim'); + animXml.set("name", anim.name); + animXml.set("anim", anim.anim); + animXml.set("loop", Std.string(anim.loop)); + animXml.set("fps", Std.string(anim.fps)); + var offset:FlxPoint = character.getAnimOffset(anim.name); + animXml.set("x", Std.string(offset.x)); + animXml.set("y", Std.string(offset.y)); + if (anim.indices.length > 0) + animXml.set("indices", anim.indices.join(",")); + xml.addChild(animXml); + } + + if (onSave != null) onSave(xml); + }*/ +} \ No newline at end of file diff --git a/source/funkin/editors/stager/StageSelection.hx b/source/funkin/editors/stager/StageSelection.hx new file mode 100644 index 00000000..d53e5d12 --- /dev/null +++ b/source/funkin/editors/stager/StageSelection.hx @@ -0,0 +1,43 @@ +package funkin.editors.stager; + +import funkin.options.OptionsScreen; +import funkin.game.Stage; +import funkin.options.type.IconOption; +import funkin.options.type.NewOption; +import funkin.options.type.OptionType; +import funkin.options.type.TextOption; + +class StageSelection extends EditorTreeMenu +{ + public override function create() + { + bgType = "charter"; + super.create(); + + var modsList:Array = Stage.getList(true, true); + + var list:Array = [ + for (char in (modsList.length == 0 ? Stage.getList(false, true) : modsList)) + new TextOption(char, "Press ACCEPT to edit this stage.", + function() { + FlxG.switchState(new StageEditor(char)); + }) + ]; + + list.insert(0, new NewOption("New Stage", "New Stage", function() { + openSubState(new UIWarningSubstate("New Stage: Feature Not Implemented!", "This feature isnt implemented yet. Please wait for more cne updates to have this functional.\n\n\n- Codename Devs", [ + {label: "Ok", color: 0xFFFF0000, onClick: function(t) {}} + ])); + })); + + main = new OptionsScreen("Stage Editor", "Select a stage to edit. HSCRIPT only stages are not supported.", list); + + DiscordUtil.call("onEditorTreeLoaded", ["Stage Editor"]); + } + + override function createPost() { + super.createPost(); + + main.changeSelection(1); + } +} \ No newline at end of file diff --git a/source/funkin/editors/stager/elements/StageCharacterButton.hx b/source/funkin/editors/stager/elements/StageCharacterButton.hx new file mode 100644 index 00000000..d133ed29 --- /dev/null +++ b/source/funkin/editors/stager/elements/StageCharacterButton.hx @@ -0,0 +1,55 @@ +package funkin.editors.stager.elements; + +import funkin.game.Character; +import funkin.game.Stage.StageCharPos; +import haxe.xml.Access; + +class StageCharacterButton extends StageElementButton { + public var charPos:StageCharPos; + public var char:Character; + + public function new(x:Float,y:Float, charPos:StageCharPos, xml:Access) { + this.charPos = charPos; + this.char = charPos.extra.get(StageEditor.exID("char")); + super(x,y, xml); + + color = 0xffa5c4ff; + + updateInfo(charPos); + } + + public override function update(elapsed:Float) { + editButton.selectable = ghostButton.selectable = deleteButton.selectable = selectable; + editButton.shouldPress = ghostButton.shouldPress = deleteButton.shouldPress = shouldPress; + + hovered = !deleteButton.hovered; + updatePos(); + super.update(elapsed); + } + + public override function updateInfo(charPos:Dynamic) { + if(charPos is StageCharPos) { + var charPos:StageCharPos = cast charPos; + this.charPos = charPos; + char.visible = !isHidden; + } + super.updateInfo(charPos); + } + + public override function onSelect() { + + } + + public override function onGhostClick() { + isHidden = !isHidden; + updateInfo(this.charPos); + } + + public override function getInfoText():String { + return '${charPos.name} (${charPos.x}, ${charPos.y})'; + } + + public override function updatePos() { + super.updatePos(); + } +} \ No newline at end of file diff --git a/source/funkin/editors/stager/elements/StageElementButton.hx b/source/funkin/editors/stager/elements/StageElementButton.hx new file mode 100644 index 00000000..b1b9a507 --- /dev/null +++ b/source/funkin/editors/stager/elements/StageElementButton.hx @@ -0,0 +1,112 @@ +package funkin.editors.stager.elements; + +import haxe.xml.Access; +import flixel.util.FlxColor; + +class StageElementButton extends UIButton { + public var xml:Access; + + public var editButton:UIButton; + public var editIcon:FlxSprite; + + public var ghostButton:UIButton; + public var ghostIcon:FlxSprite; + + public var deleteButton:UIButton; + public var deleteIcon:FlxSprite; + + public var isHidden:Bool = false; + + public function new(x:Float,y:Float, xml:Access) { + this.xml = xml; + super(x,y, getInfoText(), function () { + onSelect(); + //CharacterEditor.instance.playAnimation(this.sprite.name); + }, 282); + autoAlpha = false; + + ghostButton = new UIButton(x+282+17, y, "", function () { + onGhostClick(); + //CharacterEditor.instance.ghostAnim(this.anim); + }, 32); + ghostButton.autoAlpha = false; + members.push(ghostButton); + + ghostIcon = new FlxSprite(ghostButton.x + 8, ghostButton.y + 8).loadGraphic(Paths.image('editors/character/ghost-button'), true, 16, 16); + ghostIcon.animation.add("alive", [0]); + ghostIcon.animation.add("dead", [1]); + ghostIcon.animation.play("dead"); ghostIcon.alpha = 0.5; + ghostIcon.antialiasing = false; + ghostIcon.updateHitbox(); + members.push(ghostIcon); + + editButton = new UIButton(ghostButton.x+32+17, y, "", function () { + onEdit(); + }, 32); + editButton.frames = Paths.getFrames("editors/ui/grayscale-button"); + editButton.color = FlxColor.YELLOW; + editButton.autoAlpha = false; + members.push(editButton); + + editIcon = new FlxSprite(editButton.x + 8, editButton.y + 8).loadGraphic(Paths.image('editors/character/edit-button')); + editIcon.antialiasing = false; + members.push(editIcon); + + deleteButton = new UIButton(editButton.x+32+17, y, "", function () { + onDelete(); + }, 32); + deleteButton.color = FlxColor.RED; + deleteButton.autoAlpha = false; + members.push(deleteButton); + + deleteIcon = new FlxSprite(deleteButton.x + (15/2), deleteButton.y + 8).loadGraphic(Paths.image('editors/delete-button')); + deleteIcon.antialiasing = false; + members.push(deleteIcon); + } + + public override function update(elapsed:Float) { + editButton.selectable = ghostButton.selectable = deleteButton.selectable = selectable; + editButton.shouldPress = ghostButton.shouldPress = deleteButton.shouldPress = shouldPress; + + hovered = !deleteButton.hovered; + updatePos(); + super.update(elapsed); + } + + public function updateInfo(sprite:Dynamic) { + field.text = getInfoText(); + + ghostIcon.animation.play(!isHidden ? "alive" : "dead"); + ghostIcon.alpha = !isHidden ? 1 : 0.5; + } + + public function updatePos() { + // buttons + deleteButton.x = (editButton.x = (ghostButton.x = (x+282+17))+32+17)+32+17; + deleteButton.y = editButton.y = ghostButton.y = y; + // icons + ghostIcon.x = ghostButton.x + 8; ghostIcon.y = ghostButton.y + 8; + editIcon.x = editButton.x + 8; editIcon.y = editButton.y + 8; + deleteIcon.x = deleteButton.x + (15/2); deleteIcon.y = deleteButton.y + 8; + } + + public function onSelect() { + // TODO: implement + } + + public function onGhostClick() { + // TODO: implement + } + + public function onEdit() { + // TODO: implement + } + + public function onDelete() { + // TODO: implement + } + + public function getInfoText():String { + return 'NOT IMPLEMENTED'; + } +} \ No newline at end of file diff --git a/source/funkin/editors/stager/elements/StageSolidButton.hx b/source/funkin/editors/stager/elements/StageSolidButton.hx new file mode 100644 index 00000000..96f74c63 --- /dev/null +++ b/source/funkin/editors/stager/elements/StageSolidButton.hx @@ -0,0 +1,16 @@ +package funkin.editors.stager.elements; + +import haxe.xml.Access; +import flixel.util.FlxColor; + +class StageSolidButton extends StageSpriteButton { + + public function new(x:Float,y:Float, sprite:FlxSprite, xml:Access) { + super(x,y, sprite, xml); + color = 0xFFD9FF50; + } + + public override function onEdit() { + // TODO: implement + } +} \ No newline at end of file diff --git a/source/funkin/editors/stager/elements/StageSpriteButton.hx b/source/funkin/editors/stager/elements/StageSpriteButton.hx new file mode 100644 index 00000000..60405cef --- /dev/null +++ b/source/funkin/editors/stager/elements/StageSpriteButton.hx @@ -0,0 +1,54 @@ +package funkin.editors.stager.elements; + +import haxe.xml.Access; +import flixel.util.FlxColor; + +class StageSpriteButton extends StageElementButton { + public var sprite:FlxSprite; + + public function new(x:Float,y:Float, sprite:FlxSprite, xml:Access) { + this.sprite = sprite; + super(x,y, xml); + + //color = 0xFFD9FF50; + + updateInfo(sprite); + } + + public override function update(elapsed:Float) { + super.update(elapsed); + } + + public override function updateInfo(sprite:Dynamic) { + if(sprite is FlxSprite) { + var sprite:FlxSprite = cast sprite; + this.sprite = sprite; + sprite.visible = !isHidden; + } + super.updateInfo(sprite); + } + + public override function onGhostClick() { + isHidden = !isHidden; + updateInfo(this.sprite); + } + + public override function onEdit() { + // TODO: implement + } + + public override function onDelete() { + sprite.destroy(); + xml.x.parent.removeChild(xml.x); + StageEditor.instance.xmlMap.remove(sprite); + StageEditor.instance.stageSpritesWindow.remove(this); + } + + public override function getInfoText():String { + return '${xml.att.name} (${sprite.x}, ${sprite.y})'; + } + + public override function updatePos() { + super.updatePos(); + } +} \ No newline at end of file diff --git a/source/funkin/editors/ui/UIButtonList.hx b/source/funkin/editors/ui/UIButtonList.hx index ec8385e5..c516c73d 100644 --- a/source/funkin/editors/ui/UIButtonList.hx +++ b/source/funkin/editors/ui/UIButtonList.hx @@ -14,7 +14,7 @@ class UIButtonList extends UIWindow { public var cameraSpacing = 30; public var buttonSpacing:Float = 16; - public var buttonSize:FlxPoint = FlxPoint.get(); + public var buttonSize:FlxPoint = null; public var buttonOffset:FlxPoint = FlxPoint.get(); public var dragging:Bool = false; @@ -41,9 +41,9 @@ class UIButtonList extends UIWindow { addIcon = new FlxSprite(addButton.x + addButton.bHeight / 2, addButton.y + (32/2) - 8).loadGraphic(Paths.image('editors/charter/add-button')); addIcon.antialiasing = false; addButton.members.push(addIcon); - members.push(addButton); + content.add(addButton); - members.push(buttons); + content.add(buttons); nextscrollY = buttonCameras.scroll.y = -this.buttonSpacing; } diff --git a/source/funkin/editors/ui/UISliceSprite.hx b/source/funkin/editors/ui/UISliceSprite.hx index 09226205..2de6aeb0 100644 --- a/source/funkin/editors/ui/UISliceSprite.hx +++ b/source/funkin/editors/ui/UISliceSprite.hx @@ -5,7 +5,7 @@ import flixel.graphics.frames.FlxFrame; class UISliceSprite extends UISprite { public var bWidth:Int = 120; public var bHeight:Int = 20; - public var framesOffset:Int = 0; + public var framesOffset(default, set):Int = 0; public var incorporeal:Bool = false; @@ -14,6 +14,7 @@ class UISliceSprite extends UISprite { frames = Paths.getFrames(path); resize(w, h); + calculateFrames(); } public override function updateButton() { @@ -34,21 +35,41 @@ class UISliceSprite extends UISprite { public var drawMiddle:Bool = true; public var drawBottom:Bool = true; + var topleft:FlxFrame = null; + var top:FlxFrame = null; + var topright:FlxFrame = null; + var middleleft:FlxFrame = null; + var middle:FlxFrame = null; + var middleright:FlxFrame = null; + var bottomleft:FlxFrame = null; + var bottom:FlxFrame = null; + var bottomright:FlxFrame = null; + + function set_framesOffset(value:Int) { + if(value != framesOffset) { + framesOffset = value; + calculateFrames(); + } + return value; + } + + function calculateFrames() { + topleft = frames.frames[framesOffset]; + top = frames.frames[framesOffset + 1]; + topright = frames.frames[framesOffset + 2]; + middleleft = frames.frames[framesOffset + 3]; + middle = frames.frames[framesOffset + 4]; + middleright = frames.frames[framesOffset + 5]; + bottomleft = frames.frames[framesOffset + 6]; + bottom = frames.frames[framesOffset + 7]; + bottomright = frames.frames[framesOffset + 8]; + } + public override function draw() @:privateAccess { var x:Float = this.x; var y:Float = this.y; if (visible && !(bWidth == 0 || bHeight == 0)) { - var topleft:FlxFrame = frames.frames[framesOffset]; - var top:FlxFrame = frames.frames[framesOffset + 1]; - var topright:FlxFrame = frames.frames[framesOffset + 2]; - var middleleft:FlxFrame = frames.frames[framesOffset + 3]; - var middle:FlxFrame = frames.frames[framesOffset + 4]; - var middleright:FlxFrame = frames.frames[framesOffset + 5]; - var bottomleft:FlxFrame = frames.frames[framesOffset + 6]; - var bottom:FlxFrame = frames.frames[framesOffset + 7]; - var bottomright:FlxFrame = frames.frames[framesOffset + 8]; - // TOP if (drawTop) { // TOP LEFT diff --git a/source/funkin/editors/ui/UIWindow.hx b/source/funkin/editors/ui/UIWindow.hx index 6853ce06..59ff735f 100644 --- a/source/funkin/editors/ui/UIWindow.hx +++ b/source/funkin/editors/ui/UIWindow.hx @@ -2,17 +2,33 @@ package funkin.editors.ui; class UIWindow extends UISliceSprite { public var titleSpr:UIText; + public var collapsable:Bool = false; + public var content:FlxTypedGroup; public override function new(x:Float, y:Float, w:Int, h:Int, title:String) { super(x, y, w, h, "editors/ui/normal-popup"); members.push(titleSpr = new UIText(x + 25, y, bWidth - 50, title, 15, -1)); titleSpr.y = y + ((30 - titleSpr.height) / 2); + + content = new FlxTypedGroup(); + members.push(content); } public override function update(elapsed:Float) { super.update(elapsed); + if(collapsable && FlxG.mouse.justPressed) { + // TOOLBAR + __rect.x = x; __rect.y = y; + __rect.width = bWidth; __rect.height = 23; + if(UIState.state.isOverlapping(this, __rect)) { + content.exists = !content.exists; + drawMiddle = !drawMiddle; + drawBottom = !drawBottom; + } + } + __rect.x = x; __rect.y = y+23; __rect.width = bWidth; __rect.height = bHeight-23; hovered = UIState.state.isOverlapping(this, __rect); diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index f42cc90e..d9e6a288 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -1,5 +1,6 @@ package funkin.game; +import flixel.util.typeLimit.OneOfTwo; import flixel.FlxState; import flixel.math.FlxPoint; import funkin.backend.scripting.Script; @@ -12,65 +13,94 @@ import haxe.xml.Access; using StringTools; class Stage extends FlxBasic implements IBeatReceiver { + public var extra:Map = []; + public var stageXML:Access; public var stagePath:String; + public var stageFile:String; + public var stageName:String; public var stageSprites:Map = []; public var stageScript:Script; public var state:FlxState; public var characterPoses:Map = []; + public var defaultZoom:Float = 1.05; + public var startCam = new FlxPoint(); + + public var onXMLLoaded:(Access, Array)->Array = null; + public var onNodeLoaded:(Access, Dynamic)->Dynamic = null; + private var spritesParentFolder = ""; - public function getSprite(name:String) { + public inline function getSprite(name:String) { return stageSprites[name]; } - public function new(stage:String, ?state:FlxState) { + public function new(stage:String, ?state:FlxState, autoLoad:Bool = true) { super(); if (state == null) state = PlayState.instance; if (state == null) state = FlxG.state; this.state = state; - stagePath = Paths.xml('stages/$stage'); + stageFile = stage; + + stagePath = Paths.xml('stages/$stageFile'); try { if (Assets.exists(stagePath)) stageXML = new Access(Xml.parse(Assets.getText(stagePath)).firstElement()); } catch(e) { - Logs.trace('Couldn\'t load stage "$stage": ${e.message}', ERROR); + Logs.trace('Couldn\'t load stage "$stageFile": ${e.message}', ERROR); } - if (PlayState.instance != null) { - stageScript = Script.create(Paths.script('data/stages/$stage')); + if (autoLoad) loadXml(stageXML); + } + + public function loadXml(xml:Access, forceLoadAll:Bool = false) { + if (PlayState.instance == state) { + stageScript = Script.create(Paths.script('data/stages/$stageFile')); PlayState.instance.scripts.add(stageScript); stageScript.load(); } - if (stageXML != null) { - if (PlayState.instance != null) { - var parsed:Null; - if(stageXML.has.startCamPosX && (parsed = Std.parseFloat(stageXML.att.startCamPosX)) != null) PlayState.instance.camFollow.x = parsed; - if(stageXML.has.startCamPosY && (parsed = Std.parseFloat(stageXML.att.startCamPosY)) != null) PlayState.instance.camFollow.y = parsed; - if(stageXML.has.zoom && (parsed = Std.parseFloat(stageXML.att.zoom)) != null) PlayState.instance.defaultCamZoom = parsed; - PlayState.instance.curStage = stageXML.has.name ? stageXML.att.name : stage; + if (xml != null) { + var parsed:Null; + if((parsed = Std.parseFloat(xml.getAtt("startCamPosX"))).isNotNull()) startCam.x = parsed; + if((parsed = Std.parseFloat(xml.getAtt("startCamPosY"))).isNotNull()) startCam.y = parsed; + if((parsed = Std.parseFloat(xml.getAtt("zoom"))).isNotNull()) defaultZoom = parsed; + + stageName = xml.getAtt("name").getDefault(stageFile); + + if (PlayState.instance == state) { + if(xml.has.startCamPosX) PlayState.instance.camFollow.x = startCam.x; + if(xml.has.startCamPosY) PlayState.instance.camFollow.y = startCam.y; + if(xml.has.zoom) PlayState.instance.defaultCamZoom = defaultZoom; + PlayState.instance.curStage = stageName; } - if (stageXML.has.folder) { - spritesParentFolder = stageXML.att.folder; + if (xml.has.folder) { + spritesParentFolder = xml.att.folder; if (!spritesParentFolder.endsWith("/")) spritesParentFolder += "/"; } - var elems = []; - for(node in stageXML.elements) { - if (node.name == "high-memory" && !Options.lowMemoryMode) + var elems:Array = []; + // some way to tag that the sprites are from the group + for(node in xml.elements) { + if (node.name == "high-memory" && (!Options.lowMemoryMode || forceLoadAll)) + for(e in node.elements) + elems.push(e); + else if (node.name == "low-memory" && (Options.lowMemoryMode || forceLoadAll)) for(e in node.elements) elems.push(e); else elems.push(node); } - if (PlayState.instance != null) { - var event = PlayState.instance.scripts.event("onStageXMLParsed", EventManager.get(StageXMLEvent).recycle(this, stageXML, elems)); + if (PlayState.instance == state) { + var event = PlayState.instance.scripts.event("onStageXMLParsed", EventManager.get(StageXMLEvent).recycle(this, xml, elems)); elems = event.elems; } + if(onXMLLoaded != null) { + elems = onXMLLoaded(xml, elems); + } for(node in elems) { var sprite:Dynamic = switch(node.name) { @@ -79,8 +109,8 @@ class Stage extends FlxBasic implements IBeatReceiver { var spr = XMLUtil.createSpriteFromXML(node, spritesParentFolder, LOOP); - if (!node.has.zoomfactor && PlayState.instance != null) - spr.initialZoom = PlayState.instance.defaultCamZoom; + if (!node.has.zoomfactor/* && PlayState.instance == state*/) + spr.initialZoom = defaultZoom;//PlayState.instance.defaultCamZoom; stageSprites.set(spr.name, spr); state.add(spr); @@ -88,10 +118,11 @@ class Stage extends FlxBasic implements IBeatReceiver { case "box" | "solid": if ( !node.has.name || !node.has.width || !node.has.height) continue; - var spr = new FlxSprite( + var spr = new FunkinSprite( (node.has.x) ? Std.parseFloat(node.att.x).getDefault(0) : 0, (node.has.y) ? Std.parseFloat(node.att.y).getDefault(0) : 0 ); + spr.name = node.getAtt("name"); (node.name == "solid" ? spr.makeSolid : spr.makeGraphic)( Std.parseInt(node.att.width), @@ -99,7 +130,10 @@ class Stage extends FlxBasic implements IBeatReceiver { (node.has.color) ? CoolUtil.getColorFromDynamic(node.att.color) : -1 ); - stageSprites.set(node.getAtt("name"), spr); + if (!node.has.zoomfactor/* && PlayState.instance == state*/) + spr.initialZoom = defaultZoom;//PlayState.instance.defaultCamZoom; + + stageSprites.set(spr.name, spr); state.add(spr); spr; case "boyfriend" | "bf" | "player": @@ -127,7 +161,7 @@ class Stage extends FlxBasic implements IBeatReceiver { if (!node.has.name) continue; addCharPos(node.att.name, node); case "ratings" | "combo": - if (PlayState.instance == null) continue; + if (PlayState.instance != state) continue; PlayState.instance.comboGroup.setPosition( Std.parseFloat(node.getAtt("x")).getDefault(PlayState.instance.comboGroup.x), Std.parseFloat(node.getAtt("y")).getDefault(PlayState.instance.comboGroup.y) @@ -137,9 +171,12 @@ class Stage extends FlxBasic implements IBeatReceiver { default: null; } - if(PlayState.instance != null) { + if(PlayState.instance == state) { sprite = PlayState.instance.scripts.event("onStageNodeParsed", EventManager.get(StageNodeEvent).recycle(this, node, sprite, node.name)).sprite; } + if(onNodeLoaded != null) { + sprite = onNodeLoaded(node, sprite); + } if (sprite != null) { for(e in node.nodes.property) @@ -172,7 +209,7 @@ class Stage extends FlxBasic implements IBeatReceiver { flip: true }); - if (PlayState.instance == null) return; + if (PlayState.instance != state) return; for(k=>e in stageSprites) { stageScript.set(k, e); } @@ -181,6 +218,7 @@ class Stage extends FlxBasic implements IBeatReceiver { public function addCharPos(name:String, node:Access, ?nonXMLInfo:StageCharPosInfo):StageCharPos { var charPos = new StageCharPos(); charPos.visible = charPos.active = false; + charPos.name = name; if (nonXMLInfo != null) { charPos.setPosition(nonXMLInfo.x, nonXMLInfo.y); @@ -239,19 +277,28 @@ class Stage extends FlxBasic implements IBeatReceiver { public function measureHit(curMeasure:Int) {} - public static function getList(?mods:Bool = false):Array { + public static function getList(?mods:Bool = false, ?xmlOnly:Bool = false):Array { var list:Array = []; - for (path in Paths.getFolderContent('data/stages/', true, mods ? MODS : BOTH)) - if (Path.extension(path) == "xml" || Path.extension(path) == "hx") { - var file:String = Path.withoutDirectory(Path.withoutExtension(path)); - list.pushOnce(file); + var extensions:Array = ["xml"]; + if (!xmlOnly) extensions.push("hx"); + + for (path in Paths.getFolderContent("data/stages/", false, mods ? MODS : BOTH)) { + var extension = Path.extension(path); + if (extensions.contains(extension)) { + list.pushOnce(Path.withoutExtension(path)); } + } + + trace(list); return list; } } class StageCharPos extends FlxObject { + public var extra:Map = []; + + public var name:String; public var charSpacingX:Float = 20; public var charSpacingY:Float = 0; public var camxoffset:Float = 0; From 045176c446a92eccfc77666f9bd2624359c9e111 Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Sat, 13 Apr 2024 18:07:02 +0200 Subject: [PATCH 02/89] fix bug --- source/funkin/editors/stager/StageEditor.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/editors/stager/StageEditor.hx b/source/funkin/editors/stager/StageEditor.hx index 69776852..935ceac2 100644 --- a/source/funkin/editors/stager/StageEditor.hx +++ b/source/funkin/editors/stager/StageEditor.hx @@ -360,7 +360,7 @@ class StageEditor extends UIState { characterBG.scale.set(FlxG.width/characterBG.width, FlxG.height/characterBG.height); characterBG.scale.set(characterBG.scale.x / charCamera.zoom, characterBG.scale.y / charCamera.zoom);*/ - if (true/*!(characterPropertiresWindow.hovered || characterAnimsWindow.hovered) && !characterAnimsWindow.dragging*/) { + if (!(stageSpritesWindow.hovered) && !stageSpritesWindow.dragging) { if (FlxG.mouse.wheel != 0) { zoom += 0.25 * FlxG.mouse.wheel; updateZoom(); From 82604c455ea48345affe26272fd311fbfc5454bf Mon Sep 17 00:00:00 2001 From: Dirk-Dinkum <134403819+Dirk-Dinkum@users.noreply.github.com> Date: Sat, 13 Apr 2024 19:33:53 +0200 Subject: [PATCH 03/89] MatrixUtil math fix --- libs.xml | 2 +- source/funkin/backend/FunkinSprite.hx | 2 ++ source/funkin/backend/system/NothingCamera.hx | 4 ++++ source/funkin/backend/utils/MatrixUtil.hx | 11 ++++++++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/libs.xml b/libs.xml index cfdec718..f3d27d0f 100644 --- a/libs.xml +++ b/libs.xml @@ -9,7 +9,7 @@ - + diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx index d817f142..538c18ad 100644 --- a/source/funkin/backend/FunkinSprite.hx +++ b/source/funkin/backend/FunkinSprite.hx @@ -86,6 +86,8 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I spr.skew.set(source.skew.x, source.skew.y); spr.transformMatrix = source.transformMatrix; spr.matrixExposed = source.matrixExposed; + spr.zoomFactor = source.zoomFactor; + spr.initialZoom = source.initialZoom; spr.animOffsets = source.animOffsets.copy(); } return spr; diff --git a/source/funkin/backend/system/NothingCamera.hx b/source/funkin/backend/system/NothingCamera.hx index 12917499..45a91a1a 100644 --- a/source/funkin/backend/system/NothingCamera.hx +++ b/source/funkin/backend/system/NothingCamera.hx @@ -31,4 +31,8 @@ class NothingCamera extends FlxCamera { public override function drawTriangles(graphic:FlxGraphic, vertices:DrawData, indices:DrawData, uvtData:DrawData, ?colors:DrawData, ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader):Void {} public override function update(elapsed:Float) {} + + // override function set_zoom(Zoom:Float):Float return zoom = (Zoom == 0) ? FlxCamera.defaultZoom : Zoom; + + public override function setScale(X:Float, Y:Float):Void {} } \ No newline at end of file diff --git a/source/funkin/backend/utils/MatrixUtil.hx b/source/funkin/backend/utils/MatrixUtil.hx index 65230b94..146fd430 100644 --- a/source/funkin/backend/utils/MatrixUtil.hx +++ b/source/funkin/backend/utils/MatrixUtil.hx @@ -12,11 +12,13 @@ class MatrixUtil { if(camera == null) camera = sprite.camera; if(points is FlxBasePoint) points = [points]; var nc = funkin.backend.system.NothingCamera.instance; + nc.zoom = camera.zoom; nc.scroll.set(camera.scroll.x, camera.scroll.y); - //nc.zoom = camera.zoom; // might not be needed nc.pixelPerfectRender = camera.pixelPerfectRender; @:privateAccess sprite.drawComplex(nc); + var isFunkinSprite = sprite is FunkinSprite; + var points:Array = cast points; @:privateAccess for(point in points) { var x = sprite._matrix.__transformX(point.x * _width, point.y * _height); @@ -25,7 +27,14 @@ class MatrixUtil { // reset to ingame coords x += camera.scroll.x; y += camera.scroll.y; + + if(isFunkinSprite) { + var sprite:FunkinSprite = cast sprite; + var ratio = 1 - FlxMath.lerp(1 / camera.zoom, 1, sprite.zoomFactor); + x += camera.width / 2 * ratio; + y += camera.height / 2 * ratio; + } point.set(x, y); } return points; From bded41e10f80d0329ac5783e0d4d5807972ba4a8 Mon Sep 17 00:00:00 2001 From: Dirk-Dinkum <134403819+Dirk-Dinkum@users.noreply.github.com> Date: Sat, 13 Apr 2024 20:30:33 +0200 Subject: [PATCH 04/89] fixed zoomfactor Co-Authored-By: Ne_Eo --- source/funkin/backend/FunkinSprite.hx | 111 ++++++++------------ source/funkin/editors/stager/StageEditor.hx | 13 ++- source/funkin/game/SplashGroup.hx | 1 + source/funkin/game/Stage.hx | 11 +- 4 files changed, 64 insertions(+), 72 deletions(-) diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx index 538c18ad..eeedff8b 100644 --- a/source/funkin/backend/FunkinSprite.hx +++ b/source/funkin/backend/FunkinSprite.hx @@ -39,9 +39,11 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I public var beatAnims:Array = []; public var name:String; public var zoomFactor:Float = 1; - public var initialZoom:Float = 1; + //public var initialZoom:Float = 1; public var debugMode:Bool = false; public var animDatas:Map = []; + public var animEnabled:Bool = true; + public var zoomFactorEnabled:Bool = true; /** * ODD interval -> asynced; EVEN interval -> synced @@ -87,7 +89,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I spr.transformMatrix = source.transformMatrix; spr.matrixExposed = source.matrixExposed; spr.zoomFactor = source.zoomFactor; - spr.initialZoom = source.initialZoom; spr.animOffsets = source.animOffsets.copy(); } return spr; @@ -140,49 +141,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I { } - public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect - { - __doPreZoomScaleProcedure(camera); - var r = super.getScreenBounds(newRect, camera); - __doPostZoomScaleProcedure(); - return r; - } - - public override function drawComplex(camera:FlxCamera) - { - super.drawComplex(camera); - } - - public override function doAdditionalMatrixStuff(matrix:FlxMatrix, camera:FlxCamera) - { - super.doAdditionalMatrixStuff(matrix, camera); - matrix.translate(-camera.width / 2, -camera.height / 2); - - var requestedZoom = FlxMath.lerp(1, camera.zoom, zoomFactor); - var diff = requestedZoom / camera.zoom; - matrix.scale(diff, diff); - matrix.translate(camera.width / 2, camera.height / 2); - } - - public override function getScreenPosition(?point:FlxPoint, ?Camera:FlxCamera):FlxPoint - { - if (__shouldDoScaleProcedure()) - { - __oldScrollFactor.set(scrollFactor.x, scrollFactor.y); - var requestedZoom = FlxMath.lerp(initialZoom, camera.zoom, zoomFactor); - var diff = requestedZoom / camera.zoom; - - scrollFactor.scale(1 / diff); - - var r = super.getScreenPosition(point, Camera); - - scrollFactor.set(__oldScrollFactor.x, __oldScrollFactor.y); - - return r; - } - return super.getScreenPosition(point, Camera); - } - // ANIMATE ATLAS DRAWING #if REGION public override function draw() @@ -238,33 +196,51 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I } #end - // SCALING FUNCS - #if REGION - private inline function __shouldDoScaleProcedure() - return zoomFactor != 1; + // ZOOM FACTOR + private inline function __shouldDoZoomFactor() + return zoomFactorEnabled && zoomFactor != 1; - static var __oldScrollFactor:FlxPoint = new FlxPoint(); - static var __oldScale:FlxPoint = new FlxPoint(); - var __skipZoomProcedure:Bool = false; - - private function __doPreZoomScaleProcedure(camera:FlxCamera) + public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect { - if (__skipZoomProcedure = !__shouldDoScaleProcedure()) - return; - __oldScale.set(scale.x, scale.y); - var requestedZoom = FlxMath.lerp(initialZoom, camera.zoom, zoomFactor); - var diff = requestedZoom * camera.zoom; + if (camera == null) + camera = FlxG.camera; - scale.scale(diff); + var r = super.getScreenBounds(newRect, camera); + + if(__shouldDoZoomFactor()) { + r.x -= camera.width / 2; + r.y -= camera.height / 2; + + var ratio = FlxMath.lerp(1 / camera.zoom, 1, zoomFactor); + r.x *= ratio; + r.y *= ratio; + + r.width *= ratio; + r.height *= ratio; + + r.x += camera.width / 2; + r.y += camera.height / 2; + } + return r; } - private function __doPostZoomScaleProcedure() + public override function doAdditionalMatrixStuff(matrix:FlxMatrix, camera:FlxCamera) { - if (__skipZoomProcedure) - return; - scale.set(__oldScale.x, __oldScale.y); + super.doAdditionalMatrixStuff(matrix, camera); + if(__shouldDoZoomFactor()) { + matrix.translate(-camera.width / 2, -camera.height / 2); + + var requestedZoom = FlxMath.lerp(1, camera.zoom, zoomFactor); + var diff = requestedZoom / camera.zoom; + matrix.scale(diff, diff); + matrix.translate(camera.width / 2, camera.height / 2); + } + } + + public override function getScreenPosition(?point:FlxPoint, ?Camera:FlxCamera):FlxPoint + { + return super.getScreenPosition(point, Camera); } - #end // OFFSETTING #if REGION @@ -352,6 +328,11 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I public inline function isAnimFinished() { return animateAtlas != null ? (animateAtlas.anim.finished) : (animation.curAnim != null ? animation.curAnim.finished : true); } + + override function updateAnimation(elapsed:Float) { + if (animEnabled) + super.updateAnimation(elapsed); + } #end // Getter / Setters diff --git a/source/funkin/editors/stager/StageEditor.hx b/source/funkin/editors/stager/StageEditor.hx index 935ceac2..beeb6c23 100644 --- a/source/funkin/editors/stager/StageEditor.hx +++ b/source/funkin/editors/stager/StageEditor.hx @@ -226,9 +226,20 @@ class StageEditor extends UIState { stage.onXMLLoaded = function(xml:Access, elems:Array) { return elems; } + stage.onNodeLoadedPost = function(node:Access, sprite:Dynamic) { + if(sprite is FlxSprite) { + sprite.moves = false; + } + if (sprite is FunkinSprite) { + sprite.animEnabled = false; + //sprite.zoomFactorEnabled = false; + } + } stage.onNodeLoaded = function(node:Access, sprite:Dynamic):Dynamic { + if(sprite is FlxSprite) { + //sprite.forceIsOnScreen = true; // hack + } if(sprite is FunkinSprite) { - sprite.forceIsOnScreen = true; // hack sprite.extra.set(exID("type"), node.name); //sprite.active = false; } diff --git a/source/funkin/game/SplashGroup.hx b/source/funkin/game/SplashGroup.hx index 75008a29..ffa9f135 100644 --- a/source/funkin/game/SplashGroup.hx +++ b/source/funkin/game/SplashGroup.hx @@ -37,6 +37,7 @@ class SplashGroup extends FlxTypedGroup { // immediatly draw once and put image in GPU to prevent freezes // TODO: change to graphics cache + @:privateAccess splash.drawComplex(FlxG.camera); } catch(e:Dynamic) { Logs.trace('Couldn\'t parse splash data for "${path}": ${e.toString()}', ERROR); diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index d9e6a288..070d165f 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -29,6 +29,7 @@ class Stage extends FlxBasic implements IBeatReceiver { public var onXMLLoaded:(Access, Array)->Array = null; public var onNodeLoaded:(Access, Dynamic)->Dynamic = null; + public var onNodeLoadedPost:(Access, Dynamic)->Void = null; private var spritesParentFolder = ""; @@ -109,9 +110,6 @@ class Stage extends FlxBasic implements IBeatReceiver { var spr = XMLUtil.createSpriteFromXML(node, spritesParentFolder, LOOP); - if (!node.has.zoomfactor/* && PlayState.instance == state*/) - spr.initialZoom = defaultZoom;//PlayState.instance.defaultCamZoom; - stageSprites.set(spr.name, spr); state.add(spr); spr; @@ -130,9 +128,6 @@ class Stage extends FlxBasic implements IBeatReceiver { (node.has.color) ? CoolUtil.getColorFromDynamic(node.att.color) : -1 ); - if (!node.has.zoomfactor/* && PlayState.instance == state*/) - spr.initialZoom = defaultZoom;//PlayState.instance.defaultCamZoom; - stageSprites.set(spr.name, spr); state.add(spr); spr; @@ -182,6 +177,10 @@ class Stage extends FlxBasic implements IBeatReceiver { for(e in node.nodes.property) XMLUtil.applyXMLProperty(sprite, e); } + + if(onNodeLoadedPost != null) { + onNodeLoadedPost(node, sprite); + } } } From d145c6f6836f5415822381583a6c63212e09354f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=8D=9A=7ENex?= <87421482+NexIsDumb@users.noreply.github.com> Date: Sat, 13 Apr 2024 20:35:05 +0200 Subject: [PATCH 05/89] creation screen --- .../editors/stager/StageCreationScreen.hx | 62 +++++++++++++++++++ source/funkin/editors/stager/StageEditor.hx | 1 - .../funkin/editors/stager/StageSelection.hx | 37 ++++++++--- source/funkin/editors/ui/UISliceSprite.hx | 7 +++ 4 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 source/funkin/editors/stager/StageCreationScreen.hx diff --git a/source/funkin/editors/stager/StageCreationScreen.hx b/source/funkin/editors/stager/StageCreationScreen.hx new file mode 100644 index 00000000..f600de11 --- /dev/null +++ b/source/funkin/editors/stager/StageCreationScreen.hx @@ -0,0 +1,62 @@ +package funkin.editors.stager; + +typedef StageCreationData = { + var name:String; + var path:String; +} + +class StageCreationScreen extends UISubstateWindow { + private var onSave:Null -> Void = null; + + public var stageNameTextBox:UITextBox; + public var stagePathTextBox:UITextBox; + public var voicesExplorer:UIFileExplorer; + + public var saveButton:UIButton; + public var closeButton:UIButton; + + public function new(?onSave:StageCreationData->Void) { + super(); + if (onSave != null) this.onSave = onSave; + } + + public override function create() { + winTitle = "Creating New Stage"; + + winWidth = 748 - 32 + 40; + winHeight = 200; + + super.create(); + + function addLabelOn(ui:UISprite, text:String):UIText { + var text:UIText = new UIText(ui.x, ui.y - 24, 0, text); + ui.members.push(text); + return text; + } + + var stageInfo:UIText; + add(stageInfo = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Stage Info", 28)); + + add(stageNameTextBox = new UITextBox(stageInfo.x, stageInfo.y + stageInfo.height + 36, "Stage Name")); + addLabelOn(stageNameTextBox, "Stage Name"); + + add(stagePathTextBox = new UITextBox(stageNameTextBox.x + 320 + 26, stageNameTextBox.y, "Stage Path")); + addLabelOn(stagePathTextBox, "Stage Path"); + + add(saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20 - 125, windowSpr.y + windowSpr.bHeight - 16 - 32, "Save & Close", function() { + saveStageInfo(); + close(); + }, 125)); + + add(closeButton = new UIButton(saveButton.x - 20 - saveButton.bWidth, saveButton.y, "Cancel", close, 125)); + closeButton.color = 0xFFFF0000; + } + + function saveStageInfo() { + if (onSave != null) onSave({ + name: stageNameTextBox.label.text, + path: stagePathTextBox.label.text + }); + } + +} \ No newline at end of file diff --git a/source/funkin/editors/stager/StageEditor.hx b/source/funkin/editors/stager/StageEditor.hx index beeb6c23..7a2557c8 100644 --- a/source/funkin/editors/stager/StageEditor.hx +++ b/source/funkin/editors/stager/StageEditor.hx @@ -298,7 +298,6 @@ class StageEditor extends UIState { // TODO: implement this } for (i=>sprite in order) { - trace(sprite, Type.getClassName(Type.getClass(sprite))); var xml = xmlMap.get(sprite); if(xml != null) { if(sprite is FunkinSprite) { diff --git a/source/funkin/editors/stager/StageSelection.hx b/source/funkin/editors/stager/StageSelection.hx index d53e5d12..726849bf 100644 --- a/source/funkin/editors/stager/StageSelection.hx +++ b/source/funkin/editors/stager/StageSelection.hx @@ -6,9 +6,12 @@ import funkin.options.type.IconOption; import funkin.options.type.NewOption; import funkin.options.type.OptionType; import funkin.options.type.TextOption; +import funkin.editors.stager.StageCreationScreen.StageCreationData; class StageSelection extends EditorTreeMenu { + public var stages:Array = []; + public override function create() { bgType = "charter"; @@ -17,17 +20,17 @@ class StageSelection extends EditorTreeMenu var modsList:Array = Stage.getList(true, true); var list:Array = [ - for (char in (modsList.length == 0 ? Stage.getList(false, true) : modsList)) - new TextOption(char, "Press ACCEPT to edit this stage.", + for (stage in (modsList.length == 0 ? Stage.getList(false, true) : modsList)) { + stages.push(stage); + new TextOption(stage, "Press ACCEPT to edit this stage.", function() { - FlxG.switchState(new StageEditor(char)); - }) + FlxG.switchState(new StageEditor(stage)); + }); + } ]; list.insert(0, new NewOption("New Stage", "New Stage", function() { - openSubState(new UIWarningSubstate("New Stage: Feature Not Implemented!", "This feature isnt implemented yet. Please wait for more cne updates to have this functional.\n\n\n- Codename Devs", [ - {label: "Ok", color: 0xFFFF0000, onClick: function(t) {}} - ])); + FlxG.state.openSubState(new StageCreationScreen(saveStage)); })); main = new OptionsScreen("Stage Editor", "Select a stage to edit. HSCRIPT only stages are not supported.", list); @@ -35,6 +38,26 @@ class StageSelection extends EditorTreeMenu DiscordUtil.call("onEditorTreeLoaded", ["Stage Editor"]); } + public function saveStage(creation:StageCreationData) { + if ([for (s in stages) s.toLowerCase()].contains(creation.name.toLowerCase())) { + openSubState(new UIWarningSubstate("Creating Stage: Error!", "The stage you are trying to create alreadly exists, if you would like to override it delete the stage first!", [ + {label: "Ok", color: 0xFFFF0000, onClick: function(t) {}} + ])); + return; + } + + #if sys + // Save File + CoolUtil.safeSaveFile('${Paths.getAssetsRoot()}/data/stages/${creation.name}.xml', '\n\n'); + #end + + // Add to List + var option = new TextOption(creation.name, "Press ACCEPT to edit this stage.", function() { + FlxG.switchState(new StageEditor(creation.name)); + }); + optionsTree.members[optionsTree.members.length-1].insert(1, option); + } + override function createPost() { super.createPost(); diff --git a/source/funkin/editors/ui/UISliceSprite.hx b/source/funkin/editors/ui/UISliceSprite.hx index 2de6aeb0..e1f91b8d 100644 --- a/source/funkin/editors/ui/UISliceSprite.hx +++ b/source/funkin/editors/ui/UISliceSprite.hx @@ -45,6 +45,12 @@ class UISliceSprite extends UISprite { var bottom:FlxFrame = null; var bottomright:FlxFrame = null; + override function set_frames(val) { + super.set_frames(val); + calculateFrames(); + return val; + } + function set_framesOffset(value:Int) { if(value != framesOffset) { framesOffset = value; @@ -54,6 +60,7 @@ class UISliceSprite extends UISprite { } function calculateFrames() { + if(frames == null) return; topleft = frames.frames[framesOffset]; top = frames.frames[framesOffset + 1]; topright = frames.frames[framesOffset + 2]; From 3daeb97362f2654f3390db2b0b30a57242f36286 Mon Sep 17 00:00:00 2001 From: Dirk-Dinkum <134403819+Dirk-Dinkum@users.noreply.github.com> Date: Sat, 13 Apr 2024 20:55:26 +0200 Subject: [PATCH 06/89] fixed upside down tankmens Co-Authored-By: Ne_Eo --- source/funkin/backend/FunkinSprite.hx | 25 ++++++++++++++------- source/funkin/editors/stager/StageEditor.hx | 4 ++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx index eeedff8b..3f3f538c 100644 --- a/source/funkin/backend/FunkinSprite.hx +++ b/source/funkin/backend/FunkinSprite.hx @@ -211,10 +211,9 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I r.x -= camera.width / 2; r.y -= camera.height / 2; - var ratio = FlxMath.lerp(1 / camera.zoom, 1, zoomFactor); + var ratio = (camera.zoom > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.zoom, 1, zoomFactor)); r.x *= ratio; r.y *= ratio; - r.width *= ratio; r.height *= ratio; @@ -224,24 +223,34 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I return r; } + override public function isOnScreen(?camera:FlxCamera):Bool + { + if (forceIsOnScreen) + return true; + + if (camera == null) + camera = FlxG.camera; + + var bounds = getScreenBounds(_rect, camera); + if (bounds.width == 0 && bounds.height == 0) + return false; + return camera.containsRect(bounds); + } + + // ZOOM FACTOR RENDERING public override function doAdditionalMatrixStuff(matrix:FlxMatrix, camera:FlxCamera) { super.doAdditionalMatrixStuff(matrix, camera); if(__shouldDoZoomFactor()) { matrix.translate(-camera.width / 2, -camera.height / 2); - var requestedZoom = FlxMath.lerp(1, camera.zoom, zoomFactor); + var requestedZoom = (camera.zoom >= 0 ? Math.max : Math.min)(FlxMath.lerp(1, camera.zoom, zoomFactor), 0); var diff = requestedZoom / camera.zoom; matrix.scale(diff, diff); matrix.translate(camera.width / 2, camera.height / 2); } } - public override function getScreenPosition(?point:FlxPoint, ?Camera:FlxCamera):FlxPoint - { - return super.getScreenPosition(point, Camera); - } - // OFFSETTING #if REGION public var animOffsets:Map = new Map(); diff --git a/source/funkin/editors/stager/StageEditor.hx b/source/funkin/editors/stager/StageEditor.hx index 7a2557c8..cafe1aed 100644 --- a/source/funkin/editors/stager/StageEditor.hx +++ b/source/funkin/editors/stager/StageEditor.hx @@ -567,13 +567,13 @@ class StageEditor extends UIState { } }*/ for(sprite in stage.stageSprites) { - if(sprite.visible) { + if(sprite.visible && sprite.isOnScreen()) { @:privateAccess if(sprite._frame == null) continue; drawGuides(sprite); } } for(char in chars) { - if(char.visible) { + if(char.visible && char.isOnScreen()) { @:privateAccess if(char._frame == null) continue; drawGuides(char); } From 69046ab5aa9459e2dc05014d6bc2bfa931d9f8c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=8D=9A=7ENex?= <87421482+NexIsDumb@users.noreply.github.com> Date: Sat, 13 Apr 2024 20:58:46 +0200 Subject: [PATCH 07/89] im a perfectionist okay??? MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 😭 --- source/funkin/editors/stager/StageCreationScreen.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/editors/stager/StageCreationScreen.hx b/source/funkin/editors/stager/StageCreationScreen.hx index f600de11..e17bde86 100644 --- a/source/funkin/editors/stager/StageCreationScreen.hx +++ b/source/funkin/editors/stager/StageCreationScreen.hx @@ -24,7 +24,7 @@ class StageCreationScreen extends UISubstateWindow { winTitle = "Creating New Stage"; winWidth = 748 - 32 + 40; - winHeight = 200; + winHeight = 220; super.create(); From 5f50b80df7a578342e2aca95b61ba9b4f0456010 Mon Sep 17 00:00:00 2001 From: Dirk-Dinkum <134403819+Dirk-Dinkum@users.noreply.github.com> Date: Sat, 13 Apr 2024 21:55:44 +0200 Subject: [PATCH 08/89] UIWindow collapsing fix Co-Authored-By: Ne_Eo --- source/funkin/backend/FunkinSprite.hx | 1 + source/funkin/editors/charter/CharterNote.hx | 2 +- .../editors/charter/CharterStrumline.hx | 2 +- .../editors/charter/CharterStrumlineButton.hx | 2 +- source/funkin/editors/ui/UISliceSprite.hx | 10 ++++++++ source/funkin/editors/ui/UISprite.hx | 10 +++++++- source/funkin/editors/ui/UIState.hx | 17 ++----------- source/funkin/editors/ui/UIWindow.hx | 25 +++++++++++++------ 8 files changed, 42 insertions(+), 27 deletions(-) diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx index 3f3f538c..6e247850 100644 --- a/source/funkin/backend/FunkinSprite.hx +++ b/source/funkin/backend/FunkinSprite.hx @@ -123,6 +123,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I private var countedBeat = 0; public function beatHit(curBeat:Int) { + if(!animEnabled) return; if (beatAnims.length > 0 && (curBeat + beatOffset) % beatInterval == 0) { if(skipNegativeBeats && curBeat < 0) return; diff --git a/source/funkin/editors/charter/CharterNote.hx b/source/funkin/editors/charter/CharterNote.hx index bc214209..af6dc7ea 100644 --- a/source/funkin/editors/charter/CharterNote.hx +++ b/source/funkin/editors/charter/CharterNote.hx @@ -139,7 +139,7 @@ class CharterNote extends UISprite implements ICharterSelectable { sustainDraggable = false; if (!hovered && susLength != 0) { - UIState.state.updateSpriteRect(sustainSpr); + sustainSpr.updateSpriteRect(); sustainDraggable = UIState.state.isOverlapping(sustainSpr, @:privateAccess sustainSpr.__rect); } diff --git a/source/funkin/editors/charter/CharterStrumline.hx b/source/funkin/editors/charter/CharterStrumline.hx index c7b332e3..6ffb297a 100644 --- a/source/funkin/editors/charter/CharterStrumline.hx +++ b/source/funkin/editors/charter/CharterStrumline.hx @@ -85,7 +85,7 @@ class CharterStrumline extends UISprite { healthIcons.follow(this, ((40 * 4) - healthIcons.width) / 2, 7 + (__healthYOffset = FlxMath.lerp(__healthYOffset, draggable ? 8 : 0, 1/20))); draggingSprite.selectable = draggable; - UIState.state.updateSpriteRect(draggingSprite); + draggingSprite.updateSpriteRect(); var dragScale:Float = FlxMath.lerp(draggingSprite.scale.x, draggable ? 1 : 0.8, 1/16); draggingSprite.scale.set(dragScale, dragScale); diff --git a/source/funkin/editors/charter/CharterStrumlineButton.hx b/source/funkin/editors/charter/CharterStrumlineButton.hx index a0a8c7df..c7d4944a 100644 --- a/source/funkin/editors/charter/CharterStrumlineButton.hx +++ b/source/funkin/editors/charter/CharterStrumlineButton.hx @@ -58,7 +58,7 @@ class CharterStrumlineButton extends UISprite { super.update(elapsed); - UIState.state.updateSpriteRect(button); + button.updateSpriteRect(); if(UIState.state.curContextMenu == null && UIState.state.isOverlapping(button, button.__rect)) { buttonScale.set(0.95, 0.95); if (FlxG.mouse.justPressed && onClick != null) { diff --git a/source/funkin/editors/ui/UISliceSprite.hx b/source/funkin/editors/ui/UISliceSprite.hx index e1f91b8d..664ede98 100644 --- a/source/funkin/editors/ui/UISliceSprite.hx +++ b/source/funkin/editors/ui/UISliceSprite.hx @@ -45,6 +45,11 @@ class UISliceSprite extends UISprite { var bottom:FlxFrame = null; var bottomright:FlxFrame = null; + public var topHeight:Int = 0; + public var bottomHeight:Int = 0; + public var leftWidth:Int = 0; + public var rightWidth:Int = 0; + override function set_frames(val) { super.set_frames(val); calculateFrames(); @@ -70,6 +75,11 @@ class UISliceSprite extends UISprite { bottomleft = frames.frames[framesOffset + 6]; bottom = frames.frames[framesOffset + 7]; bottomright = frames.frames[framesOffset + 8]; + + leftWidth = Std.int(Math.max(topleft.frame.width, Math.max(middleleft.frame.width, bottomleft.frame.width))); + rightWidth = Std.int(Math.max(topright.frame.width, Math.max(middleright.frame.width, bottomright.frame.width))); + topHeight = Std.int(Math.max(topleft.frame.height, Math.max(top.frame.height, topright.frame.height))); + bottomHeight = Std.int(Math.max(topleft.frame.height, Math.max(top.frame.height, topright.frame.height))); } public override function draw() @:privateAccess { diff --git a/source/funkin/editors/ui/UISprite.hx b/source/funkin/editors/ui/UISprite.hx index 1246e6de..07c9adc8 100644 --- a/source/funkin/editors/ui/UISprite.hx +++ b/source/funkin/editors/ui/UISprite.hx @@ -55,7 +55,8 @@ class UISprite extends FlxSprite { FlxCamera._defaultCameras = cameras; for(m in members) - m.update(elapsed); + if(m.exists && m.active) + m.update(elapsed); FlxCamera._defaultCameras = __oldDefCams; } @@ -114,4 +115,11 @@ class UISprite extends FlxSprite { if (hoverCallback != null) hoverCallback(); } + + public function updateSpriteRect() { + __rect.x = x; + __rect.y = y; + __rect.width = width; + __rect.height = height; + } } \ No newline at end of file diff --git a/source/funkin/editors/ui/UIState.hx b/source/funkin/editors/ui/UIState.hx index 1c32fad6..da3fdfc8 100644 --- a/source/funkin/editors/ui/UIState.hx +++ b/source/funkin/editors/ui/UIState.hx @@ -59,28 +59,15 @@ class UIState extends MusicBeatState { currentFocus.onTextEdit(str, start, end); } - public inline function updateSpriteRect(spr:UISprite) { - spr.__rect.x = spr.x; - spr.__rect.y = spr.y; - spr.__rect.width = spr.width; - spr.__rect.height = spr.height; - } - public function updateButtonHandler(spr:UISprite, buttonHandler:Void->Void) { - spr.__rect.x = spr.x; - spr.__rect.y = spr.y; - spr.__rect.width = spr.width; - spr.__rect.height = spr.height; + spr.updateSpriteRect(); updateRectButtonHandler(spr, spr.__rect, buttonHandler); } public function isOverlapping(spr:UISprite, rect:FlxRect) { for(camera in spr.__lastDrawCameras) { var pos = FlxG.mouse.getScreenPosition(camera, FlxPoint.get()); - __rect.x = rect.x; - __rect.y = rect.y; - __rect.width = rect.width; - __rect.height = rect.height; + __rect.copyFrom(rect); __rect.x -= camera.scroll.x * spr.scrollFactor.x; __rect.y -= camera.scroll.y * spr.scrollFactor.y; diff --git a/source/funkin/editors/ui/UIWindow.hx b/source/funkin/editors/ui/UIWindow.hx index 59ff735f..64f11eb8 100644 --- a/source/funkin/editors/ui/UIWindow.hx +++ b/source/funkin/editors/ui/UIWindow.hx @@ -18,19 +18,28 @@ class UIWindow extends UISliceSprite { public override function update(elapsed:Float) { super.update(elapsed); - if(collapsable && FlxG.mouse.justPressed) { - // TOOLBAR + cursor = ARROW; + + if(collapsable) { __rect.x = x; __rect.y = y; - __rect.width = bWidth; __rect.height = 23; + __rect.width = bWidth; __rect.height = topHeight; + if(UIState.state.isOverlapping(this, __rect)) { - content.exists = !content.exists; - drawMiddle = !drawMiddle; - drawBottom = !drawBottom; + cursor = BUTTON; + if(FlxG.mouse.justPressed) { + content.exists = !content.exists; + drawMiddle = !drawMiddle; + drawBottom = !drawBottom; + } } } - __rect.x = x; __rect.y = y+23; - __rect.width = bWidth; __rect.height = bHeight-23; + __rect.x = x; + __rect.width = bWidth; + if(content.exists) { + __rect.y = y+topHeight; + __rect.height = bHeight-topHeight; + } hovered = UIState.state.isOverlapping(this, __rect); } } \ No newline at end of file From 9e9e4cd2b87c818393e7ed962996562d9b5d9b9d Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Sat, 13 Apr 2024 22:34:57 +0200 Subject: [PATCH 09/89] Added Focus and Toggles --- source/funkin/backend/FunkinSprite.hx | 1 - source/funkin/editors/stager/StageEditor.hx | 253 ++++++++------------ source/funkin/game/Character.hx | 9 +- source/funkin/game/Stage.hx | 22 +- 4 files changed, 117 insertions(+), 168 deletions(-) diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx index 6e247850..3b81598a 100644 --- a/source/funkin/backend/FunkinSprite.hx +++ b/source/funkin/backend/FunkinSprite.hx @@ -39,7 +39,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I public var beatAnims:Array = []; public var name:String; public var zoomFactor:Float = 1; - //public var initialZoom:Float = 1; public var debugMode:Bool = false; public var animDatas:Map = []; public var animEnabled:Bool = true; diff --git a/source/funkin/editors/stager/StageEditor.hx b/source/funkin/editors/stager/StageEditor.hx index cafe1aed..e38565e3 100644 --- a/source/funkin/editors/stager/StageEditor.hx +++ b/source/funkin/editors/stager/StageEditor.hx @@ -32,11 +32,15 @@ class StageEditor extends UIState { public var xmlMap:Map = new Map(); public var chars:Array = []; + public var charMap:Map = []; public var stageCamera:FlxCamera; public var guideCamera:FlxCamera; public var uiCamera:FlxCamera; + public var showOutlines:Bool = true; + public var showCharacters:Bool = true; + public var undos:UndoList = new UndoList(); public inline static function exID(id:String) { @@ -81,111 +85,6 @@ class StageEditor extends UIState { } ] }, - /*{ - label: "Edit", - childs: [ - { - label: "Undo", - keybind: [CONTROL, Z], - onSelect: _edit_undo - }, - { - label: "Redo", - keybinds: [[CONTROL, Y], [CONTROL, SHIFT, Z]], - onSelect: _edit_redo - } - ] - },*/ - /*{ - label: "Character", - childs: [ - { - label: "New Animation", - keybind: [CONTROL, N], - onSelect: _char_add_anim, - }, - { - label: "Edit Animation", - onSelect: _char_edit_anim, - }, - { - label: "Delete Animation", - keybind: [DELETE], - onSelect: _char_remove_anim, - }, - null, - { - label: "Edit Info", - onSelect: _char_edit_info, - } - ] - }, - { - label: "Playback", - childs: [ - { - label: "Play Animation", - keybind: [SPACE], - onSelect: _playback_play_anim, - }, - { - label: "Stop Animation", - onSelect: _playback_stop_anim - } - ] - }, - { - label: "Offsets", - childs: [ - { - label: "Move Left", - keybind: [LEFT], - onSelect: _offsets_left, - }, - { - label: "Move Up", - keybind: [UP], - onSelect: _offsets_up, - }, - { - label: "Move Down", - keybind: [DOWN], - onSelect: _offsets_down, - }, - { - label: "Move Right", - keybind: [RIGHT], - onSelect: _offsets_right, - }, - null, - { - label: "Move Extra Left", - keybind: [SHIFT, LEFT], - onSelect: _offsets_extra_left, - }, - { - label: "Move Extra Up", - keybind: [SHIFT, UP], - onSelect: _offsets_extra_up, - }, - { - label: "Move Extra Down", - keybind: [SHIFT, DOWN], - onSelect: _offsets_extra_down, - }, - { - label: "Move Extra Right", - keybind: [SHIFT, RIGHT], - onSelect: _offsets_extra_right, - }, - null, - { - label: "Clear Offsets", - keybind: [CONTROL, R], - onSelect: _offsets_clear, - } - ] - },*/ { label: "View", childs: [ @@ -204,7 +103,40 @@ class StageEditor extends UIState { keybind: [CONTROL, NUMPADZERO], onSelect: _view_zoomreset }, - + null, + { + label: "Focus Dad", + //keybind: [CONTROL, NUMPADZERO], + onSelect: _view_focusdad + }, + { + label: "Focus Gf", + //keybind: [CONTROL, NUMPADZERO], + onSelect: _view_focusgf + }, + { + label: "Focus BF", + //keybind: [CONTROL, NUMPADZERO], + onSelect: _view_focusbf + }, + // TODO: add support for custom character focus + ] + }, + { + label: "Editor", + childs: [ + { + label: "Show Outlines", + //keybind: [CONTROL, NUMPADPLUS], + onSelect: _editor_showOutlines, + icon: showOutlines ? 1 : 0 + }, + { + label: "Show Characters", + //keybind: [CONTROL, NUMPADMINUS], + onSelect: _editor_showCharacters, + icon: showCharacters ? 1 : 0 + } ] }, ]; @@ -226,7 +158,7 @@ class StageEditor extends UIState { stage.onXMLLoaded = function(xml:Access, elems:Array) { return elems; } - stage.onNodeLoadedPost = function(node:Access, sprite:Dynamic) { + stage.onNodeFinished = function(node:Access, sprite:Dynamic) { if(sprite is FlxSprite) { sprite.moves = false; } @@ -245,12 +177,13 @@ class StageEditor extends UIState { } if(sprite is StageCharPos) { var charPos:StageCharPos = cast sprite; + // TODO: fix default characters not being added var charName = switch(charPos.name) { case "boyfriend": "bf"; case "girlfriend": "gf"; default: charPos.name; } - var char = new Character(0,0, charName, stage.isCharFlipped(charPos.name, charName == "bf")); + var char = new Character(0,0, charName, stage.isCharFlipped(charPos.name, charName == "bf"), true); char.debugMode = true; // Play first anim, and make it the last frame var animToPlay = char.getAnimOrder()[0]; @@ -281,9 +214,10 @@ class StageEditor extends UIState { var node = char.extra.get(exID("node")); stage.applyCharStuff(char, charPos.name, 0); + charMap[charPos.name] = char; } - zoom = calculateZoom(stage.defaultZoom); + setZoom(stage.defaultZoom); topMenuSpr = new UITopMenu(topMenu); topMenuSpr.cameras = uiGroup.cameras = [uiCamera]; @@ -305,7 +239,10 @@ class StageEditor extends UIState { stageSpritesWindow.add((type == "box" || type == "solid") ? new StageSolidButton(0,0, sprite, xml) : new StageSpriteButton(0,0, sprite, xml)); } else if(sprite is StageCharPos) { - stageSpritesWindow.add(new StageCharacterButton(0,0, sprite, xml)); + var char = charMap[sprite.name]; + var button = new StageCharacterButton(0,0, sprite, xml); + char.extra.set(exID("button"), button); + stageSpritesWindow.add(button); } } } @@ -346,31 +283,10 @@ class StageEditor extends UIState { UIUtil.processShortcuts(topMenu); } - /*if (character != null) - characterPropertiresWindow.characterInfo.text = '${character.getNameList().length} Animations\nFlipped: ${character.flipX}\nSprite: ${character.sprite}\nAnim: ${character.getAnimName()}\nOffset: (${character.frameOffset.x}, ${character.frameOffset.y})'; + //if (character != null) + // characterPropertiresWindow.characterInfo.text = '${character.getNameList().length} Animations\nFlipped: ${character.flipX}\nSprite: ${character.sprite}\nAnim: ${character.getAnimName()}\nOffset: (${character.frameOffset.x}, ${character.frameOffset.y})'; - if (!(characterPropertiresWindow.hovered || characterAnimsWindow.hovered) && !characterAnimsWindow.dragging) { - if (FlxG.mouse.wheel != 0) { - zoom += 0.25 * FlxG.mouse.wheel; - __camZoom = Math.pow(2, zoom); - } - - if (FlxG.mouse.justReleasedRight) { - closeCurrentContextMenu(); - openContextMenu(topMenu[2].childs); - } - if (FlxG.mouse.pressed) { - nextScroll.set(nextScroll.x - FlxG.mouse.deltaScreenX, nextScroll.y - FlxG.mouse.deltaScreenY); - currentCursor = HAND; - } else - currentCursor = ARROW; - } else if (!FlxG.mouse.pressed) - currentCursor = ARROW; - - characterBG.scale.set(FlxG.width/characterBG.width, FlxG.height/characterBG.height); - characterBG.scale.set(characterBG.scale.x / charCamera.zoom, characterBG.scale.y / charCamera.zoom);*/ - - if (!(stageSpritesWindow.hovered) && !stageSpritesWindow.dragging) { + if ((!stageSpritesWindow.hovered && !stageSpritesWindow.dragging) && !topMenuSpr.hovered) { if (FlxG.mouse.wheel != 0) { zoom += 0.25 * FlxG.mouse.wheel; updateZoom(); @@ -530,8 +446,7 @@ class StageEditor extends UIState { updateZoom(); } function _view_zoomreset(_) { - zoom = 0; - updateZoom(); + setZoom(stage.defaultZoom); } inline function updateZoom() { @@ -541,41 +456,67 @@ class StageEditor extends UIState { inline function calculateZoom(zoom:Float) { return Math.log(zoom) / Math.log(2); } + + inline function setZoom(_zoom:Float) { + zoom = calculateZoom(__camZoom = _zoom); + } + + function _view_focusdad(_) { + focusCharacter(charMap["dad"]); + } + function _view_focusgf(_) { + focusCharacter(charMap["girlfriend"]); + } + function _view_focusbf(_) { + focusCharacter(charMap["boyfriend"]); + } + + function focusCharacter(char:Character) { + // TODO: fix this being incorrect + var point = char.getCameraPosition(); + nextScroll.set(point.x, point.y); + + setZoom(stage.defaultZoom); + } + + function _editor_showOutlines(t) { + showOutlines = !showOutlines; + t.icon = showOutlines ? 1 : 0; + } + + function _editor_showCharacters(t) { + showCharacters = !showCharacters; + t.icon = showCharacters ? 1 : 0; + for(char in chars) { + var button:StageCharacterButton = char.extra.get(exID("button")); + button.isHidden = !showCharacters; + button.updateInfo(button.charPos); + } + } #end override function draw() { super.draw(); + if(!showOutlines) return; + if(dot == null) { dot = new FlxSprite().makeGraphic(10, 10, FlxColor.RED); dot.camera = stageCamera; dot.forceIsOnScreen = true; } - //guideCamera.zoom = stageCamera.zoom; - //dot.scrollFactor.set(0, 0); - - /*for(member in members) { - if(member is FlxSprite) { - if(camera == null || camera == stageCamera) { - var sprite:FlxSprite = cast member; - @:privateAccess if(sprite._frame == null) continue; - if(sprite.visible) { - //trace("Drawing Guides for " + sprite); - drawGuides(sprite); - } - } - } - }*/ for(sprite in stage.stageSprites) { - if(sprite.visible && sprite.isOnScreen()) { + if(sprite.visible && sprite.isOnScreen(stageCamera)) { @:privateAccess if(sprite._frame == null) continue; drawGuides(sprite); } } - for(char in chars) { - if(char.visible && char.isOnScreen()) { - @:privateAccess if(char._frame == null) continue; - drawGuides(char); + if(showCharacters) { + for(char in chars) { + if(char.visible && char.isOnScreen(stageCamera)) { + @:privateAccess if(char._frame == null) continue; + drawGuides(char); + } } } } diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx index 40ddcd74..7639c367 100644 --- a/source/funkin/game/Character.hx +++ b/source/funkin/game/Character.hx @@ -78,7 +78,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset playAnim(event.animName, event.force, event.context, event.reversed, event.frame); } - public function new(x:Float, y:Float, ?character:String = "bf", isPlayer:Bool = false, switchAnims:Bool = true) + public function new(x:Float, y:Float, ?character:String = "bf", isPlayer:Bool = false, switchAnims:Bool = true, disableScripts:Bool = false) { super(x, y); @@ -114,7 +114,12 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset continue; } // Loads the script - script = Script.create(Paths.script(Path.withoutExtension(xmlPath), null, true)); + if(!disableScripts) { + script = Script.create(Paths.script(Path.withoutExtension(xmlPath), null, true)); + } else { + script = new DummyScript(curCharacter); + } + script.setParent(this); script.load(); applyXML(xml); diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index 070d165f..db547bfe 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -29,7 +29,8 @@ class Stage extends FlxBasic implements IBeatReceiver { public var onXMLLoaded:(Access, Array)->Array = null; public var onNodeLoaded:(Access, Dynamic)->Dynamic = null; - public var onNodeLoadedPost:(Access, Dynamic)->Void = null; + public var onNodeFinished:(Access, Dynamic)->Void = null; + public var onAddSprite:(FlxObject)->Void = null; private var spritesParentFolder = ""; @@ -111,8 +112,7 @@ class Stage extends FlxBasic implements IBeatReceiver { var spr = XMLUtil.createSpriteFromXML(node, spritesParentFolder, LOOP); stageSprites.set(spr.name, spr); - state.add(spr); - spr; + addSprite(spr); case "box" | "solid": if ( !node.has.name || !node.has.width || !node.has.height) continue; @@ -129,8 +129,7 @@ class Stage extends FlxBasic implements IBeatReceiver { ); stageSprites.set(spr.name, spr); - state.add(spr); - spr; + addSprite(spr); case "boyfriend" | "bf" | "player": addCharPos("boyfriend", node, { x: 770, @@ -178,8 +177,8 @@ class Stage extends FlxBasic implements IBeatReceiver { XMLUtil.applyXMLProperty(sprite, e); } - if(onNodeLoadedPost != null) { - onNodeLoadedPost(node, sprite); + if(onNodeFinished != null) { + onNodeFinished(node, sprite); } } } @@ -253,8 +252,13 @@ class Stage extends FlxBasic implements IBeatReceiver { } } - state.add(charPos); - return characterPoses[name] = charPos; + return addSprite(characterPoses[name] = charPos); + } + + function addSprite(sprite:T):T { + state.add(sprite); + if(onAddSprite != null) onAddSprite(sprite); + return sprite; } public inline function isCharFlipped(posName:String, def:Bool = false) From f0f1ab213393119d80ffdd151d7e5c5f716123d2 Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Sat, 13 Apr 2024 22:45:00 +0200 Subject: [PATCH 10/89] Fix offset focus --- source/funkin/editors/stager/StageEditor.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/funkin/editors/stager/StageEditor.hx b/source/funkin/editors/stager/StageEditor.hx index e38565e3..fec13b2a 100644 --- a/source/funkin/editors/stager/StageEditor.hx +++ b/source/funkin/editors/stager/StageEditor.hx @@ -472,9 +472,8 @@ class StageEditor extends UIState { } function focusCharacter(char:Character) { - // TODO: fix this being incorrect var point = char.getCameraPosition(); - nextScroll.set(point.x, point.y); + nextScroll.set(point.x - stageCamera.width / 2, point.y - stageCamera.height / 2); setZoom(stage.defaultZoom); } From 062ac6599249bd2968624439b51bbb298219a633 Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Sat, 13 Apr 2024 22:55:24 +0200 Subject: [PATCH 11/89] Better name for the camera xd --- .../funkin/backend/system/{NothingCamera.hx => FakeCamera.hx} | 4 ++-- source/funkin/backend/utils/MatrixUtil.hx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename source/funkin/backend/system/{NothingCamera.hx => FakeCamera.hx} (95%) diff --git a/source/funkin/backend/system/NothingCamera.hx b/source/funkin/backend/system/FakeCamera.hx similarity index 95% rename from source/funkin/backend/system/NothingCamera.hx rename to source/funkin/backend/system/FakeCamera.hx index 45a91a1a..5170c246 100644 --- a/source/funkin/backend/system/NothingCamera.hx +++ b/source/funkin/backend/system/FakeCamera.hx @@ -12,8 +12,8 @@ import openfl.geom.ColorTransform; import openfl.geom.Point; import openfl.geom.Rectangle; -class NothingCamera extends FlxCamera { - public static final instance = new NothingCamera(); +class FakeCamera extends FlxCamera { + public static final instance = new FakeCamera(); public function new() { super(); diff --git a/source/funkin/backend/utils/MatrixUtil.hx b/source/funkin/backend/utils/MatrixUtil.hx index 146fd430..25e08124 100644 --- a/source/funkin/backend/utils/MatrixUtil.hx +++ b/source/funkin/backend/utils/MatrixUtil.hx @@ -11,7 +11,7 @@ class MatrixUtil { //if(_height == -1) _height = sprite.height; if(camera == null) camera = sprite.camera; if(points is FlxBasePoint) points = [points]; - var nc = funkin.backend.system.NothingCamera.instance; + var nc = funkin.backend.system.FakeCamera.instance; nc.zoom = camera.zoom; nc.scroll.set(camera.scroll.x, camera.scroll.y); nc.pixelPerfectRender = camera.pixelPerfectRender; From f9649d3ff216e402c31fc35224a12b526323b2d7 Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Sun, 14 Apr 2024 10:24:25 +0200 Subject: [PATCH 12/89] Renamed the folder --- source/funkin/backend/utils/MatrixUtil.hx | 2 +- source/funkin/editors/EditorPicker.hx | 2 +- .../funkin/editors/{stager => stage}/StageCreationScreen.hx | 2 +- source/funkin/editors/{stager => stage}/StageEditor.hx | 6 +++--- source/funkin/editors/{stager => stage}/StageInfoScreen.hx | 2 +- source/funkin/editors/{stager => stage}/StageSelection.hx | 6 +++--- .../{stager => stage}/elements/StageCharacterButton.hx | 2 +- .../{stager => stage}/elements/StageElementButton.hx | 2 +- .../editors/{stager => stage}/elements/StageSolidButton.hx | 2 +- .../editors/{stager => stage}/elements/StageSpriteButton.hx | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) rename source/funkin/editors/{stager => stage}/StageCreationScreen.hx (98%) rename source/funkin/editors/{stager => stage}/StageEditor.hx (99%) rename source/funkin/editors/{stager => stage}/StageInfoScreen.hx (99%) rename source/funkin/editors/{stager => stage}/StageSelection.hx (95%) rename source/funkin/editors/{stager => stage}/elements/StageCharacterButton.hx (97%) rename source/funkin/editors/{stager => stage}/elements/StageElementButton.hx (98%) rename source/funkin/editors/{stager => stage}/elements/StageSolidButton.hx (87%) rename source/funkin/editors/{stager => stage}/elements/StageSpriteButton.hx (96%) diff --git a/source/funkin/backend/utils/MatrixUtil.hx b/source/funkin/backend/utils/MatrixUtil.hx index 25e08124..bd278385 100644 --- a/source/funkin/backend/utils/MatrixUtil.hx +++ b/source/funkin/backend/utils/MatrixUtil.hx @@ -27,7 +27,7 @@ class MatrixUtil { // reset to ingame coords x += camera.scroll.x; y += camera.scroll.y; - + if(isFunkinSprite) { var sprite:FunkinSprite = cast sprite; diff --git a/source/funkin/editors/EditorPicker.hx b/source/funkin/editors/EditorPicker.hx index 534ec538..7b98f0e6 100644 --- a/source/funkin/editors/EditorPicker.hx +++ b/source/funkin/editors/EditorPicker.hx @@ -20,7 +20,7 @@ class EditorPicker extends MusicBeatSubstate { { name: "Stage Editor", iconID: 2, - state: funkin.editors.stager.StageSelection + state: funkin.editors.stage.StageSelection }, { name: "UI Debug State", diff --git a/source/funkin/editors/stager/StageCreationScreen.hx b/source/funkin/editors/stage/StageCreationScreen.hx similarity index 98% rename from source/funkin/editors/stager/StageCreationScreen.hx rename to source/funkin/editors/stage/StageCreationScreen.hx index e17bde86..957ff896 100644 --- a/source/funkin/editors/stager/StageCreationScreen.hx +++ b/source/funkin/editors/stage/StageCreationScreen.hx @@ -1,4 +1,4 @@ -package funkin.editors.stager; +package funkin.editors.stage; typedef StageCreationData = { var name:String; diff --git a/source/funkin/editors/stager/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx similarity index 99% rename from source/funkin/editors/stager/StageEditor.hx rename to source/funkin/editors/stage/StageEditor.hx index fec13b2a..cf7fe342 100644 --- a/source/funkin/editors/stager/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -1,11 +1,11 @@ -package funkin.editors.stager; +package funkin.editors.stage; import flixel.math.FlxAngle; -import flixel.util.FlxColor; import flixel.math.FlxPoint; +import flixel.util.FlxColor; import funkin.backend.system.framerate.Framerate; import funkin.backend.utils.XMLUtil.AnimData; -import funkin.editors.stager.elements.*; +import funkin.editors.stage.elements.*; import funkin.editors.ui.UIContextMenu.UIContextMenuOption; import funkin.game.Character; import funkin.game.Stage; diff --git a/source/funkin/editors/stager/StageInfoScreen.hx b/source/funkin/editors/stage/StageInfoScreen.hx similarity index 99% rename from source/funkin/editors/stager/StageInfoScreen.hx rename to source/funkin/editors/stage/StageInfoScreen.hx index 89b3cedf..10fe046b 100644 --- a/source/funkin/editors/stager/StageInfoScreen.hx +++ b/source/funkin/editors/stage/StageInfoScreen.hx @@ -1,4 +1,4 @@ -package funkin.editors.stager; +package funkin.editors.stage; import flixel.math.FlxPoint; import funkin.editors.extra.PropertyButton; diff --git a/source/funkin/editors/stager/StageSelection.hx b/source/funkin/editors/stage/StageSelection.hx similarity index 95% rename from source/funkin/editors/stager/StageSelection.hx rename to source/funkin/editors/stage/StageSelection.hx index 726849bf..6fa49597 100644 --- a/source/funkin/editors/stager/StageSelection.hx +++ b/source/funkin/editors/stage/StageSelection.hx @@ -1,12 +1,12 @@ -package funkin.editors.stager; +package funkin.editors.stage; -import funkin.options.OptionsScreen; +import funkin.editors.stage.StageCreationScreen.StageCreationData; import funkin.game.Stage; +import funkin.options.OptionsScreen; import funkin.options.type.IconOption; import funkin.options.type.NewOption; import funkin.options.type.OptionType; import funkin.options.type.TextOption; -import funkin.editors.stager.StageCreationScreen.StageCreationData; class StageSelection extends EditorTreeMenu { diff --git a/source/funkin/editors/stager/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx similarity index 97% rename from source/funkin/editors/stager/elements/StageCharacterButton.hx rename to source/funkin/editors/stage/elements/StageCharacterButton.hx index d133ed29..57dc4e9d 100644 --- a/source/funkin/editors/stager/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -1,4 +1,4 @@ -package funkin.editors.stager.elements; +package funkin.editors.stage.elements; import funkin.game.Character; import funkin.game.Stage.StageCharPos; diff --git a/source/funkin/editors/stager/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx similarity index 98% rename from source/funkin/editors/stager/elements/StageElementButton.hx rename to source/funkin/editors/stage/elements/StageElementButton.hx index b1b9a507..a834e653 100644 --- a/source/funkin/editors/stager/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -1,4 +1,4 @@ -package funkin.editors.stager.elements; +package funkin.editors.stage.elements; import haxe.xml.Access; import flixel.util.FlxColor; diff --git a/source/funkin/editors/stager/elements/StageSolidButton.hx b/source/funkin/editors/stage/elements/StageSolidButton.hx similarity index 87% rename from source/funkin/editors/stager/elements/StageSolidButton.hx rename to source/funkin/editors/stage/elements/StageSolidButton.hx index 96f74c63..31eeba1d 100644 --- a/source/funkin/editors/stager/elements/StageSolidButton.hx +++ b/source/funkin/editors/stage/elements/StageSolidButton.hx @@ -1,4 +1,4 @@ -package funkin.editors.stager.elements; +package funkin.editors.stage.elements; import haxe.xml.Access; import flixel.util.FlxColor; diff --git a/source/funkin/editors/stager/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx similarity index 96% rename from source/funkin/editors/stager/elements/StageSpriteButton.hx rename to source/funkin/editors/stage/elements/StageSpriteButton.hx index 60405cef..425ffd2d 100644 --- a/source/funkin/editors/stager/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -1,4 +1,4 @@ -package funkin.editors.stager.elements; +package funkin.editors.stage.elements; import haxe.xml.Access; import flixel.util.FlxColor; From 1763b09a7bd1ac5f03288dc0336b140943d45b4d Mon Sep 17 00:00:00 2001 From: NeeEoo Date: Sun, 14 Apr 2024 14:55:08 +0200 Subject: [PATCH 13/89] Started working on edit screen --- .../layouts/stage/spriteEditScreen.xml | 67 ++++ source/funkin/editors/stage/StageEditor.hx | 146 ++++++++- .../editors/stage/StageSpriteEditScreen.hx | 286 ++++++++++++++++++ .../stage/elements/StageCharacterButton.hx | 10 +- .../stage/elements/StageElementButton.hx | 8 + .../stage/elements/StageSolidButton.hx | 2 +- .../stage/elements/StageSpriteButton.hx | 20 +- source/funkin/game/Stage.hx | 2 +- 8 files changed, 532 insertions(+), 9 deletions(-) create mode 100644 assets/editors/layouts/stage/spriteEditScreen.xml create mode 100644 source/funkin/editors/stage/StageSpriteEditScreen.hx diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml new file mode 100644 index 00000000..5b10371f --- /dev/null +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -0,0 +1,67 @@ + + + + + + + + <textbox name="nameTextBox" label="Name Identifier" text="${data.getName()}" x="20" y="title.y + TO" width="200" height="32" /> + <textbox name="spriteTextBox" label="Image File (${stage.spritesParentFolder})" text="${getEx('imageFile')}" x="last.x + last.bWidth + XOFFSET" y="title.y + TO" width="200" height="32" /> + + <set name="curY" value="nameTextBox.y + nameTextBox.bHeight + YOFFSET" /> + + <stepper name="xStepper" label="X" value="sprite.x" x="20" y="curY" step="1" width="100" /> + <stepper name="yStepper" label="Y" value="sprite.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="1" width="100" /> + + <stepper name="scrollXStepper" label="Scroll X" value="sprite.scrollFactor.x" x="spriteTextBox.x" y="curY" step="0.01" width="100" /> + <stepper name="scrollYStepper" label="Scroll Y" value="sprite.scrollFactor.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="0.01" width="100" /> + + <stepper name="scaleXStepper" label="Scale X" value="sprite.scale.x" x="20 + (200 + XOFFSET) * 2" y="curY" step="0.01" width="100" /> + <stepper name="scaleYStepper" label="Scale Y" value="sprite.scale.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="0.01" width="100" /> + + <stepper name="skewXStepper" label="Skew X" value="sprite.skew.x" x="20 + (200 + XOFFSET) * 3" y="curY" step="0.01" width="100" /> + <stepper name="skewYStepper" label="Skew Y" value="sprite.skew.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="0.01" width="100" /> + + <set name="curY" value="xStepper.y + xStepper.bHeight + YOFFSET" /> + + <stepper name="angleStepper" label="Angle" value="sprite.angle" x="20 + (200 + XOFFSET) * 0" y="curY" step="0.01" width="100" /> + <stepper name="zoomFactorStepper" label="Zoom Factor" value="sprite.zoomFactor" x="20 + (200 + XOFFSET) * 1" y="curY" step="0.01" width="100" /> + + <dropdown name="animType" label="Animation Type" value="['NONE','BEAT','LOOP'][sprite.spriteAnimType]" x="20 + (200 + XOFFSET) * 2" y="curY" width="100" height="32" options="NONE,BEAT,LOOP" /> + + <exec> + function onSave() { + sprite.x = xStepper.value; + sprite.y = yStepper.value; + sprite.zoomFactor = zoomFactorStepper.value; + //sprite.antialiasing = antialiasingCheckbox.checked; + //sprite.color = colorWheel.color; + sprite.spriteAnimType = animType.index; + + function saveXY(obj:Dynamic, name:String, x:UINumericStepper, y:UINumericStepper) { + data.xml.remove(name + ""); + data.xml.remove(name + "x"); + data.xml.remove(name + "y"); + + obj.x = x.value; + obj.y = y.value; + + if(x.value == y.value) + data.xml.set(name, x.value); + else { + data.xml.set(name + "x", x.value); + data.xml.set(name + "y", y.value); + } + } + + data.xml.set("x", xStepper.value); + data.xml.set("y", yStepper.value); + data.xml.set("zoom", zoomFactorStepper.value); + data.xml.set("type", ['NONE','BEAT','LOOP'][animType.index]); + + saveXY(sprite.scrollFactor, "scroll", scrollXStepper, scrollYStepper); + saveXY(sprite.scale, "scale", scaleXStepper, scaleYStepper); + saveXY(sprite.skew, "skew", skewXStepper, skewYStepper); + } + </exec> +</window> \ No newline at end of file diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index cf7fe342..86cf70a1 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -28,8 +28,9 @@ class StageEditor extends UIState { public var uiGroup:FlxTypedGroup<FlxSprite> = new FlxTypedGroup<FlxSprite>(); public var stageSpritesWindow:UIButtonList<StageElementButton>; + public var stageSprites:FlxTypedGroup<StageSprite> = new FlxTypedGroup<StageSprite>(); - public var xmlMap:Map<FlxBasic, Access> = new Map<FlxBasic, Access>(); + public var xmlMap:Map<FlxObject, Access> = new Map<FlxObject, Access>(); public var chars:Array<Character> = []; public var charMap:Map<String, Character> = []; @@ -38,6 +39,8 @@ class StageEditor extends UIState { public var guideCamera:FlxCamera; public var uiCamera:FlxCamera; + public static var selection:Selection; + public var showOutlines:Bool = true; public var showCharacters:Bool = true; @@ -168,11 +171,15 @@ class StageEditor extends UIState { } } stage.onNodeLoaded = function(node:Access, sprite:Dynamic):Dynamic { + var name = ""; if(sprite is FlxSprite) { //sprite.forceIsOnScreen = true; // hack } if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + name = sprite.name; sprite.extra.set(exID("type"), node.name); + sprite.extra.set(exID("imageFile"), '${node.getAtt("sprite").getDefault(sprite.name)}'); //sprite.active = false; } if(sprite is StageCharPos) { @@ -183,6 +190,7 @@ class StageEditor extends UIState { case "girlfriend": "gf"; default: charPos.name; } + name = charPos.name; var char = new Character(0,0, charName, stage.isCharFlipped(charPos.name, charName == "bf"), true); char.debugMode = true; // Play first anim, and make it the last frame @@ -204,6 +212,11 @@ class StageEditor extends UIState { } order.push(sprite); xmlMap.set(sprite, node); + + //var t = new StageSprite(name, sprite); + //t.node = node; + //stageSprites.add(t); + return sprite; } stage.loadXml(stage.stageXML, true); @@ -217,6 +230,12 @@ class StageEditor extends UIState { charMap[charPos.name] = char; } + add(stageSprites); + + for(spr in order) { + + } + setZoom(stage.defaultZoom); topMenuSpr = new UITopMenu(topMenu); @@ -595,4 +614,129 @@ class StageEditor extends UIState { enum StageChange { CEditInfo(oldInfo:Xml, newInfo:Xml); +} + +@:forward abstract Selection(Array<StageSprite>) from Array<StageSprite> to Array<StageSprite> { + public inline function new(?array:Array<StageSprite>) + this = array == null ? [] : array; + + // too lazy to put this in every for loop so i made it a abstract + //public inline function loop(onNote:CharterNote->Void, ?onEvent:CharterEvent->Void, ?draggableOnly:Bool = true) { + // for (s in this) { + // if (s is CharterNote && onNote != null && (draggableOnly ? s.draggable: true)) + // onNote(cast(s, CharterNote)); + // else if (s is CharterEvent && onEvent != null && (draggableOnly ? s.draggable: true)) + // onEvent(cast(s, CharterEvent)); + // } + //} +} + +class StageSprite extends UISprite { + public var tracker:FlxObject; + public var funkinTracker:FunkinSprite; + public var node:Access; + + public var name:String; + + public var extra:Map<String, Dynamic> = new Map<String, Dynamic>(); + + public var scrollX:Float; + public var scrollY:Float; + public var scaleX:Float; + public var scaleY:Float; + public var zoomFactor:Float = 1; // TODO: implement this + public var skewX:Float; + public var skewY:Float; + public var spriteAnimType:XMLAnimType; + + public var skipNegativeBeats:Bool = false; + public var beatInterval:Int = 0; + public var beatOffset:Int = 0; + + public var lowMemory:Bool; + public var highMemory:Bool; + + public var selected:Bool = false; + public var draggable:Bool = false; + + public function new(name:String, sprite:FlxObject) { + super(x, y); + this.name = name; + this.tracker = sprite; + + scrollX = tracker.scrollFactor.x; + scrollY = tracker.scrollFactor.y; + if(tracker is FunkinSprite) { + var tracker:FunkinSprite = cast tracker; + scaleX = tracker.scale.x; + scaleY = tracker.scale.y; + funkinTracker = tracker; + } + else if (tracker is StageCharPos) { + var tracker:StageCharPos = cast tracker; + var char:Character = tracker.extra.get(StageEditor.exID("char")); + scaleX = tracker.scale.x; + scaleY = tracker.scale.y; + funkinTracker = char; + } + + lowMemory = node.x.parent.nodeName == "low-memory"; + highMemory = node.x.parent.nodeName == "high-memory"; + + if(funkinTracker != null) { + skewX = funkinTracker.skew.x; + skewY = funkinTracker.skew.y; + alpha = funkinTracker.alpha; + spriteAnimType = funkinTracker.spriteAnimType; + antialiasing = funkinTracker.antialiasing; + width = funkinTracker.width; + height = funkinTracker.height; + color = funkinTracker.color; + + skipNegativeBeats = funkinTracker.skipNegativeBeats; + beatInterval = funkinTracker.beatInterval; + beatOffset = funkinTracker.beatOffset; + } + + } + + public override function update(elapsed:Float) { + super.update(elapsed); + if (tracker.exists) { + tracker.x = x; + tracker.y = y; + tracker.scrollFactor.set(scrollX, scrollY); + if(tracker is FlxSprite) { + var tracker:FlxSprite = cast tracker; + } + else if (tracker is StageCharPos) { + var tracker:StageCharPos = cast tracker; + tracker.skewX = skewX; + tracker.skewY = skewY; + } + + if(funkinTracker != null) { + funkinTracker.scale.set(scaleX, scaleY); + funkinTracker.skew.set(skewX, skewY); + funkinTracker.alpha = alpha; + funkinTracker.spriteAnimType = spriteAnimType; + funkinTracker.antialiasing = antialiasing; + funkinTracker.width = width; + funkinTracker.height = height; + + funkinTracker.skipNegativeBeats = skipNegativeBeats; + funkinTracker.beatInterval = beatInterval; + funkinTracker.beatOffset = beatOffset; + + funkinTracker.color = color; + } + } + } + + public function handleSelection(selectionBox:UISliceSprite):Bool { + return false; + }; + public function handleDrag(change:FlxPoint):Void { + + }; } \ No newline at end of file diff --git a/source/funkin/editors/stage/StageSpriteEditScreen.hx b/source/funkin/editors/stage/StageSpriteEditScreen.hx new file mode 100644 index 00000000..3559044d --- /dev/null +++ b/source/funkin/editors/stage/StageSpriteEditScreen.hx @@ -0,0 +1,286 @@ +package funkin.editors.stage; + +import funkin.backend.scripting.HScript; +import hscript.Interp; +import haxe.xml.Access; +import flixel.math.FlxPoint; +import funkin.backend.chart.ChartData.ChartMetaData; +import funkin.editors.extra.PropertyButton; +import funkin.editors.stage.elements.StageElementButton; +import hscript.*; +import hscript.Expr.Error; +import hscript.Parser; + +using StringTools; + +class StageSpriteEditScreen extends UISubstateWindow { + public var data:StageElementButton; + public var sprite:FunkinSprite; + + public var saveButton:UIButton; + public var closeButton:UIButton; + + var elementMap:Map<String, UISprite> = []; + + + public function new(data:StageElementButton) { + super(); + this.data = data; + } + + var parser = HScript.initParser(); + var interp = new Interp(); + + function set(name:String, value:Dynamic) { + interp.variables.set(name, value); + } + + function get(name:String):Dynamic { + return interp.variables.get(name); + } + + public override function create() { + var layout = new Access(Xml.parse(Assets.getText('assets/editors/layouts/stage/spriteEditScreen.xml')).firstElement()); + winTitle = layout.getAtt("title").getDefault(winTitle); + winWidth = Std.parseInt(layout.getAtt("width")).getDefault(winWidth); + winHeight = Std.parseInt(layout.getAtt("height")).getDefault(winHeight); + + sprite = data.getSprite(); + + set("stage", StageEditor.instance.stage); + set("sprite", sprite); + set("data", data); + set("getEx", function(name:String):Dynamic { + return sprite.extra.get(StageEditor.exID(name)); + }); + set("last", null); + + function _errorHandler(error:Error) { + var fileName = error.origin; + var fn = '$fileName:${error.line}: '; + var err = error.toString(); + if (err.startsWith(fn)) err = err.substr(fn.length); + + Logs.traceColored([ + Logs.logText(fn, GREEN), + Logs.logText(err, RED) + ], ERROR); + } + + function exec(code:String):Dynamic { + try { + if (code != null && code.trim() != "") + return interp.execute(parser.parseString(code, "spriteEditScreen.xml")); + } catch(e:Error) { + _errorHandler(e); + } catch(e) { + _errorHandler(new Error(ECustom(e.toString()), 0, 0, "spriteEditScreen.xml", 0)); + } + return null; + } + + super.create(); + + function addLabelOn(ui:UISprite, text:String) + add(new UIText(ui.x, ui.y - 24, 0, text)); + + function execString(code:String):String { + if(code.indexOf("${") == -1) return code; + var text = ""; + while(code.length > 0) { + var idx = code.indexOf("${"); + if(idx == -1) { + text += code; + break; + } + text += code.substring(0, idx); + var ei = code.indexOf("}", idx); + if(ei == -1) { + text += code.substring(idx); + break; + } + var block = code.substring(idx+2, ei); + text += exec(block); + code = code.substring(ei + 1); + } + return text; + } + + function execDefault(code:String, defaultValue:Dynamic):Dynamic { + return CoolUtil.getDefault(exec(code), defaultValue); + } + + function execAtt(el:Access, key:String, defaultValue:Dynamic):Dynamic { + return execDefault(el.getAtt(key), defaultValue); + } + + for(el in layout.elements) { + var type = el.name; + //var type:String = el.getAtt("type"); + var name:String = el.getAtt("name"); + var label:String = execString(el.getAtt("label")); + var text:String = execString(el.getAtt("text")); + var x:Float = execAtt(el, "x", 0); + var y:Float = execAtt(el, "y", 0); + var width:Null<Int> = exec(el.getAtt("width")); + var height:Null<Int> = exec(el.getAtt("height")); + var size:Int = execAtt(el, "size", 28); + + trace(type, name, label, text, x, y, width, height, size); + + var sprite:FlxSprite = switch(type) { + case "set": + set(el.getAtt("name"), exec(el.getAtt("value"))); + continue; + case "image": + var spr = XMLUtil.createSpriteFromXML(el, "", LOOP); + cast add(spr); + case "exec": + exec(el.innerData); + continue; + case "textbox": + var textBox = new UITextBox(x, y, text, width, height, (el.getAtt("multiline").getDefault("false") == "true")); + add(textBox); + addLabelOn(textBox, label); + textBox; + case "title": + cast add(new UIText(x, y, 0, label, size)); + case "stepper": + // x:Float, y:Float, value:Float = 0, step:Float = 1, precision:Int = 0, ?min:Float, ?max:Float, w:Int = 180, h:Int = 32 + var stepper = new UINumericStepper( + x, + y, + execAtt(el, "value", 0), + execAtt(el, "step", 1), + execAtt(el, "precision", 0), + execAtt(el, "min", null), + execAtt(el, "max", null), + width, + height + ); + add(stepper); + addLabelOn(stepper, label); + stepper; + case "checkbox": + var checkbox = new UICheckbox(x, y, label, execAtt(el, "value", false)); + add(checkbox); + addLabelOn(checkbox, label); + checkbox; + case "slider": + var slider = new UISlider(x, y, width, execAtt(el, "value", 0), execAtt(el, "segments", []), execAtt(el, "centered", false)); + add(slider); + addLabelOn(slider, label); + slider; + case "dropdown": + var options = execString(el.getAtt("options")).split(","); + var curValue = execAtt(el, "value", null); + var index = options.indexOf(curValue); + if (index == -1) index = 0; + var dropdown = new UIDropDown(x, y, width, height, options, index); + add(dropdown); + addLabelOn(dropdown, label); + dropdown; + // UIColorwheel + // UIAudioPlayer + // UIButtonList + // UIFileExplorer + // UIAutoCompleteTextbox + default: { + Logs.trace("Unknown element type: " + type, ERROR, RED); + Logs.trace("Skipping element: " + el.x.toString(), ERROR, RED); + continue; + } + } + + set("last", sprite); + if(name != null) set(name, sprite); + if(sprite is UISprite) elementMap.set(name, cast sprite); + } + + saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight - 20, "Save & Close", function() { + saveData(); + close(); + }, 125); + saveButton.x -= saveButton.bWidth; + saveButton.y -= saveButton.bHeight; + + closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Close", function() { + close(); + }, 125); + closeButton.color = 0xFFFF0000; + closeButton.x -= closeButton.bWidth; + //closeButton.y -= closeButton.bHeight; + add(closeButton); + add(saveButton); + } + + /*function updateIcon(icon:String) { + if (iconSprite == null) add(iconSprite = new FlxSprite()); + + if (iconSprite.animation.exists(icon)) return; + @:privateAccess iconSprite.animation.clearAnimations(); + + var path:String = Paths.image('icons/$icon'); + if (!Assets.exists(path)) path = Paths.image('icons/face'); + + iconSprite.loadGraphic(path, true, 150, 150); + iconSprite.animation.add(icon, [0], 0, false); + iconSprite.antialiasing = true; + iconSprite.animation.play(icon); + + iconSprite.scale.set(0.5, 0.5); + iconSprite.updateHitbox(); + iconSprite.setPosition(iconTextBox.x + 150 + 8, (iconTextBox.y + 16) - (iconSprite.height/2)); + }*/ + + function getElement(name:String):UISprite { + return elementMap.get(name); + } + + function callFunc(name:String, args:Array<Dynamic>) { + if (interp == null) return null; + if (!interp.variables.exists(name)) return null; + + var func = interp.variables.get(name); + if (func != null && Reflect.isFunction(func)) + return Reflect.callMethod(null, func, args); + + return null; + } + + public function saveData() { + for (el in elementMap) { + if(el is UINumericStepper) { + var el:UINumericStepper = cast el; + @:privateAccess el.__onChange(el.label.text); + } + } + + var name = cast(getElement("nameTextBox"), UITextBox).label.text; + var imageFile = cast(getElement("spriteTextBox"), UITextBox).label.text; + + // Save in sprite + sprite.name = name; + sprite.extra.set(StageEditor.exID("imageFile"), imageFile); + + // Save in xml + data.xml.x.set("name", name); + data.xml.x.set("sprite", imageFile); + + callFunc("onSave", []); + + data.updateInfo(sprite); + } +} + +typedef Element = { + var type:ElementType; + var label:String; + var ?name:String; + var ?text:String; +} + +enum abstract ElementType(Int) { + var TITLE = 0; + var TEXTBOX = 1; +} \ No newline at end of file diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index 57dc4e9d..538ae0eb 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -36,6 +36,10 @@ class StageCharacterButton extends StageElementButton { super.updateInfo(charPos); } + public override function getSprite():FunkinSprite { + return char; + } + public override function onSelect() { } @@ -45,8 +49,12 @@ class StageCharacterButton extends StageElementButton { updateInfo(this.charPos); } + public override function getName():String { + return charPos.name; + } + public override function getInfoText():String { - return '${charPos.name} (${charPos.x}, ${charPos.y})'; + return '${getName()} (${charPos.x}, ${charPos.y})'; } public override function updatePos() { diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index a834e653..dc21dcc5 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -90,6 +90,14 @@ class StageElementButton extends UIButton { deleteIcon.x = deleteButton.x + (15/2); deleteIcon.y = deleteButton.y + 8; } + public function getSprite():FunkinSprite { + return null; + } + + public function getName():String { + return "UNKNOWN"; + } + public function onSelect() { // TODO: implement } diff --git a/source/funkin/editors/stage/elements/StageSolidButton.hx b/source/funkin/editors/stage/elements/StageSolidButton.hx index 31eeba1d..698069e8 100644 --- a/source/funkin/editors/stage/elements/StageSolidButton.hx +++ b/source/funkin/editors/stage/elements/StageSolidButton.hx @@ -5,7 +5,7 @@ import flixel.util.FlxColor; class StageSolidButton extends StageSpriteButton { - public function new(x:Float,y:Float, sprite:FlxSprite, xml:Access) { + public function new(x:Float,y:Float, sprite:FunkinSprite, xml:Access) { super(x,y, sprite, xml); color = 0xFFD9FF50; } diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index 425ffd2d..0e509389 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -1,12 +1,13 @@ package funkin.editors.stage.elements; import haxe.xml.Access; +import funkin.editors.stage.StageSpriteEditScreen; import flixel.util.FlxColor; class StageSpriteButton extends StageElementButton { - public var sprite:FlxSprite; + public var sprite:FunkinSprite; - public function new(x:Float,y:Float, sprite:FlxSprite, xml:Access) { + public function new(x:Float,y:Float, sprite:FunkinSprite, xml:Access) { this.sprite = sprite; super(x,y, xml); @@ -20,14 +21,18 @@ class StageSpriteButton extends StageElementButton { } public override function updateInfo(sprite:Dynamic) { - if(sprite is FlxSprite) { - var sprite:FlxSprite = cast sprite; + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; this.sprite = sprite; sprite.visible = !isHidden; } super.updateInfo(sprite); } + public override function getSprite():FunkinSprite { + return sprite; + } + public override function onGhostClick() { isHidden = !isHidden; updateInfo(this.sprite); @@ -35,6 +40,7 @@ class StageSpriteButton extends StageElementButton { public override function onEdit() { // TODO: implement + FlxG.state.openSubState(new StageSpriteEditScreen(this)); } public override function onDelete() { @@ -44,8 +50,12 @@ class StageSpriteButton extends StageElementButton { StageEditor.instance.stageSpritesWindow.remove(this); } + public override function getName():String { + return xml.att.name; + } + public override function getInfoText():String { - return '${xml.att.name} (${sprite.x}, ${sprite.y})'; + return '${getName()} (${sprite.x}, ${sprite.y})'; } public override function updatePos() { diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index db547bfe..b04c8c13 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -32,7 +32,7 @@ class Stage extends FlxBasic implements IBeatReceiver { public var onNodeFinished:(Access, Dynamic)->Void = null; public var onAddSprite:(FlxObject)->Void = null; - private var spritesParentFolder = ""; + public var spritesParentFolder = ""; public inline function getSprite(name:String) { return stageSprites[name]; From b537ca2b95ef3a70fd80006a7b4f39ac36f76fc9 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 14 Apr 2024 17:37:43 +0200 Subject: [PATCH 14/89] Added preview + cleaner dropdown xml --- .../layouts/stage/spriteEditScreen.xml | 75 ++++++++++++++----- source/funkin/backend/FunkinSprite.hx | 9 +++ source/funkin/editors/stage/StageEditor.hx | 2 +- .../editors/stage/StageSpriteEditScreen.hx | 63 ++++++++++------ source/funkin/editors/ui/UIDropDown.hx | 51 +++++++++++-- 5 files changed, 154 insertions(+), 46 deletions(-) diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index 5b10371f..8c1cb089 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -1,42 +1,79 @@ <window width="1056" height="520" title="Editing Sprite"> - <set name="XOFFSET" value="40" /> + <set name="XOFFSET" value="50" /> <set name="YOFFSET" value="40" /> <set name="TO" value="64" /> - <title name="title" x="20" y="30 + 16" label="Sprite Data" /> + <exec> + previewSprite = new FunkinSprite(50, self.winHeight - 100); + previewSprite.frame = sprite.frame; - <textbox name="nameTextBox" label="Name Identifier" text="${data.getName()}" x="20" y="title.y + TO" width="200" height="32" /> - <textbox name="spriteTextBox" label="Image File (${stage.spritesParentFolder})" text="${getEx('imageFile')}" x="last.x + last.bWidth + XOFFSET" y="title.y + TO" width="200" height="32" /> + self.add(previewSprite); + </exec> - <set name="curY" value="nameTextBox.y + nameTextBox.bHeight + YOFFSET" /> + <title name="title" x="20" y="30 + 16" text="Sprite Data" /> + + <set name="curY" value="title.y + TO" /> <!-- ROW 1 --> + + <textbox name="nameTextBox" label="Name Identifier" text="${data.getName()}" x="20" y="curY" width="200" height="32" /> + <textbox name="spriteTextBox" label="Image File (${stage.spritesParentFolder})" text="${getEx('imageFile')}" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" /> + + <set name="curY" value="nameTextBox.y + nameTextBox.bHeight + YOFFSET" /> <!-- ROW 2 --> <stepper name="xStepper" label="X" value="sprite.x" x="20" y="curY" step="1" width="100" /> <stepper name="yStepper" label="Y" value="sprite.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="1" width="100" /> - <stepper name="scrollXStepper" label="Scroll X" value="sprite.scrollFactor.x" x="spriteTextBox.x" y="curY" step="0.01" width="100" /> - <stepper name="scrollYStepper" label="Scroll Y" value="sprite.scrollFactor.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="0.01" width="100" /> + <stepper name="scrollXStepper" label="Scroll X" value="sprite.scrollFactor.x" x="spriteTextBox.x" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="scrollYStepper" label="Scroll Y" value="sprite.scrollFactor.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="scaleXStepper" label="Scale X" value="sprite.scale.x" x="20 + (200 + XOFFSET) * 2" y="curY" step="0.01" width="100" /> - <stepper name="scaleYStepper" label="Scale Y" value="sprite.scale.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="0.01" width="100" /> + <stepper name="scaleXStepper" label="Scale X" value="sprite.scale.x" x="20 + (200 + XOFFSET) * 2" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="scaleYStepper" label="Scale Y" value="sprite.scale.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="skewXStepper" label="Skew X" value="sprite.skew.x" x="20 + (200 + XOFFSET) * 3" y="curY" step="0.01" width="100" /> - <stepper name="skewYStepper" label="Skew Y" value="sprite.skew.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="0.01" width="100" /> + <set name="curY" value="xStepper.y + xStepper.bHeight + YOFFSET" /> <!-- ROW 3 --> - <set name="curY" value="xStepper.y + xStepper.bHeight + YOFFSET" /> + <stepper name="angleStepper" label="Angle" value="sprite.angle" x="20 + (200 + XOFFSET) * 0" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="zoomFactorStepper" label="Zoom Factor" value="sprite.zoomFactor" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="angleStepper" label="Angle" value="sprite.angle" x="20 + (200 + XOFFSET) * 0" y="curY" step="0.01" width="100" /> - <stepper name="zoomFactorStepper" label="Zoom Factor" value="sprite.zoomFactor" x="20 + (200 + XOFFSET) * 1" y="curY" step="0.01" width="100" /> + <stepper name="skewXStepper" label="Skew X" value="sprite.skew.x" x="20 + (200 + XOFFSET) * 2" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="skewYStepper" label="Skew Y" value="sprite.skew.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - <dropdown name="animType" label="Animation Type" value="['NONE','BEAT','LOOP'][sprite.spriteAnimType]" x="20 + (200 + XOFFSET) * 2" y="curY" width="100" height="32" options="NONE,BEAT,LOOP" /> + <!-- TODO: Simplify this --> + <dropdown name="animType" label="Animation Type" value="sprite.spriteAnimType" x="20 + (200 + XOFFSET) * 1" y="curY" width="150" height="32"> + <item label="NONE" value="0" /> + <item label="BEAT" value="1" /> + <item label="LOOP" value="2" /> + </dropdown> + + <!-- ROW 4 --> + <set name="curY" value="angleStepper.y + angleStepper.bHeight + YOFFSET" /> + + <checkbox name="antialiasingCheckbox" text="Antialiasing" value="sprite.antialiasing" x="20 + (200 + XOFFSET) * 0" y="curY" /> + + <!-- TODO: Animation list --> + + + <!-- Preview Transform --> + + <title name="previewTitle" x="20" y="self.winHeight - 150" text="Preview Transform:" size="14" /> <exec> + function onUpdate() { + previewSprite.color = 0xFFFFFFFF; + previewSprite.skew.x = skewXStepper.value; + previewSprite.skew.y = skewYStepper.value; + previewSprite.angle = angleStepper.value; + var ratio = sprite.width / sprite.height; + previewSprite.setGraphicSize(50 * scaleXStepper.value * ratio, 50 * scaleYStepper.value); + previewSprite.updateHitbox(); + } + function onSave() { sprite.x = xStepper.value; sprite.y = yStepper.value; sprite.zoomFactor = zoomFactorStepper.value; - //sprite.antialiasing = antialiasingCheckbox.checked; + sprite.antialiasing = antialiasingCheckbox.checked; //sprite.color = colorWheel.color; - sprite.spriteAnimType = animType.index; + sprite.spriteAnimType = animType.value; + sprite.angle = angleStepper.value; function saveXY(obj:Dynamic, name:String, x:UINumericStepper, y:UINumericStepper) { data.xml.remove(name + ""); @@ -57,7 +94,9 @@ data.xml.set("x", xStepper.value); data.xml.set("y", yStepper.value); data.xml.set("zoom", zoomFactorStepper.value); - data.xml.set("type", ['NONE','BEAT','LOOP'][animType.index]); + data.xml.set("type", animType.key); + data.xml.set("antialiasing", antialiasingCheckbox.checked); + data.xml.set("angle", angleStepper.value); saveXY(sprite.scrollFactor, "scroll", scrollXStepper, scrollYStepper); saveXY(sprite.scale, "scale", scaleXStepper, scaleYStepper); diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx index 3b81598a..40b36a02 100644 --- a/source/funkin/backend/FunkinSprite.hx +++ b/source/funkin/backend/FunkinSprite.hx @@ -29,6 +29,15 @@ enum abstract XMLAnimType(Int) default: def; } } + + @:to public function toString():String { + return switch (cast this) + { + case NONE: "none"; + case BEAT: "beat"; + case LOOP: "loop"; + } + } } class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 86cf70a1..7fe8556b 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -561,7 +561,7 @@ class StageEditor extends UIState { FlxPoint.get(0.5, 0), // center //FlxPoint.get(0.5, 0.5) - ], sprite.camera, sprite.width, sprite.height); + ], sprite.camera, sprite.frameWidth, sprite.frameHeight); //Logs.trace("Guide at " + corners[0].x + ", " + corners[0].y + " sprite at " + sprite.x + ", " + sprite.y); diff --git a/source/funkin/editors/stage/StageSpriteEditScreen.hx b/source/funkin/editors/stage/StageSpriteEditScreen.hx index 3559044d..82ef54c7 100644 --- a/source/funkin/editors/stage/StageSpriteEditScreen.hx +++ b/source/funkin/editors/stage/StageSpriteEditScreen.hx @@ -1,14 +1,16 @@ package funkin.editors.stage; -import funkin.backend.scripting.HScript; -import hscript.Interp; -import haxe.xml.Access; import flixel.math.FlxPoint; import funkin.backend.chart.ChartData.ChartMetaData; +import funkin.backend.scripting.HScript; +import funkin.backend.scripting.Script; import funkin.editors.extra.PropertyButton; import funkin.editors.stage.elements.StageElementButton; +import funkin.editors.ui.UIDropDown; +import haxe.xml.Access; import hscript.*; import hscript.Expr.Error; +import hscript.Interp; import hscript.Parser; using StringTools; @@ -47,7 +49,11 @@ class StageSpriteEditScreen extends UISubstateWindow { sprite = data.getSprite(); + for(k=>e in Script.getDefaultVariables()) { + set(k, e); + } set("stage", StageEditor.instance.stage); + set("self", this); set("sprite", sprite); set("data", data); set("getEx", function(name:String):Dynamic { @@ -84,24 +90,24 @@ class StageSpriteEditScreen extends UISubstateWindow { function addLabelOn(ui:UISprite, text:String) add(new UIText(ui.x, ui.y - 24, 0, text)); - function execString(code:String):String { - if(code.indexOf("${") == -1) return code; + function execString(input:String):String { + if(input.indexOf("${") == -1) return input; var text = ""; - while(code.length > 0) { - var idx = code.indexOf("${"); + while(input.length > 0) { + var idx = input.indexOf("${"); if(idx == -1) { - text += code; + text += input; break; } - text += code.substring(0, idx); - var ei = code.indexOf("}", idx); + text += input.substring(0, idx); + var ei = input.indexOf("}", idx); if(ei == -1) { - text += code.substring(idx); + text += input.substring(idx); break; } - var block = code.substring(idx+2, ei); + var block = input.substring(idx+2, ei); text += exec(block); - code = code.substring(ei + 1); + input = input.substring(ei + 1); } return text; } @@ -117,7 +123,7 @@ class StageSpriteEditScreen extends UISubstateWindow { for(el in layout.elements) { var type = el.name; //var type:String = el.getAtt("type"); - var name:String = el.getAtt("name"); + var name:String = execString(el.getAtt("name")); var label:String = execString(el.getAtt("label")); var text:String = execString(el.getAtt("text")); var x:Float = execAtt(el, "x", 0); @@ -130,21 +136,28 @@ class StageSpriteEditScreen extends UISubstateWindow { var sprite:FlxSprite = switch(type) { case "set": - set(el.getAtt("name"), exec(el.getAtt("value"))); + set(execString(el.getAtt("name")), exec(el.getAtt("value"))); continue; case "image": var spr = XMLUtil.createSpriteFromXML(el, "", LOOP); cast add(spr); + case "solid": + var spr = new FunkinSprite(x, y).makeSolid( + execAtt(el, "width", 100), + execAtt(el, "height", 100), + execAtt(el, "color", 0xFFFFFFFF) + ); + cast add(spr); case "exec": exec(el.innerData); continue; case "textbox": - var textBox = new UITextBox(x, y, text, width, height, (el.getAtt("multiline").getDefault("false") == "true")); + var textBox = new UITextBox(x, y, text, width, height, execAtt(el, "multiline", false));//(el.getAtt("multiline").getDefault("false") == "true")); add(textBox); addLabelOn(textBox, label); textBox; case "title": - cast add(new UIText(x, y, 0, label, size)); + cast add(new UIText(x, y, 0, text, size)); case "stepper": // x:Float, y:Float, value:Float = 0, step:Float = 1, precision:Int = 0, ?min:Float, ?max:Float, w:Int = 180, h:Int = 32 var stepper = new UINumericStepper( @@ -162,7 +175,7 @@ class StageSpriteEditScreen extends UISubstateWindow { addLabelOn(stepper, label); stepper; case "checkbox": - var checkbox = new UICheckbox(x, y, label, execAtt(el, "value", false)); + var checkbox = new UICheckbox(x, y, text, execAtt(el, "value", false)); add(checkbox); addLabelOn(checkbox, label); checkbox; @@ -172,11 +185,14 @@ class StageSpriteEditScreen extends UISubstateWindow { addLabelOn(slider, label); slider; case "dropdown": - var options = execString(el.getAtt("options")).split(","); + var items:Array<DropDownItem> = []; + for(i=>node in el.nodes.item) + items.push({label: execString(node.getAtt("label")), value: execAtt(node, "value", i)}); var curValue = execAtt(el, "value", null); - var index = options.indexOf(curValue); + var index = UIDropDown.indexOfItemValue(items, curValue); if (index == -1) index = 0; - var dropdown = new UIDropDown(x, y, width, height, options, index); + + var dropdown = new UIDropDown(x, y, width, height, items, index); add(dropdown); addLabelOn(dropdown, label); dropdown; @@ -248,6 +264,11 @@ class StageSpriteEditScreen extends UISubstateWindow { return null; } + override function update(elapsed:Float) { + super.update(elapsed); + callFunc("onUpdate", [elapsed]); + } + public function saveData() { for (el in elementMap) { if(el is UINumericStepper) { diff --git a/source/funkin/editors/ui/UIDropDown.hx b/source/funkin/editors/ui/UIDropDown.hx index 1cb944b8..05fd6859 100644 --- a/source/funkin/editors/ui/UIDropDown.hx +++ b/source/funkin/editors/ui/UIDropDown.hx @@ -1,34 +1,68 @@ package funkin.editors.ui; +import flixel.util.typeLimit.OneOfTwo; + class UIDropDown extends UISliceSprite { public var dropButton:UIButton; public var label:UIText; public var index:Int = 0; public var options:Array<String>; + public var items:Array<DropDownItem>; + public var key(get, never):String; + inline function get_key():String { + return items[index].label; + } + public var value(get, never):Dynamic; + inline function get_value():Dynamic { + return items[index].value; + } public var onChange:Int->Void; var curMenu:UIContextMenu = null; - public function new(x:Float, y:Float, width:Int = 320, height:Int = 32, options:Array<String>, index:Int = 0) { + public static function getItems(options:Array<String>):Array<DropDownItem> { + return [for(i=>o in options) {label: o, value: i}]; + } + + public function new(x:Float, y:Float, width:Int = 320, height:Int = 32, _options:Array<OneOfTwo<DropDownItem, String>>, index:Int = 0) { super(x, y, width - height, height, 'editors/ui/inputbox'); // using same sprite cause fuck you - this.options = options; + var _items:Array<DropDownItem> = []; + + if(_options.length > 0) { + if(_options[0] is String) { + _items = getItems(_options); + } else { + _items = cast _options; + } + } + + this.items = _items; + this.options = [for(o in _items) o.label]; // backwards compatibility this.index = index; cursor = BUTTON; - label = new UIText(0, 0, width - height, options[index]); + label = new UIText(0, 0, width - height, items[index].label); members.push(label); dropButton = new UIButton(0, 0, "V", null, height, height); members.push(dropButton); } + public static function indexOfItemValue(items:Array<DropDownItem>, value:Dynamic):Int { + return [for(o in items) o.value].indexOf(value); + } + + public static function indexOfItemLabel(items:Array<DropDownItem>, str:String):Int { + return [for(o in items) o.label].indexOf(str); + } + public function setOption(newIndex:Int) { if (index != (index = newIndex)) { - label.text = options[index]; + label.text = items[index].label; if (onChange != null) onChange(index); } @@ -53,12 +87,17 @@ class UIDropDown extends UISliceSprite { public function openContextMenu() { var screenPos = getScreenPosition(null, __lastDrawCameras[0] == null ? FlxG.camera : __lastDrawCameras[0]); curMenu = UIState.state.openContextMenu([ - for(k=>o in options) { + for(k=>o in items) { icon: (k == index) ? 1 : 0, - label: o + label: o.label } ], function(_, i, _) { setOption(i); }, __lastDrawCameras[0].x + screenPos.x, __lastDrawCameras[0].y + screenPos.y + bHeight); } +} + +typedef DropDownItem = { + var label:String; + var value:Dynamic; } \ No newline at end of file From 4db00ad4fa388280ee48703a0e760bde15555913 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 14 Apr 2024 18:04:33 +0200 Subject: [PATCH 15/89] Small Changes --- assets/editors/layouts/stage/spriteEditScreen.xml | 5 +++++ source/funkin/editors/stage/StageEditor.hx | 4 ++-- source/funkin/editors/stage/StageSelection.hx | 2 +- source/funkin/editors/stage/StageSpriteEditScreen.hx | 11 ----------- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index 8c1cb089..a639fb84 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -67,6 +67,9 @@ } function onSave() { + sprite.name = nameTextBox.label.text; + sprite.extra.set(StageEditor.exID("imageFile"), spriteTextBox.label.text); + sprite.x = xStepper.value; sprite.y = yStepper.value; sprite.zoomFactor = zoomFactorStepper.value; @@ -91,6 +94,8 @@ } } + data.xml.set("name", nameTextBox.label.text); + data.xml.set("sprite", spriteTextBox.label.text); data.xml.set("x", xStepper.value); data.xml.set("y", yStepper.value); data.xml.set("zoom", zoomFactorStepper.value); diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 7fe8556b..c542aa7e 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -233,7 +233,7 @@ class StageEditor extends UIState { add(stageSprites); for(spr in order) { - + } setZoom(stage.defaultZoom); @@ -276,7 +276,7 @@ class StageEditor extends UIState { Framerate.codenameBuildField.alpha = 0.4; } - DiscordUtil.call("onEditorLoaded", ["Stage Editor", __stage]); + //DiscordUtil.call("onEditorLoaded", ["Stage Editor", __stage]); } override function destroy() { diff --git a/source/funkin/editors/stage/StageSelection.hx b/source/funkin/editors/stage/StageSelection.hx index 6fa49597..0ccd36a6 100644 --- a/source/funkin/editors/stage/StageSelection.hx +++ b/source/funkin/editors/stage/StageSelection.hx @@ -35,7 +35,7 @@ class StageSelection extends EditorTreeMenu main = new OptionsScreen("Stage Editor", "Select a stage to edit. HSCRIPT only stages are not supported.", list); - DiscordUtil.call("onEditorTreeLoaded", ["Stage Editor"]); + //DiscordUtil.call("onEditorTreeLoaded", ["Stage Editor"]); } public function saveStage(creation:StageCreationData) { diff --git a/source/funkin/editors/stage/StageSpriteEditScreen.hx b/source/funkin/editors/stage/StageSpriteEditScreen.hx index 82ef54c7..0537ddcb 100644 --- a/source/funkin/editors/stage/StageSpriteEditScreen.hx +++ b/source/funkin/editors/stage/StageSpriteEditScreen.hx @@ -277,17 +277,6 @@ class StageSpriteEditScreen extends UISubstateWindow { } } - var name = cast(getElement("nameTextBox"), UITextBox).label.text; - var imageFile = cast(getElement("spriteTextBox"), UITextBox).label.text; - - // Save in sprite - sprite.name = name; - sprite.extra.set(StageEditor.exID("imageFile"), imageFile); - - // Save in xml - data.xml.x.set("name", name); - data.xml.x.set("sprite", imageFile); - callFunc("onSave", []); data.updateInfo(sprite); From 145946c6f670f19693e9fd243757114092e78bf1 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 14 Apr 2024 18:09:16 +0200 Subject: [PATCH 16/89] oop --- source/funkin/editors/stage/StageSpriteEditScreen.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/source/funkin/editors/stage/StageSpriteEditScreen.hx b/source/funkin/editors/stage/StageSpriteEditScreen.hx index 0537ddcb..487ec2aa 100644 --- a/source/funkin/editors/stage/StageSpriteEditScreen.hx +++ b/source/funkin/editors/stage/StageSpriteEditScreen.hx @@ -56,6 +56,7 @@ class StageSpriteEditScreen extends UISubstateWindow { set("self", this); set("sprite", sprite); set("data", data); + set("exID", StageEditor.exID); set("getEx", function(name:String):Dynamic { return sprite.extra.get(StageEditor.exID(name)); }); From 781295acb8b455737aef56ca1eddc6f1754ca116 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 14 Apr 2024 18:35:40 +0200 Subject: [PATCH 17/89] Cleaned up code --- .../layouts/stage/spriteEditScreen.xml | 2 +- source/funkin/editors/stage/StageEditor.hx | 2 +- .../editors/stage/StageSpriteEditScreen.hx | 292 +----------------- source/funkin/editors/ui/UISoftcodedWindow.hx | 264 ++++++++++++++++ 4 files changed, 281 insertions(+), 279 deletions(-) create mode 100644 source/funkin/editors/ui/UISoftcodedWindow.hx diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index a639fb84..170fa5a5 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -68,7 +68,7 @@ function onSave() { sprite.name = nameTextBox.label.text; - sprite.extra.set(StageEditor.exID("imageFile"), spriteTextBox.label.text); + sprite.extra.set(exID("imageFile"), spriteTextBox.label.text); sprite.x = xStepper.value; sprite.y = yStepper.value; diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index c542aa7e..83419c9c 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -382,7 +382,7 @@ class StageEditor extends UIState { if (charXML.exists("scale") && character.scale.x == 1) charXML.remove("scale"); if (charXML.exists("antialiasing") && character.antialiasing) charXML.remove("antialiasing");*/ - return "<!DOCTYPE codename-engine-character>\n";// + Printer.print(charXML, true); + return "<!DOCTYPE codename-engine-stage>\n";// + Printer.print(charXML, true); } /*function _edit_undo(_) { diff --git a/source/funkin/editors/stage/StageSpriteEditScreen.hx b/source/funkin/editors/stage/StageSpriteEditScreen.hx index 487ec2aa..b220c6df 100644 --- a/source/funkin/editors/stage/StageSpriteEditScreen.hx +++ b/source/funkin/editors/stage/StageSpriteEditScreen.hx @@ -1,297 +1,35 @@ package funkin.editors.stage; -import flixel.math.FlxPoint; -import funkin.backend.chart.ChartData.ChartMetaData; -import funkin.backend.scripting.HScript; -import funkin.backend.scripting.Script; -import funkin.editors.extra.PropertyButton; import funkin.editors.stage.elements.StageElementButton; -import funkin.editors.ui.UIDropDown; -import haxe.xml.Access; -import hscript.*; -import hscript.Expr.Error; -import hscript.Interp; -import hscript.Parser; +import funkin.editors.ui.UISoftcodedWindow; using StringTools; -class StageSpriteEditScreen extends UISubstateWindow { + +class StageSpriteEditScreen extends UISoftcodedWindow { public var data:StageElementButton; public var sprite:FunkinSprite; - public var saveButton:UIButton; - public var closeButton:UIButton; - - var elementMap:Map<String, UISprite> = []; - - public function new(data:StageElementButton) { - super(); this.data = data; - } - - var parser = HScript.initParser(); - var interp = new Interp(); - - function set(name:String, value:Dynamic) { - interp.variables.set(name, value); - } - - function get(name:String):Dynamic { - return interp.variables.get(name); + this.sprite = data.getSprite(); + super("layouts/stage/spriteEditScreen.xml", [ + "stage" => StageEditor.instance.stage, + "sprite" => sprite, + "data" => data, + "exID" => StageEditor.exID, + "getEx" => function(name:String):Dynamic { + return sprite.extra.get(StageEditor.exID(name)); + } + ]); } public override function create() { - var layout = new Access(Xml.parse(Assets.getText('assets/editors/layouts/stage/spriteEditScreen.xml')).firstElement()); - winTitle = layout.getAtt("title").getDefault(winTitle); - winWidth = Std.parseInt(layout.getAtt("width")).getDefault(winWidth); - winHeight = Std.parseInt(layout.getAtt("height")).getDefault(winHeight); - - sprite = data.getSprite(); - - for(k=>e in Script.getDefaultVariables()) { - set(k, e); - } - set("stage", StageEditor.instance.stage); - set("self", this); - set("sprite", sprite); - set("data", data); - set("exID", StageEditor.exID); - set("getEx", function(name:String):Dynamic { - return sprite.extra.get(StageEditor.exID(name)); - }); - set("last", null); - - function _errorHandler(error:Error) { - var fileName = error.origin; - var fn = '$fileName:${error.line}: '; - var err = error.toString(); - if (err.startsWith(fn)) err = err.substr(fn.length); - - Logs.traceColored([ - Logs.logText(fn, GREEN), - Logs.logText(err, RED) - ], ERROR); - } - - function exec(code:String):Dynamic { - try { - if (code != null && code.trim() != "") - return interp.execute(parser.parseString(code, "spriteEditScreen.xml")); - } catch(e:Error) { - _errorHandler(e); - } catch(e) { - _errorHandler(new Error(ECustom(e.toString()), 0, 0, "spriteEditScreen.xml", 0)); - } - return null; - } - super.create(); - - function addLabelOn(ui:UISprite, text:String) - add(new UIText(ui.x, ui.y - 24, 0, text)); - - function execString(input:String):String { - if(input.indexOf("${") == -1) return input; - var text = ""; - while(input.length > 0) { - var idx = input.indexOf("${"); - if(idx == -1) { - text += input; - break; - } - text += input.substring(0, idx); - var ei = input.indexOf("}", idx); - if(ei == -1) { - text += input.substring(idx); - break; - } - var block = input.substring(idx+2, ei); - text += exec(block); - input = input.substring(ei + 1); - } - return text; - } - - function execDefault(code:String, defaultValue:Dynamic):Dynamic { - return CoolUtil.getDefault(exec(code), defaultValue); - } - - function execAtt(el:Access, key:String, defaultValue:Dynamic):Dynamic { - return execDefault(el.getAtt(key), defaultValue); - } - - for(el in layout.elements) { - var type = el.name; - //var type:String = el.getAtt("type"); - var name:String = execString(el.getAtt("name")); - var label:String = execString(el.getAtt("label")); - var text:String = execString(el.getAtt("text")); - var x:Float = execAtt(el, "x", 0); - var y:Float = execAtt(el, "y", 0); - var width:Null<Int> = exec(el.getAtt("width")); - var height:Null<Int> = exec(el.getAtt("height")); - var size:Int = execAtt(el, "size", 28); - - trace(type, name, label, text, x, y, width, height, size); - - var sprite:FlxSprite = switch(type) { - case "set": - set(execString(el.getAtt("name")), exec(el.getAtt("value"))); - continue; - case "image": - var spr = XMLUtil.createSpriteFromXML(el, "", LOOP); - cast add(spr); - case "solid": - var spr = new FunkinSprite(x, y).makeSolid( - execAtt(el, "width", 100), - execAtt(el, "height", 100), - execAtt(el, "color", 0xFFFFFFFF) - ); - cast add(spr); - case "exec": - exec(el.innerData); - continue; - case "textbox": - var textBox = new UITextBox(x, y, text, width, height, execAtt(el, "multiline", false));//(el.getAtt("multiline").getDefault("false") == "true")); - add(textBox); - addLabelOn(textBox, label); - textBox; - case "title": - cast add(new UIText(x, y, 0, text, size)); - case "stepper": - // x:Float, y:Float, value:Float = 0, step:Float = 1, precision:Int = 0, ?min:Float, ?max:Float, w:Int = 180, h:Int = 32 - var stepper = new UINumericStepper( - x, - y, - execAtt(el, "value", 0), - execAtt(el, "step", 1), - execAtt(el, "precision", 0), - execAtt(el, "min", null), - execAtt(el, "max", null), - width, - height - ); - add(stepper); - addLabelOn(stepper, label); - stepper; - case "checkbox": - var checkbox = new UICheckbox(x, y, text, execAtt(el, "value", false)); - add(checkbox); - addLabelOn(checkbox, label); - checkbox; - case "slider": - var slider = new UISlider(x, y, width, execAtt(el, "value", 0), execAtt(el, "segments", []), execAtt(el, "centered", false)); - add(slider); - addLabelOn(slider, label); - slider; - case "dropdown": - var items:Array<DropDownItem> = []; - for(i=>node in el.nodes.item) - items.push({label: execString(node.getAtt("label")), value: execAtt(node, "value", i)}); - var curValue = execAtt(el, "value", null); - var index = UIDropDown.indexOfItemValue(items, curValue); - if (index == -1) index = 0; - - var dropdown = new UIDropDown(x, y, width, height, items, index); - add(dropdown); - addLabelOn(dropdown, label); - dropdown; - // UIColorwheel - // UIAudioPlayer - // UIButtonList - // UIFileExplorer - // UIAutoCompleteTextbox - default: { - Logs.trace("Unknown element type: " + type, ERROR, RED); - Logs.trace("Skipping element: " + el.x.toString(), ERROR, RED); - continue; - } - } - - set("last", sprite); - if(name != null) set(name, sprite); - if(sprite is UISprite) elementMap.set(name, cast sprite); - } - - saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight - 20, "Save & Close", function() { - saveData(); - close(); - }, 125); - saveButton.x -= saveButton.bWidth; - saveButton.y -= saveButton.bHeight; - - closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Close", function() { - close(); - }, 125); - closeButton.color = 0xFFFF0000; - closeButton.x -= closeButton.bWidth; - //closeButton.y -= closeButton.bHeight; - add(closeButton); - add(saveButton); } - /*function updateIcon(icon:String) { - if (iconSprite == null) add(iconSprite = new FlxSprite()); - - if (iconSprite.animation.exists(icon)) return; - @:privateAccess iconSprite.animation.clearAnimations(); - - var path:String = Paths.image('icons/$icon'); - if (!Assets.exists(path)) path = Paths.image('icons/face'); - - iconSprite.loadGraphic(path, true, 150, 150); - iconSprite.animation.add(icon, [0], 0, false); - iconSprite.antialiasing = true; - iconSprite.animation.play(icon); - - iconSprite.scale.set(0.5, 0.5); - iconSprite.updateHitbox(); - iconSprite.setPosition(iconTextBox.x + 150 + 8, (iconTextBox.y + 16) - (iconSprite.height/2)); - }*/ - - function getElement(name:String):UISprite { - return elementMap.get(name); - } - - function callFunc(name:String, args:Array<Dynamic>) { - if (interp == null) return null; - if (!interp.variables.exists(name)) return null; - - var func = interp.variables.get(name); - if (func != null && Reflect.isFunction(func)) - return Reflect.callMethod(null, func, args); - - return null; - } - - override function update(elapsed:Float) { - super.update(elapsed); - callFunc("onUpdate", [elapsed]); - } - - public function saveData() { - for (el in elementMap) { - if(el is UINumericStepper) { - var el:UINumericStepper = cast el; - @:privateAccess el.__onChange(el.label.text); - } - } - - callFunc("onSave", []); - + public override function saveData() { + super.saveData(); data.updateInfo(sprite); } -} - -typedef Element = { - var type:ElementType; - var label:String; - var ?name:String; - var ?text:String; -} - -enum abstract ElementType(Int) { - var TITLE = 0; - var TEXTBOX = 1; } \ No newline at end of file diff --git a/source/funkin/editors/ui/UISoftcodedWindow.hx b/source/funkin/editors/ui/UISoftcodedWindow.hx new file mode 100644 index 00000000..49947b8d --- /dev/null +++ b/source/funkin/editors/ui/UISoftcodedWindow.hx @@ -0,0 +1,264 @@ +package funkin.editors.ui; + +import flixel.math.FlxPoint; +import funkin.backend.chart.ChartData.ChartMetaData; +import funkin.backend.scripting.HScript; +import funkin.backend.scripting.Script; +import funkin.editors.extra.PropertyButton; +import funkin.editors.stage.elements.StageElementButton; +import funkin.editors.ui.UIDropDown; +import haxe.xml.Access; +import hscript.*; +import hscript.Expr.Error; +import hscript.Interp; +import hscript.Parser; +import haxe.io.Path; + +using StringTools; + +class UISoftcodedWindow extends UISubstateWindow { + public var saveButton:UIButton; + public var closeButton:UIButton; + + var elementMap:Map<String, UISprite> = []; + + var xmlPath:String; + var filename:String; + var customVariables:Map<String, Dynamic>; + + public function new(xmlPath:String, customVariables:Map<String, Dynamic> = null) { + super(); + this.xmlPath = xmlPath; + this.filename = Path.withoutDirectory(xmlPath); + this.customVariables = customVariables; + } + + var parser = HScript.initParser(); + var interp = new Interp(); + + function set(name:String, value:Dynamic) { + interp.variables.set(name, value); + } + + function get(name:String):Dynamic { + return interp.variables.get(name); + } + + function execString(input:String):String { + if(input.indexOf("${") == -1) return input; + var text = ""; + while(input.length > 0) { + var idx = input.indexOf("${"); + if(idx == -1) { + text += input; + break; + } + text += input.substring(0, idx); + var ei = input.indexOf("}", idx); + if(ei == -1) { + text += input.substring(idx); + break; + } + var block = input.substring(idx+2, ei); + text += exec(block); + input = input.substring(ei + 1); + } + return text; + } + + function execDefault(code:String, defaultValue:Dynamic):Dynamic { + return CoolUtil.getDefault(exec(code), defaultValue); + } + + function execAtt(el:Access, key:String, defaultValue:Dynamic):Dynamic { + return execDefault(el.getAtt(key), defaultValue); + } + + function exec(code:String):Dynamic { + try { + if (code != null && code.trim() != "") + return interp.execute(parser.parseString(code, filename)); + } catch(e:Error) { + _errorHandler(e); + } catch(e) { + _errorHandler(new Error(ECustom(e.toString()), 0, 0, filename, 0)); + } + return null; + } + + function _errorHandler(error:Error) { + var fileName = error.origin; + var fn = '$fileName:${error.line}: '; + var err = error.toString(); + if (err.startsWith(fn)) err = err.substr(fn.length); + + Logs.traceColored([ + Logs.logText(fn, GREEN), + Logs.logText(err, RED) + ], ERROR); + } + + public override function create() { + var layout = new Access(Xml.parse(Assets.getText('assets/editors/' + xmlPath)).firstElement()); + winTitle = layout.getAtt("title").getDefault(winTitle); + winWidth = Std.parseInt(layout.getAtt("width")).getDefault(winWidth); + winHeight = Std.parseInt(layout.getAtt("height")).getDefault(winHeight); + + for(k=>e in Script.getDefaultVariables()) { + set(k, e); + } + set("self", this); + set("hasSaveButtons", true); + for(k=>v in customVariables) { + set(k, v); + } + set("last", null); + + super.create(); + + function addLabelOn(ui:UISprite, text:String) + add(new UIText(ui.x, ui.y - 24, 0, text)); + + for(el in layout.elements) { + var type = el.name; + //var type:String = el.getAtt("type"); + var name:String = execString(el.getAtt("name")); + var label:String = execString(el.getAtt("label")); + var text:String = execString(el.getAtt("text")); + var x:Float = execAtt(el, "x", 0); + var y:Float = execAtt(el, "y", 0); + var width:Null<Int> = exec(el.getAtt("width")); + var height:Null<Int> = exec(el.getAtt("height")); + var size:Int = execAtt(el, "size", 28); + + trace(type, name, label, text, x, y, width, height, size); + + var sprite:FlxSprite = switch(type) { + case "set": + set(execString(el.getAtt("name")), exec(el.getAtt("value"))); + continue; + case "image": + var spr = XMLUtil.createSpriteFromXML(el, "", LOOP); + cast add(spr); + case "solid": + var spr = new FunkinSprite(x, y).makeSolid( + execAtt(el, "width", 100), + execAtt(el, "height", 100), + execAtt(el, "color", 0xFFFFFFFF) + ); + cast add(spr); + case "exec": + exec(el.innerData); + continue; + case "textbox": + var textBox = new UITextBox(x, y, text, width, height, execAtt(el, "multiline", false));//(el.getAtt("multiline").getDefault("false") == "true")); + add(textBox); + addLabelOn(textBox, label); + textBox; + case "title": + cast add(new UIText(x, y, 0, text, size)); + case "stepper": + // x:Float, y:Float, value:Float = 0, step:Float = 1, precision:Int = 0, ?min:Float, ?max:Float, w:Int = 180, h:Int = 32 + var stepper = new UINumericStepper( + x, + y, + execAtt(el, "value", 0), + execAtt(el, "step", 1), + execAtt(el, "precision", 0), + execAtt(el, "min", null), + execAtt(el, "max", null), + width, + height + ); + add(stepper); + addLabelOn(stepper, label); + stepper; + case "checkbox": + var checkbox = new UICheckbox(x, y, text, execAtt(el, "value", false)); + add(checkbox); + addLabelOn(checkbox, label); + checkbox; + case "slider": + var slider = new UISlider(x, y, width, execAtt(el, "value", 0), execAtt(el, "segments", []), execAtt(el, "centered", false)); + add(slider); + addLabelOn(slider, label); + slider; + case "dropdown": + var items:Array<DropDownItem> = []; + for(i=>node in el.nodes.item) + items.push({label: execString(node.getAtt("label")), value: execAtt(node, "value", i)}); + var curValue = execAtt(el, "value", null); + var index = UIDropDown.indexOfItemValue(items, curValue); + if (index == -1) index = 0; + + var dropdown = new UIDropDown(x, y, width, height, items, index); + add(dropdown); + addLabelOn(dropdown, label); + dropdown; + // UIColorwheel + // UIAudioPlayer + // UIButtonList + // UIFileExplorer + // UIAutoCompleteTextbox + default: { + Logs.trace("Unknown element type: " + type, ERROR, RED); + Logs.trace("Skipping element: " + el.x.toString(), ERROR, RED); + continue; + } + } + + set("last", sprite); + if(name != null) set(name, sprite); + if(sprite is UISprite) elementMap.set(name, cast sprite); + } + + if(get("hasSaveButtons")) { + saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight - 20, "Save & Close", function() { + saveData(); + close(); + }, 125); + saveButton.x -= saveButton.bWidth; + saveButton.y -= saveButton.bHeight; + + closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Close", function() { + close(); + }, 125); + closeButton.color = 0xFFFF0000; + closeButton.x -= closeButton.bWidth; + //closeButton.y -= closeButton.bHeight; + add(closeButton); + add(saveButton); + } + } + + function getElement(name:String):UISprite { + return elementMap.get(name); + } + + function callFunc(name:String, args:Array<Dynamic>) { + if (interp == null) return null; + if (!interp.variables.exists(name)) return null; + + var func = interp.variables.get(name); + if (func != null && Reflect.isFunction(func)) + return Reflect.callMethod(null, func, args); + + return null; + } + + override function update(elapsed:Float) { + super.update(elapsed); + callFunc("onUpdate", [elapsed]); + } + + public function saveData() { + for (el in elementMap) { + if(el is UINumericStepper) { + var el:UINumericStepper = cast el; + @:privateAccess el.__onChange(el.label.text); + } + } + + callFunc("onSave", []); + } +} \ No newline at end of file From 997e53e9f5df7d856238db85e171772a74913ee2 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 14 Apr 2024 18:40:40 +0200 Subject: [PATCH 18/89] Fix Crash when deleting sprites --- source/funkin/editors/stage/elements/StageSpriteButton.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index 0e509389..0c759e06 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -46,6 +46,7 @@ class StageSpriteButton extends StageElementButton { public override function onDelete() { sprite.destroy(); xml.x.parent.removeChild(xml.x); + StageEditor.instance.stage.stageSprites.remove(sprite.name); StageEditor.instance.xmlMap.remove(sprite); StageEditor.instance.stageSpritesWindow.remove(this); } From 6a758604634e7b294d50fb7bd06b63c4bdf8775c Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 14 Apr 2024 19:55:26 +0200 Subject: [PATCH 19/89] Added selecting sprites --- source/funkin/editors/stage/StageEditor.hx | 100 +++++++++++++++++- .../stage/elements/StageElementButton.hx | 22 ++++ .../stage/elements/StageSpriteButton.hx | 4 + 3 files changed, 124 insertions(+), 2 deletions(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 83419c9c..d8b9cd31 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -2,7 +2,9 @@ package funkin.editors.stage; import flixel.math.FlxAngle; import flixel.math.FlxPoint; +import flixel.math.FlxRect; import flixel.util.FlxColor; +import flixel.util.FlxSort; import funkin.backend.system.framerate.Framerate; import funkin.backend.utils.XMLUtil.AnimData; import funkin.editors.stage.elements.*; @@ -18,6 +20,8 @@ class StageEditor extends UIState { static var __stage:String; public var stage:Stage; + private var _point:FlxPoint = new FlxPoint(); + public static var instance(get, null):StageEditor; private static inline function get_instance() @@ -255,7 +259,9 @@ class StageEditor extends UIState { if(xml != null) { if(sprite is FunkinSprite) { var type = sprite.extra.get(exID("type")); - stageSpritesWindow.add((type == "box" || type == "solid") ? new StageSolidButton(0,0, sprite, xml) : new StageSpriteButton(0,0, sprite, xml)); + var button:StageElementButton = (type == "box" || type == "solid") ? new StageSolidButton(0,0, sprite, xml) : new StageSpriteButton(0,0, sprite, xml); + sprite.extra.set(exID("button"), button); + stageSpritesWindow.add(button); } else if(sprite is StageCharPos) { var char = charMap[sprite.name]; @@ -311,6 +317,59 @@ class StageEditor extends UIState { updateZoom(); } + /*if(FlxG.mouse.justPressed) { + var bounds:Array<FlxRect> = []; + var sprites = stageSpritesWindow.buttons.members.map((o) -> o.getSprite()).filter((o) -> o != null && o.animateAtlas == null); + for(sprite in sprites) { + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + if(sprite.extra.exists(exID("bounds"))) { + bounds.push(cast(sprite.extra.get(exID("bounds")), FlxRect)); + } + } + } + + // sort by area + bounds.sort((a, b) -> FlxSort.byValues(FlxSort.ASCENDING, a.width * a.height, b.width * b.height)); + + Logs.trace("------------------------"); + for(bounds in bounds) { + Logs.trace(bounds.width + "x" + bounds.height); + } + }*/ + + /*if(FlxG.mouse.justPressed) { + //var sprites = Lambda.array(stage.stageSprites); + var sprites = stageSpritesWindow.buttons.members.map((o) -> o.getSprite()).filter((o) -> o != null && o.animateAtlas == null); + trace(sprites.map((o) -> cast(o, FunkinSprite).name)); + var length = sprites.length; + // Reset selected sprites + for(i in 0...length) { + var sprite = sprites[i]; + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + sprite.extra.set(exID("selected"), false); + } + } + for(i in 0...length) { + var idx = length - i - 1; + var sprite = sprites[idx]; + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + if(!sprite.extra.exists(exID("bounds"))) continue; + trace(idx, sprite.name); + var bounds = cast(sprite.extra.get(exID("bounds")), FlxRect); + var pos = FlxG.mouse.getWorldPosition(stageCamera, _point); + trace(sprite.name, bounds, pos); + if(bounds.containsPoint(pos)) { + sprite.extra.set(exID("selected"), true); + trace("Selected " + sprite.name); + break; + } + } + } + }*/ + //if (FlxG.mouse.justReleasedRight) { // closeCurrentContextMenu(); // openContextMenu(topMenu[2].childs); @@ -334,6 +393,22 @@ class StageEditor extends UIState { SaveWarning.showWarning = undos.unsaved; } + public function selectSprite(_sprite:FunkinSprite) { + var sprites = stageSpritesWindow.buttons.members.map((o) -> o.getSprite()).filter((o) -> o != null);// && o.animateAtlas == null); + for(sprite in sprites) { + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + sprite.extra.set(exID("selected"), false); + sprite.extra.get(exID("button")).selected = false; + } + } + if(_sprite is FunkinSprite) { + var sprite:FunkinSprite = cast _sprite; + sprite.extra.set(exID("selected"), true); + sprite.extra.get(exID("button")).selected = true; + } + } + // TOP MENU OPTIONS #if REGION function _file_exit(_) { @@ -519,7 +594,7 @@ class StageEditor extends UIState { if(!showOutlines) return; if(dot == null) { - dot = new FlxSprite().makeGraphic(10, 10, FlxColor.RED); + dot = new FlxSprite().makeGraphic(10, 10, FlxColor.WHITE); dot.camera = stageCamera; dot.forceIsOnScreen = true; } @@ -565,6 +640,27 @@ class StageEditor extends UIState { //Logs.trace("Guide at " + corners[0].x + ", " + corners[0].y + " sprite at " + sprite.x + ", " + sprite.y); + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + var maxX = Math.max(Math.max(corners[0].x, corners[1].x), Math.max(corners[2].x, corners[3].x)); + var maxY = Math.max(Math.max(corners[0].y, corners[1].y), Math.max(corners[2].y, corners[3].y)); + var minX = Math.min(Math.min(corners[0].x, corners[1].x), Math.min(corners[2].x, corners[3].x)); + var minY = Math.min(Math.min(corners[0].y, corners[1].y), Math.min(corners[2].y, corners[3].y)); + + if(!sprite.extra.exists(exID("bounds"))) { + sprite.extra.set(exID("bounds"), new FlxRect()); + } + cast(sprite.extra.get(exID("bounds")), FlxRect).set(minX, minY, maxX - minX, maxY - minY); + } + + dot.color = FlxColor.RED; + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + if(sprite.extra.get(exID("selected")) == true) { + dot.color = FlxColor.GREEN; + } + } + for(corner in corners) { drawDot(corner.x, corner.y); corner.put(); diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index dc21dcc5..c2df186a 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -3,6 +3,8 @@ package funkin.editors.stage.elements; import haxe.xml.Access; import flixel.util.FlxColor; +using flixel.util.FlxColorTransformUtil; + class StageElementButton extends UIButton { public var xml:Access; @@ -17,6 +19,8 @@ class StageElementButton extends UIButton { public var isHidden:Bool = false; + public var selected:Bool = false; + public function new(x:Float,y:Float, xml:Access) { this.xml = xml; super(x,y, getInfoText(), function () { @@ -64,6 +68,8 @@ class StageElementButton extends UIButton { members.push(deleteIcon); } + var _lastSelected:Bool = false; + public override function update(elapsed:Float) { editButton.selectable = ghostButton.selectable = deleteButton.selectable = selectable; editButton.shouldPress = ghostButton.shouldPress = deleteButton.shouldPress = shouldPress; @@ -71,6 +77,22 @@ class StageElementButton extends UIButton { hovered = !deleteButton.hovered; updatePos(); super.update(elapsed); + + if(selected != _lastSelected) { + _lastSelected = selected; + updateColorTransform(); + } + } + + public override function updateColorTransform() { + super.updateColorTransform(); + + if (selected) { + useColorTransform = true; + colorTransform.setOffsets(70, 70, 70, 0); + } else { + colorTransform.setOffsets(0, 0, 0, 0); + } } public function updateInfo(sprite:Dynamic) { diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index 0c759e06..96a9981e 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -33,6 +33,10 @@ class StageSpriteButton extends StageElementButton { return sprite; } + public override function onSelect() { + StageEditor.instance.selectSprite(sprite); + } + public override function onGhostClick() { isHidden = !isHidden; updateInfo(this.sprite); From 5aca072fc6db034ac3d2b54792587a42c625113a Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 14 Apr 2024 20:03:37 +0200 Subject: [PATCH 20/89] Fixed antialiasing in preview --- assets/editors/layouts/stage/spriteEditScreen.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index 170fa5a5..d84b8500 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -61,6 +61,7 @@ previewSprite.skew.x = skewXStepper.value; previewSprite.skew.y = skewYStepper.value; previewSprite.angle = angleStepper.value; + previewSprite.antialiasing = antialiasingCheckbox.checked; var ratio = sprite.width / sprite.height; previewSprite.setGraphicSize(50 * scaleXStepper.value * ratio, 50 * scaleYStepper.value); previewSprite.updateHitbox(); From 8eea36b297be27641a27c92ed29113622d62f922 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Mon, 15 Apr 2024 00:25:31 +0200 Subject: [PATCH 21/89] Added `cne run` --- commandline/Main.hx | 11 +++++++++++ commandline/commands/Compiler.hx | 14 +++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/commandline/Main.hx b/commandline/Main.hx index 8c2f9301..9d5ed778 100644 --- a/commandline/Main.hx +++ b/commandline/Main.hx @@ -70,6 +70,17 @@ class Main { "-debug : Builds a debug build." ].join("\n") }, + { + names: ["run"], + doc: "Runs the last build that was created.", + func: Compiler.run, + dDoc: [ + "Usage: run <optional arguments>", + "", + "This will run the last build that was created.", + "Additional arguments will be sent to the lime compiler." + ].join("\n") + }, { names: ["release"], doc: "Creates a final non debug build, containing all assets.", diff --git a/commandline/commands/Compiler.hx b/commandline/commands/Compiler.hx index 6d09f5aa..08c39f24 100644 --- a/commandline/commands/Compiler.hx +++ b/commandline/commands/Compiler.hx @@ -2,19 +2,23 @@ package commands; class Compiler { public static function test(args:Array<String>) { - __build(args, ["test", getBuildTarget(), "-DTEST_BUILD"]); + __runLime(args, ["test", getBuildTarget(), "-DTEST_BUILD"]); } public static function build(args:Array<String>) { - __build(args, ["build", getBuildTarget(), "-DTEST_BUILD"]); + __runLime(args, ["build", getBuildTarget(), "-DTEST_BUILD"]); } public static function release(args:Array<String>) { - __build(args, ["build", getBuildTarget()]); + __runLime(args, ["build", getBuildTarget()]); } public static function testRelease(args:Array<String>) { - __build(args, ["test", getBuildTarget()]); + __runLime(args, ["test", getBuildTarget()]); } - private static function __build(args:Array<String>, arg:Array<String>) { + public static function run(args:Array<String>) { + __runLime(args, ["run", getBuildTarget()]); + } + + private static function __runLime(args:Array<String>, arg:Array<String>) { for(a in args) arg.push(a); Sys.command("lime", arg); From 4285307d70290315fbea46438aef5b368815823b Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Sun, 14 Apr 2024 15:39:14 -0700 Subject: [PATCH 22/89] some liveshare tomfoolery got scale points working with huge help from ne_eo Co-authored-by: Ne_Eo <NeeEoo@users.noreply.github.com> --- assets/data/stages/test.xml | 36 ++ assets/data/states/StageEditor.hx | 133 +++++++ source/funkin/backend/utils/CoolUtil.hx | 15 + source/funkin/editors/stage/StageEditor.hx | 340 ++++++++++-------- .../stage/elements/StageCharacterButton.hx | 4 +- .../stage/elements/StageElementButton.hx | 9 +- .../stage/elements/StageSpriteButton.hx | 4 +- source/funkin/editors/ui/UISliceSprite.hx | 18 + source/funkin/game/Stage.hx | 1 + 9 files changed, 414 insertions(+), 146 deletions(-) create mode 100644 assets/data/stages/test.xml create mode 100644 assets/data/states/StageEditor.hx diff --git a/assets/data/stages/test.xml b/assets/data/stages/test.xml new file mode 100644 index 00000000..f74dbd01 --- /dev/null +++ b/assets/data/stages/test.xml @@ -0,0 +1,36 @@ +<!-- praying to god we remove this file later on --> + +<stage zoom="0.9" name="stage" folder="stages/default/" startCamPosY="600" startCamPosX="1000"> + <sprite name="normBG" sprite="stagefront" x="-500" y="100" scale="0.75" updateHitbox="true" /> + <sprite name="noUpdateHitbox" sprite="stagefront" x="-500" y="300" scale="0.75" /> + <sprite name="ro-tat-ay" sprite="stagefront" x="-500" y="700" scale="0.75" updateHitbox="true" angle="37" /> + + + <!-- oh yeah those exist + where the first one go + you saw the video? + the wha + https://www.youtube.com/watch?v=d6iQrh2TK98 + well that explains a bit + whats weird is that i typically think of the number *twenty* seven + guess my favortie number + 37 + -23.47 + interesting + oops + you will be surprised how it looks after me wizard and yosh used it lol, 268kb + + also i love how most of nthis files size comes from the convo + 37 is a wacky number so im using that for testing + // maybe box? so its colors + wrong format lol (im on stepmania xml) + also just realized i cant scale boxes, you can, just not <solid> + we may need a different func for boxes/solids. + storedScale should still work + and when we save we just have to save either width and scale.x, or calculate the width from the scale + i think we can do sprite.frameWidth * sprite.scale.x when saving boxes luckfully + oh yeah --> + + <!-- <box == makeGraphic --> + <!-- <solid == makeSolid --> +</stage> \ No newline at end of file diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx new file mode 100644 index 00000000..e37acc0b --- /dev/null +++ b/assets/data/states/StageEditor.hx @@ -0,0 +1,133 @@ +/** + * THIS FILE IS TEMPORARY UNTIL TRANSFORMS ARE AT A USEABLE STATE. + * TODO: + * - !!!! MOVE BACK TO SOURCE !!!! + * - Rotation + * - Skewing + * - Angle + Scale (like already at a angle) + */ + +import funkin.editors.stage.StageEditor; +import funkin.backend.utils.WindowUtils; +import openfl.Lib; + +var exID = StageEditor.exID; + +function tryUpdateHitbox(sprite) { + var spriteNode = sprite.extra.get(exID("node")); + if (spriteNode.exists("updateHitbox") && spriteNode.get("updateHitbox") == "true") { + sprite.updateHitbox(); + return true; + } + + if (!FlxG.keys.pressed.ALT) { + sprite.x = storedPos.x - (sprite.frameWidth * (storedScale.x - sprite.scale.x) * 0.5); + sprite.y = storedPos.y - (sprite.frameHeight * (storedScale.y - sprite.scale.y) * 0.5); + } + return false; +} + +function create() { + WindowUtils.preventClosing = true; + WindowUtils.resetClosing(); + WindowUtils.onClosing = function() { + if(!FlxG.keys.pressed.ALT) { + Lib.application.window.onClose.cancel(); + FlxG.switchState(new StageEditor("test")); + trace("you dont need to close doofus goofus"); + } + } +} + +function update() { + if(FlxG.keys.justPressed.R) { + trace("reloading"); + FlxG.switchState(new StageEditor("test")); + } +} + +function genericScale(sprite, relative, doX, doY) { + if (FlxG.keys.pressed.ALT) { + relative.x *= 2; + relative.y *= 2; + } + + var width = sprite.frameWidth * storedScale.x; + var height = sprite.frameHeight * storedScale.y; + if(doX) width -= relative.x; + if(doY) height -= relative.y; + CoolUtil.setGraphicSizeFloat(sprite, width, height); + + if(FlxG.keys.pressed.SHIFT) { + var nscale = Math.max(sprite.scale.x, sprite.scale.y); + sprite.scale.set(nscale, nscale); + } + + var updatedHitbox = tryUpdateHitbox(sprite); + if (FlxG.keys.pressed.ALT) { + sprite.x = storedPos.x; + sprite.y = storedPos.y; + if(updatedHitbox) { + sprite.x += (sprite.frameWidth * (storedScale.x - sprite.scale.x) * 0.5); + sprite.y += (sprite.frameHeight * (storedScale.y - sprite.scale.y) * 0.5); + } + return true; + } + return !updatedHitbox; +} + +function genericOppositeScale(sprite, relative, scaleX, scaleY, repositionX, repositionY) { + if(repositionX) relative.x *= -1; + if(repositionY) relative.y *= -1; + var repositioned = genericScale(sprite, relative, scaleX, scaleY); + if (!repositioned) { + if(repositionX) sprite.x = storedPos.x + (sprite.frameWidth * (storedScale.x - sprite.scale.x)); + if(repositionY) sprite.y = storedPos.y + (sprite.frameHeight * (storedScale.y - sprite.scale.y)); + } else if (!FlxG.keys.pressed.ALT) { + if(repositionX) sprite.x += (sprite.frameWidth * (storedScale.x - sprite.scale.x)); + if(repositionY) sprite.y += (sprite.frameHeight * (storedScale.y - sprite.scale.y)); + } +} + +function SCALE_BOTTOM_RIGHT(sprite, relative) { + genericScale(sprite, relative, true, true); +} + +function SCALE_TOP_RIGHT(sprite, relative) { + genericOppositeScale(sprite, relative, true, true, false, true); +} + +function SCALE_TOP_LEFT(sprite, relative) { + genericOppositeScale(sprite, relative, true, true, true, true); +} + +function SCALE_BOTTOM_LEFT(sprite, relative) { + genericOppositeScale(sprite, relative, true, true, true, false); +} + +function SCALE_LEFT(sprite, relative) { + genericOppositeScale(sprite, relative, true, false, true, false); +} + +function SCALE_RIGHT(sprite, relative) { + genericScale(sprite, relative, true, false); +} + +function SCALE_TOP(sprite, relative) { + genericOppositeScale(sprite, relative, false, true, false, true); +} + +function SCALE_BOTTOM(sprite, relative) { + genericScale(sprite, relative, false, true); +} + +function SKEW_LEFT(sprite, relative) {} + +function SKEW_BOTTOM(sprite, relative) {} + +function SKEW_TOP(sprite, relative) {} + +function SKEW_RIGHT(sprite, relative) {} + +function ROTATE(sprite, relative) {} + diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx index 36f817e8..240e2dde 100644 --- a/source/funkin/backend/utils/CoolUtil.hx +++ b/source/funkin/backend/utils/CoolUtil.hx @@ -416,6 +416,21 @@ class CoolUtil sprite.scale.set(nScale, nScale); } + public static function setGraphicSizeFloat(sprite:FlxSprite, Width:Float = 0, Height:Float = 0):Void + { + if (Width <= 0 && Height <= 0) + return; + + var newScaleX:Float = Width / sprite.frameWidth; + var newScaleY:Float = Height / sprite.frameHeight; + sprite.scale.set(newScaleX, newScaleY); + + if (Width <= 0) + sprite.scale.x = newScaleY; + else if (Height <= 0) + sprite.scale.y = newScaleX; + } + /** * Returns a simple string representation of a FlxKey. Used in Controls options. * @param key Key diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index d8b9cd31..fa737305 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -1,5 +1,6 @@ package funkin.editors.stage; +import lime.ui.MouseCursor; import flixel.math.FlxAngle; import flixel.math.FlxPoint; import flixel.math.FlxRect; @@ -13,6 +14,7 @@ import funkin.game.Character; import funkin.game.Stage; import haxe.xml.Access; import haxe.xml.Printer; +import openfl.ui.Mouse; using funkin.backend.utils.MatrixUtil; @@ -32,7 +34,6 @@ class StageEditor extends UIState { public var uiGroup:FlxTypedGroup<FlxSprite> = new FlxTypedGroup<FlxSprite>(); public var stageSpritesWindow:UIButtonList<StageElementButton>; - public var stageSprites:FlxTypedGroup<StageSprite> = new FlxTypedGroup<StageSprite>(); public var xmlMap:Map<FlxObject, Access> = new Map<FlxObject, Access>(); @@ -43,7 +44,12 @@ class StageEditor extends UIState { public var guideCamera:FlxCamera; public var uiCamera:FlxCamera; - public static var selection:Selection; + public var selection:Selection = new Selection(); + public var mouseMode:StageEditorMouseMode = NONE; + public var mousePoint:FlxPoint = new FlxPoint(); + public var clickPoint:FlxPoint = new FlxPoint(); + public var storedPos:FlxPoint = new FlxPoint(); + public var storedScale:FlxPoint = new FlxPoint(); public var showOutlines:Bool = true; public var showCharacters:Bool = true; @@ -182,6 +188,7 @@ class StageEditor extends UIState { if(sprite is FunkinSprite) { var sprite:FunkinSprite = cast sprite; name = sprite.name; + sprite.extra.set(exID("node"), node); sprite.extra.set(exID("type"), node.name); sprite.extra.set(exID("imageFile"), '${node.getAtt("sprite").getDefault(sprite.name)}'); //sprite.active = false; @@ -217,10 +224,6 @@ class StageEditor extends UIState { order.push(sprite); xmlMap.set(sprite, node); - //var t = new StageSprite(name, sprite); - //t.node = node; - //stageSprites.add(t); - return sprite; } stage.loadXml(stage.stageXML, true); @@ -234,12 +237,6 @@ class StageEditor extends UIState { charMap[charPos.name] = char; } - add(stageSprites); - - for(spr in order) { - - } - setZoom(stage.defaultZoom); topMenuSpr = new UITopMenu(topMenu); @@ -251,6 +248,8 @@ class StageEditor extends UIState { var buttonSize:FlxPoint = FlxPoint.get(width-margin*2, 32); stageSpritesWindow = new UIButtonList<StageElementButton>(Std.int(FlxG.width - width), TOP_MENU_HEIGHT, width, Std.int(FlxG.height - TOP_MENU_HEIGHT), "Stage Sprites", buttonSize); stageSpritesWindow.collapsable = true; + stageSpritesWindow.middleAlpha = 0.5; + stageSpritesWindow.bottomAlpha = 0.5; stageSpritesWindow.addButton.callback = () -> { // TODO: implement this } @@ -311,6 +310,8 @@ class StageEditor extends UIState { //if (character != null) // characterPropertiresWindow.characterInfo.text = '${character.getNameList().length} Animations\nFlipped: ${character.flipX}\nSprite: ${character.sprite}\nAnim: ${character.getAnimName()}\nOffset: (${character.frameOffset.x}, ${character.frameOffset.y})'; + currentCursor = ARROW; + if ((!stageSpritesWindow.hovered && !stageSpritesWindow.dragging) && !topMenuSpr.hovered) { if (FlxG.mouse.wheel != 0) { zoom += 0.25 * FlxG.mouse.wheel; @@ -370,17 +371,23 @@ class StageEditor extends UIState { } }*/ + for(sprite in selection) { + if(sprite is FunkinSprite) { + handleSelection(cast sprite); + } + } + //if (FlxG.mouse.justReleasedRight) { // closeCurrentContextMenu(); // openContextMenu(topMenu[2].childs); //} - if (FlxG.mouse.pressed) { + + if (FlxG.mouse.pressed && mouseMode == NONE) { nextScroll.set(nextScroll.x - FlxG.mouse.deltaScreenX, nextScroll.y - FlxG.mouse.deltaScreenY); currentCursor = HAND; - } else - currentCursor = ARROW; - } else if (!FlxG.mouse.pressed) - currentCursor = ARROW; + } + }/* else if (!FlxG.mouse.pressed) + currentCursor = ARROW;*/ stageCamera.scroll.set( lerp(stageCamera.scroll.x, nextScroll.x, 0.35), @@ -394,6 +401,7 @@ class StageEditor extends UIState { } public function selectSprite(_sprite:FunkinSprite) { + selection = new Selection([]); var sprites = stageSpritesWindow.buttons.members.map((o) -> o.getSprite()).filter((o) -> o != null);// && o.animateAtlas == null); for(sprite in sprites) { if(sprite is FunkinSprite) { @@ -406,6 +414,8 @@ class StageEditor extends UIState { var sprite:FunkinSprite = cast _sprite; sprite.extra.set(exID("selected"), true); sprite.extra.get(exID("button")).selected = true; + selection = new Selection([sprite]); + Logs.trace("Selected " + sprite.name); } } @@ -592,28 +602,23 @@ class StageEditor extends UIState { super.draw(); if(!showOutlines) return; - + mousePoint = FlxG.mouse.getWorldPosition(stageCamera, mousePoint); if(dot == null) { - dot = new FlxSprite().makeGraphic(10, 10, FlxColor.WHITE); + dot = new FlxSprite().makeGraphic(30, 30, FlxColor.WHITE); dot.camera = stageCamera; dot.forceIsOnScreen = true; } - for(sprite in stage.stageSprites) { - if(sprite.visible && sprite.isOnScreen(stageCamera)) { + for(sprite in selection) { + if(sprite is FunkinSprite) { @:privateAccess if(sprite._frame == null) continue; - drawGuides(sprite); - } - } - if(showCharacters) { - for(char in chars) { - if(char.visible && char.isOnScreen(stageCamera)) { - @:privateAccess if(char._frame == null) continue; - drawGuides(char); - } + drawGuides(cast sprite); } } } + var lineColor = 0xFFb794b6; + var circleColor = 0xFF99a8f2; + function drawGuides(sprite:FlxSprite) { var oldWidth = sprite.width; var oldHeight = sprite.height; @@ -652,30 +657,125 @@ class StageEditor extends UIState { } cast(sprite.extra.get(exID("bounds")), FlxRect).set(minX, minY, maxX - minX, maxY - minY); } + var funkinSprite = sprite is FunkinSprite ? cast(sprite, FunkinSprite) : null; - dot.color = FlxColor.RED; - if(sprite is FunkinSprite) { - var sprite:FunkinSprite = cast sprite; - if(sprite.extra.get(exID("selected")) == true) { - dot.color = FlxColor.GREEN; + if(funkinSprite != null) { + if(funkinSprite.extra.exists(exID("buttonBoxes"))) { + var oldButtonBoxes:Array<FlxPoint> = cast funkinSprite.extra.get(exID("buttonBoxes")); + if(oldButtonBoxes != null) { + for(point in oldButtonBoxes) { + point.put(); + } + } } } - - for(corner in corners) { - drawDot(corner.x, corner.y); - corner.put(); + var buttonBoxes = []; + if(funkinSprite != null) { + funkinSprite.extra.set(exID("buttonBoxes"), buttonBoxes); } + dot.color = lineColor; + drawLine(corners[0], corners[1]); // tl - tr drawLine(corners[0], corners[2]); // tl - bl drawLine(corners[1], corners[3]); // tr - br drawLine(corners[2], corners[3]); // bl - br + // cross + //drawLine(corners[0], corners[3]); // tl - br + //drawLine(corners[1], corners[2]); // tr - bl + + dot.color = circleColor; + + for(corner in corners) { + drawDot(corner.x, corner.y); + buttonBoxes.push(corner); + } + + if(funkinSprite == null) { + for(corner in buttonBoxes) { + corner.put(); + } + } // reset hitbox to old values sprite.width = oldWidth; sprite.height = oldHeight; } + var edges:Array<StageEditorEdge> = [ + //// corners + TOP_LEFT, //FlxPoint.get(0, 0), + TOP_RIGHT, //FlxPoint.get(1, 0), + BOTTOM_LEFT, //FlxPoint.get(0, 1), + BOTTOM_RIGHT, //FlxPoint.get(1, 1), + //// edges + MIDDLE_LEFT, //FlxPoint.get(0, 0.5), + MIDDLE_RIGHT, //FlxPoint.get(1, 0.5), + BOTTOM_MIDDLE, //FlxPoint.get(0.5, 1), + TOP_MIDDLE, //FlxPoint.get(0.5, 0), + ]; + + function tryUpdateHitbox(sprite:FunkinSprite) { + call("tryUpdateHitbox", [sprite]); + } + + function handleSelection(sprite:FunkinSprite) { + var buttonBoxes = sprite.extra.get(exID("buttonBoxes")); + + dotCheckSize = dot.frameWidth / 0.7/stageCamera.zoom; // basically adjust it to the zoom. + + if(FlxG.mouse.justPressed) { + for(i=>edge in edges) { + if(checkDot(buttonBoxes[i])) { + mouseMode = switch(edge) { + case TOP_LEFT: SCALE_TOP_LEFT; + case TOP_MIDDLE: SCALE_TOP; + case TOP_RIGHT: SCALE_TOP_RIGHT; + case MIDDLE_LEFT: SCALE_LEFT; + case MIDDLE_RIGHT: SCALE_RIGHT; + case BOTTOM_LEFT: SCALE_BOTTOM_LEFT; + case BOTTOM_MIDDLE: SCALE_BOTTOM; + case BOTTOM_RIGHT: SCALE_BOTTOM_RIGHT; + default: NONE; + } + Logs.trace("Clicked Dot: " + mouseMode.toString()); + mousePoint.copyTo(clickPoint); + storedPos.set(sprite.x, sprite.y); + storedScale.copyFrom(sprite.scale); + } + } + } + for(i=>edge in edges) { + if(checkDot(buttonBoxes[i])) { + currentCursor = switch(edge) { + // RESIZE_NESW; //RESIZE_NS; //RESIZE_NWSE; //RESIZE_WE; + case TOP_LEFT | BOTTOM_RIGHT: MouseCursor.RESIZE_NWSE; + case TOP_MIDDLE | BOTTOM_MIDDLE: MouseCursor.RESIZE_NS; + case TOP_RIGHT | BOTTOM_LEFT: MouseCursor.RESIZE_NESW; + case MIDDLE_LEFT | MIDDLE_RIGHT: MouseCursor.RESIZE_WE; + default: ARROW; + } + break; + } + } + + mouseMode = (FlxG.mouse.justReleased) ? NONE : mouseMode; + if(mouseMode == NONE) return; + var relative = clickPoint.subtractNew(mousePoint); + // todo: make this origin based + relative.rotateByDegrees(sprite.angle); + call(mouseMode.toString(), [sprite, relative]); + cast(sprite.extra.get(exID("button")), StageElementButton).updateInfo(sprite); + relative.put(); + } + + var dotCheckSize:Float = 50; + + function checkDot(point:FlxPoint):Bool { + var rect = new FlxRect(point.x - dotCheckSize/2, point.y - dotCheckSize/2, dotCheckSize, dotCheckSize); + return rect.containsPoint(mousePoint); + } + inline function drawDot(x:Float, y:Float) { dot.setPosition(x, y); dot.scale.set(0.7/stageCamera.zoom, 0.7/stageCamera.zoom); @@ -712,8 +812,8 @@ enum StageChange { CEditInfo(oldInfo:Xml, newInfo:Xml); } -@:forward abstract Selection(Array<StageSprite>) from Array<StageSprite> to Array<StageSprite> { - public inline function new(?array:Array<StageSprite>) +@:forward abstract Selection(Array<FunkinSprite>) from Array<FunkinSprite> to Array<FunkinSprite> { + public inline function new(?array:Array<FunkinSprite>) this = array == null ? [] : array; // too lazy to put this in every for loop so i made it a abstract @@ -727,112 +827,70 @@ enum StageChange { //} } -class StageSprite extends UISprite { - public var tracker:FlxObject; - public var funkinTracker:FunkinSprite; - public var node:Access; +enum abstract StageEditorMouseMode(Int) { + var NONE; - public var name:String; + var SCALE_LEFT; + var SCALE_BOTTOM; + var SCALE_TOP; + var SCALE_RIGHT; + var SCALE_TOP_LEFT; + var SCALE_TOP_RIGHT; + var SCALE_BOTTOM_LEFT; + var SCALE_BOTTOM_RIGHT; - public var extra:Map<String, Dynamic> = new Map<String, Dynamic>(); + var SKEW_LEFT; + var SKEW_BOTTOM; + var SKEW_TOP; + var SKEW_RIGHT; - public var scrollX:Float; - public var scrollY:Float; - public var scaleX:Float; - public var scaleY:Float; - public var zoomFactor:Float = 1; // TODO: implement this - public var skewX:Float; - public var skewY:Float; - public var spriteAnimType:XMLAnimType; + var ROTATE; - public var skipNegativeBeats:Bool = false; - public var beatInterval:Int = 0; - public var beatOffset:Int = 0; - - public var lowMemory:Bool; - public var highMemory:Bool; - - public var selected:Bool = false; - public var draggable:Bool = false; - - public function new(name:String, sprite:FlxObject) { - super(x, y); - this.name = name; - this.tracker = sprite; - - scrollX = tracker.scrollFactor.x; - scrollY = tracker.scrollFactor.y; - if(tracker is FunkinSprite) { - var tracker:FunkinSprite = cast tracker; - scaleX = tracker.scale.x; - scaleY = tracker.scale.y; - funkinTracker = tracker; - } - else if (tracker is StageCharPos) { - var tracker:StageCharPos = cast tracker; - var char:Character = tracker.extra.get(StageEditor.exID("char")); - scaleX = tracker.scale.x; - scaleY = tracker.scale.y; - funkinTracker = char; - } - - lowMemory = node.x.parent.nodeName == "low-memory"; - highMemory = node.x.parent.nodeName == "high-memory"; - - if(funkinTracker != null) { - skewX = funkinTracker.skew.x; - skewY = funkinTracker.skew.y; - alpha = funkinTracker.alpha; - spriteAnimType = funkinTracker.spriteAnimType; - antialiasing = funkinTracker.antialiasing; - width = funkinTracker.width; - height = funkinTracker.height; - color = funkinTracker.color; - - skipNegativeBeats = funkinTracker.skipNegativeBeats; - beatInterval = funkinTracker.beatInterval; - beatOffset = funkinTracker.beatOffset; - } - - } - - public override function update(elapsed:Float) { - super.update(elapsed); - if (tracker.exists) { - tracker.x = x; - tracker.y = y; - tracker.scrollFactor.set(scrollX, scrollY); - if(tracker is FlxSprite) { - var tracker:FlxSprite = cast tracker; - } - else if (tracker is StageCharPos) { - var tracker:StageCharPos = cast tracker; - tracker.skewX = skewX; - tracker.skewY = skewY; - } - - if(funkinTracker != null) { - funkinTracker.scale.set(scaleX, scaleY); - funkinTracker.skew.set(skewX, skewY); - funkinTracker.alpha = alpha; - funkinTracker.spriteAnimType = spriteAnimType; - funkinTracker.antialiasing = antialiasing; - funkinTracker.width = width; - funkinTracker.height = height; - - funkinTracker.skipNegativeBeats = skipNegativeBeats; - funkinTracker.beatInterval = beatInterval; - funkinTracker.beatOffset = beatOffset; - - funkinTracker.color = color; - } + public function toString():String { + return switch(cast this) { + case NONE: "NONE"; + case SCALE_LEFT: "SCALE_LEFT"; + case SCALE_BOTTOM: "SCALE_BOTTOM"; + case SCALE_TOP: "SCALE_TOP"; + case SCALE_RIGHT: "SCALE_RIGHT"; + case SCALE_TOP_LEFT: "SCALE_TOP_LEFT"; + case SCALE_TOP_RIGHT: "SCALE_TOP_RIGHT"; + case SCALE_BOTTOM_LEFT: "SCALE_BOTTOM_LEFT"; + case SCALE_BOTTOM_RIGHT: "SCALE_BOTTOM_RIGHT"; + case SKEW_LEFT: "SKEW_LEFT"; + case SKEW_BOTTOM: "SKEW_BOTTOM"; + case SKEW_TOP: "SKEW_TOP"; + case SKEW_RIGHT: "SKEW_RIGHT"; + case ROTATE: "ROTATE"; } } +} - public function handleSelection(selectionBox:UISliceSprite):Bool { - return false; - }; - public function handleDrag(change:FlxPoint):Void { +enum abstract StageEditorEdge(Int) { + var NONE; - }; + var TOP_LEFT; + var TOP_MIDDLE; + var TOP_RIGHT; + var MIDDLE_LEFT; + var MIDDLE_MIDDLE; + var MIDDLE_RIGHT; + var BOTTOM_LEFT; + var BOTTOM_MIDDLE; + var BOTTOM_RIGHT; + + function toString():String { + return switch(cast this) { + case NONE: "NONE"; + case TOP_LEFT: "TOP_LEFT"; + case TOP_MIDDLE: "TOP_MIDDLE"; + case TOP_RIGHT: "TOP_RIGHT"; + case MIDDLE_LEFT: "MIDDLE_LEFT"; + case MIDDLE_MIDDLE: "MIDDLE_MIDDLE"; + case MIDDLE_RIGHT: "MIDDLE_RIGHT"; + case BOTTOM_LEFT: "BOTTOM_LEFT"; + case BOTTOM_MIDDLE: "BOTTOM_MIDDLE"; + case BOTTOM_RIGHT: "BOTTOM_RIGHT"; + } + } } \ No newline at end of file diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index 538ae0eb..2ccf6051 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -53,8 +53,8 @@ class StageCharacterButton extends StageElementButton { return charPos.name; } - public override function getInfoText():String { - return '${getName()} (${charPos.x}, ${charPos.y})'; + public override function getPos():FlxPoint { + return FlxPoint.get(charPos.x, charPos.y); } public override function updatePos() { diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index c2df186a..ae88b66b 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -136,7 +136,14 @@ class StageElementButton extends UIButton { // TODO: implement } + public function getPos():FlxPoint { + return FlxPoint.get(-1, -1); + } + public function getInfoText():String { - return 'NOT IMPLEMENTED'; + var pos = getPos(); + var text = '${getName()} (${CoolUtil.quantize(pos.x, 100)}x${CoolUtil.quantize(pos.y, 100)})'; + pos.put(); + return text; } } \ No newline at end of file diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index 96a9981e..09cc061e 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -59,8 +59,8 @@ class StageSpriteButton extends StageElementButton { return xml.att.name; } - public override function getInfoText():String { - return '${getName()} (${sprite.x}, ${sprite.y})'; + public override function getPos():FlxPoint { + return FlxPoint.get(sprite.x, sprite.y); } public override function updatePos() { diff --git a/source/funkin/editors/ui/UISliceSprite.hx b/source/funkin/editors/ui/UISliceSprite.hx index 664ede98..a6a6afd5 100644 --- a/source/funkin/editors/ui/UISliceSprite.hx +++ b/source/funkin/editors/ui/UISliceSprite.hx @@ -31,6 +31,18 @@ class UISliceSprite extends UISprite { bHeight = h; } + override function set_alpha(value:Float) { + super.set_alpha(value); + topAlpha = alpha; + middleAlpha = alpha; + bottomAlpha = alpha; + return value; + } + + public var topAlpha:Float = 1; + public var middleAlpha:Float = 1; + public var bottomAlpha:Float = 1; + public var drawTop:Bool = true; public var drawMiddle:Bool = true; public var drawBottom:Bool = true; @@ -87,8 +99,10 @@ class UISliceSprite extends UISprite { var y:Float = this.y; if (visible && !(bWidth == 0 || bHeight == 0)) { + var oldAlpha = alpha; // TOP if (drawTop) { + super.set_alpha(topAlpha); // TOP LEFT frame = topleft; setPosition(x, y); @@ -118,6 +132,7 @@ class UISliceSprite extends UISprite { // MIDDLE if (drawMiddle && bHeight > top.frame.height + bottom.frame.height) { + super.set_alpha(middleAlpha); var middleHeight:Float = bHeight - (topleft.frame.height * Math.min(bHeight/(topleft.frame.height*2), 1)) - bottomleft.frame.height * Math.min(bHeight/(bottomleft.frame.height*2), 1); @@ -144,6 +159,7 @@ class UISliceSprite extends UISprite { // BOTTOM if (drawBottom) { + super.set_alpha(bottomAlpha); // BOTTOM LEFT frame = bottomleft; setPosition(x, y + bHeight - (bottomleft.frame.height * Math.min(bHeight/(bottomleft.frame.height*2), 1))); @@ -172,7 +188,9 @@ class UISliceSprite extends UISprite { bottomright.frame.height * Math.min(bHeight/(bottomright.frame.height*2), 1) ); super.drawSuper(); + } + super.set_alpha(oldAlpha); } setPosition(x, y); diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index b04c8c13..c890c82b 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -288,6 +288,7 @@ class Stage extends FlxBasic implements IBeatReceiver { for (path in Paths.getFolderContent("data/stages/", false, mods ? MODS : BOTH)) { var extension = Path.extension(path); if (extensions.contains(extension)) { + list.pushOnce("test"); list.pushOnce(Path.withoutExtension(path)); } } From a8997daecb2e3e555e0abb3309016ade22d86516 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:00:25 +0200 Subject: [PATCH 23/89] New Mouse Icons for Mac! Co-Authored-By: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> --- .../backend/system/macros/LinkerMacro.hx | 40 +++++++ source/funkin/backend/utils/NativeAPI.hx | 105 ++++++++++++++++++ source/funkin/backend/utils/native/Mac.hx | 50 ++++++++- .../utils/native/external/external_code.xml | 32 ++++++ .../external/include/mac/CursorHelper.h | 7 ++ .../utils/native/external/include/mac/Mac.h | 13 +++ .../native/external/src/mac/CursorHelper.mm | 21 ++++ .../utils/native/external/src/mac/Mac.mm | 80 +++++++++++++ source/funkin/editors/charter/Charter.hx | 4 +- source/funkin/editors/charter/CharterEvent.hx | 2 +- .../funkin/editors/charter/CharterEventAdd.hx | 2 +- source/funkin/editors/charter/CharterNote.hx | 2 +- .../editors/charter/CharterStrumline.hx | 2 +- .../editors/charter/CharterStrumlineButton.hx | 2 +- source/funkin/editors/stage/StageEditor.hx | 21 +++- source/funkin/editors/ui/UIAudioPlayer.hx | 4 +- source/funkin/editors/ui/UIButton.hx | 2 +- source/funkin/editors/ui/UICheckbox.hx | 2 +- source/funkin/editors/ui/UIDropDown.hx | 2 +- source/funkin/editors/ui/UIScrollBar.hx | 2 +- source/funkin/editors/ui/UISlider.hx | 6 +- source/funkin/editors/ui/UISprite.hx | 3 +- source/funkin/editors/ui/UIState.hx | 9 +- source/funkin/editors/ui/UITopMenu.hx | 2 +- source/funkin/editors/ui/UIWindow.hx | 2 +- 25 files changed, 387 insertions(+), 30 deletions(-) create mode 100644 source/funkin/backend/system/macros/LinkerMacro.hx create mode 100644 source/funkin/backend/utils/native/external/external_code.xml create mode 100644 source/funkin/backend/utils/native/external/include/mac/CursorHelper.h create mode 100644 source/funkin/backend/utils/native/external/include/mac/Mac.h create mode 100644 source/funkin/backend/utils/native/external/src/mac/CursorHelper.mm create mode 100644 source/funkin/backend/utils/native/external/src/mac/Mac.mm diff --git a/source/funkin/backend/system/macros/LinkerMacro.hx b/source/funkin/backend/system/macros/LinkerMacro.hx new file mode 100644 index 00000000..926bb800 --- /dev/null +++ b/source/funkin/backend/system/macros/LinkerMacro.hx @@ -0,0 +1,40 @@ +package funkin.backend.system.macros; + +import haxe.io.Path; +import haxe.macro.Expr; +import haxe.macro.Context; +import haxe.xml.Printer; +import sys.FileSystem; + +class LinkerMacro +{ + public static macro function xml(filename:String = 'Build.xml'):Array<Field> + { + var pos:Position = Context.currentPos(); + + var sourcePath:String = Path.directory(Context.getPosInfos(pos).file); + + if (!Path.isAbsolute(sourcePath)) + sourcePath = FileSystem.absolutePath(sourcePath); + + sourcePath = Path.removeTrailingSlashes(Path.normalize(sourcePath)); + + var includeElement:Xml = Xml.createElement('include'); + + includeElement.set('name', Path.join([sourcePath, filename])); + + @:privateAccess + { + var printer:Printer = new Printer(true); + + printer.writeNode(includeElement, '\n'); + + Context.getLocalClass().get().meta.add(':buildXml', [{ + expr: EConst(CString(printer.output.toString())), + pos: pos + }], pos); + } + + return Context.getBuildFields(); + } +} \ No newline at end of file diff --git a/source/funkin/backend/utils/NativeAPI.hx b/source/funkin/backend/utils/NativeAPI.hx index a651645e..ca7b5975 100644 --- a/source/funkin/backend/utils/NativeAPI.hx +++ b/source/funkin/backend/utils/NativeAPI.hx @@ -1,5 +1,8 @@ package funkin.backend.utils; +import haxe.macro.Expr.Case; +import openfl.ui.Mouse; +import openfl.ui.MouseCursor; import funkin.backend.utils.native.*; /** @@ -72,6 +75,17 @@ class NativeAPI { #end } + /** + * Set cursor icon. + **/ + public static function setCursorIcon(icon:CodeCursor) { + #if mac + Mac.setMouseCursorIcon(cast icon); + #else + Mouse.cursor = icon.toOpenFL(); + #end + } + public static function consoleColorToANSI(color:ConsoleColor) { return switch(color) { case BLACK: 30; @@ -141,4 +155,95 @@ enum abstract MessageBoxIcon(Int) { var MSG_QUESTION = 0x00000020; var MSG_WARNING = 0x00000030; var MSG_INFORMATION = 0x00000040; +} + +enum abstract CodeCursor(String) { + var CUSTOM;// = "arrow"; + var ARROW;// = "arrow"; + var CLICK;// = "click"; + var CROSSHAIR;// = "crosshair"; + var HAND;// = "hand"; + var IBEAM;// = "ibeam"; + var MOVE;// = "move"; + + var RESIZE_H;// = "resize_we"; + var RESIZE_V;// = "resize_ns"; + var RESIZE_TL;// = "resize_nw"; + var RESIZE_TR;// = "resize_ne"; + var RESIZE_BL;// = "resize_sw"; + var RESIZE_BR;// = "resize_se"; + var RESIZE_T;// = "resize_n"; + var RESIZE_B;// = "resize_b"; + var RESIZE_L;// = "resize_w"; + var RESIZE_R;// = "resize_e"; + + var WAIT;// = "wait"; + var WAIT_ARROW;// = "waitarrow"; + var DISABLED;// = "disabled"; + var DRAG;// = "drag"; + var DRAG_OPEN;// = "dragopen"; + + @:to public function toOpenFL():MouseCursor { + return @:privateAccess switch(cast this) { + case ARROW: MouseCursor.ARROW; + case CROSSHAIR: MouseCursor.__CROSSHAIR; + case CLICK: MouseCursor.BUTTON; + case IBEAM: MouseCursor.IBEAM; + case MOVE: MouseCursor.__MOVE; + case HAND: MouseCursor.HAND; + case DRAG: MouseCursor.HAND; + case DRAG_OPEN: MouseCursor.HAND; + case WAIT: MouseCursor.__WAIT; + case WAIT_ARROW: MouseCursor.__WAIT_ARROW; + + case DISABLED: MouseCursor.ARROW; + + case RESIZE_TR: MouseCursor.__RESIZE_NESW; + case RESIZE_BL: MouseCursor.__RESIZE_NESW; + case RESIZE_TL: MouseCursor.__RESIZE_NWSE; + case RESIZE_BR: MouseCursor.__RESIZE_NWSE; + case RESIZE_H: MouseCursor.__RESIZE_WE; + case RESIZE_V: MouseCursor.__RESIZE_NS; + + case RESIZE_T: MouseCursor.__RESIZE_NS; + case RESIZE_B: MouseCursor.__RESIZE_NS; + + case RESIZE_L: MouseCursor.__RESIZE_WE; + case RESIZE_R: MouseCursor.__RESIZE_WE; + case CUSTOM: MouseCursor.__CUSTOM; + //default: ARROW; + } + } + + @:to public function toInt():Int { + return switch(cast this) { + case ARROW: 0; + case CROSSHAIR: 1; + case CLICK: 2; + case IBEAM: 3; + case MOVE: 4; + case HAND: 5; + case DRAG: 6; + case DRAG_OPEN: 7; + case WAIT: 8; + case WAIT_ARROW: 9; + + case DISABLED: 10; + + case RESIZE_TR: 11; + case RESIZE_BL: 12; + case RESIZE_TL: 13; + case RESIZE_BR: 14; + case RESIZE_H: 15; + case RESIZE_V: 16; + + case RESIZE_T: 17; + case RESIZE_B: 18; + + case RESIZE_L: 19; + case RESIZE_R: 20; + + case CUSTOM: -1; + } + } } \ No newline at end of file diff --git a/source/funkin/backend/utils/native/Mac.hx b/source/funkin/backend/utils/native/Mac.hx index fa68700a..0db00f42 100644 --- a/source/funkin/backend/utils/native/Mac.hx +++ b/source/funkin/backend/utils/native/Mac.hx @@ -1,7 +1,11 @@ package funkin.backend.utils.native; #if mac -@:cppFileCode("#include <sys/sysctl.h>") +import funkin.backend.utils.NativeAPI.CodeCursor; +import openfl.ui.Mouse; + +@:build(funkin.backend.system.macros.LinkerMacro.xml('external/external_code.xml')) +@:headerInclude('sys/sysctl.h') class Mac { @:functionCode(' int mib [] = { CTL_HW, HW_MEMSIZE }; @@ -17,5 +21,47 @@ class Mac { { return 0; } + + public static function setMouseCursorIcon(icon:CodeCursor):Void + { + final valid:Bool = ExternalMac.setCursorIcon(icon.toInt()); + if(!valid) { + Mouse.cursor = icon.toOpenFL(); + } + } } -#end \ No newline at end of file + +@:build(funkin.backend.system.macros.LinkerMacro.xml('external/external_code.xml')) +@:native("ExternalMac") +@:include('Mac.h') +extern class ExternalMac { + @:native("ExternalMac::setCursorIcon") + public static function setCursorIcon(icon:Int):Bool; +} +#end + + +/* + +Cursor + +Description +The arrow cursor (arrow) +The I-beam cursor for indicating insertion points (iBeam) +The cross-hair cursor (crosshair) +The closed-hand cursor (closedHand) +The open-hand cursor (openHand) +The pointing-hand cursor (pointingHand) +The resize-left cursor (resizeLeft) +The resize-right cursor (resizeRight) +The resize-left-and-right cursor (resizeLeftRight) +The resize-up cursor (resizeUp) +The resize-down cursor (resizeDown) +The resize-up-and-down cursor (resizeUpDown) +The disappearing item cursor (disappearingItem) +The I-Beam text cursor for vertical layout (iBeamCursorForVerticalLayout). +The not allowed cursor (operationNotAllowed). +The drag link cursor (dragLink). +The drag copy cursor (dragCopy). +The contextual menu cursor (contextualMenu). +*/ diff --git a/source/funkin/backend/utils/native/external/external_code.xml b/source/funkin/backend/utils/native/external/external_code.xml new file mode 100644 index 00000000..308b0d35 --- /dev/null +++ b/source/funkin/backend/utils/native/external/external_code.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xml> + <pragma once="true" /> + + <files id="haxe"> + <compilerflag value="-I${this_dir}/include/mac" if="macos" /> + </files> + + <files id="__main__"> + <compilerflag value="-I${this_dir}/include/mac" if="macos" /> + </files> + + <files id="external-code"> + <section if="macos"> + <compilerflag value="-I${this_dir}/include/mac" /> + + <file name="${this_dir}/src/mac/CursorHelper.mm" /> + <file name="${this_dir}/src/mac/Mac.mm" /> + </section> + </files> + + <target id="haxe"> + <section if="macos"> + <vflag name="-framework" value="IOKit" /> + <vflag name="-framework" value="AppKit" /> + <vflag name="-framework" value="Cocoa" /> + <vflag name="-framework" value="Foundation" /> + </section> + + <files id="external-code" /> + </target> +</xml> diff --git a/source/funkin/backend/utils/native/external/include/mac/CursorHelper.h b/source/funkin/backend/utils/native/external/include/mac/CursorHelper.h new file mode 100644 index 00000000..6045293a --- /dev/null +++ b/source/funkin/backend/utils/native/external/include/mac/CursorHelper.h @@ -0,0 +1,7 @@ +#import <Foundation/Foundation.h> + +@interface CursorHelper : NSObject + ++ (NSCursor *)getCursorForSelector:(SEL)selector defaultCursor:(NSCursor *)defaultCursor; + +@end \ No newline at end of file diff --git a/source/funkin/backend/utils/native/external/include/mac/Mac.h b/source/funkin/backend/utils/native/external/include/mac/Mac.h new file mode 100644 index 00000000..2b88b858 --- /dev/null +++ b/source/funkin/backend/utils/native/external/include/mac/Mac.h @@ -0,0 +1,13 @@ +#ifndef MAC_H +#define MAC_H + +#if defined(__APPLE__) + +namespace ExternalMac +{ + bool setCursorIcon(int icon); +} + +#endif + +#endif \ No newline at end of file diff --git a/source/funkin/backend/utils/native/external/src/mac/CursorHelper.mm b/source/funkin/backend/utils/native/external/src/mac/CursorHelper.mm new file mode 100644 index 00000000..90549237 --- /dev/null +++ b/source/funkin/backend/utils/native/external/src/mac/CursorHelper.mm @@ -0,0 +1,21 @@ +#import <Cocoa/Cocoa.h> +#import "CursorHelper.h" + +@implementation CursorHelper + ++ (NSCursor *)getCursorForSelector:(SEL)selector defaultCursor:(NSCursor *)defaultCursor { + NSCursor *cursor = nil; + + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wundeclared-selector" + if ([NSCursor respondsToSelector:selector]) { + cursor = [NSCursor performSelector:selector]; + } else { + cursor = defaultCursor; + } + #pragma clang diagnostic pop + + return cursor; +} + +@end diff --git a/source/funkin/backend/utils/native/external/src/mac/Mac.mm b/source/funkin/backend/utils/native/external/src/mac/Mac.mm new file mode 100644 index 00000000..74589de1 --- /dev/null +++ b/source/funkin/backend/utils/native/external/src/mac/Mac.mm @@ -0,0 +1,80 @@ +#import <Cocoa/Cocoa.h> +#import "CursorHelper.h" + +#define ARROW 0 +#define CROSSHAIR 1 +#define CLICK 2 +#define IBEAM 3 +#define MOVE 4 +#define HAND 5 +#define DRAG 6 +#define DRAG_OPEN 7 +#define WAIT 8 +#define WAIT_ARROW 9 +#define DISABLED 10 +#define RESIZE_TR 11 +#define RESIZE_BL 12 +#define RESIZE_TL 13 +#define RESIZE_BR 14 +#define RESIZE_H 15 +#define RESIZE_V 16 +#define RESIZE_T 17 +#define RESIZE_B 18 +#define RESIZE_L 19 +#define RESIZE_R 20 +#define CUSTOM -1 + +namespace ExternalMac { + bool setCursorIcon(int icon/*, const char *customCursor, float customX, float customY*/) { + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wundeclared-selector" + + NSCursor *cursor = nil; + switch(icon) { + case ARROW: cursor = [NSCursor arrowCursor]; break; + case CLICK: cursor = [NSCursor pointingHandCursor]; break; + case CROSSHAIR: cursor = [NSCursor crosshairCursor]; break; + case HAND: cursor = [NSCursor closedHandCursor]; break; + case IBEAM: cursor = [NSCursor IBeamCursor]; break; + //case MOVE: cursor = [NSCursor moveCursor]; break; + + case RESIZE_H: cursor = [NSCursor resizeLeftRightCursor]; break; + case RESIZE_V: cursor = [NSCursor resizeUpDownCursor]; break; + // TODO: DEFAULTS + case RESIZE_TL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_TR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_BL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthWestCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_BR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthEastCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_T: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_B: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_L: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeWestCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_R: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeEastCursor) defaultCursor:[NSCursor arrowCursor]]; break; + + case WAIT: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case WAIT_ARROW: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case DISABLED: cursor = [NSCursor operationNotAllowedCursor]; break; + case DRAG: cursor = [NSCursor closedHandCursor]; break; + case DRAG_OPEN: cursor = [NSCursor openHandCursor]; break; + + /*case CUSTOM: { + // TODO: CACHING + NSString *cursorImageName = [NSString stringWithUTF8String:customCursor]; + NSImage *tmpImage = [NSImage imageNamed:cursorImageName]; + NSCursor *pointer = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)]; + + cursor = [NSCursor pointer] + break; + }*/ + case CUSTOM: cursor = [NSCursor arrowCursor]; break; + } + + #pragma clang diagnostic pop + + if(cursor != nil) { + [cursor set]; + + return true; + } + return false; + } +} diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx index ddb6db51..4bb64531 100644 --- a/source/funkin/editors/charter/Charter.hx +++ b/source/funkin/editors/charter/Charter.hx @@ -804,7 +804,7 @@ class Charter extends UIState { } if (s is CharterNote) cast(s, CharterNote).snappedToStrumline = true; - if (s is UISprite) cast(s, UISprite).cursor = BUTTON; + if (s is UISprite) cast(s, UISprite).cursor = CLICK; } if (!(verticalChange == 0 && horizontalChange == 0)) { notesGroup.sortNotes(); eventsGroup.sortEvents(); @@ -866,7 +866,7 @@ class Charter extends UIState { case SUSTAIN_DRAG: selectionDragging = FlxG.mouse.pressed; if (selectionDragging) { - currentCursor = BUTTON; + currentCursor = CLICK; selection.loop(function (n:CharterNote) { var change:Float = Math.max((mousePos.y-(FlxG.keys.pressed.SHIFT ? dragStartPos.y : quantStep(dragStartPos.y))) / 40, -n.susLength); n.tempSusLength = change; diff --git a/source/funkin/editors/charter/CharterEvent.hx b/source/funkin/editors/charter/CharterEvent.hx index af8996a4..92243689 100644 --- a/source/funkin/editors/charter/CharterEvent.hx +++ b/source/funkin/editors/charter/CharterEvent.hx @@ -23,7 +23,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable { this.step = step; this.events = events.getDefault([]); - cursor = BUTTON; + cursor = CLICK; } public override function update(elapsed:Float) { diff --git a/source/funkin/editors/charter/CharterEventAdd.hx b/source/funkin/editors/charter/CharterEventAdd.hx index 038725d3..89fbf3cf 100644 --- a/source/funkin/editors/charter/CharterEventAdd.hx +++ b/source/funkin/editors/charter/CharterEventAdd.hx @@ -13,7 +13,7 @@ class CharterEventAdd extends UISliceSprite { text = new UIText(0, 0, 0, ""); members.push(text); - cursor = BUTTON; + cursor = CLICK; } public override function onHovered() { diff --git a/source/funkin/editors/charter/CharterNote.hx b/source/funkin/editors/charter/CharterNote.hx index af6dc7ea..8d67adc2 100644 --- a/source/funkin/editors/charter/CharterNote.hx +++ b/source/funkin/editors/charter/CharterNote.hx @@ -44,7 +44,7 @@ class CharterNote extends UISprite implements ICharterSelectable { typeText = new UIText(x, y, 0, Std.string(type)); - cursor = sustainSpr.cursor = BUTTON; + cursor = sustainSpr.cursor = CLICK; moves = false; } diff --git a/source/funkin/editors/charter/CharterStrumline.hx b/source/funkin/editors/charter/CharterStrumline.hx index 6ffb297a..032521a6 100644 --- a/source/funkin/editors/charter/CharterStrumline.hx +++ b/source/funkin/editors/charter/CharterStrumline.hx @@ -64,7 +64,7 @@ class CharterStrumline extends UISprite { draggingSprite.alpha = 0.4; draggingSprite.y = 9; draggingSprite.antialiasing = true; - draggingSprite.cursor = BUTTON; + draggingSprite.cursor = CLICK; members.push(draggingSprite); button = new CharterStrumlineOptions(this); diff --git a/source/funkin/editors/charter/CharterStrumlineButton.hx b/source/funkin/editors/charter/CharterStrumlineButton.hx index c7d4944a..39207e5f 100644 --- a/source/funkin/editors/charter/CharterStrumlineButton.hx +++ b/source/funkin/editors/charter/CharterStrumlineButton.hx @@ -24,7 +24,7 @@ class CharterStrumlineButton extends UISprite { button.scale.set(0.85,0.85); button.updateHitbox(); button.antialiasing = true; - button.cursor = BUTTON; + button.cursor = CLICK; members.push(button); this.text = new UIText(0,0, 160, text); diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index fa737305..ee550b8b 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -749,10 +749,19 @@ class StageEditor extends UIState { if(checkDot(buttonBoxes[i])) { currentCursor = switch(edge) { // RESIZE_NESW; //RESIZE_NS; //RESIZE_NWSE; //RESIZE_WE; - case TOP_LEFT | BOTTOM_RIGHT: MouseCursor.RESIZE_NWSE; - case TOP_MIDDLE | BOTTOM_MIDDLE: MouseCursor.RESIZE_NS; - case TOP_RIGHT | BOTTOM_LEFT: MouseCursor.RESIZE_NESW; - case MIDDLE_LEFT | MIDDLE_RIGHT: MouseCursor.RESIZE_WE; + case TOP_LEFT: RESIZE_TL; + case TOP_MIDDLE: RESIZE_T; + case TOP_RIGHT: RESIZE_TR; + case MIDDLE_LEFT: RESIZE_L; + //case MIDDLE_MIDDLE: RESIZE_H; + case MIDDLE_RIGHT: RESIZE_R; + case BOTTOM_LEFT: RESIZE_BL; + case BOTTOM_MIDDLE: RESIZE_B; + case BOTTOM_RIGHT: RESIZE_BR; + //case TOP_LEFT | BOTTOM_RIGHT: MouseCursor.RESIZE_NWSE; + //case TOP_MIDDLE | BOTTOM_MIDDLE: MouseCursor.RESIZE_NS; + //case TOP_RIGHT | BOTTOM_LEFT: MouseCursor.RESIZE_NESW; + //case MIDDLE_LEFT | MIDDLE_RIGHT: MouseCursor.RESIZE_WE; default: ARROW; } break; @@ -873,7 +882,7 @@ enum abstract StageEditorEdge(Int) { var TOP_MIDDLE; var TOP_RIGHT; var MIDDLE_LEFT; - var MIDDLE_MIDDLE; + //var MIDDLE_MIDDLE; var MIDDLE_RIGHT; var BOTTOM_LEFT; var BOTTOM_MIDDLE; @@ -886,7 +895,7 @@ enum abstract StageEditorEdge(Int) { case TOP_MIDDLE: "TOP_MIDDLE"; case TOP_RIGHT: "TOP_RIGHT"; case MIDDLE_LEFT: "MIDDLE_LEFT"; - case MIDDLE_MIDDLE: "MIDDLE_MIDDLE"; + //case MIDDLE_MIDDLE: "MIDDLE_MIDDLE"; case MIDDLE_RIGHT: "MIDDLE_RIGHT"; case BOTTOM_LEFT: "BOTTOM_LEFT"; case BOTTOM_MIDDLE: "BOTTOM_MIDDLE"; diff --git a/source/funkin/editors/ui/UIAudioPlayer.hx b/source/funkin/editors/ui/UIAudioPlayer.hx index c0f49d90..7d688a69 100644 --- a/source/funkin/editors/ui/UIAudioPlayer.hx +++ b/source/funkin/editors/ui/UIAudioPlayer.hx @@ -57,7 +57,7 @@ class UIAudioPlayer extends UIButton { members.push(timeBarPlayer); timeBarSpr = cast new UISprite(timeBar.x, timeBar.y).makeSolid(timeBar.barWidth, timeBar.barHeight, 0x00FFFFFF); - timeBarSpr.cursor = BUTTON; + timeBarSpr.cursor = CLICK; members.push(timeBarSpr); volumeBar = new FlxBar(timeBar.x + timeBar.barWidth - 56, y + 6, LEFT_TO_RIGHT, 56, 10, sound, "volume", 0, 1); @@ -67,7 +67,7 @@ class UIAudioPlayer extends UIButton { members.push(volumeBar); volumeBarSpr = cast new UISprite(volumeBar.x, volumeBar.y).makeSolid(volumeBar.barWidth, volumeBar.barHeight, 0x00FFFFFF); - volumeBarSpr.cursor = BUTTON; + volumeBarSpr.cursor = CLICK; members.push(volumeBarSpr); volumeIcon = new FlxSprite(volumeBar.x - 12 - 8, volumeBar.y-1).loadGraphic(Paths.image('editors/ui/audio-icon')); diff --git a/source/funkin/editors/ui/UIButton.hx b/source/funkin/editors/ui/UIButton.hx index c5522c5c..bb10fad9 100644 --- a/source/funkin/editors/ui/UIButton.hx +++ b/source/funkin/editors/ui/UIButton.hx @@ -13,7 +13,7 @@ class UIButton extends UISliceSprite { field.alignment = CENTER; field.fieldWidth = w; - cursor = BUTTON; + cursor = CLICK; } public override function resize(w:Int, h:Int) { diff --git a/source/funkin/editors/ui/UICheckbox.hx b/source/funkin/editors/ui/UICheckbox.hx index a5bcdef3..d3c777b9 100644 --- a/source/funkin/editors/ui/UICheckbox.hx +++ b/source/funkin/editors/ui/UICheckbox.hx @@ -22,7 +22,7 @@ class UICheckbox extends UISprite { members.push(check); members.push(field); - cursor = BUTTON; + cursor = CLICK; } public override function update(elapsed:Float) { diff --git a/source/funkin/editors/ui/UIDropDown.hx b/source/funkin/editors/ui/UIDropDown.hx index 05fd6859..1cbcbaf3 100644 --- a/source/funkin/editors/ui/UIDropDown.hx +++ b/source/funkin/editors/ui/UIDropDown.hx @@ -43,7 +43,7 @@ class UIDropDown extends UISliceSprite { this.options = [for(o in _items) o.label]; // backwards compatibility this.index = index; - cursor = BUTTON; + cursor = CLICK; label = new UIText(0, 0, width - height, items[index].label); members.push(label); diff --git a/source/funkin/editors/ui/UIScrollBar.hx b/source/funkin/editors/ui/UIScrollBar.hx index c6ef73d2..570a0c56 100644 --- a/source/funkin/editors/ui/UIScrollBar.hx +++ b/source/funkin/editors/ui/UIScrollBar.hx @@ -24,7 +24,7 @@ class UIScrollBar extends UISprite { this.length = length; thumb = new UISliceSprite(0, 0, w, h, 'editors/ui/scrollbar'); - thumb.cursor = BUTTON; + thumb.cursor = CLICK; members.push(thumb); thumbIcon = new FlxSprite(0, 0, Paths.image('editors/ui/scrollbar-icon')); diff --git a/source/funkin/editors/ui/UISlider.hx b/source/funkin/editors/ui/UISlider.hx index d07bb915..b0d86d0a 100644 --- a/source/funkin/editors/ui/UISlider.hx +++ b/source/funkin/editors/ui/UISlider.hx @@ -45,7 +45,7 @@ class UISlider extends UISprite { makeGraphic(barWidth, 12, 0x00000000, true); this.drawRoundRect(0, 0, barWidth, 12, 8, 6, 0xFFC0C0C0); this.drawRoundRect(1, 1, barWidth-2, 12-2, 8, 5, 0xFF140013); - cursor = BUTTON; + cursor = CLICK; progressbar = new UISprite(centered ? barWidth/2 : 0); progressbar.makeGraphic(barWidth, 8, 0x00000000, true); @@ -63,7 +63,7 @@ class UISlider extends UISprite { var selectableBar:UISprite = new UISprite(x,y); selectableBar.loadGraphic(Paths.image("editors/ui/slider")); selectableBar.antialiasing = true; - selectableBar.cursor = BUTTON; + selectableBar.cursor = CLICK; members.push(selectableBar); switch (i) { @@ -74,7 +74,7 @@ class UISlider extends UISprite { selectableHitbox = new UISprite(x,y); selectableHitbox.makeSolid(barWidth, 18, -1); - selectableHitbox.cursor = BUTTON; + selectableHitbox.cursor = CLICK; selectableHitbox.alpha = 0; members.push(selectableHitbox); diff --git a/source/funkin/editors/ui/UISprite.hx b/source/funkin/editors/ui/UISprite.hx index 07c9adc8..c8e38333 100644 --- a/source/funkin/editors/ui/UISprite.hx +++ b/source/funkin/editors/ui/UISprite.hx @@ -1,6 +1,7 @@ package funkin.editors.ui; import flixel.math.FlxRect; +import funkin.backend.utils.NativeAPI.CodeCursor; import openfl.ui.MouseCursor; @:allow(funkin.editors.ui.UIState) @@ -21,7 +22,7 @@ class UISprite extends FlxSprite { public var hoverCallback:Void->Void = null; - public var cursor:MouseCursor = ARROW; + public var cursor:CodeCursor = ARROW; public var focused(get, set):Bool; public var selectable:Bool = true; diff --git a/source/funkin/editors/ui/UIState.hx b/source/funkin/editors/ui/UIState.hx index da3fdfc8..ea2f6781 100644 --- a/source/funkin/editors/ui/UIState.hx +++ b/source/funkin/editors/ui/UIState.hx @@ -3,6 +3,7 @@ package funkin.editors.ui; import flixel.math.FlxPoint; import flixel.math.FlxRect; import funkin.backend.system.framerate.Framerate; +import funkin.backend.utils.NativeAPI.CodeCursor; import funkin.editors.ui.UIContextMenu.UIContextMenuCallback; import funkin.editors.ui.UIContextMenu.UIContextMenuOption; import lime.ui.KeyCode; @@ -19,7 +20,7 @@ class UIState extends MusicBeatState { public var hoveredSprite:UISprite = null; public var currentFocus:IUIFocusable = null; - public var currentCursor:MouseCursor = ARROW; + public var currentCursor:CodeCursor = ARROW; private var __rect:FlxRect; private var __mousePos:FlxPoint; @@ -105,10 +106,12 @@ class UIState extends MusicBeatState { FlxG.sound.keysAllowed = currentFocus != null ? !(currentFocus is UITextBox) : true; if (hoveredSprite != null) { - Mouse.cursor = hoveredSprite.cursor; + NativeAPI.setCursorIcon(hoveredSprite.cursor); + //Mouse.cursor = hoveredSprite.cursor; hoveredSprite = null; } else { - Mouse.cursor = currentCursor; + NativeAPI.setCursorIcon(currentCursor); + //Mouse.cursor = currentCursor; } } diff --git a/source/funkin/editors/ui/UITopMenu.hx b/source/funkin/editors/ui/UITopMenu.hx index ae78469d..12e1b15e 100644 --- a/source/funkin/editors/ui/UITopMenu.hx +++ b/source/funkin/editors/ui/UITopMenu.hx @@ -43,7 +43,7 @@ class UITopMenuButton extends UISliceSprite { super(x, y, 0, 23, "editors/ui/menu-item"); this.contextMenu = contextMenu; this.parent = parent; - cursor = BUTTON; + cursor = CLICK; this.label = new UIText(4, 0, 0, label); this.label.alignment = CENTER; diff --git a/source/funkin/editors/ui/UIWindow.hx b/source/funkin/editors/ui/UIWindow.hx index 64f11eb8..84fb80e4 100644 --- a/source/funkin/editors/ui/UIWindow.hx +++ b/source/funkin/editors/ui/UIWindow.hx @@ -25,7 +25,7 @@ class UIWindow extends UISliceSprite { __rect.width = bWidth; __rect.height = topHeight; if(UIState.state.isOverlapping(this, __rect)) { - cursor = BUTTON; + cursor = CLICK; if(FlxG.mouse.justPressed) { content.exists = !content.exists; drawMiddle = !drawMiddle; From 7d236db474c4f1f4c2b3d6998dff1e78f7783c46 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:09:08 +0200 Subject: [PATCH 24/89] Oh yea --- source/funkin/backend/utils/NativeAPI.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/backend/utils/NativeAPI.hx b/source/funkin/backend/utils/NativeAPI.hx index ca7b5975..fac3cce0 100644 --- a/source/funkin/backend/utils/NativeAPI.hx +++ b/source/funkin/backend/utils/NativeAPI.hx @@ -192,7 +192,7 @@ enum abstract CodeCursor(String) { case MOVE: MouseCursor.__MOVE; case HAND: MouseCursor.HAND; case DRAG: MouseCursor.HAND; - case DRAG_OPEN: MouseCursor.HAND; + case DRAG_OPEN: MouseCursor.ARROW; // Could be HAND, but it might be better to use ARROW since on windows it would be weird to have the dragging cursor case WAIT: MouseCursor.__WAIT; case WAIT_ARROW: MouseCursor.__WAIT_ARROW; From 688c078e4a213e311134f3c0edb0aa3d253bad44 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:36:27 +0200 Subject: [PATCH 25/89] Moved externals + small fix --- assets/data/states/StageEditor.hx | 4 ++-- commandline/Main.hx | 15 +++++++++++---- source/external/ExternalMac.hx | 11 +++++++++++ .../system/macros => external}/LinkerMacro.hx | 2 +- .../utils/native => }/external/external_code.xml | 0 .../external/include/mac/CursorHelper.h | 0 .../utils/native => }/external/include/mac/Mac.h | 0 .../native => }/external/src/mac/CursorHelper.mm | 0 .../utils/native => }/external/src/mac/Mac.mm | 0 source/funkin/backend/utils/native/Mac.hx | 11 +---------- .../editors/stage/elements/StageElementButton.hx | 2 +- 11 files changed, 27 insertions(+), 18 deletions(-) create mode 100644 source/external/ExternalMac.hx rename source/{funkin/backend/system/macros => external}/LinkerMacro.hx (96%) rename source/{funkin/backend/utils/native => }/external/external_code.xml (100%) rename source/{funkin/backend/utils/native => }/external/include/mac/CursorHelper.h (100%) rename source/{funkin/backend/utils/native => }/external/include/mac/Mac.h (100%) rename source/{funkin/backend/utils/native => }/external/src/mac/CursorHelper.mm (100%) rename source/{funkin/backend/utils/native => }/external/src/mac/Mac.mm (100%) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index e37acc0b..a458667b 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -33,7 +33,7 @@ function create() { WindowUtils.onClosing = function() { if(!FlxG.keys.pressed.ALT) { Lib.application.window.onClose.cancel(); - FlxG.switchState(new StageEditor("test")); + FlxG.switchState(new StageEditor(StageEditor.__stage)); trace("you dont need to close doofus goofus"); } } @@ -42,7 +42,7 @@ function create() { function update() { if(FlxG.keys.justPressed.R) { trace("reloading"); - FlxG.switchState(new StageEditor("test")); + FlxG.switchState(new StageEditor(StageEditor.__stage)); } } diff --git a/commandline/Main.hx b/commandline/Main.hx index 9d5ed778..b4992402 100644 --- a/commandline/Main.hx +++ b/commandline/Main.hx @@ -49,7 +49,8 @@ class Main { "If you want a full build which contains all assets, run \"cne release\" or \"cne test-release\"", "Additional arguments will be sent to the lime compiler.", "", - "-debug : Builds a debug build." + "-debug : Builds a debug build.", + "-clean : Compiled files will be deleted before compiling." ].join("\n") }, { @@ -67,7 +68,8 @@ class Main { "If you want a full build which contains all assets, run \"cne release\" or \"cne test-release\"", "Additional arguments will be sent to the lime compiler.", "", - "-debug : Builds a debug build." + "-debug : Builds a debug build.", + "-clean : Compiled files will be deleted before compiling." ].join("\n") }, { @@ -78,6 +80,7 @@ class Main { "Usage: run <optional arguments>", "", "This will run the last build that was created.", + "If the last build was a debug build, you need to pass the -debug argument to run it.", "Additional arguments will be sent to the lime compiler." ].join("\n") }, @@ -90,7 +93,9 @@ class Main { "", "This will create and run a final ready-for-release build,", "which means this build will be able to be release on websites such as GameBanana without worrying about source-dependant stuff.", - "Additional arguments will be sent to the lime compiler." + "Additional arguments will be sent to the lime compiler.", + "", + "-clean : Compiled files will be deleted before compiling." ].join("\n") }, { @@ -102,7 +107,9 @@ class Main { "", "This will create and run a final ready-for-release build,", "which means this build will be able to be release on websites such as GameBanana without worrying about source-dependant stuff.", - "Additional arguments will be sent to the lime compiler." + "Additional arguments will be sent to the lime compiler.", + "", + "-clean : Compiled files will be deleted before compiling." ].join("\n") }, { diff --git a/source/external/ExternalMac.hx b/source/external/ExternalMac.hx new file mode 100644 index 00000000..6ac4abd4 --- /dev/null +++ b/source/external/ExternalMac.hx @@ -0,0 +1,11 @@ +package external; + +#if mac +@:build(external.LinkerMacro.xml('external_code.xml')) +@:native("ExternalMac") +@:include('Mac.h') +extern class ExternalMac { + @:native("ExternalMac::setCursorIcon") + public static function setCursorIcon(icon:Int):Bool; +} +#end \ No newline at end of file diff --git a/source/funkin/backend/system/macros/LinkerMacro.hx b/source/external/LinkerMacro.hx similarity index 96% rename from source/funkin/backend/system/macros/LinkerMacro.hx rename to source/external/LinkerMacro.hx index 926bb800..3f3912b9 100644 --- a/source/funkin/backend/system/macros/LinkerMacro.hx +++ b/source/external/LinkerMacro.hx @@ -1,4 +1,4 @@ -package funkin.backend.system.macros; +package external; import haxe.io.Path; import haxe.macro.Expr; diff --git a/source/funkin/backend/utils/native/external/external_code.xml b/source/external/external_code.xml similarity index 100% rename from source/funkin/backend/utils/native/external/external_code.xml rename to source/external/external_code.xml diff --git a/source/funkin/backend/utils/native/external/include/mac/CursorHelper.h b/source/external/include/mac/CursorHelper.h similarity index 100% rename from source/funkin/backend/utils/native/external/include/mac/CursorHelper.h rename to source/external/include/mac/CursorHelper.h diff --git a/source/funkin/backend/utils/native/external/include/mac/Mac.h b/source/external/include/mac/Mac.h similarity index 100% rename from source/funkin/backend/utils/native/external/include/mac/Mac.h rename to source/external/include/mac/Mac.h diff --git a/source/funkin/backend/utils/native/external/src/mac/CursorHelper.mm b/source/external/src/mac/CursorHelper.mm similarity index 100% rename from source/funkin/backend/utils/native/external/src/mac/CursorHelper.mm rename to source/external/src/mac/CursorHelper.mm diff --git a/source/funkin/backend/utils/native/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm similarity index 100% rename from source/funkin/backend/utils/native/external/src/mac/Mac.mm rename to source/external/src/mac/Mac.mm diff --git a/source/funkin/backend/utils/native/Mac.hx b/source/funkin/backend/utils/native/Mac.hx index 0db00f42..612335e3 100644 --- a/source/funkin/backend/utils/native/Mac.hx +++ b/source/funkin/backend/utils/native/Mac.hx @@ -4,7 +4,6 @@ package funkin.backend.utils.native; import funkin.backend.utils.NativeAPI.CodeCursor; import openfl.ui.Mouse; -@:build(funkin.backend.system.macros.LinkerMacro.xml('external/external_code.xml')) @:headerInclude('sys/sysctl.h') class Mac { @:functionCode(' @@ -24,20 +23,12 @@ class Mac { public static function setMouseCursorIcon(icon:CodeCursor):Void { - final valid:Bool = ExternalMac.setCursorIcon(icon.toInt()); + final valid:Bool = external.ExternalMac.setCursorIcon(icon.toInt()); if(!valid) { Mouse.cursor = icon.toOpenFL(); } } } - -@:build(funkin.backend.system.macros.LinkerMacro.xml('external/external_code.xml')) -@:native("ExternalMac") -@:include('Mac.h') -extern class ExternalMac { - @:native("ExternalMac::setCursorIcon") - public static function setCursorIcon(icon:Int):Bool; -} #end diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index ae88b66b..65a29459 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -142,7 +142,7 @@ class StageElementButton extends UIButton { public function getInfoText():String { var pos = getPos(); - var text = '${getName()} (${CoolUtil.quantize(pos.x, 100)}x${CoolUtil.quantize(pos.y, 100)})'; + var text = '${getName()} (${CoolUtil.quantize(pos.x, 100)}, ${CoolUtil.quantize(pos.y, 100)})'; pos.put(); return text; } From f42e59eb45f0706742525afebd4ffbc8ff2c2cab Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:57:20 +0200 Subject: [PATCH 26/89] Added diagonal resizing mouse icons --- source/external/src/mac/Mac.mm | 4 ++++ source/funkin/backend/utils/NativeAPI.hx | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index 74589de1..8858ae88 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -22,6 +22,8 @@ #define RESIZE_B 18 #define RESIZE_L 19 #define RESIZE_R 20 +#define RESIZE_TLBR 21 +#define RESIZE_TRBL 22 #define CUSTOM -1 namespace ExternalMac { @@ -49,6 +51,8 @@ namespace ExternalMac { case RESIZE_B: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthCursor) defaultCursor:[NSCursor arrowCursor]]; break; case RESIZE_L: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeWestCursor) defaultCursor:[NSCursor arrowCursor]]; break; case RESIZE_R: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeEastCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_TLBR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestSouthEastCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_TRBL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastSouthWestCursor) defaultCursor:[NSCursor arrowCursor]]; break; case WAIT: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:[NSCursor arrowCursor]]; break; case WAIT_ARROW: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:[NSCursor arrowCursor]]; break; diff --git a/source/funkin/backend/utils/NativeAPI.hx b/source/funkin/backend/utils/NativeAPI.hx index fac3cce0..e1393be8 100644 --- a/source/funkin/backend/utils/NativeAPI.hx +++ b/source/funkin/backend/utils/NativeAPI.hx @@ -177,6 +177,9 @@ enum abstract CodeCursor(String) { var RESIZE_L;// = "resize_w"; var RESIZE_R;// = "resize_e"; + var RESIZE_TLBR;// = "resize_nw_se"; + var RESIZE_TRBL;// = "resize_ne_sw"; + var WAIT;// = "wait"; var WAIT_ARROW;// = "waitarrow"; var DISABLED;// = "disabled"; @@ -207,9 +210,11 @@ enum abstract CodeCursor(String) { case RESIZE_T: MouseCursor.__RESIZE_NS; case RESIZE_B: MouseCursor.__RESIZE_NS; - case RESIZE_L: MouseCursor.__RESIZE_WE; case RESIZE_R: MouseCursor.__RESIZE_WE; + + case RESIZE_TLBR: MouseCursor.__RESIZE_NWSE; + case RESIZE_TRBL: MouseCursor.__RESIZE_NESW; case CUSTOM: MouseCursor.__CUSTOM; //default: ARROW; } @@ -239,10 +244,12 @@ enum abstract CodeCursor(String) { case RESIZE_T: 17; case RESIZE_B: 18; - case RESIZE_L: 19; case RESIZE_R: 20; + case RESIZE_TLBR: 21; + case RESIZE_TRBL: 22; + case CUSTOM: -1; } } From 5bb8576b31acd506e25dae5d39f179923ac1d21d Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:02:21 +0200 Subject: [PATCH 27/89] Added a todo --- source/funkin/editors/stage/StageEditor.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index ee550b8b..315b29c0 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -747,6 +747,7 @@ class StageEditor extends UIState { } for(i=>edge in edges) { if(checkDot(buttonBoxes[i])) { + // TODO: make it show both sided arrows when resizing, unless its at minimum size then show only one currentCursor = switch(edge) { // RESIZE_NESW; //RESIZE_NS; //RESIZE_NWSE; //RESIZE_WE; case TOP_LEFT: RESIZE_TL; From 19d6e88e9e8dda7446d5e161330cf170547a5da1 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Mon, 15 Apr 2024 08:37:47 -0700 Subject: [PATCH 28/89] fixed zooming sprites except smoke? --- assets/data/states/StageEditor.hx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index a458667b..a3fbc93d 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -47,10 +47,9 @@ function update() { } function genericScale(sprite, relative, doX, doY) { - if (FlxG.keys.pressed.ALT) { - relative.x *= 2; - relative.y *= 2; - } + var relativeMult = 1 / (FlxMath.lerp(1, stageCamera.zoom, sprite.zoomFactor) / stageCamera.zoom) * (FlxG.keys.pressed.ALT ? 2 : 1); + relative.x *= relativeMult; + relative.y *= relativeMult; var width = sprite.frameWidth * storedScale.x; var height = sprite.frameHeight * storedScale.y; From 759a124fd07adcf8f591bf3492041793d41398f5 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 02:17:11 +0200 Subject: [PATCH 29/89] New button design --- source/funkin/editors/stage/StageEditor.hx | 11 ++++-- .../stage/elements/StageCharacterButton.hx | 2 +- .../stage/elements/StageElementButton.hx | 37 +++++++++++++++++-- source/funkin/editors/ui/UIButtonList.hx | 3 +- source/funkin/editors/ui/UISliceSprite.hx | 22 ++++------- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 315b29c0..5e531a93 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -54,6 +54,9 @@ class StageEditor extends UIState { public var showOutlines:Bool = true; public var showCharacters:Bool = true; + public static inline var SPRITE_WINDOW_WIDTH:Int = 400; + public static inline var SPRITE_WINDOW_BUTTON_HEIGHT:Int = 64; + public var undos:UndoList<StageChange> = new UndoList<StageChange>(); public inline static function exID(id:String) { @@ -242,14 +245,16 @@ class StageEditor extends UIState { topMenuSpr = new UITopMenu(topMenu); topMenuSpr.cameras = uiGroup.cameras = [uiCamera]; - final margin = 22; - final width = 470; + final margin = 0;//22; + final width = SPRITE_WINDOW_WIDTH; final TOP_MENU_HEIGHT = 25; - var buttonSize:FlxPoint = FlxPoint.get(width-margin*2, 32); + var buttonSize:FlxPoint = FlxPoint.get(width-margin*2, SPRITE_WINDOW_BUTTON_HEIGHT); stageSpritesWindow = new UIButtonList<StageElementButton>(Std.int(FlxG.width - width), TOP_MENU_HEIGHT, width, Std.int(FlxG.height - TOP_MENU_HEIGHT), "Stage Sprites", buttonSize); stageSpritesWindow.collapsable = true; + stageSpritesWindow.topAlpha = 0.9; stageSpritesWindow.middleAlpha = 0.5; stageSpritesWindow.bottomAlpha = 0.5; + stageSpritesWindow.buttonSpacing = 0; stageSpritesWindow.addButton.callback = () -> { // TODO: implement this } diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index 2ccf6051..cf984d76 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -13,7 +13,7 @@ class StageCharacterButton extends StageElementButton { this.char = charPos.extra.get(StageEditor.exID("char")); super(x,y, xml); - color = 0xffa5c4ff; + color = 0xff7aa8ff; updateInfo(charPos); } diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index 65a29459..d8137986 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -21,14 +21,26 @@ class StageElementButton extends UIButton { public var selected:Bool = false; + public var tagColor:UISliceSprite; + public function new(x:Float,y:Float, xml:Access) { this.xml = xml; super(x,y, getInfoText(), function () { onSelect(); //CharacterEditor.instance.playAnimation(this.sprite.name); - }, 282); + }, StageEditor.SPRITE_WINDOW_WIDTH, StageEditor.SPRITE_WINDOW_BUTTON_HEIGHT); autoAlpha = false; + tagColor = new UISliceSprite(x, y, 10, StageEditor.SPRITE_WINDOW_BUTTON_HEIGHT, 'editors/ui/button'); + tagColor.alpha = 1; // Make entire sprite transparent + tagColor.selectable = false; + tagColor.active = false; + //members.push(tagColor); + + topAlpha = middleAlpha = bottomAlpha = 0.7; + + field.alignment = LEFT; + ghostButton = new UIButton(x+282+17, y, "", function () { onGhostClick(); //CharacterEditor.instance.ghostAnim(this.anim); @@ -77,6 +89,9 @@ class StageElementButton extends UIButton { hovered = !deleteButton.hovered; updatePos(); super.update(elapsed); + field.x += 12; + + tagColor.color = color; if(selected != _lastSelected) { _lastSelected = selected; @@ -104,12 +119,23 @@ class StageElementButton extends UIButton { public function updatePos() { // buttons - deleteButton.x = (editButton.x = (ghostButton.x = (x+282+17))+32+17)+32+17; - deleteButton.y = editButton.y = ghostButton.y = y; + var spacing = 8; + var buttonY = y + (bHeight - 32) / 2; + deleteButton.x = bWidth - deleteButton.bWidth - spacing; + deleteButton.y = buttonY; + editButton.x = deleteButton.x - editButton.bWidth - spacing; + editButton.y = buttonY; + ghostButton.x = editButton.x - ghostButton.bWidth - spacing; + ghostButton.y = buttonY; + //deleteButton.x = (editButton.x = (ghostButton.x = (x+282+17))+32+17)+32+17; + //deleteButton.y = editButton.y = ghostButton.y = y; // icons ghostIcon.x = ghostButton.x + 8; ghostIcon.y = ghostButton.y + 8; editIcon.x = editButton.x + 8; editIcon.y = editButton.y + 8; deleteIcon.x = deleteButton.x + (15/2); deleteIcon.y = deleteButton.y + 8; + + tagColor.x = x;// + bWidth - tagColor.bWidth; + tagColor.y = y; } public function getSprite():FunkinSprite { @@ -143,6 +169,11 @@ class StageElementButton extends UIButton { public function getInfoText():String { var pos = getPos(); var text = '${getName()} (${CoolUtil.quantize(pos.x, 100)}, ${CoolUtil.quantize(pos.y, 100)})'; + var sprite = getSprite(); + if(sprite != null) { + text += '\nScale: (${CoolUtil.quantize(sprite.scale.x, 100)}, ${CoolUtil.quantize(sprite.scale.y, 100)})'; + text += '\nScroll: (${CoolUtil.quantize(sprite.scrollFactor.x, 100)}, ${CoolUtil.quantize(sprite.scrollFactor.y, 100)})'; + } pos.put(); return text; } diff --git a/source/funkin/editors/ui/UIButtonList.hx b/source/funkin/editors/ui/UIButtonList.hx index c516c73d..2253460d 100644 --- a/source/funkin/editors/ui/UIButtonList.hx +++ b/source/funkin/editors/ui/UIButtonList.hx @@ -95,7 +95,8 @@ class UIButtonList<T:UIButton> extends UIWindow { curMovingInterval = 0; } } - addIcon.x = addButton.x + addButton.bWidth / 2 - addIcon.width / 2; addIcon.y = addButton.y + addButton.bHeight / 2 - addIcon.height / 2; + addIcon.x = addButton.x + addButton.bWidth / 2 - addIcon.width / 2; + addIcon.y = addButton.y + addButton.bHeight / 2 - addIcon.height / 2; } var nextscrollY:Float = 0; public override function update(elapsed:Float) { diff --git a/source/funkin/editors/ui/UISliceSprite.hx b/source/funkin/editors/ui/UISliceSprite.hx index a6a6afd5..8cc6ab2d 100644 --- a/source/funkin/editors/ui/UISliceSprite.hx +++ b/source/funkin/editors/ui/UISliceSprite.hx @@ -31,17 +31,9 @@ class UISliceSprite extends UISprite { bHeight = h; } - override function set_alpha(value:Float) { - super.set_alpha(value); - topAlpha = alpha; - middleAlpha = alpha; - bottomAlpha = alpha; - return value; - } - - public var topAlpha:Float = 1; - public var middleAlpha:Float = 1; - public var bottomAlpha:Float = 1; + public var topAlpha:Null<Float> = null; + public var middleAlpha:Null<Float> = null; + public var bottomAlpha:Null<Float> = null; public var drawTop:Bool = true; public var drawMiddle:Bool = true; @@ -102,8 +94,8 @@ class UISliceSprite extends UISprite { var oldAlpha = alpha; // TOP if (drawTop) { - super.set_alpha(topAlpha); // TOP LEFT + if(topAlpha != null) alpha = topAlpha; frame = topleft; setPosition(x, y); __setSize( @@ -132,7 +124,7 @@ class UISliceSprite extends UISprite { // MIDDLE if (drawMiddle && bHeight > top.frame.height + bottom.frame.height) { - super.set_alpha(middleAlpha); + if(middleAlpha != null) alpha = middleAlpha; var middleHeight:Float = bHeight - (topleft.frame.height * Math.min(bHeight/(topleft.frame.height*2), 1)) - bottomleft.frame.height * Math.min(bHeight/(bottomleft.frame.height*2), 1); @@ -159,7 +151,7 @@ class UISliceSprite extends UISprite { // BOTTOM if (drawBottom) { - super.set_alpha(bottomAlpha); + if(bottomAlpha != null) alpha = bottomAlpha; // BOTTOM LEFT frame = bottomleft; setPosition(x, y + bHeight - (bottomleft.frame.height * Math.min(bHeight/(bottomleft.frame.height*2), 1))); @@ -190,7 +182,7 @@ class UISliceSprite extends UISprite { super.drawSuper(); } - super.set_alpha(oldAlpha); + alpha = oldAlpha; } setPosition(x, y); From eb2724fe86ff8c66527be375fa9e54886b1e7efc Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 02:18:01 +0200 Subject: [PATCH 30/89] Remove showOutlines toggle --- source/funkin/editors/stage/StageEditor.hx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 5e531a93..d5e39655 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -51,7 +51,6 @@ class StageEditor extends UIState { public var storedPos:FlxPoint = new FlxPoint(); public var storedScale:FlxPoint = new FlxPoint(); - public var showOutlines:Bool = true; public var showCharacters:Bool = true; public static inline var SPRITE_WINDOW_WIDTH:Int = 400; @@ -141,12 +140,6 @@ class StageEditor extends UIState { { label: "Editor", childs: [ - { - label: "Show Outlines", - //keybind: [CONTROL, NUMPADPLUS], - onSelect: _editor_showOutlines, - icon: showOutlines ? 1 : 0 - }, { label: "Show Characters", //keybind: [CONTROL, NUMPADMINUS], @@ -587,11 +580,6 @@ class StageEditor extends UIState { setZoom(stage.defaultZoom); } - function _editor_showOutlines(t) { - showOutlines = !showOutlines; - t.icon = showOutlines ? 1 : 0; - } - function _editor_showCharacters(t) { showCharacters = !showCharacters; t.icon = showCharacters ? 1 : 0; @@ -606,7 +594,6 @@ class StageEditor extends UIState { override function draw() { super.draw(); - if(!showOutlines) return; mousePoint = FlxG.mouse.getWorldPosition(stageCamera, mousePoint); if(dot == null) { dot = new FlxSprite().makeGraphic(30, 30, FlxColor.WHITE); From ded62283ffd35e56a93ce7ee281928eec8df06c5 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 02:51:27 +0200 Subject: [PATCH 31/89] Added dragging + Fixed bug with cursor icon --- source/funkin/editors/stage/StageEditor.hx | 6 ++++++ .../stage/elements/StageElementButton.hx | 18 +++++++++++++++--- source/funkin/editors/ui/UIButton.hx | 6 +++++- source/funkin/editors/ui/UIState.hx | 6 ++---- source/funkin/editors/ui/UIWindow.hx | 4 ++++ 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index d5e39655..51f8c3bb 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -248,6 +248,12 @@ class StageEditor extends UIState { stageSpritesWindow.middleAlpha = 0.5; stageSpritesWindow.bottomAlpha = 0.5; stageSpritesWindow.buttonSpacing = 0; + stageSpritesWindow.dragCallback = (button, oldID, newID) -> { + var sprite:FunkinSprite = button.getSprite(); + var idx = members.indexOf(sprite); + members.splice(idx, 1); + members.insert(newID, sprite); + } stageSpritesWindow.addButton.callback = () -> { // TODO: implement this } diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index d8137986..49194d5d 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -92,17 +92,29 @@ class StageElementButton extends UIButton { field.x += 12; tagColor.color = color; + } - if(selected != _lastSelected) { - _lastSelected = selected; + //private var _lastHovered:Bool = false; + + public override function draw() { + //if(_lastHovered != (_lastHovered = hovered && !pressed)) { + if(_lastSelected != (_lastSelected = selected)) { updateColorTransform(); } + super.draw(); } + /*public override function setFrameOffset() { + var _frameOffset = 0; + if(selected) _frameOffset = 9; + if(hovered && pressed) _frameOffset = 18; + framesOffset = _frameOffset; + }*/ + public override function updateColorTransform() { super.updateColorTransform(); - if (selected) { + if(selected) { useColorTransform = true; colorTransform.setOffsets(70, 70, 70, 0); } else { diff --git a/source/funkin/editors/ui/UIButton.hx b/source/funkin/editors/ui/UIButton.hx index bb10fad9..46bc30b5 100644 --- a/source/funkin/editors/ui/UIButton.hx +++ b/source/funkin/editors/ui/UIButton.hx @@ -38,7 +38,11 @@ class UIButton extends UISliceSprite { } public override function draw() { - framesOffset = hovered ? (pressed ? 18 : 9) : 0; + setFrameOffset(); super.draw(); } + + public function setFrameOffset() { + framesOffset = hovered ? (pressed ? 18 : 9) : 0; + } } \ No newline at end of file diff --git a/source/funkin/editors/ui/UIState.hx b/source/funkin/editors/ui/UIState.hx index ea2f6781..953a4f07 100644 --- a/source/funkin/editors/ui/UIState.hx +++ b/source/funkin/editors/ui/UIState.hx @@ -105,14 +105,12 @@ class UIState extends MusicBeatState { FlxG.sound.keysAllowed = currentFocus != null ? !(currentFocus is UITextBox) : true; - if (hoveredSprite != null) { + if (hoveredSprite != null && hoveredSprite.cursor != null) { NativeAPI.setCursorIcon(hoveredSprite.cursor); - //Mouse.cursor = hoveredSprite.cursor; - hoveredSprite = null; } else { NativeAPI.setCursorIcon(currentCursor); - //Mouse.cursor = currentCursor; } + hoveredSprite = null; } public override function destroy() { diff --git a/source/funkin/editors/ui/UIWindow.hx b/source/funkin/editors/ui/UIWindow.hx index 84fb80e4..29abb538 100644 --- a/source/funkin/editors/ui/UIWindow.hx +++ b/source/funkin/editors/ui/UIWindow.hx @@ -31,6 +31,10 @@ class UIWindow extends UISliceSprite { drawMiddle = !drawMiddle; drawBottom = !drawBottom; } + } else { + if(!content.exists) { + cursor = null; + } } } From a7de29dd5fa0a8e895c65c08315ed5f87123e459 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Mon, 15 Apr 2024 17:59:43 -0700 Subject: [PATCH 32/89] modify closing --- assets/data/states/StageEditor.hx | 38 +++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index a3fbc93d..9f731f91 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -8,6 +8,7 @@ */ import funkin.editors.stage.StageEditor; +import funkin.editors.ui.UIWarningSubstate; import funkin.backend.utils.WindowUtils; import openfl.Lib; @@ -27,18 +28,47 @@ function tryUpdateHitbox(sprite) { return false; } +var allowClose = false; function create() { WindowUtils.preventClosing = true; WindowUtils.resetClosing(); WindowUtils.onClosing = function() { - if(!FlxG.keys.pressed.ALT) { + if(!allowClose) Lib.application.window.onClose.cancel(); - FlxG.switchState(new StageEditor(StageEditor.__stage)); - trace("you dont need to close doofus goofus"); - } + + var substate; + substate = new UIWarningSubstate("nuh uh", "you dont need to close goofus doofus", [ + { + label: "Actually Exit", + onClick: function(t) { + allowClose = true; + Lib.application.window.close(); + } + }, + { + label: "Reload State", + onClick: function(t) { + FlxG.switchState(new StageEditor(StageEditor.__stage)); + } + }, + { + label: "oh whoops", + onClick: function(t) { + substate.close(); + } + } + ]); + + openSubState(substate); } } +function destroy() { + WindowUtils.preventClosing = false; + WindowUtils.resetClosing(); + WindowUtils.onClosing = null; +} + function update() { if(FlxG.keys.justPressed.R) { trace("reloading"); From 7fc83f340e08da140344b662da57fcdff9beb2e1 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 03:37:23 +0200 Subject: [PATCH 33/89] Added radio buttons (wip image) --- .../layouts/stage/spriteEditScreen.xml | 7 +- assets/images/editors/ui/radiobutton.png | Bin 0 -> 1073 bytes source/funkin/editors/stage/StageEditor.hx | 4 + .../editors/stage/StageSpriteEditScreen.hx | 5 +- source/funkin/editors/ui/UICheckbox.hx | 4 +- source/funkin/editors/ui/UIRadioButton.hx | 105 ++++++++++++++++++ source/funkin/editors/ui/UISoftcodedWindow.hx | 11 ++ 7 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 assets/images/editors/ui/radiobutton.png create mode 100644 source/funkin/editors/ui/UIRadioButton.hx diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index d84b8500..a0684432 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -47,6 +47,8 @@ <set name="curY" value="angleStepper.y + angleStepper.bHeight + YOFFSET" /> <checkbox name="antialiasingCheckbox" text="Antialiasing" value="sprite.antialiasing" x="20 + (200 + XOFFSET) * 0" y="curY" /> + <radio for="memoryCheck" name="highMemoryRadio" text="High Memory Only" value="getEx('highMemory')" x="20 + (200 + XOFFSET) * 1" y="curY" /> + <radio for="memoryCheck" name="lowMemoryRadio" text="Low Memory Only" value="getEx('lowMemory')" x="20 + (200 + XOFFSET) * 2" y="curY" /> <!-- TODO: Animation list --> @@ -69,7 +71,10 @@ function onSave() { sprite.name = nameTextBox.label.text; - sprite.extra.set(exID("imageFile"), spriteTextBox.label.text); + setEx("imageFile", spriteTextBox.label.text); + + setEx("highMemory", highMemoryRadio.checked); + setEx("lowMemory", lowMemoryRadio.checked); sprite.x = xStepper.value; sprite.y = yStepper.value; diff --git a/assets/images/editors/ui/radiobutton.png b/assets/images/editors/ui/radiobutton.png new file mode 100644 index 0000000000000000000000000000000000000000..a6f7dbce1fe774fc28b2a014ca256df2234cd453 GIT binary patch literal 1073 zcmeAS@N?(olHy`uVBq!ia0vp^0YEIm!3-pI*}R@IFfi5z_=LCuxkYZBh0g6dIy&0g z+D4ML`r=kVE|3jmoSFF_i2gqLe|qnQ*49>JHkulUN+6l%*s7(ar6+0$*98}WsDX$B z*$@Na8sX~UA`nKlV?&mGeWq1?re#B#Wlg$SeUfQKl2K)XVMVNANu+i`q*h^=R&IoP zL5Om8pkk)KT)MApiic!^yJ&)oP^_k=riO-wGk=V_y1JU0ngf4?s;a7rii)zbvXYXL zqN1X_yu6OEg`Aw6mXN8etgMWTjI^}02EVB~pRuH*q=bZoDvy!4xVV^@n5d|zGKap1 zh=?MGo&vj$kdTm|prC+&fGmp!KR>@LlNKKzpA>_-B!h}LgR&Tdq9}u$FoUcxgNy)! zqyU3BKZ6(_gD^LP04D<<2LlfW1NZy>!=1ngFf9r43ua&h1E8TI5<oWuBqt}Qrl!_6 zw6wN$c6KgUu;A#?qvy_Fym;Z_rS~5`e*XOV+xH*;u70+D!@$6#=jq}YQgLhV)VtZ2 z6GV=k|2@^D@L1lq)y+Y!YYilV97T?=+w-CS+o9ElfiBB<Twb?KJ@h8(y4q~d$=^>; zHkrNmW$0@DmIKb`-q$=i%h?#i$ZsQlNhL@yCbO4)DwogliM#fE%ZsZP-{8QazfCSj z*z17QZ&j(+GxrN#;dDHIE3qVx+drgv`IN=W&$MSKi8E<$<x5T7VAj4^^H$zk&l$Rt z1af~b7O`Ew?YO1B&C)CXG$I+Elw0*&UKGOZ_VVz2t`}jGjd;$c_L}_-X7)?=uUPjm zLvxl|QT>Fo0(Ajj75NVDV7WH$d8Qy|$LY!Yr4PPk?=f7k<U!-LUq8gJ#P6E-U`xe0 zjhRdG+gKllUDkhBXs^@YnCl*J%wl1}noGA%ES|X1+(Nl0fcr>9?p7(Dlh4-avn)ND z(KFG=&SLk8%G@Bc?A?imf5h)7HcfX>&0ThHmb;ID->HPvYp&csp}oB;IiYoVA<yJ5 zUnPF;eSdK3BzZ%o_irtHINC%R!xk;Qa&zL%BqnFc1?*CXm)fcB&R#c}+0ckR?d8*h zoClu8{#ZTPm?dvJE0d)e^NkLt1#e#Q&P!LA(r9LOe(|}J#`g~&oEG{xV)Bo_;SKGt ziw}G(XDN$nvgCWt(-^f<=kliXnsWgy$^ntRL57uYs$WcdE;?7`-yhBgob#Dq^=q^1 z-7ng0#XhHGdc9`vHJJ_O5pOrnlso?aQG)*ems_<q|EhY}HSKV3!rkT+p?`5zwSSkh d?tT@2K>o*UG2<s@6F>z5gQu&X%Q~loCIEOh#2Ekp literal 0 HcmV?d00001 diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 51f8c3bb..5a46371f 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -187,6 +187,10 @@ class StageEditor extends UIState { sprite.extra.set(exID("node"), node); sprite.extra.set(exID("type"), node.name); sprite.extra.set(exID("imageFile"), '${node.getAtt("sprite").getDefault(sprite.name)}'); + var parent = new Access(node.x.parent); + sprite.extra.set(exID("parentNode"), parent); + sprite.extra.set(exID("highMemory"), parent.name == "highMemory"); + sprite.extra.set(exID("lowMemory"), parent.name == "lowMemory"); //sprite.active = false; } if(sprite is StageCharPos) { diff --git a/source/funkin/editors/stage/StageSpriteEditScreen.hx b/source/funkin/editors/stage/StageSpriteEditScreen.hx index b220c6df..c221b9fa 100644 --- a/source/funkin/editors/stage/StageSpriteEditScreen.hx +++ b/source/funkin/editors/stage/StageSpriteEditScreen.hx @@ -20,7 +20,10 @@ class StageSpriteEditScreen extends UISoftcodedWindow { "exID" => StageEditor.exID, "getEx" => function(name:String):Dynamic { return sprite.extra.get(StageEditor.exID(name)); - } + }, + "setEx" => function(name:String, value:Dynamic) { + sprite.extra.set(StageEditor.exID(name), value); + }, ]); } diff --git a/source/funkin/editors/ui/UICheckbox.hx b/source/funkin/editors/ui/UICheckbox.hx index d3c777b9..426857a5 100644 --- a/source/funkin/editors/ui/UICheckbox.hx +++ b/source/funkin/editors/ui/UICheckbox.hx @@ -10,14 +10,14 @@ class UICheckbox extends UISprite { public function new(x:Float, y:Float, text:String, checked:Bool = false, w:Int = 0) { super(x, y); loadGraphic(Paths.image('editors/ui/checkbox'), true, 20, 20); - for(frame=>name in ["normal", "hover", "pressed", "checkmark"]) + for(frame=>name in ["normal", "hover", "pressed", "selected"]) animation.add(name, [frame], 0, false); this.checked = checked; field = new UIText(x, y, w, text); check = new FlxSprite().loadGraphicFromSprite(this); - check.animation.play("checkmark"); + check.animation.play("selected"); members.push(check); members.push(field); diff --git a/source/funkin/editors/ui/UIRadioButton.hx b/source/funkin/editors/ui/UIRadioButton.hx new file mode 100644 index 00000000..ebff277a --- /dev/null +++ b/source/funkin/editors/ui/UIRadioButton.hx @@ -0,0 +1,105 @@ +package funkin.editors.ui; + +import flixel.util.typeLimit.OneOfTwo; + +class UIRadioButton extends UISprite { + public var checked:Bool = false; + public var onChecked:Bool->Void = null; + + public var field:UIText; + public var check:FlxSprite; + + public var parent:OneOfTwo<UIWindow, UISubstateWindow> = null; + public var forID:String = null; + + public function new(x:Float, y:Float, text:String, checked:Bool = false, forID:String = null, w:Int = 0) { + super(x, y); + this.forID = forID; + loadGraphic(Paths.image('editors/ui/radiobutton'), true, 20, 20); + for(frame=>name in ["normal", "hover", "pressed", "selected"]) + animation.add(name, [frame], 0, false); + + this.checked = checked; + this.targetScale = checked ? 1 : 0; + + field = new UIText(x, y, w, text); + check = new FlxSprite().loadGraphicFromSprite(this); + check.animation.play("selected"); + check.scale.set(targetScale, targetScale); + + members.push(check); + members.push(field); + + cursor = CLICK; + + autoAlpha = false; + } + + public var targetScale:Float = 1; + + public override function update(elapsed:Float) { + // ANIMATION HANDLING + animation.play(hovered ? (pressed ? "pressed" : "hover") : "normal"); + + // CHECKMARK HANDLING + if(autoAlpha) + check.alpha = checked ? 1 : 0; + check.scale.x = CoolUtil.fpsLerp(check.scale.x, targetScale, 0.25); + check.scale.y = CoolUtil.fpsLerp(check.scale.y, targetScale, 0.25); + + // POSITION HANDLING + updatePositions(); + + super.update(elapsed); + } + + public inline function updatePositions() { + check.follow(this); + field.follow(this, 25, 0); + } + + public override function draw() { + updatePositions(); + super.draw(); + } + + public override function onHovered() { + super.onHovered(); + if (FlxG.mouse.justReleased) { + // clicked + checked = !checked; + check.scale.set(1.25, 1.25); + targetScale = checked ? 1 : 0; + + if (Options.editorSFX) + CoolUtil.playMenuSFX(checked ? CHECKED : UNCHECKED, 0.5); + + if(parent != null) { + var members = (parent is UIWindow) ? (cast(parent, UIWindow)).members : (cast(parent, UISubstateWindow)).members; + var radios:Array<UIRadioButton> = cast members.filter((o) -> o is UIRadioButton && o != this); + //trace(radios); + for(radio in radios) { + if(radio.forID != null && radio.forID == forID) { + radio.checked = false; + radio.targetScale = 0; + } + } + } + + if (onChecked != null) + onChecked(checked); + } + } + + public override function updateButton() { + __rect.x = x; + __rect.y = y; + __rect.width = field.width + 30; + __rect.height = field.height > height ? field.height : height; + UIState.state.updateRectButtonHandler(this, __rect, onHovered); + } + + public override function toString() { + return "RadioButton(" + field.text + ", " + checked + ", " + forID + ")"; + } +} \ No newline at end of file diff --git a/source/funkin/editors/ui/UISoftcodedWindow.hx b/source/funkin/editors/ui/UISoftcodedWindow.hx index 49947b8d..ff751fec 100644 --- a/source/funkin/editors/ui/UISoftcodedWindow.hx +++ b/source/funkin/editors/ui/UISoftcodedWindow.hx @@ -45,6 +45,7 @@ class UISoftcodedWindow extends UISubstateWindow { } function execString(input:String):String { + if(input == null) return null; if(input.indexOf("${") == -1) return input; var text = ""; while(input.length > 0) { @@ -109,6 +110,10 @@ class UISoftcodedWindow extends UISubstateWindow { } set("self", this); set("hasSaveButtons", true); + set("getRadioButtons", function(forID:String) { + var radios:Array<UIRadioButton> = cast members.filter((o) -> o is UIRadioButton); + return cast radios.filter((o) -> o.forID == forID); + }); for(k=>v in customVariables) { set(k, v); } @@ -178,6 +183,12 @@ class UISoftcodedWindow extends UISubstateWindow { add(checkbox); addLabelOn(checkbox, label); checkbox; + case "radio": + var radio = new UIRadioButton(x, y, text, execAtt(el, "value", false), execString(el.getAtt("for"))); + radio.parent = this; + add(radio); + addLabelOn(radio, label); + radio; case "slider": var slider = new UISlider(x, y, width, execAtt(el, "value", 0), execAtt(el, "segments", []), execAtt(el, "centered", false)); add(slider); From b33a02152a4d0fe6ff1f501bd5ddb66c0b0defec Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 04:54:27 +0200 Subject: [PATCH 34/89] Added simplistic notifications --- source/funkin/editors/import.hx | 1 + source/funkin/editors/stage/StageEditor.hx | 10 +- .../stage/elements/StageCharacterButton.hx | 6 + source/funkin/editors/ui/UIState.hx | 20 +++ .../ui/notifications/UIBaseNotification.hx | 166 ++++++++++++++++++ 5 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 source/funkin/editors/ui/notifications/UIBaseNotification.hx diff --git a/source/funkin/editors/import.hx b/source/funkin/editors/import.hx index 3d64ccc2..de888fa0 100644 --- a/source/funkin/editors/import.hx +++ b/source/funkin/editors/import.hx @@ -3,6 +3,7 @@ package funkin.editors; import flixel.math.FlxPoint; import funkin.editors.ui.*; +import funkin.editors.ui.notifications.*; using funkin.editors.ui.UIUtil; #end \ No newline at end of file diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 5a46371f..463accdb 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -41,7 +41,7 @@ class StageEditor extends UIState { public var charMap:Map<String, Character> = []; public var stageCamera:FlxCamera; - public var guideCamera:FlxCamera; + //public var guideCamera:FlxCamera; public var uiCamera:FlxCamera; public var selection:Selection = new Selection(); @@ -152,13 +152,15 @@ class StageEditor extends UIState { stageCamera = FlxG.camera; - guideCamera = new FlxCamera(); - guideCamera.bgColor = 0; + //guideCamera = new FlxCamera(); + //guideCamera.bgColor = 0; uiCamera = new FlxCamera(); uiCamera.bgColor = 0; - FlxG.cameras.add(guideCamera, false); + uiCameras = [uiCamera]; + + //FlxG.cameras.add(guideCamera, false); FlxG.cameras.add(uiCamera, false); // Load from xml diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index cf984d76..905cdc99 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -41,7 +41,13 @@ class StageCharacterButton extends StageElementButton { } public override function onSelect() { + UIState.state.displayNotification(new UIBaseNotification("Selecting a character isnt implemented yet!", 2, BOTTOM_LEFT)); + CoolUtil.playMenuSFX(WARNING, 0.45); + } + public override function onEdit() { + UIState.state.displayNotification(new UIBaseNotification("Editing a character isnt implemented yet!", 2, BOTTOM_LEFT)); + CoolUtil.playMenuSFX(WARNING, 0.45); } public override function onGhostClick() { diff --git a/source/funkin/editors/ui/UIState.hx b/source/funkin/editors/ui/UIState.hx index 953a4f07..c1716104 100644 --- a/source/funkin/editors/ui/UIState.hx +++ b/source/funkin/editors/ui/UIState.hx @@ -1,5 +1,6 @@ package funkin.editors.ui; +import funkin.editors.ui.notifications.UIBaseNotification; import flixel.math.FlxPoint; import flixel.math.FlxRect; import funkin.backend.system.framerate.Framerate; @@ -22,6 +23,8 @@ class UIState extends MusicBeatState { public var currentCursor:CodeCursor = ARROW; + public var uiCameras:Array<FlxCamera> = []; + private var __rect:FlxRect; private var __mousePos:FlxPoint; @@ -144,4 +147,21 @@ class UIState extends MusicBeatState { state.openSubState(curContextMenu = new UIContextMenu(options, callback, x.getDefault(__mousePos.x), y.getDefault(__mousePos.y))); return curContextMenu; } + + public function displayNotification(notification:UIBaseNotification) { + notification.cameras = uiCameras; + notification.onRemove = (notif) -> { + notification.onRemove = null; + remove(notif, true); + }; + add(notification); + notification.update(0); + notification.appearAnimation(); + // TODO: future tooltips + //notification.x = __mousePos.x; + //notification.y = __mousePos.y; + //notification.alpha = 0; + //notification.appearAnimation(); + //FlxTween.tween(notification, {x: __mousePos.x, y: __mousePos.y, alpha: 1}, .3, {ease: FlxEase.circInOut}); + } } \ No newline at end of file diff --git a/source/funkin/editors/ui/notifications/UIBaseNotification.hx b/source/funkin/editors/ui/notifications/UIBaseNotification.hx new file mode 100644 index 00000000..b86ba3c7 --- /dev/null +++ b/source/funkin/editors/ui/notifications/UIBaseNotification.hx @@ -0,0 +1,166 @@ +package funkin.editors.ui.notifications; + +import flixel.group.FlxGroup; +import flixel.math.FlxRect; +import flixel.tweens.FlxTween; +import flixel.util.FlxTimer; + +using flixel.util.FlxSpriteUtil; + +class UIBaseNotification extends UISliceSprite { + public var textField:UIText; + public var closeButton:UIButton; + + public var onRemove:(notif:UIBaseNotification)->Void = null; + + public var showedAnimation:Bool = false; + public var closed:Bool = false; + + public function new(text:String, showTimer:Float = 5, corner:Corner = BOTTOM_LEFT) { + super(x, y, 340, 46, "editors/ui/inputbox"); + + closeButton = new UIButton(0, 0, "X", () -> { + if (closed) return; + closed = true; + + (new FlxTimer()).start(0.2, (_) -> {disappearAnimation();}); + }, 32, 32); + closeButton.hoverCallback = () -> { + closeButton.color = 0xFFAC3D3D; + closeButton.field.color = 0xFFffffff; + //closeButton.field.color = closeButton.hovered ? 0xFFffffff : 0xFF7f7f7f; + } + closeButton.autoAlpha = false; + closeButton.alpha = 0.0; + + textField = new UIText(0, 0, 0, text, 14); + textField.alignment = LEFT; + textField.fieldWidth = bWidth - 32 - 8; + members.push(textField); + + if(textField.height > bHeight) + bHeight = Std.int(textField.height); + + alpha = 0; + textField.alpha = 0; + + showingTimer = showTimer; + + members.push(closeButton); + + var margin = 20; + + switch(corner) { + case TOP_LEFT: + x = margin; + y = margin; + case TOP_RIGHT: + x = FlxG.width - bWidth - margin; + y = margin; + case BOTTOM_LEFT: + x = margin; + y = FlxG.height - bHeight - margin; + case BOTTOM_RIGHT: + x = FlxG.width - bWidth - margin; + y = FlxG.height - bHeight - margin; + } + + defaultX = x; + defaultY = y; + + switch(corner) { + case TOP_LEFT | BOTTOM_LEFT: + x -= bWidth - margin - 20; + case TOP_RIGHT | BOTTOM_RIGHT: + x += bWidth - margin - 20; + } + + closingX = x; + closingY = y; + + alpha = 0; + } + + public var defaultX:Float = 0; + public var defaultY:Float = 0; + + public var closingX:Float = 0; + public var closingY:Float = 0; + + public var showingTimer:Float = 5; + public var timerActive:Bool = false; + + public var progress:Float = 0; + public override function update(elapsed:Float) { + closeButton.color = 0xFFFFFFFF; + closeButton.field.color = 0xFF7f7f7f; + super.update(elapsed); + + if(timerActive) { + showingTimer -= elapsed; + if(showingTimer <= 0) { + timerActive = false; + idleDisappearAnimation(); + } + } + + textField.follow(this, 5, bHeight / 2 - textField.height / 2); + closeButton.follow(this, bWidth-closeButton.bWidth - 7, bHeight / 2 - closeButton.bHeight / 2); + closeButton.field.alpha = alpha * .7; + //closeButton.alpha = alpha; + textField.alpha = alpha; + } + + public function appearAnimation() { + x = closingX; alpha=0; FlxTween.cancelTweensOf(this, ["x", "alpha"]); + FlxTween.tween(this, {x: defaultX}, .4, {ease: FlxEase.circInOut}); + FlxTween.tween(this, {alpha: 1}, .3, {ease: FlxEase.sineOut, startDelay: .1, onComplete: (_) -> { + if(showingTimer > 0) timerActive = true; + }}); + + showedAnimation = true; + } + + public var isClosing:Bool = false; + + public function disappearAnimation() { + if (isClosing) return; + isClosing = true; + + // TODO: make it so you can click through the notification + closeButton.active = false; + closeButton.selectable = false; + closeButton.canBeHovered = false; + selectable = false; + canBeHovered = false; + + x = defaultX; alpha = 1; FlxTween.cancelTweensOf(this, ["x", "alpha"]); + FlxTween.tween(this, {alpha: 0}, .3, {ease: FlxEase.sineOut, onComplete: (_) -> { + if(onRemove != null) onRemove(this); + destroy(); + }}); + + showedAnimation = false; + } + + public function idleDisappearAnimation() { + if (isClosing) return; + isClosing = true; + + x = defaultX; alpha = 1; FlxTween.cancelTweensOf(this, ["x", "alpha"]); + FlxTween.tween(this, {alpha: 0}, .3, {ease: FlxEase.sineOut}); + FlxTween.tween(this, {x: closingX}, .4, {ease: FlxEase.circInOut, onComplete: (_) -> { + if(onRemove != null) onRemove(this); + destroy(); + }}); + + showedAnimation = false; + } +} + +enum abstract Corner(Int) { + var TOP_LEFT = 0; + var TOP_RIGHT = 1; + var BOTTOM_LEFT = 2; + var BOTTOM_RIGHT = 3; +} \ No newline at end of file From 36ac2f0cf54740dc7055e08496385625aa28f128 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 13:02:02 +0200 Subject: [PATCH 35/89] Added selection helpers --- source/funkin/editors/stage/StageEditor.hx | 120 +++++++++++++++++---- 1 file changed, 98 insertions(+), 22 deletions(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 463accdb..b552d415 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -100,6 +100,42 @@ class StageEditor extends UIState { } ] }, + /*{ + label: "Edit", + childs: [ + { + label: "Undo", + keybind: [CONTROL, Z], + onSelect: _edit_undo, + }, + { + label: "Redo", + keybind: [CONTROL, SHIFT, Z], + onSelect: _edit_redo, + }, + null, + ] + },*/ + { + label: "Select", + childs: [ + { + label: "All", + keybind: [CONTROL, A], + onSelect: (_) -> _select_all(_), + }, + { + label: "Deselect", + keybind: [CONTROL, D], + onSelect: (_) -> _select_deselect(_), + }, + { + label: "Inverse", + keybind: [CONTROL, SHIFT, I], + onSelect: (_) -> _select_inverse(_), + }, + ] + }, { label: "View", childs: [ @@ -381,9 +417,12 @@ class StageEditor extends UIState { } }*/ - for(sprite in selection) { - if(sprite is FunkinSprite) { - handleSelection(cast sprite); + // TODO: make this work with multiple selections + if(selection.length == 1) { + for(sprite in selection) { + if(sprite is FunkinSprite) { + handleSelection(cast sprite); + } } } @@ -410,25 +449,6 @@ class StageEditor extends UIState { SaveWarning.showWarning = undos.unsaved; } - public function selectSprite(_sprite:FunkinSprite) { - selection = new Selection([]); - var sprites = stageSpritesWindow.buttons.members.map((o) -> o.getSprite()).filter((o) -> o != null);// && o.animateAtlas == null); - for(sprite in sprites) { - if(sprite is FunkinSprite) { - var sprite:FunkinSprite = cast sprite; - sprite.extra.set(exID("selected"), false); - sprite.extra.get(exID("button")).selected = false; - } - } - if(_sprite is FunkinSprite) { - var sprite:FunkinSprite = cast _sprite; - sprite.extra.set(exID("selected"), true); - sprite.extra.get(exID("button")).selected = true; - selection = new Selection([sprite]); - Logs.trace("Selected " + sprite.name); - } - } - // TOP MENU OPTIONS #if REGION function _file_exit(_) { @@ -542,6 +562,62 @@ class StageEditor extends UIState { undos.addToUndo(CEditInfo(oldInfo, newInfo));*/ } + public function selectSprite(_sprite:FunkinSprite) { + _select_deselect(null, false); + + if(_sprite is FunkinSprite) { + selection = new Selection([cast _sprite]); + } + updateSelection(); + } + + function getSprites() { + return stageSpritesWindow.buttons.members.map((o) -> o.getSprite()).filter((o) -> o != null); + } + + function updateSelection() { + var sprites = getSprites(); + // Unselect all + for(sprite in sprites) { + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + sprite.extra.set(exID("selected"), false); + sprite.extra.get(exID("button")).selected = false; + } + } + // Mark selected as selected + for(sprite in selection) { + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + sprite.extra.set(exID("selected"), true); + sprite.extra.get(exID("button")).selected = true; + Logs.trace("Selected " + sprite.name); + } + } + } + + function _select_all(_, checkSelection:Bool = true) { + _select_deselect(null, false); + var sprites = getSprites(); + selection = new Selection(sprites); + if(checkSelection) updateSelection(); + } + + function _select_deselect(_, checkSelection:Bool = true) { + var sprites = getSprites();// && o.animateAtlas == null); + selection = new Selection(); + if(checkSelection) updateSelection(); + } + + function _select_inverse(_, checkSelection:Bool = true) { + var oldSelection = selection; + _select_all(null, false); + for(sprite in oldSelection) { + selection.remove(sprite); + } + if(checkSelection) updateSelection(); + } + var zoom(default, set):Float = 0; var __camZoom(default, set):Float = 1; function set_zoom(val:Float) { From 67dbe9a5998979c43b7fc49fd3cbb142f5555b00 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 13:19:16 +0200 Subject: [PATCH 36/89] Better selection! --- source/funkin/editors/stage/StageEditor.hx | 9 ++++++--- source/funkin/editors/ui/UIUtil.hx | 23 ++++++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index b552d415..201f333a 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -563,10 +563,14 @@ class StageEditor extends UIState { } public function selectSprite(_sprite:FunkinSprite) { - _select_deselect(null, false); + if(!UIUtil.getKeyState(CONTROL, PRESSED)) + _select_deselect(null, false); if(_sprite is FunkinSprite) { - selection = new Selection([cast _sprite]); + if(selection.contains(_sprite)) + selection.remove(_sprite); + else + selection.push(_sprite); } updateSelection(); } @@ -604,7 +608,6 @@ class StageEditor extends UIState { } function _select_deselect(_, checkSelection:Bool = true) { - var sprites = getSprites();// && o.animateAtlas == null); selection = new Selection(); if(checkSelection) updateSelection(); } diff --git a/source/funkin/editors/ui/UIUtil.hx b/source/funkin/editors/ui/UIUtil.hx index 7f9de548..4a5a0ee4 100644 --- a/source/funkin/editors/ui/UIUtil.hx +++ b/source/funkin/editors/ui/UIUtil.hx @@ -1,5 +1,6 @@ package funkin.editors.ui; +import flixel.input.FlxInput.FlxInputState; import flixel.input.keyboard.FlxKey; import funkin.editors.ui.UIContextMenu.UIContextMenuOption; @@ -14,6 +15,19 @@ class UIUtil { return contextMenu != null && UIState.state.curContextMenu == contextMenu; } + @:noUsing public static function fixKey(key:FlxKey):FlxKey { + return switch(key) { + #if mac + case CONTROL: WINDOWS; // Remap control to the meta key + #end + default: key; + } + } + + public static function getKeyState(key:FlxKey, Status:FlxInputState):Bool { + return FlxG.keys.checkStatus(fixKey(key), Status); + } + /** * Process all options with shortcuts present in a `Array<UIContextMenuOption>`. Also checks childrens. * @param topMenuOptions @@ -41,14 +55,7 @@ class UIUtil { var shouldPress = Std.int(key) > 0; if(!shouldPress) key = -key; - var k = switch(key) { - #if mac - case CONTROL: - WINDOWS; - #end - default: - key; - } + var k = fixKey(key); if (FlxG.keys.checkStatus(k, shouldPress ? JUST_PRESSED : JUST_RELEASED)) { justPressed = true; } else if (!FlxG.keys.checkStatus(k, shouldPress ? PRESSED : RELEASED)) { From daeae7a004c5b8d1999648edb86a367d588f3108 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 14:32:23 +0200 Subject: [PATCH 37/89] Added stage saving --- source/funkin/backend/utils/XMLUtil.hx | 2 + source/funkin/editors/stage/StageEditor.hx | 126 ++++++++++++++++++--- source/funkin/game/Stage.hx | 83 +++++++++----- 3 files changed, 166 insertions(+), 45 deletions(-) diff --git a/source/funkin/backend/utils/XMLUtil.hx b/source/funkin/backend/utils/XMLUtil.hx index 8ee00025..97d28ffe 100644 --- a/source/funkin/backend/utils/XMLUtil.hx +++ b/source/funkin/backend/utils/XMLUtil.hx @@ -154,6 +154,8 @@ class XMLUtil { spr.skipNegativeBeats = node.att.playOnCountdown == "true"; if (node.has.beatInterval) spr.beatInterval = Std.parseInt(node.att.beatInterval); + if (node.has.interval) + spr.beatInterval = Std.parseInt(node.att.interval); if (node.has.beatOffset) spr.beatOffset = Std.parseInt(node.att.beatOffset); diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 201f333a..81a807d4 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -256,6 +256,7 @@ class StageEditor extends UIState { char.alpha = 0.5; char.extra.set(exID("node"), node); char.extra.set(exID("pos"), charPos); + charPos.extra.set(exID("node"), node); charPos.extra.set(exID("char"), char); chars.push(char); } @@ -269,7 +270,7 @@ class StageEditor extends UIState { for(char in chars) { var charPos = char.extra.get(exID("pos")); - var node = char.extra.get(exID("node")); + var node:Access = cast char.extra.get(exID("node")); stage.applyCharStuff(char, charPos.name, 0); charMap[charPos.name] = char; @@ -478,26 +479,119 @@ class StageEditor extends UIState { undos.save(); } + function saveToXml(xml:Xml, name:String, value:Dynamic, ?defaultValue:Dynamic) { + if(value == null || value == defaultValue) return xml; + xml.set(name, Std.string(value)); + return xml; + } + function savePointToXml(xml:Xml, name:String, point:FlxPoint, ?defaultValueX:Float, ?defaultValueY:Float) { + if (point == null) return xml; + if(point.x == point.y) { + saveToXml(xml, name, point.x, defaultValueX); + } else { + saveToXml(xml, name + "x", point.x, defaultValueX); + saveToXml(xml, name + "y", point.y, defaultValueY); + } + return xml; + } + + function getBoolOfNode(node:Access, name:String) { + var xml:Xml = cast node; + + return xml.exists(name) && xml.get(name) == "true"; + } + function buildStage():String { - /*if (character.isPlayer != character.playerOffsets) { - character.switchOffset('singLEFT', 'singRIGHT'); - character.switchOffset('singLEFTmiss', 'singRIGHTmiss'); + var xml = Xml.createElement("stage"); + saveToXml(xml, "zoom", stage.defaultZoom, 1.05); + saveToXml(xml, "name", stage.stageName); + saveToXml(xml, "folder", stage.spritesParentFolder); + saveToXml(xml, "startCamPosX", stage.startCam.x, 0); + saveToXml(xml, "startCamPosY", stage.startCam.y, 0); + + for(sprite in getSprites()) { + var button:StageElementButton = sprite.extra.get(exID("button")); + if(button is StageSolidButton) { + var button:StageSolidButton = cast button; + var sprite:FunkinSprite = button.getSprite(); + var node:Access = cast sprite.extra.get(exID("node")); + Logs.trace("SOLID / BOX isnt implemented yet!"); + } else if(button is StageSpriteButton) { + var button:StageSpriteButton = cast button; + var sprite:FunkinSprite = button.getSprite(); + var node:Access = cast sprite.extra.get(exID("node")); + var spriteXML = Xml.createElement("sprite"); + saveToXml(spriteXML, "name", sprite.name); + saveToXml(spriteXML, "x", sprite.x, 0); + saveToXml(spriteXML, "y", sprite.y, 0); + saveToXml(spriteXML, "sprite", sprite.extra.get(exID("imageFile"))); + savePointToXml(spriteXML, "scale", sprite.scale, 1, 1); + savePointToXml(spriteXML, "scroll", sprite.scrollFactor, 0, 0); + saveToXml(spriteXML, "skewx", sprite.skew.x, 0); + saveToXml(spriteXML, "skewy", sprite.skew.y, 0); + saveToXml(spriteXML, "alpha", sprite.alpha, 1); + //saveToXml(spriteXML, "graphicSize", sprite.width, sprite.width); + //saveToXml(spriteXML, "graphicSizex", sprite.height, sprite.height); + //saveToXml(spriteXML, "graphicSizey", sprite.height, sprite.height); + saveToXml(spriteXML, "zoomfactor", sprite.zoomFactor, 1); + saveToXml(spriteXML, "updateHitbox", getBoolOfNode(node, "updateHitbox"), false); + saveToXml(spriteXML, "antialiasing", sprite.antialiasing, true); + //saveToXml(spriteXML, "width", sprite.width); + //saveToXml(spriteXML, "height", sprite.height); + saveToXml(spriteXML, "playOnCountdown", getBoolOfNode(node, "playOnCountdown"), false); + saveToXml(spriteXML, "interval", node.getAtt("beatInterval"), 2); + saveToXml(spriteXML, "interval", node.getAtt("interval"), 2); + saveToXml(spriteXML, "beatOffset", node.getAtt("beatOffset"), 0); + saveToXml(spriteXML, "type", sprite.spriteAnimType, LOOP); + saveToXml(spriteXML, "color", sprite.color.toWebString(), "#FFFFFF"); + //saveToXml(spriteXML, "flipX", sprite.flipX, false); + xml.addChild(spriteXML); + } else if(button is StageCharacterButton) { + var button:StageCharacterButton = cast button; + var charPos:StageCharPos = button.charPos; + var char:Character = cast charPos.extra.get(exID("char")); + var node:Access = cast charPos.extra.get(exID("node")); + var nodeName = switch(charPos.name) { + case "boyfriend": "boyfriend"; + case "dad": "dad"; + case "girlfriend": "girlfriend"; + default: "character"; + } + var defaultPos = Stage.getDefaultPos(charPos.name); + var charXML:Xml = Xml.createElement(nodeName); + if(nodeName == "character") + saveToXml(charXML, "name", char.curCharacter); + saveToXml(charXML, "x", charPos.x, defaultPos.x); + saveToXml(charXML, "y", charPos.y, defaultPos.y); + saveToXml(charXML, "camxoffset", charPos.camxoffset, 0); + saveToXml(charXML, "camyoffset", charPos.camyoffset, 0); + saveToXml(charXML, "skewx", charPos.skewX, 0); + saveToXml(charXML, "skewy", charPos.skewY, 0); + saveToXml(charXML, "spacingx", charPos.charSpacingX, 20); + saveToXml(charXML, "spacingy", charPos.charSpacingY, 0); + saveToXml(charXML, "alpha", charPos.alpha, 1); + saveToXml(charXML, "flipX", charPos.flipX, defaultPos.flip); + savePointToXml(charXML, "scroll", charPos.scrollFactor, defaultPos.scroll, defaultPos.scroll); + savePointToXml(charXML, "scale", charPos.scale, 1, 1); + xml.addChild(charXML); + } else { + Logs.trace("Unknown Stage Type : " + Type.getClassName(Type.getClass(button))); + Logs.trace("> Sprite : " + Type.getClassName(Type.getClass(sprite))); + } } - var charXML:Xml = character.buildXML([ - for (button in characterAnimsWindow.buttons.members) - button.anim - ]); // clean - if (charXML.exists("gameOverChar") && character.gameOverCharacter == "bf-dead") charXML.remove("gameOverChar"); - if (charXML.exists("camx") && character.cameraOffset.x == 0) charXML.remove("camx"); - if (charXML.exists("camy") && character.cameraOffset.y == 0) charXML.remove("camy"); - if (charXML.exists("holdTime") && character.holdTime == 4) charXML.remove("holdTime"); - if (charXML.exists("flipX") && !character.flipX) charXML.remove("flipX"); - if (charXML.exists("scale") && character.scale.x == 1) charXML.remove("scale"); - if (charXML.exists("antialiasing") && character.antialiasing) charXML.remove("antialiasing");*/ + //if (charXML.exists("gameOverChar") && character.gameOverCharacter == "bf-dead") charXML.remove("gameOverChar"); + //if (charXML.exists("camx") && character.cameraOffset.x == 0) charXML.remove("camx"); + //if (charXML.exists("camy") && character.cameraOffset.y == 0) charXML.remove("camy"); + //if (charXML.exists("holdTime") && character.holdTime == 4) charXML.remove("holdTime"); + //if (charXML.exists("flipX") && !character.flipX) charXML.remove("flipX"); + //if (charXML.exists("scale") && character.scale.x == 1) charXML.remove("scale"); + //if (charXML.exists("antialiasing") && character.antialiasing) charXML.remove("antialiasing");*/ - return "<!DOCTYPE codename-engine-stage>\n";// + Printer.print(charXML, true); + Logs.trace(Printer.print(xml, true)); + + return "<!DOCTYPE codename-engine-stage>\n" + Printer.print(xml, true); } /*function _edit_undo(_) { diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index c890c82b..9d066a23 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -184,28 +184,13 @@ class Stage extends FlxBasic implements IBeatReceiver { } if (characterPoses["girlfriend"] == null) - addCharPos("girlfriend", null, { - x: 400, - y: 130, - scroll: 0.95, - flip: false - }); + addCharPos("girlfriend", null, getDefaultPos("girlfriend")); if (characterPoses["dad"] == null) - addCharPos("dad", null, { - x: 100, - y: 100, - scroll: 1, - flip: false - }); + addCharPos("dad", null, getDefaultPos("dad")); if (characterPoses["boyfriend"] == null) - addCharPos("boyfriend", null, { - x: 770, - y: 100, - scroll: 1, - flip: true - }); + addCharPos("boyfriend", null, getDefaultPos("boyfriend")); if (PlayState.instance != state) return; for(k=>e in stageSprites) { @@ -213,6 +198,35 @@ class Stage extends FlxBasic implements IBeatReceiver { } } + public static function getDefaultPos(name:String):StageCharPosInfo { + return switch(name) { + case "boyfriend" | "bf" | "player": { + x: 770, + y: 100, + scroll: 1, + flip: true + }; + case "girlfriend" | "gf": { + x: 400, + y: 130, + scroll: 0.95, + flip: false + }; + case "dad" | "opponent": { + x: 100, + y: 100, + scroll: 1, + flip: false + }; + default: { + x: 0, + y: 0, + scroll: 1, + flip: false + }; + } + } + public function addCharPos(name:String, node:Access, ?nonXMLInfo:StageCharPosInfo):StageCharPos { var charPos = new StageCharPos(); charPos.visible = charPos.active = false; @@ -227,6 +241,8 @@ class Stage extends FlxBasic implements IBeatReceiver { if (node != null) { charPos.x = Std.parseFloat(node.getAtt("x")).getDefault(charPos.x); charPos.y = Std.parseFloat(node.getAtt("y")).getDefault(charPos.y); + charPos.charSpacingX = Std.parseFloat(node.getAtt("spacingx")).getDefault(charPos.charSpacingX); + charPos.charSpacingY = Std.parseFloat(node.getAtt("spacingy")).getDefault(charPos.charSpacingY); charPos.camxoffset = Std.parseFloat(node.getAtt("camxoffset")).getDefault(charPos.camxoffset); charPos.camyoffset = Std.parseFloat(node.getAtt("camyoffset")).getDefault(charPos.camyoffset); charPos.skewX = Std.parseFloat(node.getAtt("skewx")).getDefault(charPos.skewX); @@ -234,21 +250,30 @@ class Stage extends FlxBasic implements IBeatReceiver { charPos.alpha = Std.parseFloat(node.getAtt("alpha")).getDefault(charPos.alpha); charPos.flipX = (node.has.flip || node.has.flipX) ? (node.getAtt("flip") == "true" || node.getAtt("flipX") == "true") : charPos.flipX; - var scale = Std.parseFloat(node.getAtt("scale")).getDefault(charPos.scale.x); - charPos.scale.set(scale, scale); + if (node.has.scale) { + var scale:Null<Float> = Std.parseFloat(node.att.scale); + if (scale.isNotNull()) charPos.scale.set(scale, scale); + } + if (node.has.scalex) { + var scale:Null<Float> = Std.parseFloat(node.att.scalex); + if (scale.isNotNull()) charPos.scale.x = scale; + } + if (node.has.scaley) { + var scale:Null<Float> = Std.parseFloat(node.att.scaley); + if (scale.isNotNull()) charPos.scale.y = scale; + } if (node.has.scroll) { var scroll:Null<Float> = Std.parseFloat(node.att.scroll); if (scroll != null) charPos.scrollFactor.set(scroll, scroll); - } else { - if (node.has.scrollx) { - var scroll:Null<Float> = Std.parseFloat(node.att.scrollx); - if (scroll != null) charPos.scrollFactor.x = scroll; - } - if (node.has.scrolly) { - var scroll:Null<Float> = Std.parseFloat(node.att.scrolly); - if (scroll != null) charPos.scrollFactor.y = scroll; - } + } + if (node.has.scrollx) { + var scroll:Null<Float> = Std.parseFloat(node.att.scrollx); + if (scroll != null) charPos.scrollFactor.x = scroll; + } + if (node.has.scrolly) { + var scroll:Null<Float> = Std.parseFloat(node.att.scrolly); + if (scroll != null) charPos.scrollFactor.y = scroll; } } From 7db1d7ae3301c372d4663fc2912d00cdef734a46 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Tue, 16 Apr 2024 06:59:42 -0700 Subject: [PATCH 38/89] the add button works! --- .../layouts/stage/spriteEditScreen.xml | 11 +++++----- source/funkin/editors/stage/StageEditor.hx | 22 ++++++++++++++++++- .../editors/stage/StageSpriteEditScreen.hx | 11 ++++++++++ source/funkin/editors/ui/UIButtonList.hx | 2 +- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index a0684432..b5bcfd58 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -76,12 +76,12 @@ setEx("highMemory", highMemoryRadio.checked); setEx("lowMemory", lowMemoryRadio.checked); - sprite.x = xStepper.value; - sprite.y = yStepper.value; - sprite.zoomFactor = zoomFactorStepper.value; - sprite.antialiasing = antialiasingCheckbox.checked; + //sprite.x = xStepper.value; + //sprite.y = yStepper.value; + //sprite.zoomFactor = zoomFactorStepper.value; + //sprite.antialiasing = antialiasingCheckbox.checked; //sprite.color = colorWheel.color; - sprite.spriteAnimType = animType.value; + //sprite.spriteAnimType = animType.value; sprite.angle = angleStepper.value; function saveXY(obj:Dynamic, name:String, x:UINumericStepper, y:UINumericStepper) { @@ -112,6 +112,7 @@ saveXY(sprite.scrollFactor, "scroll", scrollXStepper, scrollYStepper); saveXY(sprite.scale, "scale", scaleXStepper, scaleYStepper); saveXY(sprite.skew, "skew", skewXStepper, skewYStepper); + XMLUtil.loadSpriteFromXML(sprite, data.xml, stage.spritesParentFolder); } </exec> </window> \ No newline at end of file diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 463accdb..9c03b4c5 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -261,7 +261,27 @@ class StageEditor extends UIState { members.insert(newID, sprite); } stageSpritesWindow.addButton.callback = () -> { - // TODO: implement this + var node:Access = new Access(Xml.createElement("sprite")); + stage.stageXML.x.addChild(node.x); + node.att.name = "sprite_" + stageSpritesWindow.buttons.length; + + var sprite:FunkinSprite = new FunkinSprite(); + add(sprite); + sprite.extra.set(exID("node"), node); + sprite.extra.set(exID("type"), node.name); + sprite.extra.set(exID("imageFile"), ''); + sprite.extra.set(exID("parentNode"), stage.stageXML.x); + sprite.extra.set(exID("highMemory"), false); + sprite.extra.set(exID("lowMemory"), false); + xmlMap.set(sprite, node); + + var button:StageElementButton = new StageSpriteButton(0, 0, sprite, node); + sprite.extra.set(exID("button"), button); + stageSpritesWindow.add(button); + + var substate = new StageSpriteEditScreen(button); + substate.newSprite = true; + openSubState(substate); } for (i=>sprite in order) { var xml = xmlMap.get(sprite); diff --git a/source/funkin/editors/stage/StageSpriteEditScreen.hx b/source/funkin/editors/stage/StageSpriteEditScreen.hx index c221b9fa..d1b4cf18 100644 --- a/source/funkin/editors/stage/StageSpriteEditScreen.hx +++ b/source/funkin/editors/stage/StageSpriteEditScreen.hx @@ -7,8 +7,10 @@ using StringTools; class StageSpriteEditScreen extends UISoftcodedWindow { + public var newSprite:Bool = false; public var data:StageElementButton; public var sprite:FunkinSprite; + var isSaving:Bool = false; public function new(data:StageElementButton) { this.data = data; @@ -32,7 +34,16 @@ class StageSpriteEditScreen extends UISoftcodedWindow { } public override function saveData() { + isSaving = true; super.saveData(); data.updateInfo(sprite); } + + public override function close() { + if (!isSaving && newSprite) { + data.onDelete(); + trace("deleting sprite"); + } + super.close(); + } } \ No newline at end of file diff --git a/source/funkin/editors/ui/UIButtonList.hx b/source/funkin/editors/ui/UIButtonList.hx index 2253460d..fffe3701 100644 --- a/source/funkin/editors/ui/UIButtonList.hx +++ b/source/funkin/editors/ui/UIButtonList.hx @@ -48,7 +48,7 @@ class UIButtonList<T:UIButton> extends UIWindow { } public inline function add(button:T) { - button.ID = buttons.members.length-1; + button.ID = buttons.members.length; buttons.add(button); curMovingInterval = 0; nextscrollY += button.bHeight; From 07c91ee116172662041d5135795f3bd60e473d66 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:22:37 +0200 Subject: [PATCH 39/89] Added character editing --- .../layouts/stage/characterEditScreen.xml | 111 +++++++++ .../layouts/stage/spriteEditScreen.xml | 75 +++--- source/funkin/editors/stage/StageEditor.hx | 46 ++-- .../editors/stage/StageSpriteEditScreen.hx | 49 ---- .../stage/elements/StageCharacterButton.hx | 57 ++++- .../stage/elements/StageElementButton.hx | 2 +- .../stage/elements/StageSpriteButton.hx | 62 ++++- source/funkin/editors/ui/UISoftcodedWindow.hx | 223 ++++++++++-------- source/funkin/game/Stage.hx | 53 +++++ 9 files changed, 449 insertions(+), 229 deletions(-) create mode 100644 assets/editors/layouts/stage/characterEditScreen.xml delete mode 100644 source/funkin/editors/stage/StageSpriteEditScreen.hx diff --git a/assets/editors/layouts/stage/characterEditScreen.xml b/assets/editors/layouts/stage/characterEditScreen.xml new file mode 100644 index 00000000..654db6ea --- /dev/null +++ b/assets/editors/layouts/stage/characterEditScreen.xml @@ -0,0 +1,111 @@ +<window width="550" height="570" title="Editing Character ${button.getName()}"> + <set name="XOFFSET" value="30" /> + <set name="YOFFSET" value="40" /> + <set name="TO" value="64" /> + + <exec> + function col(c:Int) { + return 20 + (150 + XOFFSET) * c; + } + previewSprite = null; + if(char.animateAtlas == null) { + previewSprite = new FunkinSprite(0, 0); + previewSprite.frame = char.frame; + + self.add(previewSprite); + } + </exec> + + <title name="title" x="20" y="30 + 16" text="Character Data" /> + + <section> + <set name="curY" value="title.y + TO" /> + + <stepper name="xStepper" label="X" value="charPos.x" x="col(0)" y="curY" step="1" width="100" /> + <stepper name="yStepper" label="Y" value="charPos.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="1" width="100" /> + + <stepper name="scrollXStepper" label="Scroll X" value="charPos.scrollFactor.x" x="col(1)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="scrollYStepper" label="Scroll Y" value="charPos.scrollFactor.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + + <stepper name="scaleXStepper" label="Scale X" value="charPos.scale.x" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="scaleYStepper" label="Scale Y" value="charPos.scale.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + </section> + + <section> + <set name="curY" value="xStepper.y + xStepper.bHeight + YOFFSET" /> + + <stepper name="camxStepper" label="Cam X" value="charPos.camxoffset" x="col(0)" y="curY" step="1" width="100" /> + <stepper name="camyStepper" label="Cam Y" value="charPos.camyoffset" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="1" width="100" /> + + <stepper name="skewXStepper" label="Skew X" value="charPos.skewX" x="col(1)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="skewYStepper" label="Skew Y" value="charPos.skewY" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + + <label name="spacingLabel" text="Spacing (X, Y)" x="col(2)" y="curY" size="15" /> + <stepper name="spacingXStepper" value="charPos.charSpacingX" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="spacingYStepper" value="charPos.charSpacingY" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + </section> + + <section> + <set name="curY" value="camxStepper.y + camxStepper.bHeight + YOFFSET" /> + + <stepper name="alphaStepper" label="Alpha" value="charPos.alpha" x="col(0)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="zoomFactorStepper" label="Zoom Factor" value="charPos.zoomFactor" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + </section> + + <section> + <set name="curY" value="alphaStepper.y + alphaStepper.bHeight + YOFFSET - 20" /> + + <checkbox name="flipXCheckbox" text="Flip X" value="charPos.flipX" x="col(0)" y="curY" /> + + <radio for="memoryCheck" name="highMemoryRadio" text="High Memory Only" value="getEx('highMemory')" x="last.field.x + last.field.width + XOFFSET * 2" y="curY" /> + <radio for="memoryCheck" name="lowMemoryRadio" text="Low Memory Only" value="getEx('lowMemory')" x="last.field.x + last.field.width + XOFFSET * 2" y="curY" /> + </section> + + <section if="previewSprite != null"> + <title name="previewTitle" x="20" y="self.winHeight - 220" text="Preview Transform:" size="15" /> + </section> + <section if="previewSprite == null"> + <exec> + self.windowSpr.bHeight -= 170; + </exec> + </section> + + <exec> + function onUpdate() { + if(previewSprite == null) return; + previewSprite.skew.x = skewXStepper.value; + previewSprite.skew.y = skewYStepper.value; + previewSprite.antialiasing = char.antialiasing; + var ratio = char.frameWidth / char.frameHeight; + previewSprite.setGraphicSize(145 * scaleXStepper.value * ratio, 145 * scaleYStepper.value); + previewSprite.updateHitbox(); + if(flipXCheckbox.checked != (charPos.name == "boyfriend")) + previewSprite.scale.x *= -1; + + previewSprite.x = 30; + previewSprite.y = self.winHeight - previewSprite.height - 30; + } + + function onSave() { + setEx("highMemory", highMemoryRadio.checked); + setEx("lowMemory", lowMemoryRadio.checked); + + charPos.x = xStepper.value; + charPos.y = yStepper.value; + charPos.scrollFactor.set(scrollXStepper.value, scrollYStepper.value); + charPos.scale.set(scaleXStepper.value, scaleYStepper.value); + charPos.camxoffset = camxStepper.value; + charPos.camyoffset = camyStepper.value; + charPos.skewX = skewXStepper.value; + charPos.skewY = skewYStepper.value; + charPos.alpha = alphaStepper.value; + charPos.charSpacingX = spacingXStepper.value; + charPos.charSpacingY = spacingYStepper.value; + charPos.flipX = flipXCheckbox.checked; + charPos.zoomFactor = zoomFactorStepper.value; + + charPos.revertCharacter(char); + charPos.prepareCharacter(char, charPos._id); + } + </exec> +</window> \ No newline at end of file diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index b5bcfd58..534b8598 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -1,65 +1,74 @@ -<window width="1056" height="520" title="Editing Sprite"> +<window width="1056" height="520" title="Editing Sprite ${button.getName()}"> <set name="XOFFSET" value="50" /> <set name="YOFFSET" value="40" /> <set name="TO" value="64" /> <exec> - previewSprite = new FunkinSprite(50, self.winHeight - 100); - previewSprite.frame = sprite.frame; + function col(c:Int) { + return 20 + (200 + XOFFSET) * c; + } - self.add(previewSprite); + if(sprite.animateAtlas == null) { + previewSprite = new FunkinSprite(50, self.winHeight - 100); + previewSprite.frame = sprite.frame; + + self.add(previewSprite); + } </exec> <title name="title" x="20" y="30 + 16" text="Sprite Data" /> <set name="curY" value="title.y + TO" /> <!-- ROW 1 --> - <textbox name="nameTextBox" label="Name Identifier" text="${data.getName()}" x="20" y="curY" width="200" height="32" /> - <textbox name="spriteTextBox" label="Image File (${stage.spritesParentFolder})" text="${getEx('imageFile')}" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" /> + <textbox name="nameTextBox" label="Name Identifier" value="button.getName()" x="col(0)" y="curY" width="200" height="32" /> + <textbox name="spriteTextBox" label="Image File (${stage.spritesParentFolder})" value="getEx('imageFile')" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" /> <set name="curY" value="nameTextBox.y + nameTextBox.bHeight + YOFFSET" /> <!-- ROW 2 --> - <stepper name="xStepper" label="X" value="sprite.x" x="20" y="curY" step="1" width="100" /> + <stepper name="xStepper" label="X" value="sprite.x" x="col(0)" y="curY" step="1" width="100" /> <stepper name="yStepper" label="Y" value="sprite.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="1" width="100" /> <stepper name="scrollXStepper" label="Scroll X" value="sprite.scrollFactor.x" x="spriteTextBox.x" y="curY" precision="2" step="0.01" width="100" /> <stepper name="scrollYStepper" label="Scroll Y" value="sprite.scrollFactor.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="scaleXStepper" label="Scale X" value="sprite.scale.x" x="20 + (200 + XOFFSET) * 2" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="scaleXStepper" label="Scale X" value="sprite.scale.x" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> <stepper name="scaleYStepper" label="Scale Y" value="sprite.scale.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> <set name="curY" value="xStepper.y + xStepper.bHeight + YOFFSET" /> <!-- ROW 3 --> - <stepper name="angleStepper" label="Angle" value="sprite.angle" x="20 + (200 + XOFFSET) * 0" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="angleStepper" label="Angle" value="sprite.angle" x="col(0)" y="curY" precision="2" step="0.01" width="100" /> <stepper name="zoomFactorStepper" label="Zoom Factor" value="sprite.zoomFactor" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="skewXStepper" label="Skew X" value="sprite.skew.x" x="20 + (200 + XOFFSET) * 2" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="skewYStepper" label="Skew Y" value="sprite.skew.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - <!-- TODO: Simplify this --> - <dropdown name="animType" label="Animation Type" value="sprite.spriteAnimType" x="20 + (200 + XOFFSET) * 1" y="curY" width="150" height="32"> + <dropdown name="animType" label="Animation Type" value="sprite.spriteAnimType" x="col(1)" y="curY" width="150" height="32"> <item label="NONE" value="0" /> <item label="BEAT" value="1" /> <item label="LOOP" value="2" /> </dropdown> + <stepper name="skewXStepper" label="Skew X" value="sprite.skew.x" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="skewYStepper" label="Skew Y" value="sprite.skew.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + <!-- ROW 4 --> <set name="curY" value="angleStepper.y + angleStepper.bHeight + YOFFSET" /> - <checkbox name="antialiasingCheckbox" text="Antialiasing" value="sprite.antialiasing" x="20 + (200 + XOFFSET) * 0" y="curY" /> - <radio for="memoryCheck" name="highMemoryRadio" text="High Memory Only" value="getEx('highMemory')" x="20 + (200 + XOFFSET) * 1" y="curY" /> - <radio for="memoryCheck" name="lowMemoryRadio" text="Low Memory Only" value="getEx('lowMemory')" x="20 + (200 + XOFFSET) * 2" y="curY" /> + <checkbox name="antialiasingCheckbox" text="Antialiasing" value="sprite.antialiasing" x="col(0)" y="curY" /> + <radio for="memoryCheck" name="highMemoryRadio" text="High Memory Only" value="getEx('highMemory')" x="col(1)" y="curY" /> + <radio for="memoryCheck" name="lowMemoryRadio" text="Low Memory Only" value="getEx('lowMemory')" x="col(2)" y="curY" /> <!-- TODO: Animation list --> <!-- Preview Transform --> - <title name="previewTitle" x="20" y="self.winHeight - 150" text="Preview Transform:" size="14" /> + <section if="previewSprite != null"> + <title name="previewTitle" x="20" y="self.winHeight - 150" text="Preview Transform:" size="15" /> + </section> <exec> function onUpdate() { - previewSprite.color = 0xFFFFFFFF; + if(previewSprite == null) return; + previewSprite.color = 0xFFFFFFFF; // TODO: Color Wheel previewSprite.skew.x = skewXStepper.value; previewSprite.skew.y = skewYStepper.value; previewSprite.angle = angleStepper.value; @@ -85,34 +94,34 @@ sprite.angle = angleStepper.value; function saveXY(obj:Dynamic, name:String, x:UINumericStepper, y:UINumericStepper) { - data.xml.remove(name + ""); - data.xml.remove(name + "x"); - data.xml.remove(name + "y"); + button.xml.remove(name + ""); + button.xml.remove(name + "x"); + button.xml.remove(name + "y"); obj.x = x.value; obj.y = y.value; if(x.value == y.value) - data.xml.set(name, x.value); + button.xml.set(name, x.value); else { - data.xml.set(name + "x", x.value); - data.xml.set(name + "y", y.value); + button.xml.set(name + "x", x.value); + button.xml.set(name + "y", y.value); } } - data.xml.set("name", nameTextBox.label.text); - data.xml.set("sprite", spriteTextBox.label.text); - data.xml.set("x", xStepper.value); - data.xml.set("y", yStepper.value); - data.xml.set("zoom", zoomFactorStepper.value); - data.xml.set("type", animType.key); - data.xml.set("antialiasing", antialiasingCheckbox.checked); - data.xml.set("angle", angleStepper.value); + button.xml.set("name", nameTextBox.label.text); + button.xml.set("sprite", spriteTextBox.label.text); + button.xml.set("x", xStepper.value); + button.xml.set("y", yStepper.value); + button.xml.set("zoom", zoomFactorStepper.value); + button.xml.set("type", animType.key); + button.xml.set("antialiasing", antialiasingCheckbox.checked); + button.xml.set("angle", angleStepper.value); saveXY(sprite.scrollFactor, "scroll", scrollXStepper, scrollYStepper); saveXY(sprite.scale, "scale", scaleXStepper, scaleYStepper); saveXY(sprite.skew, "skew", skewXStepper, skewYStepper); - XMLUtil.loadSpriteFromXML(sprite, data.xml, stage.spritesParentFolder); + XMLUtil.loadSpriteFromXML(sprite, button.xml, stage.spritesParentFolder); } </exec> </window> \ No newline at end of file diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 51896319..e094cf4f 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -1,6 +1,5 @@ package funkin.editors.stage; -import lime.ui.MouseCursor; import flixel.math.FlxAngle; import flixel.math.FlxPoint; import flixel.math.FlxRect; @@ -9,11 +8,13 @@ import flixel.util.FlxSort; import funkin.backend.system.framerate.Framerate; import funkin.backend.utils.XMLUtil.AnimData; import funkin.editors.stage.elements.*; +import funkin.editors.stage.elements.StageSpriteButton.StageSpriteEditScreen; import funkin.editors.ui.UIContextMenu.UIContextMenuOption; import funkin.game.Character; import funkin.game.Stage; import haxe.xml.Access; import haxe.xml.Printer; +import lime.ui.MouseCursor; import openfl.ui.Mouse; using funkin.backend.utils.MatrixUtil; @@ -78,11 +79,6 @@ class StageEditor extends UIState { { label: "File", childs: [ - { - label: "New", - onSelect: _file_new, - }, - null, { label: "Save", keybind: [CONTROL, S], @@ -215,6 +211,7 @@ class StageEditor extends UIState { } } stage.onNodeLoaded = function(node:Access, sprite:Dynamic):Dynamic { + var parent = new Access(node.x.parent); var name = ""; if(sprite is FlxSprite) { //sprite.forceIsOnScreen = true; // hack @@ -225,7 +222,6 @@ class StageEditor extends UIState { sprite.extra.set(exID("node"), node); sprite.extra.set(exID("type"), node.name); sprite.extra.set(exID("imageFile"), '${node.getAtt("sprite").getDefault(sprite.name)}'); - var parent = new Access(node.x.parent); sprite.extra.set(exID("parentNode"), parent); sprite.extra.set(exID("highMemory"), parent.name == "highMemory"); sprite.extra.set(exID("lowMemory"), parent.name == "lowMemory"); @@ -254,10 +250,17 @@ class StageEditor extends UIState { // Add it to the stage char.visible = true; char.alpha = 0.5; - char.extra.set(exID("node"), node); - char.extra.set(exID("pos"), charPos); - charPos.extra.set(exID("node"), node); - charPos.extra.set(exID("char"), char); + function setEx(name:String, value:Dynamic) { + char.extra.set(exID(name), value); + charPos.extra.set(exID(name), value); + } + setEx("node", node); + setEx("pos", charPos); + setEx("char", char); + + setEx("parentNode", parent); + setEx("highMemory", parent.name == "highMemory"); + setEx("lowMemory", parent.name == "lowMemory"); chars.push(char); } order.push(sprite); @@ -307,12 +310,12 @@ class StageEditor extends UIState { sprite.extra.set(exID("node"), node); sprite.extra.set(exID("type"), node.name); sprite.extra.set(exID("imageFile"), ''); - sprite.extra.set(exID("parentNode"), stage.stageXML.x); + sprite.extra.set(exID("parentNode"), new Access(node.x.parent)); sprite.extra.set(exID("highMemory"), false); sprite.extra.set(exID("lowMemory"), false); xmlMap.set(sprite, node); - var button:StageElementButton = new StageSpriteButton(0, 0, sprite, node); + var button:StageSpriteButton = new StageSpriteButton(0, 0, sprite, node); sprite.extra.set(exID("button"), button); stageSpritesWindow.add(button); @@ -477,9 +480,6 @@ class StageEditor extends UIState { else FlxG.switchState(new StageSelection()); } - function _file_new(_) { - } - function _file_save(_) { #if sys CoolUtil.safeSaveFile( @@ -506,6 +506,7 @@ class StageEditor extends UIState { } function savePointToXml(xml:Xml, name:String, point:FlxPoint, ?defaultValueX:Float, ?defaultValueY:Float) { if (point == null) return xml; + if(defaultValueY == null) defaultValueY = defaultValueX; if(point.x == point.y) { saveToXml(xml, name, point.x, defaultValueX); } else { @@ -545,8 +546,8 @@ class StageEditor extends UIState { saveToXml(spriteXML, "x", sprite.x, 0); saveToXml(spriteXML, "y", sprite.y, 0); saveToXml(spriteXML, "sprite", sprite.extra.get(exID("imageFile"))); - savePointToXml(spriteXML, "scale", sprite.scale, 1, 1); - savePointToXml(spriteXML, "scroll", sprite.scrollFactor, 0, 0); + savePointToXml(spriteXML, "scale", sprite.scale, 1); + savePointToXml(spriteXML, "scroll", sprite.scrollFactor, 0); saveToXml(spriteXML, "skewx", sprite.skew.x, 0); saveToXml(spriteXML, "skewy", sprite.skew.y, 0); saveToXml(spriteXML, "alpha", sprite.alpha, 1); @@ -590,9 +591,10 @@ class StageEditor extends UIState { saveToXml(charXML, "spacingx", charPos.charSpacingX, 20); saveToXml(charXML, "spacingy", charPos.charSpacingY, 0); saveToXml(charXML, "alpha", charPos.alpha, 1); + saveToXml(charXML, "zoomfactor", charPos.zoomFactor, 1); saveToXml(charXML, "flipX", charPos.flipX, defaultPos.flip); - savePointToXml(charXML, "scroll", charPos.scrollFactor, defaultPos.scroll, defaultPos.scroll); - savePointToXml(charXML, "scale", charPos.scale, 1, 1); + savePointToXml(charXML, "scroll", charPos.scrollFactor, defaultPos.scroll); + savePointToXml(charXML, "scale", charPos.scale, 1); xml.addChild(charXML); } else { Logs.trace("Unknown Stage Type : " + Type.getClassName(Type.getClass(button))); @@ -791,7 +793,7 @@ class StageEditor extends UIState { for(char in chars) { var button:StageCharacterButton = char.extra.get(exID("button")); button.isHidden = !showCharacters; - button.updateInfo(button.charPos); + button.updateInfo(); } } #end @@ -972,7 +974,7 @@ class StageEditor extends UIState { // todo: make this origin based relative.rotateByDegrees(sprite.angle); call(mouseMode.toString(), [sprite, relative]); - cast(sprite.extra.get(exID("button")), StageElementButton).updateInfo(sprite); + cast(sprite.extra.get(exID("button")), StageElementButton).updateInfo(); relative.put(); } diff --git a/source/funkin/editors/stage/StageSpriteEditScreen.hx b/source/funkin/editors/stage/StageSpriteEditScreen.hx deleted file mode 100644 index d1b4cf18..00000000 --- a/source/funkin/editors/stage/StageSpriteEditScreen.hx +++ /dev/null @@ -1,49 +0,0 @@ -package funkin.editors.stage; - -import funkin.editors.stage.elements.StageElementButton; -import funkin.editors.ui.UISoftcodedWindow; - -using StringTools; - - -class StageSpriteEditScreen extends UISoftcodedWindow { - public var newSprite:Bool = false; - public var data:StageElementButton; - public var sprite:FunkinSprite; - var isSaving:Bool = false; - - public function new(data:StageElementButton) { - this.data = data; - this.sprite = data.getSprite(); - super("layouts/stage/spriteEditScreen.xml", [ - "stage" => StageEditor.instance.stage, - "sprite" => sprite, - "data" => data, - "exID" => StageEditor.exID, - "getEx" => function(name:String):Dynamic { - return sprite.extra.get(StageEditor.exID(name)); - }, - "setEx" => function(name:String, value:Dynamic) { - sprite.extra.set(StageEditor.exID(name), value); - }, - ]); - } - - public override function create() { - super.create(); - } - - public override function saveData() { - isSaving = true; - super.saveData(); - data.updateInfo(sprite); - } - - public override function close() { - if (!isSaving && newSprite) { - data.onDelete(); - trace("deleting sprite"); - } - super.close(); - } -} \ No newline at end of file diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index 905cdc99..e28e89d3 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -15,7 +15,7 @@ class StageCharacterButton extends StageElementButton { color = 0xff7aa8ff; - updateInfo(charPos); + updateInfo(); } public override function update(elapsed:Float) { @@ -27,13 +27,10 @@ class StageCharacterButton extends StageElementButton { super.update(elapsed); } - public override function updateInfo(charPos:Dynamic) { - if(charPos is StageCharPos) { - var charPos:StageCharPos = cast charPos; - this.charPos = charPos; - char.visible = !isHidden; - } - super.updateInfo(charPos); + public override function updateInfo() { + char.visible = !isHidden; + char.alpha = 0.5 * charPos.alpha; + super.updateInfo(); } public override function getSprite():FunkinSprite { @@ -46,13 +43,17 @@ class StageCharacterButton extends StageElementButton { } public override function onEdit() { - UIState.state.displayNotification(new UIBaseNotification("Editing a character isnt implemented yet!", 2, BOTTOM_LEFT)); - CoolUtil.playMenuSFX(WARNING, 0.45); + FlxG.state.openSubState(new StageCharacterEditScreen(this)); } + //public override function onEdit() { + // UIState.state.displayNotification(new UIBaseNotification("Editing a character isnt implemented yet!", 2, BOTTOM_LEFT)); + // CoolUtil.playMenuSFX(WARNING, 0.45); + //} + public override function onGhostClick() { isHidden = !isHidden; - updateInfo(this.charPos); + updateInfo(); } public override function getName():String { @@ -66,4 +67,38 @@ class StageCharacterButton extends StageElementButton { public override function updatePos() { super.updatePos(); } +} + +class StageCharacterEditScreen extends UISoftcodedWindow { + public var button:StageCharacterButton; + public var char:Character; + public var charPos:StageCharPos; + + public function new(button:StageCharacterButton) { + this.button = button; + this.char = button.char; + this.charPos = button.charPos; + super("layouts/stage/characterEditScreen.xml", [ + "stage" => StageEditor.instance.stage, + "char" => char, + "charPos" => charPos, + "button" => button, + "exID" => StageEditor.exID, + "getEx" => function(name:String):Dynamic { + return char.extra.get(StageEditor.exID(name)); + }, + "setEx" => function(name:String, value:Dynamic) { + char.extra.set(StageEditor.exID(name), value); + }, + ]); + } + + public override function create() { + super.create(); + } + + public override function saveData() { + super.saveData(); + button.updateInfo(); + } } \ No newline at end of file diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index 49194d5d..11f3edf1 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -122,7 +122,7 @@ class StageElementButton extends UIButton { } } - public function updateInfo(sprite:Dynamic) { + public function updateInfo() { field.text = getInfoText(); ghostIcon.animation.play(!isHidden ? "alive" : "dead"); diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index 09cc061e..5c584548 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -1,8 +1,9 @@ package funkin.editors.stage.elements; -import haxe.xml.Access; -import funkin.editors.stage.StageSpriteEditScreen; import flixel.util.FlxColor; +import funkin.editors.stage.elements.StageElementButton; +import funkin.editors.ui.UISoftcodedWindow; +import haxe.xml.Access; class StageSpriteButton extends StageElementButton { public var sprite:FunkinSprite; @@ -13,20 +14,16 @@ class StageSpriteButton extends StageElementButton { //color = 0xFFD9FF50; - updateInfo(sprite); + updateInfo(); } public override function update(elapsed:Float) { super.update(elapsed); } - public override function updateInfo(sprite:Dynamic) { - if(sprite is FunkinSprite) { - var sprite:FunkinSprite = cast sprite; - this.sprite = sprite; - sprite.visible = !isHidden; - } - super.updateInfo(sprite); + public override function updateInfo() { + sprite.visible = !isHidden; + super.updateInfo(); } public override function getSprite():FunkinSprite { @@ -39,11 +36,10 @@ class StageSpriteButton extends StageElementButton { public override function onGhostClick() { isHidden = !isHidden; - updateInfo(this.sprite); + updateInfo(); } public override function onEdit() { - // TODO: implement FlxG.state.openSubState(new StageSpriteEditScreen(this)); } @@ -66,4 +62,46 @@ class StageSpriteButton extends StageElementButton { public override function updatePos() { super.updatePos(); } +} + +class StageSpriteEditScreen extends UISoftcodedWindow { + public var newSprite:Bool = false; + public var button:StageSpriteButton; + public var sprite:FunkinSprite; + var isSaving:Bool = false; + + public function new(button:StageSpriteButton) { + this.button = button; + this.sprite = button.getSprite(); + super("layouts/stage/spriteEditScreen.xml", [ + "stage" => StageEditor.instance.stage, + "sprite" => sprite, + "button" => button, + "exID" => StageEditor.exID, + "getEx" => function(name:String):Dynamic { + return sprite.extra.get(StageEditor.exID(name)); + }, + "setEx" => function(name:String, value:Dynamic) { + sprite.extra.set(StageEditor.exID(name), value); + }, + ]); + } + + public override function create() { + super.create(); + } + + public override function saveData() { + isSaving = true; + super.saveData(); + button.updateInfo(); + } + + public override function close() { + if (!isSaving && newSprite) { + button.onDelete(); + trace("deleting sprite"); + } + super.close(); + } } \ No newline at end of file diff --git a/source/funkin/editors/ui/UISoftcodedWindow.hx b/source/funkin/editors/ui/UISoftcodedWindow.hx index ff751fec..5e0c71b9 100644 --- a/source/funkin/editors/ui/UISoftcodedWindow.hx +++ b/source/funkin/editors/ui/UISoftcodedWindow.hx @@ -71,7 +71,7 @@ class UISoftcodedWindow extends UISubstateWindow { return CoolUtil.getDefault(exec(code), defaultValue); } - function execAtt(el:Access, key:String, defaultValue:Dynamic):Dynamic { + function execAtt(el:Access, key:String, ?defaultValue:Dynamic):Dynamic { return execDefault(el.getAtt(key), defaultValue); } @@ -101,9 +101,6 @@ class UISoftcodedWindow extends UISubstateWindow { public override function create() { var layout = new Access(Xml.parse(Assets.getText('assets/editors/' + xmlPath)).firstElement()); - winTitle = layout.getAtt("title").getDefault(winTitle); - winWidth = Std.parseInt(layout.getAtt("width")).getDefault(winWidth); - winHeight = Std.parseInt(layout.getAtt("height")).getDefault(winHeight); for(k=>e in Script.getDefaultVariables()) { set(k, e); @@ -119,110 +116,134 @@ class UISoftcodedWindow extends UISubstateWindow { } set("last", null); + winTitle = execString(layout.getAtt("title").getDefault(winTitle)); + winWidth = Std.parseInt(layout.getAtt("width")).getDefault(winWidth); + winHeight = Std.parseInt(layout.getAtt("height")).getDefault(winHeight); + super.create(); function addLabelOn(ui:UISprite, text:String) add(new UIText(ui.x, ui.y - 24, 0, text)); - for(el in layout.elements) { - var type = el.name; - //var type:String = el.getAtt("type"); - var name:String = execString(el.getAtt("name")); - var label:String = execString(el.getAtt("label")); - var text:String = execString(el.getAtt("text")); - var x:Float = execAtt(el, "x", 0); - var y:Float = execAtt(el, "y", 0); - var width:Null<Int> = exec(el.getAtt("width")); - var height:Null<Int> = exec(el.getAtt("height")); - var size:Int = execAtt(el, "size", 28); - - trace(type, name, label, text, x, y, width, height, size); - - var sprite:FlxSprite = switch(type) { - case "set": - set(execString(el.getAtt("name")), exec(el.getAtt("value"))); - continue; - case "image": - var spr = XMLUtil.createSpriteFromXML(el, "", LOOP); - cast add(spr); - case "solid": - var spr = new FunkinSprite(x, y).makeSolid( - execAtt(el, "width", 100), - execAtt(el, "height", 100), - execAtt(el, "color", 0xFFFFFFFF) - ); - cast add(spr); - case "exec": - exec(el.innerData); - continue; - case "textbox": - var textBox = new UITextBox(x, y, text, width, height, execAtt(el, "multiline", false));//(el.getAtt("multiline").getDefault("false") == "true")); - add(textBox); - addLabelOn(textBox, label); - textBox; - case "title": - cast add(new UIText(x, y, 0, text, size)); - case "stepper": - // x:Float, y:Float, value:Float = 0, step:Float = 1, precision:Int = 0, ?min:Float, ?max:Float, w:Int = 180, h:Int = 32 - var stepper = new UINumericStepper( - x, - y, - execAtt(el, "value", 0), - execAtt(el, "step", 1), - execAtt(el, "precision", 0), - execAtt(el, "min", null), - execAtt(el, "max", null), - width, - height - ); - add(stepper); - addLabelOn(stepper, label); - stepper; - case "checkbox": - var checkbox = new UICheckbox(x, y, text, execAtt(el, "value", false)); - add(checkbox); - addLabelOn(checkbox, label); - checkbox; - case "radio": - var radio = new UIRadioButton(x, y, text, execAtt(el, "value", false), execString(el.getAtt("for"))); - radio.parent = this; - add(radio); - addLabelOn(radio, label); - radio; - case "slider": - var slider = new UISlider(x, y, width, execAtt(el, "value", 0), execAtt(el, "segments", []), execAtt(el, "centered", false)); - add(slider); - addLabelOn(slider, label); - slider; - case "dropdown": - var items:Array<DropDownItem> = []; - for(i=>node in el.nodes.item) - items.push({label: execString(node.getAtt("label")), value: execAtt(node, "value", i)}); - var curValue = execAtt(el, "value", null); - var index = UIDropDown.indexOfItemValue(items, curValue); - if (index == -1) index = 0; - - var dropdown = new UIDropDown(x, y, width, height, items, index); - add(dropdown); - addLabelOn(dropdown, label); - dropdown; - // UIColorwheel - // UIAudioPlayer - // UIButtonList - // UIFileExplorer - // UIAutoCompleteTextbox - default: { - Logs.trace("Unknown element type: " + type, ERROR, RED); - Logs.trace("Skipping element: " + el.x.toString(), ERROR, RED); - continue; - } - } - - set("last", sprite); - if(name != null) set(name, sprite); - if(sprite is UISprite) elementMap.set(name, cast sprite); + function getArr(i:Iterator<Access>) { + return [for(e in i) e]; } + function addLayout(elements:Array<Access>) { + for(el in elements) { + var type = el.name; + + switch(type) { + case "section": + if(execAtt(el, "if", true) != true) + continue; + if(execAtt(el, "unless", false) != false) + continue; + addLayout(getArr(el.elements)); + continue; + case "set": + set(execString(el.getAtt("name")), execAtt(el, "value")); + continue; + case "exec": + exec(el.innerData); + continue; + } + + var name:String = execString(el.getAtt("name")); + var label:String = execString(el.getAtt("label")); + var x:Float = execAtt(el, "x", 0); + var y:Float = execAtt(el, "y", 0); + + var sprite:FlxSprite = switch(type) { + case "image": + var spr = XMLUtil.createSpriteFromXML(el, "", LOOP); + spr.x = x; + spr.y = y; + cast add(spr); + case "solid": + var spr = new FunkinSprite(x, y).makeSolid( + execAtt(el, "width", 100), + execAtt(el, "height", 100), + execAtt(el, "color", 0xFFFFFFFF) + ); + cast add(spr); + case "textbox": + var text:String = execString(el.getAtt("text")); + text = Std.string(execAtt(el, "value", text)); + var textBox = new UITextBox(x, y, text, execAtt(el, "width"), execAtt(el, "height"), execAtt(el, "multiline", false));//(el.getAtt("multiline").getDefault("false") == "true")); + add(textBox); + addLabelOn(textBox, label); + textBox; + case "title": + cast add(new UIText(x, y, 0, execString(el.getAtt("text")), execAtt(el, "size", 28))); + case "label": + cast add(new UIText(x, y - 24, 0, execString(el.getAtt("text")), execAtt(el, "size", 15))); + case "text": + cast add(new UIText(x, y, 0, execString(el.getAtt("text")), execAtt(el, "size", 15))); + case "stepper": + // x:Float, y:Float, value:Float = 0, step:Float = 1, precision:Int = 0, ?min:Float, ?max:Float, w:Int = 180, h:Int = 32 + var stepper = new UINumericStepper( + x, + y, + execAtt(el, "value", 0), + execAtt(el, "step", 1), + execAtt(el, "precision", 0), + execAtt(el, "min"), + execAtt(el, "max"), + execAtt(el, "width"), + execAtt(el, "height") + ); + add(stepper); + addLabelOn(stepper, label); + stepper; + case "checkbox": + var checkbox = new UICheckbox(x, y, execString(el.getAtt("text")), execAtt(el, "value", false)); + add(checkbox); + addLabelOn(checkbox, label); + checkbox; + case "radio": + var radio = new UIRadioButton(x, y, execString(el.getAtt("text")), execAtt(el, "value", false), execString(el.getAtt("for"))); + radio.parent = this; + add(radio); + addLabelOn(radio, label); + radio; + case "slider": + var slider = new UISlider(x, y, execAtt(el, "width"), execAtt(el, "value", 0), execAtt(el, "segments", []), execAtt(el, "centered", false)); + add(slider); + addLabelOn(slider, label); + slider; + case "dropdown": + var items:Array<DropDownItem> = []; + for(i=>node in el.nodes.item) + items.push({label: execString(node.getAtt("label")), value: execAtt(node, "value", i)}); + var curValue = execAtt(el, "value"); + var index = UIDropDown.indexOfItemValue(items, curValue); + if (index == -1) index = 0; + + var dropdown = new UIDropDown(x, y, execAtt(el, "width"), execAtt(el, "height"), items, index); + add(dropdown); + addLabelOn(dropdown, label); + dropdown; + // UIColorwheel + // UIAudioPlayer + // UIButtonList + // UIFileExplorer + // UIAutoCompleteTextbox + default: { + Logs.trace("Unknown element type: " + type, ERROR, RED); + Logs.trace("Skipping element: " + el.x.toString(), ERROR, RED); + continue; + } + } + + set("last", sprite); + if(name != null) set(name, sprite); + if(sprite is UISprite) elementMap.set(name, cast sprite); + } + } + + addLayout(getArr(layout.elements)); + if(get("hasSaveButtons")) { saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight - 20, "Save & Close", function() { saveData(); diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index 9d066a23..6a98e173 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -249,6 +249,7 @@ class Stage extends FlxBasic implements IBeatReceiver { charPos.skewY = Std.parseFloat(node.getAtt("skewy")).getDefault(charPos.skewY); charPos.alpha = Std.parseFloat(node.getAtt("alpha")).getDefault(charPos.alpha); charPos.flipX = (node.has.flip || node.has.flipX) ? (node.getAtt("flip") == "true" || node.getAtt("flipX") == "true") : charPos.flipX; + charPos.zoomFactor = Std.parseFloat(node.getAtt("zoomfactor")).getDefault(charPos.zoomFactor); if (node.has.scale) { var scale:Null<Float> = Std.parseFloat(node.att.scale); @@ -337,6 +338,7 @@ class StageCharPos extends FlxObject { public var alpha:Float = 1; public var flipX:Bool = false; public var scale:FlxPoint = FlxPoint.get(1, 1); + public var zoomFactor:Float = 1; public function new() { super(); @@ -349,13 +351,49 @@ class StageCharPos extends FlxObject { super.destroy(); } + private var _id:Float = -1; + + private var oldInfo:OldCharInfo = null; + public function prepareCharacter(char:Character, id:Float = 0) { + _id = id; + oldInfo = getOldInfo(char); char.setPosition(x + (id * charSpacingX), y + (id * charSpacingY)); char.scrollFactor.set(scrollFactor.x, scrollFactor.y); char.scale.x *= scale.x; char.scale.y *= scale.y; char.cameraOffset += FlxPoint.weak(camxoffset, camyoffset); char.skew.x += skewX; char.skew.y += skewY; char.alpha *= alpha; + char.zoomFactor *= zoomFactor; + } + + public function getOldInfo(char:Character) { + return { + x: char.x, y: char.y, + scrollX: char.scrollFactor.x, scrollY: char.scrollFactor.y, + scaleX: char.scale.x, scaleY: char.scale.y, + camxoffset: char.cameraOffset.x, camyoffset: char.cameraOffset.y, + skewX: char.skew.x, skewY: char.skew.y, + alpha: char.alpha, zoomFactor: char.zoomFactor + } + } + + public function revertCharacter(char:Character) { + if(oldInfo == null) return; + for(field in Reflect.fields(oldInfo)) { + switch(field) { + case "scrollX": char.scrollFactor.x = oldInfo.scrollX; + case "scrollY": char.scrollFactor.y = oldInfo.scrollY; + case "scaleX": char.scale.x = oldInfo.scaleX; + case "scaleY": char.scale.y = oldInfo.scaleY; + case "camxoffset": char.cameraOffset.x = oldInfo.camxoffset; + case "camyoffset": char.cameraOffset.y = oldInfo.camyoffset; + case "skewX": char.skew.x = oldInfo.skewX; + case "skewY": char.skew.y = oldInfo.skewY; + default: Reflect.setField(char, field, Reflect.field(oldInfo, field)); + } + } + oldInfo = null; } } typedef StageCharPosInfo = { @@ -363,4 +401,19 @@ typedef StageCharPosInfo = { var y:Float; var flip:Bool; var scroll:Float; +} + +typedef OldCharInfo = { + var x:Float; + var y:Float; + var scrollX:Float; + var scrollY:Float; + var scaleX:Float; + var scaleY:Float; + var camxoffset:Float; + var camyoffset:Float; + var skewX:Float; + var skewY:Float; + var alpha:Float; + var zoomFactor:Float; } \ No newline at end of file From 0e92c664b375a7fc8b74d4c2ed35adcfae15839f Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:58:40 +0200 Subject: [PATCH 40/89] Made it generate xml groups --- source/funkin/editors/stage/StageEditor.hx | 52 +++++++++++++------ .../stage/elements/StageCharacterButton.hx | 1 + 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index e094cf4f..03be9548 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -273,7 +273,7 @@ class StageEditor extends UIState { for(char in chars) { var charPos = char.extra.get(exID("pos")); - var node:Access = cast char.extra.get(exID("node")); + //var node:Access = cast char.extra.get(exID("node")); stage.applyCharStuff(char, charPos.name, 0); charMap[charPos.name] = char; @@ -327,15 +327,18 @@ class StageEditor extends UIState { var xml = xmlMap.get(sprite); if(xml != null) { if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; var type = sprite.extra.get(exID("type")); var button:StageElementButton = (type == "box" || type == "solid") ? new StageSolidButton(0,0, sprite, xml) : new StageSpriteButton(0,0, sprite, xml); sprite.extra.set(exID("button"), button); stageSpritesWindow.add(button); } else if(sprite is StageCharPos) { - var char = charMap[sprite.name]; - var button = new StageCharacterButton(0,0, sprite, xml); + var charPos:StageCharPos = cast sprite; + var char = charMap[charPos.name]; + var button = new StageCharacterButton(0,0, charPos, xml); char.extra.set(exID("button"), button); + charPos.extra.set(exID("button"), button); stageSpritesWindow.add(button); } } @@ -530,16 +533,19 @@ class StageEditor extends UIState { saveToXml(xml, "startCamPosX", stage.startCam.x, 0); saveToXml(xml, "startCamPosY", stage.startCam.y, 0); + var group:Xml = null; + var curGroup:String = null; + for(sprite in getSprites()) { var button:StageElementButton = sprite.extra.get(exID("button")); + var newNode:Xml = null; + var sprite:FunkinSprite = button.getSprite(); if(button is StageSolidButton) { var button:StageSolidButton = cast button; - var sprite:FunkinSprite = button.getSprite(); var node:Access = cast sprite.extra.get(exID("node")); Logs.trace("SOLID / BOX isnt implemented yet!"); } else if(button is StageSpriteButton) { var button:StageSpriteButton = cast button; - var sprite:FunkinSprite = button.getSprite(); var node:Access = cast sprite.extra.get(exID("node")); var spriteXML = Xml.createElement("sprite"); saveToXml(spriteXML, "name", sprite.name); @@ -566,11 +572,12 @@ class StageEditor extends UIState { saveToXml(spriteXML, "type", sprite.spriteAnimType, LOOP); saveToXml(spriteXML, "color", sprite.color.toWebString(), "#FFFFFF"); //saveToXml(spriteXML, "flipX", sprite.flipX, false); - xml.addChild(spriteXML); + newNode = spriteXML; } else if(button is StageCharacterButton) { var button:StageCharacterButton = cast button; var charPos:StageCharPos = button.charPos; var char:Character = cast charPos.extra.get(exID("char")); + sprite = button.getSprite(); var node:Access = cast charPos.extra.get(exID("node")); var nodeName = switch(charPos.name) { case "boyfriend": "boyfriend"; @@ -595,21 +602,34 @@ class StageEditor extends UIState { saveToXml(charXML, "flipX", charPos.flipX, defaultPos.flip); savePointToXml(charXML, "scroll", charPos.scrollFactor, defaultPos.scroll); savePointToXml(charXML, "scale", charPos.scale, 1); - xml.addChild(charXML); + newNode = charXML; } else { Logs.trace("Unknown Stage Type : " + Type.getClassName(Type.getClass(button))); Logs.trace("> Sprite : " + Type.getClassName(Type.getClass(sprite))); } - } - // clean - //if (charXML.exists("gameOverChar") && character.gameOverCharacter == "bf-dead") charXML.remove("gameOverChar"); - //if (charXML.exists("camx") && character.cameraOffset.x == 0) charXML.remove("camx"); - //if (charXML.exists("camy") && character.cameraOffset.y == 0) charXML.remove("camy"); - //if (charXML.exists("holdTime") && character.holdTime == 4) charXML.remove("holdTime"); - //if (charXML.exists("flipX") && !character.flipX) charXML.remove("flipX"); - //if (charXML.exists("scale") && character.scale.x == 1) charXML.remove("scale"); - //if (charXML.exists("antialiasing") && character.antialiasing) charXML.remove("antialiasing");*/ + if(newNode != null && sprite != null) { + var isLowMemory = sprite.extra.get(exID("lowMemory")) == true; + var isHighMemory = sprite.extra.get(exID("highMemory")) == true; + /* // Only if this compiled :sob: + var groupName:String = null; + if ((groupName = isLowMemory ? "low-memory" : isHighMemory ? "high-memory" : null) != null) { + var a = group != null && groupName != curGroup && ((group = cast xml.addChild(group)) != null); + (group = (group == null ? Xml.createElement(curGroup = groupName) : group)).addChild(newNode); + }else xml.addChild(newNode); + */ + + var groupName = isLowMemory ? "low-memory" : isHighMemory ? "high-memory" : null; + if(group != null && groupName != curGroup) { + xml.addChild(group); + group = null; + } + if(groupName != null) + (group = (group == null ? Xml.createElement(curGroup = groupName) : group)).addChild(newNode); + else + xml.addChild(newNode); + } + } Logs.trace(Printer.print(xml, true)); diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index e28e89d3..3fcb88ef 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -89,6 +89,7 @@ class StageCharacterEditScreen extends UISoftcodedWindow { }, "setEx" => function(name:String, value:Dynamic) { char.extra.set(StageEditor.exID(name), value); + charPos.extra.set(StageEditor.exID(name), value); }, ]); } From 4ca8d66aa6fcfb1258e05867131df0035a14c877 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:54:17 +0200 Subject: [PATCH 41/89] Stage Editor now recognizes unknown elements Added a unknown element editor Added angle to sprites and characters --- assets/data/stages/test.xml | 32 +----- .../layouts/stage/characterEditScreen.xml | 6 +- .../layouts/stage/unknownEditScreen.xml | 39 +++++++ source/funkin/backend/utils/XMLUtil.hx | 3 + source/funkin/editors/stage/StageEditor.hx | 24 +++- .../stage/elements/StageCharacterButton.hx | 6 +- .../stage/elements/StageElementButton.hx | 4 + .../stage/elements/StageSpriteButton.hx | 1 + .../stage/elements/StageUnknownButton.hx | 103 ++++++++++++++++++ source/funkin/game/Stage.hx | 8 +- 10 files changed, 183 insertions(+), 43 deletions(-) create mode 100644 assets/editors/layouts/stage/unknownEditScreen.xml create mode 100644 source/funkin/editors/stage/elements/StageUnknownButton.hx diff --git a/assets/data/stages/test.xml b/assets/data/stages/test.xml index f74dbd01..82cfbadd 100644 --- a/assets/data/stages/test.xml +++ b/assets/data/stages/test.xml @@ -4,33 +4,7 @@ <sprite name="normBG" sprite="stagefront" x="-500" y="100" scale="0.75" updateHitbox="true" /> <sprite name="noUpdateHitbox" sprite="stagefront" x="-500" y="300" scale="0.75" /> <sprite name="ro-tat-ay" sprite="stagefront" x="-500" y="700" scale="0.75" updateHitbox="true" angle="37" /> - - - <!-- oh yeah those exist - where the first one go - you saw the video? - the wha - https://www.youtube.com/watch?v=d6iQrh2TK98 - well that explains a bit - whats weird is that i typically think of the number *twenty* seven - guess my favortie number - 37 - -23.47 - interesting - oops - you will be surprised how it looks after me wizard and yosh used it lol, 268kb - - also i love how most of nthis files size comes from the convo - 37 is a wacky number so im using that for testing - // maybe box? so its colors - wrong format lol (im on stepmania xml) - also just realized i cant scale boxes, you can, just not <solid> - we may need a different func for boxes/solids. - storedScale should still work - and when we save we just have to save either width and scale.x, or calculate the width from the scale - i think we can do sprite.frameWidth * sprite.scale.x when saving boxes luckfully - oh yeah --> - - <!-- <box == makeGraphic --> - <!-- <solid == makeSolid --> + <box name="box" x="0" y="0" width="200" height="200" color="0xFF0000" /> + <solid name="box2" x="0" y="300" width="200" height="200" color="0x00FF00" /> + <unknown-sprite /> </stage> \ No newline at end of file diff --git a/assets/editors/layouts/stage/characterEditScreen.xml b/assets/editors/layouts/stage/characterEditScreen.xml index 654db6ea..3fc6e08e 100644 --- a/assets/editors/layouts/stage/characterEditScreen.xml +++ b/assets/editors/layouts/stage/characterEditScreen.xml @@ -49,7 +49,9 @@ <set name="curY" value="camxStepper.y + camxStepper.bHeight + YOFFSET" /> <stepper name="alphaStepper" label="Alpha" value="charPos.alpha" x="col(0)" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="zoomFactorStepper" label="Zoom Factor" value="charPos.zoomFactor" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="angleStepper" label="Angle" value="charPos.angle" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + + <stepper name="zoomFactorStepper" label="Zoom Factor" value="charPos.zoomFactor" x="col(1)" y="curY" precision="2" step="0.01" width="100" /> </section> <section> @@ -75,6 +77,7 @@ if(previewSprite == null) return; previewSprite.skew.x = skewXStepper.value; previewSprite.skew.y = skewYStepper.value; + previewSprite.angle = angleStepper.value; previewSprite.antialiasing = char.antialiasing; var ratio = char.frameWidth / char.frameHeight; previewSprite.setGraphicSize(145 * scaleXStepper.value * ratio, 145 * scaleYStepper.value); @@ -103,6 +106,7 @@ charPos.charSpacingY = spacingYStepper.value; charPos.flipX = flipXCheckbox.checked; charPos.zoomFactor = zoomFactorStepper.value; + charPos.angle = angleStepper.value; charPos.revertCharacter(char); charPos.prepareCharacter(char, charPos._id); diff --git a/assets/editors/layouts/stage/unknownEditScreen.xml b/assets/editors/layouts/stage/unknownEditScreen.xml new file mode 100644 index 00000000..4c053731 --- /dev/null +++ b/assets/editors/layouts/stage/unknownEditScreen.xml @@ -0,0 +1,39 @@ +<window width="310" height="570" title="Editing XML <${button.getName()} />"> + <set name="XOFFSET" value="30" /> + <set name="YOFFSET" value="40" /> + <set name="TO" value="64" /> + + <exec> + function col(c:Int) { + return 20 + (150 + XOFFSET) * c; + } + </exec> + + <title name="title" x="20" y="30 + 16" text="Xml Data" /> + + <section> + <set name="curY" value="title.y + TO" /> + + <textbox name="nodeNameTextBox" label="Element Name" value="button.getName()" x="col(0)" y="curY" width="280" height="32" /> + </section> + <section> + <set name="curY" value="nodeNameTextBox.y + nodeNameTextBox.bHeight + YOFFSET - 20" /> + + <radio for="memoryCheck" name="highMemoryRadio" text="High Memory Only" value="button.highMemory" x="col(0)" y="curY" /> + <radio for="memoryCheck" name="lowMemoryRadio" text="Low Memory Only" value="button.lowMemory" x="col(0)" y="last.y + last.check.height + YOFFSET - 30" /> + </section> + + <section> + <set name="curY" value="lowMemoryRadio.y + lowMemoryRadio.check.height + YOFFSET - 20" /> + + <!-- TODO: attribute button list --> + </section> + + <exec> + function onSave() { + button.xml.nodeName = nodeNameTextBox.label.text; + button.highMemory = highMemoryRadio.checked; + button.lowMemory = lowMemoryRadio.checked; + } + </exec> +</window> \ No newline at end of file diff --git a/source/funkin/backend/utils/XMLUtil.hx b/source/funkin/backend/utils/XMLUtil.hx index 97d28ffe..52a3bd47 100644 --- a/source/funkin/backend/utils/XMLUtil.hx +++ b/source/funkin/backend/utils/XMLUtil.hx @@ -150,6 +150,9 @@ class XMLUtil { if(node.has.color) spr.color = FlxColor.fromString(node.getAtt("color")).getDefault(0xFFFFFFFF); + if(node.has.angle) + spr.angle = Std.parseFloat(node.getAtt("angle")).getDefault(spr.angle); + if (node.has.playOnCountdown) spr.skipNegativeBeats = node.att.playOnCountdown == "true"; if (node.has.beatInterval) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 03be9548..1ca88bcd 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -213,6 +213,7 @@ class StageEditor extends UIState { stage.onNodeLoaded = function(node:Access, sprite:Dynamic):Dynamic { var parent = new Access(node.x.parent); var name = ""; + trace(node, sprite); if(sprite is FlxSprite) { //sprite.forceIsOnScreen = true; // hack } @@ -340,6 +341,9 @@ class StageEditor extends UIState { char.extra.set(exID("button"), button); charPos.extra.set(exID("button"), button); stageSpritesWindow.add(button); + } else if(sprite == null) { + var button = new StageUnknownButton(0,0, xml); + stageSpritesWindow.add(button); } } } @@ -486,7 +490,7 @@ class StageEditor extends UIState { function _file_save(_) { #if sys CoolUtil.safeSaveFile( - '${Paths.getAssetsRoot()}/data/stages/${stage.stageName}.xml', + '${Paths.getAssetsRoot()}/data/stages/${__stage}.xml', buildStage() ); undos.save(); @@ -497,7 +501,7 @@ class StageEditor extends UIState { function _file_saveas(_) { openSubState(new SaveSubstate(buildStage(), { - defaultSaveFile: '${stage.stageName}.xml' + defaultSaveFile: '${__stage}.xml' })); undos.save(); } @@ -557,6 +561,7 @@ class StageEditor extends UIState { saveToXml(spriteXML, "skewx", sprite.skew.x, 0); saveToXml(spriteXML, "skewy", sprite.skew.y, 0); saveToXml(spriteXML, "alpha", sprite.alpha, 1); + saveToXml(spriteXML, "angle", sprite.angle, 0); //saveToXml(spriteXML, "graphicSize", sprite.width, sprite.width); //saveToXml(spriteXML, "graphicSizex", sprite.height, sprite.height); //saveToXml(spriteXML, "graphicSizey", sprite.height, sprite.height); @@ -577,7 +582,6 @@ class StageEditor extends UIState { var button:StageCharacterButton = cast button; var charPos:StageCharPos = button.charPos; var char:Character = cast charPos.extra.get(exID("char")); - sprite = button.getSprite(); var node:Access = cast charPos.extra.get(exID("node")); var nodeName = switch(charPos.name) { case "boyfriend": "boyfriend"; @@ -598,12 +602,17 @@ class StageEditor extends UIState { saveToXml(charXML, "spacingx", charPos.charSpacingX, 20); saveToXml(charXML, "spacingy", charPos.charSpacingY, 0); saveToXml(charXML, "alpha", charPos.alpha, 1); + saveToXml(charXML, "angle", charPos.angle, 0); saveToXml(charXML, "zoomfactor", charPos.zoomFactor, 1); saveToXml(charXML, "flipX", charPos.flipX, defaultPos.flip); savePointToXml(charXML, "scroll", charPos.scrollFactor, defaultPos.scroll); savePointToXml(charXML, "scale", charPos.scale, 1); newNode = charXML; - } else { + } else if(button is StageUnknownButton) { + var button:StageUnknownButton = cast button; + newNode = button.xml.x; + } + else { Logs.trace("Unknown Stage Type : " + Type.getClassName(Type.getClass(button))); Logs.trace("> Sprite : " + Type.getClassName(Type.getClass(sprite))); } @@ -714,9 +723,12 @@ class StageEditor extends UIState { function getSprites() { return stageSpritesWindow.buttons.members.map((o) -> o.getSprite()).filter((o) -> o != null); } + function getRealSprites() { + return stageSpritesWindow.buttons.members.filter(o -> o.canRender()).map((o) -> o.getSprite()).filter((o) -> o != null); + } function updateSelection() { - var sprites = getSprites(); + var sprites = getRealSprites(); // Unselect all for(sprite in sprites) { if(sprite is FunkinSprite) { @@ -738,7 +750,7 @@ class StageEditor extends UIState { function _select_all(_, checkSelection:Bool = true) { _select_deselect(null, false); - var sprites = getSprites(); + var sprites = getRealSprites(); selection = new Selection(sprites); if(checkSelection) updateSelection(); } diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index 3fcb88ef..b271fbc9 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -19,11 +19,6 @@ class StageCharacterButton extends StageElementButton { } public override function update(elapsed:Float) { - editButton.selectable = ghostButton.selectable = deleteButton.selectable = selectable; - editButton.shouldPress = ghostButton.shouldPress = deleteButton.shouldPress = shouldPress; - - hovered = !deleteButton.hovered; - updatePos(); super.update(elapsed); } @@ -83,6 +78,7 @@ class StageCharacterEditScreen extends UISoftcodedWindow { "char" => char, "charPos" => charPos, "button" => button, + "xml" => button.xml, "exID" => StageEditor.exID, "getEx" => function(name:String):Dynamic { return char.extra.get(StageEditor.exID(name)); diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index 11f3edf1..f41915b3 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -154,6 +154,10 @@ class StageElementButton extends UIButton { return null; } + public function canRender() { + return true; + } + public function getName():String { return "UNKNOWN"; } diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index 5c584548..ac133b14 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -77,6 +77,7 @@ class StageSpriteEditScreen extends UISoftcodedWindow { "stage" => StageEditor.instance.stage, "sprite" => sprite, "button" => button, + "xml" => button.xml, "exID" => StageEditor.exID, "getEx" => function(name:String):Dynamic { return sprite.extra.get(StageEditor.exID(name)); diff --git a/source/funkin/editors/stage/elements/StageUnknownButton.hx b/source/funkin/editors/stage/elements/StageUnknownButton.hx new file mode 100644 index 00000000..70c4f7ae --- /dev/null +++ b/source/funkin/editors/stage/elements/StageUnknownButton.hx @@ -0,0 +1,103 @@ +package funkin.editors.stage.elements; + +import funkin.game.Character; +import funkin.game.Stage.StageCharPos; +import haxe.xml.Access; + +class StageUnknownButton extends StageElementButton { + public var lowMemory:Bool = false; + public var highMemory:Bool = false; + + public function new(x:Float,y:Float, xml:Access) { + super(x,y, xml); + + if(xml.x.parent != null) { + lowMemory = xml.x.parent.nodeName == "low-memory"; + highMemory = xml.x.parent.nodeName == "high-memory"; + } + + color = 0xff000000; + + ghostButton.exists = false; + members.remove(ghostButton); + + ghostIcon.exists = false; + members.remove(ghostIcon); + + updateInfo(); + } + + public override function update(elapsed:Float) { + super.update(elapsed); + } + + public override function updateInfo() { + super.updateInfo(); + } + + public override function getSprite():FunkinSprite { + var sprite = new FunkinSprite(); // to allow it to be saved + sprite.extra.set(StageEditor.exID("lowMemory"), lowMemory); + sprite.extra.set(StageEditor.exID("highMemory"), highMemory); + sprite.extra.set(StageEditor.exID("button"), this); + return sprite; + } + + public override function canRender() { + return false; + } + + public override function onSelect() { + } + + public override function onEdit() { + FlxG.state.openSubState(new StageUnknownEditScreen(this)); + } + + //public override function onEdit() { + // UIState.state.displayNotification(new UIBaseNotification("Editing a character isnt implemented yet!", 2, BOTTOM_LEFT)); + // CoolUtil.playMenuSFX(WARNING, 0.45); + //} + + public override function onGhostClick() { + } + + public override function getName():String { + return xml.name; + } + + public override function getPos():FlxPoint { + return FlxPoint.get(0, 0); + } + + public override function getInfoText():String { + return 'Unknown\n<${getName()} />'; + } + + public override function updatePos() { + super.updatePos(); + } +} + +class StageUnknownEditScreen extends UISoftcodedWindow { + public var button:StageUnknownButton; + + public function new(button:StageUnknownButton) { + this.button = button; + super("layouts/stage/unknownEditScreen.xml", [ + "stage" => StageEditor.instance.stage, + "button" => button, + "xml" => button.xml, + "exID" => StageEditor.exID + ]); + } + + public override function create() { + super.create(); + } + + public override function saveData() { + super.saveData(); + button.updateInfo(); + } +} \ No newline at end of file diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index 6a98e173..b5547770 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -248,6 +248,7 @@ class Stage extends FlxBasic implements IBeatReceiver { charPos.skewX = Std.parseFloat(node.getAtt("skewx")).getDefault(charPos.skewX); charPos.skewY = Std.parseFloat(node.getAtt("skewy")).getDefault(charPos.skewY); charPos.alpha = Std.parseFloat(node.getAtt("alpha")).getDefault(charPos.alpha); + charPos.angle = Std.parseFloat(node.getAtt("angle")).getDefault(charPos.angle); charPos.flipX = (node.has.flip || node.has.flipX) ? (node.getAtt("flip") == "true" || node.getAtt("flipX") == "true") : charPos.flipX; charPos.zoomFactor = Std.parseFloat(node.getAtt("zoomfactor")).getDefault(charPos.zoomFactor); @@ -364,6 +365,7 @@ class StageCharPos extends FlxObject { char.cameraOffset += FlxPoint.weak(camxoffset, camyoffset); char.skew.x += skewX; char.skew.y += skewY; char.alpha *= alpha; + char.angle += angle; char.zoomFactor *= zoomFactor; } @@ -374,7 +376,8 @@ class StageCharPos extends FlxObject { scaleX: char.scale.x, scaleY: char.scale.y, camxoffset: char.cameraOffset.x, camyoffset: char.cameraOffset.y, skewX: char.skew.x, skewY: char.skew.y, - alpha: char.alpha, zoomFactor: char.zoomFactor + alpha: char.alpha, zoomFactor: char.zoomFactor, + angle: char.angle } } @@ -390,7 +393,7 @@ class StageCharPos extends FlxObject { case "camyoffset": char.cameraOffset.y = oldInfo.camyoffset; case "skewX": char.skew.x = oldInfo.skewX; case "skewY": char.skew.y = oldInfo.skewY; - default: Reflect.setField(char, field, Reflect.field(oldInfo, field)); + default: Reflect.setProperty(char, field, Reflect.field(oldInfo, field)); } } oldInfo = null; @@ -416,4 +419,5 @@ typedef OldCharInfo = { var skewY:Float; var alpha:Float; var zoomFactor:Float; + var angle:Float; } \ No newline at end of file From 243577b4593bed16f5798665a6f70c1d21c8e11c Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 18:08:18 +0200 Subject: [PATCH 42/89] Small cleanup --- source/funkin/game/Stage.hx | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index b5547770..a621dc83 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -131,26 +131,11 @@ class Stage extends FlxBasic implements IBeatReceiver { stageSprites.set(spr.name, spr); addSprite(spr); case "boyfriend" | "bf" | "player": - addCharPos("boyfriend", node, { - x: 770, - y: 100, - scroll: 1, - flip: true - }); + addCharPos("boyfriend", node, getDefaultPos("boyfriend")); case "girlfriend" | "gf": - addCharPos("girlfriend", node, { - x: 400, - y: 130, - scroll: 0.95, - flip: false - }); + addCharPos("girlfriend", node, getDefaultPos("girlfriend")); case "dad" | "opponent": - addCharPos("dad", node, { - x: 100, - y: 100, - scroll: 1, - flip: false - }); + addCharPos("dad", node, getDefaultPos("dad")); case "character" | "char": if (!node.has.name) continue; addCharPos(node.att.name, node); From 80299334d3453d5428f3c699c2295d8453710931 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 18:43:13 +0200 Subject: [PATCH 43/89] Made it possible to select characters --- .../stage/elements/StageCharacterButton.hx | 6 +++- source/funkin/editors/ui/UISoftcodedWindow.hx | 29 ++++++++++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index b271fbc9..d9660b60 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -33,9 +33,13 @@ class StageCharacterButton extends StageElementButton { } public override function onSelect() { + StageEditor.instance.selectSprite(char); + } + + /*public override function onSelect() { UIState.state.displayNotification(new UIBaseNotification("Selecting a character isnt implemented yet!", 2, BOTTOM_LEFT)); CoolUtil.playMenuSFX(WARNING, 0.45); - } + }*/ public override function onEdit() { FlxG.state.openSubState(new StageCharacterEditScreen(this)); diff --git a/source/funkin/editors/ui/UISoftcodedWindow.hx b/source/funkin/editors/ui/UISoftcodedWindow.hx index 5e0c71b9..7b430bc3 100644 --- a/source/funkin/editors/ui/UISoftcodedWindow.hx +++ b/source/funkin/editors/ui/UISoftcodedWindow.hx @@ -43,6 +43,9 @@ class UISoftcodedWindow extends UISubstateWindow { function get(name:String):Dynamic { return interp.variables.get(name); } + function varExists(name:String):Bool { + return interp.variables.exists(name); + } function execString(input:String):String { if(input == null) return null; @@ -116,6 +119,10 @@ class UISoftcodedWindow extends UISubstateWindow { } set("last", null); + if(varExists("winTitle")) winTitle = get("winTitle"); + if(varExists("winWidth")) winWidth = get("winWidth"); + if(varExists("winHeight")) winHeight = get("winHeight"); + winTitle = execString(layout.getAtt("title").getDefault(winTitle)); winWidth = Std.parseInt(layout.getAtt("width")).getDefault(winWidth); winHeight = Std.parseInt(layout.getAtt("height")).getDefault(winHeight); @@ -175,11 +182,11 @@ class UISoftcodedWindow extends UISubstateWindow { addLabelOn(textBox, label); textBox; case "title": - cast add(new UIText(x, y, 0, execString(el.getAtt("text")), execAtt(el, "size", 28))); + cast add(new UIText(x, y, execAtt(el, "width", 0), execString(el.getAtt("text")), execAtt(el, "size", 28))); case "label": - cast add(new UIText(x, y - 24, 0, execString(el.getAtt("text")), execAtt(el, "size", 15))); + cast add(new UIText(x, y - 24, execAtt(el, "width", 0), execString(el.getAtt("text")), execAtt(el, "size", 15))); case "text": - cast add(new UIText(x, y, 0, execString(el.getAtt("text")), execAtt(el, "size", 15))); + cast add(new UIText(x, y, execAtt(el, "width", 0), execString(el.getAtt("text")), execAtt(el, "size", 15))); case "stepper": // x:Float, y:Float, value:Float = 0, step:Float = 1, precision:Int = 0, ?min:Float, ?max:Float, w:Int = 180, h:Int = 32 var stepper = new UINumericStepper( @@ -244,22 +251,28 @@ class UISoftcodedWindow extends UISubstateWindow { addLayout(getArr(layout.elements)); - if(get("hasSaveButtons")) { + if(get("hasSaveButton")) { saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight - 20, "Save & Close", function() { saveData(); close(); }, 125); saveButton.x -= saveButton.bWidth; saveButton.y -= saveButton.bHeight; + add(saveButton); + } - closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Close", function() { + if(get("hasCloseButton")) { + var x = saveButton != null ? saveButton.x - 20 : windowSpr.x + windowSpr.bWidth - 20; + var y = saveButton != null ? saveButton.y : windowSpr.y + windowSpr.bHeight - 20; + closeButton = new UIButton(x, y, "Close", function() { close(); }, 125); - closeButton.color = 0xFFFF0000; + if(saveButton != null) + closeButton.color = 0xFFFF0000; closeButton.x -= closeButton.bWidth; - //closeButton.y -= closeButton.bHeight; + if(saveButton == null) + closeButton.y -= closeButton.bHeight; add(closeButton); - add(saveButton); } } From c11df2a7a7937b50615c24541348e6980eaf6adf Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:12:18 +0200 Subject: [PATCH 44/89] Added buttonlist for softcoded, added attributes list --- assets/data/stages/test.xml | 2 + .../layouts/stage/spriteEditScreen.xml | 61 +++++++++++-------- .../layouts/stage/unknownEditScreen.xml | 36 +++++++++-- source/funkin/editors/extra/PropertyButton.hx | 30 +++++---- source/funkin/editors/stage/StageEditor.hx | 13 ++-- .../stage/elements/StageCharacterButton.hx | 2 + source/funkin/editors/ui/UISoftcodedWindow.hx | 33 +++++++++- 7 files changed, 127 insertions(+), 50 deletions(-) diff --git a/assets/data/stages/test.xml b/assets/data/stages/test.xml index 82cfbadd..be041748 100644 --- a/assets/data/stages/test.xml +++ b/assets/data/stages/test.xml @@ -7,4 +7,6 @@ <box name="box" x="0" y="0" width="200" height="200" color="0xFF0000" /> <solid name="box2" x="0" y="300" width="200" height="200" color="0x00FF00" /> <unknown-sprite /> + + <unknown-sprite-1-attr name="test" /> </stage> \ No newline at end of file diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index 534b8598..611e5feb 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -18,45 +18,52 @@ <title name="title" x="20" y="30 + 16" text="Sprite Data" /> - <set name="curY" value="title.y + TO" /> <!-- ROW 1 --> + <section> <!-- ROW 1 --> + <set name="curY" value="title.y + TO" /> - <textbox name="nameTextBox" label="Name Identifier" value="button.getName()" x="col(0)" y="curY" width="200" height="32" /> - <textbox name="spriteTextBox" label="Image File (${stage.spritesParentFolder})" value="getEx('imageFile')" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" /> + <textbox name="nameTextBox" label="Name Identifier" value="button.getName()" x="col(0)" y="curY" width="200" height="32" /> + <textbox name="spriteTextBox" label="Image File (${stage.spritesParentFolder})" value="getEx('imageFile')" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" /> + </section> - <set name="curY" value="nameTextBox.y + nameTextBox.bHeight + YOFFSET" /> <!-- ROW 2 --> + <section> <!-- ROW 2 --> + <set name="curY" value="nameTextBox.y + nameTextBox.bHeight + YOFFSET" /> - <stepper name="xStepper" label="X" value="sprite.x" x="col(0)" y="curY" step="1" width="100" /> - <stepper name="yStepper" label="Y" value="sprite.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="1" width="100" /> + <stepper name="xStepper" label="X" value="sprite.x" x="col(0)" y="curY" step="1" width="100" /> + <stepper name="yStepper" label="Y" value="sprite.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="1" width="100" /> - <stepper name="scrollXStepper" label="Scroll X" value="sprite.scrollFactor.x" x="spriteTextBox.x" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="scrollYStepper" label="Scroll Y" value="sprite.scrollFactor.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="scrollXStepper" label="Scroll X" value="sprite.scrollFactor.x" x="spriteTextBox.x" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="scrollYStepper" label="Scroll Y" value="sprite.scrollFactor.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="scaleXStepper" label="Scale X" value="sprite.scale.x" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="scaleYStepper" label="Scale Y" value="sprite.scale.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="scaleXStepper" label="Scale X" value="sprite.scale.x" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="scaleYStepper" label="Scale Y" value="sprite.scale.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + </section> - <set name="curY" value="xStepper.y + xStepper.bHeight + YOFFSET" /> <!-- ROW 3 --> + <section> <!-- ROW 3 --> + <set name="curY" value="xStepper.y + xStepper.bHeight + YOFFSET" /> - <stepper name="angleStepper" label="Angle" value="sprite.angle" x="col(0)" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="zoomFactorStepper" label="Zoom Factor" value="sprite.zoomFactor" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="angleStepper" label="Angle" value="sprite.angle" x="col(0)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="zoomFactorStepper" label="Zoom Factor" value="sprite.zoomFactor" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - <!-- TODO: Simplify this --> - <dropdown name="animType" label="Animation Type" value="sprite.spriteAnimType" x="col(1)" y="curY" width="150" height="32"> - <item label="NONE" value="0" /> - <item label="BEAT" value="1" /> - <item label="LOOP" value="2" /> - </dropdown> + <!-- TODO: Simplify this --> + <dropdown name="animType" label="Animation Type" value="sprite.spriteAnimType" x="col(1)" y="curY" width="150" height="32"> + <item label="NONE" value="0" /> + <item label="BEAT" value="1" /> + <item label="LOOP" value="2" /> + </dropdown> - <stepper name="skewXStepper" label="Skew X" value="sprite.skew.x" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="skewYStepper" label="Skew Y" value="sprite.skew.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="skewXStepper" label="Skew X" value="sprite.skew.x" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="skewYStepper" label="Skew Y" value="sprite.skew.y" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + </section> - <!-- ROW 4 --> - <set name="curY" value="angleStepper.y + angleStepper.bHeight + YOFFSET" /> + <section> <!-- ROW 4 --> + <set name="curY" value="angleStepper.y + angleStepper.bHeight + YOFFSET" /> - <checkbox name="antialiasingCheckbox" text="Antialiasing" value="sprite.antialiasing" x="col(0)" y="curY" /> - <radio for="memoryCheck" name="highMemoryRadio" text="High Memory Only" value="getEx('highMemory')" x="col(1)" y="curY" /> - <radio for="memoryCheck" name="lowMemoryRadio" text="Low Memory Only" value="getEx('lowMemory')" x="col(2)" y="curY" /> + <checkbox name="antialiasingCheckbox" text="Antialiasing" value="sprite.antialiasing" x="col(0)" y="curY" /> + <radio for="memoryCheck" name="highMemoryRadio" text="High Memory Only" value="getEx('highMemory')" x="col(1)" y="curY" /> + <radio for="memoryCheck" name="lowMemoryRadio" text="Low Memory Only" value="getEx('lowMemory')" x="col(2)" y="curY" /> - <!-- TODO: Animation list --> + <!-- TODO: Animation list --> + </section> <!-- Preview Transform --> diff --git a/assets/editors/layouts/stage/unknownEditScreen.xml b/assets/editors/layouts/stage/unknownEditScreen.xml index 4c053731..b2b54542 100644 --- a/assets/editors/layouts/stage/unknownEditScreen.xml +++ b/assets/editors/layouts/stage/unknownEditScreen.xml @@ -1,15 +1,16 @@ -<window width="310" height="570" title="Editing XML <${button.getName()} />"> +<window width="350" height="570" title="Editing XML <${button.getName()} />"> + <set name="MARGIN" value="20" /> <set name="XOFFSET" value="30" /> <set name="YOFFSET" value="40" /> <set name="TO" value="64" /> <exec> function col(c:Int) { - return 20 + (150 + XOFFSET) * c; + return MARGIN + (150 + XOFFSET) * c; } </exec> - <title name="title" x="20" y="30 + 16" text="Xml Data" /> + <title name="title" x="MARGIN" y="30 + 16" text="Xml Data" /> <section> <set name="curY" value="title.y + TO" /> @@ -17,16 +18,36 @@ <textbox name="nodeNameTextBox" label="Element Name" value="button.getName()" x="col(0)" y="curY" width="280" height="32" /> </section> <section> - <set name="curY" value="nodeNameTextBox.y + nodeNameTextBox.bHeight + YOFFSET - 20" /> + <set name="curY" value="nodeNameTextBox.y + nodeNameTextBox.bHeight + YOFFSET - 30" /> <radio for="memoryCheck" name="highMemoryRadio" text="High Memory Only" value="button.highMemory" x="col(0)" y="curY" /> <radio for="memoryCheck" name="lowMemoryRadio" text="Low Memory Only" value="button.lowMemory" x="col(0)" y="last.y + last.check.height + YOFFSET - 30" /> </section> <section> - <set name="curY" value="lowMemoryRadio.y + lowMemoryRadio.check.height + YOFFSET - 20" /> + <set name="curY" value="lowMemoryRadio.y + lowMemoryRadio.check.height + YOFFSET" /> + <set name="listWidth" value="self.winWidth - MARGIN * 2" /> - <!-- TODO: attribute button list --> + <buttonlist name="attributesList" label="Attributes" x="col(0)" y="curY" width="listWidth" height="260" buttonSizeX="listWidth-10" buttonSizeY="35" buttonSpacing="5"> + <texture path="editors/ui/inputbox" /> + <camSpacing value="0" /> + + <code> + import funkin.editors.extra.PropertyButton; + + var buttonList = buttonlist; // important for now, since it gets reset after the code is run + + var width = buttonList.buttonSize.x; + var height = buttonList.buttonSize.y; + + buttonList.addButton.callback = function() { + buttonList.add(new PropertyButton("newProperty", "valueHere", buttonList, width, height, 110, 145, 25)); + } + + for (i in xml.attributes()) + buttonList.add(new PropertyButton(i, xml.get(i), buttonList, width, height, 110, 145, 25)); + </code> + </buttonlist> </section> <exec> @@ -34,6 +55,9 @@ button.xml.nodeName = nodeNameTextBox.label.text; button.highMemory = highMemoryRadio.checked; button.lowMemory = lowMemoryRadio.checked; + + for (val in attributesList.buttons.members) + xml.set(val.propertyText.label.text, val.valueText.label.text); } </exec> </window> \ No newline at end of file diff --git a/source/funkin/editors/extra/PropertyButton.hx b/source/funkin/editors/extra/PropertyButton.hx index 0ffad946..4cf5a9c3 100644 --- a/source/funkin/editors/extra/PropertyButton.hx +++ b/source/funkin/editors/extra/PropertyButton.hx @@ -6,28 +6,36 @@ class PropertyButton extends UIButton { public var deleteButton:UIButton; public var deleteIcon:FlxSprite; - public function new(property, value, parent) { - super(0, 0, '', function () {}, 280, 35); - members.push(propertyText = new UITextBox(5, 5, property, 100, 25)); - members.push(valueText = new UITextBox(propertyText.x + propertyText.bWidth + 10, 5, value, 135, 25)); + public function new(property, value, parent, width:Int = 280, height:Int = 35, nameWidth:Int = 100, valueWidth:Int = 135, inputHeight:Int = 25) { + super(0, 0, '', function () {}, width, height); + members.push(propertyText = new UITextBox(5, 5, property, nameWidth, inputHeight)); + members.push(valueText = new UITextBox(propertyText.x + propertyText.bWidth + 10, 5, value, valueWidth, inputHeight)); - deleteButton = new UIButton(valueText.x + 135, bHeight/2 - (25/2), "", function () { + var deleteSize = height - 5 * 2; + deleteButton = new UIButton(valueText.x + 135, bHeight/2 - (deleteSize/2), "", function () { parent.remove(this); - }, 25, 25); + }, deleteSize, deleteSize); deleteButton.color = 0xFFFF0000; deleteButton.autoAlpha = false; members.push(deleteButton); - deleteIcon = new FlxSprite(deleteButton.x + (15/2), deleteButton.y + 8).loadGraphic(Paths.image('editors/delete-button')); + deleteIcon = new FlxSprite(deleteButton.x, deleteButton.y).loadGraphic(Paths.image('editors/delete-button')); deleteIcon.antialiasing = false; members.push(deleteIcon); + + updatePos(); } public override function update(elapsed) { super.update(elapsed); - propertyText.follow(this, 5, 5); - valueText.follow(this, propertyText.x + propertyText.bWidth, 5); - deleteButton.follow(this, valueText.x + 135, bHeight/2 - (25/2)); - deleteIcon.follow(deleteButton, 5, 5); + updatePos(); + } + + public function updatePos() { + propertyText.follow(this, 5, bHeight/2 - (propertyText.bHeight/2)); + valueText.follow(this, propertyText.x + propertyText.bWidth, bHeight/2 - (valueText.bHeight/2)); + //deleteButton.follow(this, valueText.x + 135, bHeight/2 - (25/2)); + deleteButton.follow(this, bWidth - deleteButton.bWidth - 5, bHeight/2 - deleteButton.bHeight/2); + deleteIcon.follow(deleteButton, deleteButton.bWidth / 2 - deleteIcon.width / 2, deleteButton.bHeight / 2 - deleteIcon.height / 2); } } \ No newline at end of file diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 1ca88bcd..5e926095 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -197,6 +197,7 @@ class StageEditor extends UIState { // Load from xml var order:Array<Dynamic> = []; + var orderNodes:Array<Access> = []; stage = new Stage(__stage, this, false); stage.onXMLLoaded = function(xml:Access, elems:Array<Access>) { return elems; @@ -212,14 +213,14 @@ class StageEditor extends UIState { } stage.onNodeLoaded = function(node:Access, sprite:Dynamic):Dynamic { var parent = new Access(node.x.parent); - var name = ""; + //var name = ""; trace(node, sprite); if(sprite is FlxSprite) { //sprite.forceIsOnScreen = true; // hack } if(sprite is FunkinSprite) { var sprite:FunkinSprite = cast sprite; - name = sprite.name; + //name = sprite.name; sprite.extra.set(exID("node"), node); sprite.extra.set(exID("type"), node.name); sprite.extra.set(exID("imageFile"), '${node.getAtt("sprite").getDefault(sprite.name)}'); @@ -236,7 +237,7 @@ class StageEditor extends UIState { case "girlfriend": "gf"; default: charPos.name; } - name = charPos.name; + //name = charPos.name; var char = new Character(0,0, charName, stage.isCharFlipped(charPos.name, charName == "bf"), true); char.debugMode = true; // Play first anim, and make it the last frame @@ -265,6 +266,7 @@ class StageEditor extends UIState { chars.push(char); } order.push(sprite); + orderNodes.push(node); xmlMap.set(sprite, node); return sprite; @@ -325,7 +327,7 @@ class StageEditor extends UIState { openSubState(substate); } for (i=>sprite in order) { - var xml = xmlMap.get(sprite); + var xml = (sprite != null) ? xmlMap.get(sprite) : orderNodes[i]; if(xml != null) { if(sprite is FunkinSprite) { var sprite:FunkinSprite = cast sprite; @@ -951,7 +953,8 @@ class StageEditor extends UIState { } function handleSelection(sprite:FunkinSprite) { - var buttonBoxes = sprite.extra.get(exID("buttonBoxes")); + if(!sprite.extra.exists(exID("buttonBoxes"))) return; + var buttonBoxes:Array<FlxPoint> = cast sprite.extra.get(exID("buttonBoxes")); dotCheckSize = dot.frameWidth / 0.7/stageCamera.zoom; // basically adjust it to the zoom. diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index d9660b60..59003bec 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -25,6 +25,8 @@ class StageCharacterButton extends StageElementButton { public override function updateInfo() { char.visible = !isHidden; char.alpha = 0.5 * charPos.alpha; + charPos.scale.x = char.scale.x; + charPos.scale.y = char.scale.y; super.updateInfo(); } diff --git a/source/funkin/editors/ui/UISoftcodedWindow.hx b/source/funkin/editors/ui/UISoftcodedWindow.hx index 7b430bc3..8bf0faca 100644 --- a/source/funkin/editors/ui/UISoftcodedWindow.hx +++ b/source/funkin/editors/ui/UISoftcodedWindow.hx @@ -109,7 +109,8 @@ class UISoftcodedWindow extends UISubstateWindow { set(k, e); } set("self", this); - set("hasSaveButtons", true); + set("hasSaveButton", true); + set("hasCloseButton", true); set("getRadioButtons", function(forID:String) { var radios:Array<UIRadioButton> = cast members.filter((o) -> o is UIRadioButton); return cast radios.filter((o) -> o.forID == forID); @@ -231,6 +232,36 @@ class UISoftcodedWindow extends UISubstateWindow { add(dropdown); addLabelOn(dropdown, label); dropdown; + case "buttonlist": + //x:Float, y:Float, width:Int, height:Int, windowName:String, buttonSize:FlxPoint, ?buttonOffset:FlxPoint, ?buttonSpacing:Float + var buttonlist = new UIButtonList<UIButton>( + x, + y, + execAtt(el, "width"), + execAtt(el, "height"), + execString(el.getAtt("title")).getDefault(""), + FlxPoint.get(execAtt(el, "buttonSizeX", 0), execAtt(el, "buttonSizeY", 0)), + FlxPoint.get(execAtt(el, "buttonOffsetX", 0), execAtt(el, "buttonOffsetY", 0)), + execAtt(el, "buttonSpacing") + ); + var old = get("buttonlist"); + set("buttonlist", buttonlist); + var texture = "editors/ui/inputbox"; + var code = ""; + for(node in getArr(el.elements)) { + switch(node.name) { + case "camSpacing": buttonlist.cameraSpacing = execAtt(node, "value", 0); + case "texture": texture = execString(node.getAtt("path")).getDefault(texture); + case "code": code = node.innerData; + } + } + buttonlist.frames = Paths.getFrames(texture); + if(code != "") + exec(code); + add(buttonlist); + addLabelOn(buttonlist, label); + set("buttonlist", old); + buttonlist; // UIColorwheel // UIAudioPlayer // UIButtonList From 90d11ad2ec89971ee73b725bf4478d7d43cf17b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=8D=9A=7ENex?= <87421482+NexIsDumb@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:59:33 +0200 Subject: [PATCH 45/89] mouse selections and chars names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit studying maths for a test while it took 30m to compile each time multitask ig😭 --- source/funkin/editors/stage/StageEditor.hx | 163 +++++++++------------ 1 file changed, 69 insertions(+), 94 deletions(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 5e926095..51b66abc 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -214,7 +214,7 @@ class StageEditor extends UIState { stage.onNodeLoaded = function(node:Access, sprite:Dynamic):Dynamic { var parent = new Access(node.x.parent); //var name = ""; - trace(node, sprite); + //trace(node, sprite); if(sprite is FlxSprite) { //sprite.forceIsOnScreen = true; // hack } @@ -239,6 +239,7 @@ class StageEditor extends UIState { } //name = charPos.name; var char = new Character(0,0, charName, stage.isCharFlipped(charPos.name, charName == "bf"), true); + char.name = charName; char.debugMode = true; // Play first anim, and make it the last frame var animToPlay = char.getAnimOrder()[0]; @@ -376,6 +377,7 @@ class StageEditor extends UIState { //private var movingCam:Bool = false; //private var camDragSpeed:Float = 1.2; + private var movedTillRel:FlxPoint = FlxPoint.get(0,0); private var nextScroll:FlxPoint = FlxPoint.get(0,0); public override function update(elapsed:Float) { @@ -397,59 +399,6 @@ class StageEditor extends UIState { updateZoom(); } - /*if(FlxG.mouse.justPressed) { - var bounds:Array<FlxRect> = []; - var sprites = stageSpritesWindow.buttons.members.map((o) -> o.getSprite()).filter((o) -> o != null && o.animateAtlas == null); - for(sprite in sprites) { - if(sprite is FunkinSprite) { - var sprite:FunkinSprite = cast sprite; - if(sprite.extra.exists(exID("bounds"))) { - bounds.push(cast(sprite.extra.get(exID("bounds")), FlxRect)); - } - } - } - - // sort by area - bounds.sort((a, b) -> FlxSort.byValues(FlxSort.ASCENDING, a.width * a.height, b.width * b.height)); - - Logs.trace("------------------------"); - for(bounds in bounds) { - Logs.trace(bounds.width + "x" + bounds.height); - } - }*/ - - /*if(FlxG.mouse.justPressed) { - //var sprites = Lambda.array(stage.stageSprites); - var sprites = stageSpritesWindow.buttons.members.map((o) -> o.getSprite()).filter((o) -> o != null && o.animateAtlas == null); - trace(sprites.map((o) -> cast(o, FunkinSprite).name)); - var length = sprites.length; - // Reset selected sprites - for(i in 0...length) { - var sprite = sprites[i]; - if(sprite is FunkinSprite) { - var sprite:FunkinSprite = cast sprite; - sprite.extra.set(exID("selected"), false); - } - } - for(i in 0...length) { - var idx = length - i - 1; - var sprite = sprites[idx]; - if(sprite is FunkinSprite) { - var sprite:FunkinSprite = cast sprite; - if(!sprite.extra.exists(exID("bounds"))) continue; - trace(idx, sprite.name); - var bounds = cast(sprite.extra.get(exID("bounds")), FlxRect); - var pos = FlxG.mouse.getWorldPosition(stageCamera, _point); - trace(sprite.name, bounds, pos); - if(bounds.containsPoint(pos)) { - sprite.extra.set(exID("selected"), true); - trace("Selected " + sprite.name); - break; - } - } - } - }*/ - // TODO: make this work with multiple selections if(selection.length == 1) { for(sprite in selection) { @@ -464,9 +413,29 @@ class StageEditor extends UIState { // openContextMenu(topMenu[2].childs); //} - if (FlxG.mouse.pressed && mouseMode == NONE) { - nextScroll.set(nextScroll.x - FlxG.mouse.deltaScreenX, nextScroll.y - FlxG.mouse.deltaScreenY); - currentCursor = HAND; + if (mouseMode == NONE) { + if (FlxG.mouse.pressed) { + var pos = [FlxG.mouse.deltaScreenX, FlxG.mouse.deltaScreenY]; + movedTillRel.x += Math.abs(pos[0]); movedTillRel.y += Math.abs(pos[1]); + nextScroll.set(nextScroll.x - pos[0], nextScroll.y - pos[1]); + currentCursor = HAND; + } + + if (FlxG.mouse.justReleased) { + if (movedTillRel.x < 16 && movedTillRel.y < 16) { + var sprites = getRealSprites(); + for (i in 0...sprites.length) { + var sprite = sprites[sprites.length - i - 1]; + if(sprite.animateAtlas != null) continue; + + calcSpriteBounds(sprite); + if (cast(sprite.extra.get(exID("bounds")), FlxRect).containsPoint(FlxG.mouse.getWorldPosition(stageCamera, _point))) { + selectSprite(sprite); break; + } + } + } + movedTillRel.set(); + } } }/* else if (!FlxG.mouse.pressed) currentCursor = ARROW;*/ @@ -853,43 +822,7 @@ class StageEditor extends UIState { var circleColor = 0xFF99a8f2; function drawGuides(sprite:FlxSprite) { - var oldWidth = sprite.width; - var oldHeight = sprite.height; - var oldOffset = sprite.offset.clone(FlxPoint.weak()); - var oldOrigin = sprite.origin.clone(FlxPoint.weak()); - sprite.updateHitbox(); - sprite.offset.copyFrom(oldOffset); - sprite.origin.copyFrom(oldOrigin); - - var corners = sprite.getMatrixPosition([ - // corners - FlxPoint.get(0, 0), - FlxPoint.get(1, 0), - FlxPoint.get(0, 1), - FlxPoint.get(1, 1), - // edges - FlxPoint.get(0, 0.5), - FlxPoint.get(1, 0.5), - FlxPoint.get(0.5, 1), - FlxPoint.get(0.5, 0), - // center - //FlxPoint.get(0.5, 0.5) - ], sprite.camera, sprite.frameWidth, sprite.frameHeight); - - //Logs.trace("Guide at " + corners[0].x + ", " + corners[0].y + " sprite at " + sprite.x + ", " + sprite.y); - - if(sprite is FunkinSprite) { - var sprite:FunkinSprite = cast sprite; - var maxX = Math.max(Math.max(corners[0].x, corners[1].x), Math.max(corners[2].x, corners[3].x)); - var maxY = Math.max(Math.max(corners[0].y, corners[1].y), Math.max(corners[2].y, corners[3].y)); - var minX = Math.min(Math.min(corners[0].x, corners[1].x), Math.min(corners[2].x, corners[3].x)); - var minY = Math.min(Math.min(corners[0].y, corners[1].y), Math.min(corners[2].y, corners[3].y)); - - if(!sprite.extra.exists(exID("bounds"))) { - sprite.extra.set(exID("bounds"), new FlxRect()); - } - cast(sprite.extra.get(exID("bounds")), FlxRect).set(minX, minY, maxX - minX, maxY - minY); - } + var corners = calcSpriteBounds(sprite); var funkinSprite = sprite is FunkinSprite ? cast(sprite, FunkinSprite) : null; if(funkinSprite != null) { @@ -929,10 +862,52 @@ class StageEditor extends UIState { corner.put(); } } + } + + function calcSpriteBounds(sprite:FlxSprite) { + var oldWidth = sprite.width; + var oldHeight = sprite.height; + var oldOffset = sprite.offset.clone(FlxPoint.weak()); + var oldOrigin = sprite.origin.clone(FlxPoint.weak()); + sprite.updateHitbox(); + sprite.offset.copyFrom(oldOffset); + sprite.origin.copyFrom(oldOrigin); + + var corners = sprite.getMatrixPosition([ + // corners + FlxPoint.get(0, 0), + FlxPoint.get(1, 0), + FlxPoint.get(0, 1), + FlxPoint.get(1, 1), + // edges + FlxPoint.get(0, 0.5), + FlxPoint.get(1, 0.5), + FlxPoint.get(0.5, 1), + FlxPoint.get(0.5, 0), + // center + //FlxPoint.get(0.5, 0.5) + ], sprite.camera, sprite.frameWidth, sprite.frameHeight); + + //Logs.trace("Guide at " + corners[0].x + ", " + corners[0].y + " sprite at " + sprite.x + ", " + sprite.y); + + if(sprite is FunkinSprite) { + var sprite:FunkinSprite = cast sprite; + var maxX = Math.max(Math.max(corners[0].x, corners[1].x), Math.max(corners[2].x, corners[3].x)); + var maxY = Math.max(Math.max(corners[0].y, corners[1].y), Math.max(corners[2].y, corners[3].y)); + var minX = Math.min(Math.min(corners[0].x, corners[1].x), Math.min(corners[2].x, corners[3].x)); + var minY = Math.min(Math.min(corners[0].y, corners[1].y), Math.min(corners[2].y, corners[3].y)); + + if(!sprite.extra.exists(exID("bounds"))) { + sprite.extra.set(exID("bounds"), new FlxRect()); + } + cast(sprite.extra.get(exID("bounds")), FlxRect).set(minX, minY, maxX - minX, maxY - minY); + } // reset hitbox to old values sprite.width = oldWidth; sprite.height = oldHeight; + + return corners; } var edges:Array<StageEditorEdge> = [ From dfbd01bd22b86ffc068458ebc499e622b1db4988 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 21:12:20 +0200 Subject: [PATCH 46/89] Reordered something that bothered me --- assets/editors/layouts/stage/characterEditScreen.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/editors/layouts/stage/characterEditScreen.xml b/assets/editors/layouts/stage/characterEditScreen.xml index 3fc6e08e..b6674370 100644 --- a/assets/editors/layouts/stage/characterEditScreen.xml +++ b/assets/editors/layouts/stage/characterEditScreen.xml @@ -37,12 +37,12 @@ <stepper name="camxStepper" label="Cam X" value="charPos.camxoffset" x="col(0)" y="curY" step="1" width="100" /> <stepper name="camyStepper" label="Cam Y" value="charPos.camyoffset" x="last.x + last.bWidth + XOFFSET - 20" y="curY" step="1" width="100" /> - <stepper name="skewXStepper" label="Skew X" value="charPos.skewX" x="col(1)" y="curY" precision="2" step="0.01" width="100" /> - <stepper name="skewYStepper" label="Skew Y" value="charPos.skewY" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> - - <label name="spacingLabel" text="Spacing (X, Y)" x="col(2)" y="curY" size="15" /> - <stepper name="spacingXStepper" value="charPos.charSpacingX" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> + <label name="spacingLabel" text="Spacing (X, Y)" x="col(1)" y="curY" size="15" /> + <stepper name="spacingXStepper" value="charPos.charSpacingX" x="col(1)" y="curY" precision="2" step="0.01" width="100" /> <stepper name="spacingYStepper" value="charPos.charSpacingY" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> + + <stepper name="skewXStepper" label="Skew X" value="charPos.skewX" x="col(2)" y="curY" precision="2" step="0.01" width="100" /> + <stepper name="skewYStepper" label="Skew Y" value="charPos.skewY" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> </section> <section> From 53dc9d958e63d93caa545f03eed4aee1ff4e4292 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 21:50:09 +0200 Subject: [PATCH 47/89] Added new visible icon (icon by betah) Co-Authored-By: betah <103602526+betah96@users.noreply.github.com> --- assets/images/editors/stage/visible-icon.png | Bin 0 -> 301 bytes .../stage/elements/StageElementButton.hx | 44 +++++++++--------- .../stage/elements/StageUnknownButton.hx | 8 ++-- 3 files changed, 26 insertions(+), 26 deletions(-) create mode 100644 assets/images/editors/stage/visible-icon.png diff --git a/assets/images/editors/stage/visible-icon.png b/assets/images/editors/stage/visible-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ad78967b21442f44088345b9c73a95355f81fa12 GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^3P3Et!3HGD8EPYe6k~CayA#8@b22Z19F}xPUq=Rp zjs4tz5?O(K&H|6fVg?4j!ywFfJby(BP;iB(i(`m~_uB~v`3@QIIPd=Z-=2BhuL;t# z0yqVx?>+qLR-x9~*gws;9e%y=YcMFXk=V54)#Q!YQ8Pr9rznTU%ND)2ch&hl;YXNW z{H#A$+66eCa(`!t-ywGId+@*R_JSILusF8O_X^*BvH!sR=<(f{g0zLdul7h>@0@#l zxe;r}(YrDGvgb1KpE%`iR8!a@JL}}P%KDud%Xc)*dlqJW@2kBNe^=q&8%wrYvrJmU nH2cWr`#?AIrABzB`T8<w0ofct3<8&eCxa+YS3j3^P6<r_3M_MA literal 0 HcmV?d00001 diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index f41915b3..0aae9177 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -11,8 +11,8 @@ class StageElementButton extends UIButton { public var editButton:UIButton; public var editIcon:FlxSprite; - public var ghostButton:UIButton; - public var ghostIcon:FlxSprite; + public var visibleButton:UIButton; + public var visibleIcon:FlxSprite; public var deleteButton:UIButton; public var deleteIcon:FlxSprite; @@ -41,22 +41,22 @@ class StageElementButton extends UIButton { field.alignment = LEFT; - ghostButton = new UIButton(x+282+17, y, "", function () { + visibleButton = new UIButton(x+282+17, y, "", function () { onGhostClick(); //CharacterEditor.instance.ghostAnim(this.anim); }, 32); - ghostButton.autoAlpha = false; - members.push(ghostButton); + visibleButton.autoAlpha = false; + members.push(visibleButton); - ghostIcon = new FlxSprite(ghostButton.x + 8, ghostButton.y + 8).loadGraphic(Paths.image('editors/character/ghost-button'), true, 16, 16); - ghostIcon.animation.add("alive", [0]); - ghostIcon.animation.add("dead", [1]); - ghostIcon.animation.play("dead"); ghostIcon.alpha = 0.5; - ghostIcon.antialiasing = false; - ghostIcon.updateHitbox(); - members.push(ghostIcon); + visibleIcon = new FlxSprite(visibleButton.x + 8, visibleButton.y + 8).loadGraphic(Paths.image('editors/stage/visible-icon'), true, 16, 16); + visibleIcon.animation.add("visible", [0]); + visibleIcon.animation.add("invisible", [1]); + visibleIcon.animation.play("visible"); + visibleIcon.antialiasing = false; + visibleIcon.updateHitbox(); + members.push(visibleIcon); - editButton = new UIButton(ghostButton.x+32+17, y, "", function () { + editButton = new UIButton(visibleButton.x+32+17, y, "", function () { onEdit(); }, 32); editButton.frames = Paths.getFrames("editors/ui/grayscale-button"); @@ -83,8 +83,8 @@ class StageElementButton extends UIButton { var _lastSelected:Bool = false; public override function update(elapsed:Float) { - editButton.selectable = ghostButton.selectable = deleteButton.selectable = selectable; - editButton.shouldPress = ghostButton.shouldPress = deleteButton.shouldPress = shouldPress; + editButton.selectable = visibleButton.selectable = deleteButton.selectable = selectable; + editButton.shouldPress = visibleButton.shouldPress = deleteButton.shouldPress = shouldPress; hovered = !deleteButton.hovered; updatePos(); @@ -125,8 +125,8 @@ class StageElementButton extends UIButton { public function updateInfo() { field.text = getInfoText(); - ghostIcon.animation.play(!isHidden ? "alive" : "dead"); - ghostIcon.alpha = !isHidden ? 1 : 0.5; + visibleIcon.animation.play(isHidden ? "invisible" : "visible"); + //visibleIcon.alpha = !isHidden ? 1 : 0.5; } public function updatePos() { @@ -137,12 +137,12 @@ class StageElementButton extends UIButton { deleteButton.y = buttonY; editButton.x = deleteButton.x - editButton.bWidth - spacing; editButton.y = buttonY; - ghostButton.x = editButton.x - ghostButton.bWidth - spacing; - ghostButton.y = buttonY; - //deleteButton.x = (editButton.x = (ghostButton.x = (x+282+17))+32+17)+32+17; - //deleteButton.y = editButton.y = ghostButton.y = y; + visibleButton.x = editButton.x - visibleButton.bWidth - spacing; + visibleButton.y = buttonY; + //deleteButton.x = (editButton.x = (visibleButton.x = (x+282+17))+32+17)+32+17; + //deleteButton.y = editButton.y = visibleButton.y = y; // icons - ghostIcon.x = ghostButton.x + 8; ghostIcon.y = ghostButton.y + 8; + visibleIcon.x = visibleButton.x + 8; visibleIcon.y = visibleButton.y + 8; editIcon.x = editButton.x + 8; editIcon.y = editButton.y + 8; deleteIcon.x = deleteButton.x + (15/2); deleteIcon.y = deleteButton.y + 8; diff --git a/source/funkin/editors/stage/elements/StageUnknownButton.hx b/source/funkin/editors/stage/elements/StageUnknownButton.hx index 70c4f7ae..cc1565d8 100644 --- a/source/funkin/editors/stage/elements/StageUnknownButton.hx +++ b/source/funkin/editors/stage/elements/StageUnknownButton.hx @@ -18,11 +18,11 @@ class StageUnknownButton extends StageElementButton { color = 0xff000000; - ghostButton.exists = false; - members.remove(ghostButton); + visibleButton.exists = false; + members.remove(visibleButton); - ghostIcon.exists = false; - members.remove(ghostIcon); + visibleIcon.exists = false; + members.remove(visibleIcon); updateInfo(); } From 900e2b075f8409b5a396352e4e923069bf56cf6b Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 21:55:07 +0200 Subject: [PATCH 48/89] Better name for visibility --- .../stage/elements/StageCharacterButton.hx | 2 +- .../stage/elements/StageElementButton.hx | 50 +++++++++---------- .../stage/elements/StageSpriteButton.hx | 2 +- .../stage/elements/StageUnknownButton.hx | 10 ++-- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index 59003bec..14d510a8 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -52,7 +52,7 @@ class StageCharacterButton extends StageElementButton { // CoolUtil.playMenuSFX(WARNING, 0.45); //} - public override function onGhostClick() { + public override function onVisiblityToggle() { isHidden = !isHidden; updateInfo(); } diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index 0aae9177..3535dc1b 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -11,8 +11,8 @@ class StageElementButton extends UIButton { public var editButton:UIButton; public var editIcon:FlxSprite; - public var visibleButton:UIButton; - public var visibleIcon:FlxSprite; + public var visibilityButton:UIButton; + public var visibilityIcon:FlxSprite; public var deleteButton:UIButton; public var deleteIcon:FlxSprite; @@ -27,7 +27,6 @@ class StageElementButton extends UIButton { this.xml = xml; super(x,y, getInfoText(), function () { onSelect(); - //CharacterEditor.instance.playAnimation(this.sprite.name); }, StageEditor.SPRITE_WINDOW_WIDTH, StageEditor.SPRITE_WINDOW_BUTTON_HEIGHT); autoAlpha = false; @@ -41,22 +40,21 @@ class StageElementButton extends UIButton { field.alignment = LEFT; - visibleButton = new UIButton(x+282+17, y, "", function () { - onGhostClick(); - //CharacterEditor.instance.ghostAnim(this.anim); + visibilityButton = new UIButton(x+282+17, y, "", function () { + onVisiblityToggle(); }, 32); - visibleButton.autoAlpha = false; - members.push(visibleButton); + visibilityButton.autoAlpha = false; + members.push(visibilityButton); - visibleIcon = new FlxSprite(visibleButton.x + 8, visibleButton.y + 8).loadGraphic(Paths.image('editors/stage/visible-icon'), true, 16, 16); - visibleIcon.animation.add("visible", [0]); - visibleIcon.animation.add("invisible", [1]); - visibleIcon.animation.play("visible"); - visibleIcon.antialiasing = false; - visibleIcon.updateHitbox(); - members.push(visibleIcon); + visibilityIcon = new FlxSprite(visibilityButton.x + 8, visibilityButton.y + 8).loadGraphic(Paths.image('editors/stage/visible-icon'), true, 16, 16); + visibilityIcon.animation.add("visible", [0]); + visibilityIcon.animation.add("invisible", [1]); + visibilityIcon.animation.play("visible"); + visibilityIcon.antialiasing = false; + visibilityIcon.updateHitbox(); + members.push(visibilityIcon); - editButton = new UIButton(visibleButton.x+32+17, y, "", function () { + editButton = new UIButton(visibilityButton.x+32+17, y, "", function () { onEdit(); }, 32); editButton.frames = Paths.getFrames("editors/ui/grayscale-button"); @@ -83,8 +81,8 @@ class StageElementButton extends UIButton { var _lastSelected:Bool = false; public override function update(elapsed:Float) { - editButton.selectable = visibleButton.selectable = deleteButton.selectable = selectable; - editButton.shouldPress = visibleButton.shouldPress = deleteButton.shouldPress = shouldPress; + editButton.selectable = visibilityButton.selectable = deleteButton.selectable = selectable; + editButton.shouldPress = visibilityButton.shouldPress = deleteButton.shouldPress = shouldPress; hovered = !deleteButton.hovered; updatePos(); @@ -125,8 +123,8 @@ class StageElementButton extends UIButton { public function updateInfo() { field.text = getInfoText(); - visibleIcon.animation.play(isHidden ? "invisible" : "visible"); - //visibleIcon.alpha = !isHidden ? 1 : 0.5; + visibilityIcon.animation.play(isHidden ? "invisible" : "visible"); + //visibilityIcon.alpha = !isHidden ? 1 : 0.5; } public function updatePos() { @@ -137,12 +135,12 @@ class StageElementButton extends UIButton { deleteButton.y = buttonY; editButton.x = deleteButton.x - editButton.bWidth - spacing; editButton.y = buttonY; - visibleButton.x = editButton.x - visibleButton.bWidth - spacing; - visibleButton.y = buttonY; - //deleteButton.x = (editButton.x = (visibleButton.x = (x+282+17))+32+17)+32+17; - //deleteButton.y = editButton.y = visibleButton.y = y; + visibilityButton.x = editButton.x - visibilityButton.bWidth - spacing; + visibilityButton.y = buttonY; + //deleteButton.x = (editButton.x = (visibilityButton.x = (x+282+17))+32+17)+32+17; + //deleteButton.y = editButton.y = visibilityButton.y = y; // icons - visibleIcon.x = visibleButton.x + 8; visibleIcon.y = visibleButton.y + 8; + visibilityIcon.x = visibilityButton.x + 8; visibilityIcon.y = visibilityButton.y + 8; editIcon.x = editButton.x + 8; editIcon.y = editButton.y + 8; deleteIcon.x = deleteButton.x + (15/2); deleteIcon.y = deleteButton.y + 8; @@ -166,7 +164,7 @@ class StageElementButton extends UIButton { // TODO: implement } - public function onGhostClick() { + public function onVisiblityToggle() { // TODO: implement } diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index ac133b14..79fad780 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -34,7 +34,7 @@ class StageSpriteButton extends StageElementButton { StageEditor.instance.selectSprite(sprite); } - public override function onGhostClick() { + public override function onVisiblityToggle() { isHidden = !isHidden; updateInfo(); } diff --git a/source/funkin/editors/stage/elements/StageUnknownButton.hx b/source/funkin/editors/stage/elements/StageUnknownButton.hx index cc1565d8..6844fd18 100644 --- a/source/funkin/editors/stage/elements/StageUnknownButton.hx +++ b/source/funkin/editors/stage/elements/StageUnknownButton.hx @@ -18,11 +18,11 @@ class StageUnknownButton extends StageElementButton { color = 0xff000000; - visibleButton.exists = false; - members.remove(visibleButton); + visibilityButton.exists = false; + members.remove(visibilityButton); - visibleIcon.exists = false; - members.remove(visibleIcon); + visibilityIcon.exists = false; + members.remove(visibilityIcon); updateInfo(); } @@ -59,7 +59,7 @@ class StageUnknownButton extends StageElementButton { // CoolUtil.playMenuSFX(WARNING, 0.45); //} - public override function onGhostClick() { + public override function onVisiblityToggle() { } public override function getName():String { From 52fbe9aaf79612b107aa0a9c83c672b04e292915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=8D=9A=7ENex?= <87421482+NexIsDumb@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:25:10 +0200 Subject: [PATCH 49/89] slightly better and alpha value --- assets/editors/layouts/stage/spriteEditScreen.xml | 7 ++++++- source/funkin/editors/stage/StageEditor.hx | 7 ++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index 611e5feb..6968066b 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -22,7 +22,9 @@ <set name="curY" value="title.y + TO" /> <textbox name="nameTextBox" label="Name Identifier" value="button.getName()" x="col(0)" y="curY" width="200" height="32" /> - <textbox name="spriteTextBox" label="Image File (${stage.spritesParentFolder})" value="getEx('imageFile')" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" /> + <textbox name="spriteTextBox" value="getEx('imageFile')" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" /> + <label name="imageFile" text="Image File In (${stage.spritesParentFolder})" x="last.x" y="nameTextBox.y - 14" size="15" /> + <stepper name="alphaStepper" label="Alpha" value="sprite.alpha" x="spriteTextBox.x + spriteTextBox.bWidth + XOFFSET" y="curY" precision="2" step="0.01" width="100" /> </section> <section> <!-- ROW 2 --> @@ -79,6 +81,7 @@ previewSprite.skew.x = skewXStepper.value; previewSprite.skew.y = skewYStepper.value; previewSprite.angle = angleStepper.value; + previewSprite.alpha = alphaStepper.value; previewSprite.antialiasing = antialiasingCheckbox.checked; var ratio = sprite.width / sprite.height; previewSprite.setGraphicSize(50 * scaleXStepper.value * ratio, 50 * scaleYStepper.value); @@ -99,6 +102,7 @@ //sprite.color = colorWheel.color; //sprite.spriteAnimType = animType.value; sprite.angle = angleStepper.value; + sprite.alpha = alphaStepper.value; function saveXY(obj:Dynamic, name:String, x:UINumericStepper, y:UINumericStepper) { button.xml.remove(name + ""); @@ -124,6 +128,7 @@ button.xml.set("type", animType.key); button.xml.set("antialiasing", antialiasingCheckbox.checked); button.xml.set("angle", angleStepper.value); + button.xml.set("alpha", alphaStepper.value); saveXY(sprite.scrollFactor, "scroll", scrollXStepper, scrollYStepper); saveXY(sprite.scale, "scale", scaleXStepper, scaleYStepper); diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 51b66abc..e0e4fc33 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -416,20 +416,21 @@ class StageEditor extends UIState { if (mouseMode == NONE) { if (FlxG.mouse.pressed) { var pos = [FlxG.mouse.deltaScreenX, FlxG.mouse.deltaScreenY]; - movedTillRel.x += Math.abs(pos[0]); movedTillRel.y += Math.abs(pos[1]); + movedTillRel.x += pos[0]; movedTillRel.y += pos[1]; nextScroll.set(nextScroll.x - pos[0], nextScroll.y - pos[1]); currentCursor = HAND; } if (FlxG.mouse.justReleased) { - if (movedTillRel.x < 16 && movedTillRel.y < 16) { + if (Math.abs(movedTillRel.x) < 16 && Math.abs(movedTillRel.y) < 16) { + var point = FlxG.mouse.getWorldPosition(stageCamera, _point); var sprites = getRealSprites(); for (i in 0...sprites.length) { var sprite = sprites[sprites.length - i - 1]; if(sprite.animateAtlas != null) continue; calcSpriteBounds(sprite); - if (cast(sprite.extra.get(exID("bounds")), FlxRect).containsPoint(FlxG.mouse.getWorldPosition(stageCamera, _point))) { + if (cast(sprite.extra.get(exID("bounds")), FlxRect).containsPoint(point)) { selectSprite(sprite); break; } } From a1a0b04cdb686f52bafd447e8a347ce0258a23cf Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:35:11 +0200 Subject: [PATCH 50/89] Remade the edit icon --- assets/images/editors/character/edit-button.png | Bin 335 -> 180 bytes assets/images/editors/stage/visible-icon.png | Bin 301 -> 133 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/images/editors/character/edit-button.png b/assets/images/editors/character/edit-button.png index e0018a547525ca652a7510bc245fab0b2904a965..7c257b718d52c7c23c0acc20107c6bab556c53e4 100644 GIT binary patch delta 152 zcmV;J0B8Tt0<-~;B!7EJL_t(|0b?K*{D%T$F_JVZD@%eg2#}@uc+Hys_j(V&4IxD{ zNF&Gq7={}{th13dW4Hvb=Idu9{=a^xh0PGS0faPzXb=X8k*yioC1h&`(SuJj!hoB* z^FfLTYQ|>(%n(AFF#%KoiXoVq2^)ZH2<e&TKPn(eGXP_kbrHLwB1@P60000<MNUMn GLSTYoQaio? delta 308 zcmV-40n7fh0nY-EB!2;OQb$4nuFf3k0003ANkl<ZIE|f>u};G<6h%+`50TZO>f9YE zD?fmuEL~XG8H$C3{0R{fN*J;+u&}U15kJ7d5-B?a6JkIS|Ijemvg5Q3+|hpL`o8xJ zGnJ*uFt>IR{&;vBrc9za@a4%B0IS84o0n_qrnTHb0|T!XOMgDUzwCL{mDWTYf{T1d z)s-F$aC>%VXEK?<z<vJ%Kwd~p8?LIZ3=Oh08MNwyV%Nl-g&4y{zME`GtDdSWgF!}P z*u*xHGWO2$LWW!TFAUBWlom)C{|N>VS(*&n%{nkKu$1v$*h{e8tf`w8rTwp=wAc%K z2B+tbygpsnxGl$CHj1(|8S19Bu+jbV`%xI2EsQVbzyQBaosQv`TT0ac0000<MNUMn GLSTXbpO75@ diff --git a/assets/images/editors/stage/visible-icon.png b/assets/images/editors/stage/visible-icon.png index ad78967b21442f44088345b9c73a95355f81fa12..2e6033332341899adaecdc5740c49a74203c5f38 100644 GIT binary patch delta 116 zcmZ3>)XF$PBA1Z?2;!?9z5pqvk|4ie28Oc9XDxs{J5LwKkP60R2gV$pH~cs58=Uw* zVgJE|<mBW-0ha5H`X7G(8~?rW$oZcRd0S-y4xM3J(ej-=VB;6&1$xXX!VH$4B8S!; RV0{TP-_zC4Wt~$(698O^EG_^5 delta 286 zcmZo=T+1{;qMn0|fq|i%p*9joF%}28J29*~C-V}>VM%xNb!1@J*w6hZkrl}2Ebxdd zW?<ku48n}Z^H-z*1y^{wIEHw5znyT9?~nnH^X|X@?U~p8njk$ZfKy=l-ovkM6>6=G z{nLEg;nxel27@9SiA_shP2QLtHA7T+igIYYY*GDtdsm&`6Mls0#n1Y4rCosIDff4V z_#I;Rz6by7ZZD`22#aIee6R5B7yA#~j~?HRDM(xR`)ZHG_0GA+mm9Hm9K9Q}FMBQ% z|A|xXMm2>kva?QptE}Idv3y6<yk}w7_rBUY@pl#Oy|HAgHOr(mOtX({z7KRXUuuMB dny)W|7LYB@0VF`+Qt)ID<>~6@vd$@?2>=aCb436E From e60c38ac0dfeb1bc70665d51c93863c4e0bde6bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=8D=9A=7ENex?= <87421482+NexIsDumb@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:36:03 +0200 Subject: [PATCH 51/89] =?UTF-8?q?perfectionism=F0=9F=98=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/editors/layouts/stage/spriteEditScreen.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/editors/layouts/stage/spriteEditScreen.xml index 6968066b..9c49f410 100644 --- a/assets/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/editors/layouts/stage/spriteEditScreen.xml @@ -23,8 +23,8 @@ <textbox name="nameTextBox" label="Name Identifier" value="button.getName()" x="col(0)" y="curY" width="200" height="32" /> <textbox name="spriteTextBox" value="getEx('imageFile')" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" /> - <label name="imageFile" text="Image File In (${stage.spritesParentFolder})" x="last.x" y="nameTextBox.y - 14" size="15" /> <stepper name="alphaStepper" label="Alpha" value="sprite.alpha" x="spriteTextBox.x + spriteTextBox.bWidth + XOFFSET" y="curY" precision="2" step="0.01" width="100" /> + <label name="imageFile" text="Image File In (${stage.spritesParentFolder})" x="spriteTextBox.x" y="spriteTextBox.y - 14" size="15" /> </section> <section> <!-- ROW 2 --> From f61502c2d514301d926b62fa6d21a2109a597021 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Tue, 16 Apr 2024 23:23:21 +0200 Subject: [PATCH 52/89] Made visibility icon change alpha --- source/funkin/editors/stage/elements/StageElementButton.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index 3535dc1b..6b188a94 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -124,7 +124,7 @@ class StageElementButton extends UIButton { field.text = getInfoText(); visibilityIcon.animation.play(isHidden ? "invisible" : "visible"); - //visibilityIcon.alpha = !isHidden ? 1 : 0.5; + visibilityIcon.alpha = !isHidden ? 1 : 0.5; } public function updatePos() { From 88eb0d48e03c3ad40d310d2d9f68ca20e6806dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=8D=9A=7ENex?= <87421482+NexIsDumb@users.noreply.github.com> Date: Tue, 16 Apr 2024 23:24:53 +0200 Subject: [PATCH 53/89] editors/ inside data/ --- assets/{ => data}/editors/layouts/stage/characterEditScreen.xml | 0 assets/{ => data}/editors/layouts/stage/spriteEditScreen.xml | 0 assets/{ => data}/editors/layouts/stage/unknownEditScreen.xml | 0 source/funkin/editors/stage/elements/StageCharacterButton.hx | 2 +- source/funkin/editors/stage/elements/StageSpriteButton.hx | 2 +- source/funkin/editors/stage/elements/StageUnknownButton.hx | 2 +- source/funkin/editors/ui/UISoftcodedWindow.hx | 2 +- 7 files changed, 4 insertions(+), 4 deletions(-) rename assets/{ => data}/editors/layouts/stage/characterEditScreen.xml (100%) rename assets/{ => data}/editors/layouts/stage/spriteEditScreen.xml (100%) rename assets/{ => data}/editors/layouts/stage/unknownEditScreen.xml (100%) diff --git a/assets/editors/layouts/stage/characterEditScreen.xml b/assets/data/editors/layouts/stage/characterEditScreen.xml similarity index 100% rename from assets/editors/layouts/stage/characterEditScreen.xml rename to assets/data/editors/layouts/stage/characterEditScreen.xml diff --git a/assets/editors/layouts/stage/spriteEditScreen.xml b/assets/data/editors/layouts/stage/spriteEditScreen.xml similarity index 100% rename from assets/editors/layouts/stage/spriteEditScreen.xml rename to assets/data/editors/layouts/stage/spriteEditScreen.xml diff --git a/assets/editors/layouts/stage/unknownEditScreen.xml b/assets/data/editors/layouts/stage/unknownEditScreen.xml similarity index 100% rename from assets/editors/layouts/stage/unknownEditScreen.xml rename to assets/data/editors/layouts/stage/unknownEditScreen.xml diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index 14d510a8..9a97f306 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -79,7 +79,7 @@ class StageCharacterEditScreen extends UISoftcodedWindow { this.button = button; this.char = button.char; this.charPos = button.charPos; - super("layouts/stage/characterEditScreen.xml", [ + super("layouts/stage/characterEditScreen", [ "stage" => StageEditor.instance.stage, "char" => char, "charPos" => charPos, diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index 79fad780..264bba05 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -73,7 +73,7 @@ class StageSpriteEditScreen extends UISoftcodedWindow { public function new(button:StageSpriteButton) { this.button = button; this.sprite = button.getSprite(); - super("layouts/stage/spriteEditScreen.xml", [ + super("layouts/stage/spriteEditScreen", [ "stage" => StageEditor.instance.stage, "sprite" => sprite, "button" => button, diff --git a/source/funkin/editors/stage/elements/StageUnknownButton.hx b/source/funkin/editors/stage/elements/StageUnknownButton.hx index 6844fd18..371ba403 100644 --- a/source/funkin/editors/stage/elements/StageUnknownButton.hx +++ b/source/funkin/editors/stage/elements/StageUnknownButton.hx @@ -84,7 +84,7 @@ class StageUnknownEditScreen extends UISoftcodedWindow { public function new(button:StageUnknownButton) { this.button = button; - super("layouts/stage/unknownEditScreen.xml", [ + super("layouts/stage/unknownEditScreen", [ "stage" => StageEditor.instance.stage, "button" => button, "xml" => button.xml, diff --git a/source/funkin/editors/ui/UISoftcodedWindow.hx b/source/funkin/editors/ui/UISoftcodedWindow.hx index 8bf0faca..e791f883 100644 --- a/source/funkin/editors/ui/UISoftcodedWindow.hx +++ b/source/funkin/editors/ui/UISoftcodedWindow.hx @@ -103,7 +103,7 @@ class UISoftcodedWindow extends UISubstateWindow { } public override function create() { - var layout = new Access(Xml.parse(Assets.getText('assets/editors/' + xmlPath)).firstElement()); + var layout = new Access(Xml.parse(Assets.getText(Paths.xml("editors/" + xmlPath))).firstElement()); for(k=>e in Script.getDefaultVariables()) { set(k, e); From c1a977ce1498b76f3a112636096321eb725a67d0 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Wed, 17 Apr 2024 07:51:45 -0700 Subject: [PATCH 54/89] use a context menu for adding i got school but ill fix some of the suadhnasidj when back home --- .../layouts/stage/characterEditScreen.xml | 4 + source/funkin/editors/stage/StageEditor.hx | 119 ++++++++++++++---- source/funkin/editors/ui/UIContextMenu.hx | 6 +- source/funkin/editors/ui/UIState.hx | 4 +- 4 files changed, 108 insertions(+), 25 deletions(-) diff --git a/assets/data/editors/layouts/stage/characterEditScreen.xml b/assets/data/editors/layouts/stage/characterEditScreen.xml index b6674370..22b64ac5 100644 --- a/assets/data/editors/layouts/stage/characterEditScreen.xml +++ b/assets/data/editors/layouts/stage/characterEditScreen.xml @@ -52,6 +52,10 @@ <stepper name="angleStepper" label="Angle" value="charPos.angle" x="last.x + last.bWidth + XOFFSET - 20" y="curY" precision="2" step="0.01" width="100" /> <stepper name="zoomFactorStepper" label="Zoom Factor" value="charPos.zoomFactor" x="col(1)" y="curY" precision="2" step="0.01" width="100" /> + + <section if="charPos.extra.exists('extraPos')"> + <textbox name="charName" label="Position Name" value="charPos.name" x="col(2)" y="curY" width="100"/> + </section> </section> <section> diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index e0e4fc33..2e73cc54 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -305,27 +305,32 @@ class StageEditor extends UIState { members.insert(newID, sprite); } stageSpritesWindow.addButton.callback = () -> { - var node:Access = new Access(Xml.createElement("sprite")); - stage.stageXML.x.addChild(node.x); - node.att.name = "sprite_" + stageSpritesWindow.buttons.length; - - var sprite:FunkinSprite = new FunkinSprite(); - add(sprite); - sprite.extra.set(exID("node"), node); - sprite.extra.set(exID("type"), node.name); - sprite.extra.set(exID("imageFile"), ''); - sprite.extra.set(exID("parentNode"), new Access(node.x.parent)); - sprite.extra.set(exID("highMemory"), false); - sprite.extra.set(exID("lowMemory"), false); - xmlMap.set(sprite, node); - - var button:StageSpriteButton = new StageSpriteButton(0, 0, sprite, node); - sprite.extra.set(exID("button"), button); - stageSpritesWindow.add(button); - - var substate = new StageSpriteEditScreen(button); - substate.newSprite = true; - openSubState(substate); + var lastDrawCam = stageSpritesWindow.addButton.__lastDrawCameras[0]; + var screenPos = stageSpritesWindow.addButton.getScreenPosition(null, lastDrawCam == null ? FlxG.camera : lastDrawCam); + openContextMenu([ + { + label: "Sprite", + onSelect: _sprite_new, + color: 0xFF00FF00, + icon: 2 + }, + { + label: "Box", + onSelect: function(_) { + UIState.state.displayNotification(new UIBaseNotification("Creating a box isnt implemented yet!", 2, BOTTOM_LEFT)); + CoolUtil.playMenuSFX(WARNING, 0.45); + }, + color: 0xFF00FF00, + icon: 2 + }, + { + label: "Character", + onSelect: _character_new, + color: 0xFF00FF00, + icon: 2 + } + ], null, lastDrawCam.x + screenPos.x, lastDrawCam.y + screenPos.y + stageSpritesWindow.addButton.bHeight, stageSpritesWindow.addButton.bWidth); + screenPos.put(); } for (i=>sprite in order) { var xml = (sprite != null) ? xmlMap.get(sprite) : orderNodes[i]; @@ -478,6 +483,78 @@ class StageEditor extends UIState { undos.save(); } + function _sprite_new(_) { + var node:Access = new Access(Xml.createElement("sprite")); + stage.stageXML.x.addChild(node.x); + node.att.name = "sprite_" + stageSpritesWindow.buttons.length; + + var sprite:FunkinSprite = new FunkinSprite(); + insert(members.indexOf(stage), sprite); + sprite.extra.set(exID("node"), node); + sprite.extra.set(exID("type"), node.name); + sprite.extra.set(exID("imageFile"), ''); + sprite.extra.set(exID("parentNode"), stage.stageXML.x); + sprite.extra.set(exID("highMemory"), false); + sprite.extra.set(exID("lowMemory"), false); + xmlMap.set(sprite, node); + + var button:StageSpriteButton = new StageSpriteButton(0, 0, sprite, node); + sprite.extra.set(exID("button"), button); + stageSpritesWindow.add(button); + + var substate = new StageSpriteEditScreen(button); + substate.newSprite = true; + openSubState(substate); + } + + function _character_new(_) { + var node:Access = new Access(Xml.createElement("char")); + stage.stageXML.x.addChild(node.x); + node.att.name = "character_" + stageSpritesWindow.buttons.length; + + var charPos = new StageCharPos(); + charPos.visible = charPos.active = false; + charPos.name = "character_" + stageSpritesWindow.buttons.length; + charPos.extra.set(exID("extraChar"), true); + stage.characterPoses[charPos.name] = charPos; + + var char = new Character(0,0, "bf", stage.isCharFlipped(charPos.name, true), true); + char.name = "bf"; + char.debugMode = true; + // Play first anim, and make it the last frame + var animToPlay = char.getAnimOrder()[0]; + char.playAnim(animToPlay, true, NONE); + var lastIndx = (char.animateAtlas != null) ? + char.animateAtlas.anim.length - 1 : + char.animation.curAnim.numFrames - 1; + char.playAnim(animToPlay, true, NONE, false, lastIndx); + char.stopAnimation(); + + // Add it to the stage + char.visible = true; + char.alpha = 0.5; + function setEx(name:String, value:Dynamic) { + char.extra.set(exID(name), value); + charPos.extra.set(exID(name), value); + } + setEx("node", node); + setEx("pos", charPos); + setEx("char", char); + + setEx("parentNode", stage.stageXML); + setEx("highMemory", false); + setEx("lowMemory", false); + chars.push(char); + + stage.applyCharStuff(char, charPos.name, 0); + charMap[charPos.name] = char; + + var button = new StageCharacterButton(0,0, charPos, node); + char.extra.set(exID("button"), button); + charPos.extra.set(exID("button"), button); + stageSpritesWindow.add(button); + } + function saveToXml(xml:Xml, name:String, value:Dynamic, ?defaultValue:Dynamic) { if(value == null || value == defaultValue) return xml; xml.set(name, Std.string(value)); diff --git a/source/funkin/editors/ui/UIContextMenu.hx b/source/funkin/editors/ui/UIContextMenu.hx index 8cc5bcb0..36db45ab 100644 --- a/source/funkin/editors/ui/UIContextMenu.hx +++ b/source/funkin/editors/ui/UIContextMenu.hx @@ -7,6 +7,7 @@ class UIContextMenu extends MusicBeatSubstate { public var options:Array<UIContextMenuOption>; var x:Float; var y:Float; + var w:Int = 100; var contextCam:FlxCamera; var bg:UISliceSprite; @@ -21,11 +22,12 @@ class UIContextMenu extends MusicBeatSubstate { __oobDeletion = false; } - public function new(options:Array<UIContextMenuOption>, callback:UIContextMenuCallback, x:Float, y:Float) { + public function new(options:Array<UIContextMenuOption>, callback:UIContextMenuCallback, x:Float, y:Float, ?w:Int = 100) { super(); this.options = options.getDefault([]); this.x = x; this.y = y; + this.w = w; this.callback = callback; } @@ -37,7 +39,7 @@ class UIContextMenu extends MusicBeatSubstate { contextCam.scroll.set(0, 7.5); FlxG.cameras.add(contextCam, false); - bg = new UISliceSprite(x, y, 100, 100, 'editors/ui/context-bg'); + bg = new UISliceSprite(x, y, w, 100, 'editors/ui/context-bg'); bg.cameras = [contextCam]; add(bg); diff --git a/source/funkin/editors/ui/UIState.hx b/source/funkin/editors/ui/UIState.hx index c1716104..e2e580af 100644 --- a/source/funkin/editors/ui/UIState.hx +++ b/source/funkin/editors/ui/UIState.hx @@ -136,7 +136,7 @@ class UIState extends MusicBeatState { } } - public function openContextMenu(options:Array<UIContextMenuOption>, ?callback:UIContextMenuCallback, ?x:Float, ?y:Float) { + public function openContextMenu(options:Array<UIContextMenuOption>, ?callback:UIContextMenuCallback, ?x:Float, ?y:Float, ?w:Int) { var state = FlxG.state; while(state.subState != null && !(state._requestSubStateReset && state._requestedSubState == null)) state = state.subState; @@ -144,7 +144,7 @@ class UIState extends MusicBeatState { state.persistentDraw = true; state.persistentUpdate = true; - state.openSubState(curContextMenu = new UIContextMenu(options, callback, x.getDefault(__mousePos.x), y.getDefault(__mousePos.y))); + state.openSubState(curContextMenu = new UIContextMenu(options, callback, x.getDefault(__mousePos.x), y.getDefault(__mousePos.y), w)); return curContextMenu; } From 65e8b9b4e2f72cc7d02ad2cc09e662a1732ee64e Mon Sep 17 00:00:00 2001 From: Dirk-Dinkum <134403819+Dirk-Dinkum@users.noreply.github.com> Date: Wed, 17 Apr 2024 19:45:35 +0200 Subject: [PATCH 55/89] rot scaling --- assets/data/states/StageEditor.hx | 83 ++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 7 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index 9f731f91..f18d377a 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -1,11 +1,11 @@ /** - * THIS FILE IS TEMPORARY UNTIL TRANSFORMS ARE AT A USEABLE STATE. - * TODO: - * - !!!! MOVE BACK TO SOURCE !!!! - * - Rotation - * - Skewing - * - Angle + Scale (like already at a angle) - */ +* THIS FILE IS TEMPORARY UNTIL TRANSFORMS ARE AT A USEABLE STATE. +* TODO: +* - !!!! MOVE BACK TO SOURCE !!!! +* - Rotation +* - Skewing +* - Angle + Scale (like already at a angle) +*/ import funkin.editors.stage.StageEditor; import funkin.editors.ui.UIWarningSubstate; @@ -77,6 +77,7 @@ function update() { } function genericScale(sprite, relative, doX, doY) { + var relativeMult = 1 / (FlxMath.lerp(1, stageCamera.zoom, sprite.zoomFactor) / stageCamera.zoom) * (FlxG.keys.pressed.ALT ? 2 : 1); relative.x *= relativeMult; relative.y *= relativeMult; @@ -118,38 +119,105 @@ function genericOppositeScale(sprite, relative, scaleX, scaleY, repositionX, rep } } +var oldSpritePos = FlxPoint.get(); function SCALE_BOTTOM_RIGHT(sprite, relative) { + preRotBullshit(sprite, relative); genericScale(sprite, relative, true, true); + postRotBullshit(sprite, relative); } +/** + ROTATION +**/ +function preRotBullshit(sprite, relative) { + // just remove the other line in source + rotateByDegrees(relative, -sprite.angle); + + if (sprite.angle != 0) + relative = rotateAround(relative, FlxPoint.weak(0, 0), -sprite.angle); + + if (FlxG.mouse.justPressed) { + oldSpritePos.x = sprite.x; + oldSpritePos.y = sprite.y; + } +} + +function postRotBullshit(sprite, relative) { + if (sprite.angle != 0) { + var p = rotateAround(FlxPoint.get(sprite.x, sprite.y), oldSpritePos, sprite.angle); + sprite.x = p.x; + sprite.y = p.y; + } +} +import flixel.math.FlxAngle; + +function rotateAround(p, origin, angle) { + var rel = FlxPoint.get(p.x - origin.x, p.y - origin.y); + rotateByDegrees(rel, angle); + p.x = origin.x + rel.x; + p.y = origin.y + rel.y; + return p; +} + function rotateByDegrees(p, angle) { + var rads = angle * FlxAngle.TO_RAD; + var s:Float = Math.sin(rads); + var c:Float = Math.cos(rads); + var tempX:Float = p.x; + + p.x = tempX * c - p.y * s; + p.y = tempX * s + p.y * c; + + return this; + } + /** + END OF ROTATION + **/ + + function SCALE_TOP_RIGHT(sprite, relative) { + preRotBullshit(sprite, relative); genericOppositeScale(sprite, relative, true, true, false, true); + postRotBullshit(sprite, relative); } function SCALE_TOP_LEFT(sprite, relative) { + preRotBullshit(sprite, relative); genericOppositeScale(sprite, relative, true, true, true, true); + postRotBullshit(sprite, relative); } function SCALE_BOTTOM_LEFT(sprite, relative) { + preRotBullshit(sprite, relative); genericOppositeScale(sprite, relative, true, true, true, false); + postRotBullshit(sprite, relative); } function SCALE_LEFT(sprite, relative) { + preRotBullshit(sprite, relative); genericOppositeScale(sprite, relative, true, false, true, false); + postRotBullshit(sprite, relative); } function SCALE_RIGHT(sprite, relative) { + preRotBullshit(sprite, relative); genericScale(sprite, relative, true, false); + postRotBullshit(sprite, relative); } function SCALE_TOP(sprite, relative) { + preRotBullshit(sprite, relative); genericOppositeScale(sprite, relative, false, true, false, true); + postRotBullshit(sprite, relative); } function SCALE_BOTTOM(sprite, relative) { + preRotBullshit(sprite, relative); genericScale(sprite, relative, false, true); + postRotBullshit(sprite, relative); } + + function SKEW_LEFT(sprite, relative) {} function SKEW_BOTTOM(sprite, relative) {} @@ -160,3 +228,4 @@ function SKEW_RIGHT(sprite, relative) {} function ROTATE(sprite, relative) {} + From f081470554218b3d7c44caba3cbbf6ca520444f9 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Wed, 17 Apr 2024 19:46:10 +0200 Subject: [PATCH 56/89] Small optimization --- .../funkin/backend/system/framerate/SystemInfo.hx | 2 +- source/funkin/backend/utils/CoolUtil.hx | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/source/funkin/backend/system/framerate/SystemInfo.hx b/source/funkin/backend/system/framerate/SystemInfo.hx index a815e3b5..979670e5 100644 --- a/source/funkin/backend/system/framerate/SystemInfo.hx +++ b/source/funkin/backend/system/framerate/SystemInfo.hx @@ -17,7 +17,7 @@ class SystemInfo extends FramerateCategory { static var __formattedSysText:String = ""; - public static inline function init() { + public static function init() { #if linux var process = new HiddenProcess("cat", ["/etc/os-release"]); if (process.exitCode() != 0) Logs.trace('Unable to grab OS Label', ERROR, RED); diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx index 240e2dde..d286d347 100644 --- a/source/funkin/backend/utils/CoolUtil.hx +++ b/source/funkin/backend/utils/CoolUtil.hx @@ -133,10 +133,8 @@ class CoolUtil * Whenever a value is NaN or not. * @param v Value */ - public static inline function isNaN(v:Dynamic) { - if (v is Float || v is Int) - return Math.isNaN(cast(v, Float)); - return false; + public static inline function isNaN(v:Dynamic):Bool { + return (v is Float) ? Math.isNaN(cast(v, Float)) : false; } /** @@ -185,20 +183,21 @@ class CoolUtil return str; } + private static var sizeLabels:Array<String> = ["B", "KB", "MB", "GB", "TB"]; + /** * Returns a string representation of a size, following this format: `1.02 GB`, `134.00 MB` * @param size Size to convert to string * @return String Result string representation */ public static function getSizeString(size:Float):String { - var labels = ["B", "KB", "MB", "GB", "TB"]; var rSize:Float = size; var label:Int = 0; - while(rSize > 1024 && label < labels.length-1) { + while(rSize > 1024 && label < sizeLabels.length-1) { label++; rSize /= 1024; } - return '${Std.int(rSize) + "." + addZeros(Std.string(Std.int((rSize % 1) * 100)), 2)}${labels[label]}'; + return Std.int(rSize) + "." + addZeros(Std.string(Std.int((rSize % 1) * 100)), 2) + sizeLabels[label]; } /** From 75e3ab79c5ff3ee597fe54448ed4650dc63cec50 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Wed, 17 Apr 2024 21:51:10 +0200 Subject: [PATCH 57/89] Added Stage Info Edit Screen + Bug fixes --- .../layouts/stage/spriteEditScreen.xml | 7 + .../editors/layouts/stage/stageInfoScreen.xml | 85 +++++++++ .../layouts/stage/unknownEditScreen.xml | 3 + assets/data/stages/test.xml | 2 +- source/funkin/backend/utils/WindowUtils.hx | 2 +- source/funkin/editors/stage/StageEditor.hx | 32 +++- .../funkin/editors/stage/StageInfoScreen.hx | 169 ------------------ source/funkin/game/Stage.hx | 7 + 8 files changed, 130 insertions(+), 177 deletions(-) create mode 100644 assets/data/editors/layouts/stage/stageInfoScreen.xml delete mode 100644 source/funkin/editors/stage/StageInfoScreen.hx diff --git a/assets/data/editors/layouts/stage/spriteEditScreen.xml b/assets/data/editors/layouts/stage/spriteEditScreen.xml index 9c49f410..9c0c20fe 100644 --- a/assets/data/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/data/editors/layouts/stage/spriteEditScreen.xml @@ -119,6 +119,13 @@ button.xml.set(name + "y", y.value); } } + function save(name:String, value:Dynamic) { + button.xml.remove(name); + button.xml.set(name, value); + } + + // TODO: remove old attributes to prevent possible errors + // button.xml.remove(); button.xml.set("name", nameTextBox.label.text); button.xml.set("sprite", spriteTextBox.label.text); diff --git a/assets/data/editors/layouts/stage/stageInfoScreen.xml b/assets/data/editors/layouts/stage/stageInfoScreen.xml new file mode 100644 index 00000000..d5e2bfaf --- /dev/null +++ b/assets/data/editors/layouts/stage/stageInfoScreen.xml @@ -0,0 +1,85 @@ +<window width="470" height="620" title="Editing Stage Info '${stage.stageName}'"> + <set name="MARGIN" value="20" /> + <set name="XOFFSET" value="50" /> + <set name="YOFFSET" value="40" /> + <set name="TO" value="64" /> + <set name="storedProps" value="[]" /> + + <exec> + function col(c:Int) { + return MARGIN + (170 + XOFFSET) * c; + } + + for(prop => val in stage.extra) + if(!StringTools.startsWith(prop, "stageEditor.")) + storedProps.push(prop); + </exec> + + <title name="title" x="MARGIN" y="30 + 16" text="Stage Info" /> + + <section> <!-- ROW 1 --> + <set name="curY" value="title.y + TO" /> + + <textbox name="nameTextBox" label="Stage Name" value="stage.stageName" x="col(0)" y="curY" width="200" height="32" /> + <textbox name="spritePathTextBox" value="stage.spritesParentFolder" x="col(1)" y="curY" width="200" height="32" /> + <label text="Sprite Path (Needs Refresh)" x="spritePathTextBox.x" y="spritePathTextBox.y - 14" size="15" /> + </section> + + <section> <!-- ROW 2 --> + <set name="curY" value="nameTextBox.y + nameTextBox.bHeight + YOFFSET" /> + + <label text="Start Cam Pos (X, Y)" x="col(0)" y="curY" /> + <stepper name="camxStepper" value="stage.startCam.x" x="col(0)" y="curY" step="1" width="120" /> + <stepper name="camyStepper" value="stage.startCam.y" x="last.x + last.bWidth + XOFFSET - 30" y="curY" step="1" width="120" /> + + <stepper name="zoomStepper" label="Zoom" value="stage.defaultZoom" x="col(1)" y="curY" precision="2" step="0.01" width="100" /> + </section> + + <section> + <set name="curY" value="camxStepper.y + camxStepper.bHeight + YOFFSET" /> + <set name="listWidth" value="self.winWidth - MARGIN * 2" /> + + <buttonlist name="attributesList" label="Custom Attributes" x="col(0)" y="curY" width="listWidth" height="290" buttonSizeX="listWidth-10" buttonSizeY="35" buttonSpacing="5"> + <texture path="editors/ui/inputbox" /> + <camSpacing value="0" /> + + <code> + import funkin.editors.extra.PropertyButton; + + var buttonList = buttonlist; // important for now, since it gets reset after the code is run + + var width = buttonList.buttonSize.x; + var height = buttonList.buttonSize.y; + + buttonList.addButton.callback = function() { + buttonList.add(new PropertyButton("newProperty", "valueHere", buttonList, width, height, 150, 220, 25)); + } + + //var defaultAttribs = Stage.DEFAULT_ATTRIBUTES; + //for (i in stage.stageXML.attributes()) { + // trace(i, defaultAttribs); + // if (!defaultAttribs.contains(i)) + // buttonList.add(new PropertyButton(i, stage.stageXML.get(i), buttonList, width, height, 150, 220, 25)); + //} + for(key => val in stage.extra) + buttonList.add(new PropertyButton(key, val, buttonList, width, height, 150, 220, 25)); + </code> + </buttonlist> + </section> + + <exec> + function onSave() { + stage.startCam.x = camxStepper.value; + stage.startCam.y = camyStepper.value; + stage.defaultZoom = zoomStepper.value; + stage.stageName = nameTextBox.label.text; + stage.spritesParentFolder = spritePathTextBox.label.text; + + for(prop in storedProps) + stage.extra.remove(prop); + + for(prop in attributesList.buttons.members) + stage.extra.set(prop.propertyText.label.text, prop.valueText.label.text); + } + </exec> +</window> \ No newline at end of file diff --git a/assets/data/editors/layouts/stage/unknownEditScreen.xml b/assets/data/editors/layouts/stage/unknownEditScreen.xml index b2b54542..ec6f3d71 100644 --- a/assets/data/editors/layouts/stage/unknownEditScreen.xml +++ b/assets/data/editors/layouts/stage/unknownEditScreen.xml @@ -56,6 +56,9 @@ button.highMemory = highMemoryRadio.checked; button.lowMemory = lowMemoryRadio.checked; + for (i in xml.attributes()) + xml.remove(i); + for (val in attributesList.buttons.members) xml.set(val.propertyText.label.text, val.valueText.label.text); } diff --git a/assets/data/stages/test.xml b/assets/data/stages/test.xml index be041748..697711bb 100644 --- a/assets/data/stages/test.xml +++ b/assets/data/stages/test.xml @@ -1,6 +1,6 @@ <!-- praying to god we remove this file later on --> -<stage zoom="0.9" name="stage" folder="stages/default/" startCamPosY="600" startCamPosX="1000"> +<stage zoom="0.9" name="stage" folder="stages/default/" startCamPosY="600" startCamPosX="1000" example="value"> <sprite name="normBG" sprite="stagefront" x="-500" y="100" scale="0.75" updateHitbox="true" /> <sprite name="noUpdateHitbox" sprite="stagefront" x="-500" y="300" scale="0.75" /> <sprite name="ro-tat-ay" sprite="stagefront" x="-500" y="700" scale="0.75" updateHitbox="true" angle="37" /> diff --git a/source/funkin/backend/utils/WindowUtils.hx b/source/funkin/backend/utils/WindowUtils.hx index 571f781a..d6210d9a 100644 --- a/source/funkin/backend/utils/WindowUtils.hx +++ b/source/funkin/backend/utils/WindowUtils.hx @@ -28,7 +28,7 @@ class WindowUtils { static var __triedClosing:Bool = false; public static inline function resetClosing() __triedClosing = false; - public static inline function init() { + public static function init() { resetTitle(); resetClosing(); diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 2e73cc54..411a1de2 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -96,10 +96,10 @@ class StageEditor extends UIState { } ] }, - /*{ + { label: "Edit", childs: [ - { + /*{ label: "Undo", keybind: [CONTROL, Z], onSelect: _edit_undo, @@ -109,9 +109,25 @@ class StageEditor extends UIState { keybind: [CONTROL, SHIFT, Z], onSelect: _edit_redo, }, - null, + null,*/ + { + label: "Edit Stage Info", + onSelect: (_) -> { + openSubState(new UISoftcodedWindow( + "layouts/stage/stageInfoScreen", + [ + "winTitle" => "Editing Stage Info", + "hasSaveButton" => true, + "hasCloseButton" => true, + "stage" => stage, + "Stage" => Stage, + "exID" => exID + ] + )); + }, + } ] - },*/ + }, { label: "Select", childs: [ @@ -586,6 +602,10 @@ class StageEditor extends UIState { saveToXml(xml, "startCamPosX", stage.startCam.x, 0); saveToXml(xml, "startCamPosY", stage.startCam.y, 0); + for(prop in stage.extra.keys()) + if(!Stage.DEFAULT_ATTRIBUTES.contains(prop) && !prop.startsWith("stageEditor.")) + saveToXml(xml, prop, stage.extra.get(prop)); + var group:Xml = null; var curGroup:String = null; @@ -742,11 +762,11 @@ class StageEditor extends UIState { } }*/ - public function editInfoWithUI() { + /*public function editInfoWithUI() { FlxG.state.openSubState(new StageInfoScreen(stage, (_) -> { if (_ != null) editInfo(_); })); - } + }*/ public function editInfo(newInfo:Xml, addtoUndo:Bool = true) { /*var oldInfo = stage.buildXML(); diff --git a/source/funkin/editors/stage/StageInfoScreen.hx b/source/funkin/editors/stage/StageInfoScreen.hx deleted file mode 100644 index 10fe046b..00000000 --- a/source/funkin/editors/stage/StageInfoScreen.hx +++ /dev/null @@ -1,169 +0,0 @@ -package funkin.editors.stage; - -import flixel.math.FlxPoint; -import funkin.editors.extra.PropertyButton; -import funkin.game.Stage; -import haxe.xml.Access; - -class StageInfoScreen extends UISubstateWindow { - public var stage:Stage; - - public var saveButton:UIButton; - public var closeButton:UIButton; - - public var onSave:(xml:Xml) -> Void = null; - - public function new(stage:Stage, ?onSave:(xml:Xml) -> Void) { - this.stage = stage; - this.onSave = onSave; - super(); - } - - public override function create() { - winTitle = "Editing Stage"; - winWidth = 1014; - winHeight = 600; - - super.create(); - - function addLabelOn(ui:UISprite, text:String) - add(new UIText(ui.x, ui.y - 24, 0, text)); - - /*var title:UIText; - add(title = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Sprite Data", 28)); - - spriteTextBox = new UITextBox(title.x, title.y + title.height + 38, character.sprite, 200); - add(spriteTextBox); - addLabelOn(spriteTextBox, "Sprite"); - - iconTextBox = new UITextBox(spriteTextBox.x + 200 + 26, spriteTextBox.y, character.getIcon(), 150); - iconTextBox.onChange = (newIcon:String) -> {updateIcon(newIcon);} - add(iconTextBox); - addLabelOn(iconTextBox, "Icon"); - - updateIcon(character.getIcon()); - - gameOverCharTextBox = new UITextBox(iconTextBox.x + 150 + (75 + 12), iconTextBox.y, character.gameOverCharacter, 200); - add(gameOverCharTextBox); - addLabelOn(gameOverCharTextBox, "Game Over Character"); - - antialiasingCheckbox = new UICheckbox(spriteTextBox.x, spriteTextBox.y + 10 + 32 + 28, "Antialiasing", character.antialiasing); - add(antialiasingCheckbox); - addLabelOn(antialiasingCheckbox, "Antialiased"); - - flipXCheckbox = new UICheckbox(antialiasingCheckbox.x + 172, spriteTextBox.y + 10 + 32 + 28, "FlipX", character.flipX); - add(flipXCheckbox); - addLabelOn(flipXCheckbox, "Flipped"); - - iconColorWheel = new UIColorwheel(gameOverCharTextBox.x + 200 + 20, gameOverCharTextBox.y, character.iconColor); - add(iconColorWheel); - addLabelOn(iconColorWheel, "Icon Color"); - - add(title = new UIText(spriteTextBox.x, spriteTextBox.y + 10 + 46 + 84, 0, "Character Data", 28)); - - positionXStepper = new UINumericStepper(title.x, title.y + title.height + 36, character.globalOffset.x, 0.001, 2, null, null, 84); - add(positionXStepper); - addLabelOn(positionXStepper, "Position (X,Y)"); - - add(new UIText(positionXStepper.x + 84 - 32 + 0, positionXStepper.y + 9, 0, ",", 22)); - - positionYStepper = new UINumericStepper(positionXStepper.x + 84 - 32 + 26, positionXStepper.y, character.globalOffset.y, 0.001, 2, null, null, 84); - add(positionYStepper); - - cameraXStepper = new UINumericStepper(positionYStepper.x + 36 + 84 - 32, positionYStepper.y, character.cameraOffset.x, 0.001, 2, null, null, 84); - add(cameraXStepper); - addLabelOn(cameraXStepper, "Camera Position (X,Y)"); - - add(new UIText(cameraXStepper.x + 84 - 32 + 0, cameraXStepper.y + 9, 0, ",", 22)); - - cameraYStepper = new UINumericStepper(cameraXStepper.x + 84 - 32 + 26, cameraXStepper.y, character.cameraOffset.y, 0.001, 2, null, null, 84); - add(cameraYStepper); - - scaleStepper = new UINumericStepper(cameraYStepper.x + 84 - 32 + 90, cameraYStepper.y, character.scale.x, 0.001, 2, null, null, 74); - add(scaleStepper); - addLabelOn(scaleStepper, "Scale"); - - singTimeStepper = new UINumericStepper(scaleStepper.x + 74 - 32 + 36, scaleStepper.y, character.holdTime, 0.001, 2, null, null, 74); - add(singTimeStepper); - addLabelOn(singTimeStepper, "Sing Duration (Steps)"); - - customPropertiesButtonList = new UIButtonList<PropertyButton>(singTimeStepper.x + singTimeStepper.width + 200, singTimeStepper.y, 290, 200, '', FlxPoint.get(280, 35), null, 5); - customPropertiesButtonList.frames = Paths.getFrames('editors/ui/inputbox'); - customPropertiesButtonList.cameraSpacing = 0; - customPropertiesButtonList.addButton.callback = function() { - customPropertiesButtonList.add(new PropertyButton("newProperty", "valueHere", customPropertiesButtonList)); - } - for (prop=>val in character.extra) - customPropertiesButtonList.add(new PropertyButton(prop, val, customPropertiesButtonList)); - add(customPropertiesButtonList); - addLabelOn(customPropertiesButtonList, "Custom Values (Advanced)"); - - isPlayerCheckbox = new UICheckbox(positionXStepper.x, positionXStepper.y + 10 + 32 + 28, "isPlayer", character.playerOffsets); - add(isPlayerCheckbox); - addLabelOn(isPlayerCheckbox, "Is Player"); - - isGFCheckbox = new UICheckbox(isPlayerCheckbox.x + 128, positionXStepper.y + 10 + 32 + 28, "isGF", character.isGF); - add(isGFCheckbox); - addLabelOn(isGFCheckbox, "Is GF"); - - for (checkbox in [isPlayerCheckbox, isGFCheckbox, antialiasingCheckbox, flipXCheckbox]) - {checkbox.y += 4; checkbox.x += 6;}*/ - - saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight- 20, "Save & Close", function() { - //saveCharacterInfo(); - close(); - }, 125); - saveButton.x -= saveButton.bWidth; - saveButton.y -= saveButton.bHeight; - - closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Close", function() { - if (onSave != null) onSave(null); - close(); - }, 125); - closeButton.x -= closeButton.bWidth; - closeButton.color = 0xFFFF0000; - add(closeButton); - add(saveButton); - } - - /*function saveCharacterInfo() { - for (stepper in [positionXStepper, positionYStepper, cameraXStepper, cameraYStepper, singTimeStepper, scaleStepper]) - @:privateAccess stepper.__onChange(stepper.label.text); - - var xml = Xml.createElement("character"); - xml.set("isPlayer", isPlayerCheckbox.checked ? "true" : "false"); - xml.set("isGF", isGFCheckbox.checked ? "true" : "false"); - xml.set("x", Std.string(positionXStepper.value)); - xml.set("y", Std.string(positionYStepper.value)); - xml.set("gameOverChar", gameOverCharTextBox.label.text); - xml.set("camx", Std.string(cameraXStepper.value)); - xml.set("camy", Std.string(cameraYStepper.value)); - xml.set("holdTime", Std.string(singTimeStepper.value)); - xml.set("flipX", Std.string(flipXCheckbox.checked)); - xml.set("icon", iconTextBox.label.text); - xml.set("scale", Std.string(scaleStepper.value)); - xml.set("antialiasing", antialiasingCheckbox.checked ? "true" : "false"); - xml.set("sprite", spriteTextBox.label.text); - if (iconColorWheel.colorChanged) - xml.set("color", iconColorWheel.curColor.toWebString()); - for (val in customPropertiesButtonList.buttons.members) - xml.set(val.propertyText.label.text, val.valueText.label.text); - - for (anim in character.animDatas) - { - var animXml:Xml = Xml.createElement('anim'); - animXml.set("name", anim.name); - animXml.set("anim", anim.anim); - animXml.set("loop", Std.string(anim.loop)); - animXml.set("fps", Std.string(anim.fps)); - var offset:FlxPoint = character.getAnimOffset(anim.name); - animXml.set("x", Std.string(offset.x)); - animXml.set("y", Std.string(offset.y)); - if (anim.indices.length > 0) - animXml.set("indices", anim.indices.join(",")); - xml.addChild(animXml); - } - - if (onSave != null) onSave(xml); - }*/ -} \ No newline at end of file diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx index a621dc83..f4f13d70 100644 --- a/source/funkin/game/Stage.hx +++ b/source/funkin/game/Stage.hx @@ -57,6 +57,8 @@ class Stage extends FlxBasic implements IBeatReceiver { if (autoLoad) loadXml(stageXML); } + public static var DEFAULT_ATTRIBUTES:Array<String> = ["name", "startCamPosX", "startCamPosY", "zoom", "folder"]; + public function loadXml(xml:Access, forceLoadAll:Bool = false) { if (PlayState.instance == state) { stageScript = Script.create(Paths.script('data/stages/$stageFile')); @@ -83,6 +85,11 @@ class Stage extends FlxBasic implements IBeatReceiver { if (!spritesParentFolder.endsWith("/")) spritesParentFolder += "/"; } + // Load custom attributes + for(att in xml.x.attributes()) + if(!DEFAULT_ATTRIBUTES.contains(att)) + extra.set(att, xml.x.get(att)); + var elems:Array<Access> = []; // some way to tag that the sprites are from the group for(node in xml.elements) { From 7c60a4e632faa96ff2e4faa9b06515965bb49f8a Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Wed, 17 Apr 2024 22:20:55 +0200 Subject: [PATCH 58/89] Added XML Editing of anything --- .../layouts/stage/spriteEditScreen.xml | 41 ++++++++++++++- .../editors/layouts/stage/xmlEditScreen.xml | 51 +++++++++++++++++++ source/funkin/editors/stage/StageEditor.hx | 21 ++++++++ source/funkin/editors/stage/StageSelection.hx | 1 - .../stage/elements/StageCharacterButton.hx | 7 ++- .../stage/elements/StageElementButton.hx | 2 +- .../stage/elements/StageSolidButton.hx | 2 +- .../stage/elements/StageSpriteButton.hx | 8 ++- 8 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 assets/data/editors/layouts/stage/xmlEditScreen.xml diff --git a/assets/data/editors/layouts/stage/spriteEditScreen.xml b/assets/data/editors/layouts/stage/spriteEditScreen.xml index 9c0c20fe..651756a0 100644 --- a/assets/data/editors/layouts/stage/spriteEditScreen.xml +++ b/assets/data/editors/layouts/stage/spriteEditScreen.xml @@ -1,4 +1,5 @@ <window width="1056" height="520" title="Editing Sprite ${button.getName()}"> + <set name="MARGIN" value="20" /> <set name="XOFFSET" value="50" /> <set name="YOFFSET" value="40" /> <set name="TO" value="64" /> @@ -24,7 +25,7 @@ <textbox name="nameTextBox" label="Name Identifier" value="button.getName()" x="col(0)" y="curY" width="200" height="32" /> <textbox name="spriteTextBox" value="getEx('imageFile')" x="last.x + last.bWidth + XOFFSET" y="curY" width="200" height="32" /> <stepper name="alphaStepper" label="Alpha" value="sprite.alpha" x="spriteTextBox.x + spriteTextBox.bWidth + XOFFSET" y="curY" precision="2" step="0.01" width="100" /> - <label name="imageFile" text="Image File In (${stage.spritesParentFolder})" x="spriteTextBox.x" y="spriteTextBox.y - 14" size="15" /> + <label name="imageFile" text="Image File (WIP: needs reload) In (${stage.spritesParentFolder})" x="spriteTextBox.x" y="spriteTextBox.y - 14" size="15" /> </section> <section> <!-- ROW 2 --> @@ -67,6 +68,44 @@ <!-- TODO: Animation list --> </section> + <section> <!-- RIGHT SIDE --> + <set name="curY" value="title.y + TO" /> + <set name="listWidth" value="250" /> + + <buttonlist name="animations" label="Animations (TODO)" x="col(3)" y="curY" width="listWidth" height="330" buttonSizeX="listWidth-10" buttonSizeY="35" buttonSpacing="5"> + <texture path="editors/ui/inputbox" /> + <camSpacing value="0" /> + + <code> + buttonlist.addButton.exists = false; + </code> + + <!-- <code> + import funkin.editors.extra.PropertyButton; + + var buttonList = buttonlist; // important for now, since it gets reset after the code is run + + var width = buttonList.buttonSize.x; + var height = buttonList.buttonSize.y; + + buttonList.addButton.callback = function() { + buttonList.add(new PropertyButton("newProperty", "valueHere", buttonList, width, height, 150, 220, 25)); + } + + //var defaultAttribs = Stage.DEFAULT_ATTRIBUTES; + //for (i in stage.stageXML.attributes()) { + // trace(i, defaultAttribs); + // if (!defaultAttribs.contains(i)) + // buttonList.add(new PropertyButton(i, stage.stageXML.get(i), buttonList, width, height, 150, 220, 25)); + //} + for(key => val in stage.extra) + buttonList.add(new PropertyButton(key, val, buttonList, width, height, 150, 220, 25)); + </code> --> + </buttonlist> + + <text text="Tip: To access custom properties, hold shift when clicking edit" x="col(2) - 60" y="self.winHeight - 50" size="15" /> + </section> + <!-- Preview Transform --> diff --git a/assets/data/editors/layouts/stage/xmlEditScreen.xml b/assets/data/editors/layouts/stage/xmlEditScreen.xml new file mode 100644 index 00000000..7a7ac956 --- /dev/null +++ b/assets/data/editors/layouts/stage/xmlEditScreen.xml @@ -0,0 +1,51 @@ +<window width="450" height="570" title="Editing XML ${type}"> + <!-- BASED ON unknownEditScreen.xml --> + <set name="MARGIN" value="20" /> + <set name="XOFFSET" value="30" /> + <set name="YOFFSET" value="40" /> + <set name="TO" value="64" /> + + <exec> + function col(c:Int) { + return MARGIN + (150 + XOFFSET) * c; + } + </exec> + + <title name="title" x="MARGIN" y="30 + 16" text="Xml Data" /> + + <section> + <set name="curY" value="title.y + TO" /> + <set name="listWidth" value="self.winWidth - MARGIN * 2" /> + + <buttonlist name="attributesList" label="Attributes" x="col(0)" y="curY" width="listWidth" height="400" buttonSizeX="listWidth-10" buttonSizeY="35" buttonSpacing="5"> + <texture path="editors/ui/inputbox" /> + <camSpacing value="0" /> + + <code> + import funkin.editors.extra.PropertyButton; + + var buttonList = buttonlist; // important for now, since it gets reset after the code is run + + var width = buttonList.buttonSize.x; + var height = buttonList.buttonSize.y; + + buttonList.addButton.callback = function() { + buttonList.add(new PropertyButton("newProperty", "valueHere", buttonList, width, height, 160, 195, 25)); + } + + for (i in xml.attributes()) + buttonList.add(new PropertyButton(i, xml.get(i), buttonList, width, height, 160, 195, 25)); + </code> + </buttonlist> + </section> + + <exec> + function onSave() { + for (i in xml.attributes()) + xml.remove(i); + + for (val in attributesList.buttons.members) + xml.set(val.propertyText.label.text, val.valueText.label.text); + } + </exec> +</window> \ No newline at end of file diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 411a1de2..fa41a5a6 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -1210,4 +1210,25 @@ enum abstract StageEditorEdge(Int) { case BOTTOM_RIGHT: "BOTTOM_RIGHT"; } } +} + +class StageXMLEditScreen extends UISoftcodedWindow { + public var xml:Access; + public var saveCallback:Void->Void; + + public function new(xml:Access, saveCallback:Void->Void, type:String = "Unknown") { + this.xml = xml; + this.saveCallback = saveCallback; + super("layouts/stage/xmlEditScreen", [ + "stage" => StageEditor.instance.stage, + "xml" => xml, + "exID" => StageEditor.exID, + "type" => type + ]); + } + + override function saveData() { + super.saveData(); + if(saveCallback != null) saveCallback(); + } } \ No newline at end of file diff --git a/source/funkin/editors/stage/StageSelection.hx b/source/funkin/editors/stage/StageSelection.hx index 0ccd36a6..0f0fc06c 100644 --- a/source/funkin/editors/stage/StageSelection.hx +++ b/source/funkin/editors/stage/StageSelection.hx @@ -3,7 +3,6 @@ package funkin.editors.stage; import funkin.editors.stage.StageCreationScreen.StageCreationData; import funkin.game.Stage; import funkin.options.OptionsScreen; -import funkin.options.type.IconOption; import funkin.options.type.NewOption; import funkin.options.type.OptionType; import funkin.options.type.TextOption; diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index 9a97f306..44ff1ec4 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -1,5 +1,6 @@ package funkin.editors.stage.elements; +import funkin.editors.stage.StageEditor.StageXMLEditScreen; import funkin.game.Character; import funkin.game.Stage.StageCharPos; import haxe.xml.Access; @@ -44,7 +45,11 @@ class StageCharacterButton extends StageElementButton { }*/ public override function onEdit() { - FlxG.state.openSubState(new StageCharacterEditScreen(this)); + if(!FlxG.keys.pressed.SHIFT) { + FlxG.state.openSubState(new StageCharacterEditScreen(this)); + } else { + FlxG.state.openSubState(new StageXMLEditScreen(this.xml, updateInfo, "Character")); + } } //public override function onEdit() { diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index 6b188a94..ec646615 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -1,7 +1,7 @@ package funkin.editors.stage.elements; -import haxe.xml.Access; import flixel.util.FlxColor; +import haxe.xml.Access; using flixel.util.FlxColorTransformUtil; diff --git a/source/funkin/editors/stage/elements/StageSolidButton.hx b/source/funkin/editors/stage/elements/StageSolidButton.hx index 698069e8..6ded6d26 100644 --- a/source/funkin/editors/stage/elements/StageSolidButton.hx +++ b/source/funkin/editors/stage/elements/StageSolidButton.hx @@ -1,7 +1,7 @@ package funkin.editors.stage.elements; -import haxe.xml.Access; import flixel.util.FlxColor; +import haxe.xml.Access; class StageSolidButton extends StageSpriteButton { diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index 264bba05..bd38fd06 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -1,6 +1,6 @@ package funkin.editors.stage.elements; -import flixel.util.FlxColor; +import funkin.editors.stage.StageEditor.StageXMLEditScreen; import funkin.editors.stage.elements.StageElementButton; import funkin.editors.ui.UISoftcodedWindow; import haxe.xml.Access; @@ -40,7 +40,11 @@ class StageSpriteButton extends StageElementButton { } public override function onEdit() { - FlxG.state.openSubState(new StageSpriteEditScreen(this)); + if(!FlxG.keys.pressed.SHIFT) { + FlxG.state.openSubState(new StageSpriteEditScreen(this)); + } else { + FlxG.state.openSubState(new StageXMLEditScreen(this.xml, updateInfo, "Sprite")); + } } public override function onDelete() { From e3fa6ceea9e054dfe6797373b5c82961be46957f Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Thu, 18 Apr 2024 00:07:39 +0200 Subject: [PATCH 59/89] New Icon for advanced Edit --- .../images/editors/character/edit-button.png | Bin 180 -> 213 bytes .../editors/character/CharacterAnimButtons.hx | 5 +++- source/funkin/editors/stage/StageEditor.hx | 2 ++ .../stage/elements/StageCharacterButton.hx | 2 ++ .../stage/elements/StageElementButton.hx | 26 +++++++++++++++++- .../stage/elements/StageSpriteButton.hx | 2 ++ .../stage/elements/StageUnknownButton.hx | 2 ++ 7 files changed, 37 insertions(+), 2 deletions(-) diff --git a/assets/images/editors/character/edit-button.png b/assets/images/editors/character/edit-button.png index 7c257b718d52c7c23c0acc20107c6bab556c53e4..47991177cde47a074dfaf756c9014ba9fb18df7e 100644 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^3P3Et!3-oF?)7E^Da8Pv5LZS<#{d8SzkaB7b9esr zGZOcD5B#sFI9{{nznhz~vLsMd*uUHmAjMb`<QL4~@a#q!kdx%;;uunKYwc-Az5@yz zE`e@=Gw%IAaCOImTT?<~XVl1f*d)|MPCjv4YGSFe@uS_AR(bc<wu-4Q`2OPQsylb) zwr4+lcCT`W+&lZ73yLaBen^Gr_1EosFiYCqzyIJ26<sC<&-+u}v$pQP`dSod8-u5- KpUXO@geCwCj#gX% literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`)t)YnAr*|t3SxiSnNkcVnP_W! zHyLtFSo*W#?5zLatN0J_D!LkbD4$@EXp?qYvw5Ov@(z~u&t9ji{M%o*qV=r64#pOf z<_rP0&WUR!Z>pwbvt4ZVH$K!bd-rF@E{?2Y=?rHCoMss^hA?(1&X~n1-H^laa^^F8 dEd@_whUDp`yB8^W&j31u!PC{xWt~$(695qWK5+m5 diff --git a/source/funkin/editors/character/CharacterAnimButtons.hx b/source/funkin/editors/character/CharacterAnimButtons.hx index c80913cd..01ba60d4 100644 --- a/source/funkin/editors/character/CharacterAnimButtons.hx +++ b/source/funkin/editors/character/CharacterAnimButtons.hx @@ -44,7 +44,10 @@ class CharacterAnimButtons extends UIButton { editButton.autoAlpha = false; members.push(editButton); - editIcon = new FlxSprite(editButton.x + 8, editButton.y + 8).loadGraphic(Paths.image('editors/character/edit-button')); + editIcon = new FlxSprite(editButton.x + 8, editButton.y + 8).loadGraphic(Paths.image('editors/character/edit-button'), true, 16, 16); + editIcon.animation.add("edit", [0]); + editIcon.animation.add("advanced", [1]); + editIcon.animation.play("edit"); editIcon.antialiasing = false; members.push(editIcon); diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index fa41a5a6..6bb54a80 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -645,6 +645,7 @@ class StageEditor extends UIState { saveToXml(spriteXML, "beatOffset", node.getAtt("beatOffset"), 0); saveToXml(spriteXML, "type", sprite.spriteAnimType, LOOP); saveToXml(spriteXML, "color", sprite.color.toWebString(), "#FFFFFF"); + // TODO: save custom parameters //saveToXml(spriteXML, "flipX", sprite.flipX, false); newNode = spriteXML; } else if(button is StageCharacterButton) { @@ -676,6 +677,7 @@ class StageEditor extends UIState { saveToXml(charXML, "flipX", charPos.flipX, defaultPos.flip); savePointToXml(charXML, "scroll", charPos.scrollFactor, defaultPos.scroll); savePointToXml(charXML, "scale", charPos.scale, 1); + // TODO: save custom parameters newNode = charXML; } else if(button is StageUnknownButton) { var button:StageUnknownButton = cast button; diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index 44ff1ec4..f23d6fe4 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -16,6 +16,8 @@ class StageCharacterButton extends StageElementButton { color = 0xff7aa8ff; + hasAdvancedEdit = true; + updateInfo(); } diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index ec646615..6ce04ddf 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -18,6 +18,7 @@ class StageElementButton extends UIButton { public var deleteIcon:FlxSprite; public var isHidden:Bool = false; + public var hasAdvancedEdit:Bool = false; public var selected:Bool = false; @@ -62,7 +63,9 @@ class StageElementButton extends UIButton { editButton.autoAlpha = false; members.push(editButton); - editIcon = new FlxSprite(editButton.x + 8, editButton.y + 8).loadGraphic(Paths.image('editors/character/edit-button')); + editIcon = new FlxSprite(editButton.x + 8, editButton.y + 8).loadGraphic(Paths.image('editors/character/edit-button'), true, 16, 16); + editIcon.animation.add("edit", [0]); + editIcon.animation.add("advanced", [1]); editIcon.antialiasing = false; members.push(editIcon); @@ -76,8 +79,21 @@ class StageElementButton extends UIButton { deleteIcon = new FlxSprite(deleteButton.x + (15/2), deleteButton.y + 8).loadGraphic(Paths.image('editors/delete-button')); deleteIcon.antialiasing = false; members.push(deleteIcon); + + setEditNormal(); } + public function setEditNormal() { + editIcon.animation.play("edit"); + editButton.color = FlxColor.YELLOW; + } + + public function setEditAdvanced() { + editIcon.animation.play("advanced"); + editButton.color = 0xFFFF5B0F; + } + + var _lastSelected:Bool = false; public override function update(elapsed:Float) { @@ -89,6 +105,14 @@ class StageElementButton extends UIButton { super.update(elapsed); field.x += 12; + if(hasAdvancedEdit) { + if(FlxG.keys.pressed.SHIFT) { + setEditAdvanced(); + } else { + setEditNormal(); + } + } + tagColor.color = color; } diff --git a/source/funkin/editors/stage/elements/StageSpriteButton.hx b/source/funkin/editors/stage/elements/StageSpriteButton.hx index bd38fd06..485eca9f 100644 --- a/source/funkin/editors/stage/elements/StageSpriteButton.hx +++ b/source/funkin/editors/stage/elements/StageSpriteButton.hx @@ -14,6 +14,8 @@ class StageSpriteButton extends StageElementButton { //color = 0xFFD9FF50; + hasAdvancedEdit = true; + updateInfo(); } diff --git a/source/funkin/editors/stage/elements/StageUnknownButton.hx b/source/funkin/editors/stage/elements/StageUnknownButton.hx index 371ba403..12c8c5d3 100644 --- a/source/funkin/editors/stage/elements/StageUnknownButton.hx +++ b/source/funkin/editors/stage/elements/StageUnknownButton.hx @@ -24,6 +24,8 @@ class StageUnknownButton extends StageElementButton { visibilityIcon.exists = false; members.remove(visibilityIcon); + setEditAdvanced(); + updateInfo(); } From 4d4400a34c13b30c773046a29eb547e7a337098e Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Thu, 18 Apr 2024 00:14:01 +0200 Subject: [PATCH 60/89] Fixed selection bug --- source/funkin/editors/stage/StageEditor.hx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 6bb54a80..622a5920 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -420,6 +420,8 @@ class StageEditor extends UIState { updateZoom(); } + var prevMode = mouseMode; + // TODO: make this work with multiple selections if(selection.length == 1) { for(sprite in selection) { @@ -434,11 +436,12 @@ class StageEditor extends UIState { // openContextMenu(topMenu[2].childs); //} - if (mouseMode == NONE) { + if (mouseMode == NONE && prevMode == NONE) { if (FlxG.mouse.pressed) { - var pos = [FlxG.mouse.deltaScreenX, FlxG.mouse.deltaScreenY]; - movedTillRel.x += pos[0]; movedTillRel.y += pos[1]; - nextScroll.set(nextScroll.x - pos[0], nextScroll.y - pos[1]); + var x = FlxG.mouse.deltaScreenX; + var y = FlxG.mouse.deltaScreenY; + movedTillRel.x += x; movedTillRel.y += y; + nextScroll.set(nextScroll.x - x, nextScroll.y - y); currentCursor = HAND; } From 68264acf6615246f0c3f359ebc64c0daf9801fbf Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Thu, 18 Apr 2024 03:12:10 +0200 Subject: [PATCH 61/89] Implemented rotation + new dot sprite --- assets/data/states/StageEditor.hx | 38 +++++-- assets/images/editors/stage/selectionDot.png | Bin 0 -> 793 bytes source/funkin/editors/stage/StageEditor.hx | 114 +++++++++++++++---- 3 files changed, 117 insertions(+), 35 deletions(-) create mode 100644 assets/images/editors/stage/selectionDot.png diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index f18d377a..e8624bf5 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -10,6 +10,7 @@ import funkin.editors.stage.StageEditor; import funkin.editors.ui.UIWarningSubstate; import funkin.backend.utils.WindowUtils; +import flixel.math.FlxAngle; import openfl.Lib; var exID = StageEditor.exID; @@ -130,12 +131,9 @@ function SCALE_BOTTOM_RIGHT(sprite, relative) { ROTATION **/ function preRotBullshit(sprite, relative) { - // just remove the other line in source - rotateByDegrees(relative, -sprite.angle); - if (sprite.angle != 0) relative = rotateAround(relative, FlxPoint.weak(0, 0), -sprite.angle); - + if (FlxG.mouse.justPressed) { oldSpritePos.x = sprite.x; oldSpritePos.y = sprite.y; @@ -149,16 +147,16 @@ function postRotBullshit(sprite, relative) { sprite.y = p.y; } } -import flixel.math.FlxAngle; function rotateAround(p, origin, angle) { var rel = FlxPoint.get(p.x - origin.x, p.y - origin.y); rotateByDegrees(rel, angle); p.x = origin.x + rel.x; p.y = origin.y + rel.y; + rel.put(); return p; } - function rotateByDegrees(p, angle) { +function rotateByDegrees(p, angle) { var rads = angle * FlxAngle.TO_RAD; var s:Float = Math.sin(rads); var c:Float = Math.cos(rads); @@ -166,9 +164,7 @@ function rotateAround(p, origin, angle) { p.x = tempX * c - p.y * s; p.y = tempX * s + p.y * c; - - return this; - } +} /** END OF ROTATION **/ @@ -226,6 +222,28 @@ function SKEW_TOP(sprite, relative) {} function SKEW_RIGHT(sprite, relative) {} -function ROTATE(sprite, relative) {} +/*var storedCenter = FlxPoint.get(); +var storedRelative = FlxPoint.get();*/ + +function ROTATE(sprite, relative) { + var buttonBoxes:Array<FlxPoint> = sprite.extra.get(exID("buttonBoxes")); + var p:FlxPoint = buttonBoxes[8]; + + FlxG.mouse.getWorldPosition(stageCamera, _point); + + var dx:Float = _point.x - p.x; + var dy:Float = _point.y - p.y; + var angle = FlxAngle.angleFromOrigin(dx, dy, true) + 90; + if(FlxG.keys.pressed.SHIFT) angle = Std.int(angle / 45) * 45; + sprite.angle = angle; + + //storedCenter.set(p.x, p.y); + //storedRelative.set(_point.x, _point.y); +} +/*function postDraw() { + if(storedCenter.x != 0 || storedCenter.y != 0) { + drawLine(storedCenter, storedRelative, 0.3); + } +}*/ \ No newline at end of file diff --git a/assets/images/editors/stage/selectionDot.png b/assets/images/editors/stage/selectionDot.png new file mode 100644 index 0000000000000000000000000000000000000000..d5aa449e24d3233da0ba7b19a038c94e4b81b7db GIT binary patch literal 793 zcmV+!1LpjRP)<h;3K|Lk000e1NJLTq002M$001Be1^@s6qMd$(00009a7bBm000XU z000XU0RWnu7ytkQ%Sl8*RA_<anNLsDKp2OgZZ-%}qlp*rW_F35i19*5goxbGlV3tU zg`PC<8Q`ubPI^Sc`T>BRh|zeIkl-JLUD?aeL#HxZJKYxADT%-2O{STd_nEhynYQl) zlE|qmz$0KDxC`6@u9>=@z!zW}cn`b<j`BLLl`m<SwI!`eI#PZenLh0t{%hrDRgOwp zmUL18oYaY=72~UD;9mGHcuUgOIlxJ6sn~3A@k2?^CCy8^DQU#mxTFWBE-b=NgWr?1 zcji#t+B3d~1)s+6NSe*jH?~>RXDB~yz3rD1Z>si{Jrk1ro}{Oef{Z>c3ryc$7T@kL zCTY9ecvH1)Sjhn=`QIhYq_it)Gm^f!_;$nPk^{}sa>_t$eoxYLN}IFVv<7FwU%tKR z^h*!Zt-fKp_)97;_}G@x_;KZG`7sXFnob92^E*1*n$NQ**c;=TBmzlSfv>>jGC$jL z=opwVWt%?-e5i;y3v_IL6IjH5@EGQzRR##DE_jUZ5SWVjP2gdLz+qYd?4OZ!56pF< z8vwA-v@Yt<6oWUQ%BLTzW0j|xK-&Y<rB>p4*8|gLv;s-LflD61Y3dWrfS5lDoK(yl zu^9bE#jp#n2Jov!{$YZD!voW195#SY9-uCLPVjGgVBWF$4WjpAT?!NYIS)*m5jKE# z9-uC5B=}D}Fm1+0ou9&8VBC~_eG1>Ve0PEIcoTeG5im=y3_Hnx0R$EB0^sF8eAV|m zY-eWb_#JL5kq}uaJxsS&QU+-AyDC2+(oN&rjm9MHlpSe`cH~Zp+57{Qml8X0@so}J z>!fIG7cniqsp4tz%{=_9CsF2d*io^A5f?v{^i0vg$b?Q0MkXXJC|cVei}14sF=`y1 z=k3tf`Hsda=jR#7q@twdaRG2wQPOcThyPmnfmG;t{4s;a)7MSi4+f8?-%!o*c<KB< X65c@Dh1Dg)00000NkvXXu0mjfE<AXi literal 0 HcmV?d00001 diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 622a5920..3d539e1a 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -51,6 +51,8 @@ class StageEditor extends UIState { public var clickPoint:FlxPoint = new FlxPoint(); public var storedPos:FlxPoint = new FlxPoint(); public var storedScale:FlxPoint = new FlxPoint(); + public var storedSkew:FlxPoint = new FlxPoint(); + public var storedAngle:Float = 0; public var showCharacters:Bool = true; @@ -909,9 +911,19 @@ class StageEditor extends UIState { mousePoint = FlxG.mouse.getWorldPosition(stageCamera, mousePoint); if(dot == null) { - dot = new FlxSprite().makeGraphic(30, 30, FlxColor.WHITE); + dot = new FlxSprite().loadGraphic(Paths.image("editors/stage/selectionDot"), true, 32, 32); + dot.antialiasing = true; + dot.animation.add("default", [0], 0, false); + dot.animation.add("hollow", [1], 0, false); + dot.animation.play("default"); + //dot = new FlxSprite().makeGraphic(30, 30, FlxColor.WHITE); dot.camera = stageCamera; dot.forceIsOnScreen = true; + + line = new FlxSprite().makeGraphic(30, 30, FlxColor.WHITE); + line.camera = stageCamera; + line.color = lineColor; + line.forceIsOnScreen = true; } for(sprite in selection) { if(sprite is FunkinSprite) { @@ -921,8 +933,9 @@ class StageEditor extends UIState { } } - var lineColor = 0xFFb794b6; - var circleColor = 0xFF99a8f2; + var lineColor:FlxColor = 0xFFb794b6; + var circleColor:FlxColor = 0xFF99a8f2; + var hollowColor:FlxColor = 0xffb2beff; function drawGuides(sprite:FlxSprite) { var corners = calcSpriteBounds(sprite); @@ -943,20 +956,37 @@ class StageEditor extends UIState { funkinSprite.extra.set(exID("buttonBoxes"), buttonBoxes); } - dot.color = lineColor; - drawLine(corners[0], corners[1]); // tl - tr drawLine(corners[0], corners[2]); // tl - bl drawLine(corners[1], corners[3]); // tr - br drawLine(corners[2], corners[3]); // bl - br + + drawLine(corners[7], corners[9], 0.3); // tc - ac // top center to angle center + // cross //drawLine(corners[0], corners[3]); // tl - br //drawLine(corners[1], corners[2]); // tr - bl dot.color = circleColor; - for(corner in corners) { - drawDot(corner.x, corner.y); + final ANGLE_INDEX = StageEditorEdge.ROTATE_CIRCLE.toInt(); + final CENTER_INDEX = StageEditorEdge.CENTER_CIRCLE.toInt(); + + dot.animation.play("default"); + + for(i in 0...corners.length) { + var corner = corners[i]; + if(i != CENTER_INDEX) { + if(i == ANGLE_INDEX) { + dot.color = hollowColor; + drawDot(corner.x, corner.y); + dot.animation.play("hollow"); + dot.color = circleColor; + drawDot(corner.x, corner.y); + } else { + drawDot(corner.x, corner.y); + } + } buttonBoxes.push(corner); } @@ -988,7 +1018,9 @@ class StageEditor extends UIState { FlxPoint.get(0.5, 1), FlxPoint.get(0.5, 0), // center - //FlxPoint.get(0.5, 0.5) + FlxPoint.get(0.5, 0.5), + //FlxPoint.get(0.5, -100/sprite.frameHeight) // angle + FlxPoint.get(0.5, -0.5) // angle ], sprite.camera, sprite.frameWidth, sprite.frameHeight); //Logs.trace("Guide at " + corners[0].x + ", " + corners[0].y + " sprite at " + sprite.x + ", " + sprite.y); @@ -1024,6 +1056,10 @@ class StageEditor extends UIState { MIDDLE_RIGHT, //FlxPoint.get(1, 0.5), BOTTOM_MIDDLE, //FlxPoint.get(0.5, 1), TOP_MIDDLE, //FlxPoint.get(0.5, 0), + + CENTER_CIRCLE, //FlxPoint.get(0.5, -0.5) + + ROTATE_CIRCLE, //FlxPoint.get(0.5, -0.5) ]; function tryUpdateHitbox(sprite:FunkinSprite) { @@ -1048,12 +1084,15 @@ class StageEditor extends UIState { case BOTTOM_LEFT: SCALE_BOTTOM_LEFT; case BOTTOM_MIDDLE: SCALE_BOTTOM; case BOTTOM_RIGHT: SCALE_BOTTOM_RIGHT; + case ROTATE_CIRCLE: ROTATE; default: NONE; } Logs.trace("Clicked Dot: " + mouseMode.toString()); mousePoint.copyTo(clickPoint); storedPos.set(sprite.x, sprite.y); + storedSkew.set(sprite.skew.x, sprite.skew.y); storedScale.copyFrom(sprite.scale); + storedAngle = sprite.angle; } } } @@ -1075,6 +1114,8 @@ class StageEditor extends UIState { //case TOP_MIDDLE | BOTTOM_MIDDLE: MouseCursor.RESIZE_NS; //case TOP_RIGHT | BOTTOM_LEFT: MouseCursor.RESIZE_NESW; //case MIDDLE_LEFT | MIDDLE_RIGHT: MouseCursor.RESIZE_WE; + + case ROTATE_CIRCLE: FlxG.mouse.pressed ? DRAG : #if mac DRAG_OPEN #else CLICK #end; default: ARROW; } break; @@ -1085,13 +1126,13 @@ class StageEditor extends UIState { if(mouseMode == NONE) return; var relative = clickPoint.subtractNew(mousePoint); // todo: make this origin based - relative.rotateByDegrees(sprite.angle); + //relative.rotateByDegrees(sprite.angle); call(mouseMode.toString(), [sprite, relative]); cast(sprite.extra.get(exID("button")), StageElementButton).updateInfo(); relative.put(); } - var dotCheckSize:Float = 50; + var dotCheckSize:Float = 53; function checkDot(point:FlxPoint):Bool { var rect = new FlxRect(point.x - dotCheckSize/2, point.y - dotCheckSize/2, dotCheckSize, dotCheckSize); @@ -1106,28 +1147,29 @@ class StageEditor extends UIState { dot.draw(); } - function drawLine(point1:FlxPoint, point2:FlxPoint) { + function drawLine(point1:FlxPoint, point2:FlxPoint, sizeModify:Float = 1) { var dx:Float = point2.x - point1.x; var dy:Float = point2.y - point1.y; var angle:Float = Math.atan2(dy, dx); var distance:Float = Math.sqrt(dx * dx + dy * dy); - dot.setPosition(point1.x, point1.y); - dot.angle = angle * FlxAngle.TO_DEG; - dot.origin.set(0, dot.frameHeight / 2); - dot.scale.x = distance / dot.frameWidth; - dot.scale.y = 0.20/stageCamera.zoom; - //dot.x -= dot.width / 2; - dot.y -= dot.height / 2; - dot.draw(); + line.setPosition(point1.x, point1.y); + line.angle = angle * FlxAngle.TO_DEG; + line.origin.set(0, line.frameHeight / 2); + line.scale.x = distance / line.frameWidth; + line.scale.y = 0.20/stageCamera.zoom * sizeModify; + //line.x -= line.width / 2; + line.y -= line.height / 2; + line.draw(); // Reset the angle and scale - dot.angle = 0; - dot.scale.x = dot.scale.y = 1; - dot.updateHitbox(); + line.angle = 0; + line.scale.x = line.scale.y = 1; + line.updateHitbox(); } var dot:FlxSprite = null; + var line:FlxSprite = null; } enum StageChange { @@ -1189,9 +1231,9 @@ enum abstract StageEditorMouseMode(Int) { } enum abstract StageEditorEdge(Int) { - var NONE; + var NONE = -1; - var TOP_LEFT; + var TOP_LEFT = 0; var TOP_MIDDLE; var TOP_RIGHT; var MIDDLE_LEFT; @@ -1200,8 +1242,11 @@ enum abstract StageEditorEdge(Int) { var BOTTOM_LEFT; var BOTTOM_MIDDLE; var BOTTOM_RIGHT; + var CENTER_CIRCLE; - function toString():String { + var ROTATE_CIRCLE; + + public function toString():String { return switch(cast this) { case NONE: "NONE"; case TOP_LEFT: "TOP_LEFT"; @@ -1213,6 +1258,25 @@ enum abstract StageEditorEdge(Int) { case BOTTOM_LEFT: "BOTTOM_LEFT"; case BOTTOM_MIDDLE: "BOTTOM_MIDDLE"; case BOTTOM_RIGHT: "BOTTOM_RIGHT"; + case CENTER_CIRCLE: "CENTER_CIRCLE"; + case ROTATE_CIRCLE: "ROTATE_CIRCLE"; + } + } + + public function toInt():Int { + return switch(cast this) { + case NONE: -1; + case TOP_LEFT: 0; + case TOP_MIDDLE: 1; + case TOP_RIGHT: 2; + case MIDDLE_LEFT: 3; + + case MIDDLE_RIGHT: 4; + case BOTTOM_LEFT: 5; + case BOTTOM_MIDDLE: 6; + case BOTTOM_RIGHT: 7; + case CENTER_CIRCLE: 8; + case ROTATE_CIRCLE: 9; } } } From ecdb18476eeacc4ff4918ff4606ac6989090ae58 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Fri, 19 Apr 2024 07:43:51 -0700 Subject: [PATCH 62/89] line grabbing with skewing! --- assets/data/states/StageEditor.hx | 9 ++++- source/funkin/editors/stage/StageEditor.hx | 43 ++++++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index e8624bf5..e9dd375c 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -213,12 +213,19 @@ function SCALE_BOTTOM(sprite, relative) { } +function checkSkew() { + return (mouseMode >= 9 && mouseMode <= 12); +} function SKEW_LEFT(sprite, relative) {} function SKEW_BOTTOM(sprite, relative) {} -function SKEW_TOP(sprite, relative) {} +function SKEW_TOP(sprite, relative) { + SCALE_TOP(sprite, relative); + // TODO: use the proper math. skew rotates the perpendicular edges like a circle (Ex: skew.x = 45, left & right edges rotate 45 degrees.) + sprite.skew.x = storedSkew.x + relative.x * 0.25; +} function SKEW_RIGHT(sprite, relative) {} diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 3d539e1a..57ed4877 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -1073,6 +1073,21 @@ class StageEditor extends UIState { dotCheckSize = dot.frameWidth / 0.7/stageCamera.zoom; // basically adjust it to the zoom. if(FlxG.mouse.justPressed) { + for (i in StageEditorMouseMode.SKEW_TOP...(StageEditorMouseMode.SKEW_BOTTOM + 1)) { + var cappedI1 = Math.max(i - StageEditorMouseMode.SKEW_TOP - 1, 0); + var cappedI2 = Math.min(i - StageEditorMouseMode.SKEW_TOP + 1, 3); + var point1 = buttonBoxes[Std.int(cappedI1)]; + var point2 = buttonBoxes[Std.int(cappedI2)]; + if (checkLine(point1, point2, point2.x - point1.x, point2.y - point1.y)) { + mousePoint.copyTo(clickPoint); + storedPos.set(sprite.x, sprite.y); + storedSkew.copyFrom(sprite.skew); + storedScale.copyFrom(sprite.scale); + storedAngle = sprite.angle; + mouseMode = i; + } + } + for(i=>edge in edges) { if(checkDot(buttonBoxes[i])) { mouseMode = switch(edge) { @@ -1147,6 +1162,28 @@ class StageEditor extends UIState { dot.draw(); } + function checkLine(point1:FlxPoint, point2:FlxPoint, dx:Float, dy:Float) { + var leftRegion = Math.min(point1.x, point2.x) - dotCheckSize * 0.2; + var rightRegion = Math.max(point1.x, point2.x) + dotCheckSize * 0.2; + var topRegion = Math.min(point1.y, point2.y) - dotCheckSize * 0.2; + var bottomRegion = Math.max(point1.y, point2.y) + dotCheckSize * 0.2; + + if (dx == 0.0 || dy == 0.0) + return (mousePoint.x >= leftRegion && mousePoint.x <= rightRegion) + && (mousePoint.y >= topRegion && mousePoint.y <= bottomRegion); + + var inc = dx * ((mousePoint.y - point1.y) / dy); + leftRegion += inc; + rightRegion += inc; + + inc = dy * ((mousePoint.x - point1.x) / dx); + topRegion += inc; + bottomRegion += inc; + + return (mousePoint.x >= leftRegion && mousePoint.x <= rightRegion) + && (mousePoint.y >= topRegion && mousePoint.y <= bottomRegion); + } + function drawLine(point1:FlxPoint, point2:FlxPoint, sizeModify:Float = 1) { var dx:Float = point2.x - point1.x; var dy:Float = point2.y - point1.y; @@ -1191,7 +1228,7 @@ enum StageChange { //} } -enum abstract StageEditorMouseMode(Int) { +enum abstract StageEditorMouseMode(Int) from Int to Int { var NONE; var SCALE_LEFT; @@ -1203,10 +1240,10 @@ enum abstract StageEditorMouseMode(Int) { var SCALE_BOTTOM_LEFT; var SCALE_BOTTOM_RIGHT; - var SKEW_LEFT; - var SKEW_BOTTOM; var SKEW_TOP; + var SKEW_LEFT; var SKEW_RIGHT; + var SKEW_BOTTOM; var ROTATE; From 8b68b5ae35cbd87333050b1561763fe28d77fc30 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sat, 20 Apr 2024 01:21:52 +0200 Subject: [PATCH 63/89] New Trashcan icon Co-Authored-By: betah <103602526+betah96@users.noreply.github.com> --- assets/images/editors/stage/trash-icon.png | Bin 0 -> 277 bytes .../editors/stage/elements/StageElementButton.hx | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 assets/images/editors/stage/trash-icon.png diff --git a/assets/images/editors/stage/trash-icon.png b/assets/images/editors/stage/trash-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..37041078906584ef29f0ef96a751c07ef4d9ffd9 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!3mx&jv*HQ$qPgbnmXP}N&P=)Bh>i3SGuQ1 z;q2$UyGa3|!OdL4{5g#?I1i;H{P_4;-BW_?f!>6v)6*;dd{7LLuxD8LG$EaRH-j9T zfpZ6=!Px}{4AqQBJeb-T&#>;u5OBE0^XTy5h8Tk^hP6BmOW8}Lq#2H@@*EHnv19Pk z-(bSPq`}s}uy9W2nwgD_jf@O#^TM`YnB4pg=r+F82+uTMUj{88n*)eJ;8O5p5asFW K=d#Wzp$P!7;8nB$ literal 0 HcmV?d00001 diff --git a/source/funkin/editors/stage/elements/StageElementButton.hx b/source/funkin/editors/stage/elements/StageElementButton.hx index 6ce04ddf..2dce7c63 100644 --- a/source/funkin/editors/stage/elements/StageElementButton.hx +++ b/source/funkin/editors/stage/elements/StageElementButton.hx @@ -76,7 +76,7 @@ class StageElementButton extends UIButton { deleteButton.autoAlpha = false; members.push(deleteButton); - deleteIcon = new FlxSprite(deleteButton.x + (15/2), deleteButton.y + 8).loadGraphic(Paths.image('editors/delete-button')); + deleteIcon = new FlxSprite(deleteButton.x + 8, deleteButton.y + 8).loadGraphic(Paths.image('editors/stage/trash-icon')); deleteIcon.antialiasing = false; members.push(deleteIcon); @@ -166,7 +166,7 @@ class StageElementButton extends UIButton { // icons visibilityIcon.x = visibilityButton.x + 8; visibilityIcon.y = visibilityButton.y + 8; editIcon.x = editButton.x + 8; editIcon.y = editButton.y + 8; - deleteIcon.x = deleteButton.x + (15/2); deleteIcon.y = deleteButton.y + 8; + deleteIcon.x = deleteButton.x + 8; deleteIcon.y = deleteButton.y + 8; tagColor.x = x;// + bWidth - tagColor.bWidth; tagColor.y = y; From 7535392ffb664ba2ca4d041290bfd4bf720fb601 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Fri, 19 Apr 2024 17:21:35 -0700 Subject: [PATCH 64/89] SKEW_TOP works! ill do the other skews later lol --- assets/data/states/StageEditor.hx | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index e9dd375c..dbcc6fb8 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -71,6 +71,9 @@ function destroy() { } function update() { + if (FlxG.mouse.justPressed) + lastRelative.set(); + if(FlxG.keys.justPressed.R) { trace("reloading"); FlxG.switchState(new StageEditor(StageEditor.__stage)); @@ -212,19 +215,25 @@ function SCALE_BOTTOM(sprite, relative) { postRotBullshit(sprite, relative); } - -function checkSkew() { - return (mouseMode >= 9 && mouseMode <= 12); -} +var lastRelative = FlxPoint.get(); function SKEW_LEFT(sprite, relative) {} function SKEW_BOTTOM(sprite, relative) {} function SKEW_TOP(sprite, relative) { - SCALE_TOP(sprite, relative); - // TODO: use the proper math. skew rotates the perpendicular edges like a circle (Ex: skew.x = 45, left & right edges rotate 45 degrees.) - sprite.skew.x = storedSkew.x + relative.x * 0.25; + if (!FlxG.keys.pressed.SHIFT) + SCALE_TOP(sprite, relative); + + var topLeft = sprite.extra.get(exID("buttonBoxes"))[0]; + var bottomLeft = sprite.extra.get(exID("buttonBoxes"))[2]; + + sprite.skew.x = Math.atan2( + bottomLeft.x - (topLeft.x + (lastRelative.x - relative.x) * 2), + bottomLeft.y - (topLeft.y + (FlxG.keys.pressed.SHIFT ? 0 : relative.y - lastRelative.y)) + ) * FlxAngle.TO_DEG; + + lastRelative.set(relative.x, relative.y); } function SKEW_RIGHT(sprite, relative) {} From 4b46ef53825fe3f097dea05f0197a1c4d3bcab25 Mon Sep 17 00:00:00 2001 From: Sonamaker1 <87080176+Sonamaker1@users.noreply.github.com> Date: Fri, 19 Apr 2024 19:11:26 -0700 Subject: [PATCH 65/89] Sprite moving. I'll finish this later --- assets/data/states/StageEditor.hx | 9 +++++- source/funkin/editors/stage/StageEditor.hx | 33 +++++++++++++++++----- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index dbcc6fb8..2f1ebafb 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -179,6 +179,13 @@ function SCALE_TOP_RIGHT(sprite, relative) { postRotBullshit(sprite, relative); } +function MOVE_CENTER(sprite, relative) { + preRotBullshit(sprite, relative); + sprite.x = storedPos.x-relative.x; + sprite.y = storedPos.y-relative.y; + postRotBullshit(sprite, relative); +} + function SCALE_TOP_LEFT(sprite, relative) { preRotBullshit(sprite, relative); genericOppositeScale(sprite, relative, true, true, true, true); @@ -262,4 +269,4 @@ function ROTATE(sprite, relative) { if(storedCenter.x != 0 || storedCenter.y != 0) { drawLine(storedCenter, storedRelative, 0.3); } -}*/ \ No newline at end of file +}*/ diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 57ed4877..6499a360 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -986,8 +986,15 @@ class StageEditor extends UIState { } else { drawDot(corner.x, corner.y); } + buttonBoxes.push(corner); } - buttonBoxes.push(corner); + else if(sprite.visible){ + dot.color = circleColor; + drawDot(corner.x, corner.y, 0.7); + dot.animation.play("hollow"); + buttonBoxes.push(corner); + } + } if(funkinSprite == null) { @@ -1099,6 +1106,7 @@ class StageEditor extends UIState { case BOTTOM_LEFT: SCALE_BOTTOM_LEFT; case BOTTOM_MIDDLE: SCALE_BOTTOM; case BOTTOM_RIGHT: SCALE_BOTTOM_RIGHT; + case CENTER_CIRCLE: MOVE_CENTER; case ROTATE_CIRCLE: ROTATE; default: NONE; } @@ -1109,6 +1117,11 @@ class StageEditor extends UIState { storedScale.copyFrom(sprite.scale); storedAngle = sprite.angle; } + + if(mouseMode == MOVE_CENTER){ + trace(mouseMode); + storedPos.set(sprite.x, sprite.y); + } } } for(i=>edge in edges) { @@ -1120,7 +1133,7 @@ class StageEditor extends UIState { case TOP_MIDDLE: RESIZE_T; case TOP_RIGHT: RESIZE_TR; case MIDDLE_LEFT: RESIZE_L; - //case MIDDLE_MIDDLE: RESIZE_H; + case CENTER_CIRCLE: HAND; case MIDDLE_RIGHT: RESIZE_R; case BOTTOM_LEFT: RESIZE_BL; case BOTTOM_MIDDLE: RESIZE_B; @@ -1150,13 +1163,16 @@ class StageEditor extends UIState { var dotCheckSize:Float = 53; function checkDot(point:FlxPoint):Bool { - var rect = new FlxRect(point.x - dotCheckSize/2, point.y - dotCheckSize/2, dotCheckSize, dotCheckSize); - return rect.containsPoint(mousePoint); + if(point!=null){ + var rect = new FlxRect(point.x - dotCheckSize/2, point.y - dotCheckSize/2, dotCheckSize, dotCheckSize); + return rect.containsPoint(mousePoint); + } + return false; } - inline function drawDot(x:Float, y:Float) { + inline function drawDot(x:Float, y:Float, ?scale:Float = 1) { dot.setPosition(x, y); - dot.scale.set(0.7/stageCamera.zoom, 0.7/stageCamera.zoom); + dot.scale.set(0.7/stageCamera.zoom * scale, 0.7/stageCamera.zoom * scale); dot.x -= dot.width / 2; dot.y -= dot.height / 2; dot.draw(); @@ -1240,6 +1256,8 @@ enum abstract StageEditorMouseMode(Int) from Int to Int { var SCALE_BOTTOM_LEFT; var SCALE_BOTTOM_RIGHT; + var MOVE_CENTER; + var SKEW_TOP; var SKEW_LEFT; var SKEW_RIGHT; @@ -1258,6 +1276,7 @@ enum abstract StageEditorMouseMode(Int) from Int to Int { case SCALE_TOP_RIGHT: "SCALE_TOP_RIGHT"; case SCALE_BOTTOM_LEFT: "SCALE_BOTTOM_LEFT"; case SCALE_BOTTOM_RIGHT: "SCALE_BOTTOM_RIGHT"; + case MOVE_CENTER: "MOVE_CENTER"; case SKEW_LEFT: "SKEW_LEFT"; case SKEW_BOTTOM: "SKEW_BOTTOM"; case SKEW_TOP: "SKEW_TOP"; @@ -1337,4 +1356,4 @@ class StageXMLEditScreen extends UISoftcodedWindow { super.saveData(); if(saveCallback != null) saveCallback(); } -} \ No newline at end of file +} From 0b20d3c1155cdd03fd99a5aa2bfcbe5055fd67a7 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sat, 20 Apr 2024 22:10:38 +0200 Subject: [PATCH 66/89] Fixed cursor on move for mac --- source/external/src/mac/CursorHelper.mm | 1 + source/external/src/mac/Mac.mm | 25 +++++++++++----------- source/funkin/editors/stage/StageEditor.hx | 3 ++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/source/external/src/mac/CursorHelper.mm b/source/external/src/mac/CursorHelper.mm index 90549237..49f7eab9 100644 --- a/source/external/src/mac/CursorHelper.mm +++ b/source/external/src/mac/CursorHelper.mm @@ -11,6 +11,7 @@ if ([NSCursor respondsToSelector:selector]) { cursor = [NSCursor performSelector:selector]; } else { + NSLog(@"CursorHelper: selector %@ not found", NSStringFromSelector(selector)); cursor = defaultCursor; } #pragma clang diagnostic pop diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index 8858ae88..8303e289 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -39,23 +39,24 @@ namespace ExternalMac { case HAND: cursor = [NSCursor closedHandCursor]; break; case IBEAM: cursor = [NSCursor IBeamCursor]; break; //case MOVE: cursor = [NSCursor moveCursor]; break; + //case MOVE: cursor = [CursorHelper getCursorForSelector:@selector(_moveCursor) defaultCursor:nil]; break; case RESIZE_H: cursor = [NSCursor resizeLeftRightCursor]; break; case RESIZE_V: cursor = [NSCursor resizeUpDownCursor]; break; // TODO: DEFAULTS - case RESIZE_TL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case RESIZE_TR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case RESIZE_BL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthWestCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case RESIZE_BR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthEastCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case RESIZE_T: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case RESIZE_B: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case RESIZE_L: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeWestCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case RESIZE_R: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeEastCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case RESIZE_TLBR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestSouthEastCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case RESIZE_TRBL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastSouthWestCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case RESIZE_TL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestCursor) defaultCursor:nil]; break; + case RESIZE_TR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastCursor) defaultCursor:nil]; break; + case RESIZE_BL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthWestCursor) defaultCursor:nil]; break; + case RESIZE_BR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthEastCursor) defaultCursor:nil]; break; + case RESIZE_T: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthCursor) defaultCursor:nil]; break; + case RESIZE_B: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthCursor) defaultCursor:nil]; break; + case RESIZE_L: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeWestCursor) defaultCursor:nil]; break; + case RESIZE_R: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeEastCursor) defaultCursor:nil]; break; + case RESIZE_TLBR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestSouthEastCursor) defaultCursor:nil]; break; + case RESIZE_TRBL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastSouthWestCursor) defaultCursor:nil]; break; - case WAIT: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:[NSCursor arrowCursor]]; break; - case WAIT_ARROW: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:[NSCursor arrowCursor]]; break; + case WAIT: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:nil]; break; + case WAIT_ARROW: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:nil]; break; case DISABLED: cursor = [NSCursor operationNotAllowedCursor]; break; case DRAG: cursor = [NSCursor closedHandCursor]; break; case DRAG_OPEN: cursor = [NSCursor openHandCursor]; break; diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 6499a360..1d2766ab 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -1127,13 +1127,14 @@ class StageEditor extends UIState { for(i=>edge in edges) { if(checkDot(buttonBoxes[i])) { // TODO: make it show both sided arrows when resizing, unless its at minimum size then show only one + // TODO: make this rotate with the sprite currentCursor = switch(edge) { // RESIZE_NESW; //RESIZE_NS; //RESIZE_NWSE; //RESIZE_WE; case TOP_LEFT: RESIZE_TL; case TOP_MIDDLE: RESIZE_T; case TOP_RIGHT: RESIZE_TR; case MIDDLE_LEFT: RESIZE_L; - case CENTER_CIRCLE: HAND; + case CENTER_CIRCLE: #if mac FlxG.mouse.pressed ? DRAG : DRAG_OPEN #else MOVE #end; case MIDDLE_RIGHT: RESIZE_R; case BOTTOM_LEFT: RESIZE_BL; case BOTTOM_MIDDLE: RESIZE_B; From 7f734b6aaaa4e64855dd918b4eb81604952408c2 Mon Sep 17 00:00:00 2001 From: Sonamaker1 <87080176+Sonamaker1@users.noreply.github.com> Date: Sat, 20 Apr 2024 13:39:25 -0700 Subject: [PATCH 67/89] Added linux cursors Note: DRAG_OPEN and MOVE are not available on my linux flavor. May need more testing --- source/funkin/editors/stage/StageEditor.hx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 1d2766ab..f19bfc3e 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -1134,7 +1134,10 @@ class StageEditor extends UIState { case TOP_MIDDLE: RESIZE_T; case TOP_RIGHT: RESIZE_TR; case MIDDLE_LEFT: RESIZE_L; - case CENTER_CIRCLE: #if mac FlxG.mouse.pressed ? DRAG : DRAG_OPEN #else MOVE #end; + case CENTER_CIRCLE: + #if (mac) FlxG.mouse.pressed ? DRAG : DRAG_OPEN + #elseif (linux) FlxG.mouse.pressed ? DRAG : CLICK + #else MOVE #end; case MIDDLE_RIGHT: RESIZE_R; case BOTTOM_LEFT: RESIZE_BL; case BOTTOM_MIDDLE: RESIZE_B; From 193fbae4bf5560d982ff8eb3f061b7b2f7d13242 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Sat, 20 Apr 2024 15:14:49 -0700 Subject: [PATCH 68/89] fix charPos not displaying position and scale properly --- .../editors/stage/elements/StageCharacterButton.hx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/funkin/editors/stage/elements/StageCharacterButton.hx b/source/funkin/editors/stage/elements/StageCharacterButton.hx index f23d6fe4..d74e8834 100644 --- a/source/funkin/editors/stage/elements/StageCharacterButton.hx +++ b/source/funkin/editors/stage/elements/StageCharacterButton.hx @@ -28,9 +28,14 @@ class StageCharacterButton extends StageElementButton { public override function updateInfo() { char.visible = !isHidden; char.alpha = 0.5 * charPos.alpha; - charPos.scale.x = char.scale.x; - charPos.scale.y = char.scale.y; + var charScale = (char.xml.has.scale ? Std.parseFloat(char.xml.att.scale).getDefault(1) : 1); + charPos.scale.x = char.scale.x / charScale; + charPos.scale.y = char.scale.y / charScale; + charPos.x = char.x; + charPos.y = char.y; + char.scale.copyFrom(charPos.scale); super.updateInfo(); + char.scale.scale(charScale); } public override function getSprite():FunkinSprite { From abe385a1913feb40e0228b15f18c7786a16f6369 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Sat, 20 Apr 2024 15:57:49 -0700 Subject: [PATCH 69/89] rotated skew and SKEW_RIGHT are fucky right now --- assets/data/states/StageEditor.hx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index 2f1ebafb..140e31d5 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -229,8 +229,9 @@ function SKEW_LEFT(sprite, relative) {} function SKEW_BOTTOM(sprite, relative) {} function SKEW_TOP(sprite, relative) { + preRotBullshit(sprite, relative); if (!FlxG.keys.pressed.SHIFT) - SCALE_TOP(sprite, relative); + genericOppositeScale(sprite, relative, false, true, false, true); var topLeft = sprite.extra.get(exID("buttonBoxes"))[0]; var bottomLeft = sprite.extra.get(exID("buttonBoxes"))[2]; @@ -240,10 +241,26 @@ function SKEW_TOP(sprite, relative) { bottomLeft.y - (topLeft.y + (FlxG.keys.pressed.SHIFT ? 0 : relative.y - lastRelative.y)) ) * FlxAngle.TO_DEG; - lastRelative.set(relative.x, relative.y); + lastRelative.set(relative.x, (FlxG.keys.pressed.SHIFT ? lastRelative.y : relative.y)); + postRotBullshit(sprite, relative); } -function SKEW_RIGHT(sprite, relative) {} +function SKEW_RIGHT(sprite, relative) { + preRotBullshit(sprite, relative); + if (!FlxG.keys.pressed.SHIFT) + genericScale(sprite, relative, true, false); + + var topLeft = sprite.extra.get(exID("buttonBoxes"))[0]; + var topRight = sprite.extra.get(exID("buttonBoxes"))[1]; + + sprite.skew.y = Math.atan2( + topLeft.x - (topRight.x + (FlxG.keys.pressed.SHIFT ? 0 : relative.x - lastRelative.x)), + topLeft.y - (topRight.y + (lastRelative.y - relative.y) * 2) + ) * FlxAngle.TO_DEG; + + lastRelative.set((FlxG.keys.pressed.SHIFT ? lastRelative.x : relative.x), relative.y); + postRotBullshit(sprite, relative); +} /*var storedCenter = FlxPoint.get(); var storedRelative = FlxPoint.get();*/ From 34a8292f6f8282b72a5318f5a1ceb2d2238d2f34 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:44:26 +0200 Subject: [PATCH 70/89] Fix type xml generation --- source/funkin/editors/stage/StageEditor.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index f19bfc3e..8704c22d 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -648,7 +648,8 @@ class StageEditor extends UIState { saveToXml(spriteXML, "interval", node.getAtt("beatInterval"), 2); saveToXml(spriteXML, "interval", node.getAtt("interval"), 2); saveToXml(spriteXML, "beatOffset", node.getAtt("beatOffset"), 0); - saveToXml(spriteXML, "type", sprite.spriteAnimType, LOOP); + if(sprite.spriteAnimType != LOOP) spriteXML.remove("type"); + spriteXML.set("type", sprite.spriteAnimType.toString()); saveToXml(spriteXML, "color", sprite.color.toWebString(), "#FFFFFF"); // TODO: save custom parameters //saveToXml(spriteXML, "flipX", sprite.flipX, false); From a827f5c73d5a2a5ccd316eade6357c1401aa1bd2 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:50:16 +0200 Subject: [PATCH 71/89] Oops --- source/funkin/editors/stage/StageEditor.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 8704c22d..49be4a97 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -648,7 +648,7 @@ class StageEditor extends UIState { saveToXml(spriteXML, "interval", node.getAtt("beatInterval"), 2); saveToXml(spriteXML, "interval", node.getAtt("interval"), 2); saveToXml(spriteXML, "beatOffset", node.getAtt("beatOffset"), 0); - if(sprite.spriteAnimType != LOOP) spriteXML.remove("type"); + if(sprite.spriteAnimType != LOOP) spriteXML.set("type", sprite.spriteAnimType.toString()); saveToXml(spriteXML, "color", sprite.color.toWebString(), "#FFFFFF"); // TODO: save custom parameters From 566418dcab5d9702b5425e0d7903a7b013a15d48 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:57:33 +0200 Subject: [PATCH 72/89] Fixed dumb typo --- source/funkin/editors/stage/StageEditor.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 49be4a97..a5590a69 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -631,7 +631,7 @@ class StageEditor extends UIState { saveToXml(spriteXML, "y", sprite.y, 0); saveToXml(spriteXML, "sprite", sprite.extra.get(exID("imageFile"))); savePointToXml(spriteXML, "scale", sprite.scale, 1); - savePointToXml(spriteXML, "scroll", sprite.scrollFactor, 0); + savePointToXml(spriteXML, "scroll", sprite.scrollFactor, 1); saveToXml(spriteXML, "skewx", sprite.skew.x, 0); saveToXml(spriteXML, "skewy", sprite.skew.y, 0); saveToXml(spriteXML, "alpha", sprite.alpha, 1); From 974d8742c37b0443768fac645f06e71f3ab3e85c Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Sun, 21 Apr 2024 23:02:29 +0200 Subject: [PATCH 73/89] Removed useless pragmas --- source/external/src/mac/CursorHelper.mm | 3 --- source/external/src/mac/Mac.mm | 5 ----- 2 files changed, 8 deletions(-) diff --git a/source/external/src/mac/CursorHelper.mm b/source/external/src/mac/CursorHelper.mm index 49f7eab9..5ee99b81 100644 --- a/source/external/src/mac/CursorHelper.mm +++ b/source/external/src/mac/CursorHelper.mm @@ -6,15 +6,12 @@ + (NSCursor *)getCursorForSelector:(SEL)selector defaultCursor:(NSCursor *)defaultCursor { NSCursor *cursor = nil; - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wundeclared-selector" if ([NSCursor respondsToSelector:selector]) { cursor = [NSCursor performSelector:selector]; } else { NSLog(@"CursorHelper: selector %@ not found", NSStringFromSelector(selector)); cursor = defaultCursor; } - #pragma clang diagnostic pop return cursor; } diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index 8303e289..8e10d492 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -28,9 +28,6 @@ namespace ExternalMac { bool setCursorIcon(int icon/*, const char *customCursor, float customX, float customY*/) { - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wundeclared-selector" - NSCursor *cursor = nil; switch(icon) { case ARROW: cursor = [NSCursor arrowCursor]; break; @@ -73,8 +70,6 @@ namespace ExternalMac { case CUSTOM: cursor = [NSCursor arrowCursor]; break; } - #pragma clang diagnostic pop - if(cursor != nil) { [cursor set]; From 0b8f681da9dd6569eaec6f43998b764266b25a27 Mon Sep 17 00:00:00 2001 From: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> Date: Mon, 22 Apr 2024 00:27:12 +0300 Subject: [PATCH 74/89] Support for custom image ig? --- source/external/src/mac/Mac.mm | 125 +++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 37 deletions(-) diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index 8e10d492..af86ece5 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -1,3 +1,4 @@ +#include <unordered_map> #import <Cocoa/Cocoa.h> #import "CursorHelper.h" @@ -26,55 +27,105 @@ #define RESIZE_TRBL 22 #define CUSTOM -1 -namespace ExternalMac { - bool setCursorIcon(int icon/*, const char *customCursor, float customX, float customY*/) { +namespace ExternalMac +{ + std::unordered_map<std::string, NSCursor *> customCursorCache; + + bool setCursorIcon(int icon, const char *customCursor, float customX, float customY) + { NSCursor *cursor = nil; - switch(icon) { - case ARROW: cursor = [NSCursor arrowCursor]; break; - case CLICK: cursor = [NSCursor pointingHandCursor]; break; - case CROSSHAIR: cursor = [NSCursor crosshairCursor]; break; - case HAND: cursor = [NSCursor closedHandCursor]; break; - case IBEAM: cursor = [NSCursor IBeamCursor]; break; - //case MOVE: cursor = [NSCursor moveCursor]; break; - //case MOVE: cursor = [CursorHelper getCursorForSelector:@selector(_moveCursor) defaultCursor:nil]; break; - case RESIZE_H: cursor = [NSCursor resizeLeftRightCursor]; break; - case RESIZE_V: cursor = [NSCursor resizeUpDownCursor]; break; + switch (icon) + { + case ARROW: + cursor = [NSCursor arrowCursor]; + break; + case CLICK: + cursor = [NSCursor pointingHandCursor]; + break; + case CROSSHAIR: + cursor = [NSCursor crosshairCursor]; + break; + case HAND: + cursor = [NSCursor closedHandCursor]; + break; + case IBEAM: + cursor = [NSCursor IBeamCursor]; + break; + case RESIZE_H: + cursor = [NSCursor resizeLeftRightCursor]; + break; + case RESIZE_V: + cursor = [NSCursor resizeUpDownCursor]; + break; // TODO: DEFAULTS - case RESIZE_TL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestCursor) defaultCursor:nil]; break; - case RESIZE_TR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastCursor) defaultCursor:nil]; break; - case RESIZE_BL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthWestCursor) defaultCursor:nil]; break; - case RESIZE_BR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthEastCursor) defaultCursor:nil]; break; - case RESIZE_T: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthCursor) defaultCursor:nil]; break; - case RESIZE_B: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthCursor) defaultCursor:nil]; break; - case RESIZE_L: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeWestCursor) defaultCursor:nil]; break; - case RESIZE_R: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeEastCursor) defaultCursor:nil]; break; - case RESIZE_TLBR: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestSouthEastCursor) defaultCursor:nil]; break; - case RESIZE_TRBL: cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastSouthWestCursor) defaultCursor:nil]; break; - - case WAIT: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:nil]; break; - case WAIT_ARROW: cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor) defaultCursor:nil]; break; - case DISABLED: cursor = [NSCursor operationNotAllowedCursor]; break; - case DRAG: cursor = [NSCursor closedHandCursor]; break; - case DRAG_OPEN: cursor = [NSCursor openHandCursor]; break; + case RESIZE_TL: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestCursor)defaultCursor:nil]; + break; + case RESIZE_TR: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastCursor)defaultCursor:nil]; + break; + case RESIZE_BL: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthWestCursor)defaultCursor:nil]; + break; + case RESIZE_BR: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthEastCursor)defaultCursor:nil]; + break; + case RESIZE_T: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthCursor)defaultCursor:nil]; + break; + case RESIZE_B: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeSouthCursor)defaultCursor:nil]; + break; + case RESIZE_L: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeWestCursor)defaultCursor:nil]; + break; + case RESIZE_R: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeEastCursor)defaultCursor:nil]; + break; + case RESIZE_TLBR: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthWestSouthEastCursor)defaultCursor:nil]; + break; + case RESIZE_TRBL: + cursor = [CursorHelper getCursorForSelector:@selector(_windowResizeNorthEastSouthWestCursor)defaultCursor:nil]; + break; + case WAIT: + cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor)defaultCursor:nil]; + break; + case WAIT_ARROW: + cursor = [CursorHelper getCursorForSelector:@selector(_waitCursor)defaultCursor:nil]; + break; + case DISABLED: + cursor = [NSCursor operationNotAllowedCursor]; + break; + case DRAG: + cursor = [NSCursor closedHandCursor]; + break; + case DRAG_OPEN: + cursor = [NSCursor openHandCursor]; + break; + case CUSTOM: + NSString *cursorImageName = [NSString stringWithUTF8String:customCursor]; - /*case CUSTOM: { - // TODO: CACHING - NSString *cursorImageName = [NSString stringWithUTF8String:customCursor]; - NSImage *tmpImage = [NSImage imageNamed:cursorImageName]; - NSCursor *pointer = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)]; + if (customCursorCache.find(cursorImageName.UTF8String) != customCursorCache.end()) + cursor = customCursorCache[cursorImageName.UTF8String]; + else + { + NSImage *tmpImage = [NSImage imageNamed:cursorImageName]; + cursor = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)]; + customCursorCache[cursorImageName.UTF8String] = cursor; + } - cursor = [NSCursor pointer] break; - }*/ - case CUSTOM: cursor = [NSCursor arrowCursor]; break; } - if(cursor != nil) { + if (cursor != nil) + { [cursor set]; return true; } + return false; } } From 60b81ee7bad57a726cdc9f17bb58b4fd6e547010 Mon Sep 17 00:00:00 2001 From: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> Date: Mon, 22 Apr 2024 00:27:31 +0300 Subject: [PATCH 75/89] Update Mac.h --- source/external/include/mac/Mac.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/external/include/mac/Mac.h b/source/external/include/mac/Mac.h index 2b88b858..516b5050 100644 --- a/source/external/include/mac/Mac.h +++ b/source/external/include/mac/Mac.h @@ -5,9 +5,9 @@ namespace ExternalMac { - bool setCursorIcon(int icon); + bool setCursorIcon(int icon, const char *customCursor, float customX, float customY); } #endif -#endif \ No newline at end of file +#endif From c0b9a97f401c67630177bb1ba0c904b9f1972cfc Mon Sep 17 00:00:00 2001 From: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> Date: Mon, 22 Apr 2024 00:29:41 +0300 Subject: [PATCH 76/89] Update ExternalMac.hx --- source/external/ExternalMac.hx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source/external/ExternalMac.hx b/source/external/ExternalMac.hx index 6ac4abd4..46a9e5f1 100644 --- a/source/external/ExternalMac.hx +++ b/source/external/ExternalMac.hx @@ -2,10 +2,11 @@ package external; #if mac @:build(external.LinkerMacro.xml('external_code.xml')) -@:native("ExternalMac") @:include('Mac.h') -extern class ExternalMac { - @:native("ExternalMac::setCursorIcon") - public static function setCursorIcon(icon:Int):Bool; +@:native('ExternalMac') +extern class ExternalMac +{ + @:native('ExternalMac::setCursorIcon') + public static function setCursorIcon(icon:Int, customCursor:cpp.ConstCharStar, customX:Single, customY:Single):Bool; } -#end \ No newline at end of file +#end From b2efa65ff8a2ac6a134a32f3223e1bdc6a87739b Mon Sep 17 00:00:00 2001 From: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> Date: Mon, 22 Apr 2024 00:32:21 +0300 Subject: [PATCH 77/89] Update CursorHelper.mm --- source/external/src/mac/CursorHelper.mm | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/source/external/src/mac/CursorHelper.mm b/source/external/src/mac/CursorHelper.mm index 5ee99b81..3999bbb5 100644 --- a/source/external/src/mac/CursorHelper.mm +++ b/source/external/src/mac/CursorHelper.mm @@ -3,17 +3,22 @@ @implementation CursorHelper -+ (NSCursor *)getCursorForSelector:(SEL)selector defaultCursor:(NSCursor *)defaultCursor { - NSCursor *cursor = nil; ++ (NSCursor *)getCursorForSelector:(SEL)selector defaultCursor:(NSCursor *)defaultCursor +{ + NSCursor *cursor = nil; - if ([NSCursor respondsToSelector:selector]) { - cursor = [NSCursor performSelector:selector]; - } else { + if ([NSCursor respondsToSelector:selector]) + { + cursor = [NSCursor performSelector:selector]; + } + else + { NSLog(@"CursorHelper: selector %@ not found", NSStringFromSelector(selector)); - cursor = defaultCursor; - } + + cursor = defaultCursor; + } - return cursor; + return cursor; } @end From 0f5d5799e0e8cdc4d30337b50e24a4ab20ef30e8 Mon Sep 17 00:00:00 2001 From: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> Date: Mon, 22 Apr 2024 07:31:53 +0300 Subject: [PATCH 78/89] Release the image after setting --- source/external/src/mac/Mac.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index af86ece5..c134ba04 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -114,6 +114,7 @@ namespace ExternalMac NSImage *tmpImage = [NSImage imageNamed:cursorImageName]; cursor = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)]; customCursorCache[cursorImageName.UTF8String] = cursor; + [tmpImage release]; } break; From 6ba393771d3cafc6cac45dd741ddc43732703fac Mon Sep 17 00:00:00 2001 From: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> Date: Mon, 22 Apr 2024 07:33:52 +0300 Subject: [PATCH 79/89] Update Mac.mm --- source/external/src/mac/Mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index c134ba04..a974c49c 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -114,7 +114,7 @@ namespace ExternalMac NSImage *tmpImage = [NSImage imageNamed:cursorImageName]; cursor = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)]; customCursorCache[cursorImageName.UTF8String] = cursor; - [tmpImage release]; + // [tmpImage release]; } break; From bf993d5919c19186b2ff993b40f772766d21eee6 Mon Sep 17 00:00:00 2001 From: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> Date: Mon, 22 Apr 2024 07:36:18 +0300 Subject: [PATCH 80/89] Update Mac.hx --- source/funkin/backend/utils/native/Mac.hx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/funkin/backend/utils/native/Mac.hx b/source/funkin/backend/utils/native/Mac.hx index 612335e3..abdb478c 100644 --- a/source/funkin/backend/utils/native/Mac.hx +++ b/source/funkin/backend/utils/native/Mac.hx @@ -5,7 +5,8 @@ import funkin.backend.utils.NativeAPI.CodeCursor; import openfl.ui.Mouse; @:headerInclude('sys/sysctl.h') -class Mac { +class Mac +{ @:functionCode(' int mib [] = { CTL_HW, HW_MEMSIZE }; int64_t value = 0; @@ -23,10 +24,10 @@ class Mac { public static function setMouseCursorIcon(icon:CodeCursor):Void { - final valid:Bool = external.ExternalMac.setCursorIcon(icon.toInt()); - if(!valid) { + final valid:Bool = external.ExternalMac.setCursorIcon(icon.toInt(), null, 0, 0); + + if (!valid) Mouse.cursor = icon.toOpenFL(); - } } } #end From 2f1f05b4ed895a264502888d2e9ca9f0981947aa Mon Sep 17 00:00:00 2001 From: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:31:08 +0300 Subject: [PATCH 81/89] Update Mac.mm --- source/external/src/mac/Mac.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index a974c49c..febc8f02 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -1,4 +1,5 @@ #include <unordered_map> + #import <Cocoa/Cocoa.h> #import "CursorHelper.h" @@ -29,7 +30,7 @@ namespace ExternalMac { - std::unordered_map<std::string, NSCursor *> customCursorCache; + std::unordered_map<const char *, NSCursor *> customCursorCache; bool setCursorIcon(int icon, const char *customCursor, float customX, float customY) { From a95988dbebc01a6deab3648f9cd6682e6ea2424b Mon Sep 17 00:00:00 2001 From: Mihai Alexandru <77043862+MAJigsaw77@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:00:28 +0300 Subject: [PATCH 82/89] Update Mac.mm --- source/external/src/mac/Mac.mm | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index febc8f02..a1e92974 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -112,10 +112,17 @@ namespace ExternalMac cursor = customCursorCache[cursorImageName.UTF8String]; else { + NSString *cursorImageName = [NSString stringWithUTF8String:customCursor]; NSImage *tmpImage = [NSImage imageNamed:cursorImageName]; - cursor = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)]; - customCursorCache[cursorImageName.UTF8String] = cursor; - // [tmpImage release]; + + if (tmpImage != nullptr) + { + cursor = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)]; + customCursorCache[customCursor] = cursor; + // [tmpImage release]; + } + else + NSLog(@"Failed to load image %@", cursorImageName); } break; From 21a9cc7b8fdbbad9873af7fbf3046fdb7ca442c8 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:14:52 +0200 Subject: [PATCH 83/89] Fixed custom cursors on mac --- source/external/src/mac/Mac.mm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index a1e92974..f49fa2a3 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -106,16 +106,14 @@ namespace ExternalMac cursor = [NSCursor openHandCursor]; break; case CUSTOM: - NSString *cursorImageName = [NSString stringWithUTF8String:customCursor]; - - if (customCursorCache.find(cursorImageName.UTF8String) != customCursorCache.end()) - cursor = customCursorCache[cursorImageName.UTF8String]; + if (customCursorCache.find(customCursor) != customCursorCache.end()) + cursor = customCursorCache[customCursor]; else { NSString *cursorImageName = [NSString stringWithUTF8String:customCursor]; - NSImage *tmpImage = [NSImage imageNamed:cursorImageName]; + NSImage *tmpImage = [[NSImage alloc] initWithContentsOfFile:cursorImageName]; - if (tmpImage != nullptr) + if (tmpImage != nil) { cursor = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)]; customCursorCache[customCursor] = cursor; From 764e5acf1212397cca39732f292ba38f0c6b0846 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Mon, 22 Apr 2024 07:23:01 -0700 Subject: [PATCH 84/89] sprite transform is undoable still need a lot more undos to make tho --- assets/data/states/StageEditor.hx | 17 +++- source/funkin/editors/stage/StageEditor.hx | 90 +++++++++++++--------- 2 files changed, 70 insertions(+), 37 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index 140e31d5..b0644601 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -226,7 +226,22 @@ var lastRelative = FlxPoint.get(); function SKEW_LEFT(sprite, relative) {} -function SKEW_BOTTOM(sprite, relative) {} +function SKEW_BOTTOM(sprite, relative) { + preRotBullshit(sprite, relative); + if (!FlxG.keys.pressed.SHIFT) + genericScale(sprite, relative, false, true); + + var topLeft = sprite.extra.get(exID("buttonBoxes"))[0]; + var bottomLeft = sprite.extra.get(exID("buttonBoxes"))[2]; + + sprite.skew.x = Math.atan2( + topLeft.x - (bottomLeft.x + (lastRelative.x - relative.x) * 2), + topLeft.y - (bottomLeft.y + (FlxG.keys.pressed.SHIFT ? 0 : lastRelative.y - relative.y)) + ) * FlxAngle.TO_DEG; + + lastRelative.set(relative.x, (FlxG.keys.pressed.SHIFT ? lastRelative.y : relative.y)); + postRotBullshit(sprite, relative); +} function SKEW_TOP(sprite, relative) { preRotBullshit(sprite, relative); diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index a5590a69..2416f6ed 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -101,7 +101,7 @@ class StageEditor extends UIState { { label: "Edit", childs: [ - /*{ + { label: "Undo", keybind: [CONTROL, Z], onSelect: _edit_undo, @@ -111,7 +111,7 @@ class StageEditor extends UIState { keybind: [CONTROL, SHIFT, Z], onSelect: _edit_redo, }, - null,*/ + null, { label: "Edit Stage Info", onSelect: (_) -> { @@ -416,6 +416,7 @@ class StageEditor extends UIState { currentCursor = ARROW; + mousePoint = FlxG.mouse.getWorldPosition(stageCamera, mousePoint); if ((!stageSpritesWindow.hovered && !stageSpritesWindow.dragging) && !topMenuSpr.hovered) { if (FlxG.mouse.wheel != 0) { zoom += 0.25 * FlxG.mouse.wheel; @@ -722,31 +723,19 @@ class StageEditor extends UIState { return "<!DOCTYPE codename-engine-stage>\n" + Printer.print(xml, true); } - /*function _edit_undo(_) { + function _edit_undo(_) { var undo = undos.undo(); switch(undo) { case null: // do nothing case CEditInfo(oldInfo, newInfo): - editInfo(oldInfo, false); - case CCreateAnim(animID, animData): - deleteAnim(animData.name, false); - case CEditAnim(name, oldData, animData): - editAnim(name, oldData, false); - case CDeleteAnim(animID, animData): - createAnim(animData, animID, false); - case CChangeOffset(name, change): - changeOffset(name, change * -1, false); - case CResetOffsets(oldOffsets): - for (anim => offsets in oldOffsets) { - character.animOffsets.set(anim, offsets.clone()); - ghosts.setOffsets(anim, offsets.clone()); - } - - for (charButton in characterAnimsWindow.buttons.members) - charButton.updateInfo(charButton.anim, character.getAnimOffset(charButton.anim), ghosts.animGhosts[charButton.anim].visible); - - changeOffset(character.getAnimName(), FlxPoint.get(0, 0), false); // apply da new offsets + //editInfo(oldInfo, false); + case CTransform(sprite, oldInfo, newInfo): + sprite.setPosition(oldInfo.x, oldInfo.y); + sprite.scale.set(oldInfo.scaleX, oldInfo.scaleY); + sprite.skew.set(oldInfo.skewX, oldInfo.skewY); + sprite.angle = oldInfo.angle; + cast(sprite.extra.get(exID("button")), StageElementButton).updateInfo(); } } @@ -757,18 +746,14 @@ class StageEditor extends UIState { // do nothing case CEditInfo(oldInfo, newInfo): editInfo(newInfo, false); - case CCreateAnim(animID, animData): - createAnim(animData, animID, false); - case CEditAnim(name, oldData, animData): - editAnim(oldData.name, animData, false); - case CDeleteAnim(animID, animData): - deleteAnim(animData.name, false); - case CChangeOffset(name, change): - changeOffset(name, change, false); - case CResetOffsets(oldOffsets): - clearOffsets(false); + case CTransform(sprite, oldInfo, newInfo): + sprite.setPosition(newInfo.x, newInfo.y); + sprite.scale.set(newInfo.scaleX, newInfo.scaleY); + sprite.skew.set(newInfo.skewX, newInfo.skewY); + sprite.angle = newInfo.angle; + cast(sprite.extra.get(exID("button")), StageElementButton).updateInfo(); } - }*/ + } /*public function editInfoWithUI() { FlxG.state.openSubState(new StageInfoScreen(stage, (_) -> { @@ -910,7 +895,6 @@ class StageEditor extends UIState { override function draw() { super.draw(); - mousePoint = FlxG.mouse.getWorldPosition(stageCamera, mousePoint); if(dot == null) { dot = new FlxSprite().loadGraphic(Paths.image("editors/stage/selectionDot"), true, 32, 32); dot.antialiasing = true; @@ -1080,6 +1064,7 @@ class StageEditor extends UIState { dotCheckSize = dot.frameWidth / 0.7/stageCamera.zoom; // basically adjust it to the zoom. + var prevMode = mouseMode; if(FlxG.mouse.justPressed) { for (i in StageEditorMouseMode.SKEW_TOP...(StageEditorMouseMode.SKEW_BOTTOM + 1)) { var cappedI1 = Math.max(i - StageEditorMouseMode.SKEW_TOP - 1, 0); @@ -1156,10 +1141,32 @@ class StageEditor extends UIState { } mouseMode = (FlxG.mouse.justReleased) ? NONE : mouseMode; + + if (prevMode == NONE && mouseMode == NONE) return; + + if (prevMode != NONE && mouseMode == NONE) { + undos.addToUndo(CTransform(sprite, { + x: storedPos.x, + y: storedPos.y, + scaleX: storedScale.x, + scaleY: storedScale.y, + skewX: storedSkew.x, + skewY: storedSkew.y, + angle: storedAngle + }, { + x: sprite.x, + y: sprite.y, + scaleX: sprite.scale.x, + scaleY: sprite.scale.y, + skewX: sprite.skew.x, + skewY: sprite.skew.y, + angle: sprite.angle + })); + } + if(mouseMode == NONE) return; + var relative = clickPoint.subtractNew(mousePoint); - // todo: make this origin based - //relative.rotateByDegrees(sprite.angle); call(mouseMode.toString(), [sprite, relative]); cast(sprite.extra.get(exID("button")), StageElementButton).updateInfo(); relative.put(); @@ -1230,8 +1237,19 @@ class StageEditor extends UIState { var line:FlxSprite = null; } +typedef StageSprInfo = { + x:Float, + y:Float, + scaleX:Float, + scaleY:Float, + skewX:Float, + skewY:Float, // i dont wanna be cloning a bunch of FlxPoints. Theres a pool for a reason. + angle:Float +} + enum StageChange { CEditInfo(oldInfo:Xml, newInfo:Xml); + CTransform(sprite:FunkinSprite, oldInfo:StageSprInfo, newInfo:StageSprInfo); } @:forward abstract Selection(Array<FunkinSprite>) from Array<FunkinSprite> to Array<FunkinSprite> { From be63e260e25ec0b57a21f52f886b585bbc97c2b0 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:38:06 +0200 Subject: [PATCH 85/89] Made mac custom cursors more optimized --- source/external/src/mac/Mac.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/external/src/mac/Mac.mm b/source/external/src/mac/Mac.mm index f49fa2a3..de4c62f8 100644 --- a/source/external/src/mac/Mac.mm +++ b/source/external/src/mac/Mac.mm @@ -117,10 +117,12 @@ namespace ExternalMac { cursor = [[NSCursor alloc] initWithImage:tmpImage hotSpot:NSMakePoint(customX, customY)]; customCursorCache[customCursor] = cursor; - // [tmpImage release]; + [tmpImage release]; } else NSLog(@"Failed to load image %@", cursorImageName); + + [cursorImageName release]; } break; From a04d93b7c3196d7a03c6beb0511bbe3f4e8c6731 Mon Sep 17 00:00:00 2001 From: NeeEoo <NeeEoo@users.noreply.github.com> Date: Wed, 24 Apr 2024 03:15:22 +0200 Subject: [PATCH 86/89] Small Cleanup --- source/funkin/backend/assets/Paths.hx | 5 ++--- source/funkin/backend/chart/EventsData.hx | 2 +- source/funkin/backend/utils/CoolUtil.hx | 10 ++++++++++ source/funkin/game/Character.hx | 2 +- source/funkin/game/PlayState.hx | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/source/funkin/backend/assets/Paths.hx b/source/funkin/backend/assets/Paths.hx index 125d4d93..174e758e 100644 --- a/source/funkin/backend/assets/Paths.hx +++ b/source/funkin/backend/assets/Paths.hx @@ -97,13 +97,12 @@ class Paths return getPath('images/$key.$ext', library); } - inline static public function script(key:String, ?library:String, isAssetsPath:Bool = false) { + static public function script(key:String, ?library:String, isAssetsPath:Bool = false) { var scriptPath = isAssetsPath ? key : getPath(key, library); if (!OpenFlAssets.exists(scriptPath)) { var p:String; for(ex in Script.scriptExtensions) { - p = '$scriptPath.$ex'; - if (OpenFlAssets.exists(p)) { + if (OpenFlAssets.exists(p = scriptPath + '.' + ex)) { scriptPath = p; break; } diff --git a/source/funkin/backend/chart/EventsData.hx b/source/funkin/backend/chart/EventsData.hx index e801f18f..9527c1b1 100644 --- a/source/funkin/backend/chart/EventsData.hx +++ b/source/funkin/backend/chart/EventsData.hx @@ -76,7 +76,7 @@ class EventsData { for (file in Paths.getFolderContent('data/events/', true, BOTH)) { if (Path.extension(file) != "json" && Path.extension(file) != "pack") continue; - var eventName:String = Path.withoutExtension(Path.withoutDirectory(file)); + var eventName:String = CoolUtil.getFilename(file); var fileTxt:String = Assets.getText(file); if (Path.extension(file) == "pack") { diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx index d286d347..ecfd6156 100644 --- a/source/funkin/backend/utils/CoolUtil.hx +++ b/source/funkin/backend/utils/CoolUtil.hx @@ -719,6 +719,16 @@ class CoolUtil @:noUsing public static inline function flxeaseFromString(mainEase:String, suffix:String) return Reflect.field(FlxEase, mainEase + (mainEase == "linear" ? "" : suffix)); + /* + * Returns the filename of a path, without the extension. + * @param path Path to get the filename from + * @return Filename + */ + @:noUsing public static inline function getFilename(file:String) { + var file = new haxe.io.Path(file); + return file.file; + } + public static function sortAlphabetically(array:Array<String>, ?lowercase:Bool=false) { array.sort(function(a1, a2):Int { if(lowercase) { diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx index 7639c367..1a5ad6c6 100644 --- a/source/funkin/game/Character.hx +++ b/source/funkin/game/Character.hx @@ -544,7 +544,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset public static function getList(?mods:Bool = false):Array<String> { return [ for (path in Paths.getFolderContent('data/characters/', true, mods ? MODS : BOTH)) - if (Path.extension(path) == "xml") Path.withoutDirectory(Path.withoutExtension(path)) + if (Path.extension(path) == "xml") CoolUtil.getFilename(path) ]; } } diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index a4de7511..790ce116 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -587,7 +587,7 @@ class PlayState extends MusicBeatState for (event in SONG.events) songEvents.pushOnce(event.name); for (file in Paths.getFolderContent('data/events/', true, fromMods ? MODS : BOTH)) { - var fileName:String = Path.withoutExtension(Path.withoutDirectory(file)); + var fileName:String = CoolUtil.getFilename(file); if (EventsData.eventsList.contains(fileName) && songEvents.contains(fileName)) { addScript(file); } From 9d5599a1a3c3604ed9ad027295b82a254af87ff5 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Thu, 25 Apr 2024 07:42:57 -0700 Subject: [PATCH 87/89] info undo small commit but now i gotta get to school --- .../editors/layouts/stage/stageInfoScreen.xml | 31 ++++++++++-- source/funkin/editors/stage/StageEditor.hx | 50 ++++++++++++------- 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/assets/data/editors/layouts/stage/stageInfoScreen.xml b/assets/data/editors/layouts/stage/stageInfoScreen.xml index d5e2bfaf..1a477da8 100644 --- a/assets/data/editors/layouts/stage/stageInfoScreen.xml +++ b/assets/data/editors/layouts/stage/stageInfoScreen.xml @@ -6,13 +6,26 @@ <set name="storedProps" value="[]" /> <exec> + import haxe.ds.StringMap; + var oldInfo = { + name: stage.stageName, + folder: stage.spritesParentFolder, + startCamX: stage.startCam.x, + startCamY: stage.startCam.y, + zoom: stage.defaultZoom, + attrib: new StringMap() + }; + function col(c:Int) { return MARGIN + (170 + XOFFSET) * c; } - for(prop => val in stage.extra) - if(!StringTools.startsWith(prop, "stageEditor.")) + for(prop => val in stage.extra) { + if(!StringTools.startsWith(prop, "stageEditor.")) { storedProps.push(prop); + oldInfo.attrib.set(prop, val); + } + } </exec> <title name="title" x="MARGIN" y="30 + 16" text="Stage Info" /> @@ -78,8 +91,20 @@ for(prop in storedProps) stage.extra.remove(prop); - for(prop in attributesList.buttons.members) + var newInfo = { + name: stage.stageName, + folder: stage.spritesParentFolder, + startCamX: stage.startCam.x, + startCamY: stage.startCam.y, + zoom: stage.defaultZoom, + attrib: new StringMap() + }; + for(prop in attributesList.buttons.members) { stage.extra.set(prop.propertyText.label.text, prop.valueText.label.text); + newInfo.attrib.set(prop.propertyText.label.text, prop.valueText.label.text); + } + + FlxG.state.undos.addToUndo(CEditInfo(oldInfo, newInfo)); } </exec> </window> \ No newline at end of file diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 2416f6ed..54aa3f0e 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -123,7 +123,8 @@ class StageEditor extends UIState { "hasCloseButton" => true, "stage" => stage, "Stage" => Stage, - "exID" => exID + "exID" => exID, + "CEditInfo" => StageChange.CEditInfo ] )); }, @@ -729,7 +730,16 @@ class StageEditor extends UIState { case null: // do nothing case CEditInfo(oldInfo, newInfo): - //editInfo(oldInfo, false); + stage.startCam.x = oldInfo.startCamX; + stage.startCam.y = oldInfo.startCamY; + stage.defaultZoom = oldInfo.zoom; + stage.stageName = oldInfo.name; + stage.spritesParentFolder = oldInfo.folder; + + for (attrib in newInfo.attrib.keys()) + stage.extra.remove(attrib); + for (attrib => val in oldInfo.attrib) + stage.extra.set(attrib, val); case CTransform(sprite, oldInfo, newInfo): sprite.setPosition(oldInfo.x, oldInfo.y); sprite.scale.set(oldInfo.scaleX, oldInfo.scaleY); @@ -745,7 +755,16 @@ class StageEditor extends UIState { case null: // do nothing case CEditInfo(oldInfo, newInfo): - editInfo(newInfo, false); + stage.startCam.x = newInfo.startCamX; + stage.startCam.y = newInfo.startCamY; + stage.defaultZoom = newInfo.zoom; + stage.stageName = newInfo.name; + stage.spritesParentFolder = newInfo.folder; + + for (attrib in oldInfo.attrib.keys()) + stage.extra.remove(attrib); + for (attrib => val in newInfo.attrib) + stage.extra.set(attrib, val); case CTransform(sprite, oldInfo, newInfo): sprite.setPosition(newInfo.x, newInfo.y); sprite.scale.set(newInfo.scaleX, newInfo.scaleY); @@ -755,20 +774,6 @@ class StageEditor extends UIState { } } - /*public function editInfoWithUI() { - FlxG.state.openSubState(new StageInfoScreen(stage, (_) -> { - if (_ != null) editInfo(_); - })); - }*/ - - public function editInfo(newInfo:Xml, addtoUndo:Bool = true) { - /*var oldInfo = stage.buildXML(); - stage.applyXML(new Access(newInfo)); - - if (addtoUndo) - undos.addToUndo(CEditInfo(oldInfo, newInfo));*/ - } - public function selectSprite(_sprite:FunkinSprite) { if(!UIUtil.getKeyState(CONTROL, PRESSED)) _select_deselect(null, false); @@ -1237,6 +1242,15 @@ class StageEditor extends UIState { var line:FlxSprite = null; } +typedef StageInfo = { + name:String, + folder:String, + startCamX:Float, + startCamY:Float, + zoom:Float, + attrib:Map<String, String> +}; + typedef StageSprInfo = { x:Float, y:Float, @@ -1248,7 +1262,7 @@ typedef StageSprInfo = { } enum StageChange { - CEditInfo(oldInfo:Xml, newInfo:Xml); + CEditInfo(oldInfo:StageInfo, newInfo:StageInfo); CTransform(sprite:FunkinSprite, oldInfo:StageSprInfo, newInfo:StageSprInfo); } From ca7902141317365d5f1a2e1ea16446d0fd1c17d6 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Fri, 26 Apr 2024 07:17:40 -0700 Subject: [PATCH 88/89] fix other skews --- assets/data/states/StageEditor.hx | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index b0644601..e5b2be4a 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -224,7 +224,23 @@ function SCALE_BOTTOM(sprite, relative) { var lastRelative = FlxPoint.get(); -function SKEW_LEFT(sprite, relative) {} +function SKEW_LEFT(sprite, relative) { + preRotBullshit(sprite, relative); + if (!FlxG.keys.pressed.SHIFT) + genericOppositeScale(sprite, relative, true, false, true, false); + + var topLeft = sprite.extra.get(exID("buttonBoxes"))[0]; + var topRight = sprite.extra.get(exID("buttonBoxes"))[1]; + + sprite.y = storedPos.y - relative.y * 0.5; + sprite.skew.y = Math.atan2( + topRight.y - (topLeft.y + (lastRelative.y - relative.y)), + topRight.x - (topLeft.x + (FlxG.keys.pressed.SHIFT ? 0 : relative.x - lastRelative.x)) + ) * FlxAngle.TO_DEG; + + lastRelative.set((FlxG.keys.pressed.SHIFT ? lastRelative.x : relative.x), relative.y); + postRotBullshit(sprite, relative); +} function SKEW_BOTTOM(sprite, relative) { preRotBullshit(sprite, relative); @@ -234,8 +250,9 @@ function SKEW_BOTTOM(sprite, relative) { var topLeft = sprite.extra.get(exID("buttonBoxes"))[0]; var bottomLeft = sprite.extra.get(exID("buttonBoxes"))[2]; + sprite.x = storedPos.x - relative.x * 0.5; sprite.skew.x = Math.atan2( - topLeft.x - (bottomLeft.x + (lastRelative.x - relative.x) * 2), + topLeft.x - (bottomLeft.x + (lastRelative.x - relative.x)), topLeft.y - (bottomLeft.y + (FlxG.keys.pressed.SHIFT ? 0 : lastRelative.y - relative.y)) ) * FlxAngle.TO_DEG; @@ -251,8 +268,9 @@ function SKEW_TOP(sprite, relative) { var topLeft = sprite.extra.get(exID("buttonBoxes"))[0]; var bottomLeft = sprite.extra.get(exID("buttonBoxes"))[2]; + sprite.x = storedPos.x - relative.x * 0.5; sprite.skew.x = Math.atan2( - bottomLeft.x - (topLeft.x + (lastRelative.x - relative.x) * 2), + bottomLeft.x - (topLeft.x + (lastRelative.x - relative.x)), bottomLeft.y - (topLeft.y + (FlxG.keys.pressed.SHIFT ? 0 : relative.y - lastRelative.y)) ) * FlxAngle.TO_DEG; @@ -268,9 +286,10 @@ function SKEW_RIGHT(sprite, relative) { var topLeft = sprite.extra.get(exID("buttonBoxes"))[0]; var topRight = sprite.extra.get(exID("buttonBoxes"))[1]; + sprite.y = storedPos.y - relative.y * 0.5; sprite.skew.y = Math.atan2( - topLeft.x - (topRight.x + (FlxG.keys.pressed.SHIFT ? 0 : relative.x - lastRelative.x)), - topLeft.y - (topRight.y + (lastRelative.y - relative.y) * 2) + topLeft.y - (topRight.y + (lastRelative.y - relative.y)), + topLeft.x - (topRight.x + (FlxG.keys.pressed.SHIFT ? 0 : lastRelative.x - relative.x)) ) * FlxAngle.TO_DEG; lastRelative.set((FlxG.keys.pressed.SHIFT ? lastRelative.x : relative.x), relative.y); From c0bb9dd84007df1ad8884c2986797171df26cf19 Mon Sep 17 00:00:00 2001 From: SrtHero278 <srtpro278@gmail.com> Date: Fri, 26 Apr 2024 22:13:48 -0700 Subject: [PATCH 89/89] rotate corner idk if i should show the dot or not --- assets/data/states/StageEditor.hx | 8 +------- source/funkin/editors/stage/StageEditor.hx | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/assets/data/states/StageEditor.hx b/assets/data/states/StageEditor.hx index e5b2be4a..f56533db 100644 --- a/assets/data/states/StageEditor.hx +++ b/assets/data/states/StageEditor.hx @@ -296,9 +296,6 @@ function SKEW_RIGHT(sprite, relative) { postRotBullshit(sprite, relative); } -/*var storedCenter = FlxPoint.get(); -var storedRelative = FlxPoint.get();*/ - function ROTATE(sprite, relative) { var buttonBoxes:Array<FlxPoint> = sprite.extra.get(exID("buttonBoxes")); var p:FlxPoint = buttonBoxes[8]; @@ -307,12 +304,9 @@ function ROTATE(sprite, relative) { var dx:Float = _point.x - p.x; var dy:Float = _point.y - p.y; - var angle = FlxAngle.angleFromOrigin(dx, dy, true) + 90; + var angle = FlxAngle.angleFromOrigin(dx, dy, true) + angleOffset; if(FlxG.keys.pressed.SHIFT) angle = Std.int(angle / 45) * 45; sprite.angle = angle; - - //storedCenter.set(p.x, p.y); - //storedRelative.set(_point.x, _point.y); } diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx index 54aa3f0e..51f20731 100644 --- a/source/funkin/editors/stage/StageEditor.hx +++ b/source/funkin/editors/stage/StageEditor.hx @@ -53,6 +53,7 @@ class StageEditor extends UIState { public var storedScale:FlxPoint = new FlxPoint(); public var storedSkew:FlxPoint = new FlxPoint(); public var storedAngle:Float = 0; + public var angleOffset:Float = 0; public var showCharacters:Bool = true; @@ -1002,6 +1003,7 @@ class StageEditor extends UIState { sprite.updateHitbox(); sprite.offset.copyFrom(oldOffset); sprite.origin.copyFrom(oldOrigin); + @:privateAccess sprite.updateTrig(); var corners = sprite.getMatrixPosition([ // corners @@ -1017,8 +1019,13 @@ class StageEditor extends UIState { // center FlxPoint.get(0.5, 0.5), //FlxPoint.get(0.5, -100/sprite.frameHeight) // angle - FlxPoint.get(0.5, -0.5) // angle + FlxPoint.get(0.5, -0.5), // angle + FlxPoint.get(1, 0) // rotate corner ], sprite.camera, sprite.frameWidth, sprite.frameHeight); + @:privateAccess corners[corners.length - 1].add( + dotCheckSize * 0.35 * sprite._cosAngle + dotCheckSize * 0.35 * sprite._sinAngle, + -dotCheckSize * 0.35 * sprite._cosAngle + dotCheckSize * 0.35 * sprite._sinAngle + ); //Logs.trace("Guide at " + corners[0].x + ", " + corners[0].y + " sprite at " + sprite.x + ", " + sprite.y); @@ -1057,6 +1064,7 @@ class StageEditor extends UIState { CENTER_CIRCLE, //FlxPoint.get(0.5, -0.5) ROTATE_CIRCLE, //FlxPoint.get(0.5, -0.5) + ROTATE_CORNER ]; function tryUpdateHitbox(sprite:FunkinSprite) { @@ -1098,7 +1106,12 @@ class StageEditor extends UIState { case BOTTOM_MIDDLE: SCALE_BOTTOM; case BOTTOM_RIGHT: SCALE_BOTTOM_RIGHT; case CENTER_CIRCLE: MOVE_CENTER; - case ROTATE_CIRCLE: ROTATE; + case ROTATE_CIRCLE: + angleOffset = 90; + ROTATE; + case ROTATE_CORNER: + angleOffset = Math.atan(sprite.height / sprite.width) * FlxAngle.TO_DEG; + ROTATE; default: NONE; } Logs.trace("Clicked Dot: " + mouseMode.toString()); @@ -1138,7 +1151,7 @@ class StageEditor extends UIState { //case TOP_RIGHT | BOTTOM_LEFT: MouseCursor.RESIZE_NESW; //case MIDDLE_LEFT | MIDDLE_RIGHT: MouseCursor.RESIZE_WE; - case ROTATE_CIRCLE: FlxG.mouse.pressed ? DRAG : #if mac DRAG_OPEN #else CLICK #end; + case ROTATE_CIRCLE | ROTATE_CORNER: FlxG.mouse.pressed ? DRAG : #if mac DRAG_OPEN #else CLICK #end; default: ARROW; } break; @@ -1338,6 +1351,7 @@ enum abstract StageEditorEdge(Int) { var CENTER_CIRCLE; var ROTATE_CIRCLE; + var ROTATE_CORNER; public function toString():String { return switch(cast this) { @@ -1353,6 +1367,7 @@ enum abstract StageEditorEdge(Int) { case BOTTOM_RIGHT: "BOTTOM_RIGHT"; case CENTER_CIRCLE: "CENTER_CIRCLE"; case ROTATE_CIRCLE: "ROTATE_CIRCLE"; + case ROTATE_CORNER: "ROTATE_CORNER"; } } @@ -1370,6 +1385,7 @@ enum abstract StageEditorEdge(Int) { case BOTTOM_RIGHT: 7; case CENTER_CIRCLE: 8; case ROTATE_CIRCLE: 9; + case ROTATE_CORNER: 10; } } }