* Tasedit: major refactoring
This commit is contained in:
parent
872d55c4c3
commit
851dae6878
|
@ -1,4 +1,4 @@
|
||||||
#define MAXIMUM_NUMBER_OF_LOGS 64
|
#define MAXIMUM_NUMBER_OF_LOGS 256
|
||||||
|
|
||||||
#define DONT_ADD_NEWLINE 0
|
#define DONT_ADD_NEWLINE 0
|
||||||
#define DO_ADD_NEWLINE 1
|
#define DO_ADD_NEWLINE 1
|
||||||
|
|
|
@ -1355,7 +1355,7 @@ MENU TASEDITMENU
|
||||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||||
BEGIN
|
BEGIN
|
||||||
CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER,6,5,299,370
|
CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER,6,5,299,370
|
||||||
GROUPBOX "Playback",IDC_STATIC,310,5,118,62,BS_CENTER,WS_EX_RIGHT
|
GROUPBOX " Playback ",IDC_STATIC,310,5,118,62,BS_CENTER,WS_EX_RIGHT
|
||||||
PUSHBUTTON "<<",TASEDIT_REWIND_FULL,314,14,22,14,NOT WS_TABSTOP
|
PUSHBUTTON "<<",TASEDIT_REWIND_FULL,314,14,22,14,NOT WS_TABSTOP
|
||||||
PUSHBUTTON "<",TASEDIT_REWIND,336,14,22,14,NOT WS_TABSTOP
|
PUSHBUTTON "<",TASEDIT_REWIND,336,14,22,14,NOT WS_TABSTOP
|
||||||
PUSHBUTTON "||",TASEDIT_PLAYSTOP,358,14,22,14,NOT WS_TABSTOP
|
PUSHBUTTON "||",TASEDIT_PLAYSTOP,358,14,22,14,NOT WS_TABSTOP
|
||||||
|
@ -1366,9 +1366,9 @@ BEGIN
|
||||||
CONTROL " Follow cursor",CHECK_FOLLOW_CURSOR,"Button",BS_AUTOCHECKBOX,315,30,105,12
|
CONTROL " Follow cursor",CHECK_FOLLOW_CURSOR,"Button",BS_AUTOCHECKBOX,315,30,105,12
|
||||||
CONTROL " Auto-restore last position",CHECK_AUTORESTORE_PLAYBACK,
|
CONTROL " Auto-restore last position",CHECK_AUTORESTORE_PLAYBACK,
|
||||||
"Button",BS_AUTOCHECKBOX,315,53,105,12
|
"Button",BS_AUTOCHECKBOX,315,53,105,12
|
||||||
GROUPBOX "Recording",IDC_STATIC,310,68,118,48,BS_CENTER,WS_EX_RIGHT
|
GROUPBOX " Recording ",IDC_STATIC,310,68,118,48,BS_CENTER,WS_EX_RIGHT
|
||||||
GROUPBOX "Editing",IDC_STATIC,310,118,118,38,BS_CENTER,WS_EX_RIGHT
|
GROUPBOX " Editing ",IDC_STATIC,310,118,118,38,BS_CENTER,WS_EX_RIGHT
|
||||||
GROUPBOX "Bookmarks",IDC_STATIC,310,158,118,101,BS_CENTER,WS_EX_RIGHT
|
GROUPBOX " Bookmarks ",IDC_BOOKMARKS_BOX,310,158,118,101,BS_CENTER,WS_EX_RIGHT
|
||||||
CONTROL "",IDC_BOOKMARKSLIST,"SysListView32",LVS_LIST | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER,315,168,108,86
|
CONTROL "",IDC_BOOKMARKSLIST,"SysListView32",LVS_LIST | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER,315,168,108,86
|
||||||
CONTROL "",IDC_HISTORYLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOLABELWRAP | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER,315,271,108,100
|
CONTROL "",IDC_HISTORYLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOLABELWRAP | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER,315,271,108,100
|
||||||
CONTROL " OFF",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,316,78,29,10
|
CONTROL " OFF",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,316,78,29,10
|
||||||
|
@ -1379,7 +1379,7 @@ BEGIN
|
||||||
CONTROL " 4P",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,397,91,23,10
|
CONTROL " 4P",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,397,91,23,10
|
||||||
CONTROL " Superimpose",IDC_SUPERIMPOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,316,104,55,10
|
CONTROL " Superimpose",IDC_SUPERIMPOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,316,104,55,10
|
||||||
CONTROL " Omit blank",IDC_OMITBLANK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,375,104,49,10
|
CONTROL " Omit blank",IDC_OMITBLANK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,375,104,49,10
|
||||||
GROUPBOX "History",IDC_STATIC,310,261,118,114,BS_CENTER,WS_EX_RIGHT
|
GROUPBOX " History ",IDC_STATIC,310,261,118,114,BS_CENTER,WS_EX_RIGHT
|
||||||
END
|
END
|
||||||
|
|
||||||
ASSEMBLER DIALOGEX 0, 0, 202, 135
|
ASSEMBLER DIALOGEX 0, 0, 202, 135
|
||||||
|
|
|
@ -500,6 +500,7 @@
|
||||||
#define CHECK_AUTORESTORE_PLAYBACK 1261
|
#define CHECK_AUTORESTORE_PLAYBACK 1261
|
||||||
#define IDC_PROGRESS1 1262
|
#define IDC_PROGRESS1 1262
|
||||||
#define CHECK_FOLLOW_CURSOR 1263
|
#define CHECK_FOLLOW_CURSOR 1263
|
||||||
|
#define IDC_BOOKMARKS_BOX 1264
|
||||||
#define MENU_NETWORK 40040
|
#define MENU_NETWORK 40040
|
||||||
#define MENU_PALETTE 40041
|
#define MENU_PALETTE 40041
|
||||||
#define MENU_SOUND 40042
|
#define MENU_SOUND 40042
|
||||||
|
@ -869,7 +870,7 @@
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 160
|
#define _APS_NEXT_RESOURCE_VALUE 160
|
||||||
#define _APS_NEXT_COMMAND_VALUE 40473
|
#define _APS_NEXT_COMMAND_VALUE 40473
|
||||||
#define _APS_NEXT_CONTROL_VALUE 1263
|
#define _APS_NEXT_CONTROL_VALUE 1265
|
||||||
#define _APS_NEXT_SYMED_VALUE 101
|
#define _APS_NEXT_SYMED_VALUE 101
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "taseditlib/taseditproj.h"
|
#include "taseditlib/taseditproj.h"
|
||||||
//#include "taseditlib/inputhistory.h"
|
|
||||||
#include "fceu.h"
|
#include "fceu.h"
|
||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
#include "replay.h"
|
#include "replay.h"
|
||||||
|
@ -22,27 +21,14 @@ using namespace std;
|
||||||
//to change header font
|
//to change header font
|
||||||
//http://forums.devx.com/archive/index.php/t-37234.html
|
//http://forums.devx.com/archive/index.php/t-37234.html
|
||||||
|
|
||||||
bool old_project_changed;
|
|
||||||
int old_multitrack_recording_joypad, multitrack_recording_joypad;
|
int old_multitrack_recording_joypad, multitrack_recording_joypad;
|
||||||
bool old_movie_readonly;
|
bool old_movie_readonly;
|
||||||
int lastCursor;
|
|
||||||
bool old_emu_paused, emu_paused;
|
|
||||||
int old_pauseframe;
|
|
||||||
bool old_show_pauseframe, show_pauseframe;
|
|
||||||
int undo_hint_pos, old_undo_hint_pos, undo_hint_time;
|
|
||||||
bool old_show_undo_hint, show_undo_hint;
|
|
||||||
bool old_rewind_button_state, rewind_button_state;
|
|
||||||
bool old_forward_button_state, forward_button_state;
|
|
||||||
int button_hold_time;
|
|
||||||
int seeking_start_frame = 0;
|
|
||||||
bool TASEdit_focus = false;
|
bool TASEdit_focus = false;
|
||||||
int listItems; // number of items per list page
|
int listItems; // number of items per list page
|
||||||
// saved FCEU config
|
// saved FCEU config
|
||||||
int saved_eoptions;
|
int saved_eoptions;
|
||||||
int saved_EnableAutosave;
|
int saved_EnableAutosave;
|
||||||
extern int EnableAutosave;
|
extern int EnableAutosave;
|
||||||
bool saved_compressSavestates;
|
|
||||||
extern bool compressSavestates;
|
|
||||||
|
|
||||||
// vars saved in cfg file
|
// vars saved in cfg file
|
||||||
int TasEdit_wndx, TasEdit_wndy;
|
int TasEdit_wndx, TasEdit_wndy;
|
||||||
|
@ -65,13 +51,15 @@ char windowCaptions[6][30] = { "TAS Editor",
|
||||||
"TAS Editor (Recording 2P)",
|
"TAS Editor (Recording 2P)",
|
||||||
"TAS Editor (Recording 3P)",
|
"TAS Editor (Recording 3P)",
|
||||||
"TAS Editor (Recording 4P)"};
|
"TAS Editor (Recording 4P)"};
|
||||||
|
char bookmarksCaption[2][23] = { " Bookmarks ", " Bookmarks / Branches " };
|
||||||
|
|
||||||
HWND hwndTasEdit = 0;
|
HWND hwndTasEdit = 0;
|
||||||
HMENU hmenu, hrmenu;
|
HMENU hmenu, hrmenu;
|
||||||
HWND hwndList, hwndHeader;
|
HWND hwndList, hwndHeader;
|
||||||
WNDPROC hwndList_oldWndProc, hwndHeader_oldWndproc;
|
WNDPROC hwndList_oldWndProc, hwndHeader_oldWndproc;
|
||||||
HWND hwndHistoryList;
|
HWND hwndHistoryList;
|
||||||
WNDPROC hwndHistoryList_oldWndProc;
|
WNDPROC hwndHistoryList_oldWndProc;
|
||||||
HWND hwndBookmarksList;
|
HWND hwndBookmarksList, hwndBookmarks;
|
||||||
WNDPROC hwndBookmarksList_oldWndProc;
|
WNDPROC hwndBookmarksList_oldWndProc;
|
||||||
HWND hwndProgressbar, hwndRewind, hwndForward;
|
HWND hwndProgressbar, hwndRewind, hwndForward;
|
||||||
HWND hwndRB_RecOff, hwndRB_RecAll, hwndRB_Rec1P, hwndRB_Rec2P, hwndRB_Rec3P, hwndRB_Rec4P;
|
HWND hwndRB_RecOff, hwndRB_RecAll, hwndRB_Rec1P, hwndRB_Rec2P, hwndRB_Rec3P, hwndRB_Rec4P;
|
||||||
|
@ -84,9 +72,11 @@ static TSelectionFrames selectionFrames;
|
||||||
//add a new fceud_ function?? blehhh maybe
|
//add a new fceud_ function?? blehhh maybe
|
||||||
extern EMOVIEMODE movieMode;
|
extern EMOVIEMODE movieMode;
|
||||||
|
|
||||||
|
// all Taseditor functional modules
|
||||||
TASEDIT_PROJECT project;
|
TASEDIT_PROJECT project;
|
||||||
INPUT_HISTORY history;
|
INPUT_HISTORY history;
|
||||||
//GREENZONE greenzone;
|
PLAYBACK playback;
|
||||||
|
GREENZONE greenzone;
|
||||||
|
|
||||||
|
|
||||||
void GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
|
void GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
|
||||||
|
@ -164,11 +154,11 @@ LONG CustomDraw(NMLVCUSTOMDRAW* msg)
|
||||||
if(cell_x == COLUMN_FRAMENUM || cell_x == COLUMN_FRAMENUM2)
|
if(cell_x == COLUMN_FRAMENUM || cell_x == COLUMN_FRAMENUM2)
|
||||||
{
|
{
|
||||||
// frame number
|
// frame number
|
||||||
if (show_undo_hint && cell_y == undo_hint_pos)
|
if (cell_y == history.GetUndoHint())
|
||||||
{
|
{
|
||||||
// undo hint here
|
// undo hint here
|
||||||
msg->clrTextBk = UNDOHINT_FRAMENUM_COLOR;
|
msg->clrTextBk = UNDOHINT_FRAMENUM_COLOR;
|
||||||
} else if (cell_y == currFrameCounter || (cell_y == pauseframe-1 && show_pauseframe))
|
} else if (cell_y == currFrameCounter || cell_y == playback.GetPauseFrame())
|
||||||
{
|
{
|
||||||
// current frame
|
// current frame
|
||||||
if(TASEdit_show_markers && currMovieData.frames_flags[cell_y] & MARKER_FLAG_BIT)
|
if(TASEdit_show_markers && currMovieData.frames_flags[cell_y] & MARKER_FLAG_BIT)
|
||||||
|
@ -180,7 +170,7 @@ LONG CustomDraw(NMLVCUSTOMDRAW* msg)
|
||||||
{
|
{
|
||||||
// marked frame
|
// marked frame
|
||||||
msg->clrTextBk = MARKED_FRAMENUM_COLOR;
|
msg->clrTextBk = MARKED_FRAMENUM_COLOR;
|
||||||
} else if(cell_y < currMovieData.greenZoneCount && !currMovieData.savestates[cell_y].empty())
|
} else if(cell_y < greenzone.greenZoneCount && !greenzone.savestates[cell_y].empty())
|
||||||
{
|
{
|
||||||
if (TASEdit_show_lag_frames && (currMovieData.frames_flags[cell_y] & LAG_FLAG_BIT))
|
if (TASEdit_show_lag_frames && (currMovieData.frames_flags[cell_y] & LAG_FLAG_BIT))
|
||||||
{
|
{
|
||||||
|
@ -195,15 +185,15 @@ LONG CustomDraw(NMLVCUSTOMDRAW* msg)
|
||||||
} else if((cell_x - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS == 0 || (cell_x - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS == 2)
|
} else if((cell_x - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS == 0 || (cell_x - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS == 2)
|
||||||
{
|
{
|
||||||
// pad 1 or 3
|
// pad 1 or 3
|
||||||
if (show_undo_hint && cell_y == undo_hint_pos)
|
if (cell_y == history.GetUndoHint())
|
||||||
{
|
{
|
||||||
// undo hint here
|
// undo hint here
|
||||||
msg->clrTextBk = UNDOHINT_INPUT_COLOR1;
|
msg->clrTextBk = UNDOHINT_INPUT_COLOR1;
|
||||||
} else if (cell_y == currFrameCounter || (cell_y == pauseframe-1 && show_pauseframe))
|
} else if (cell_y == currFrameCounter || cell_y == playback.GetPauseFrame())
|
||||||
{
|
{
|
||||||
// current frame
|
// current frame
|
||||||
msg->clrTextBk = CUR_INPUT_COLOR1;
|
msg->clrTextBk = CUR_INPUT_COLOR1;
|
||||||
} else if(cell_y < currMovieData.greenZoneCount && !currMovieData.savestates[cell_y].empty())
|
} else if(cell_y < greenzone.greenZoneCount && !greenzone.savestates[cell_y].empty())
|
||||||
{
|
{
|
||||||
if (TASEdit_show_lag_frames && (currMovieData.frames_flags[cell_y] & LAG_FLAG_BIT))
|
if (TASEdit_show_lag_frames && (currMovieData.frames_flags[cell_y] & LAG_FLAG_BIT))
|
||||||
{
|
{
|
||||||
|
@ -218,15 +208,15 @@ LONG CustomDraw(NMLVCUSTOMDRAW* msg)
|
||||||
} else if((cell_x - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS == 1 || (cell_x - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS == 3)
|
} else if((cell_x - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS == 1 || (cell_x - COLUMN_JOYPAD1_A) / NUM_JOYPAD_BUTTONS == 3)
|
||||||
{
|
{
|
||||||
// pad 2 or 4
|
// pad 2 or 4
|
||||||
if (show_undo_hint && cell_y == undo_hint_pos)
|
if (cell_y == history.GetUndoHint())
|
||||||
{
|
{
|
||||||
// undo hint here
|
// undo hint here
|
||||||
msg->clrTextBk = UNDOHINT_INPUT_COLOR2;
|
msg->clrTextBk = UNDOHINT_INPUT_COLOR2;
|
||||||
} else if (cell_y == currFrameCounter || (cell_y == pauseframe-1 && show_pauseframe))
|
} else if (cell_y == currFrameCounter || cell_y == playback.GetPauseFrame())
|
||||||
{
|
{
|
||||||
// current frame
|
// current frame
|
||||||
msg->clrTextBk = CUR_INPUT_COLOR2;
|
msg->clrTextBk = CUR_INPUT_COLOR2;
|
||||||
} else if(cell_y < currMovieData.greenZoneCount && !currMovieData.savestates[cell_y].empty())
|
} else if(cell_y < greenzone.greenZoneCount && !greenzone.savestates[cell_y].empty())
|
||||||
{
|
{
|
||||||
if (TASEdit_show_lag_frames && (currMovieData.frames_flags[cell_y] & LAG_FLAG_BIT))
|
if (TASEdit_show_lag_frames && (currMovieData.frames_flags[cell_y] & LAG_FLAG_BIT))
|
||||||
{
|
{
|
||||||
|
@ -253,98 +243,18 @@ void UpdateTasEdit()
|
||||||
|
|
||||||
UpdateList();
|
UpdateList();
|
||||||
|
|
||||||
// pause when seeking hit pauseframe
|
greenzone.update();
|
||||||
if(!FCEUI_EmulationPaused())
|
playback.update();
|
||||||
if(pauseframe && pauseframe <= currFrameCounter + 1)
|
history.update();
|
||||||
SeekingStop();
|
|
||||||
|
|
||||||
// update seeking progressbar
|
|
||||||
old_emu_paused = emu_paused;
|
|
||||||
emu_paused = (bool)FCEUI_EmulationPaused();
|
|
||||||
if (pauseframe)
|
|
||||||
{
|
|
||||||
SendMessage(hwndProgressbar, PBM_SETPOS, PROGRESSBAR_WIDTH * (currFrameCounter-seeking_start_frame) / (pauseframe-seeking_start_frame), 0);
|
|
||||||
} else if (old_emu_paused != emu_paused)
|
|
||||||
{
|
|
||||||
// emulator got paused/unpaused externally
|
|
||||||
if (old_emu_paused && !emu_paused)
|
|
||||||
// externally unpaused - progressbar should be empty
|
|
||||||
SendMessage(hwndProgressbar, PBM_SETPOS, 0, 0);
|
|
||||||
else
|
|
||||||
// externally paused - progressbar should be full
|
|
||||||
SendMessage(hwndProgressbar, PBM_SETPOS, PROGRESSBAR_WIDTH, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update flashing pauseframe
|
|
||||||
if (old_pauseframe != pauseframe && old_pauseframe) RedrawRow(old_pauseframe-1);
|
|
||||||
old_pauseframe = pauseframe;
|
|
||||||
old_show_pauseframe = show_pauseframe;
|
|
||||||
if (pauseframe)
|
|
||||||
show_pauseframe = (int)(clock() / PAUSEFRAME_BLINKING_PERIOD) & 1;
|
|
||||||
else
|
|
||||||
show_pauseframe = false;
|
|
||||||
if (old_show_pauseframe != show_pauseframe) RedrawRow(pauseframe-1);
|
|
||||||
|
|
||||||
// update undo_hint
|
|
||||||
if (old_undo_hint_pos != undo_hint_pos && old_undo_hint_pos >= 0) RedrawRow(old_undo_hint_pos);
|
|
||||||
old_undo_hint_pos = undo_hint_pos;
|
|
||||||
old_show_undo_hint = show_undo_hint;
|
|
||||||
show_undo_hint = false;
|
|
||||||
if (undo_hint_pos >= 0)
|
|
||||||
{
|
|
||||||
if ((int)clock() < undo_hint_time)
|
|
||||||
show_undo_hint = true;
|
|
||||||
else
|
|
||||||
undo_hint_pos = -1; // finished hinting
|
|
||||||
}
|
|
||||||
if (old_show_undo_hint != show_undo_hint) RedrawRow(undo_hint_pos);
|
|
||||||
|
|
||||||
//update the playback cursor
|
|
||||||
if(currFrameCounter != lastCursor)
|
|
||||||
{
|
|
||||||
FollowPlayback();
|
|
||||||
//update the old and new rows
|
|
||||||
RedrawRow(lastCursor);
|
|
||||||
RedrawRow(currFrameCounter);
|
|
||||||
UpdateWindow(hwndList);
|
|
||||||
lastCursor = currFrameCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update < and > buttons
|
|
||||||
if(emu_paused)
|
|
||||||
{
|
|
||||||
old_rewind_button_state = rewind_button_state;
|
|
||||||
rewind_button_state = (bool)(Button_GetState(hwndRewind) & BST_PUSHED);
|
|
||||||
if (rewind_button_state)
|
|
||||||
{
|
|
||||||
if (!old_rewind_button_state)
|
|
||||||
{
|
|
||||||
button_hold_time = clock();
|
|
||||||
Tasedit_RewindFrame();
|
|
||||||
} else if (button_hold_time + HOLD_REPEAT_DELAY < clock())
|
|
||||||
{
|
|
||||||
Tasedit_RewindFrame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
old_forward_button_state = forward_button_state;
|
|
||||||
forward_button_state = (bool)(Button_GetState(hwndForward) & BST_PUSHED);
|
|
||||||
if (forward_button_state)
|
|
||||||
{
|
|
||||||
if (!old_forward_button_state)
|
|
||||||
{
|
|
||||||
button_hold_time = clock();
|
|
||||||
Tasedit_ForwardFrame();
|
|
||||||
} else if (button_hold_time + HOLD_REPEAT_DELAY < clock())
|
|
||||||
{
|
|
||||||
Tasedit_ForwardFrame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update window caption
|
// update window caption
|
||||||
if (old_movie_readonly != movie_readonly || old_multitrack_recording_joypad != multitrack_recording_joypad || old_project_changed != project.changed)
|
if (project.old_changed != project.changed || old_movie_readonly != movie_readonly || old_multitrack_recording_joypad != multitrack_recording_joypad)
|
||||||
RedrawWindowCaption();
|
RedrawWindowCaption();
|
||||||
old_project_changed = project.changed;
|
project.update();
|
||||||
|
|
||||||
|
// update Bookmarks/Branches groupbox caption
|
||||||
|
if (old_movie_readonly != movie_readonly)
|
||||||
|
RedrawBookmarksCaption();
|
||||||
|
|
||||||
// update recording radio buttons if user used hotkey to switch R/W
|
// update recording radio buttons if user used hotkey to switch R/W
|
||||||
if (old_movie_readonly != movie_readonly || old_multitrack_recording_joypad != multitrack_recording_joypad)
|
if (old_movie_readonly != movie_readonly || old_multitrack_recording_joypad != multitrack_recording_joypad)
|
||||||
|
@ -379,11 +289,6 @@ void UpdateList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateProgressbar(int a, int b)
|
|
||||||
{
|
|
||||||
SendMessage(hwndProgressbar, PBM_SETPOS, PROGRESSBAR_WIDTH * a / b, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RedrawWindowCaption()
|
void RedrawWindowCaption()
|
||||||
{
|
{
|
||||||
char windowCaption[300]; // 260 + 30 + 1 + ...
|
char windowCaption[300]; // 260 + 30 + 1 + ...
|
||||||
|
@ -403,6 +308,10 @@ void RedrawWindowCaption()
|
||||||
strcat(windowCaption, "*");
|
strcat(windowCaption, "*");
|
||||||
SetWindowText(hwndTasEdit, windowCaption);
|
SetWindowText(hwndTasEdit, windowCaption);
|
||||||
}
|
}
|
||||||
|
void RedrawBookmarksCaption()
|
||||||
|
{
|
||||||
|
SetWindowText(hwndBookmarks, bookmarksCaption[(movie_readonly)?0:1]);
|
||||||
|
}
|
||||||
void RedrawTasedit()
|
void RedrawTasedit()
|
||||||
{
|
{
|
||||||
InvalidateRect(hwndTasEdit,0,FALSE);
|
InvalidateRect(hwndTasEdit,0,FALSE);
|
||||||
|
@ -411,63 +320,11 @@ void RedrawList()
|
||||||
{
|
{
|
||||||
InvalidateRect(hwndList,0,FALSE);
|
InvalidateRect(hwndList,0,FALSE);
|
||||||
}
|
}
|
||||||
void RedrawHistoryList()
|
|
||||||
{
|
|
||||||
ListView_SetItemState(hwndHistoryList, history.GetCursorPos(), LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
|
|
||||||
ListView_EnsureVisible(hwndHistoryList, history.GetCursorPos(), FALSE);
|
|
||||||
InvalidateRect(hwndHistoryList,0,FALSE);
|
|
||||||
}
|
|
||||||
void RedrawRow(int index)
|
void RedrawRow(int index)
|
||||||
{
|
{
|
||||||
ListView_RedrawItems(hwndList,index,index);
|
ListView_RedrawItems(hwndList,index,index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tasedit_RewindFrame()
|
|
||||||
{
|
|
||||||
if (currFrameCounter > 0) JumpToFrame(currFrameCounter-1);
|
|
||||||
turbo = false;
|
|
||||||
FollowPlayback();
|
|
||||||
}
|
|
||||||
void Tasedit_ForwardFrame()
|
|
||||||
{
|
|
||||||
JumpToFrame(currFrameCounter+1);
|
|
||||||
turbo = false;
|
|
||||||
FollowPlayback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tasedit_ToggleEmulationPause()
|
|
||||||
{
|
|
||||||
if (FCEUI_EmulationPaused())
|
|
||||||
UnpauseEmulation();
|
|
||||||
else
|
|
||||||
PauseEmulation();
|
|
||||||
}
|
|
||||||
void PauseEmulation()
|
|
||||||
{
|
|
||||||
FCEUI_SetEmulationPaused(1);
|
|
||||||
// make some additional stuff
|
|
||||||
}
|
|
||||||
void UnpauseEmulation()
|
|
||||||
{
|
|
||||||
FCEUI_SetEmulationPaused(0);
|
|
||||||
// make some additional stuff
|
|
||||||
}
|
|
||||||
|
|
||||||
void SeekingStart(int finish_frame)
|
|
||||||
{
|
|
||||||
seeking_start_frame = currFrameCounter;
|
|
||||||
pauseframe = finish_frame;
|
|
||||||
turbo = true;
|
|
||||||
UnpauseEmulation();
|
|
||||||
}
|
|
||||||
void SeekingStop()
|
|
||||||
{
|
|
||||||
pauseframe = 0;
|
|
||||||
turbo = false;
|
|
||||||
PauseEmulation();
|
|
||||||
SendMessage(hwndProgressbar, PBM_SETPOS, PROGRESSBAR_WIDTH, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ECONTEXTMENU
|
enum ECONTEXTMENU
|
||||||
{
|
{
|
||||||
CONTEXTMENU_STRAY = 0,
|
CONTEXTMENU_STRAY = 0,
|
||||||
|
@ -523,80 +380,7 @@ void MarkersChanged()
|
||||||
|
|
||||||
void InputChangedRec()
|
void InputChangedRec()
|
||||||
{
|
{
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_RECORD, currFrameCounter,currFrameCounter));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_RECORD, currFrameCounter, currFrameCounter));
|
||||||
}
|
|
||||||
void InvalidateGreenZone(int after)
|
|
||||||
{
|
|
||||||
if (after < 0) return;
|
|
||||||
project.changed = true;
|
|
||||||
if (currMovieData.greenZoneCount > after+1)
|
|
||||||
{
|
|
||||||
currMovieData.greenZoneCount = after+1;
|
|
||||||
currMovieData.rerecordCount++;
|
|
||||||
// either set playback cursor to the end of greenzone or run seeking to restore playback position
|
|
||||||
if (currFrameCounter >= currMovieData.greenZoneCount)
|
|
||||||
{
|
|
||||||
if (TASEdit_restore_position)
|
|
||||||
{
|
|
||||||
if (pauseframe)
|
|
||||||
JumpToFrame(pauseframe-1);
|
|
||||||
else
|
|
||||||
JumpToFrame(currFrameCounter);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
JumpToFrame(currMovieData.greenZoneCount-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// redraw list even if greenzone didn't change
|
|
||||||
RedrawList();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JumpToFrame(int index)
|
|
||||||
{
|
|
||||||
// Returns true if a jump to the frame is made, false if nothing's done.
|
|
||||||
if (index<0) return false;
|
|
||||||
|
|
||||||
if (index >= currMovieData.greenZoneCount)
|
|
||||||
{
|
|
||||||
/* Handle jumps outside greenzone. */
|
|
||||||
if (JumpToFrame(currMovieData.greenZoneCount-1))
|
|
||||||
{
|
|
||||||
// seek from the end of greenzone
|
|
||||||
SeekingStart(index+1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/* Handle jumps inside greenzone. */
|
|
||||||
if (currMovieData.loadTasSavestate(index))
|
|
||||||
{
|
|
||||||
currFrameCounter = index;
|
|
||||||
turbo = false;
|
|
||||||
// if playback was seeking, pause emulation right here
|
|
||||||
if (pauseframe) SeekingStop();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//Search for an earlier frame with savestate
|
|
||||||
int i = (index>0)? index-1 : 0;
|
|
||||||
for (; i > 0; --i)
|
|
||||||
{
|
|
||||||
if (currMovieData.loadTasSavestate(i)) break;
|
|
||||||
}
|
|
||||||
if (!i)
|
|
||||||
StartFromZero();
|
|
||||||
else
|
|
||||||
currFrameCounter = i;
|
|
||||||
// continue from the frame
|
|
||||||
SeekingStart(index+1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartFromZero()
|
|
||||||
{
|
|
||||||
poweron(true);
|
|
||||||
currFrameCounter = 0;
|
|
||||||
currMovieData.TryDumpIncremental();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags)
|
void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags)
|
||||||
|
@ -610,15 +394,15 @@ void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags)
|
||||||
{
|
{
|
||||||
currMovieData.records[*it].toggleBit(joy,bit);
|
currMovieData.records[*it].toggleBit(joy,bit);
|
||||||
}
|
}
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CHANGE, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CHANGE, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
//update one row
|
//update one row
|
||||||
currMovieData.records[row_index].toggleBit(joy,bit);
|
currMovieData.records[row_index].toggleBit(joy,bit);
|
||||||
if (currMovieData.records[row_index].checkBit(joy,bit))
|
if (currMovieData.records[row_index].checkBit(joy,bit))
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_SET, row_index, row_index));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_SET, row_index, row_index));
|
||||||
else
|
else
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_UNSET, row_index, row_index));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_UNSET, row_index, row_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -633,7 +417,7 @@ void SingleClick(LPNMITEMACTIVATE info)
|
||||||
{
|
{
|
||||||
// click on the "icons" column - jump to the frame
|
// click on the "icons" column - jump to the frame
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
JumpToFrame(row_index);
|
playback.JumpToFrame(row_index);
|
||||||
RedrawList();
|
RedrawList();
|
||||||
} else if(column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2)
|
} else if(column_index == COLUMN_FRAMENUM || column_index == COLUMN_FRAMENUM2)
|
||||||
{
|
{
|
||||||
|
@ -666,7 +450,7 @@ void DoubleClick(LPNMITEMACTIVATE info)
|
||||||
{
|
{
|
||||||
// double click sends playback to the frame
|
// double click sends playback to the frame
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
JumpToFrame(row_index);
|
playback.JumpToFrame(row_index);
|
||||||
RedrawList();
|
RedrawList();
|
||||||
} else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
|
} else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
|
||||||
{
|
{
|
||||||
|
@ -696,7 +480,7 @@ void CloneFrames()
|
||||||
} else frames++;
|
} else frames++;
|
||||||
}
|
}
|
||||||
UpdateList();
|
UpdateList();
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CLONE, *selectionFrames.begin()));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CLONE, *selectionFrames.begin()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void InsertFrames()
|
void InsertFrames()
|
||||||
|
@ -724,7 +508,7 @@ void InsertFrames()
|
||||||
} else frames++;
|
} else frames++;
|
||||||
}
|
}
|
||||||
UpdateList();
|
UpdateList();
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, *selectionFrames.begin()));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, *selectionFrames.begin()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteFrames()
|
void DeleteFrames()
|
||||||
|
@ -740,11 +524,11 @@ void DeleteFrames()
|
||||||
}
|
}
|
||||||
// check if user deleted all frames
|
// check if user deleted all frames
|
||||||
if (!currMovieData.getNumRecords())
|
if (!currMovieData.getNumRecords())
|
||||||
StartFromZero();
|
playback.StartFromZero();
|
||||||
// reduce list
|
// reduce list
|
||||||
UpdateList();
|
UpdateList();
|
||||||
|
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_DELETE, start_index, end_index));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_DELETE, start_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearFrames(bool cut)
|
void ClearFrames(bool cut)
|
||||||
|
@ -755,9 +539,25 @@ void ClearFrames(bool cut)
|
||||||
currMovieData.records[*it].clear();
|
currMovieData.records[*it].clear();
|
||||||
}
|
}
|
||||||
if (cut)
|
if (cut)
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CUT, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CUT, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||||
else
|
else
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CLEAR, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CLEAR, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Truncate()
|
||||||
|
{
|
||||||
|
int frame = currFrameCounter;
|
||||||
|
if (selectionFrames.size())
|
||||||
|
{
|
||||||
|
frame=*selectionFrames.begin();
|
||||||
|
ClearSelection();
|
||||||
|
}
|
||||||
|
if (currMovieData.getNumRecords() > frame+1)
|
||||||
|
{
|
||||||
|
currMovieData.truncateAt(frame+1);
|
||||||
|
UpdateList();
|
||||||
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_TRUNCATE, frame+1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//the column set operation, for setting a button/Marker for a span of selected values
|
//the column set operation, for setting a button/Marker for a span of selected values
|
||||||
|
@ -810,9 +610,9 @@ void ColumnSet(int column)
|
||||||
for(TSelectionFrames::iterator it(selectionFrames.begin()); it != selectionFrames.end(); it++)
|
for(TSelectionFrames::iterator it(selectionFrames.begin()); it != selectionFrames.end(); it++)
|
||||||
currMovieData.records[*it].setBitValue(joy,button,newValue);
|
currMovieData.records[*it].setBitValue(joy,button,newValue);
|
||||||
if (newValue)
|
if (newValue)
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_SET, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_SET, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||||
else
|
else
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_UNSET, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_UNSET, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1048,7 +848,7 @@ bool Paste()
|
||||||
|
|
||||||
pGlobal = strchr(pGlobal, '\n');
|
pGlobal = strchr(pGlobal, '\n');
|
||||||
}
|
}
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_PASTE, *selectionFrames.begin()));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_PASTE, *selectionFrames.begin()));
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1058,7 +858,6 @@ bool Paste()
|
||||||
CloseClipboard();
|
CloseClipboard();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
//The subclass wndproc for the listview header
|
//The subclass wndproc for the listview header
|
||||||
LRESULT APIENTRY HeaderWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
|
LRESULT APIENTRY HeaderWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
|
||||||
|
@ -1247,22 +1046,21 @@ void OpenProject()
|
||||||
multitrack_recording_joypad = MULTITRACK_RECORDING_ALL;
|
multitrack_recording_joypad = MULTITRACK_RECORDING_ALL;
|
||||||
UncheckRecordingRadioButtons();
|
UncheckRecordingRadioButtons();
|
||||||
RecheckRecordingRadioButtons();
|
RecheckRecordingRadioButtons();
|
||||||
|
playback.reset();
|
||||||
// remember to update fourscore status
|
// remember to update fourscore status
|
||||||
bool last_fourscore = currMovieData.fourscore;
|
bool last_fourscore = currMovieData.fourscore;
|
||||||
// Load project
|
// Load project
|
||||||
project.LoadProject(project.GetProjectFile());
|
project.LoadProject(project.GetProjectFile());
|
||||||
UpdateList();
|
UpdateList();
|
||||||
UpdateHistoryList();
|
|
||||||
RedrawHistoryList();
|
|
||||||
// update fourscore status
|
// update fourscore status
|
||||||
if (last_fourscore && !currMovieData.fourscore)
|
if (last_fourscore && !currMovieData.fourscore)
|
||||||
RemoveFourscore();
|
RemoveFourscore();
|
||||||
else if (!last_fourscore && currMovieData.fourscore)
|
else if (!last_fourscore && currMovieData.fourscore)
|
||||||
AddFourscore();
|
AddFourscore();
|
||||||
SeekingStop();
|
|
||||||
FollowPlayback();
|
FollowPlayback();
|
||||||
RedrawTasedit();
|
RedrawTasedit();
|
||||||
RedrawWindowCaption();
|
RedrawWindowCaption();
|
||||||
|
RedrawBookmarksCaption();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1336,15 +1134,12 @@ bool AskSaveProject()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Takes a selected .fm2 file and adds it to the Project inputlog
|
void Import()
|
||||||
static void Import()
|
|
||||||
{
|
{
|
||||||
//Pull the fm2 header, comments, subtitle information out and put it into the project info
|
|
||||||
//Pull the input out and add it to the main branch input log file
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
//Takes current inputlog and saves it as a .fm2 file
|
//Takes current inputlog and saves it as a .fm2 file
|
||||||
static void Export()
|
void Export()
|
||||||
{
|
{
|
||||||
//TODO: redesign this
|
//TODO: redesign this
|
||||||
//Dump project header info into file, then comments & subtitles, then input log
|
//Dump project header info into file, then comments & subtitles, then input log
|
||||||
|
@ -1371,22 +1166,6 @@ static void Export()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Truncate()
|
|
||||||
{
|
|
||||||
int frame = currFrameCounter;
|
|
||||||
if (selectionFrames.size())
|
|
||||||
{
|
|
||||||
frame=*selectionFrames.begin();
|
|
||||||
ClearSelection();
|
|
||||||
}
|
|
||||||
if (currMovieData.getNumRecords() > frame+1)
|
|
||||||
{
|
|
||||||
currMovieData.truncateAt(frame+1);
|
|
||||||
UpdateList();
|
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_TRUNCATE, frame+1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//used to track selection
|
//used to track selection
|
||||||
void ItemRangeChanged(NMLVODSTATECHANGE* info)
|
void ItemRangeChanged(NMLVODSTATECHANGE* info)
|
||||||
{
|
{
|
||||||
|
@ -1449,6 +1228,7 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
listItems = ListView_GetCountPerPage(hwndList);
|
listItems = ListView_GetCountPerPage(hwndList);
|
||||||
hwndHistoryList = GetDlgItem(hwndDlg, IDC_HISTORYLIST);
|
hwndHistoryList = GetDlgItem(hwndDlg, IDC_HISTORYLIST);
|
||||||
hwndBookmarksList = GetDlgItem(hwndDlg, IDC_BOOKMARKSLIST);
|
hwndBookmarksList = GetDlgItem(hwndDlg, IDC_BOOKMARKSLIST);
|
||||||
|
hwndBookmarks = GetDlgItem(hwndDlg, IDC_BOOKMARKS_BOX);
|
||||||
hwndProgressbar = GetDlgItem(hwndDlg, IDC_PROGRESS1);
|
hwndProgressbar = GetDlgItem(hwndDlg, IDC_PROGRESS1);
|
||||||
SendMessage(hwndProgressbar, PBM_SETRANGE, 0, MAKELPARAM(0, PROGRESSBAR_WIDTH));
|
SendMessage(hwndProgressbar, PBM_SETRANGE, 0, MAKELPARAM(0, PROGRESSBAR_WIDTH));
|
||||||
hwndRewind = GetDlgItem(hwndDlg, TASEDIT_REWIND);
|
hwndRewind = GetDlgItem(hwndDlg, TASEDIT_REWIND);
|
||||||
|
@ -1518,15 +1298,15 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
switch(((LPNMHDR)lParam)->code)
|
switch(((LPNMHDR)lParam)->code)
|
||||||
{
|
{
|
||||||
case NM_CUSTOMDRAW:
|
case NM_CUSTOMDRAW:
|
||||||
SetWindowLong(hwndDlg, DWL_MSGRESULT, HistoryCustomDraw((NMLVCUSTOMDRAW*)lParam));
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, history.CustomDraw((NMLVCUSTOMDRAW*)lParam));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
case LVN_GETDISPINFO:
|
case LVN_GETDISPINFO:
|
||||||
HistoryGetDispInfo((NMLVDISPINFO*)lParam);
|
history.GetDispInfo((NMLVDISPINFO*)lParam);
|
||||||
break;
|
break;
|
||||||
case NM_CLICK:
|
case NM_CLICK:
|
||||||
case NM_DBLCLK:
|
case NM_DBLCLK:
|
||||||
case NM_RCLICK:
|
case NM_RCLICK:
|
||||||
HistoryClick((LPNMITEMACTIVATE)lParam);
|
history.Click((LPNMITEMACTIVATE)lParam);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1536,7 +1316,7 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
{
|
{
|
||||||
case NM_CLICK:
|
case NM_CLICK:
|
||||||
case NM_DBLCLK:
|
case NM_DBLCLK:
|
||||||
Tasedit_ToggleEmulationPause();
|
playback.ToggleEmulationPause();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1623,12 +1403,12 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
// insert at selection
|
// insert at selection
|
||||||
int index = *selectionFrames.begin();
|
int index = *selectionFrames.begin();
|
||||||
currMovieData.insertEmpty(index,frames);
|
currMovieData.insertEmpty(index,frames);
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, index));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, index));
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
// insert at playback cursor
|
// insert at playback cursor
|
||||||
currMovieData.insertEmpty(currFrameCounter,frames);
|
currMovieData.insertEmpty(currFrameCounter,frames);
|
||||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, currFrameCounter));
|
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, currFrameCounter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1646,15 +1426,15 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
break;
|
break;
|
||||||
case TASEDIT_REWIND_FULL:
|
case TASEDIT_REWIND_FULL:
|
||||||
//rewinds to beginning of greenzone
|
//rewinds to beginning of greenzone
|
||||||
JumpToFrame(FindBeginningOfGreenZone(0));
|
playback.JumpToFrame(greenzone.FindBeginningOfGreenZone());
|
||||||
FollowPlayback();
|
FollowPlayback();
|
||||||
break;
|
break;
|
||||||
case TASEDIT_PLAYSTOP:
|
case TASEDIT_PLAYSTOP:
|
||||||
Tasedit_ToggleEmulationPause();
|
playback.ToggleEmulationPause();
|
||||||
break;
|
break;
|
||||||
case TASEDIT_FORWARD_FULL:
|
case TASEDIT_FORWARD_FULL:
|
||||||
//moves to the end of greenzone
|
//moves to the end of greenzone
|
||||||
JumpToFrame(currMovieData.greenZoneCount-1);
|
playback.JumpToFrame(greenzone.greenZoneCount-1);
|
||||||
FollowPlayback();
|
FollowPlayback();
|
||||||
break;
|
break;
|
||||||
case ACCEL_CTRL_F:
|
case ACCEL_CTRL_F:
|
||||||
|
@ -1708,7 +1488,7 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
if (new_capacity < TASEdit_greenzone_capacity)
|
if (new_capacity < TASEdit_greenzone_capacity)
|
||||||
{
|
{
|
||||||
TASEdit_greenzone_capacity = new_capacity;
|
TASEdit_greenzone_capacity = new_capacity;
|
||||||
currMovieData.ClearGreenzoneTail();
|
greenzone.ClearGreenzoneTail();
|
||||||
RedrawList();
|
RedrawList();
|
||||||
} else TASEdit_greenzone_capacity = new_capacity;
|
} else TASEdit_greenzone_capacity = new_capacity;
|
||||||
}
|
}
|
||||||
|
@ -1745,7 +1525,8 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
CheckMenuItem(hmenu, ID_CONFIG_BINDMARKERSTOINPUT, TASEdit_bind_markers?MF_CHECKED : MF_UNCHECKED);
|
CheckMenuItem(hmenu, ID_CONFIG_BINDMARKERSTOINPUT, TASEdit_bind_markers?MF_CHECKED : MF_UNCHECKED);
|
||||||
break;
|
break;
|
||||||
case IDC_PROGRESS_BUTTON:
|
case IDC_PROGRESS_BUTTON:
|
||||||
if (pauseframe) SeekingStop();
|
// click on progressbar - stop seeking
|
||||||
|
if (playback.pauseframe) playback.SeekingStop();
|
||||||
break;
|
break;
|
||||||
case IDC_RADIO1:
|
case IDC_RADIO1:
|
||||||
// switch to readonly, no need to recheck radiobuttons
|
// switch to readonly, no need to recheck radiobuttons
|
||||||
|
@ -1792,9 +1573,9 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
int result = history.undo();
|
int result = history.undo();
|
||||||
if (result >= 0)
|
if (result >= 0)
|
||||||
{
|
{
|
||||||
FollowUndo();
|
|
||||||
UpdateList();
|
UpdateList();
|
||||||
InvalidateGreenZone(result);
|
FollowUndo();
|
||||||
|
greenzone.InvalidateGreenZone(result);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1804,9 +1585,9 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
int result = history.redo();
|
int result = history.redo();
|
||||||
if (result >= 0)
|
if (result >= 0)
|
||||||
{
|
{
|
||||||
FollowRedo();
|
|
||||||
UpdateList();
|
UpdateList();
|
||||||
InvalidateGreenZone(result);
|
FollowUndo();
|
||||||
|
greenzone.InvalidateGreenZone(result);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1820,15 +1601,6 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FindBeginningOfGreenZone(int starting_index)
|
|
||||||
{
|
|
||||||
for (int i=starting_index; i<currMovieData.greenZoneCount; ++i)
|
|
||||||
{
|
|
||||||
if (!currMovieData.savestates[i].empty()) return i;
|
|
||||||
}
|
|
||||||
return starting_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CheckItemVisible(int frame)
|
bool CheckItemVisible(int frame)
|
||||||
{
|
{
|
||||||
int top = ListView_GetTopIndex(hwndList);
|
int top = ListView_GetTopIndex(hwndList);
|
||||||
|
@ -1842,10 +1614,9 @@ void FollowPlayback()
|
||||||
{
|
{
|
||||||
if (TASEdit_follow_playback) ListView_EnsureVisible(hwndList,currFrameCounter,FALSE);
|
if (TASEdit_follow_playback) ListView_EnsureVisible(hwndList,currFrameCounter,FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FollowUndo()
|
void FollowUndo()
|
||||||
{
|
{
|
||||||
int jump_frame = history.GetNextToCurrentSnapshot().jump_frame;
|
int jump_frame = history.GetUndoHint();
|
||||||
if (TASEdit_jump_to_undo && jump_frame >= 0)
|
if (TASEdit_jump_to_undo && jump_frame >= 0)
|
||||||
{
|
{
|
||||||
if (!CheckItemVisible(jump_frame))
|
if (!CheckItemVisible(jump_frame))
|
||||||
|
@ -1854,24 +1625,6 @@ void FollowUndo()
|
||||||
ListView_EnsureVisible(hwndList, jump_frame, false);
|
ListView_EnsureVisible(hwndList, jump_frame, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// init undo hint
|
|
||||||
undo_hint_pos = jump_frame;
|
|
||||||
undo_hint_time = clock() + UNDO_HINT_TIME;
|
|
||||||
}
|
|
||||||
void FollowRedo()
|
|
||||||
{
|
|
||||||
int jump_frame = history.GetCurrentSnapshot().jump_frame;
|
|
||||||
if (TASEdit_jump_to_undo && jump_frame >= 0)
|
|
||||||
{
|
|
||||||
if (!CheckItemVisible(jump_frame))
|
|
||||||
{
|
|
||||||
ListView_EnsureVisible(hwndList, currMovieData.getNumRecords()-1, true);
|
|
||||||
ListView_EnsureVisible(hwndList, jump_frame, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// init undo hint
|
|
||||||
undo_hint_pos = jump_frame;
|
|
||||||
undo_hint_time = clock() + UNDO_HINT_TIME;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnterTasEdit()
|
void EnterTasEdit()
|
||||||
|
@ -1896,9 +1649,6 @@ void EnterTasEdit()
|
||||||
// switch off autosaves
|
// switch off autosaves
|
||||||
saved_EnableAutosave = EnableAutosave;
|
saved_EnableAutosave = EnableAutosave;
|
||||||
EnableAutosave = 0;
|
EnableAutosave = 0;
|
||||||
// switch on savestates compression
|
|
||||||
saved_compressSavestates = compressSavestates;
|
|
||||||
compressSavestates = true;
|
|
||||||
|
|
||||||
|
|
||||||
UpdateCheckedMenuItems();
|
UpdateCheckedMenuItems();
|
||||||
|
@ -1916,107 +1666,96 @@ void EnterTasEdit()
|
||||||
CheckMenuItem(hmenu, ID_VIEW_SHOWDOTINEMPTYCELLS, TASEdit_show_dot?MF_CHECKED : MF_UNCHECKED);
|
CheckMenuItem(hmenu, ID_VIEW_SHOWDOTINEMPTYCELLS, TASEdit_show_dot?MF_CHECKED : MF_UNCHECKED);
|
||||||
|
|
||||||
SetWindowPos(hwndTasEdit,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
|
SetWindowPos(hwndTasEdit,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
|
||||||
}
|
|
||||||
|
|
||||||
// either start new movie or use current movie
|
playback.init();
|
||||||
if (movieMode == MOVIEMODE_INACTIVE)
|
greenzone.init();
|
||||||
{
|
// either start new movie or use current movie
|
||||||
FCEUI_StopMovie();
|
if (movieMode == MOVIEMODE_INACTIVE)
|
||||||
CreateCleanMovie();
|
|
||||||
StartFromZero();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//use current movie to create a new project
|
|
||||||
FCEUI_StopMovie();
|
|
||||||
}
|
|
||||||
// always start work from read-only mode, ready to switch to MULTITRACK_RECORDING_ALL
|
|
||||||
movie_readonly = true;
|
|
||||||
multitrack_recording_joypad = MULTITRACK_RECORDING_ALL;
|
|
||||||
RecheckRecordingRadioButtons();
|
|
||||||
movieMode = MOVIEMODE_TASEDIT;
|
|
||||||
|
|
||||||
//prepare the main listview
|
|
||||||
ListView_SetExtendedListViewStyleEx(hwndList,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
|
|
||||||
//subclass the header
|
|
||||||
hwndHeader = ListView_GetHeader(hwndList);
|
|
||||||
hwndHeader_oldWndproc = (WNDPROC)SetWindowLong(hwndHeader,GWL_WNDPROC,(LONG)HeaderWndProc);
|
|
||||||
//subclass the whole listview
|
|
||||||
hwndList_oldWndProc = (WNDPROC)SetWindowLong(hwndList,GWL_WNDPROC,(LONG)ListWndProc);
|
|
||||||
//setup images for the listview
|
|
||||||
HIMAGELIST himglist = ImageList_Create(8,12,ILC_COLOR8 | ILC_MASK,1,1);
|
|
||||||
HBITMAP bmp = LoadBitmap(fceu_hInstance,MAKEINTRESOURCE(IDB_TE_ARROW));
|
|
||||||
ImageList_AddMasked(himglist, bmp, 0xFF00FF);
|
|
||||||
DeleteObject(bmp);
|
|
||||||
ListView_SetImageList(hwndList,himglist,LVSIL_SMALL);
|
|
||||||
//setup columns
|
|
||||||
LVCOLUMN lvc;
|
|
||||||
int colidx=0;
|
|
||||||
// icons column
|
|
||||||
lvc.mask = LVCF_WIDTH;
|
|
||||||
lvc.cx = 13;
|
|
||||||
ListView_InsertColumn(hwndList, colidx++, &lvc);
|
|
||||||
// frame number column
|
|
||||||
lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT;
|
|
||||||
lvc.fmt = LVCFMT_CENTER;
|
|
||||||
lvc.cx = 75;
|
|
||||||
lvc.pszText = "Frame#";
|
|
||||||
ListView_InsertColumn(hwndList, colidx++, &lvc);
|
|
||||||
// pads columns
|
|
||||||
lvc.cx = 21;
|
|
||||||
// add pads 1 and 2
|
|
||||||
for (int joy = 0; joy < 2; ++joy)
|
|
||||||
{
|
|
||||||
for (int btn = 0; btn < NUM_JOYPAD_BUTTONS; ++btn)
|
|
||||||
{
|
{
|
||||||
lvc.pszText = buttonNames[btn];
|
FCEUI_StopMovie();
|
||||||
ListView_InsertColumn(hwndList, colidx++, &lvc);
|
CreateCleanMovie();
|
||||||
|
playback.StartFromZero();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//use current movie to create a new project
|
||||||
|
FCEUI_StopMovie();
|
||||||
|
}
|
||||||
|
// always start work from read-only mode, ready to switch to MULTITRACK_RECORDING_ALL
|
||||||
|
movie_readonly = true;
|
||||||
|
multitrack_recording_joypad = MULTITRACK_RECORDING_ALL;
|
||||||
|
RecheckRecordingRadioButtons();
|
||||||
|
movieMode = MOVIEMODE_TASEDIT;
|
||||||
|
|
||||||
|
//prepare the main listview
|
||||||
|
ListView_SetExtendedListViewStyleEx(hwndList,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
|
||||||
|
//subclass the header
|
||||||
|
hwndHeader = ListView_GetHeader(hwndList);
|
||||||
|
hwndHeader_oldWndproc = (WNDPROC)SetWindowLong(hwndHeader,GWL_WNDPROC,(LONG)HeaderWndProc);
|
||||||
|
//subclass the whole listview
|
||||||
|
hwndList_oldWndProc = (WNDPROC)SetWindowLong(hwndList,GWL_WNDPROC,(LONG)ListWndProc);
|
||||||
|
//setup images for the listview
|
||||||
|
HIMAGELIST himglist = ImageList_Create(8,12,ILC_COLOR8 | ILC_MASK,1,1);
|
||||||
|
HBITMAP bmp = LoadBitmap(fceu_hInstance,MAKEINTRESOURCE(IDB_TE_ARROW));
|
||||||
|
ImageList_AddMasked(himglist, bmp, 0xFF00FF);
|
||||||
|
DeleteObject(bmp);
|
||||||
|
ListView_SetImageList(hwndList,himglist,LVSIL_SMALL);
|
||||||
|
//setup columns
|
||||||
|
LVCOLUMN lvc;
|
||||||
|
int colidx=0;
|
||||||
|
// icons column
|
||||||
|
lvc.mask = LVCF_WIDTH;
|
||||||
|
lvc.cx = 13;
|
||||||
|
ListView_InsertColumn(hwndList, colidx++, &lvc);
|
||||||
|
// frame number column
|
||||||
|
lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT;
|
||||||
|
lvc.fmt = LVCFMT_CENTER;
|
||||||
|
lvc.cx = 75;
|
||||||
|
lvc.pszText = "Frame#";
|
||||||
|
ListView_InsertColumn(hwndList, colidx++, &lvc);
|
||||||
|
// pads columns
|
||||||
|
lvc.cx = 21;
|
||||||
|
// add pads 1 and 2
|
||||||
|
for (int joy = 0; joy < 2; ++joy)
|
||||||
|
{
|
||||||
|
for (int btn = 0; btn < NUM_JOYPAD_BUTTONS; ++btn)
|
||||||
|
{
|
||||||
|
lvc.pszText = buttonNames[btn];
|
||||||
|
ListView_InsertColumn(hwndList, colidx++, &lvc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add pads 3 and 4 and frame_number2
|
||||||
|
if (currMovieData.fourscore) AddFourscore();
|
||||||
|
UpdateList();
|
||||||
|
|
||||||
|
//prepare the history listview
|
||||||
|
ListView_SetExtendedListViewStyleEx(hwndHistoryList,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
|
||||||
|
//subclass the whole listview
|
||||||
|
hwndHistoryList_oldWndProc = (WNDPROC)SetWindowLong(hwndHistoryList,GWL_WNDPROC,(LONG)HistoryListWndProc);
|
||||||
|
lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT;
|
||||||
|
lvc.cx = 200;
|
||||||
|
lvc.fmt = LVCFMT_LEFT;
|
||||||
|
ListView_InsertColumn(hwndHistoryList, 0, &lvc);
|
||||||
|
|
||||||
|
// init variables
|
||||||
|
project.init();
|
||||||
|
history.init(TasEdit_undo_levels);
|
||||||
|
SetFocus(hwndHistoryList);
|
||||||
|
FCEU_DispMessage("Tasedit engaged",0);
|
||||||
}
|
}
|
||||||
// add pads 3 and 4 and frame_number2
|
|
||||||
if (currMovieData.fourscore) AddFourscore();
|
|
||||||
UpdateList();
|
|
||||||
|
|
||||||
//prepare the history listview
|
|
||||||
ListView_SetExtendedListViewStyleEx(hwndHistoryList,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
|
|
||||||
//subclass the whole listview
|
|
||||||
hwndHistoryList_oldWndProc = (WNDPROC)SetWindowLong(hwndHistoryList,GWL_WNDPROC,(LONG)HistoryListWndProc);
|
|
||||||
lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT;
|
|
||||||
lvc.cx = 200;
|
|
||||||
lvc.fmt = LVCFMT_LEFT;
|
|
||||||
ListView_InsertColumn(hwndHistoryList, 0, &lvc);
|
|
||||||
|
|
||||||
// init variables
|
|
||||||
lastCursor = -1;
|
|
||||||
old_project_changed = false;
|
|
||||||
old_pauseframe = 0;
|
|
||||||
old_show_pauseframe = show_pauseframe = false;
|
|
||||||
undo_hint_pos = old_undo_hint_pos = undo_hint_time = -1;
|
|
||||||
old_show_undo_hint = show_undo_hint = false;
|
|
||||||
old_rewind_button_state = rewind_button_state = false;
|
|
||||||
old_forward_button_state = forward_button_state = false;
|
|
||||||
old_emu_paused = emu_paused = true;
|
|
||||||
SeekingStop();
|
|
||||||
currMovieData.TryDumpIncremental();
|
|
||||||
project.init(&history);
|
|
||||||
history.init(TasEdit_undo_levels);
|
|
||||||
SetFocus(hwndHistoryList);
|
|
||||||
FCEU_DispMessage("Tasedit engaged",0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExitTasEdit()
|
bool ExitTasEdit()
|
||||||
{
|
{
|
||||||
if (!AskSaveProject()) return false;
|
if (!AskSaveProject()) return false;
|
||||||
|
|
||||||
DestroyWindow(hwndTasEdit);
|
DestroyWindow(hwndTasEdit);
|
||||||
hwndTasEdit = 0;
|
hwndTasEdit = 0;
|
||||||
SeekingStop();
|
|
||||||
TASEdit_focus = false;
|
TASEdit_focus = false;
|
||||||
// restore "eoptions"
|
// restore "eoptions"
|
||||||
eoptions = saved_eoptions;
|
eoptions = saved_eoptions;
|
||||||
// restore autosaves
|
// restore autosaves
|
||||||
EnableAutosave = saved_EnableAutosave;
|
EnableAutosave = saved_EnableAutosave;
|
||||||
// restore compression
|
|
||||||
compressSavestates = saved_compressSavestates;
|
|
||||||
|
|
||||||
DoPriority();
|
DoPriority();
|
||||||
UpdateCheckedMenuItems();
|
UpdateCheckedMenuItems();
|
||||||
|
@ -2024,69 +1763,12 @@ bool ExitTasEdit()
|
||||||
KeyboardClearBackgroundAccessBit(KEYBACKACCESS_TASEDIT);
|
KeyboardClearBackgroundAccessBit(KEYBACKACCESS_TASEDIT);
|
||||||
JoystickClearBackgroundAccessBit(JOYBACKACCESS_TASEDIT);
|
JoystickClearBackgroundAccessBit(JOYBACKACCESS_TASEDIT);
|
||||||
// release memory
|
// release memory
|
||||||
currMovieData.clearGreenzone();
|
greenzone.clearGreenzone();
|
||||||
history.free();
|
history.free();
|
||||||
|
|
||||||
movieMode = MOVIEMODE_INACTIVE;
|
movieMode = MOVIEMODE_INACTIVE;
|
||||||
FCEU_DispMessage("Tasedit disengaged",0);
|
FCEU_DispMessage("Tasedit disengaged",0);
|
||||||
CreateCleanMovie();
|
CreateCleanMovie();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
void HistoryGetDispInfo(NMLVDISPINFO* nmlvDispInfo)
|
|
||||||
{
|
|
||||||
LVITEM& item = nmlvDispInfo->item;
|
|
||||||
if(item.mask & LVIF_TEXT)
|
|
||||||
strcpy(item.pszText, history.GetItemDesc(item.iItem));
|
|
||||||
}
|
|
||||||
|
|
||||||
LONG HistoryCustomDraw(NMLVCUSTOMDRAW* msg)
|
|
||||||
{
|
|
||||||
switch(msg->nmcd.dwDrawStage)
|
|
||||||
{
|
|
||||||
case CDDS_PREPAINT:
|
|
||||||
return CDRF_NOTIFYITEMDRAW;
|
|
||||||
case CDDS_ITEMPREPAINT:
|
|
||||||
{
|
|
||||||
if (history.GetItemCoherence(msg->nmcd.dwItemSpec))
|
|
||||||
msg->clrTextBk = HISTORY_COHERENT_COLOR;
|
|
||||||
else
|
|
||||||
msg->clrTextBk = HISTORY_NORMAL_COLOR;
|
|
||||||
return CDRF_DODEFAULT;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return CDRF_DODEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryClick(LPNMITEMACTIVATE info)
|
|
||||||
{
|
|
||||||
// jump to pointed input snapshot
|
|
||||||
int item = info->iItem;
|
|
||||||
if (item >= 0)
|
|
||||||
{
|
|
||||||
int previous_item = history.GetCursorPos();
|
|
||||||
int result = history.jump(item);
|
|
||||||
if (result >= 0)
|
|
||||||
{
|
|
||||||
if (item < previous_item) FollowUndo(); else FollowRedo();
|
|
||||||
UpdateList();
|
|
||||||
InvalidateGreenZone(result);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RedrawHistoryList();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateHistoryList()
|
|
||||||
{
|
|
||||||
//update the number of items in the history list
|
|
||||||
int currLVItemCount = ListView_GetItemCount(hwndHistoryList);
|
|
||||||
int history_size = history.GetTotalItems();
|
|
||||||
if(currLVItemCount != history_size)
|
|
||||||
{
|
|
||||||
ListView_SetItemCountEx(hwndHistoryList,history_size,LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL);
|
|
||||||
RedrawHistoryList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
#define NUM_JOYPADS 4
|
#define NUM_JOYPADS 4
|
||||||
#define NUM_JOYPAD_BUTTONS 8
|
#define NUM_JOYPAD_BUTTONS 8
|
||||||
#define PAUSEFRAME_BLINKING_PERIOD 100
|
|
||||||
#define PROGRESSBAR_WIDTH 200
|
#define PROGRESSBAR_WIDTH 200
|
||||||
#define HOLD_REPEAT_DELAY 250 // in milliseconds
|
|
||||||
|
|
||||||
#define GREENZONE_CAPACITY_DEFAULT 100000
|
#define GREENZONE_CAPACITY_DEFAULT 100000
|
||||||
#define GREENZONE_CAPACITY_MIN 1
|
#define GREENZONE_CAPACITY_MIN 1
|
||||||
|
@ -14,8 +12,6 @@
|
||||||
#define UNDO_LEVELS_MAX 999
|
#define UNDO_LEVELS_MAX 999
|
||||||
#define UNDO_LEVELS_DEFAULT 100
|
#define UNDO_LEVELS_DEFAULT 100
|
||||||
|
|
||||||
#define UNDO_HINT_TIME 200
|
|
||||||
|
|
||||||
// multitrack
|
// multitrack
|
||||||
#define MULTITRACK_RECORDING_ALL 0
|
#define MULTITRACK_RECORDING_ALL 0
|
||||||
#define MULTITRACK_RECORDING_1P 1
|
#define MULTITRACK_RECORDING_1P 1
|
||||||
|
@ -77,44 +73,26 @@
|
||||||
#define CUR_INPUT_COLOR2 0xE4D8A8
|
#define CUR_INPUT_COLOR2 0xE4D8A8
|
||||||
#define GREENZONE_INPUT_COLOR2 0xAEE2AE
|
#define GREENZONE_INPUT_COLOR2 0xAEE2AE
|
||||||
#define LAG_INPUT_COLOR2 0xB8B3E2
|
#define LAG_INPUT_COLOR2 0xB8B3E2
|
||||||
|
|
||||||
#define HISTORY_COHERENT_COLOR 0xF9DDE6
|
|
||||||
#define HISTORY_NORMAL_COLOR 0xFFFFFF
|
|
||||||
|
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
void EnterTasEdit();
|
void EnterTasEdit();
|
||||||
void InitDialog();
|
void InitDialog();
|
||||||
bool ExitTasEdit();
|
bool ExitTasEdit();
|
||||||
void UpdateTasEdit();
|
void UpdateTasEdit();
|
||||||
void UpdateList();
|
void UpdateList();
|
||||||
void UpdateHistoryList();
|
|
||||||
void UpdateProgressbar(int a, int b);
|
|
||||||
void InputChangedRec();
|
void InputChangedRec();
|
||||||
void InvalidateGreenZone(int after);
|
|
||||||
bool JumpToFrame(int index);
|
|
||||||
int FindBeginningOfGreenZone(int starting_index);
|
|
||||||
bool CheckItemVisible(int frame);
|
bool CheckItemVisible(int frame);
|
||||||
void FollowPlayback();
|
void FollowPlayback();
|
||||||
void FollowUndo();
|
void FollowUndo();
|
||||||
void FollowRedo();
|
|
||||||
void ClearSelection();
|
void ClearSelection();
|
||||||
void ClearRowSelection(int index);
|
void ClearRowSelection(int index);
|
||||||
void AddFourscore();
|
void AddFourscore();
|
||||||
void RemoveFourscore();
|
void RemoveFourscore();
|
||||||
void RedrawWindowCaption();
|
void RedrawWindowCaption();
|
||||||
|
void RedrawBookmarksCaption();
|
||||||
void RedrawTasedit();
|
void RedrawTasedit();
|
||||||
void RedrawList();
|
void RedrawList();
|
||||||
void RedrawHistoryList();
|
|
||||||
void RedrawRow(int index);
|
void RedrawRow(int index);
|
||||||
void SeekingStart(int finish_frame);
|
|
||||||
void SeekingStop();
|
|
||||||
void Tasedit_ToggleEmulationPause();
|
|
||||||
void PauseEmulation();
|
|
||||||
void UnpauseEmulation();
|
|
||||||
void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags);
|
void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags);
|
||||||
void Tasedit_RewindFrame();
|
|
||||||
void Tasedit_ForwardFrame();
|
|
||||||
void StartFromZero();
|
|
||||||
void SwitchToReadOnly();
|
void SwitchToReadOnly();
|
||||||
void UncheckRecordingRadioButtons();
|
void UncheckRecordingRadioButtons();
|
||||||
void RecheckRecordingRadioButtons();
|
void RecheckRecordingRadioButtons();
|
||||||
|
@ -128,12 +106,8 @@ void CloneFrames();
|
||||||
void InsertFrames();
|
void InsertFrames();
|
||||||
void DeleteFrames();
|
void DeleteFrames();
|
||||||
void ClearFrames(bool cut = false);
|
void ClearFrames(bool cut = false);
|
||||||
|
void Truncate();
|
||||||
void ColumnSet(int column);
|
void ColumnSet(int column);
|
||||||
bool Copy();
|
bool Copy();
|
||||||
void Cut();
|
void Cut();
|
||||||
bool Paste();
|
bool Paste();
|
||||||
void Truncate();
|
|
||||||
void HistoryGetDispInfo(NMLVDISPINFO* nmlvDispInfo);
|
|
||||||
LONG HistoryCustomDraw(NMLVCUSTOMDRAW* msg);
|
|
||||||
void HistoryClick(LPNMITEMACTIVATE info);
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,248 @@
|
||||||
|
//Implementation file of Greenzone class
|
||||||
|
|
||||||
|
#include "movie.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "../common.h"
|
||||||
|
#include "zlib.h"
|
||||||
|
#include "taseditproj.h"
|
||||||
|
#include "../tasedit.h"
|
||||||
|
|
||||||
|
extern TASEDIT_PROJECT project;
|
||||||
|
extern PLAYBACK playback;
|
||||||
|
extern int TASEdit_greenzone_capacity;
|
||||||
|
extern bool TASEdit_bind_markers;
|
||||||
|
extern bool TASEdit_restore_position;
|
||||||
|
|
||||||
|
extern void FCEU_printf(char *format, ...);
|
||||||
|
|
||||||
|
GREENZONE::GREENZONE()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GREENZONE::init()
|
||||||
|
{
|
||||||
|
|
||||||
|
clearGreenzone();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
void GREENZONE::reset()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void GREENZONE::update()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GREENZONE::TryDumpIncremental(bool lagFlag)
|
||||||
|
{
|
||||||
|
// if movie length is less than currFrame, pad it with empty frames
|
||||||
|
if((int)currMovieData.records.size() <= currFrameCounter)
|
||||||
|
currMovieData.insertEmpty(-1, 1 + currFrameCounter - (int)currMovieData.records.size());
|
||||||
|
|
||||||
|
// if frame chanegd - log savestate
|
||||||
|
storeTasSavestate(currFrameCounter);
|
||||||
|
// also log frame_flags
|
||||||
|
if (currFrameCounter > 0)
|
||||||
|
{
|
||||||
|
// lagFlag indicates that lag was in previous frame
|
||||||
|
if (lagFlag)
|
||||||
|
currMovieData.frames_flags[currFrameCounter-1] |= LAG_FLAG_BIT;
|
||||||
|
else
|
||||||
|
currMovieData.frames_flags[currFrameCounter-1] &= ~LAG_FLAG_BIT;
|
||||||
|
}
|
||||||
|
// update greenzone upper limit
|
||||||
|
if (greenZoneCount <= currFrameCounter)
|
||||||
|
greenZoneCount = currFrameCounter+1;
|
||||||
|
|
||||||
|
ClearGreenzoneTail();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GREENZONE::loadTasSavestate(int frame)
|
||||||
|
{
|
||||||
|
if (frame < 0 || frame >= (int)currMovieData.records.size())
|
||||||
|
return false;
|
||||||
|
if ((int)savestates.size() <= frame || savestates[frame].empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
EMUFILE_MEMORY ms(&savestates[frame]);
|
||||||
|
return FCEUSS_LoadFP(&ms, SSLOADPARAM_NOBACKUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GREENZONE::storeTasSavestate(int frame)
|
||||||
|
{
|
||||||
|
if ((int)savestates.size()<=frame)
|
||||||
|
savestates.resize(frame+1);
|
||||||
|
|
||||||
|
EMUFILE_MEMORY ms(&savestates[frame]);
|
||||||
|
FCEUSS_SaveMS(&ms, Z_DEFAULT_COMPRESSION);
|
||||||
|
ms.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GREENZONE::ClearGreenzoneTail()
|
||||||
|
{
|
||||||
|
int tail_frame = greenZoneCount-1 - TASEdit_greenzone_capacity;
|
||||||
|
|
||||||
|
if (tail_frame >= currFrameCounter) tail_frame = currFrameCounter - 1;
|
||||||
|
for (;tail_frame >= 0; tail_frame--)
|
||||||
|
{
|
||||||
|
if (savestates[tail_frame].empty()) break;
|
||||||
|
ClearSavestate(tail_frame);
|
||||||
|
|
||||||
|
RedrawRow(tail_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GREENZONE::ClearSavestate(int index)
|
||||||
|
{
|
||||||
|
std::vector<uint8> tmp;
|
||||||
|
savestates[index].swap(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GREENZONE::clearGreenzone()
|
||||||
|
{
|
||||||
|
int size = savestates.size();
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
ClearSavestate(i);
|
||||||
|
}
|
||||||
|
greenZoneCount = 1;
|
||||||
|
currMovieData.frames_flags.resize(1);
|
||||||
|
// reset lua_colorings
|
||||||
|
// reset monitorings
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int GREENZONE::dumpGreenzone(EMUFILE *os)
|
||||||
|
{
|
||||||
|
int start = os->ftell();
|
||||||
|
int frame, size;
|
||||||
|
int last_tick = 0;
|
||||||
|
// write size
|
||||||
|
write32le(greenZoneCount, os);
|
||||||
|
write32le(currFrameCounter, os);
|
||||||
|
// write savestates
|
||||||
|
for (frame = 0; frame < greenZoneCount; ++frame)
|
||||||
|
{
|
||||||
|
// update TASEditor progressbar from time to time
|
||||||
|
if (frame / PROGRESSBAR_UPDATE_RATE > last_tick)
|
||||||
|
{
|
||||||
|
playback.SetProgressbar(frame, greenZoneCount);
|
||||||
|
last_tick = frame / PROGRESSBAR_UPDATE_RATE;
|
||||||
|
}
|
||||||
|
if (savestates[frame].empty()) continue;
|
||||||
|
write32le(frame, os);
|
||||||
|
// write frames_flags
|
||||||
|
os->fwrite(&currMovieData.frames_flags[frame], 1);
|
||||||
|
// write lua_colorings
|
||||||
|
// write monitorings
|
||||||
|
// write savestate
|
||||||
|
size = savestates[frame].size();
|
||||||
|
write32le(size, os);
|
||||||
|
os->fwrite(savestates[frame].data(), size);
|
||||||
|
|
||||||
|
}
|
||||||
|
// write -1 as eof for greenzone
|
||||||
|
write32le(-1, os);
|
||||||
|
|
||||||
|
int end = os->ftell();
|
||||||
|
return end-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GREENZONE::loadGreenzone(EMUFILE *is)
|
||||||
|
{
|
||||||
|
clearGreenzone();
|
||||||
|
currMovieData.frames_flags.resize(currMovieData.records.size());
|
||||||
|
int frame = 0, prev_frame = 0, size = 0;
|
||||||
|
int last_tick = 0;
|
||||||
|
// read size
|
||||||
|
if (read32le((uint32 *)&size, is) && size >= 0 && size <= (int)currMovieData.records.size())
|
||||||
|
{
|
||||||
|
greenZoneCount = size;
|
||||||
|
savestates.resize(greenZoneCount);
|
||||||
|
int greenzone_tail_frame = greenZoneCount-1 - TASEdit_greenzone_capacity;
|
||||||
|
|
||||||
|
if (read32le((uint32 *)&frame, is))
|
||||||
|
{
|
||||||
|
currFrameCounter = frame;
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
if (!read32le((uint32 *)&frame, is)) break;
|
||||||
|
if (frame == -1) break;
|
||||||
|
// update TASEditor progressbar from time to time
|
||||||
|
if (frame / PROGRESSBAR_UPDATE_RATE > last_tick)
|
||||||
|
{
|
||||||
|
playback.SetProgressbar(frame, greenZoneCount);
|
||||||
|
last_tick = frame / PROGRESSBAR_UPDATE_RATE;
|
||||||
|
}
|
||||||
|
// read frames_flags
|
||||||
|
if ((int)is->fread(&currMovieData.frames_flags[frame],1) != 1) break;
|
||||||
|
// read lua_colorings
|
||||||
|
// read monitorings
|
||||||
|
// read savestate
|
||||||
|
if (!read32le((uint32 *)&size, is)) break;
|
||||||
|
if (size < 0) break;
|
||||||
|
if (frame > greenzone_tail_frame || frame == currFrameCounter)
|
||||||
|
{
|
||||||
|
// load savestate
|
||||||
|
savestates[frame].resize(size);
|
||||||
|
if ((int)is->fread(savestates[frame].data(),size) < size) break;
|
||||||
|
prev_frame = frame; // successfully read one greenzone frame info
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// skip loading this savestate
|
||||||
|
if (is->fseek(size,SEEK_CUR) != 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
greenZoneCount = prev_frame+1; // cut greenZoneCount to last good frame
|
||||||
|
if (frame == -1)
|
||||||
|
{
|
||||||
|
// everything went fine - load savestate at cursor position
|
||||||
|
if (loadTasSavestate(currFrameCounter))
|
||||||
|
return true;
|
||||||
|
} else goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error:
|
||||||
|
// there was some error while reading greenzone
|
||||||
|
FCEU_printf("Error loading greenzone\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GREENZONE::InvalidateGreenZone(int after)
|
||||||
|
{
|
||||||
|
if (after < 0) return;
|
||||||
|
project.changed = true;
|
||||||
|
if (greenZoneCount > after+1)
|
||||||
|
{
|
||||||
|
greenZoneCount = after+1;
|
||||||
|
currMovieData.rerecordCount++;
|
||||||
|
// either set playback cursor to the end of greenzone or run seeking to restore playback position
|
||||||
|
if (currFrameCounter >= greenZoneCount)
|
||||||
|
{
|
||||||
|
if (TASEdit_restore_position)
|
||||||
|
playback.restorePosition();
|
||||||
|
else
|
||||||
|
playback.JumpToFrame(greenZoneCount-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// redraw list even if greenzone didn't change
|
||||||
|
RedrawList();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GREENZONE::FindBeginningOfGreenZone(int starting_index)
|
||||||
|
{
|
||||||
|
for (int i = starting_index; i < greenZoneCount; ++i)
|
||||||
|
{
|
||||||
|
if (!savestates[i].empty()) return i;
|
||||||
|
}
|
||||||
|
return starting_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
//Specification file for Greenzone class
|
||||||
|
|
||||||
|
|
||||||
|
class GREENZONE
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GREENZONE();
|
||||||
|
void init();
|
||||||
|
void reset();
|
||||||
|
void update();
|
||||||
|
|
||||||
|
void TryDumpIncremental(bool lagFlag = true);
|
||||||
|
|
||||||
|
void clearGreenzone();
|
||||||
|
int dumpGreenzone(EMUFILE *os);
|
||||||
|
bool loadGreenzone(EMUFILE *is);
|
||||||
|
|
||||||
|
bool loadTasSavestate(int frame);
|
||||||
|
void storeTasSavestate(int frame);
|
||||||
|
void ClearGreenzoneTail();
|
||||||
|
void ClearSavestate(int index);
|
||||||
|
|
||||||
|
void InvalidateGreenZone(int after);
|
||||||
|
|
||||||
|
int FindBeginningOfGreenZone(int starting_index = 0);
|
||||||
|
|
||||||
|
// data
|
||||||
|
int greenZoneCount;
|
||||||
|
std::vector<std::vector<uint8>> savestates;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
};
|
|
@ -1,15 +1,19 @@
|
||||||
//Implementation file of Input History and Input Snapshot classes (for Undo feature)
|
//Implementation file of Input History class (Undo feature)
|
||||||
|
|
||||||
#include "movie.h"
|
#include "movie.h"
|
||||||
|
#include "../common.h"
|
||||||
|
#include "../tasedit.h"
|
||||||
|
#include "inputsnapshot.h"
|
||||||
#include "inputhistory.h"
|
#include "inputhistory.h"
|
||||||
#include "zlib.h"
|
#include "playback.h"
|
||||||
|
#include "greenzone.h"
|
||||||
|
|
||||||
|
extern PLAYBACK playback;
|
||||||
extern void FCEU_printf(char *format, ...);
|
extern void FCEU_printf(char *format, ...);
|
||||||
extern void RedrawHistoryList();
|
extern HWND hwndHistoryList;
|
||||||
extern void UpdateHistoryList();
|
extern GREENZONE greenzone;
|
||||||
extern void UpdateProgressbar(int a, int b);
|
|
||||||
|
|
||||||
char modCaptions[23][12] = {"Init",
|
char modCaptions[24][12] = {"Init",
|
||||||
"Change",
|
"Change",
|
||||||
"Set",
|
"Set",
|
||||||
"Unset",
|
"Unset",
|
||||||
|
@ -22,6 +26,7 @@ char modCaptions[23][12] = {"Init",
|
||||||
"PasteInsert",
|
"PasteInsert",
|
||||||
"Clone",
|
"Clone",
|
||||||
"Record",
|
"Record",
|
||||||
|
"Import",
|
||||||
"Branch0",
|
"Branch0",
|
||||||
"Branch1",
|
"Branch1",
|
||||||
"Branch2",
|
"Branch2",
|
||||||
|
@ -34,311 +39,6 @@ char modCaptions[23][12] = {"Init",
|
||||||
"Branch9"};
|
"Branch9"};
|
||||||
char joypadCaptions[4][5] = {"(1P)", "(2P)", "(3P)", "(4P)"};
|
char joypadCaptions[4][5] = {"(1P)", "(2P)", "(3P)", "(4P)"};
|
||||||
|
|
||||||
INPUT_SNAPSHOT::INPUT_SNAPSHOT()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void INPUT_SNAPSHOT::init(MovieData& md)
|
|
||||||
{
|
|
||||||
// retrieve input data from movie data
|
|
||||||
size = md.getNumRecords();
|
|
||||||
fourscore = md.fourscore;
|
|
||||||
int num = (fourscore)?4:2;
|
|
||||||
joysticks.resize(num*size); // it's much faster to have this format [joy + frame << JOY_POWER] than have [frame][joy]
|
|
||||||
hot_changes.resize(num*size * HOTCHANGE_BYTES_PER_JOY);
|
|
||||||
int pos = 0;
|
|
||||||
if (fourscore)
|
|
||||||
{
|
|
||||||
for (int frame = 0; frame < size; ++frame)
|
|
||||||
{
|
|
||||||
joysticks[pos++] = md.records[frame].joysticks[0];
|
|
||||||
joysticks[pos++] = md.records[frame].joysticks[1];
|
|
||||||
joysticks[pos++] = md.records[frame].joysticks[2];
|
|
||||||
joysticks[pos++] = md.records[frame].joysticks[3];
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
for (int frame = 0; frame < size; ++frame)
|
|
||||||
{
|
|
||||||
joysticks[pos++] = md.records[frame].joysticks[0];
|
|
||||||
joysticks[pos++] = md.records[frame].joysticks[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
coherent = true;
|
|
||||||
// save time to description
|
|
||||||
time_t raw_time;
|
|
||||||
time(&raw_time);
|
|
||||||
struct tm * timeinfo = localtime(&raw_time);
|
|
||||||
strftime(description, 10, "%H:%M:%S ", timeinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void INPUT_SNAPSHOT::toMovie(MovieData& md, int start)
|
|
||||||
{
|
|
||||||
// write input data to movie data
|
|
||||||
md.records.resize(size);
|
|
||||||
md.frames_flags.resize(size);
|
|
||||||
if (fourscore)
|
|
||||||
{
|
|
||||||
int pos = start << 2;
|
|
||||||
for (int frame = start; frame < size; ++frame)
|
|
||||||
{
|
|
||||||
md.records[frame].joysticks[0] = joysticks[pos++];
|
|
||||||
md.records[frame].joysticks[1] = joysticks[pos++];
|
|
||||||
md.records[frame].joysticks[2] = joysticks[pos++];
|
|
||||||
md.records[frame].joysticks[3] = joysticks[pos++];
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
int pos = start << 1;
|
|
||||||
for (int frame = start; frame < size; ++frame)
|
|
||||||
{
|
|
||||||
md.records[frame].joysticks[0] = joysticks[pos++];
|
|
||||||
md.records[frame].joysticks[1] = joysticks[pos++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void INPUT_SNAPSHOT::save(EMUFILE *os)
|
|
||||||
{
|
|
||||||
// write vars
|
|
||||||
write32le(size, os);
|
|
||||||
if (fourscore) write8le(4, os); else write8le((uint8)0, os);
|
|
||||||
if (coherent) write8le(1, os); else write8le((uint8)0, os);
|
|
||||||
write32le(jump_frame, os);
|
|
||||||
// write description
|
|
||||||
int len = strlen(description);
|
|
||||||
write8le(len, os);
|
|
||||||
os->fwrite(&description[0], len);
|
|
||||||
// compress and save joysticks data
|
|
||||||
len = joysticks.size();
|
|
||||||
int comprlen = (len>>9)+12 + len;
|
|
||||||
std::vector<uint8> cbuf(comprlen);
|
|
||||||
int e = compress(cbuf.data(), (uLongf*)&comprlen,(uint8*)joysticks.data(),len);
|
|
||||||
// write size
|
|
||||||
write32le(comprlen, os);
|
|
||||||
os->fwrite(cbuf.data(), comprlen);
|
|
||||||
// compress and save hot_changes data
|
|
||||||
len = hot_changes.size();
|
|
||||||
comprlen = (len>>9)+12 + len;
|
|
||||||
std::vector<uint8> cbuf2(comprlen);
|
|
||||||
e = compress(cbuf2.data(),(uLongf*)&comprlen,(uint8*)hot_changes.data(),len);
|
|
||||||
// write size
|
|
||||||
write32le(comprlen, os);
|
|
||||||
os->fwrite(cbuf2.data(), comprlen);
|
|
||||||
}
|
|
||||||
bool INPUT_SNAPSHOT::load(EMUFILE *is)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
uint8 tmp;
|
|
||||||
// read vars
|
|
||||||
if (!read32le(&size, is)) return false;
|
|
||||||
if (!read8le(&tmp, is)) return false;
|
|
||||||
fourscore = (tmp != 0);
|
|
||||||
if (!read8le(&tmp, is)) return false;
|
|
||||||
coherent = (tmp != 0);
|
|
||||||
if (!read32le(&jump_frame, is)) return false;
|
|
||||||
// read description
|
|
||||||
if (!read8le(&tmp, is)) return false;
|
|
||||||
if (tmp < 0 || tmp >= SNAPSHOT_DESC_MAX_LENGTH) return false;
|
|
||||||
if (is->fread(&description[0], tmp) != tmp) return false;
|
|
||||||
description[tmp] = 0; // add '0' because it wasn't saved
|
|
||||||
// read and uncompress joysticks data
|
|
||||||
len = (fourscore)?4*size:2*size;
|
|
||||||
joysticks.resize(len);
|
|
||||||
// read size
|
|
||||||
int comprlen;
|
|
||||||
if (!read32le(&comprlen, is)) return false;
|
|
||||||
if (comprlen <= 0 || comprlen > len) return false;
|
|
||||||
std::vector<uint8> cbuf(comprlen);
|
|
||||||
if (is->fread(cbuf.data(),comprlen) != comprlen) return false;
|
|
||||||
int e = uncompress((uint8*)joysticks.data(),(uLongf*)&len,cbuf.data(),comprlen);
|
|
||||||
if (e != Z_OK && e != Z_BUF_ERROR) return false;
|
|
||||||
// read and uncompress hot_changes data
|
|
||||||
len = (fourscore) ? 4*size*HOTCHANGE_BYTES_PER_JOY : 2*size*HOTCHANGE_BYTES_PER_JOY;
|
|
||||||
hot_changes.resize(len);
|
|
||||||
// read size
|
|
||||||
if (!read32le(&comprlen, is)) return false;
|
|
||||||
if (comprlen <= 0 || comprlen > len) return false;
|
|
||||||
std::vector<uint8> cbuf2(comprlen);
|
|
||||||
if (is->fread(cbuf2.data(),comprlen) != comprlen) return false;
|
|
||||||
e = uncompress(hot_changes.data(),(uLongf*)&len,cbuf.data(),comprlen);
|
|
||||||
if (e != Z_OK && e != Z_BUF_ERROR) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool INPUT_SNAPSHOT::skipLoad(EMUFILE *is)
|
|
||||||
{
|
|
||||||
int tmp;
|
|
||||||
uint8 tmp1;
|
|
||||||
// read vars
|
|
||||||
if (!read32le(&tmp, is)) return false;
|
|
||||||
if (!read8le(&tmp1, is)) return false;
|
|
||||||
if (!read8le(&tmp1, is)) return false;
|
|
||||||
if (!read32le(&tmp, is)) return false;
|
|
||||||
// read description
|
|
||||||
if (!read8le(&tmp1, is)) return false;
|
|
||||||
if (is->fseek(tmp1, SEEK_CUR) != 0) return false;
|
|
||||||
// read joysticks data
|
|
||||||
if (!read32le(&tmp, is)) return false;
|
|
||||||
if (is->fseek(tmp, SEEK_CUR) != 0) return false;
|
|
||||||
// read hot_changes data
|
|
||||||
if (!read32le(&tmp, is)) return false;
|
|
||||||
if (is->fseek(tmp, SEEK_CUR) != 0) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if any difference is found
|
|
||||||
bool INPUT_SNAPSHOT::checkDiff(INPUT_SNAPSHOT& inp)
|
|
||||||
{
|
|
||||||
if (size != inp.size) return true;
|
|
||||||
if (findFirstChange(inp) >= 0)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if joypads differ
|
|
||||||
bool INPUT_SNAPSHOT::checkJoypadDiff(INPUT_SNAPSHOT& inp, int frame, int joy)
|
|
||||||
{
|
|
||||||
if (fourscore)
|
|
||||||
{
|
|
||||||
int pos = frame << 2;
|
|
||||||
if (pos < (inp.size << 2))
|
|
||||||
{
|
|
||||||
if (joysticks[pos+joy] != inp.joysticks[pos+joy]) return true;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
if (joysticks[pos+joy]) return true;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
int pos = frame << 1;
|
|
||||||
if (pos < (inp.size << 1))
|
|
||||||
{
|
|
||||||
if (joysticks[pos+joy] != inp.joysticks[pos+joy]) return true;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
if (joysticks[pos+joy]) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// return number of first frame of difference
|
|
||||||
int INPUT_SNAPSHOT::findFirstChange(INPUT_SNAPSHOT& inp, int start, int end)
|
|
||||||
{
|
|
||||||
// search for differences to the specified end (or to size)
|
|
||||||
if (end < 0 || end >= size) end = size-1;
|
|
||||||
|
|
||||||
if (fourscore)
|
|
||||||
{
|
|
||||||
int inp_end = inp.size << 2;
|
|
||||||
end = (end << 2) + 3;
|
|
||||||
for (int pos = start << 2; pos <= end; ++pos)
|
|
||||||
{
|
|
||||||
// if found different byte, or found emptiness in inp when there's non-zero value here
|
|
||||||
if (pos < inp_end)
|
|
||||||
{
|
|
||||||
if (joysticks[pos] != inp.joysticks[pos]) return (pos >> 2);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
if (joysticks[pos]) return (pos >> 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
int inp_end = inp.size << 1;
|
|
||||||
end = (end << 1) + 1;
|
|
||||||
for (int pos = start << 1; pos <= end; ++pos)
|
|
||||||
{
|
|
||||||
// if found different byte, or found emptiness in inp when there's non-zero value here
|
|
||||||
if (pos < inp_end)
|
|
||||||
{
|
|
||||||
if (joysticks[pos] != inp.joysticks[pos]) return (pos >> 1);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
if (joysticks[pos]) return (pos >> 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if current size is less then previous return size-1 as the frame of difference
|
|
||||||
if (size < inp.size) return size-1;
|
|
||||||
|
|
||||||
return -1; // no changes were found
|
|
||||||
}
|
|
||||||
int INPUT_SNAPSHOT::findFirstChange(MovieData& md)
|
|
||||||
{
|
|
||||||
// search for differences from the beginning to the end of movie (or to size)
|
|
||||||
int end = md.getNumRecords()-1;
|
|
||||||
if (end >= size) end = size-1;
|
|
||||||
|
|
||||||
if (fourscore)
|
|
||||||
{
|
|
||||||
for (int frame = 0, pos = 0; frame <= end; ++frame)
|
|
||||||
{
|
|
||||||
if (joysticks[pos++] != md.records[frame].joysticks[0]) return frame;
|
|
||||||
if (joysticks[pos++] != md.records[frame].joysticks[1]) return frame;
|
|
||||||
if (joysticks[pos++] != md.records[frame].joysticks[2]) return frame;
|
|
||||||
if (joysticks[pos++] != md.records[frame].joysticks[3]) return frame;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
for (int frame = 0, pos = 0; frame <= end; ++frame)
|
|
||||||
{
|
|
||||||
if (joysticks[pos++] != md.records[frame].joysticks[0]) return frame;
|
|
||||||
if (joysticks[pos++] != md.records[frame].joysticks[1]) return frame;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if sizes differ, return last frame from the lesser of them
|
|
||||||
if (size != md.getNumRecords()) return end;
|
|
||||||
|
|
||||||
return -1; // no changes were found
|
|
||||||
}
|
|
||||||
|
|
||||||
void INPUT_SNAPSHOT::SetMaxHotChange(int frame, int absolute_button)
|
|
||||||
{
|
|
||||||
if (frame < 0 || frame >= size) return;
|
|
||||||
// set max value (15) to the button hotness
|
|
||||||
if (fourscore)
|
|
||||||
{
|
|
||||||
// 32 buttons, 16bytes
|
|
||||||
if (absolute_button & 1)
|
|
||||||
// odd buttons (B, T, D, R) - set upper 4 bits of the byte
|
|
||||||
hot_changes[(frame << 4) | (absolute_button >> 1)] &= 0xF0;
|
|
||||||
else
|
|
||||||
// even buttons (A, S, U, L) - set lower 4 bits of the byte
|
|
||||||
hot_changes[(frame << 4) | (absolute_button >> 1)] &= 0x0F;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
// 16 buttons, 8bytes
|
|
||||||
if (absolute_button & 1)
|
|
||||||
// odd buttons (B, T, D, R) - set upper 4 bits of the byte
|
|
||||||
hot_changes[(frame << 3) | (absolute_button >> 1)] &= 0xF0;
|
|
||||||
else
|
|
||||||
// even buttons (A, S, U, L) - set lower 4 bits of the byte
|
|
||||||
hot_changes[(frame << 3) | (absolute_button >> 1)] &= 0x0F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int INPUT_SNAPSHOT::GetHotChangeInfo(int frame, int absolute_button)
|
|
||||||
{
|
|
||||||
if (frame < 0 || frame >= size) return 0;
|
|
||||||
if (absolute_button < 0 || absolute_button > 31) return 0;
|
|
||||||
|
|
||||||
uint8 val;
|
|
||||||
if (fourscore)
|
|
||||||
// 32 buttons, 16bytes
|
|
||||||
val = hot_changes[(frame << 4) + (absolute_button >> 1)];
|
|
||||||
else
|
|
||||||
// 16 buttons, 8bytes
|
|
||||||
val = hot_changes[(frame << 3) + (absolute_button >> 1)];
|
|
||||||
|
|
||||||
if (absolute_button & 1)
|
|
||||||
// odd buttons (B, T, D, R) - upper 4 bits of the byte
|
|
||||||
return val >> 4;
|
|
||||||
else
|
|
||||||
// even buttons (A, S, U, L) - lower 4 bits of the byte
|
|
||||||
return val & 15;
|
|
||||||
}
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
INPUT_HISTORY::INPUT_HISTORY()
|
INPUT_HISTORY::INPUT_HISTORY()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -346,6 +46,9 @@ INPUT_HISTORY::INPUT_HISTORY()
|
||||||
|
|
||||||
void INPUT_HISTORY::init(int new_size)
|
void INPUT_HISTORY::init(int new_size)
|
||||||
{
|
{
|
||||||
|
// init vars
|
||||||
|
undo_hint_pos = old_undo_hint_pos = undo_hint_time = -1;
|
||||||
|
old_show_undo_hint = show_undo_hint = false;
|
||||||
history_size = new_size + 1;
|
history_size = new_size + 1;
|
||||||
// clear snapshots history
|
// clear snapshots history
|
||||||
history_total_items = 0;
|
history_total_items = 0;
|
||||||
|
@ -358,12 +61,35 @@ void INPUT_HISTORY::init(int new_size)
|
||||||
strcat(inp.description, modCaptions[0]);
|
strcat(inp.description, modCaptions[0]);
|
||||||
inp.jump_frame = -1;
|
inp.jump_frame = -1;
|
||||||
AddInputSnapshotToHistory(inp);
|
AddInputSnapshotToHistory(inp);
|
||||||
|
|
||||||
|
UpdateHistoryList();
|
||||||
|
RedrawHistoryList();
|
||||||
}
|
}
|
||||||
void INPUT_HISTORY::free()
|
void INPUT_HISTORY::free()
|
||||||
{
|
{
|
||||||
input_snapshots.resize(0);
|
input_snapshots.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void INPUT_HISTORY::update()
|
||||||
|
{
|
||||||
|
// update undo_hint
|
||||||
|
if (old_undo_hint_pos != undo_hint_pos && old_undo_hint_pos >= 0) RedrawRow(old_undo_hint_pos);
|
||||||
|
old_undo_hint_pos = undo_hint_pos;
|
||||||
|
old_show_undo_hint = show_undo_hint;
|
||||||
|
show_undo_hint = false;
|
||||||
|
if (undo_hint_pos >= 0)
|
||||||
|
{
|
||||||
|
if ((int)clock() < undo_hint_time)
|
||||||
|
show_undo_hint = true;
|
||||||
|
else
|
||||||
|
undo_hint_pos = -1; // finished hinting
|
||||||
|
}
|
||||||
|
if (old_show_undo_hint != show_undo_hint) RedrawRow(undo_hint_pos);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// returns frame of first input change (for greenzone invalidation)
|
// returns frame of first input change (for greenzone invalidation)
|
||||||
int INPUT_HISTORY::jump(int new_pos)
|
int INPUT_HISTORY::jump(int new_pos)
|
||||||
{
|
{
|
||||||
|
@ -371,6 +97,14 @@ int INPUT_HISTORY::jump(int new_pos)
|
||||||
// if nothing is done, do not invalidate greenzone
|
// if nothing is done, do not invalidate greenzone
|
||||||
if (new_pos == history_cursor_pos) return -1;
|
if (new_pos == history_cursor_pos) return -1;
|
||||||
|
|
||||||
|
// create undo_hint
|
||||||
|
if (new_pos < history_cursor_pos)
|
||||||
|
undo_hint_pos = GetCurrentSnapshot().jump_frame;
|
||||||
|
else
|
||||||
|
undo_hint_pos = GetNextToCurrentSnapshot().jump_frame;
|
||||||
|
undo_hint_time = clock() + UNDO_HINT_TIME;
|
||||||
|
show_undo_hint = true;
|
||||||
|
|
||||||
// make jump
|
// make jump
|
||||||
history_cursor_pos = new_pos;
|
history_cursor_pos = new_pos;
|
||||||
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
|
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
|
||||||
|
@ -381,6 +115,7 @@ int INPUT_HISTORY::jump(int new_pos)
|
||||||
// update current movie
|
// update current movie
|
||||||
input_snapshots[real_pos].toMovie(currMovieData, first_change);
|
input_snapshots[real_pos].toMovie(currMovieData, first_change);
|
||||||
RedrawHistoryList();
|
RedrawHistoryList();
|
||||||
|
|
||||||
return first_change;
|
return first_change;
|
||||||
}
|
}
|
||||||
int INPUT_HISTORY::undo()
|
int INPUT_HISTORY::undo()
|
||||||
|
@ -392,34 +127,6 @@ int INPUT_HISTORY::redo()
|
||||||
return jump(history_cursor_pos + 1);
|
return jump(history_cursor_pos + 1);
|
||||||
}
|
}
|
||||||
// ----------------------------
|
// ----------------------------
|
||||||
INPUT_SNAPSHOT& INPUT_HISTORY::GetCurrentSnapshot()
|
|
||||||
{
|
|
||||||
return input_snapshots[(history_start_pos + history_cursor_pos) % history_size];
|
|
||||||
}
|
|
||||||
INPUT_SNAPSHOT& INPUT_HISTORY::GetNextToCurrentSnapshot()
|
|
||||||
{
|
|
||||||
if (history_cursor_pos < history_total_items)
|
|
||||||
return input_snapshots[(history_start_pos + history_cursor_pos + 1) % history_size];
|
|
||||||
else
|
|
||||||
return input_snapshots[(history_start_pos + history_cursor_pos) % history_size];
|
|
||||||
}
|
|
||||||
int INPUT_HISTORY::GetCursorPos()
|
|
||||||
{
|
|
||||||
return history_cursor_pos;
|
|
||||||
}
|
|
||||||
int INPUT_HISTORY::GetTotalItems()
|
|
||||||
{
|
|
||||||
return history_total_items;
|
|
||||||
}
|
|
||||||
char* INPUT_HISTORY::GetItemDesc(int pos)
|
|
||||||
{
|
|
||||||
return input_snapshots[(history_start_pos + pos) % history_size].description;
|
|
||||||
}
|
|
||||||
bool INPUT_HISTORY::GetItemCoherence(int pos)
|
|
||||||
{
|
|
||||||
return input_snapshots[(history_start_pos + pos) % history_size].coherent;
|
|
||||||
}
|
|
||||||
// ----------------------------
|
|
||||||
void INPUT_HISTORY::AddInputSnapshotToHistory(INPUT_SNAPSHOT &inp)
|
void INPUT_HISTORY::AddInputSnapshotToHistory(INPUT_SNAPSHOT &inp)
|
||||||
{
|
{
|
||||||
// history uses conveyor of snapshots (vector with fixed size) to aviod resizing which is awfully expensive with such large objects as INPUT_SNAPSHOT
|
// history uses conveyor of snapshots (vector with fixed size) to aviod resizing which is awfully expensive with such large objects as INPUT_SNAPSHOT
|
||||||
|
@ -485,6 +192,7 @@ int INPUT_HISTORY::RegisterInputChanges(int mod_type, int start, int end)
|
||||||
case MODTYPE_TRUNCATE:
|
case MODTYPE_TRUNCATE:
|
||||||
case MODTYPE_CLEAR:
|
case MODTYPE_CLEAR:
|
||||||
case MODTYPE_CUT:
|
case MODTYPE_CUT:
|
||||||
|
case MODTYPE_IMPORT:
|
||||||
case MODTYPE_BRANCH_0: case MODTYPE_BRANCH_1:
|
case MODTYPE_BRANCH_0: case MODTYPE_BRANCH_1:
|
||||||
case MODTYPE_BRANCH_2: case MODTYPE_BRANCH_3:
|
case MODTYPE_BRANCH_2: case MODTYPE_BRANCH_3:
|
||||||
case MODTYPE_BRANCH_4: case MODTYPE_BRANCH_5:
|
case MODTYPE_BRANCH_4: case MODTYPE_BRANCH_5:
|
||||||
|
@ -507,7 +215,7 @@ int INPUT_HISTORY::RegisterInputChanges(int mod_type, int start, int end)
|
||||||
case MODTYPE_RECORD:
|
case MODTYPE_RECORD:
|
||||||
{
|
{
|
||||||
// add info which joypads were affected
|
// add info which joypads were affected
|
||||||
int num = (inp.fourscore)?4:2;
|
int num = (inp.input_type + 1) * 2; // hacky, only for distingushing between normal2p and fourscore
|
||||||
for (int i = 0; i < num; ++i)
|
for (int i = 0; i < num; ++i)
|
||||||
{
|
{
|
||||||
if (inp.checkJoypadDiff(input_snapshots[real_pos], first_changes, i))
|
if (inp.checkJoypadDiff(input_snapshots[real_pos], first_changes, i))
|
||||||
|
@ -531,7 +239,7 @@ int INPUT_HISTORY::RegisterInputChanges(int mod_type, int start, int end)
|
||||||
}
|
}
|
||||||
return first_changes;
|
return first_changes;
|
||||||
}
|
}
|
||||||
// ----------------------------
|
|
||||||
void INPUT_HISTORY::save(EMUFILE *os)
|
void INPUT_HISTORY::save(EMUFILE *os)
|
||||||
{
|
{
|
||||||
int real_pos, last_tick = 0;
|
int real_pos, last_tick = 0;
|
||||||
|
@ -543,7 +251,7 @@ void INPUT_HISTORY::save(EMUFILE *os)
|
||||||
{
|
{
|
||||||
real_pos = (history_start_pos + i) % history_size;
|
real_pos = (history_start_pos + i) % history_size;
|
||||||
input_snapshots[real_pos].save(os);
|
input_snapshots[real_pos].save(os);
|
||||||
UpdateProgressbar(i, history_total_items);
|
playback.SetProgressbar(i, history_total_items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void INPUT_HISTORY::load(EMUFILE *is)
|
void INPUT_HISTORY::load(EMUFILE *is)
|
||||||
|
@ -555,6 +263,7 @@ void INPUT_HISTORY::load(EMUFILE *is)
|
||||||
// read vars
|
// read vars
|
||||||
if (!read32le((uint32 *)&history_cursor_pos, is)) goto error;
|
if (!read32le((uint32 *)&history_cursor_pos, is)) goto error;
|
||||||
if (!read32le((uint32 *)&history_total_items, is)) goto error;
|
if (!read32le((uint32 *)&history_total_items, is)) goto error;
|
||||||
|
if (history_cursor_pos > history_total_items) goto error;
|
||||||
history_start_pos = 0;
|
history_start_pos = 0;
|
||||||
// read snapshots
|
// read snapshots
|
||||||
int total = history_total_items;
|
int total = history_total_items;
|
||||||
|
@ -582,19 +291,109 @@ void INPUT_HISTORY::load(EMUFILE *is)
|
||||||
{
|
{
|
||||||
// skip snapshots if current history_size is less then history_total_items
|
// skip snapshots if current history_size is less then history_total_items
|
||||||
if (!input_snapshots[i].load(is)) goto error;
|
if (!input_snapshots[i].load(is)) goto error;
|
||||||
UpdateProgressbar(i, history_total_items);
|
playback.SetProgressbar(i, history_total_items);
|
||||||
}
|
}
|
||||||
// skip redo snapshots if needed
|
// skip redo snapshots if needed
|
||||||
for (; i < total; ++i)
|
for (; i < total; ++i)
|
||||||
if (!inp.skipLoad(is)) goto error;
|
if (!inp.skipLoad(is)) goto error;
|
||||||
|
|
||||||
|
// init vars
|
||||||
|
undo_hint_pos = old_undo_hint_pos = undo_hint_time = -1;
|
||||||
|
old_show_undo_hint = show_undo_hint = false;
|
||||||
|
|
||||||
|
UpdateHistoryList();
|
||||||
|
RedrawHistoryList();
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
// couldn't load full history - reset it
|
// couldn't load full history - reset it
|
||||||
FCEU_printf("Error loading history\n");
|
FCEU_printf("Error loading history\n");
|
||||||
init(history_size-1);
|
init(history_size-1);
|
||||||
}
|
}
|
||||||
|
// ----------------------------
|
||||||
|
void INPUT_HISTORY::GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
|
||||||
|
{
|
||||||
|
LVITEM& item = nmlvDispInfo->item;
|
||||||
|
if(item.mask & LVIF_TEXT)
|
||||||
|
strcpy(item.pszText, GetItemDesc(item.iItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG INPUT_HISTORY::CustomDraw(NMLVCUSTOMDRAW* msg)
|
||||||
|
{
|
||||||
|
switch(msg->nmcd.dwDrawStage)
|
||||||
|
{
|
||||||
|
case CDDS_PREPAINT:
|
||||||
|
return CDRF_NOTIFYITEMDRAW;
|
||||||
|
case CDDS_ITEMPREPAINT:
|
||||||
|
{
|
||||||
|
if (GetItemCoherence(msg->nmcd.dwItemSpec))
|
||||||
|
msg->clrTextBk = HISTORY_COHERENT_COLOR;
|
||||||
|
else
|
||||||
|
msg->clrTextBk = HISTORY_NORMAL_COLOR;
|
||||||
|
return CDRF_DODEFAULT;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return CDRF_DODEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void INPUT_HISTORY::Click(LPNMITEMACTIVATE info)
|
||||||
|
{
|
||||||
|
// jump to pointed input snapshot
|
||||||
|
int item = info->iItem;
|
||||||
|
if (item >= 0)
|
||||||
|
{
|
||||||
|
int result = jump(item);
|
||||||
|
if (result >= 0)
|
||||||
|
{
|
||||||
|
UpdateList();
|
||||||
|
FollowUndo();
|
||||||
|
greenzone.InvalidateGreenZone(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RedrawHistoryList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void INPUT_HISTORY::UpdateHistoryList()
|
||||||
|
{
|
||||||
|
//update the number of items in the history list
|
||||||
|
int currLVItemCount = ListView_GetItemCount(hwndHistoryList);
|
||||||
|
if(currLVItemCount != history_total_items)
|
||||||
|
ListView_SetItemCountEx(hwndHistoryList, history_total_items, LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void INPUT_HISTORY::RedrawHistoryList()
|
||||||
|
{
|
||||||
|
ListView_SetItemState(hwndHistoryList, history_cursor_pos, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
|
||||||
|
ListView_EnsureVisible(hwndHistoryList, history_cursor_pos, FALSE);
|
||||||
|
InvalidateRect(hwndHistoryList, 0, FALSE);
|
||||||
|
}
|
||||||
|
// ----------------------------
|
||||||
|
INPUT_SNAPSHOT& INPUT_HISTORY::GetCurrentSnapshot()
|
||||||
|
{
|
||||||
|
return input_snapshots[(history_start_pos + history_cursor_pos) % history_size];
|
||||||
|
}
|
||||||
|
INPUT_SNAPSHOT& INPUT_HISTORY::GetNextToCurrentSnapshot()
|
||||||
|
{
|
||||||
|
if (history_cursor_pos < history_total_items)
|
||||||
|
return input_snapshots[(history_start_pos + history_cursor_pos + 1) % history_size];
|
||||||
|
else
|
||||||
|
return input_snapshots[(history_start_pos + history_cursor_pos) % history_size];
|
||||||
|
}
|
||||||
|
char* INPUT_HISTORY::GetItemDesc(int pos)
|
||||||
|
{
|
||||||
|
return input_snapshots[(history_start_pos + pos) % history_size].description;
|
||||||
|
}
|
||||||
|
bool INPUT_HISTORY::GetItemCoherence(int pos)
|
||||||
|
{
|
||||||
|
return input_snapshots[(history_start_pos + pos) % history_size].coherent;
|
||||||
|
}
|
||||||
|
int INPUT_HISTORY::GetUndoHint()
|
||||||
|
{
|
||||||
|
if (show_undo_hint)
|
||||||
|
return undo_hint_pos;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
//Specification file for Input History and Input Snapshot classes
|
//Specification file for Input History class
|
||||||
|
|
||||||
#include <time.h>
|
#define UNDO_HINT_TIME 200
|
||||||
|
|
||||||
#define HOTCHANGE_BYTES_PER_JOY 4
|
|
||||||
#define SNAPSHOT_DESC_MAX_LENGTH 50
|
|
||||||
|
|
||||||
#define MODTYPE_INIT 0
|
#define MODTYPE_INIT 0
|
||||||
#define MODTYPE_CHANGE 1
|
#define MODTYPE_CHANGE 1
|
||||||
|
@ -18,48 +15,20 @@
|
||||||
#define MODTYPE_PASTEINSERT 10
|
#define MODTYPE_PASTEINSERT 10
|
||||||
#define MODTYPE_CLONE 11
|
#define MODTYPE_CLONE 11
|
||||||
#define MODTYPE_RECORD 12
|
#define MODTYPE_RECORD 12
|
||||||
#define MODTYPE_BRANCH_0 13
|
#define MODTYPE_IMPORT 13
|
||||||
#define MODTYPE_BRANCH_1 14
|
#define MODTYPE_BRANCH_0 14
|
||||||
#define MODTYPE_BRANCH_2 15
|
#define MODTYPE_BRANCH_1 15
|
||||||
#define MODTYPE_BRANCH_3 16
|
#define MODTYPE_BRANCH_2 16
|
||||||
#define MODTYPE_BRANCH_4 17
|
#define MODTYPE_BRANCH_3 17
|
||||||
#define MODTYPE_BRANCH_5 18
|
#define MODTYPE_BRANCH_4 18
|
||||||
#define MODTYPE_BRANCH_6 19
|
#define MODTYPE_BRANCH_5 19
|
||||||
#define MODTYPE_BRANCH_7 20
|
#define MODTYPE_BRANCH_6 20
|
||||||
#define MODTYPE_BRANCH_8 21
|
#define MODTYPE_BRANCH_7 21
|
||||||
#define MODTYPE_BRANCH_9 22
|
#define MODTYPE_BRANCH_8 22
|
||||||
|
#define MODTYPE_BRANCH_9 23
|
||||||
|
|
||||||
class INPUT_SNAPSHOT
|
#define HISTORY_COHERENT_COLOR 0xF9DDE6
|
||||||
{
|
#define HISTORY_NORMAL_COLOR 0xFFFFFF
|
||||||
public:
|
|
||||||
INPUT_SNAPSHOT();
|
|
||||||
void init(MovieData& md);
|
|
||||||
void toMovie(MovieData& md, int start = 0);
|
|
||||||
|
|
||||||
void save(EMUFILE *os);
|
|
||||||
bool load(EMUFILE *is);
|
|
||||||
bool skipLoad(EMUFILE *is);
|
|
||||||
|
|
||||||
bool checkDiff(INPUT_SNAPSHOT& inp);
|
|
||||||
bool checkJoypadDiff(INPUT_SNAPSHOT& inp, int frame, int joy);
|
|
||||||
int findFirstChange(INPUT_SNAPSHOT& inp, int start = 0, int end = -1);
|
|
||||||
int findFirstChange(MovieData& md);
|
|
||||||
|
|
||||||
void SetMaxHotChange(int frame, int absolute_button);
|
|
||||||
int GetHotChangeInfo(int frame, int absolute_button);
|
|
||||||
|
|
||||||
int size; // in frames
|
|
||||||
bool fourscore;
|
|
||||||
std::vector<uint8> joysticks; // Format: joy0-for-frame0, joy1-for-frame0, joy2-for-frame0, joy3-for-frame0, joy0-for-frame1, joy1-for-frame1, ...
|
|
||||||
std::vector<uint8> hot_changes; // Format: buttons01joy0-for-frame0, buttons23joy0-for-frame0, buttons45joy0-for-frame0, buttons67joy0-for-frame0, buttons01joy1-for-frame0, ...
|
|
||||||
|
|
||||||
bool coherent; // indicates whether this state was made by inputchange of previous state
|
|
||||||
int jump_frame; // for jumping when making undo
|
|
||||||
char description[SNAPSHOT_DESC_MAX_LENGTH];
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class INPUT_HISTORY
|
class INPUT_HISTORY
|
||||||
{
|
{
|
||||||
|
@ -68,6 +37,8 @@ public:
|
||||||
void init(int new_size);
|
void init(int new_size);
|
||||||
void free();
|
void free();
|
||||||
|
|
||||||
|
void update(); // called every frame
|
||||||
|
|
||||||
void save(EMUFILE *os);
|
void save(EMUFILE *os);
|
||||||
void load(EMUFILE *is);
|
void load(EMUFILE *is);
|
||||||
|
|
||||||
|
@ -85,10 +56,16 @@ public:
|
||||||
|
|
||||||
INPUT_SNAPSHOT& GetCurrentSnapshot();
|
INPUT_SNAPSHOT& GetCurrentSnapshot();
|
||||||
INPUT_SNAPSHOT& GetNextToCurrentSnapshot();
|
INPUT_SNAPSHOT& GetNextToCurrentSnapshot();
|
||||||
int GetCursorPos();
|
|
||||||
int GetTotalItems();
|
|
||||||
char* GetItemDesc(int pos);
|
char* GetItemDesc(int pos);
|
||||||
bool GetItemCoherence(int pos);
|
bool GetItemCoherence(int pos);
|
||||||
|
int GetUndoHint();
|
||||||
|
|
||||||
|
void GetDispInfo(NMLVDISPINFO* nmlvDispInfo);
|
||||||
|
LONG CustomDraw(NMLVCUSTOMDRAW* msg);
|
||||||
|
void Click(LPNMITEMACTIVATE info);
|
||||||
|
|
||||||
|
void RedrawHistoryList();
|
||||||
|
void UpdateHistoryList();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<INPUT_SNAPSHOT> input_snapshots;
|
std::vector<INPUT_SNAPSHOT> input_snapshots;
|
||||||
|
@ -98,5 +75,9 @@ private:
|
||||||
int history_total_items;
|
int history_total_items;
|
||||||
int history_size;
|
int history_size;
|
||||||
|
|
||||||
|
int undo_hint_pos, old_undo_hint_pos;
|
||||||
|
int undo_hint_time;
|
||||||
|
bool old_show_undo_hint, show_undo_hint;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,334 @@
|
||||||
|
//Implementation file of Input Snapshot class (Undo feature)
|
||||||
|
|
||||||
|
#include "movie.h"
|
||||||
|
#include "inputsnapshot.h"
|
||||||
|
#include "zlib.h"
|
||||||
|
|
||||||
|
const int bytes_per_frame[NUM_SUPPORTED_INPUT_TYPES] = {2, 4}; // 16bits for normal joypads, 32bits for fourscore
|
||||||
|
|
||||||
|
extern void FCEU_printf(char *format, ...);
|
||||||
|
|
||||||
|
INPUT_SNAPSHOT::INPUT_SNAPSHOT()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void INPUT_SNAPSHOT::init(MovieData& md)
|
||||||
|
{
|
||||||
|
// retrieve input data from movie data
|
||||||
|
size = md.getNumRecords();
|
||||||
|
input_type = (md.fourscore)?1:0;
|
||||||
|
joysticks.resize(bytes_per_frame[input_type] * size); // it's much faster to have this format than have [frame][joy] or other structures
|
||||||
|
hot_changes.resize(bytes_per_frame[input_type] * size * HOTCHANGE_BYTES_PER_JOY);
|
||||||
|
// fill input vector
|
||||||
|
int pos = 0;
|
||||||
|
switch(input_type)
|
||||||
|
{
|
||||||
|
case FOURSCORE:
|
||||||
|
{
|
||||||
|
for (int frame = 0; frame < size; ++frame)
|
||||||
|
{
|
||||||
|
joysticks[pos++] = md.records[frame].joysticks[0];
|
||||||
|
joysticks[pos++] = md.records[frame].joysticks[1];
|
||||||
|
joysticks[pos++] = md.records[frame].joysticks[2];
|
||||||
|
joysticks[pos++] = md.records[frame].joysticks[3];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NORMAL_2JOYPADS:
|
||||||
|
{
|
||||||
|
for (int frame = 0; frame < size; ++frame)
|
||||||
|
{
|
||||||
|
joysticks[pos++] = md.records[frame].joysticks[0];
|
||||||
|
joysticks[pos++] = md.records[frame].joysticks[1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
coherent = true;
|
||||||
|
// save time to description
|
||||||
|
time_t raw_time;
|
||||||
|
time(&raw_time);
|
||||||
|
struct tm * timeinfo = localtime(&raw_time);
|
||||||
|
strftime(description, 10, "%H:%M:%S ", timeinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void INPUT_SNAPSHOT::toMovie(MovieData& md, int start)
|
||||||
|
{
|
||||||
|
// write input data to movie data
|
||||||
|
md.records.resize(size);
|
||||||
|
md.frames_flags.resize(size);
|
||||||
|
switch(input_type)
|
||||||
|
{
|
||||||
|
case FOURSCORE:
|
||||||
|
{
|
||||||
|
int pos = start * bytes_per_frame[input_type];
|
||||||
|
for (int frame = start; frame < size; ++frame)
|
||||||
|
{
|
||||||
|
md.records[frame].joysticks[0] = joysticks[pos++];
|
||||||
|
md.records[frame].joysticks[1] = joysticks[pos++];
|
||||||
|
md.records[frame].joysticks[2] = joysticks[pos++];
|
||||||
|
md.records[frame].joysticks[3] = joysticks[pos++];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NORMAL_2JOYPADS:
|
||||||
|
{
|
||||||
|
int pos = start * bytes_per_frame[input_type];
|
||||||
|
for (int frame = start; frame < size; ++frame)
|
||||||
|
{
|
||||||
|
md.records[frame].joysticks[0] = joysticks[pos++];
|
||||||
|
md.records[frame].joysticks[1] = joysticks[pos++];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void INPUT_SNAPSHOT::save(EMUFILE *os)
|
||||||
|
{
|
||||||
|
// write vars
|
||||||
|
write32le(size, os);
|
||||||
|
write8le(input_type, os);
|
||||||
|
if (coherent) write8le(1, os); else write8le((uint8)0, os);
|
||||||
|
write32le(jump_frame, os);
|
||||||
|
// write description
|
||||||
|
int len = strlen(description);
|
||||||
|
write8le(len, os);
|
||||||
|
os->fwrite(&description[0], len);
|
||||||
|
// compress and save joysticks data
|
||||||
|
len = joysticks.size();
|
||||||
|
int comprlen = (len>>9)+12 + len;
|
||||||
|
std::vector<uint8> cbuf(comprlen);
|
||||||
|
int e = compress(cbuf.data(), (uLongf*)&comprlen,(uint8*)joysticks.data(),len);
|
||||||
|
// write size
|
||||||
|
write32le(comprlen, os);
|
||||||
|
os->fwrite(cbuf.data(), comprlen);
|
||||||
|
// compress and save hot_changes data
|
||||||
|
len = hot_changes.size();
|
||||||
|
comprlen = (len>>9)+12 + len;
|
||||||
|
std::vector<uint8> cbuf2(comprlen);
|
||||||
|
e = compress(cbuf2.data(),(uLongf*)&comprlen,(uint8*)hot_changes.data(),len);
|
||||||
|
// write size
|
||||||
|
write32le(comprlen, os);
|
||||||
|
os->fwrite(cbuf2.data(), comprlen);
|
||||||
|
}
|
||||||
|
bool INPUT_SNAPSHOT::load(EMUFILE *is)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
uint8 tmp;
|
||||||
|
// read vars
|
||||||
|
if (!read32le(&size, is)) return false;
|
||||||
|
if (!read8le(&tmp, is)) return false;
|
||||||
|
input_type = tmp;
|
||||||
|
if (!read8le(&tmp, is)) return false;
|
||||||
|
coherent = (tmp != 0);
|
||||||
|
if (!read32le(&jump_frame, is)) return false;
|
||||||
|
// read description
|
||||||
|
if (!read8le(&tmp, is)) return false;
|
||||||
|
if (tmp < 0 || tmp >= SNAPSHOT_DESC_MAX_LENGTH) return false;
|
||||||
|
if (is->fread(&description[0], tmp) != tmp) return false;
|
||||||
|
description[tmp] = 0; // add '0' because it wasn't saved
|
||||||
|
// read and uncompress joysticks data
|
||||||
|
len = size * bytes_per_frame[input_type];
|
||||||
|
joysticks.resize(len);
|
||||||
|
// read size
|
||||||
|
int comprlen;
|
||||||
|
if (!read32le(&comprlen, is)) return false;
|
||||||
|
if (comprlen <= 0 || comprlen > len) return false;
|
||||||
|
std::vector<uint8> cbuf(comprlen);
|
||||||
|
if (is->fread(cbuf.data(),comprlen) != comprlen) return false;
|
||||||
|
int e = uncompress((uint8*)joysticks.data(),(uLongf*)&len,cbuf.data(),comprlen);
|
||||||
|
if (e != Z_OK && e != Z_BUF_ERROR) return false;
|
||||||
|
// read and uncompress hot_changes data
|
||||||
|
len = size * bytes_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||||
|
hot_changes.resize(len);
|
||||||
|
// read size
|
||||||
|
if (!read32le(&comprlen, is)) return false;
|
||||||
|
if (comprlen <= 0 || comprlen > len) return false;
|
||||||
|
std::vector<uint8> cbuf2(comprlen);
|
||||||
|
if (is->fread(cbuf2.data(),comprlen) != comprlen) return false;
|
||||||
|
e = uncompress(hot_changes.data(),(uLongf*)&len,cbuf.data(),comprlen);
|
||||||
|
if (e != Z_OK && e != Z_BUF_ERROR) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool INPUT_SNAPSHOT::skipLoad(EMUFILE *is)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
uint8 tmp1;
|
||||||
|
// read vars
|
||||||
|
if (!read32le(&tmp, is)) return false;
|
||||||
|
if (!read8le(&tmp1, is)) return false;
|
||||||
|
if (!read8le(&tmp1, is)) return false;
|
||||||
|
if (!read32le(&tmp, is)) return false;
|
||||||
|
// read description
|
||||||
|
if (!read8le(&tmp1, is)) return false;
|
||||||
|
if (tmp1 < 0 || tmp1 >= SNAPSHOT_DESC_MAX_LENGTH) return false;
|
||||||
|
if (is->fseek(tmp1, SEEK_CUR) != 0) return false;
|
||||||
|
// read joysticks data
|
||||||
|
if (!read32le(&tmp, is)) return false;
|
||||||
|
if (is->fseek(tmp, SEEK_CUR) != 0) return false;
|
||||||
|
// read hot_changes data
|
||||||
|
if (!read32le(&tmp, is)) return false;
|
||||||
|
if (is->fseek(tmp, SEEK_CUR) != 0) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if any difference is found
|
||||||
|
bool INPUT_SNAPSHOT::checkDiff(INPUT_SNAPSHOT& inp)
|
||||||
|
{
|
||||||
|
if (size != inp.size) return true;
|
||||||
|
if (findFirstChange(inp) >= 0)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if joypads differ
|
||||||
|
bool INPUT_SNAPSHOT::checkJoypadDiff(INPUT_SNAPSHOT& inp, int frame, int joy)
|
||||||
|
{
|
||||||
|
switch(input_type)
|
||||||
|
{
|
||||||
|
case FOURSCORE:
|
||||||
|
case NORMAL_2JOYPADS:
|
||||||
|
{
|
||||||
|
int pos = frame * bytes_per_frame[input_type];
|
||||||
|
if (pos < (inp.size * bytes_per_frame[input_type]))
|
||||||
|
{
|
||||||
|
if (joysticks[pos+joy] != inp.joysticks[pos+joy]) return true;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if (joysticks[pos+joy]) return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// return number of first frame of difference
|
||||||
|
int INPUT_SNAPSHOT::findFirstChange(INPUT_SNAPSHOT& inp, int start, int end)
|
||||||
|
{
|
||||||
|
// search for differences to the specified end (or to size)
|
||||||
|
if (end < 0 || end >= size) end = size-1;
|
||||||
|
|
||||||
|
switch(input_type)
|
||||||
|
{
|
||||||
|
case FOURSCORE:
|
||||||
|
case NORMAL_2JOYPADS:
|
||||||
|
{
|
||||||
|
int inp_end = inp.size * bytes_per_frame[input_type];
|
||||||
|
end = ((end + 1) * bytes_per_frame[input_type]) - 1;
|
||||||
|
for (int pos = start * bytes_per_frame[input_type]; pos <= end; ++pos)
|
||||||
|
{
|
||||||
|
// if found different byte, or found emptiness in inp when there's non-zero value here
|
||||||
|
if (pos < inp_end)
|
||||||
|
{
|
||||||
|
if (joysticks[pos] != inp.joysticks[pos]) return (pos / bytes_per_frame[input_type]);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if (joysticks[pos]) return (pos / bytes_per_frame[input_type]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if current size is less then previous return size-1 as the frame of difference
|
||||||
|
if (size < inp.size) return size-1;
|
||||||
|
// no changes were found
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int INPUT_SNAPSHOT::findFirstChange(MovieData& md)
|
||||||
|
{
|
||||||
|
// search for differences from the beginning to the end of movie (or to size)
|
||||||
|
int end = md.getNumRecords()-1;
|
||||||
|
if (end >= size) end = size-1;
|
||||||
|
|
||||||
|
switch(input_type)
|
||||||
|
{
|
||||||
|
case FOURSCORE:
|
||||||
|
{
|
||||||
|
for (int frame = 0, pos = 0; frame <= end; ++frame)
|
||||||
|
{
|
||||||
|
if (joysticks[pos++] != md.records[frame].joysticks[0]) return frame;
|
||||||
|
if (joysticks[pos++] != md.records[frame].joysticks[1]) return frame;
|
||||||
|
if (joysticks[pos++] != md.records[frame].joysticks[2]) return frame;
|
||||||
|
if (joysticks[pos++] != md.records[frame].joysticks[3]) return frame;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NORMAL_2JOYPADS:
|
||||||
|
{
|
||||||
|
for (int frame = 0, pos = 0; frame <= end; ++frame)
|
||||||
|
{
|
||||||
|
if (joysticks[pos++] != md.records[frame].joysticks[0]) return frame;
|
||||||
|
if (joysticks[pos++] != md.records[frame].joysticks[1]) return frame;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if sizes differ, return last frame from the lesser of them
|
||||||
|
if (size != md.getNumRecords()) return end;
|
||||||
|
|
||||||
|
return -1; // no changes were found
|
||||||
|
}
|
||||||
|
|
||||||
|
void INPUT_SNAPSHOT::SetMaxHotChange(int frame, int absolute_button)
|
||||||
|
{
|
||||||
|
if (frame < 0 || frame >= size) return;
|
||||||
|
// set max value (15) to the button hotness
|
||||||
|
switch(input_type)
|
||||||
|
{
|
||||||
|
case FOURSCORE:
|
||||||
|
{
|
||||||
|
// 32 buttons = 16bytes
|
||||||
|
if (absolute_button & 1)
|
||||||
|
// odd buttons (B, T, D, R) - set upper 4 bits of the byte
|
||||||
|
hot_changes[(frame << 4) | (absolute_button >> 1)] &= 0xF0;
|
||||||
|
else
|
||||||
|
// even buttons (A, S, U, L) - set lower 4 bits of the byte
|
||||||
|
hot_changes[(frame << 4) | (absolute_button >> 1)] &= 0x0F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NORMAL_2JOYPADS:
|
||||||
|
{
|
||||||
|
// 16 buttons = 8bytes
|
||||||
|
if (absolute_button & 1)
|
||||||
|
// odd buttons (B, T, D, R) - set upper 4 bits of the byte
|
||||||
|
hot_changes[(frame << 3) | (absolute_button >> 1)] &= 0xF0;
|
||||||
|
else
|
||||||
|
// even buttons (A, S, U, L) - set lower 4 bits of the byte
|
||||||
|
hot_changes[(frame << 3) | (absolute_button >> 1)] &= 0x0F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int INPUT_SNAPSHOT::GetHotChangeInfo(int frame, int absolute_button)
|
||||||
|
{
|
||||||
|
if (frame < 0 || frame >= size) return 0;
|
||||||
|
if (absolute_button < 0 || absolute_button > 31) return 0;
|
||||||
|
|
||||||
|
uint8 val;
|
||||||
|
switch(input_type)
|
||||||
|
{
|
||||||
|
case FOURSCORE:
|
||||||
|
{
|
||||||
|
// 32 buttons, 16bytes
|
||||||
|
val = hot_changes[(frame << 4) + (absolute_button >> 1)];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NORMAL_2JOYPADS:
|
||||||
|
{
|
||||||
|
// 16 buttons, 8bytes
|
||||||
|
val = hot_changes[(frame << 3) + (absolute_button >> 1)];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (absolute_button & 1)
|
||||||
|
// odd buttons (B, T, D, R) - upper 4 bits of the byte
|
||||||
|
return val >> 4;
|
||||||
|
else
|
||||||
|
// even buttons (A, S, U, L) - lower 4 bits of the byte
|
||||||
|
return val & 15;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
//Specification file for Input Snapshot class
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define HOTCHANGE_BYTES_PER_JOY 4
|
||||||
|
#define SNAPSHOT_DESC_MAX_LENGTH 50
|
||||||
|
|
||||||
|
#define NUM_SUPPORTED_INPUT_TYPES 2
|
||||||
|
#define NORMAL_2JOYPADS 0
|
||||||
|
#define FOURSCORE 1
|
||||||
|
|
||||||
|
class INPUT_SNAPSHOT
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
INPUT_SNAPSHOT();
|
||||||
|
void init(MovieData& md);
|
||||||
|
void toMovie(MovieData& md, int start = 0);
|
||||||
|
|
||||||
|
void save(EMUFILE *os);
|
||||||
|
bool load(EMUFILE *is);
|
||||||
|
bool skipLoad(EMUFILE *is);
|
||||||
|
|
||||||
|
bool checkDiff(INPUT_SNAPSHOT& inp);
|
||||||
|
bool checkJoypadDiff(INPUT_SNAPSHOT& inp, int frame, int joy);
|
||||||
|
int findFirstChange(INPUT_SNAPSHOT& inp, int start = 0, int end = -1);
|
||||||
|
int findFirstChange(MovieData& md);
|
||||||
|
|
||||||
|
void SetMaxHotChange(int frame, int absolute_button);
|
||||||
|
int GetHotChangeInfo(int frame, int absolute_button);
|
||||||
|
|
||||||
|
int size; // in frames
|
||||||
|
int input_type; // 0=normal, 1=fourscore, in future may support other input types
|
||||||
|
std::vector<uint8> joysticks; // Format: joy0-for-frame0, joy1-for-frame0, joy2-for-frame0, joy3-for-frame0, joy0-for-frame1, joy1-for-frame1, ...
|
||||||
|
std::vector<uint8> hot_changes; // Format: buttons01joy0-for-frame0, buttons23joy0-for-frame0, buttons45joy0-for-frame0, buttons67joy0-for-frame0, buttons01joy1-for-frame0, ...
|
||||||
|
|
||||||
|
bool coherent; // indicates whether this state was made by inputchange of previous state
|
||||||
|
int jump_frame; // for jumping when making undo
|
||||||
|
char description[SNAPSHOT_DESC_MAX_LENGTH];
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,239 @@
|
||||||
|
//Implementation file of Playback class
|
||||||
|
|
||||||
|
#include "movie.h"
|
||||||
|
#include "../common.h"
|
||||||
|
#include "taseditproj.h"
|
||||||
|
#include "../tasedit.h"
|
||||||
|
|
||||||
|
extern HWND hwndProgressbar, hwndList, hwndRewind, hwndForward;
|
||||||
|
extern void FCEU_printf(char *format, ...);
|
||||||
|
extern bool turbo;
|
||||||
|
extern GREENZONE greenzone;
|
||||||
|
|
||||||
|
PLAYBACK::PLAYBACK()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLAYBACK::init()
|
||||||
|
{
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
void PLAYBACK::reset()
|
||||||
|
{
|
||||||
|
lastCursor = -1;
|
||||||
|
pauseframe = old_pauseframe = 0;
|
||||||
|
old_show_pauseframe = show_pauseframe = false;
|
||||||
|
old_rewind_button_state = rewind_button_state = false;
|
||||||
|
old_forward_button_state = forward_button_state = false;
|
||||||
|
old_emu_paused = emu_paused = true;
|
||||||
|
SeekingStop();
|
||||||
|
}
|
||||||
|
void PLAYBACK::update()
|
||||||
|
{
|
||||||
|
// pause when seeking hit pauseframe
|
||||||
|
if(!FCEUI_EmulationPaused())
|
||||||
|
if(pauseframe && pauseframe <= currFrameCounter + 1)
|
||||||
|
SeekingStop();
|
||||||
|
|
||||||
|
// update seeking progressbar
|
||||||
|
old_emu_paused = emu_paused;
|
||||||
|
emu_paused = (FCEUI_EmulationPaused() != 0);
|
||||||
|
if (pauseframe && !emu_paused)
|
||||||
|
{
|
||||||
|
SetProgressbar(currFrameCounter - seeking_start_frame, pauseframe-seeking_start_frame);
|
||||||
|
} else if (old_emu_paused != emu_paused)
|
||||||
|
{
|
||||||
|
// emulator got paused/unpaused externally
|
||||||
|
if (old_emu_paused && !emu_paused)
|
||||||
|
// externally unpaused - progressbar should be empty
|
||||||
|
SetProgressbar(0, 1);
|
||||||
|
else
|
||||||
|
// externally paused - progressbar should be full
|
||||||
|
SetProgressbar(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update flashing pauseframe
|
||||||
|
if (old_pauseframe != pauseframe && old_pauseframe) RedrawRow(old_pauseframe-1);
|
||||||
|
old_pauseframe = pauseframe;
|
||||||
|
old_show_pauseframe = show_pauseframe;
|
||||||
|
if (pauseframe)
|
||||||
|
show_pauseframe = (int)(clock() / PAUSEFRAME_BLINKING_PERIOD) & 1;
|
||||||
|
else
|
||||||
|
show_pauseframe = false;
|
||||||
|
if (old_show_pauseframe != show_pauseframe) RedrawRow(pauseframe-1);
|
||||||
|
|
||||||
|
//update the playback cursor
|
||||||
|
if(currFrameCounter != lastCursor)
|
||||||
|
{
|
||||||
|
FollowPlayback();
|
||||||
|
//update the old and new rows
|
||||||
|
RedrawRow(lastCursor);
|
||||||
|
RedrawRow(currFrameCounter);
|
||||||
|
UpdateWindow(hwndList);
|
||||||
|
lastCursor = currFrameCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update < and > buttons
|
||||||
|
if(emu_paused)
|
||||||
|
{
|
||||||
|
old_rewind_button_state = rewind_button_state;
|
||||||
|
rewind_button_state = (Button_GetState(hwndRewind) & BST_PUSHED) != 0;
|
||||||
|
if (rewind_button_state)
|
||||||
|
{
|
||||||
|
if (!old_rewind_button_state)
|
||||||
|
{
|
||||||
|
button_hold_time = clock();
|
||||||
|
RewindFrame();
|
||||||
|
} else if (button_hold_time + HOLD_REPEAT_DELAY < clock())
|
||||||
|
{
|
||||||
|
RewindFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_forward_button_state = forward_button_state;
|
||||||
|
forward_button_state = (Button_GetState(hwndForward) & BST_PUSHED) != 0;
|
||||||
|
if (forward_button_state)
|
||||||
|
{
|
||||||
|
if (!old_forward_button_state)
|
||||||
|
{
|
||||||
|
button_hold_time = clock();
|
||||||
|
ForwardFrame();
|
||||||
|
} else if (button_hold_time + HOLD_REPEAT_DELAY < clock())
|
||||||
|
{
|
||||||
|
ForwardFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLAYBACK::updateProgressbar()
|
||||||
|
{
|
||||||
|
if (pauseframe)
|
||||||
|
{
|
||||||
|
SetProgressbar(currFrameCounter - seeking_start_frame, pauseframe-seeking_start_frame);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if (emu_paused)
|
||||||
|
SetProgressbar(1, 1);
|
||||||
|
else
|
||||||
|
SetProgressbar(0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLAYBACK::ToggleEmulationPause()
|
||||||
|
{
|
||||||
|
if (FCEUI_EmulationPaused())
|
||||||
|
UnpauseEmulation();
|
||||||
|
else
|
||||||
|
PauseEmulation();
|
||||||
|
}
|
||||||
|
void PLAYBACK::PauseEmulation()
|
||||||
|
{
|
||||||
|
FCEUI_SetEmulationPaused(1);
|
||||||
|
// make some additional stuff
|
||||||
|
}
|
||||||
|
void PLAYBACK::UnpauseEmulation()
|
||||||
|
{
|
||||||
|
FCEUI_SetEmulationPaused(0);
|
||||||
|
// make some additional stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLAYBACK::SeekingStart(int finish_frame)
|
||||||
|
{
|
||||||
|
seeking_start_frame = currFrameCounter;
|
||||||
|
pauseframe = finish_frame;
|
||||||
|
turbo = true;
|
||||||
|
UnpauseEmulation();
|
||||||
|
}
|
||||||
|
void PLAYBACK::SeekingStop()
|
||||||
|
{
|
||||||
|
pauseframe = 0;
|
||||||
|
turbo = false;
|
||||||
|
PauseEmulation();
|
||||||
|
SetProgressbar(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLAYBACK::RewindFrame()
|
||||||
|
{
|
||||||
|
if (currFrameCounter > 0) JumpToFrame(currFrameCounter-1);
|
||||||
|
turbo = false;
|
||||||
|
FollowPlayback();
|
||||||
|
}
|
||||||
|
void PLAYBACK::ForwardFrame()
|
||||||
|
{
|
||||||
|
JumpToFrame(currFrameCounter+1);
|
||||||
|
turbo = false;
|
||||||
|
FollowPlayback();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLAYBACK::StartFromZero()
|
||||||
|
{
|
||||||
|
poweron(true);
|
||||||
|
currFrameCounter = 0;
|
||||||
|
greenzone.TryDumpIncremental();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PLAYBACK::JumpToFrame(int index)
|
||||||
|
{
|
||||||
|
// Returns true if a jump to the frame is made, false if started seeking or if nothing's done
|
||||||
|
if (index<0) return false;
|
||||||
|
|
||||||
|
if (index >= greenzone.greenZoneCount)
|
||||||
|
{
|
||||||
|
// handle jump outside greenzone
|
||||||
|
if (JumpToFrame(greenzone.greenZoneCount-1))
|
||||||
|
// seek from the end of greenzone
|
||||||
|
SeekingStart(index+1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Handle jumps inside greenzone. */
|
||||||
|
if (greenzone.loadTasSavestate(index))
|
||||||
|
{
|
||||||
|
currFrameCounter = index;
|
||||||
|
turbo = false;
|
||||||
|
// if playback was seeking, pause emulation right here
|
||||||
|
if (pauseframe) SeekingStop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//Search for an earlier frame with savestate
|
||||||
|
int i = (index>0)? index-1 : 0;
|
||||||
|
for (; i > 0; i--)
|
||||||
|
{
|
||||||
|
if (greenzone.loadTasSavestate(i)) break;
|
||||||
|
}
|
||||||
|
if (!i)
|
||||||
|
StartFromZero();
|
||||||
|
else
|
||||||
|
currFrameCounter = i;
|
||||||
|
// continue from the frame
|
||||||
|
SeekingStart(index+1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLAYBACK::restorePosition()
|
||||||
|
{
|
||||||
|
if (pauseframe)
|
||||||
|
JumpToFrame(pauseframe-1);
|
||||||
|
else
|
||||||
|
JumpToFrame(currFrameCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PLAYBACK::GetPauseFrame()
|
||||||
|
{
|
||||||
|
if (show_pauseframe)
|
||||||
|
return pauseframe-1;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLAYBACK::SetProgressbar(int a, int b)
|
||||||
|
{
|
||||||
|
SendMessage(hwndProgressbar, PBM_SETPOS, PROGRESSBAR_WIDTH * a / b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
//Specification file for Playback class
|
||||||
|
|
||||||
|
#define PAUSEFRAME_BLINKING_PERIOD 100
|
||||||
|
#define HOLD_REPEAT_DELAY 250 // in milliseconds
|
||||||
|
|
||||||
|
|
||||||
|
class PLAYBACK
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PLAYBACK();
|
||||||
|
void init();
|
||||||
|
void reset();
|
||||||
|
void update();
|
||||||
|
|
||||||
|
void updateProgressbar();
|
||||||
|
|
||||||
|
void SeekingStart(int finish_frame);
|
||||||
|
void SeekingStop();
|
||||||
|
void ToggleEmulationPause();
|
||||||
|
void PauseEmulation();
|
||||||
|
void UnpauseEmulation();
|
||||||
|
|
||||||
|
void RewindFrame();
|
||||||
|
void ForwardFrame();
|
||||||
|
|
||||||
|
bool JumpToFrame(int index);
|
||||||
|
void restorePosition();
|
||||||
|
|
||||||
|
void StartFromZero();
|
||||||
|
|
||||||
|
int GetPauseFrame();
|
||||||
|
void SetProgressbar(int a, int b);
|
||||||
|
|
||||||
|
int pauseframe;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int lastCursor; // for currentCursor we use external variable currFrameCounter
|
||||||
|
bool old_emu_paused, emu_paused;
|
||||||
|
int old_pauseframe;
|
||||||
|
bool old_show_pauseframe, show_pauseframe;
|
||||||
|
bool old_rewind_button_state, rewind_button_state;
|
||||||
|
bool old_forward_button_state, forward_button_state;
|
||||||
|
int button_hold_time;
|
||||||
|
int seeking_start_frame;
|
||||||
|
|
||||||
|
};
|
|
@ -1,34 +1,89 @@
|
||||||
//Implementation file of TASEdit Project file object
|
//Implementation file of TASEdit Project class
|
||||||
|
|
||||||
//Contains all the TASEDit project and all files/settings associated with it
|
|
||||||
//Also contains all methods for manipulating the project files/settings, and saving them to disk
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include "../main.h"
|
#include "../main.h"
|
||||||
#include "taseditproj.h"
|
#include "taseditproj.h"
|
||||||
|
|
||||||
|
extern INPUT_HISTORY history;
|
||||||
|
extern PLAYBACK playback;
|
||||||
|
extern GREENZONE greenzone;
|
||||||
|
|
||||||
|
extern void FCEU_printf(char *format, ...);
|
||||||
|
|
||||||
TASEDIT_PROJECT::TASEDIT_PROJECT() //Non parameterized constructor, loads project with default values
|
TASEDIT_PROJECT::TASEDIT_PROJECT() //Non parameterized constructor, loads project with default values
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TASEDIT_PROJECT::init(INPUT_HISTORY* history_ptr)
|
void TASEDIT_PROJECT::init()
|
||||||
{
|
{
|
||||||
// keep references to other Taseditor objects
|
|
||||||
history = history_ptr;
|
|
||||||
//greenzone = greenzone_ptr;
|
|
||||||
//bookmarks_bookmarks_ptr;
|
|
||||||
|
|
||||||
|
// init new project
|
||||||
projectName="";
|
projectName="";
|
||||||
fm2FileName="";
|
fm2FileName="";
|
||||||
projectFile="";
|
projectFile="";
|
||||||
|
|
||||||
changed=false;
|
reset();
|
||||||
|
}
|
||||||
|
void TASEDIT_PROJECT::reset()
|
||||||
|
{
|
||||||
|
old_changed = changed = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
void TASEDIT_PROJECT::update()
|
||||||
|
{
|
||||||
|
old_changed = changed;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: a parameterized constructor that can serve as an import fm2 function
|
bool TASEDIT_PROJECT::saveProject()
|
||||||
|
{
|
||||||
|
std::string PFN = GetProjectFile();
|
||||||
|
if (PFN.empty()) return false;
|
||||||
|
const char* filename = PFN.c_str();
|
||||||
|
EMUFILE_FILE* ofs = FCEUD_UTF8_fstream(filename,"wb");
|
||||||
|
//ofs << GetProjectName() << std::endl;
|
||||||
|
//ofs << GetFM2Name() << std::endl;
|
||||||
|
|
||||||
|
currMovieData.dump(ofs, true);
|
||||||
|
greenzone.dumpGreenzone(ofs);
|
||||||
|
history.save(ofs);
|
||||||
|
|
||||||
|
delete ofs;
|
||||||
|
|
||||||
|
playback.updateProgressbar();
|
||||||
|
this->reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader);
|
||||||
|
|
||||||
|
|
||||||
|
bool TASEDIT_PROJECT::LoadProject(std::string PFN)
|
||||||
|
{
|
||||||
|
const char* filename = PFN.c_str();
|
||||||
|
|
||||||
|
EMUFILE_FILE ifs(filename, "rb");
|
||||||
|
|
||||||
|
FCEU_printf("Loading project %s\n", filename);
|
||||||
|
|
||||||
|
LoadFM2(currMovieData, &ifs, ifs.size(), false);
|
||||||
|
LoadSubtitles(currMovieData);
|
||||||
|
|
||||||
|
// try to load greenzone
|
||||||
|
if (!greenzone.loadGreenzone(&ifs))
|
||||||
|
{
|
||||||
|
// there was some error while loading greenzone - reset playback to frame 0
|
||||||
|
poweron(true);
|
||||||
|
currFrameCounter = 0;
|
||||||
|
// try to load history
|
||||||
|
history.load(&ifs);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// -----------------------------------------------------------------
|
||||||
//All the get/set functions...
|
//All the get/set functions...
|
||||||
std::string TASEDIT_PROJECT::GetProjectName()
|
std::string TASEDIT_PROJECT::GetProjectName()
|
||||||
{
|
{
|
||||||
|
@ -55,53 +110,3 @@ void TASEDIT_PROJECT::SetProjectFile(std::string e)
|
||||||
projectFile = e;
|
projectFile = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TASEDIT_PROJECT::saveProject()
|
|
||||||
{
|
|
||||||
std::string PFN = GetProjectFile();
|
|
||||||
if (PFN.empty()) return false;
|
|
||||||
const char* filename = PFN.c_str();
|
|
||||||
EMUFILE_FILE* ofs = FCEUD_UTF8_fstream(filename,"wb");
|
|
||||||
//ofs << GetProjectName() << std::endl;
|
|
||||||
//ofs << GetFM2Name() << std::endl;
|
|
||||||
|
|
||||||
currMovieData.dump(ofs, true);
|
|
||||||
ofs->fputc('\0'); // TODO: Add main branch name.
|
|
||||||
currMovieData.dumpGreenzone(ofs);
|
|
||||||
|
|
||||||
history->save(ofs);
|
|
||||||
|
|
||||||
delete ofs;
|
|
||||||
|
|
||||||
changed=false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader);
|
|
||||||
|
|
||||||
|
|
||||||
bool TASEDIT_PROJECT::LoadProject(std::string PFN)
|
|
||||||
{
|
|
||||||
const char* filename = PFN.c_str();
|
|
||||||
|
|
||||||
EMUFILE_FILE ifs(filename, "rb");
|
|
||||||
|
|
||||||
LoadFM2(currMovieData, &ifs, ifs.size(), false);
|
|
||||||
LoadSubtitles(currMovieData);
|
|
||||||
|
|
||||||
char branchname;
|
|
||||||
branchname = ifs.fgetc(); // TODO: Add main branch name.
|
|
||||||
|
|
||||||
// try to load greenzone
|
|
||||||
if (!currMovieData.loadGreenzone(&ifs))
|
|
||||||
{
|
|
||||||
// there was some error while loading greenzone - reset playback to frame 0
|
|
||||||
poweron(true);
|
|
||||||
currFrameCounter = 0;
|
|
||||||
}
|
|
||||||
// try to load history
|
|
||||||
history->load(&ifs);
|
|
||||||
|
|
||||||
changed = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,82 +1,40 @@
|
||||||
//Specification file for the TASEdit Project file object
|
//Specification file for the TASEdit Project class
|
||||||
//Written by Chris220
|
|
||||||
|
|
||||||
//Contains all the TASEDit project and all files/settings associated with it
|
|
||||||
//Also contains all methods for manipulating the project files/settings, and saving them to disk
|
|
||||||
|
|
||||||
|
|
||||||
//adelikat: How this needs to be structured conceptually
|
|
||||||
//A project is just all the settings and associated files
|
|
||||||
//No fm2 data shoudl be loaded here, instead all input logs that are unsaved should be stored in .ilog files which are stripped fm2 (no header info)
|
|
||||||
//When saving a project all ilog files are saved to disk if necessary, and the .tas project file is saved
|
|
||||||
//The "main branch" will be an ilog file too, but probably a special case from the others
|
|
||||||
|
|
||||||
//When loading, all settings are loaded into the project, all .ilog files are loaded, the main branch .log is loaded as the current fm2 file in the emulator
|
|
||||||
//The greenzone is loaded as well
|
|
||||||
//All notes are added to teh right columns
|
|
||||||
//All ilog files are listed in the input log list
|
|
||||||
|
|
||||||
#include "movie.h"
|
#include "movie.h"
|
||||||
|
#include "inputsnapshot.h"
|
||||||
#include "inputhistory.h"
|
#include "inputhistory.h"
|
||||||
|
#include "playback.h"
|
||||||
//The notes feature, displays user notes in the notes column
|
#include "greenzone.h"
|
||||||
struct TASENote
|
|
||||||
{
|
|
||||||
std::string note;
|
|
||||||
int frame;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Movie header info
|
|
||||||
struct TASEHeader
|
|
||||||
{
|
|
||||||
int version; //Will always be 3 but might as well store it
|
|
||||||
int emuVersion;
|
|
||||||
bool palFlag;
|
|
||||||
std::string romFilename;
|
|
||||||
std::string romChecksum;
|
|
||||||
std::string guid;
|
|
||||||
bool fourscore; //note: TASEdit probably won't support 4 player input for quite some time
|
|
||||||
bool microphone;
|
|
||||||
bool port0; //Always true
|
|
||||||
bool port1; //Should always be true for now at least
|
|
||||||
bool port2; //Will need to always be false until fourscore is supported
|
|
||||||
bool FDS;
|
|
||||||
bool NewPPU; //Let's make this always false for now as to not support new PPU (until it is ready)
|
|
||||||
};
|
|
||||||
|
|
||||||
class TASEDIT_PROJECT
|
class TASEDIT_PROJECT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TASEDIT_PROJECT();
|
TASEDIT_PROJECT();
|
||||||
void init(INPUT_HISTORY* history_ptr);
|
void init();
|
||||||
|
void reset();
|
||||||
std::string GetProjectName();
|
void update();
|
||||||
void SetProjectName(std::string e);
|
|
||||||
|
|
||||||
std::string GetFM2Name();
|
|
||||||
void SetFM2Name(std::string e);
|
|
||||||
|
|
||||||
std::string GetProjectFile();
|
|
||||||
void SetProjectFile(std::string e);
|
|
||||||
|
|
||||||
bool saveProject();
|
bool saveProject();
|
||||||
bool LoadProject(std::string PFN);
|
bool LoadProject(std::string PFN);
|
||||||
|
|
||||||
bool Export2FM2(std::string filename); //creates a fm2 out of header, comments, subtitles, and main branch input log, return false if any errors occur
|
bool Export2FM2(std::string filename); //creates a fm2 out of header, comments, subtitles, and main branch input log, return false if any errors occur
|
||||||
|
|
||||||
|
std::string GetProjectName();
|
||||||
|
void SetProjectName(std::string e);
|
||||||
|
std::string GetFM2Name();
|
||||||
|
void SetFM2Name(std::string e);
|
||||||
|
std::string GetProjectFile();
|
||||||
|
void SetProjectFile(std::string e);
|
||||||
|
|
||||||
// public vars
|
// public vars
|
||||||
bool changed;
|
bool changed, old_changed;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string projectName; //The TASEdit Project's name
|
std::string projectName; //The TASEdit Project's name
|
||||||
std::string fm2FileName; //The main branch ilog file (todo rename more appropriately)
|
std::string fm2FileName; //The main branch ilog file (todo rename more appropriately)
|
||||||
std::string projectFile; //The TASEdit Project's filename (For saving purposes) //adelikat: TODO: why the hell is this different from project name??!
|
std::string projectFile; //The TASEdit Project's filename (For saving purposes) //adelikat: TODO: why the hell is this different from project name??!
|
||||||
std::vector<TASENote> notes; //User notes
|
|
||||||
std::vector<std::string> inputlogs; //List of associated .ilog files
|
std::vector<std::string> inputlogs; //List of associated .ilog files
|
||||||
TASEHeader header;
|
|
||||||
std::vector<std::string> comments;
|
std::vector<std::string> comments;
|
||||||
std::vector<std::string> subtitles;
|
std::vector<std::string> subtitles;
|
||||||
|
|
||||||
// references to other important objects of Taseditor
|
|
||||||
INPUT_HISTORY* history;
|
|
||||||
};
|
};
|
||||||
|
|
11
src/fceu.cpp
11
src/fceu.cpp
|
@ -52,6 +52,9 @@
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include "drivers/win/pref.h"
|
#include "drivers/win/pref.h"
|
||||||
|
|
||||||
|
#include "drivers/win/taseditlib/greenzone.h"
|
||||||
|
extern GREENZONE greenzone;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -713,11 +716,13 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
||||||
}
|
}
|
||||||
else justLagged = false;
|
else justLagged = false;
|
||||||
|
|
||||||
// auto-savestates for TASEditor
|
|
||||||
currMovieData.TryDumpIncremental();
|
|
||||||
|
|
||||||
if (movieSubtitles)
|
if (movieSubtitles)
|
||||||
ProcessSubtitles();
|
ProcessSubtitles();
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if(FCEUMOV_Mode(MOVIEMODE_TASEDIT))
|
||||||
|
greenzone.TryDumpIncremental(lagFlag);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_CloseGame(void)
|
void FCEUI_CloseGame(void)
|
||||||
|
|
210
src/movie.cpp
210
src/movie.cpp
|
@ -37,12 +37,12 @@
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "./drivers/win/common.h"
|
#include "./drivers/win/common.h"
|
||||||
#include "./drivers/win/tasedit.h"
|
|
||||||
#include "./drivers/win/window.h"
|
#include "./drivers/win/window.h"
|
||||||
extern void AddRecentMovieFile(const char *filename);
|
extern void AddRecentMovieFile(const char *filename);
|
||||||
|
|
||||||
extern void UpdateProgressbar(int a, int b);
|
extern void InputChangedRec();
|
||||||
|
extern int TASEdit_greenzone_capacity;
|
||||||
|
extern bool TASEdit_bind_markers;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -51,10 +51,6 @@ using namespace std;
|
||||||
|
|
||||||
extern char FileBase[];
|
extern char FileBase[];
|
||||||
extern bool AutoSS; //Declared in fceu.cpp, keeps track if a auto-savestate has been made
|
extern bool AutoSS; //Declared in fceu.cpp, keeps track if a auto-savestate has been made
|
||||||
#ifdef WIN32
|
|
||||||
extern int TASEdit_greenzone_capacity;
|
|
||||||
extern bool TASEdit_bind_markers;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::vector<int> subtitleFrames; //Frame numbers for subtitle messages
|
std::vector<int> subtitleFrames; //Frame numbers for subtitle messages
|
||||||
std::vector<string> subtitleMessages; //Messages of subtitles
|
std::vector<string> subtitleMessages; //Messages of subtitles
|
||||||
|
@ -154,56 +150,6 @@ void MovieData::cloneRegion(int at, int frames)
|
||||||
records[i+at].Clone(records[i+at+frames]);
|
records[i+at].Clone(records[i+at+frames]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MovieData::TryDumpIncremental()
|
|
||||||
{
|
|
||||||
if(movieMode == MOVIEMODE_TASEDIT)
|
|
||||||
{
|
|
||||||
// if movie length is less than currFrame, pad it with empty frames
|
|
||||||
if(currFrameCounter >= (int)currMovieData.records.size() || currMovieData.records.size()==0)
|
|
||||||
currMovieData.insertEmpty(-1, 1 + currFrameCounter - (int)currMovieData.records.size());
|
|
||||||
//always log savestates in taseditor mode
|
|
||||||
currMovieData.storeTasSavestate(currFrameCounter, Z_DEFAULT_COMPRESSION);
|
|
||||||
// also log frame_flags
|
|
||||||
if (currFrameCounter > 0)
|
|
||||||
{
|
|
||||||
// lagFlag indicates that lag was in previous frame
|
|
||||||
if (lagFlag)
|
|
||||||
currMovieData.frames_flags[currFrameCounter-1] |= LAG_FLAG_BIT;
|
|
||||||
else
|
|
||||||
currMovieData.frames_flags[currFrameCounter-1] &= ~LAG_FLAG_BIT;
|
|
||||||
}
|
|
||||||
// update greenzone upper limit
|
|
||||||
if (currMovieData.greenZoneCount <= currFrameCounter)
|
|
||||||
currMovieData.greenZoneCount = currFrameCounter+1;
|
|
||||||
|
|
||||||
ClearGreenzoneTail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MovieData::ClearGreenzoneTail()
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
int tail_frame = currMovieData.greenZoneCount-1 - TASEdit_greenzone_capacity;
|
|
||||||
#else
|
|
||||||
int tail_frame = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (tail_frame >= currFrameCounter) tail_frame = currFrameCounter - 1;
|
|
||||||
for (;tail_frame >= 0; tail_frame--)
|
|
||||||
{
|
|
||||||
if (currMovieData.savestates[tail_frame].empty()) break;
|
|
||||||
ClearSavestate(tail_frame);
|
|
||||||
#ifdef WIN32
|
|
||||||
RedrawRow(tail_frame);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void MovieData::ClearSavestate(int index)
|
|
||||||
{
|
|
||||||
std::vector<uint8> tmp;
|
|
||||||
currMovieData.savestates[index].swap(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
MovieRecord::MovieRecord()
|
MovieRecord::MovieRecord()
|
||||||
{
|
{
|
||||||
joysticks.data[0] = 0;
|
joysticks.data[0] = 0;
|
||||||
|
@ -468,7 +414,6 @@ MovieData::MovieData()
|
||||||
, PPUflag(false)
|
, PPUflag(false)
|
||||||
, rerecordCount(0)
|
, rerecordCount(0)
|
||||||
, binaryFlag(false)
|
, binaryFlag(false)
|
||||||
, greenZoneCount(0)
|
|
||||||
, microphone(false)
|
, microphone(false)
|
||||||
{
|
{
|
||||||
memset(&romChecksum,0,sizeof(MD5DATA));
|
memset(&romChecksum,0,sizeof(MD5DATA));
|
||||||
|
@ -580,125 +525,6 @@ int MovieData::dump(EMUFILE *os, bool binary)
|
||||||
return end-start;
|
return end-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MovieData::clearGreenzone()
|
|
||||||
{
|
|
||||||
int size = currMovieData.savestates.size();
|
|
||||||
for (int i = 0; i < size; ++i)
|
|
||||||
{
|
|
||||||
ClearSavestate(i);
|
|
||||||
}
|
|
||||||
greenZoneCount = 1;
|
|
||||||
currMovieData.frames_flags.resize(1);
|
|
||||||
// reset lua_colorings
|
|
||||||
// reset monitorings
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int MovieData::dumpGreenzone(EMUFILE *os)
|
|
||||||
{
|
|
||||||
int start = os->ftell();
|
|
||||||
int frame, size;
|
|
||||||
int last_tick = 0;
|
|
||||||
// write size
|
|
||||||
write32le(greenZoneCount, os);
|
|
||||||
write32le(currFrameCounter, os);
|
|
||||||
// write savestates
|
|
||||||
for (frame = 0; frame < greenZoneCount; ++frame)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
// update TASEditor progressbar from time to time
|
|
||||||
if (frame / PROGRESSBAR_UPDATE_RATE > last_tick)
|
|
||||||
{
|
|
||||||
UpdateProgressbar(frame, greenZoneCount);
|
|
||||||
last_tick = frame / PROGRESSBAR_UPDATE_RATE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (savestates[frame].empty()) continue;
|
|
||||||
write32le(frame, os);
|
|
||||||
// write frames_flags
|
|
||||||
os->fwrite(&frames_flags[frame], 1);
|
|
||||||
// write lua_colorings
|
|
||||||
// write monitorings
|
|
||||||
// write savestate
|
|
||||||
size = savestates[frame].size();
|
|
||||||
write32le(size, os);
|
|
||||||
os->fwrite(savestates[frame].data(), size);
|
|
||||||
|
|
||||||
}
|
|
||||||
// write -1 as eof for greenzone
|
|
||||||
write32le(-1, os);
|
|
||||||
|
|
||||||
int end = os->ftell();
|
|
||||||
return end-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MovieData::loadGreenzone(EMUFILE *is)
|
|
||||||
{
|
|
||||||
clearGreenzone();
|
|
||||||
frames_flags.resize(records.size());
|
|
||||||
int frame = 0, prev_frame = 0, size = 0;
|
|
||||||
int last_tick = 0;
|
|
||||||
// read size
|
|
||||||
if (read32le((uint32 *)&size, is))
|
|
||||||
{
|
|
||||||
greenZoneCount = size;
|
|
||||||
savestates.resize(greenZoneCount);
|
|
||||||
#ifdef WIN32
|
|
||||||
int greenzone_tail_frame = greenZoneCount-1 - TASEdit_greenzone_capacity;
|
|
||||||
#else
|
|
||||||
int greenzone_tail_frame = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (read32le((uint32 *)&frame, is))
|
|
||||||
{
|
|
||||||
currFrameCounter = frame;
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
if (!read32le((uint32 *)&frame, is)) break;
|
|
||||||
if (frame == -1) break;
|
|
||||||
#ifdef WIN32
|
|
||||||
// update TASEditor progressbar from time to time
|
|
||||||
if (frame / PROGRESSBAR_UPDATE_RATE > last_tick)
|
|
||||||
{
|
|
||||||
UpdateProgressbar(frame, greenZoneCount);
|
|
||||||
last_tick = frame / PROGRESSBAR_UPDATE_RATE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// read frames_flags
|
|
||||||
if ((int)is->fread(&frames_flags[frame],1) != 1) break;
|
|
||||||
// read lua_colorings
|
|
||||||
// read monitorings
|
|
||||||
// read savestate
|
|
||||||
if (!read32le((uint32 *)&size, is)) break;
|
|
||||||
if (frame > greenzone_tail_frame || frame == currFrameCounter)
|
|
||||||
{
|
|
||||||
// load savestate
|
|
||||||
savestates[frame].resize(size);
|
|
||||||
if ((int)is->fread(savestates[frame].data(),size) < size) break;
|
|
||||||
prev_frame = frame; // successfully read one greenzone frame info
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
// skip loading this savestate
|
|
||||||
if (is->fseek(size,SEEK_CUR) != 0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
greenZoneCount = prev_frame+1; // cut greenZoneCount to last good frame
|
|
||||||
if (frame == -1)
|
|
||||||
{
|
|
||||||
// everything went fine - load savestate at cursor position
|
|
||||||
if (currMovieData.loadTasSavestate(currFrameCounter))
|
|
||||||
return true;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
// there was some error while reading greenzone
|
|
||||||
FCEU_printf("Error loading greenzone\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int FCEUMOV_GetFrame(void)
|
int FCEUMOV_GetFrame(void)
|
||||||
{
|
{
|
||||||
return currFrameCounter;
|
return currFrameCounter;
|
||||||
|
@ -1013,25 +839,6 @@ void MovieData::dumpSavestateTo(std::vector<uint8>* buf, int compressionLevel)
|
||||||
ms.trim();
|
ms.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MovieData::loadTasSavestate(int frame)
|
|
||||||
{
|
|
||||||
if (frame<0 || frame>=(int)currMovieData.records.size())
|
|
||||||
return false;
|
|
||||||
if ((int)savestates.size()<=frame || savestates[frame].empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
EMUFILE_MEMORY ms(&savestates[frame]);
|
|
||||||
return FCEUSS_LoadFP(&ms, SSLOADPARAM_NOBACKUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MovieData::storeTasSavestate(int frame, int compression_level)
|
|
||||||
{
|
|
||||||
if ((int)savestates.size()<=frame)
|
|
||||||
savestates.resize(frame+1);
|
|
||||||
|
|
||||||
MovieData::dumpSavestateTo(&savestates[frame],compression_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
//begin playing an existing movie
|
//begin playing an existing movie
|
||||||
bool FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _pauseframe)
|
bool FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _pauseframe)
|
||||||
{
|
{
|
||||||
|
@ -1103,7 +910,6 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _paus
|
||||||
{
|
{
|
||||||
currFrameCounter = 0;
|
currFrameCounter = 0;
|
||||||
pauseframe = _pauseframe;
|
pauseframe = _pauseframe;
|
||||||
//currMovieData.TryDumpIncremental();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1193,13 +999,13 @@ static int _currCommand = 0;
|
||||||
//either dumps the current joystick state or loads one state from the movie
|
//either dumps the current joystick state or loads one state from the movie
|
||||||
void FCEUMOV_AddInputState()
|
void FCEUMOV_AddInputState()
|
||||||
{
|
{
|
||||||
//todo - for tasedit, either dump or load depending on whether input recording is enabled
|
|
||||||
//or something like that
|
|
||||||
//(input recording is just like standard read+write movie recording with input taken from gamepad)
|
|
||||||
//otherwise, it will come from the tasedit data.
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if(movieMode == MOVIEMODE_TASEDIT)
|
if(movieMode == MOVIEMODE_TASEDIT)
|
||||||
{
|
{
|
||||||
|
// if movie length is less than currFrame, pad it with empty frames
|
||||||
|
if((int)currMovieData.records.size() <= currFrameCounter)
|
||||||
|
currMovieData.insertEmpty(-1, 1 + currFrameCounter - (int)currMovieData.records.size());
|
||||||
|
|
||||||
MovieRecord* mr = &currMovieData.records[currFrameCounter];
|
MovieRecord* mr = &currMovieData.records[currFrameCounter];
|
||||||
if(movie_readonly || turbo || pauseframe > currFrameCounter)
|
if(movie_readonly || turbo || pauseframe > currFrameCounter)
|
||||||
{
|
{
|
||||||
|
@ -1218,7 +1024,7 @@ void FCEUMOV_AddInputState()
|
||||||
joyports[1].log(mr);
|
joyports[1].log(mr);
|
||||||
mr->commands = 0;
|
mr->commands = 0;
|
||||||
|
|
||||||
InputChangedRec(); // TODO: don't call function explicitly, taseditor should catch changes in UpdateTasedit function
|
InputChangedRec();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
|
17
src/movie.h
17
src/movie.h
|
@ -178,7 +178,7 @@ public:
|
||||||
std::string romFilename;
|
std::string romFilename;
|
||||||
std::vector<uint8> savestate;
|
std::vector<uint8> savestate;
|
||||||
std::vector<MovieRecord> records;
|
std::vector<MovieRecord> records;
|
||||||
std::vector<std::vector<uint8> > savestates;
|
//std::vector<std::vector<uint8> > savestates;
|
||||||
std::vector<uint8> frames_flags;
|
std::vector<uint8> frames_flags;
|
||||||
std::vector<std::wstring> comments;
|
std::vector<std::wstring> comments;
|
||||||
std::vector<std::string> subtitles;
|
std::vector<std::string> subtitles;
|
||||||
|
@ -188,6 +188,7 @@ public:
|
||||||
|
|
||||||
//was the frame data stored in binary?
|
//was the frame data stored in binary?
|
||||||
bool binaryFlag;
|
bool binaryFlag;
|
||||||
|
int loadFrameCount;
|
||||||
|
|
||||||
//which ports are defined for the movie
|
//which ports are defined for the movie
|
||||||
int ports[3];
|
int ports[3];
|
||||||
|
@ -196,11 +197,6 @@ public:
|
||||||
//whether microphone is enabled
|
//whether microphone is enabled
|
||||||
bool microphone;
|
bool microphone;
|
||||||
|
|
||||||
//----TasEdit stuff---
|
|
||||||
int greenZoneCount;
|
|
||||||
int loadFrameCount;
|
|
||||||
//----
|
|
||||||
|
|
||||||
int getNumRecords() { return records.size(); }
|
int getNumRecords() { return records.size(); }
|
||||||
|
|
||||||
class TDictionary : public std::map<std::string,std::string>
|
class TDictionary : public std::map<std::string,std::string>
|
||||||
|
@ -234,9 +230,6 @@ public:
|
||||||
void truncateAt(int frame);
|
void truncateAt(int frame);
|
||||||
void installValue(std::string& key, std::string& val);
|
void installValue(std::string& key, std::string& val);
|
||||||
int dump(EMUFILE* os, bool binary);
|
int dump(EMUFILE* os, bool binary);
|
||||||
void clearGreenzone();
|
|
||||||
int dumpGreenzone(EMUFILE *os);
|
|
||||||
bool loadGreenzone(EMUFILE *is);
|
|
||||||
|
|
||||||
void clearRecordRange(int start, int len);
|
void clearRecordRange(int start, int len);
|
||||||
void insertEmpty(int at, int frames);
|
void insertEmpty(int at, int frames);
|
||||||
|
@ -245,12 +238,6 @@ public:
|
||||||
static bool loadSavestateFrom(std::vector<uint8>* buf);
|
static bool loadSavestateFrom(std::vector<uint8>* buf);
|
||||||
static void dumpSavestateTo(std::vector<uint8>* buf, int compressionLevel);
|
static void dumpSavestateTo(std::vector<uint8>* buf, int compressionLevel);
|
||||||
|
|
||||||
bool loadTasSavestate(int frame);
|
|
||||||
void storeTasSavestate(int frame, int compression_level);
|
|
||||||
void TryDumpIncremental();
|
|
||||||
void ClearGreenzoneTail();
|
|
||||||
void ClearSavestate(int index);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void installInt(std::string& val, int& var)
|
void installInt(std::string& val, int& var)
|
||||||
{
|
{
|
||||||
|
|
|
@ -418,7 +418,10 @@
|
||||||
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
|
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\src\drivers\win\tasedit.cpp" />
|
<ClCompile Include="..\src\drivers\win\tasedit.cpp" />
|
||||||
|
<ClCompile Include="..\src\drivers\win\taseditlib\greenzone.cpp" />
|
||||||
<ClCompile Include="..\src\drivers\win\taseditlib\inputhistory.cpp" />
|
<ClCompile Include="..\src\drivers\win\taseditlib\inputhistory.cpp" />
|
||||||
|
<ClCompile Include="..\src\drivers\win\taseditlib\inputsnapshot.cpp" />
|
||||||
|
<ClCompile Include="..\src\drivers\win\taseditlib\playback.cpp" />
|
||||||
<ClCompile Include="..\src\drivers\win\texthook.cpp" />
|
<ClCompile Include="..\src\drivers\win\texthook.cpp" />
|
||||||
<ClCompile Include="..\src\drivers\win\throttle.cpp" />
|
<ClCompile Include="..\src\drivers\win\throttle.cpp" />
|
||||||
<ClCompile Include="..\src\drivers\win\timing.cpp" />
|
<ClCompile Include="..\src\drivers\win\timing.cpp" />
|
||||||
|
|
|
@ -908,6 +908,9 @@
|
||||||
<Filter>boards</Filter>
|
<Filter>boards</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\src\drivers\win\taseditlib\inputhistory.cpp" />
|
<ClCompile Include="..\src\drivers\win\taseditlib\inputhistory.cpp" />
|
||||||
|
<ClCompile Include="..\src\drivers\win\taseditlib\inputsnapshot.cpp" />
|
||||||
|
<ClCompile Include="..\src\drivers\win\taseditlib\playback.cpp" />
|
||||||
|
<ClCompile Include="..\src\drivers\win\taseditlib\greenzone.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\src\cart.h">
|
<ClInclude Include="..\src\cart.h">
|
||||||
|
|
Loading…
Reference in New Issue