1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-09-11 20:57:20 +00:00

Merge pull request #129 from FunkinCrew/feature/chart-editor-note-graph

Chart Editor: Note Preview Graph
This commit is contained in:
Cameron Taylor 2023-08-16 04:14:12 -04:00 committed by GitHub
commit ab34bbdcee
3 changed files with 169 additions and 13 deletions

View file

@ -16,10 +16,10 @@ class ChartEditorNotePreview extends FlxSprite
// Constants
//
static final NOTE_WIDTH:Int = 5;
static final NOTE_HEIGHT:Int = 1;
static final WIDTH:Int = NOTE_WIDTH * 9;
static final NOTE_HEIGHT:Int = 1;
static final BG_COLOR:FlxColor = FlxColor.GRAY;
static final BG_COLOR:FlxColor = 0xFF606060;
static final LEFT_COLOR:FlxColor = 0xFFFF22AA;
static final DOWN_COLOR:FlxColor = 0xFF00EEFF;
static final UP_COLOR:FlxColor = 0xFF00CC00;

View file

@ -1,5 +1,6 @@
package funkin.ui.debug.charting;
import flixel.math.FlxMath;
import haxe.ui.components.TextField;
import haxe.ui.components.DropDown;
import haxe.ui.components.NumberStepper;
@ -416,6 +417,7 @@ class ChartEditorState extends HaxeUIState
// Make sure view is updated when we change view modes.
noteDisplayDirty = true;
notePreviewDirty = true;
notePreviewViewportBoundsDirty = true;
this.scrollPositionInPixels = this.scrollPositionInPixels;
return isViewDownscroll;
@ -482,6 +484,7 @@ class ChartEditorState extends HaxeUIState
// Make sure view is updated when the variation changes.
noteDisplayDirty = true;
notePreviewDirty = true;
notePreviewViewportBoundsDirty = true;
return selectedVariation;
}
@ -498,6 +501,7 @@ class ChartEditorState extends HaxeUIState
// Make sure view is updated when the difficulty changes.
noteDisplayDirty = true;
notePreviewDirty = true;
notePreviewViewportBoundsDirty = true;
return selectedDifficulty;
}
@ -514,6 +518,7 @@ class ChartEditorState extends HaxeUIState
// Make sure view is updated when the character changes.
noteDisplayDirty = true;
notePreviewDirty = true;
notePreviewViewportBoundsDirty = true;
return selectedCharacter;
}
@ -531,6 +536,7 @@ class ChartEditorState extends HaxeUIState
// Make sure view is updated when we change modes.
noteDisplayDirty = true;
notePreviewDirty = true;
notePreviewViewportBoundsDirty = true;
this.scrollPositionInPixels = 0;
return isInPatternMode;
@ -550,6 +556,8 @@ class ChartEditorState extends HaxeUIState
*/
var notePreviewDirty:Bool = true;
var notePreviewViewportBoundsDirty:Bool = true;
/**
* Whether the chart has been modified since it was last saved.
* Used to determine whether to auto-save, etc.
@ -673,6 +681,12 @@ class ChartEditorState extends HaxeUIState
*/
var gridPlayheadScrollAreaPressed:Bool = false;
/**
* Where the user's last mouse click was on the note preview scroll area.
* `null` if the user isn't clicking on the note preview.
*/
var notePreviewScrollAreaStartPos:FlxPoint = null;
/**
* The SongNoteData which is currently being placed.
* As the user drags, we will update this note's sustain length.
@ -1030,6 +1044,12 @@ class ChartEditorState extends HaxeUIState
*/
var selectionSquareBitmap:BitmapData = null;
/**
* The IMAGE used for the note preview bitmap. Updated by ChartEditorThemeHandler.
* The image is split and used for a 9-slice sprite for the box over the note preview.
*/
var notePreviewViewportBitmap:BitmapData = null;
/**
* The tiled sprite used to display the grid.
* The height is the length of the song, and scrolling is done by simply the sprite.
@ -1065,6 +1085,12 @@ class ChartEditorState extends HaxeUIState
*/
var notePreview:ChartEditorNotePreview;
/**
* The rectangular sprite used for representing the current viewport on the note preview.
* We move this up and down and resize it to represent the visible area.
*/
var notePreviewViewport:FlxSliceSprite;
/**
* The rectangular sprite used for rendering the selection box.
* Uses a 9-slice to stretch the selection box to the correct size without warping.
@ -1280,10 +1306,70 @@ class ChartEditorState extends HaxeUIState
function buildNotePreview():Void
{
var height:Int = FlxG.height - MENU_BAR_HEIGHT - GRID_TOP_PAD - 200;
var height:Int = FlxG.height - MENU_BAR_HEIGHT - GRID_TOP_PAD - PLAYBAR_HEIGHT - GRID_TOP_PAD - GRID_TOP_PAD;
notePreview = new ChartEditorNotePreview(height);
notePreview.x = 350;
notePreview.y = MENU_BAR_HEIGHT + GRID_TOP_PAD;
// add(notePreview);
add(notePreview);
notePreviewViewport.scrollFactor.set(0, 0);
add(notePreviewViewport);
notePreviewViewport.zIndex = 30;
setNotePreviewViewportBounds(calculateNotePreviewViewportBounds());
}
function calculateNotePreviewViewportBounds():FlxRect
{
var bounds:FlxRect = new FlxRect();
// Horizontal position and width are constant.
bounds.x = notePreview.x;
bounds.width = notePreview.width;
// Vertical position depends on scroll position.
bounds.y = notePreview.y + (notePreview.height * (scrollPositionInPixels / songLengthInPixels));
// Height depends on the viewport size.
bounds.height = notePreview.height * (FlxG.height / songLengthInPixels);
// Make sure the viewport doesn't go off the top or bottom of the note preview.
if (bounds.y < notePreview.y)
{
bounds.height -= notePreview.y - bounds.y;
bounds.y = notePreview.y;
}
else if (bounds.y + bounds.height > notePreview.y + notePreview.height)
{
bounds.height -= (bounds.y + bounds.height) - (notePreview.y + notePreview.height);
}
var MIN_HEIGHT:Int = 8;
if (bounds.height < MIN_HEIGHT)
{
bounds.y -= MIN_HEIGHT - bounds.height;
bounds.height = MIN_HEIGHT;
}
return bounds;
}
function setNotePreviewViewportBounds(bounds:FlxRect = null):Void
{
if (bounds == null)
{
notePreviewViewport.visible = false;
notePreviewViewport.x = -9999;
notePreviewViewport.y = -9999;
}
else
{
notePreviewViewport.visible = true;
notePreviewViewport.x = bounds.x;
notePreviewViewport.y = bounds.y;
notePreviewViewport.width = bounds.width;
notePreviewViewport.height = bounds.height;
}
}
function buildSpectrogram(target:FlxSound):Void
@ -1622,7 +1708,7 @@ class ChartEditorState extends HaxeUIState
handleToolboxes();
handlePlaybar();
handlePlayhead();
// handleNotePreview();
handleNotePreview();
handleFileKeybinds();
handleEditKeybinds();
@ -1907,6 +1993,11 @@ class ChartEditorState extends HaxeUIState
{
gridPlayheadScrollAreaPressed = true;
}
else if (FlxG.mouse.overlaps(notePreview))
{
// Clicked note preview
notePreviewScrollAreaStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
}
else if (!overlapsGrid || overlapsSelectionBorder)
{
selectionBoxStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
@ -1924,6 +2015,10 @@ class ChartEditorState extends HaxeUIState
{
Cursor.cursorMode = Grabbing;
}
else if (notePreviewScrollAreaStartPos != null)
{
Cursor.cursorMode = Pointer;
}
else if (FlxG.mouse.overlaps(gridPlayheadScrollArea))
{
Cursor.cursorMode = Pointer;
@ -1938,6 +2033,11 @@ class ChartEditorState extends HaxeUIState
gridPlayheadScrollAreaPressed = false;
}
if (notePreviewScrollAreaStartPos != null && FlxG.mouse.released)
{
notePreviewScrollAreaStartPos = null;
}
if (gridPlayheadScrollAreaPressed)
{
// Clicked on the playhead scroll area.
@ -2185,6 +2285,14 @@ class ChartEditorState extends HaxeUIState
}
}
}
else if (notePreviewScrollAreaStartPos != null)
{
trace('Updating current song time while clicking and holding...');
var clickedPosInPixels:Float = FlxMath.remapToRange(FlxG.mouse.screenY, notePreview.y, notePreview.y + notePreview.height, 0, songLengthInPixels);
scrollPositionInPixels = clickedPosInPixels;
moveSongToScrollPosition();
}
else if (currentPlaceNoteData != null)
{
// Handle extending the note as you drag.
@ -3214,7 +3322,6 @@ class ChartEditorState extends HaxeUIState
*/
function handleNotePreview():Void
{
// TODO: Finish this.
if (notePreviewDirty)
{
notePreviewDirty = false;
@ -3224,13 +3331,12 @@ class ChartEditorState extends HaxeUIState
notePreview.addNotes(currentSongChartNoteData, Std.int(songLengthInMs));
notePreview.addEvents(currentSongChartEventData, Std.int(songLengthInMs));
}
}
/**
* Perform a spot update on the note preview, by editing the note preview
* only where necessary. More efficient than a full update.
*/
function updateNotePreview(note:SongNoteData, ?deleteNote:Bool = false):Void {}
if (notePreviewViewportBoundsDirty)
{
setNotePreviewViewportBounds(calculateNotePreviewViewportBounds());
}
}
/**
* Handles passive behavior of the menu bar, such as updating labels or enabled/disabled status.
@ -3336,6 +3442,9 @@ class ChartEditorState extends HaxeUIState
// We need to update the note sprites.
noteDisplayDirty = true;
// Update the note preview viewport box.
setNotePreviewViewportBounds(calculateNotePreviewViewportBounds());
}
}
@ -3500,6 +3609,8 @@ class ChartEditorState extends HaxeUIState
// Offset the selection box start position, if we are dragging.
if (selectionBoxStartPos != null) selectionBoxStartPos.y -= diff;
// Update the note preview viewport box.
setNotePreviewViewportBounds(calculateNotePreviewViewportBounds());
return this.scrollPositionInPixels;
}
@ -3759,6 +3870,9 @@ class ChartEditorState extends HaxeUIState
loadSong(songMetadata, songChartData);
notePreviewDirty = true;
notePreviewViewportBoundsDirty = true;
if (audioInstTrack != null)
{
audioInstTrack.stop();

View file

@ -64,6 +64,14 @@ class ChartEditorThemeHandler
static final PLAYHEAD_BLOCK_BORDER_COLOR:FlxColor = 0xFF9D0011;
static final PLAYHEAD_BLOCK_FILL_COLOR:FlxColor = 0xFFBD0231;
// Border on the square over the note preview.
static final NOTE_PREVIEW_VIEWPORT_BORDER_COLOR_LIGHT = 0xFFF8A657;
static final NOTE_PREVIEW_VIEWPORT_BORDER_COLOR_DARK = 0xFFF8A657;
// Fill on the square over the note preview.
static final NOTE_PREVIEW_VIEWPORT_FILL_COLOR_LIGHT = 0x80F8A657;
static final NOTE_PREVIEW_VIEWPORT_FILL_COLOR_DARK = 0x80F8A657;
static final TOTAL_COLUMN_COUNT:Int = ChartEditorState.STRUMLINE_SIZE * 2 + 1;
/**
@ -75,6 +83,7 @@ class ChartEditorThemeHandler
updateBackground(state);
updateGridBitmap(state);
updateSelectionSquare(state);
updateNotePreview(state);
}
/**
@ -116,7 +125,7 @@ class ChartEditorThemeHandler
// 2 * (Strumline Size) + 1 grid squares wide, by (4 * quarter notes per measure) grid squares tall.
// This gets reused to fill the screen.
var gridWidth:Int = Std.int(ChartEditorState.GRID_SIZE * TOTAL_COLUMN_COUNT);
var gridHeight:Int = Std.int(ChartEditorState.GRID_SIZE * Conductor.stepsPerMeasure);
var gridHeight:Int = Std.int(ChartEditorState.GRID_SIZE * Conductor.stepsPerMeasure * state.currentZoomLevel);
state.gridBitmap = FlxGridOverlay.createGrid(ChartEditorState.GRID_SIZE, ChartEditorState.GRID_SIZE, gridWidth, gridHeight, true, gridColor1, gridColor2);
// Selection borders
@ -234,6 +243,39 @@ class ChartEditorThemeHandler
32, 32);
}
static function updateNotePreview(state:ChartEditorState):Void
{
var viewportBorderColor:FlxColor = switch (state.currentTheme)
{
case Light: NOTE_PREVIEW_VIEWPORT_BORDER_COLOR_LIGHT;
case Dark: NOTE_PREVIEW_VIEWPORT_BORDER_COLOR_DARK;
default: NOTE_PREVIEW_VIEWPORT_BORDER_COLOR_LIGHT;
};
var viewportFillColor:FlxColor = switch (state.currentTheme)
{
case Light: NOTE_PREVIEW_VIEWPORT_FILL_COLOR_LIGHT;
case Dark: NOTE_PREVIEW_VIEWPORT_FILL_COLOR_DARK;
default: NOTE_PREVIEW_VIEWPORT_FILL_COLOR_LIGHT;
};
state.notePreviewViewportBitmap = new BitmapData(ChartEditorState.GRID_SIZE, ChartEditorState.GRID_SIZE, true);
state.notePreviewViewportBitmap.fillRect(new Rectangle(0, 0, ChartEditorState.GRID_SIZE, ChartEditorState.GRID_SIZE), viewportBorderColor);
state.notePreviewViewportBitmap.fillRect(new Rectangle(SELECTION_SQUARE_BORDER_WIDTH, SELECTION_SQUARE_BORDER_WIDTH,
ChartEditorState.GRID_SIZE - (SELECTION_SQUARE_BORDER_WIDTH * 2), ChartEditorState.GRID_SIZE - (SELECTION_SQUARE_BORDER_WIDTH * 2)),
viewportFillColor);
state.notePreviewViewport = new FlxSliceSprite(state.notePreviewViewportBitmap,
new FlxRect(SELECTION_SQUARE_BORDER_WIDTH
+ 1, SELECTION_SQUARE_BORDER_WIDTH
+ 1, ChartEditorState.GRID_SIZE
- (2 * SELECTION_SQUARE_BORDER_WIDTH + 2),
ChartEditorState.GRID_SIZE
- (2 * SELECTION_SQUARE_BORDER_WIDTH + 2)),
32, 32);
}
public static function buildPlayheadBlock():FlxSprite
{
var playheadBlock:FlxSprite = new FlxSprite();