image uploader

This commit is contained in:
lunarcleint
2025-01-14 17:37:21 -07:00
parent fdf53b3d4f
commit 117c3a2dab
8 changed files with 236 additions and 13 deletions
+53 -1
View File
@@ -1,5 +1,9 @@
package funkin.backend.utils;
import flixel.graphics.FlxGraphic;
import openfl.display.BitmapData;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.graphics.frames.FlxFramesCollection;
#if sys
import sys.FileSystem;
#end
@@ -299,7 +303,7 @@ final class CoolUtil
label++;
rSize /= 1024;
}
return Std.int(rSize) + "." + addZeros(Std.string(Std.int((rSize % 1) * 100)), 2) + sizeLabels[label];
return Std.int(rSize) + ((label <= 1) ? "" : "." + addZeros(Std.string(Std.int((rSize % 1) * 100)), 2)) + sizeLabels[label];
}
/**
@@ -1088,6 +1092,54 @@ final class CoolUtil
}
return result;
}
/**
* ! REQUIRES FULL PATH!!!
* @param path
* @return Bool
*/
public static function imageHasFrameData(path:String):String {
if (FileSystem.exists(Path.withExtension(path, "xml"))) return "xml";
if (FileSystem.exists(Path.withExtension(path, "txt"))) return "txt";
if (FileSystem.exists(Path.withExtension(path, "json"))) return "json";
return null;
}
public static function loadFramesFromData(data:String, ext:String = null):FlxFramesCollection {
var frames:FlxFramesCollection = null;
var tempBitmap:BitmapData = new BitmapData(1, 1, false);
// Worlds hackiest work around alert???
var graphic:FlxGraphic = FlxG.bitmap.add(tempBitmap);
@:privateAccess {
graphic.width = 9999999;
graphic.height = 9999999;
}
try {
switch (ext) {
case "xml": frames = FlxAtlasFrames.fromSparrow(graphic, Xml.parse(data));
case "txt": frames = FlxAtlasFrames.fromSpriteSheetPacker(graphic, data);
case "json": frames = FlxAtlasFrames.fromAseprite(graphic, data);
}
} catch (e) {trace(e);}
return frames;
}
public static function getAnimsListFromFrames(frames:FlxFramesCollection, ext:String = null):Array<String> {
if (frames == null) return null;
var animsList:Array<String> = [];
for (frame in frames.frames) {
var animName:String = ext == "txt" ? frame.name.split("_")[0] : frame.name.substr(0, frame.name.length-4);
if (!animsList.contains(animName))
animsList.push(animName);
}
return animsList;
}
}
/**
@@ -10,6 +10,7 @@ class CharacterPropertiesWindow extends UISliceSprite {
public var positionYStepper:UINumericStepper;
public var scaleStepper:UINumericStepper;
public var editCharacterButton:UIButton;
public var editSpriteButton:UIButton;
public var flipXCheckbox:UICheckbox;
public var cameraXStepper:UINumericStepper;
@@ -49,9 +50,14 @@ class CharacterPropertiesWindow extends UISliceSprite {
members.push(scaleStepper);
addLabelOn(scaleStepper, "Scale");
editCharacterButton = new UIButton(scaleStepper.x + 90 -32 + 26, scaleStepper.y, "Edit Info", editCharacterInfoUI);
editCharacterButton = new UIButton(scaleStepper.x + 90 -32 + 26, scaleStepper.y-20, "Edit Info", editCharacterInfoUI, 120, 24);
editCharacterButton.field.size -= 2;
members.push(editCharacterButton);
editSpriteButton = new UIButton(editCharacterButton.x, editCharacterButton.y+24+6, "Edit Sprite", editCharacterSpriteUI, 120, 24);
editSpriteButton.field.size -= 2;
members.push(editSpriteButton);
flipXCheckbox = new UICheckbox(scaleStepper.x+22, scaleStepper.y+32+14, "Flipped?", character.isPlayer ? !character.__baseFlipped : character.__baseFlipped);
flipXCheckbox.onChecked = (checked:Bool) -> {this.changeFlipX(checked);};
members.push(flipXCheckbox);
@@ -130,6 +136,12 @@ class CharacterPropertiesWindow extends UISliceSprite {
}));
}
public function editCharacterSpriteUI() {
CharacterEditor.instance.openSubState(new CharacterSpriteScreen(character.sprite, (sprite:String) -> {
trace(sprite);
}));
}
public function changeFlipX(newFlipX:Bool) @:privateAccess {
character.flipX = character.isPlayer ? !newFlipX : newFlipX;
character.__baseFlipped = character.flipX;
@@ -0,0 +1,65 @@
package funkin.editors.character;
import flixel.text.FlxText.FlxTextFormat;
import flixel.text.FlxText.FlxTextFormatMarkerPair;
class CharacterSpriteScreen extends UISubstateWindow {
private var imagePath:String = null;
private var onSave:String -> Void = null;
public var imageExplorer:UIFileExplorer;
public var saveButton:UIButton;
public var closeButton:UIButton;
public function new(imagePath:String, ?onSave:String->Void) {
super();
this.imagePath = imagePath;
if (onSave != null) this.onSave = onSave;
}
public override function create() {
winTitle = 'Edit character sprite';
winWidth = 360; winHeight = 183;
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;
}
super.create();
imageExplorer = new UIImageExplorer(20, windowSpr.y + 30 + 16 + 20, 320, 58, (_, _) -> {refreshWindowSize();});
add(imageExplorer);
addLabelOn(imageExplorer, "Character Image File").applyMarkup(
"Character Image File $* Required$",
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight - 20, "Save & Close", function() {
close();
}, 125);
saveButton.x -= saveButton.bWidth;
saveButton.y -= saveButton.bHeight;
closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Cancel", function() {
close();
}, 125);
closeButton.color = 0xFFFF0000;
closeButton.x -= closeButton.bWidth;
//closeButton.y -= closeButton.bHeight;
add(closeButton);
add(saveButton);
refreshWindowSize();
}
public function refreshWindowSize() {
windowSpr.bWidth = 20 + imageExplorer.bWidth + 20;
windowSpr.bHeight = 30 + 16 + 20 + imageExplorer.bHeight + 14 + saveButton.bHeight + 14;
saveButton.x = windowSpr.x + windowSpr.bWidth - 20 - saveButton.bWidth;
closeButton.x = saveButton.x - 20 - closeButton.bWidth;
closeButton.y = saveButton.y = imageExplorer.y + imageExplorer.bHeight + 14;
}
}
@@ -82,7 +82,8 @@ class SongCreationScreen extends UISubstateWindow {
var voicesUIText:UIText = null;
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Flags.SOUND_EXT, function (res) {
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Flags.SOUND_EXT, function (path, res) {
if (path == null || res == null) return;
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
instExplorer.members.push(audioPlayer);
instExplorer.uiElement = audioPlayer;
@@ -92,7 +93,8 @@ class SongCreationScreen extends UISubstateWindow {
"Inst Audio File $* Required$",
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
voicesExplorer = new UIFileExplorer(instExplorer.x + 320 + 26, instExplorer.y, null, null, Flags.SOUND_EXT, function (res) {
voicesExplorer = new UIFileExplorer(instExplorer.x + 320 + 26, instExplorer.y, null, null, Flags.SOUND_EXT, function (path, res) {
if (path == null || res == null) return;
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(voicesExplorer.x + 8, voicesExplorer.y + 8, res);
voicesExplorer.members.push(audioPlayer);
voicesExplorer.uiElement = audioPlayer;
+2
View File
@@ -7,6 +7,7 @@ class DrawAxis extends FlxObject {
public override function draw() {
super.draw();
/*
for (camera in cameras) {
var gfx:Graphics = FlxG.renderBlit ? {
FlxSpriteUtil.flashGfx.clear();
@@ -27,5 +28,6 @@ class DrawAxis extends FlxObject {
if (FlxG.renderBlit)
camera.buffer.draw(FlxSpriteUtil.flashGfxSprite);
}
*/
}
}
+11 -9
View File
@@ -11,24 +11,26 @@ class UIFileExplorer extends UISliceSprite {
public var deleteIcon:FlxSprite;
public var file:Bytes = null;
public var onFile:Bytes->Void;
public var filePath:String = null;
public var onFile:(String, Bytes)->Void;
public var uiElement:UISprite;
public var uiElement:FlxSprite;
public function new(x:Float, y:Float, ?w:Int, ?h:Int, fileType:String = "txt", ?onFile:Bytes->Void) {
public function new(x:Float, y:Float, ?w:Int, ?h:Int, fileType:String = "txt", ?onFile:(String, Bytes)->Void) {
super(x, y, (w != null ? w : 320), (h != null ? h : 58), 'editors/ui/inputbox');
if (onFile != null) this.onFile = onFile;
uploadButton = new UIButton(x + 8, y+ 8, null, function () {
var fileDialog = new FileDialog();
fileDialog.onOpen.add(function(res) {
file = cast res;
fileDialog.onSelect.add(function(path) {
filePath = path;
file = cast sys.io.File.getBytes(path);
deleteButton.visible = deleteButton.selectable = deleteIcon.visible = !(uploadButton.visible = uploadButton.selectable = false);
if (this.onFile != null) this.onFile(file);
if (this.onFile != null) this.onFile(filePath, file);
});
fileDialog.open(fileType);
fileDialog.browse(OPEN, fileType);
}, bWidth - 16, bHeight - 16);
members.push(uploadButton);
@@ -42,7 +44,7 @@ class UIFileExplorer extends UISliceSprite {
deleteIcon = new FlxSprite(deleteButton.x + ((bHeight - 16)/2) - 8, deleteButton.y + ((bHeight - 16)/2) - 8).loadGraphic(Paths.image('editors/delete-button'));
deleteIcon.antialiasing = false;
members.push(deleteIcon);
deleteButton.members.push(deleteIcon);
deleteButton.visible = deleteButton.selectable = deleteIcon.visible = false;
}
@@ -68,7 +70,7 @@ class UIFileExplorer extends UISliceSprite {
uiElement.destroy();
}
file = null;
file = null; onFile(null, null);
MemoryUtil.clearMajor();
deleteButton.visible = deleteButton.selectable = deleteIcon.visible = !(uploadButton.visible = uploadButton.selectable = true);
@@ -0,0 +1,84 @@
package funkin.editors.ui;
import flixel.text.FlxText.FlxTextFormat;
import flixel.text.FlxText.FlxTextFormatMarkerPair;
import sys.io.File;
import sys.FileSystem;
import haxe.io.Bytes;
import haxe.io.Path;
import openfl.display.BitmapData;
using StringTools;
using funkin.backend.utils.BitmapUtil;
class UIImageExplorer extends UIFileExplorer {
public function new(x:Float, y:Float, ?w:Int, ?h:Int, ?onFile:(String, Bytes)->Void) {
super(x, y, w, h, "png, jpg", function (filePath, file) {
if (filePath != null && file != null) uploadImage(filePath, file);
if (onFile != null) onFile(filePath, file);
});
deleteButton.bWidth = 26;
deleteButton.bHeight = 26;
}
public var fileText:UIText;
public function uploadImage(filePath:String, file:Bytes) {
var imagePath:Dynamic = Path.normalize(filePath);
var dataPathExt:String = CoolUtil.imageHasFrameData(imagePath);
var animationList:Array<String> = [];
if (dataPathExt != null)
animationList = CoolUtil.getAnimsListFromFrames(CoolUtil.loadFramesFromData(File.getContent(Path.withExtension(imagePath, dataPathExt)), dataPathExt), dataPathExt);
uiElement = new FlxSprite().loadGraphic(BitmapData.fromBytes(file).crop());
var imageScale:Float = 1;
if (uiElement.width < 300 || uiElement.height < 200)
imageScale = Math.max(300/uiElement.width, 200/uiElement.height);
else if (uiElement.width > 700 || uiElement.height > 500)
imageScale = Math.min(700/uiElement.width, 500/uiElement.height);
uiElement.scale.set(imageScale, imageScale);
uiElement.updateHitbox();
bWidth = Std.int(uiElement.width)+32; bHeight = Std.int(uiElement.height)+32+deleteButton.bHeight+4;
uiElement.x = x+16; uiElement.y = y+16+deleteButton.bHeight+4;
uiElement.antialiasing = true;
members.push(uiElement);
imagePath = new Path(imagePath);
fileText = new UIText(x+20, y+16, bWidth-20-deleteButton.bWidth-16, '${imagePath.file}.${imagePath.ext} (${CoolUtil.getSizeString(file.length)}, ${animationList.length} Animations Found)');
if (animationList.length <= 0) fileText.applyMarkup(
'${imagePath.file}.${imagePath.ext} (${CoolUtil.getSizeString(file.length)}, #NO Animations Found#)',
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "#")]);
members.push(fileText);
deleteButton.x = x + bWidth - deleteButton.bWidth - 16;
deleteButton.y = y + 12;
deleteIcon.x = deleteButton.x + deleteButton.bWidth/2 - 8;
deleteIcon.y = deleteButton.y + deleteButton.bHeight/2 - 8;
/*
var normalFilePath:String = Path.normalize(filePath);
var gamePath:String = Path.normalize(Sys.getCwd());
if (normalFilePath.contains(gamePath))
normalFilePath = normalFilePath.replace(gamePath, ".");
*/
}
public override function removeFile() {
bWidth = 320; bHeight = 58;
members.remove(fileText);
fileText.destroy();
super.removeFile();
}
}
+4
View File
@@ -261,6 +261,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public function drawHitbox() {
if (_matrix == null || frame == null) return;
/*
for (camera in cameras) {
var gfx:Graphics = FlxG.renderBlit ? {
FlxSpriteUtil.flashGfx.clear();
@@ -276,9 +277,11 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
if (FlxG.renderBlit)
camera.buffer.draw(FlxSpriteUtil.flashGfxSprite);
}
*/
}
public function drawCamera() {
/*
for (camera in cameras) {
var gfx:Graphics = FlxG.renderBlit ? {
FlxSpriteUtil.flashGfx.clear();
@@ -301,6 +304,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
if (FlxG.renderBlit)
camera.buffer.draw(FlxSpriteUtil.flashGfxSprite);
}
*/
}
public var singAnims = ["singLEFT", "singDOWN", "singUP", "singRIGHT"];