* Tasedit: refactoring, bugfixes

* Tasedit: storing Markers in input history, undo/redo for Markers
This commit is contained in:
ansstuff 2011-10-20 13:00:34 +00:00
parent 22eeba79a1
commit 1a9b6f109a
14 changed files with 389 additions and 171 deletions

View File

@ -158,7 +158,10 @@ LONG CustomDraw(NMLVCUSTOMDRAW* msg)
if (cell_y == history.GetUndoHint())
{
// undo hint here
msg->clrTextBk = UNDOHINT_FRAMENUM_COLOR;
if(TASEdit_show_markers && (markers.markers_array[cell_y] & MARKER_FLAG_BIT))
msg->clrTextBk = MARKED_UNDOHINT_FRAMENUM_COLOR;
else
msg->clrTextBk = UNDOHINT_FRAMENUM_COLOR;
} else if (cell_y == currFrameCounter || cell_y == playback.GetPauseFrame())
{
// current frame
@ -376,14 +379,9 @@ void RightClick(LPNMITEMACTIVATE info)
RightClickMenu(info);
}
void MarkersChanged()
{
project.changed = true;
}
void InputChangedRec()
{
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_RECORD, currFrameCounter, currFrameCounter));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_RECORD, currFrameCounter, currFrameCounter));
}
void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags)
@ -397,15 +395,15 @@ void ToggleJoypadBit(int column_index, int row_index, UINT KeyFlags)
{
currMovieData.records[*it].toggleBit(joy,bit);
}
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CHANGE, *selectionFrames.begin(), *selectionFrames.rbegin()));
greenzone.InvalidateGreenZone(history.RegisterChanges(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))
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_SET, row_index, row_index));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_SET, row_index, row_index));
else
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_UNSET, row_index, row_index));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_UNSET, row_index, row_index));
}
}
@ -429,9 +427,14 @@ void SingleClick(LPNMITEMACTIVATE info)
{
// reverse MARKER_FLAG_BIT in pointed frame
markers.ToggleMarker(row_index);
MarkersChanged();
if (markers.markers_array[row_index])
history.RegisterChanges(MODTYPE_MARKER_SET, row_index);
else
history.RegisterChanges(MODTYPE_MARKER_UNSET, row_index);
project.changed = true;
// deselect this row, so that new marker will be seen immediately
ListView_SetItemState(hwndList, row_index, 0, LVIS_SELECTED);
// also no need to redraw row
}
}
else if(column_index >= COLUMN_JOYPAD1_A && column_index <= COLUMN_JOYPAD4_R)
@ -481,7 +484,7 @@ void CloneFrames()
} else frames++;
}
UpdateList();
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CLONE, *selectionFrames.begin()));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_CLONE, *selectionFrames.begin()));
}
void InsertFrames()
@ -508,7 +511,7 @@ void InsertFrames()
} else frames++;
}
UpdateList();
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, *selectionFrames.begin()));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_INSERT, *selectionFrames.begin()));
}
void DeleteFrames()
@ -528,7 +531,7 @@ void DeleteFrames()
// reduce list
UpdateList();
int result = history.RegisterInputChanges(MODTYPE_DELETE, start_index);
int result = history.RegisterChanges(MODTYPE_DELETE, start_index);
if (result >= 0)
{
greenzone.InvalidateGreenZone(result);
@ -546,9 +549,9 @@ void ClearFrames(bool cut)
currMovieData.records[*it].clear();
}
if (cut)
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CUT, *selectionFrames.begin(), *selectionFrames.rbegin()));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_CUT, *selectionFrames.begin(), *selectionFrames.rbegin()));
else
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_CLEAR, *selectionFrames.begin(), *selectionFrames.rbegin()));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_CLEAR, *selectionFrames.begin(), *selectionFrames.rbegin()));
}
void Truncate()
@ -563,7 +566,7 @@ void Truncate()
{
currMovieData.truncateAt(frame+1);
UpdateList();
int result = history.RegisterInputChanges(MODTYPE_TRUNCATE, frame+1);
int result = history.RegisterChanges(MODTYPE_TRUNCATE, frame+1);
if (result >= 0)
{
greenzone.InvalidateGreenZone(result);
@ -595,15 +598,17 @@ void ColumnSet(int column)
// set all
for(TSelectionFrames::iterator it(selectionFrames.begin()); it != selectionFrames.end(); it++)
markers.markers_array[*it] |= MARKER_FLAG_BIT;
history.RegisterChanges(MODTYPE_MARKER_SET, *selectionFrames.begin(), *selectionFrames.rbegin());
} else
{
// unset all
for(TSelectionFrames::iterator it(selectionFrames.begin()); it != selectionFrames.end(); it++)
markers.markers_array[*it] &= ~MARKER_FLAG_BIT;
history.RegisterChanges(MODTYPE_MARKER_UNSET, *selectionFrames.begin(), *selectionFrames.rbegin());
}
MarkersChanged();
project.changed = true;
ClearSelection();
RedrawList();
// no need to RedrawList();
} else
{
// buttons column
@ -624,9 +629,9 @@ void ColumnSet(int column)
for(TSelectionFrames::iterator it(selectionFrames.begin()); it != selectionFrames.end(); it++)
currMovieData.records[*it].setBitValue(joy,button,newValue);
if (newValue)
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_SET, *selectionFrames.begin(), *selectionFrames.rbegin()));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_SET, *selectionFrames.begin(), *selectionFrames.rbegin()));
else
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_UNSET, *selectionFrames.begin(), *selectionFrames.rbegin()));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_UNSET, *selectionFrames.begin(), *selectionFrames.rbegin()));
}
}
@ -862,7 +867,7 @@ bool Paste()
pGlobal = strchr(pGlobal, '\n');
}
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_PASTE, *selectionFrames.begin()));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_PASTE, *selectionFrames.begin()));
result = true;
}
@ -1417,14 +1422,14 @@ BOOL CALLBACK WndprocTasEdit(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
currMovieData.insertEmpty(index, frames);
if (TASEdit_bind_markers)
markers.insertEmpty(index, frames);
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, index));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_INSERT, index));
} else
{
// insert at playback cursor
currMovieData.insertEmpty(currFrameCounter, frames);
if (TASEdit_bind_markers)
markers.insertEmpty(currFrameCounter, frames);
greenzone.InvalidateGreenZone(history.RegisterInputChanges(MODTYPE_INSERT, currFrameCounter));
greenzone.InvalidateGreenZone(history.RegisterChanges(MODTYPE_INSERT, currFrameCounter));
}
}
}
@ -1627,8 +1632,19 @@ void FollowUndo()
{
if (!CheckItemVisible(jump_frame))
{
ListView_EnsureVisible(hwndList, currMovieData.getNumRecords()-1, true);
ListView_EnsureVisible(hwndList, jump_frame, false);
// center list at jump_frame
int list_items = listItems;
if (currMovieData.fourscore) list_items--;
int lower_border = (list_items - 1) / 2;
int upper_border = (list_items - 1) - lower_border;
int index = jump_frame + lower_border;
if (index >= currMovieData.getNumRecords())
index = currMovieData.getNumRecords()-1;
ListView_EnsureVisible(hwndList, index, false);
index = jump_frame - upper_border;
if (index < 0)
index = 0;
ListView_EnsureVisible(hwndList, index, false);
}
}
}
@ -1710,6 +1726,7 @@ void EnterTasEdit()
SetWindowPos(hwndTasEdit,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
greenzone.init();
playback.init();
// either start new movie or use current movie
if (movieMode == MOVIEMODE_INACTIVE)
@ -1722,6 +1739,7 @@ void EnterTasEdit()
{
//use current movie to create a new project
FCEUI_StopMovie();
greenzone.TryDumpIncremental(lagFlag != 0);
}
// always start work from read-only mode, ready to switch to MULTITRACK_RECORDING_ALL
movie_readonly = true;
@ -1780,8 +1798,6 @@ void EnterTasEdit()
ListView_InsertColumn(hwndHistoryList, 0, &lvc);
// init variables
greenzone.init();
greenzone.TryDumpIncremental(lagFlag != 0);
markers.init();
project.init();
history.init(TasEdit_undo_levels);
@ -1811,6 +1827,7 @@ bool ExitTasEdit()
markers.free();
greenzone.clearGreenzone();
history.free();
playback.SeekingStop();
movieMode = MOVIEMODE_INACTIVE;
FCEU_DispMessage("Tasedit disengaged",0);

View File

@ -58,6 +58,7 @@
// listview colors
#define NORMAL_FRAMENUM_COLOR 0xFFFFFF
#define UNDOHINT_FRAMENUM_COLOR 0xF9DDE6
#define MARKED_UNDOHINT_FRAMENUM_COLOR 0xE1E7EC
#define MARKED_FRAMENUM_COLOR 0xC0FCFF
#define CUR_MARKED_FRAMENUM_COLOR 0xDEF7F4
#define CUR_FRAMENUM_COLOR 0xFCF1CE

View File

@ -6,6 +6,7 @@
#include "zlib.h"
#include "taseditproj.h"
#include "../tasedit.h"
#include "zlib.h"
extern TASEDIT_PROJECT project;
extern PLAYBACK playback;
@ -14,6 +15,8 @@ extern bool TASEdit_restore_position;
extern void FCEU_printf(char *format, ...);
char greenzone_save_id[GREENZONE_ID_LEN] = "GREENZONE";
GREENZONE::GREENZONE()
{
@ -22,7 +25,6 @@ GREENZONE::GREENZONE()
void GREENZONE::init()
{
clearGreenzone();
reset();
}
void GREENZONE::reset()
@ -128,8 +130,18 @@ void GREENZONE::save(EMUFILE *os)
{
int frame, size;
int last_tick = 0;
// write "GREENZONE" string
os->fwrite(greenzone_save_id, GREENZONE_ID_LEN);
// write size
write32le(greenZoneCount, os);
// compress and write lag history
int len = lag_history.size();
uLongf comprlen = (len>>9)+12 + len;
std::vector<uint8> cbuf(comprlen);
compress(cbuf.data(), &comprlen, lag_history.data(), len);
write32le(comprlen, os);
os->fwrite(cbuf.data(), comprlen);
// write playback position
write32le(currFrameCounter, os);
// write savestates
for (frame = 0; frame < greenZoneCount; ++frame)
@ -142,35 +154,47 @@ void GREENZONE::save(EMUFILE *os)
}
if (savestates[frame].empty()) continue;
write32le(frame, os);
// write lag history
write8le(lag_history[frame], os);
// 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);
}
// returns true if couldn't load
bool GREENZONE::load(EMUFILE *is)
{
clearGreenzone();
lag_history.resize(currMovieData.getNumRecords());
int frame = 0, prev_frame = 0, size = 0;
int frame = 0, prev_frame = -1, size = 0;
int last_tick = 0;
// read "GREENZONE" string
char save_id[GREENZONE_ID_LEN];
if ((int)is->fread(save_id, GREENZONE_ID_LEN) < GREENZONE_ID_LEN) goto error;
if (strcmp(greenzone_save_id, save_id)) goto error; // string is not valid
// read size
if (read32le((uint32 *)&size, is) && size >= 0 && size <= currMovieData.getNumRecords())
{
greenZoneCount = size;
savestates.resize(greenZoneCount);
int greenzone_tail_frame = greenZoneCount-1 - TASEdit_greenzone_capacity;
// read and uncompress lag history
lag_history.resize(greenZoneCount);
int comprlen;
uLongf destlen = greenZoneCount;
if (!read32le(&comprlen, is)) goto error;
if (comprlen <= 0) goto error;
std::vector<uint8> cbuf(comprlen);
if (is->fread(cbuf.data(), comprlen) != comprlen) goto error;
int e = uncompress(lag_history.data(), &destlen, cbuf.data(), comprlen);
if (e != Z_OK && e != Z_BUF_ERROR) goto error;
// read playback position
if (read32le((uint32 *)&frame, is))
{
currFrameCounter = frame;
// read savestates
while(1)
{
if (!read32le((uint32 *)&frame, is)) break;
@ -181,8 +205,6 @@ bool GREENZONE::load(EMUFILE *is)
playback.SetProgressbar(frame, greenZoneCount);
last_tick = frame / PROGRESSBAR_UPDATE_RATE;
}
// read lag history
if (!read8le(&lag_history[frame], is)) break;
// read lua_colorings
// read monitorings
// read savestate
@ -200,19 +222,27 @@ bool GREENZONE::load(EMUFILE *is)
if (is->fseek(size,SEEK_CUR) != 0) break;
}
}
greenZoneCount = prev_frame+1; // cut greenZoneCount to last good frame
if (frame == -1)
if (prev_frame+1 == greenZoneCount)
{
// everything went fine - load savestate at cursor position
loadTasSavestate(currFrameCounter);
return false;
}
// uh, okay, but maybe we managed to read at least something from the file
for (; prev_frame >= 0; prev_frame--)
{
if (loadTasSavestate(currFrameCounter))
return true;
} else goto error;
{
greenZoneCount = prev_frame+1; // cut greenZoneCount to this good frame
currFrameCounter = prev_frame;
FCEU_printf("Greenzone loaded partially\n");
return false;
}
}
}
}
error:
// there was some error while reading greenzone
FCEU_printf("Error loading greenzone\n");
return false;
return true;
}
void GREENZONE::InvalidateGreenZone(int after)

View File

@ -2,6 +2,8 @@
//#define LAG_FLAG_BIT 1
#define GREENZONE_ID_LEN 10
class GREENZONE
{
public:

View File

@ -3,17 +3,19 @@
#include "movie.h"
#include "../common.h"
#include "../tasedit.h"
#include "inputsnapshot.h"
#include "inputhistory.h"
#include "playback.h"
#include "greenzone.h"
#include "taseditproj.h"
extern void FCEU_printf(char *format, ...);
extern HWND hwndHistoryList;
extern bool TASEdit_bind_markers;
extern PLAYBACK playback;
extern void FCEU_printf(char *format, ...);
extern HWND hwndHistoryList;
extern GREENZONE greenzone;
extern TASEDIT_PROJECT project;
char modCaptions[24][12] = {"Init",
char history_save_id[HISTORY_ID_LEN] = "HISTORY";
char modCaptions[26][12] = {"Init",
"Change",
"Set",
"Unset",
@ -36,7 +38,9 @@ char modCaptions[24][12] = {"Init",
"Branch6",
"Branch7",
"Branch8",
"Branch9"};
"Branch9",
"Mark Set",
"Mark Unset"};
char joypadCaptions[4][5] = {"(1P)", "(2P)", "(3P)", "(4P)"};
INPUT_HISTORY::INPUT_HISTORY()
@ -47,9 +51,10 @@ INPUT_HISTORY::INPUT_HISTORY()
void INPUT_HISTORY::init(int new_size)
{
// init vars
if (new_size > 0)
history_size = new_size + 1;
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;
input_snapshots.resize(history_size);
@ -97,24 +102,36 @@ int INPUT_HISTORY::jump(int new_pos)
// if nothing is done, do not invalidate greenzone
if (new_pos == history_cursor_pos) return -1;
// make jump
int old_pos = history_cursor_pos;
history_cursor_pos = new_pos;
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
RedrawHistoryList();
// create undo_hint
if (new_pos < history_cursor_pos)
if (new_pos > old_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;
// update markers
if (TASEdit_bind_markers)
{
if (input_snapshots[real_pos].checkMarkersDiff())
{
input_snapshots[real_pos].toMarkers();
project.changed = true;
}
}
int first_change = input_snapshots[real_pos].findFirstChange(currMovieData);
if (first_change < 0) return -1; // if somehow there's no changes
// update current movie
input_snapshots[real_pos].toMovie(currMovieData, first_change);
RedrawHistoryList();
int first_change = input_snapshots[real_pos].findFirstChange(currMovieData);
if (first_change >= 0)
input_snapshots[real_pos].toMovie(currMovieData, first_change);
else
RedrawList();
return first_change;
}
@ -145,7 +162,7 @@ void INPUT_HISTORY::AddInputSnapshotToHistory(INPUT_SNAPSHOT &inp)
// overwrite old snapshot
real_pos = (history_start_pos + history_cursor_pos) % history_size;
// compare with the snapshot we're going to overwrite, if it's different then break the chain of coherent snapshots
if (input_snapshots[real_pos].checkDiff(inp))
if (input_snapshots[real_pos].checkDiff(inp) || input_snapshots[real_pos].checkMarkersDiff(inp))
{
for (int i = history_cursor_pos+1; i < history_total_items; ++i)
{
@ -167,64 +184,18 @@ void INPUT_HISTORY::AddInputSnapshotToHistory(INPUT_SNAPSHOT &inp)
}
// returns frame of first actual change
int INPUT_HISTORY::RegisterInputChanges(int mod_type, int start, int end)
int INPUT_HISTORY::RegisterChanges(int mod_type, int start, int end)
{
// create new input shanshot
INPUT_SNAPSHOT inp;
inp.init(currMovieData);
// check if there are differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(input_snapshots[real_pos], start, end);
if (first_changes >= 0)
if (mod_type == MODTYPE_MARKER_SET || mod_type == MODTYPE_MARKER_UNSET)
{
// differences found
// fade old hot_changes by 1
// highlight new hot changes
// special case: changed markers, but input didn't change
// fill description
strcat(inp.description, modCaptions[mod_type]);
switch (mod_type)
{
case MODTYPE_CHANGE:
case MODTYPE_SET:
case MODTYPE_UNSET:
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:
case MODTYPE_BRANCH_6: case MODTYPE_BRANCH_7:
case MODTYPE_BRANCH_8: case MODTYPE_BRANCH_9:
{
inp.jump_frame = first_changes;
break;
}
case MODTYPE_INSERT:
case MODTYPE_DELETE:
case MODTYPE_PASTE:
case MODTYPE_PASTEINSERT:
case MODTYPE_CLONE:
{
// for these changes user prefers to see frame of attempted change (selection beginning), not frame of actual differences
inp.jump_frame = start;
break;
}
case MODTYPE_RECORD:
{
// add info which joypads were affected
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))
strcat(inp.description, joypadCaptions[i]);
}
inp.jump_frame = start;
}
}
// add upper and lower frame to description
inp.jump_frame = start;
// add the frame to description
char framenum[11];
_itoa(start, framenum, 10);
strcat(inp.description, " ");
@ -236,13 +207,83 @@ int INPUT_HISTORY::RegisterInputChanges(int mod_type, int start, int end)
strcat(inp.description, framenum);
}
AddInputSnapshotToHistory(inp);
return -1;
} else
{
// check if there are input differences from latest snapshot
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
int first_changes = inp.findFirstChange(input_snapshots[real_pos], start, end);
if (first_changes >= 0)
{
// differences found
// fade old hot_changes by 1
// highlight new hot changes
// fill description
strcat(inp.description, modCaptions[mod_type]);
switch (mod_type)
{
case MODTYPE_CHANGE:
case MODTYPE_SET:
case MODTYPE_UNSET:
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:
case MODTYPE_BRANCH_6: case MODTYPE_BRANCH_7:
case MODTYPE_BRANCH_8: case MODTYPE_BRANCH_9:
{
inp.jump_frame = first_changes;
break;
}
case MODTYPE_INSERT:
case MODTYPE_DELETE:
case MODTYPE_PASTE:
case MODTYPE_PASTEINSERT:
case MODTYPE_CLONE:
{
// for these changes user prefers to see frame of attempted change (selection beginning), not frame of actual differences
inp.jump_frame = start;
break;
}
case MODTYPE_RECORD:
{
// add info which joypads were affected
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))
strcat(inp.description, joypadCaptions[i]);
}
inp.jump_frame = start;
}
}
// add upper and lower frame to description
char framenum[11];
_itoa(start, framenum, 10);
strcat(inp.description, " ");
strcat(inp.description, framenum);
if (end > start)
{
_itoa(end, framenum, 10);
strcat(inp.description, "-");
strcat(inp.description, framenum);
}
AddInputSnapshotToHistory(inp);
}
return first_changes;
}
return first_changes;
}
void INPUT_HISTORY::save(EMUFILE *os)
{
int real_pos, last_tick = 0;
// write "HISTORY" string
os->fwrite(history_save_id, HISTORY_ID_LEN);
// write vars
write32le(history_cursor_pos, os);
write32le(history_total_items, os);
@ -254,12 +295,17 @@ void INPUT_HISTORY::save(EMUFILE *os)
playback.SetProgressbar(i, history_total_items);
}
}
void INPUT_HISTORY::load(EMUFILE *is)
// returns true if couldn't load
bool INPUT_HISTORY::load(EMUFILE *is)
{
int i = -1;
INPUT_SNAPSHOT inp;
// delete old snapshots
input_snapshots.resize(history_size);
// read "HISTORY" string
char save_id[HISTORY_ID_LEN];
if ((int)is->fread(save_id, HISTORY_ID_LEN) < HISTORY_ID_LEN) goto error;
if (strcmp(history_save_id, save_id)) goto error; // string is not valid
// read vars
if (!read32le((uint32 *)&history_cursor_pos, is)) goto error;
if (!read32le((uint32 *)&history_total_items, is)) goto error;
@ -301,13 +347,12 @@ void INPUT_HISTORY::load(EMUFILE *is)
undo_hint_pos = old_undo_hint_pos = undo_hint_time = -1;
old_show_undo_hint = show_undo_hint = false;
// everything went well
UpdateHistoryList();
RedrawHistoryList();
return;
return false;
error:
// couldn't load full history - reset it
FCEU_printf("Error loading history\n");
init(history_size-1);
return true;
}
// ----------------------------
void INPUT_HISTORY::GetDispInfo(NMLVDISPINFO* nmlvDispInfo)

View File

@ -26,21 +26,25 @@
#define MODTYPE_BRANCH_7 21
#define MODTYPE_BRANCH_8 22
#define MODTYPE_BRANCH_9 23
#define MODTYPE_MARKER_SET 24
#define MODTYPE_MARKER_UNSET 25
#define HISTORY_COHERENT_COLOR 0xF9DDE6
#define HISTORY_NORMAL_COLOR 0xFFFFFF
#define HISTORY_ID_LEN 8
class INPUT_HISTORY
{
public:
INPUT_HISTORY();
void init(int new_size);
void init(int new_size = 0);
void free();
void update(); // called every frame
void save(EMUFILE *os);
void load(EMUFILE *is);
bool load(EMUFILE *is);
int undo();
int redo();
@ -48,7 +52,7 @@ public:
void AddInputSnapshotToHistory(INPUT_SNAPSHOT &inp);
int RegisterInputChanges(int mod_type, int start = 0, int end =-1);
int RegisterChanges(int mod_type, int start = 0, int end =-1);
int InputChanged(int start, int end);
int InputInserted(int start);

View File

@ -2,12 +2,15 @@
#include "movie.h"
#include "inputsnapshot.h"
#include "markers.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, ...);
extern MARKERS markers;
INPUT_SNAPSHOT::INPUT_SNAPSHOT()
{
@ -15,6 +18,7 @@ INPUT_SNAPSHOT::INPUT_SNAPSHOT()
void INPUT_SNAPSHOT::init(MovieData& md)
{
already_compressed = false;
// retrieve input data from movie data
size = md.getNumRecords();
input_type = (md.fourscore)?1:0;
@ -45,6 +49,9 @@ void INPUT_SNAPSHOT::init(MovieData& md)
break;
}
}
// make a copy of markers.markers_array
markers_array = markers.markers_array;
coherent = true;
// save time to description
time_t raw_time;
@ -53,6 +60,11 @@ void INPUT_SNAPSHOT::init(MovieData& md)
strftime(description, 10, "%H:%M:%S ", timeinfo);
}
void INPUT_SNAPSHOT::toMarkers()
{
markers.markers_array = markers_array;
}
void INPUT_SNAPSHOT::toMovie(MovieData& md, int start)
{
// write input data to movie data
@ -84,6 +96,30 @@ void INPUT_SNAPSHOT::toMovie(MovieData& md, int start)
}
}
void INPUT_SNAPSHOT::compress_data()
{
// compress joysticks
int len = joysticks.size();
uLongf comprlen = (len>>9)+12 + len;
joysticks_compressed.resize(comprlen);
compress(joysticks_compressed.data(), &comprlen, joysticks.data(), len);
joysticks_compressed.resize(comprlen);
// compress hot_changes
len = hot_changes.size();
comprlen = (len>>9)+12 + len;
hot_changes_compressed.resize(comprlen);
compress(hot_changes_compressed.data(), &comprlen, hot_changes.data(), len);
hot_changes_compressed.resize(comprlen);
// compress markers
len = markers_array.size();
comprlen = (len>>9)+12 + len;
markers_array_compressed.resize(comprlen);
compress(markers_array_compressed.data(), &comprlen, markers_array.data(), len);
markers_array_compressed.resize(comprlen);
// don't compress anymore
already_compressed = true;
}
void INPUT_SNAPSHOT::save(EMUFILE *os)
{
// write vars
@ -95,22 +131,18 @@ void INPUT_SNAPSHOT::save(EMUFILE *os)
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);
// write data
if (!already_compressed)
compress_data();
// save joysticks data
write32le(joysticks_compressed.size(), os);
os->fwrite(joysticks_compressed.data(), joysticks_compressed.size());
// save hot_changes data
write32le(hot_changes_compressed.size(), os);
os->fwrite(hot_changes_compressed.data(), hot_changes_compressed.size());
// save markers data
write32le(markers_array_compressed.size(), os);
os->fwrite(markers_array_compressed.data(), markers_array_compressed.size());
}
bool INPUT_SNAPSHOT::load(EMUFILE *is)
{
@ -128,27 +160,41 @@ bool INPUT_SNAPSHOT::load(EMUFILE *is)
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
// read data
already_compressed = true;
int comprlen;
uLongf destlen;
// read and uncompress joysticks data
destlen = size * bytes_per_frame[input_type];
joysticks.resize(destlen);
// read size
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 (comprlen <= 0) return false;
joysticks_compressed.resize(comprlen);
if (is->fread(joysticks_compressed.data(), comprlen) != comprlen) return false;
int e = uncompress(joysticks.data(), &destlen, joysticks_compressed.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);
destlen = size * bytes_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
hot_changes.resize(destlen);
// 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 (comprlen <= 0) return false;
hot_changes_compressed.resize(comprlen);
if (is->fread(hot_changes_compressed.data(), comprlen) != comprlen) return false;
e = uncompress(hot_changes.data(), &destlen, hot_changes_compressed.data(), comprlen);
if (e != Z_OK && e != Z_BUF_ERROR) return false;
// read and uncompress markers data
destlen = size;
markers_array.resize(destlen);
// read size
if (!read32le(&comprlen, is)) return false;
if (comprlen <= 0) return false;
markers_array_compressed.resize(comprlen);
if (is->fread(markers_array_compressed.data(), comprlen) != comprlen) return false;
e = uncompress(markers_array.data(), &destlen, markers_array_compressed.data(), comprlen);
if (e != Z_OK && e != Z_BUF_ERROR) return false;
return true;
}
bool INPUT_SNAPSHOT::skipLoad(EMUFILE *is)
@ -204,6 +250,24 @@ bool INPUT_SNAPSHOT::checkJoypadDiff(INPUT_SNAPSHOT& inp, int frame, int joy)
}
return false;
}
// return true if any difference in markers_array is found
bool INPUT_SNAPSHOT::checkMarkersDiff(INPUT_SNAPSHOT& inp)
{
if (size != inp.size) return true;
for (int i = size-1; i >= 0; i--)
if ((markers_array[i] - inp.markers_array[i]) & MARKER_FLAG_BIT) return true;
return false;
}
// return true if any difference in markers_array is found, comparing to markers.markers_array
bool INPUT_SNAPSHOT::checkMarkersDiff()
{
if (markers_array.size() != markers.markers_array.size()) return true;
for (int i = markers_array.size()-1; i >= 0; i--)
if ((markers_array[i] - markers.markers_array[i]) & MARKER_FLAG_BIT) return true;
return false;
}
// return number of first frame of difference
int INPUT_SNAPSHOT::findFirstChange(INPUT_SNAPSHOT& inp, int start, int end)
{

View File

@ -14,7 +14,9 @@ class INPUT_SNAPSHOT
public:
INPUT_SNAPSHOT();
void init(MovieData& md);
void toMovie(MovieData& md, int start = 0);
void toMarkers();
void save(EMUFILE *os);
bool load(EMUFILE *is);
@ -22,6 +24,10 @@ public:
bool checkDiff(INPUT_SNAPSHOT& inp);
bool checkJoypadDiff(INPUT_SNAPSHOT& inp, int frame, int joy);
bool checkMarkersDiff(INPUT_SNAPSHOT& inp);
bool checkMarkersDiff();
int findFirstChange(INPUT_SNAPSHOT& inp, int start = 0, int end = -1);
int findFirstChange(MovieData& md);
@ -32,12 +38,19 @@ public:
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, ...
std::vector<uint8> markers_array; // just a copy of markers.markers_array
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:
void compress_data();
bool already_compressed; // to compress only once
std::vector<uint8> joysticks_compressed;
std::vector<uint8> hot_changes_compressed;
std::vector<uint8> markers_array_compressed;
};

View File

@ -4,7 +4,9 @@
#include "../common.h"
#include "taseditproj.h"
//#include "../tasedit.h"
#include "zlib.h"
char markers_save_id[MARKERS_ID_LEN] = "MARKERS";
MARKERS::MARKERS()
{
@ -29,24 +31,43 @@ void MARKERS::update()
void MARKERS::save(EMUFILE *os)
{
// write "MARKERS" string
os->fwrite(markers_save_id, MARKERS_ID_LEN);
// write size
int size = markers_array.size();
write32le(size, os);
// write array
os->fwrite(markers_array.data(), size);
// compress and write array
int len = markers_array.size();
uLongf comprlen = (len>>9)+12 + len;
std::vector<uint8> cbuf(comprlen);
compress(cbuf.data(), &comprlen, markers_array.data(), len);
write32le(comprlen, os);
os->fwrite(cbuf.data(), comprlen);
}
// returns true if couldn't load
bool MARKERS::load(EMUFILE *is)
{
markers_array.resize(currMovieData.getNumRecords());
// read "MARKERS" string
char save_id[MARKERS_ID_LEN];
if ((int)is->fread(save_id, MARKERS_ID_LEN) < MARKERS_ID_LEN) goto error;
if (strcmp(markers_save_id, save_id)) goto error; // string is not valid
int size;
if (read32le((uint32 *)&size, is) && size == currMovieData.getNumRecords())
{
// read array
if ((int)is->fread(markers_array.data(), size) == size) return true;
// read and uncompress array
int comprlen;
uLongf destlen = size;
if (!read32le(&comprlen, is)) goto error;
if (comprlen <= 0) goto error;
std::vector<uint8> cbuf(comprlen);
if (is->fread(cbuf.data(), comprlen) != comprlen) goto error;
int e = uncompress(markers_array.data(), &destlen, cbuf.data(), comprlen);
if (e != Z_OK && e != Z_BUF_ERROR) goto error;
return false;
}
error:
FCEU_printf("Error loading markers\n");
return false;
return true;
}
// ----------------------------------------------------------
void MARKERS::ToggleMarker(int frame)

View File

@ -2,6 +2,8 @@
#define MARKER_FLAG_BIT 1
#define MARKERS_ID_LEN 8
class MARKERS
{
public:

View File

@ -291,7 +291,8 @@ bool PLAYBACK::JumpToFrame(int index)
else
currFrameCounter = i;
// continue from the frame
SeekingStart(index+1);
if (index != currFrameCounter)
SeekingStart(index+1);
return false;
}

View File

@ -65,23 +65,38 @@ bool TASEDIT_PROJECT::LoadProject(std::string PFN)
EMUFILE_FILE ifs(filename, "rb");
FCEU_printf("Loading TASEdit project %s\n", filename);
FCEU_printf("\nLoading TASEdit project %s\n", filename);
bool error;
LoadFM2(currMovieData, &ifs, ifs.size(), false);
LoadSubtitles(currMovieData);
// try to load markers
if (markers.load(&ifs))
error = markers.load(&ifs);
if (error)
{
FCEU_printf("Error loading markers\n");
markers.init();
} else
{
// try to load greenzone
if (greenzone.load(&ifs))
{
// there was some error while loading greenzone - reset playback to frame 0
poweron(true);
currFrameCounter = 0;
// try to load history
history.load(&ifs);
}
error = greenzone.load(&ifs);
}
if (error)
{
FCEU_printf("Error loading greenzone\n");
greenzone.init();
playback.StartFromZero(); // reset playback to frame 0
} else
{
// try to load history
error = history.load(&ifs);
}
if (error)
{
FCEU_printf("Error loading history\n");
history.init();
}
reset();
playback.updateProgressbar();
return true;

View File

@ -1676,6 +1676,7 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
if(!LuaConsoleHWnd)
LuaConsoleHWnd = CreateDialog(fceu_hInstance, MAKEINTRESOURCE(IDD_LUA), hWnd, (DLGPROC) DlgLuaScriptDialog);
else
ShowWindow(LuaConsoleHWnd, SW_SHOWNORMAL);
SetForegroundWindow(LuaConsoleHWnd);
break;
case FCEUX_CONTEXT_CLOSELUAWINDOWS:
@ -1686,6 +1687,8 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
//Recent Lua 1
#ifdef _S9XLUA_H
case FCEUX_CONTEXT_LOADLASTLUA:
ShowWindow(LuaConsoleHWnd, SW_SHOWNORMAL);
SetForegroundWindow(LuaConsoleHWnd);
if(recent_lua[0])
{
if (!FCEU_LoadLuaCode(recent_lua[0]))

View File

@ -721,7 +721,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
#ifdef WIN32
if(FCEUMOV_Mode(MOVIEMODE_TASEDIT))
greenzone.TryDumpIncremental((bool)lagFlag);
greenzone.TryDumpIncremental(lagFlag != 0);
#endif
}