* 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 DO_ADD_NEWLINE 1
|
||||
|
|
|
@ -1355,7 +1355,7 @@ MENU TASEDITMENU
|
|||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
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,336,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 " Auto-restore last position",CHECK_AUTORESTORE_PLAYBACK,
|
||||
"Button",BS_AUTOCHECKBOX,315,53,105,12
|
||||
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 "Bookmarks",IDC_STATIC,310,158,118,101,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 " 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_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
|
||||
|
@ -1379,7 +1379,7 @@ BEGIN
|
|||
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 " 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
|
||||
|
||||
ASSEMBLER DIALOGEX 0, 0, 202, 135
|
||||
|
|
|
@ -500,6 +500,7 @@
|
|||
#define CHECK_AUTORESTORE_PLAYBACK 1261
|
||||
#define IDC_PROGRESS1 1262
|
||||
#define CHECK_FOLLOW_CURSOR 1263
|
||||
#define IDC_BOOKMARKS_BOX 1264
|
||||
#define MENU_NETWORK 40040
|
||||
#define MENU_PALETTE 40041
|
||||
#define MENU_SOUND 40042
|
||||
|
@ -869,7 +870,7 @@
|
|||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 160
|
||||
#define _APS_NEXT_COMMAND_VALUE 40473
|
||||
#define _APS_NEXT_CONTROL_VALUE 1263
|
||||
#define _APS_NEXT_CONTROL_VALUE 1265
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "taseditlib/taseditproj.h"
|
||||
//#include "taseditlib/inputhistory.h"
|
||||
#include "fceu.h"
|
||||
#include "debugger.h"
|
||||
#include "replay.h"
|
||||
|
@ -22,27 +21,14 @@ using namespace std;
|
|||
//to change header font
|
||||
//http://forums.devx.com/archive/index.php/t-37234.html
|
||||
|
||||
bool old_project_changed;
|
||||
int old_multitrack_recording_joypad, multitrack_recording_joypad;
|
||||
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;
|
||||
int listItems; // number of items per list page
|
||||
// saved FCEU config
|
||||
int saved_eoptions;
|
||||
int saved_EnableAutosave;
|
||||
extern int EnableAutosave;
|
||||
bool saved_compressSavestates;
|
||||
extern bool compressSavestates;
|
||||
|
||||
// vars saved in cfg file
|
||||
int TasEdit_wndx, TasEdit_wndy;
|
||||
|
@ -65,13 +51,15 @@ char windowCaptions[6][30] = { "TAS Editor",
|
|||
"TAS Editor (Recording 2P)",
|
||||
"TAS Editor (Recording 3P)",
|
||||
"TAS Editor (Recording 4P)"};
|
||||
char bookmarksCaption[2][23] = { " Bookmarks ", " Bookmarks / Branches " };
|
||||
|
||||
HWND hwndTasEdit = 0;
|
||||
HMENU hmenu, hrmenu;
|
||||
HWND hwndList, hwndHeader;
|
||||
WNDPROC hwndList_oldWndProc, hwndHeader_oldWndproc;
|
||||
HWND hwndHistoryList;
|
||||
WNDPROC hwndHistoryList_oldWndProc;
|
||||
HWND hwndBookmarksList;
|
||||
HWND hwndBookmarksList, hwndBookmarks;
|
||||
WNDPROC hwndBookmarksList_oldWndProc;
|
||||
HWND hwndProgressbar, hwndRewind, hwndForward;
|
||||
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
|
||||
extern EMOVIEMODE movieMode;
|
||||
|
||||
// all Taseditor functional modules
|
||||
TASEDIT_PROJECT project;
|
||||
INPUT_HISTORY history;
|
||||
//GREENZONE greenzone;
|
||||
PLAYBACK playback;
|
||||
GREENZONE greenzone;
|
||||
|
||||
|
||||
void GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
|
||||
|
@ -164,11 +154,11 @@ LONG CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
if(cell_x == COLUMN_FRAMENUM || cell_x == COLUMN_FRAMENUM2)
|
||||
{
|
||||
// frame number
|
||||
if (show_undo_hint && cell_y == undo_hint_pos)
|
||||
if (cell_y == history.GetUndoHint())
|
||||
{
|
||||
// undo hint here
|
||||
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
|
||||
if(TASEdit_show_markers && currMovieData.frames_flags[cell_y] & MARKER_FLAG_BIT)
|
||||
|
@ -180,7 +170,7 @@ LONG CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
{
|
||||
// marked frame
|
||||
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))
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
// pad 1 or 3
|
||||
if (show_undo_hint && cell_y == undo_hint_pos)
|
||||
if (cell_y == history.GetUndoHint())
|
||||
{
|
||||
// undo hint here
|
||||
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
|
||||
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))
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
// pad 2 or 4
|
||||
if (show_undo_hint && cell_y == undo_hint_pos)
|
||||
if (cell_y == history.GetUndoHint())
|
||||
{
|
||||
// undo hint here
|
||||
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
|
||||
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))
|
||||
{
|
||||
|
@ -253,98 +243,18 @@ void UpdateTasEdit()
|
|||
|
||||
UpdateList();
|
||||
|
||||
// pause when seeking hit pauseframe
|
||||
if(!FCEUI_EmulationPaused())
|
||||
if(pauseframe && pauseframe <= currFrameCounter + 1)
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
greenzone.update();
|
||||
playback.update();
|
||||
history.update();
|
||||
|
||||
// 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();
|
||||
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
|
||||
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()
|
||||
{
|
||||
char windowCaption[300]; // 260 + 30 + 1 + ...
|
||||
|
@ -403,6 +308,10 @@ void RedrawWindowCaption()
|
|||
strcat(windowCaption, "*");
|
||||
SetWindowText(hwndTasEdit, windowCaption);
|
||||
}
|
||||
void RedrawBookmarksCaption()
|
||||
{
|
||||
SetWindowText(hwndBookmarks, bookmarksCaption[(movie_readonly)?0:1]);
|
||||
}
|
||||
void RedrawTasedit()
|
||||
{
|
||||
InvalidateRect(hwndTasEdit,0,FALSE);
|
||||
|
@ -411,63 +320,11 @@ void RedrawList()
|
|||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
CONTEXTMENU_STRAY = 0,
|
||||
|
@ -523,80 +380,7 @@ void MarkersChanged()
|
|||
|
||||
void InputChangedRec()
|
||||
{
|
||||
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();
|
||||
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_RECORD, currFrameCounter, currFrameCounter));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CHANGE, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CHANGE, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||
} else
|
||||
{
|
||||
//update one row
|
||||
currMovieData.records[row_index].toggleBit(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
|
||||
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
|
||||
ClearSelection();
|
||||
JumpToFrame(row_index);
|
||||
playback.JumpToFrame(row_index);
|
||||
RedrawList();
|
||||
} 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
|
||||
ClearSelection();
|
||||
JumpToFrame(row_index);
|
||||
playback.JumpToFrame(row_index);
|
||||
RedrawList();
|
||||
} else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
|
||||
{
|
||||
|
@ -696,7 +480,7 @@ void CloneFrames()
|
|||
} else frames++;
|
||||
}
|
||||
UpdateList();
|
||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CLONE, *selectionFrames.begin()));
|
||||
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CLONE, *selectionFrames.begin()));
|
||||
}
|
||||
|
||||
void InsertFrames()
|
||||
|
@ -724,7 +508,7 @@ void InsertFrames()
|
|||
} else frames++;
|
||||
}
|
||||
UpdateList();
|
||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, *selectionFrames.begin()));
|
||||
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, *selectionFrames.begin()));
|
||||
}
|
||||
|
||||
void DeleteFrames()
|
||||
|
@ -740,11 +524,11 @@ void DeleteFrames()
|
|||
}
|
||||
// check if user deleted all frames
|
||||
if (!currMovieData.getNumRecords())
|
||||
StartFromZero();
|
||||
playback.StartFromZero();
|
||||
// reduce list
|
||||
UpdateList();
|
||||
|
||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_DELETE, start_index, end_index));
|
||||
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_DELETE, start_index));
|
||||
}
|
||||
|
||||
void ClearFrames(bool cut)
|
||||
|
@ -755,9 +539,25 @@ void ClearFrames(bool cut)
|
|||
currMovieData.records[*it].clear();
|
||||
}
|
||||
if (cut)
|
||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CUT, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CUT, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||
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
|
||||
|
@ -810,9 +610,9 @@ void ColumnSet(int column)
|
|||
for(TSelectionFrames::iterator it(selectionFrames.begin()); it != selectionFrames.end(); it++)
|
||||
currMovieData.records[*it].setBitValue(joy,button,newValue);
|
||||
if (newValue)
|
||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_SET, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_SET, *selectionFrames.begin(), *selectionFrames.rbegin()));
|
||||
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');
|
||||
}
|
||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_PASTE, *selectionFrames.begin()));
|
||||
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_PASTE, *selectionFrames.begin()));
|
||||
result = true;
|
||||
}
|
||||
|
||||
|
@ -1058,7 +858,6 @@ bool Paste()
|
|||
CloseClipboard();
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
//The subclass wndproc for the listview header
|
||||
LRESULT APIENTRY HeaderWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
|
||||
|
@ -1247,22 +1046,21 @@ void OpenProject()
|
|||
multitrack_recording_joypad = MULTITRACK_RECORDING_ALL;
|
||||
UncheckRecordingRadioButtons();
|
||||
RecheckRecordingRadioButtons();
|
||||
playback.reset();
|
||||
// remember to update fourscore status
|
||||
bool last_fourscore = currMovieData.fourscore;
|
||||
// Load project
|
||||
project.LoadProject(project.GetProjectFile());
|
||||
UpdateList();
|
||||
UpdateHistoryList();
|
||||
RedrawHistoryList();
|
||||
// update fourscore status
|
||||
if (last_fourscore && !currMovieData.fourscore)
|
||||
RemoveFourscore();
|
||||
else if (!last_fourscore && currMovieData.fourscore)
|
||||
AddFourscore();
|
||||
SeekingStop();
|
||||
FollowPlayback();
|
||||
RedrawTasedit();
|
||||
RedrawWindowCaption();
|
||||
RedrawBookmarksCaption();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1336,15 +1134,12 @@ bool AskSaveProject()
|
|||
return true;
|
||||
}
|
||||
|
||||
//Takes a selected .fm2 file and adds it to the Project inputlog
|
||||
static void Import()
|
||||
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
|
||||
static void Export()
|
||||
void Export()
|
||||
{
|
||||
//TODO: redesign this
|
||||
//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
|
||||
void ItemRangeChanged(NMLVODSTATECHANGE* info)
|
||||
{
|
||||
|
@ -1449,6 +1228,7 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
listItems = ListView_GetCountPerPage(hwndList);
|
||||
hwndHistoryList = GetDlgItem(hwndDlg, IDC_HISTORYLIST);
|
||||
hwndBookmarksList = GetDlgItem(hwndDlg, IDC_BOOKMARKSLIST);
|
||||
hwndBookmarks = GetDlgItem(hwndDlg, IDC_BOOKMARKS_BOX);
|
||||
hwndProgressbar = GetDlgItem(hwndDlg, IDC_PROGRESS1);
|
||||
SendMessage(hwndProgressbar, PBM_SETRANGE, 0, MAKELPARAM(0, PROGRESSBAR_WIDTH));
|
||||
hwndRewind = GetDlgItem(hwndDlg, TASEDIT_REWIND);
|
||||
|
@ -1518,15 +1298,15 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
switch(((LPNMHDR)lParam)->code)
|
||||
{
|
||||
case NM_CUSTOMDRAW:
|
||||
SetWindowLong(hwndDlg, DWL_MSGRESULT, HistoryCustomDraw((NMLVCUSTOMDRAW*)lParam));
|
||||
SetWindowLong(hwndDlg, DWL_MSGRESULT, history.CustomDraw((NMLVCUSTOMDRAW*)lParam));
|
||||
return TRUE;
|
||||
case LVN_GETDISPINFO:
|
||||
HistoryGetDispInfo((NMLVDISPINFO*)lParam);
|
||||
history.GetDispInfo((NMLVDISPINFO*)lParam);
|
||||
break;
|
||||
case NM_CLICK:
|
||||
case NM_DBLCLK:
|
||||
case NM_RCLICK:
|
||||
HistoryClick((LPNMITEMACTIVATE)lParam);
|
||||
history.Click((LPNMITEMACTIVATE)lParam);
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -1536,7 +1316,7 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
{
|
||||
case NM_CLICK:
|
||||
case NM_DBLCLK:
|
||||
Tasedit_ToggleEmulationPause();
|
||||
playback.ToggleEmulationPause();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -1623,12 +1403,12 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
// insert at selection
|
||||
int index = *selectionFrames.begin();
|
||||
currMovieData.insertEmpty(index,frames);
|
||||
InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, index));
|
||||
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, index));
|
||||
} else
|
||||
{
|
||||
// insert at playback cursor
|
||||
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;
|
||||
case TASEDIT_REWIND_FULL:
|
||||
//rewinds to beginning of greenzone
|
||||
JumpToFrame(FindBeginningOfGreenZone(0));
|
||||
playback.JumpToFrame(greenzone.FindBeginningOfGreenZone());
|
||||
FollowPlayback();
|
||||
break;
|
||||
case TASEDIT_PLAYSTOP:
|
||||
Tasedit_ToggleEmulationPause();
|
||||
playback.ToggleEmulationPause();
|
||||
break;
|
||||
case TASEDIT_FORWARD_FULL:
|
||||
//moves to the end of greenzone
|
||||
JumpToFrame(currMovieData.greenZoneCount-1);
|
||||
playback.JumpToFrame(greenzone.greenZoneCount-1);
|
||||
FollowPlayback();
|
||||
break;
|
||||
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)
|
||||
{
|
||||
TASEdit_greenzone_capacity = new_capacity;
|
||||
currMovieData.ClearGreenzoneTail();
|
||||
greenzone.ClearGreenzoneTail();
|
||||
RedrawList();
|
||||
} 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);
|
||||
break;
|
||||
case IDC_PROGRESS_BUTTON:
|
||||
if (pauseframe) SeekingStop();
|
||||
// click on progressbar - stop seeking
|
||||
if (playback.pauseframe) playback.SeekingStop();
|
||||
break;
|
||||
case IDC_RADIO1:
|
||||
// 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();
|
||||
if (result >= 0)
|
||||
{
|
||||
FollowUndo();
|
||||
UpdateList();
|
||||
InvalidateGreenZone(result);
|
||||
FollowUndo();
|
||||
greenzone.InvalidateGreenZone(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1804,9 +1585,9 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
int result = history.redo();
|
||||
if (result >= 0)
|
||||
{
|
||||
FollowRedo();
|
||||
UpdateList();
|
||||
InvalidateGreenZone(result);
|
||||
FollowUndo();
|
||||
greenzone.InvalidateGreenZone(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1820,15 +1601,6 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
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)
|
||||
{
|
||||
int top = ListView_GetTopIndex(hwndList);
|
||||
|
@ -1842,10 +1614,9 @@ void FollowPlayback()
|
|||
{
|
||||
if (TASEdit_follow_playback) ListView_EnsureVisible(hwndList,currFrameCounter,FALSE);
|
||||
}
|
||||
|
||||
void FollowUndo()
|
||||
{
|
||||
int jump_frame = history.GetNextToCurrentSnapshot().jump_frame;
|
||||
int jump_frame = history.GetUndoHint();
|
||||
if (TASEdit_jump_to_undo && jump_frame >= 0)
|
||||
{
|
||||
if (!CheckItemVisible(jump_frame))
|
||||
|
@ -1854,24 +1625,6 @@ void FollowUndo()
|
|||
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()
|
||||
|
@ -1896,9 +1649,6 @@ void EnterTasEdit()
|
|||
// switch off autosaves
|
||||
saved_EnableAutosave = EnableAutosave;
|
||||
EnableAutosave = 0;
|
||||
// switch on savestates compression
|
||||
saved_compressSavestates = compressSavestates;
|
||||
compressSavestates = true;
|
||||
|
||||
|
||||
UpdateCheckedMenuItems();
|
||||
|
@ -1916,107 +1666,96 @@ void EnterTasEdit()
|
|||
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);
|
||||
}
|
||||
|
||||
// either start new movie or use current movie
|
||||
if (movieMode == MOVIEMODE_INACTIVE)
|
||||
{
|
||||
FCEUI_StopMovie();
|
||||
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)
|
||||
playback.init();
|
||||
greenzone.init();
|
||||
// either start new movie or use current movie
|
||||
if (movieMode == MOVIEMODE_INACTIVE)
|
||||
{
|
||||
lvc.pszText = buttonNames[btn];
|
||||
ListView_InsertColumn(hwndList, colidx++, &lvc);
|
||||
FCEUI_StopMovie();
|
||||
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()
|
||||
{
|
||||
if (!AskSaveProject()) return false;
|
||||
|
||||
DestroyWindow(hwndTasEdit);
|
||||
hwndTasEdit = 0;
|
||||
SeekingStop();
|
||||
TASEdit_focus = false;
|
||||
// restore "eoptions"
|
||||
eoptions = saved_eoptions;
|
||||
// restore autosaves
|
||||
EnableAutosave = saved_EnableAutosave;
|
||||
// restore compression
|
||||
compressSavestates = saved_compressSavestates;
|
||||
|
||||
DoPriority();
|
||||
UpdateCheckedMenuItems();
|
||||
|
@ -2024,69 +1763,12 @@ bool ExitTasEdit()
|
|||
KeyboardClearBackgroundAccessBit(KEYBACKACCESS_TASEDIT);
|
||||
JoystickClearBackgroundAccessBit(JOYBACKACCESS_TASEDIT);
|
||||
// release memory
|
||||
currMovieData.clearGreenzone();
|
||||
greenzone.clearGreenzone();
|
||||
history.free();
|
||||
|
||||
movieMode = MOVIEMODE_INACTIVE;
|
||||
FCEU_DispMessage("Tasedit disengaged",0);
|
||||
CreateCleanMovie();
|
||||
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_JOYPAD_BUTTONS 8
|
||||
#define PAUSEFRAME_BLINKING_PERIOD 100
|
||||
#define PROGRESSBAR_WIDTH 200
|
||||
#define HOLD_REPEAT_DELAY 250 // in milliseconds
|
||||
|
||||
#define GREENZONE_CAPACITY_DEFAULT 100000
|
||||
#define GREENZONE_CAPACITY_MIN 1
|
||||
|
@ -14,8 +12,6 @@
|
|||
#define UNDO_LEVELS_MAX 999
|
||||
#define UNDO_LEVELS_DEFAULT 100
|
||||
|
||||
#define UNDO_HINT_TIME 200
|
||||
|
||||
// multitrack
|
||||
#define MULTITRACK_RECORDING_ALL 0
|
||||
#define MULTITRACK_RECORDING_1P 1
|
||||
|
@ -77,44 +73,26 @@
|
|||
#define CUR_INPUT_COLOR2 0xE4D8A8
|
||||
#define GREENZONE_INPUT_COLOR2 0xAEE2AE
|
||||
#define LAG_INPUT_COLOR2 0xB8B3E2
|
||||
|
||||
#define HISTORY_COHERENT_COLOR 0xF9DDE6
|
||||
#define HISTORY_NORMAL_COLOR 0xFFFFFF
|
||||
|
||||
// -----------------------------
|
||||
void EnterTasEdit();
|
||||
void InitDialog();
|
||||
bool ExitTasEdit();
|
||||
void UpdateTasEdit();
|
||||
void UpdateList();
|
||||
void UpdateHistoryList();
|
||||
void UpdateProgressbar(int a, int b);
|
||||
void InputChangedRec();
|
||||
void InvalidateGreenZone(int after);
|
||||
bool JumpToFrame(int index);
|
||||
int FindBeginningOfGreenZone(int starting_index);
|
||||
bool CheckItemVisible(int frame);
|
||||
void FollowPlayback();
|
||||
void FollowUndo();
|
||||
void FollowRedo();
|
||||
void ClearSelection();
|
||||
void ClearRowSelection(int index);
|
||||
void AddFourscore();
|
||||
void RemoveFourscore();
|
||||
void RedrawWindowCaption();
|
||||
void RedrawBookmarksCaption();
|
||||
void RedrawTasedit();
|
||||
void RedrawList();
|
||||
void RedrawHistoryList();
|
||||
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 Tasedit_RewindFrame();
|
||||
void Tasedit_ForwardFrame();
|
||||
void StartFromZero();
|
||||
void SwitchToReadOnly();
|
||||
void UncheckRecordingRadioButtons();
|
||||
void RecheckRecordingRadioButtons();
|
||||
|
@ -128,12 +106,8 @@ void CloneFrames();
|
|||
void InsertFrames();
|
||||
void DeleteFrames();
|
||||
void ClearFrames(bool cut = false);
|
||||
void Truncate();
|
||||
void ColumnSet(int column);
|
||||
bool Copy();
|
||||
void Cut();
|
||||
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 "../common.h"
|
||||
#include "../tasedit.h"
|
||||
#include "inputsnapshot.h"
|
||||
#include "inputhistory.h"
|
||||
#include "zlib.h"
|
||||
#include "playback.h"
|
||||
#include "greenzone.h"
|
||||
|
||||
extern PLAYBACK playback;
|
||||
extern void FCEU_printf(char *format, ...);
|
||||
extern void RedrawHistoryList();
|
||||
extern void UpdateHistoryList();
|
||||
extern void UpdateProgressbar(int a, int b);
|
||||
extern HWND hwndHistoryList;
|
||||
extern GREENZONE greenzone;
|
||||
|
||||
char modCaptions[23][12] = {"Init",
|
||||
char modCaptions[24][12] = {"Init",
|
||||
"Change",
|
||||
"Set",
|
||||
"Unset",
|
||||
|
@ -22,6 +26,7 @@ char modCaptions[23][12] = {"Init",
|
|||
"PasteInsert",
|
||||
"Clone",
|
||||
"Record",
|
||||
"Import",
|
||||
"Branch0",
|
||||
"Branch1",
|
||||
"Branch2",
|
||||
|
@ -34,311 +39,6 @@ char modCaptions[23][12] = {"Init",
|
|||
"Branch9"};
|
||||
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()
|
||||
{
|
||||
|
||||
|
@ -346,6 +46,9 @@ INPUT_HISTORY::INPUT_HISTORY()
|
|||
|
||||
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;
|
||||
// clear snapshots history
|
||||
history_total_items = 0;
|
||||
|
@ -358,12 +61,35 @@ void INPUT_HISTORY::init(int new_size)
|
|||
strcat(inp.description, modCaptions[0]);
|
||||
inp.jump_frame = -1;
|
||||
AddInputSnapshotToHistory(inp);
|
||||
|
||||
UpdateHistoryList();
|
||||
RedrawHistoryList();
|
||||
}
|
||||
void INPUT_HISTORY::free()
|
||||
{
|
||||
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)
|
||||
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 (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
|
||||
history_cursor_pos = new_pos;
|
||||
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
|
||||
input_snapshots[real_pos].toMovie(currMovieData, first_change);
|
||||
RedrawHistoryList();
|
||||
|
||||
return first_change;
|
||||
}
|
||||
int INPUT_HISTORY::undo()
|
||||
|
@ -392,34 +127,6 @@ int INPUT_HISTORY::redo()
|
|||
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)
|
||||
{
|
||||
// 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_CLEAR:
|
||||
case MODTYPE_CUT:
|
||||
case MODTYPE_IMPORT:
|
||||
case MODTYPE_BRANCH_0: case MODTYPE_BRANCH_1:
|
||||
case MODTYPE_BRANCH_2: case MODTYPE_BRANCH_3:
|
||||
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:
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
// ----------------------------
|
||||
|
||||
void INPUT_HISTORY::save(EMUFILE *os)
|
||||
{
|
||||
int real_pos, last_tick = 0;
|
||||
|
@ -543,7 +251,7 @@ void INPUT_HISTORY::save(EMUFILE *os)
|
|||
{
|
||||
real_pos = (history_start_pos + i) % history_size;
|
||||
input_snapshots[real_pos].save(os);
|
||||
UpdateProgressbar(i, history_total_items);
|
||||
playback.SetProgressbar(i, history_total_items);
|
||||
}
|
||||
}
|
||||
void INPUT_HISTORY::load(EMUFILE *is)
|
||||
|
@ -555,6 +263,7 @@ void INPUT_HISTORY::load(EMUFILE *is)
|
|||
// read vars
|
||||
if (!read32le((uint32 *)&history_cursor_pos, 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;
|
||||
// read snapshots
|
||||
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
|
||||
if (!input_snapshots[i].load(is)) goto error;
|
||||
UpdateProgressbar(i, history_total_items);
|
||||
playback.SetProgressbar(i, history_total_items);
|
||||
}
|
||||
// skip redo snapshots if needed
|
||||
for (; i < total; ++i)
|
||||
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;
|
||||
error:
|
||||
// couldn't load full history - reset it
|
||||
FCEU_printf("Error loading history\n");
|
||||
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 HOTCHANGE_BYTES_PER_JOY 4
|
||||
#define SNAPSHOT_DESC_MAX_LENGTH 50
|
||||
#define UNDO_HINT_TIME 200
|
||||
|
||||
#define MODTYPE_INIT 0
|
||||
#define MODTYPE_CHANGE 1
|
||||
|
@ -18,48 +15,20 @@
|
|||
#define MODTYPE_PASTEINSERT 10
|
||||
#define MODTYPE_CLONE 11
|
||||
#define MODTYPE_RECORD 12
|
||||
#define MODTYPE_BRANCH_0 13
|
||||
#define MODTYPE_BRANCH_1 14
|
||||
#define MODTYPE_BRANCH_2 15
|
||||
#define MODTYPE_BRANCH_3 16
|
||||
#define MODTYPE_BRANCH_4 17
|
||||
#define MODTYPE_BRANCH_5 18
|
||||
#define MODTYPE_BRANCH_6 19
|
||||
#define MODTYPE_BRANCH_7 20
|
||||
#define MODTYPE_BRANCH_8 21
|
||||
#define MODTYPE_BRANCH_9 22
|
||||
#define MODTYPE_IMPORT 13
|
||||
#define MODTYPE_BRANCH_0 14
|
||||
#define MODTYPE_BRANCH_1 15
|
||||
#define MODTYPE_BRANCH_2 16
|
||||
#define MODTYPE_BRANCH_3 17
|
||||
#define MODTYPE_BRANCH_4 18
|
||||
#define MODTYPE_BRANCH_5 19
|
||||
#define MODTYPE_BRANCH_6 20
|
||||
#define MODTYPE_BRANCH_7 21
|
||||
#define MODTYPE_BRANCH_8 22
|
||||
#define MODTYPE_BRANCH_9 23
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
};
|
||||
#define HISTORY_COHERENT_COLOR 0xF9DDE6
|
||||
#define HISTORY_NORMAL_COLOR 0xFFFFFF
|
||||
|
||||
class INPUT_HISTORY
|
||||
{
|
||||
|
@ -68,6 +37,8 @@ public:
|
|||
void init(int new_size);
|
||||
void free();
|
||||
|
||||
void update(); // called every frame
|
||||
|
||||
void save(EMUFILE *os);
|
||||
void load(EMUFILE *is);
|
||||
|
||||
|
@ -85,10 +56,16 @@ public:
|
|||
|
||||
INPUT_SNAPSHOT& GetCurrentSnapshot();
|
||||
INPUT_SNAPSHOT& GetNextToCurrentSnapshot();
|
||||
int GetCursorPos();
|
||||
int GetTotalItems();
|
||||
char* GetItemDesc(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:
|
||||
std::vector<INPUT_SNAPSHOT> input_snapshots;
|
||||
|
@ -98,5 +75,9 @@ private:
|
|||
int history_total_items;
|
||||
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 "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
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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="";
|
||||
fm2FileName="";
|
||||
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...
|
||||
std::string TASEDIT_PROJECT::GetProjectName()
|
||||
{
|
||||
|
@ -55,53 +110,3 @@ void TASEDIT_PROJECT::SetProjectFile(std::string 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
|
||||
//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
|
||||
//Specification file for the TASEdit Project class
|
||||
|
||||
#include "movie.h"
|
||||
#include "inputsnapshot.h"
|
||||
#include "inputhistory.h"
|
||||
|
||||
//The notes feature, displays user notes in the notes column
|
||||
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)
|
||||
};
|
||||
#include "playback.h"
|
||||
#include "greenzone.h"
|
||||
|
||||
class TASEDIT_PROJECT
|
||||
{
|
||||
public:
|
||||
TASEDIT_PROJECT();
|
||||
void init(INPUT_HISTORY* history_ptr);
|
||||
|
||||
std::string GetProjectName();
|
||||
void SetProjectName(std::string e);
|
||||
|
||||
std::string GetFM2Name();
|
||||
void SetFM2Name(std::string e);
|
||||
|
||||
std::string GetProjectFile();
|
||||
void SetProjectFile(std::string e);
|
||||
void init();
|
||||
void reset();
|
||||
void update();
|
||||
|
||||
bool saveProject();
|
||||
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
|
||||
|
||||
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
|
||||
bool changed;
|
||||
bool changed, old_changed;
|
||||
|
||||
private:
|
||||
std::string projectName; //The TASEdit Project's name
|
||||
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::vector<TASENote> notes; //User notes
|
||||
std::vector<std::string> inputlogs; //List of associated .ilog files
|
||||
TASEHeader header;
|
||||
std::vector<std::string> comments;
|
||||
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
|
||||
#include "drivers/win/pref.h"
|
||||
|
||||
#include "drivers/win/taseditlib/greenzone.h"
|
||||
extern GREENZONE greenzone;
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
|
@ -713,11 +716,13 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
|||
}
|
||||
else justLagged = false;
|
||||
|
||||
// auto-savestates for TASEditor
|
||||
currMovieData.TryDumpIncremental();
|
||||
|
||||
if (movieSubtitles)
|
||||
ProcessSubtitles();
|
||||
|
||||
#ifdef WIN32
|
||||
if(FCEUMOV_Mode(MOVIEMODE_TASEDIT))
|
||||
greenzone.TryDumpIncremental(lagFlag);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FCEUI_CloseGame(void)
|
||||
|
|
210
src/movie.cpp
210
src/movie.cpp
|
@ -37,12 +37,12 @@
|
|||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include "./drivers/win/common.h"
|
||||
#include "./drivers/win/tasedit.h"
|
||||
#include "./drivers/win/window.h"
|
||||
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
|
||||
|
||||
using namespace std;
|
||||
|
@ -51,10 +51,6 @@ using namespace std;
|
|||
|
||||
extern char FileBase[];
|
||||
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<string> subtitleMessages; //Messages of subtitles
|
||||
|
@ -154,56 +150,6 @@ void MovieData::cloneRegion(int at, int 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()
|
||||
{
|
||||
joysticks.data[0] = 0;
|
||||
|
@ -468,7 +414,6 @@ MovieData::MovieData()
|
|||
, PPUflag(false)
|
||||
, rerecordCount(0)
|
||||
, binaryFlag(false)
|
||||
, greenZoneCount(0)
|
||||
, microphone(false)
|
||||
{
|
||||
memset(&romChecksum,0,sizeof(MD5DATA));
|
||||
|
@ -580,125 +525,6 @@ int MovieData::dump(EMUFILE *os, bool binary)
|
|||
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)
|
||||
{
|
||||
return currFrameCounter;
|
||||
|
@ -1013,25 +839,6 @@ void MovieData::dumpSavestateTo(std::vector<uint8>* buf, int compressionLevel)
|
|||
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
|
||||
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;
|
||||
pauseframe = _pauseframe;
|
||||
//currMovieData.TryDumpIncremental();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1193,13 +999,13 @@ static int _currCommand = 0;
|
|||
//either dumps the current joystick state or loads one state from the movie
|
||||
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
|
||||
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];
|
||||
if(movie_readonly || turbo || pauseframe > currFrameCounter)
|
||||
{
|
||||
|
@ -1218,7 +1024,7 @@ void FCEUMOV_AddInputState()
|
|||
joyports[1].log(mr);
|
||||
mr->commands = 0;
|
||||
|
||||
InputChangedRec(); // TODO: don't call function explicitly, taseditor should catch changes in UpdateTasedit function
|
||||
InputChangedRec();
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
|
17
src/movie.h
17
src/movie.h
|
@ -178,7 +178,7 @@ public:
|
|||
std::string romFilename;
|
||||
std::vector<uint8> savestate;
|
||||
std::vector<MovieRecord> records;
|
||||
std::vector<std::vector<uint8> > savestates;
|
||||
//std::vector<std::vector<uint8> > savestates;
|
||||
std::vector<uint8> frames_flags;
|
||||
std::vector<std::wstring> comments;
|
||||
std::vector<std::string> subtitles;
|
||||
|
@ -188,6 +188,7 @@ public:
|
|||
|
||||
//was the frame data stored in binary?
|
||||
bool binaryFlag;
|
||||
int loadFrameCount;
|
||||
|
||||
//which ports are defined for the movie
|
||||
int ports[3];
|
||||
|
@ -196,11 +197,6 @@ public:
|
|||
//whether microphone is enabled
|
||||
bool microphone;
|
||||
|
||||
//----TasEdit stuff---
|
||||
int greenZoneCount;
|
||||
int loadFrameCount;
|
||||
//----
|
||||
|
||||
int getNumRecords() { return records.size(); }
|
||||
|
||||
class TDictionary : public std::map<std::string,std::string>
|
||||
|
@ -234,9 +230,6 @@ public:
|
|||
void truncateAt(int frame);
|
||||
void installValue(std::string& key, std::string& val);
|
||||
int dump(EMUFILE* os, bool binary);
|
||||
void clearGreenzone();
|
||||
int dumpGreenzone(EMUFILE *os);
|
||||
bool loadGreenzone(EMUFILE *is);
|
||||
|
||||
void clearRecordRange(int start, int len);
|
||||
void insertEmpty(int at, int frames);
|
||||
|
@ -245,12 +238,6 @@ public:
|
|||
static bool loadSavestateFrom(std::vector<uint8>* buf);
|
||||
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:
|
||||
void installInt(std::string& val, int& var)
|
||||
{
|
||||
|
|
|
@ -418,7 +418,10 @@
|
|||
<XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)1.xdc</XMLDocumentationFileName>
|
||||
</ClCompile>
|
||||
<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\inputsnapshot.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\taseditlib\playback.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\texthook.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\throttle.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\timing.cpp" />
|
||||
|
|
|
@ -908,6 +908,9 @@
|
|||
<Filter>boards</Filter>
|
||||
</ClCompile>
|
||||
<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>
|
||||
<ClInclude Include="..\src\cart.h">
|
||||
|
|
Loading…
Reference in New Issue