* Taseditor: fixed AdjustLag feature
* Taseditor: changed fm3 version to v2 * Taseditor: Ctrl+Z/Ctrl+Y trigger twice when crossing AdjustLag operations
This commit is contained in:
parent
acfb5bf912
commit
fd35046e62
|
@ -322,7 +322,7 @@ void NewProject()
|
|||
ApplyMovieInputConfig();
|
||||
if (params.copy_current_input)
|
||||
// copy Input from current snapshot (from history)
|
||||
history.GetCurrentSnapshot().toMovie(currMovieData);
|
||||
history.GetCurrentSnapshot().inputlog.toMovie(currMovieData);
|
||||
if (!params.copy_current_markers)
|
||||
markers_manager.reset();
|
||||
if (params.author_name != L"") currMovieData.comments.push_back(L"author " + params.author_name);
|
||||
|
@ -330,6 +330,9 @@ void NewProject()
|
|||
// reset Taseditor
|
||||
project.init(); // new project has blank name
|
||||
greenzone.reset();
|
||||
if (params.copy_current_input)
|
||||
// copy LagLog from current snapshot (from history)
|
||||
greenzone.laglog = history.GetCurrentSnapshot().laglog;
|
||||
playback.reset();
|
||||
playback.StartFromZero();
|
||||
bookmarks.reset();
|
||||
|
|
|
@ -47,13 +47,13 @@ void BOOKMARK::free()
|
|||
bool BOOKMARK::checkDiffFromCurrent()
|
||||
{
|
||||
// check if the Bookmark data differs from current project/MovieData/Markers/settings
|
||||
if (not_empty && snapshot.jump_frame == currFrameCounter)
|
||||
if (not_empty && snapshot.keyframe == currFrameCounter)
|
||||
{
|
||||
if (snapshot.size == currMovieData.getNumRecords() && snapshot.findFirstChange(currMovieData) < 0)
|
||||
if (snapshot.inputlog.size == currMovieData.getNumRecords() && snapshot.inputlog.findFirstChange(currMovieData) < 0)
|
||||
{
|
||||
if (!snapshot.MarkersDifferFromCurrent())
|
||||
{
|
||||
if (snapshot.has_hot_changes == taseditor_config.enable_hot_changes)
|
||||
if (snapshot.inputlog.has_hot_changes == taseditor_config.enable_hot_changes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -67,9 +67,9 @@ void BOOKMARK::set()
|
|||
{
|
||||
// copy Input and Hotchanges
|
||||
snapshot.init(currMovieData, taseditor_config.enable_hot_changes);
|
||||
snapshot.jump_frame = currFrameCounter;
|
||||
snapshot.keyframe = currFrameCounter;
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
snapshot.copyHotChanges(&history.GetCurrentSnapshot());
|
||||
snapshot.inputlog.copyHotChanges(&history.GetCurrentSnapshot().inputlog);
|
||||
// copy savestate
|
||||
savestate = greenzone.GetSavestate(currFrameCounter);
|
||||
// save screenshot
|
||||
|
@ -164,5 +164,3 @@ bool BOOKMARK::skipLoad(EMUFILE *is)
|
|||
}
|
||||
// ----------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ void BOOKMARKS::init()
|
|||
lvc.mask = LVCF_WIDTH;
|
||||
lvc.cx = BOOKMARKSLIST_COLUMN_ICONS_WIDTH;
|
||||
ListView_InsertColumn(hwndBookmarksList, 0, &lvc);
|
||||
// jump_frame column
|
||||
// keyframe column
|
||||
lvc.mask = LVCF_WIDTH | LVCF_FMT;
|
||||
lvc.fmt = LVCFMT_CENTER;
|
||||
lvc.cx = BOOKMARKSLIST_COLUMN_FRAMENUM_WIDTH;
|
||||
|
@ -352,7 +352,7 @@ void BOOKMARKS::set(int slot)
|
|||
// First save changes in edited note (in case it's being currently edited)
|
||||
markers_manager.UpdateMarkerNote();
|
||||
|
||||
int previous_frame = bookmarks_array[slot].snapshot.jump_frame;
|
||||
int previous_frame = bookmarks_array[slot].snapshot.keyframe;
|
||||
if (bookmarks_array[slot].checkDiffFromCurrent())
|
||||
{
|
||||
BOOKMARK backup_copy(bookmarks_array[slot]);
|
||||
|
@ -363,8 +363,8 @@ void BOOKMARKS::set(int slot)
|
|||
if (slot != old_current_branch && old_current_branch != ITEM_UNDER_MOUSE_CLOUD)
|
||||
{
|
||||
// current_branch was switched to slot, redraw Bookmarks List to change the color of digits
|
||||
piano_roll.RedrawRow(bookmarks_array[old_current_branch].snapshot.jump_frame);
|
||||
RedrawChangedBookmarks(bookmarks_array[old_current_branch].snapshot.jump_frame);
|
||||
piano_roll.RedrawRow(bookmarks_array[old_current_branch].snapshot.keyframe);
|
||||
RedrawChangedBookmarks(bookmarks_array[old_current_branch].snapshot.keyframe);
|
||||
}
|
||||
// also redraw List rows
|
||||
if (previous_frame >= 0 && previous_frame != currFrameCounter)
|
||||
|
@ -389,7 +389,7 @@ void BOOKMARKS::jump(int slot)
|
|||
if (slot < 0 || slot >= TOTAL_BOOKMARKS) return;
|
||||
if (bookmarks_array[slot].not_empty)
|
||||
{
|
||||
int frame = bookmarks_array[slot].snapshot.jump_frame;
|
||||
int frame = bookmarks_array[slot].snapshot.keyframe;
|
||||
playback.jump(frame);
|
||||
piano_roll.FollowPauseframe();
|
||||
bookmarks_array[slot].jumped();
|
||||
|
@ -406,7 +406,7 @@ void BOOKMARKS::deploy(int slot)
|
|||
if (slot < 0 || slot >= TOTAL_BOOKMARKS) return;
|
||||
if (!bookmarks_array[slot].not_empty) return;
|
||||
|
||||
int jump_frame = bookmarks_array[slot].snapshot.jump_frame;
|
||||
int keyframe = bookmarks_array[slot].snapshot.keyframe;
|
||||
bool markers_changed = false;
|
||||
// revert Markers to the Bookmarked state
|
||||
//if (taseditor_config.bind_markers)
|
||||
|
@ -420,17 +420,20 @@ void BOOKMARKS::deploy(int slot)
|
|||
// revert current movie data to the Bookmarked state
|
||||
if (taseditor_config.branch_full_movie)
|
||||
{
|
||||
bookmarks_array[slot].snapshot.toMovie(currMovieData);
|
||||
bookmarks_array[slot].snapshot.inputlog.toMovie(currMovieData);
|
||||
} else
|
||||
{
|
||||
// restore movie up to and not including bookmarked frame (simulating old TASing method)
|
||||
if (jump_frame)
|
||||
bookmarks_array[slot].snapshot.toMovie(currMovieData, 0, jump_frame - 1);
|
||||
if (keyframe)
|
||||
bookmarks_array[slot].snapshot.inputlog.toMovie(currMovieData, 0, keyframe - 1);
|
||||
else
|
||||
currMovieData.truncateAt(0);
|
||||
// add empty frame at the end (at jump_frame)
|
||||
// add empty frame at the end (at keyframe)
|
||||
currMovieData.insertEmpty(-1, 1);
|
||||
}
|
||||
// revert Greenzone's LagLog to the Bookmarked state
|
||||
greenzone.laglog = bookmarks_array[slot].snapshot.laglog;
|
||||
|
||||
int first_change = history.RegisterBranching(slot, markers_changed);
|
||||
if (first_change >= 0)
|
||||
{
|
||||
|
@ -449,18 +452,18 @@ void BOOKMARKS::deploy(int slot)
|
|||
bookmarks_array[slot].jumped();
|
||||
}
|
||||
// jump to the target (bookmarked frame)
|
||||
if (greenzone.SavestateIsEmpty(jump_frame))
|
||||
greenzone.WriteSavestate(jump_frame, bookmarks_array[slot].savestate);
|
||||
playback.jump(jump_frame);
|
||||
if (greenzone.SavestateIsEmpty(keyframe))
|
||||
greenzone.WriteSavestate(keyframe, bookmarks_array[slot].savestate);
|
||||
playback.jump(keyframe);
|
||||
// switch current branch to this branch
|
||||
int old_current_branch = branches.GetCurrentBranch();
|
||||
branches.HandleBookmarkDeploy(slot);
|
||||
if (slot != old_current_branch && old_current_branch != ITEM_UNDER_MOUSE_CLOUD)
|
||||
{
|
||||
piano_roll.RedrawRow(bookmarks_array[old_current_branch].snapshot.jump_frame);
|
||||
RedrawChangedBookmarks(bookmarks_array[old_current_branch].snapshot.jump_frame);
|
||||
piano_roll.RedrawRow(jump_frame);
|
||||
RedrawChangedBookmarks(jump_frame);
|
||||
piano_roll.RedrawRow(bookmarks_array[old_current_branch].snapshot.keyframe);
|
||||
RedrawChangedBookmarks(bookmarks_array[old_current_branch].snapshot.keyframe);
|
||||
piano_roll.RedrawRow(keyframe);
|
||||
RedrawChangedBookmarks(keyframe);
|
||||
}
|
||||
FCEU_DispMessage("Branch %d loaded.", 0, slot);
|
||||
}
|
||||
|
@ -553,7 +556,7 @@ void BOOKMARKS::RedrawChangedBookmarks(int frame)
|
|||
{
|
||||
for (int i = 0; i < TOTAL_BOOKMARKS; ++i)
|
||||
{
|
||||
if (bookmarks_array[i].snapshot.jump_frame == frame)
|
||||
if (bookmarks_array[i].snapshot.keyframe == frame)
|
||||
RedrawBookmark(i);
|
||||
}
|
||||
}
|
||||
|
@ -614,7 +617,7 @@ void BOOKMARKS::GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
|
|||
case BOOKMARKS_COLUMN_FRAME:
|
||||
{
|
||||
if (bookmarks_array[(item.iItem + 1) % TOTAL_BOOKMARKS].not_empty)
|
||||
U32ToDecStr(item.pszText, bookmarks_array[(item.iItem + 1) % TOTAL_BOOKMARKS].snapshot.jump_frame, DIGITS_IN_FRAMENUM);
|
||||
U32ToDecStr(item.pszText, bookmarks_array[(item.iItem + 1) % TOTAL_BOOKMARKS].snapshot.keyframe, DIGITS_IN_FRAMENUM);
|
||||
break;
|
||||
}
|
||||
case BOOKMARKS_COLUMN_TIME:
|
||||
|
@ -650,7 +653,7 @@ LONG BOOKMARKS::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
{
|
||||
// frame number
|
||||
SelectObject(msg->nmcd.hdc, piano_roll.hMainListFont);
|
||||
int frame = bookmarks_array[cell_y].snapshot.jump_frame;
|
||||
int frame = bookmarks_array[cell_y].snapshot.keyframe;
|
||||
if (frame == currFrameCounter || frame == (playback.GetFlashingPauseFrame() - 1))
|
||||
{
|
||||
// current frame
|
||||
|
@ -659,7 +662,7 @@ LONG BOOKMARKS::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
{
|
||||
if (!greenzone.SavestateIsEmpty(frame))
|
||||
{
|
||||
if (greenzone.GetLagHistoryAtFrame(frame))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(frame))
|
||||
msg->clrTextBk = LAG_FRAMENUM_COLOR;
|
||||
else
|
||||
msg->clrTextBk = GREENZONE_FRAMENUM_COLOR;
|
||||
|
@ -668,7 +671,7 @@ LONG BOOKMARKS::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
|| (!greenzone.SavestateIsEmpty(frame & EVERY4TH) && !greenzone.SavestateIsEmpty((frame & EVERY4TH) + 4))
|
||||
|| (!greenzone.SavestateIsEmpty(frame & EVERY2ND) && !greenzone.SavestateIsEmpty((frame & EVERY2ND) + 2)))
|
||||
{
|
||||
if (greenzone.GetLagHistoryAtFrame(frame))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(frame))
|
||||
msg->clrTextBk = PALE_LAG_FRAMENUM_COLOR;
|
||||
else
|
||||
msg->clrTextBk = PALE_GREENZONE_FRAMENUM_COLOR;
|
||||
|
@ -681,7 +684,7 @@ LONG BOOKMARKS::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
{
|
||||
// frame number
|
||||
SelectObject(msg->nmcd.hdc, piano_roll.hMainListFont);
|
||||
int frame = bookmarks_array[cell_y].snapshot.jump_frame;
|
||||
int frame = bookmarks_array[cell_y].snapshot.keyframe;
|
||||
if (frame == currFrameCounter || frame == (playback.GetFlashingPauseFrame() - 1))
|
||||
{
|
||||
// current frame
|
||||
|
@ -690,7 +693,7 @@ LONG BOOKMARKS::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
{
|
||||
if (!greenzone.SavestateIsEmpty(frame))
|
||||
{
|
||||
if (greenzone.GetLagHistoryAtFrame(frame))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(frame))
|
||||
msg->clrTextBk = LAG_INPUT_COLOR1;
|
||||
else
|
||||
msg->clrTextBk = GREENZONE_INPUT_COLOR1;
|
||||
|
@ -699,7 +702,7 @@ LONG BOOKMARKS::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
|| (!greenzone.SavestateIsEmpty(frame & EVERY4TH) && !greenzone.SavestateIsEmpty((frame & EVERY4TH) + 4))
|
||||
|| (!greenzone.SavestateIsEmpty(frame & EVERY2ND) && !greenzone.SavestateIsEmpty((frame & EVERY2ND) + 2)))
|
||||
{
|
||||
if (greenzone.GetLagHistoryAtFrame(frame))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(frame))
|
||||
msg->clrTextBk = PALE_LAG_INPUT_COLOR1;
|
||||
else
|
||||
msg->clrTextBk = PALE_GREENZONE_INPUT_COLOR1;
|
||||
|
@ -728,12 +731,12 @@ void BOOKMARKS::RightClick()
|
|||
int BOOKMARKS::FindBookmarkAtFrame(int frame)
|
||||
{
|
||||
int cur_bookmark = branches.GetCurrentBranch();
|
||||
if (cur_bookmark != ITEM_UNDER_MOUSE_CLOUD && bookmarks_array[cur_bookmark].snapshot.jump_frame == frame)
|
||||
if (cur_bookmark != ITEM_UNDER_MOUSE_CLOUD && bookmarks_array[cur_bookmark].snapshot.keyframe == frame)
|
||||
return cur_bookmark + TOTAL_BOOKMARKS; // blue digit has highest priority when drawing
|
||||
for (int i = 0; i < TOTAL_BOOKMARKS; ++i)
|
||||
{
|
||||
cur_bookmark = (i + 1) % TOTAL_BOOKMARKS;
|
||||
if (bookmarks_array[cur_bookmark].not_empty && bookmarks_array[cur_bookmark].snapshot.jump_frame == frame)
|
||||
if (bookmarks_array[cur_bookmark].not_empty && bookmarks_array[cur_bookmark].snapshot.keyframe == frame)
|
||||
return cur_bookmark; // green digit
|
||||
}
|
||||
return -1; // no Bookmarks at the frame
|
||||
|
|
|
@ -312,7 +312,7 @@ void BRANCHES::update()
|
|||
} else
|
||||
{
|
||||
parent = FindFullTimelineForBranch(current_branch);
|
||||
if (parent != current_branch && bookmarks.bookmarks_array[parent].snapshot.jump_frame == bookmarks.bookmarks_array[current_branch].snapshot.jump_frame)
|
||||
if (parent != current_branch && bookmarks.bookmarks_array[parent].snapshot.keyframe == bookmarks.bookmarks_array[current_branch].snapshot.keyframe)
|
||||
parent = current_branch;
|
||||
}
|
||||
do
|
||||
|
@ -325,12 +325,12 @@ void BRANCHES::update()
|
|||
if (parent == ITEM_UNDER_MOUSE_CLOUD)
|
||||
lower_frame = -1;
|
||||
else
|
||||
lower_frame = bookmarks.bookmarks_array[parent].snapshot.jump_frame;
|
||||
lower_frame = bookmarks.bookmarks_array[parent].snapshot.keyframe;
|
||||
} while (parent != ITEM_UNDER_MOUSE_CLOUD && currFrameCounter < lower_frame);
|
||||
if (branch == TOTAL_BOOKMARKS)
|
||||
upper_frame = currMovieData.getNumRecords() - 1;
|
||||
else
|
||||
upper_frame = bookmarks.bookmarks_array[branch].snapshot.jump_frame;
|
||||
upper_frame = bookmarks.bookmarks_array[branch].snapshot.keyframe;
|
||||
branch_x = BranchCurrX[branch];
|
||||
branch_y = BranchCurrY[branch];
|
||||
if (parent == ITEM_UNDER_MOUSE_CLOUD)
|
||||
|
@ -611,12 +611,12 @@ void BRANCHES::RedrawBranchesTree()
|
|||
if (IsSafeToShowBranchesData())
|
||||
{
|
||||
SetBkMode(hBitmapDC, TRANSPARENT);
|
||||
// jump_frame of item under cursor (except cloud - it doesn't have particular frame)
|
||||
// keyframe of item under cursor (except cloud - it doesn't have particular frame)
|
||||
if (bookmarks.item_under_mouse == TOTAL_BOOKMARKS || (bookmarks.item_under_mouse >= 0 && bookmarks.item_under_mouse < TOTAL_BOOKMARKS && bookmarks.bookmarks_array[bookmarks.item_under_mouse].not_empty))
|
||||
{
|
||||
char framenum_string[DIGITS_IN_FRAMENUM+1] = {0};
|
||||
if (bookmarks.item_under_mouse < TOTAL_BOOKMARKS)
|
||||
U32ToDecStr(framenum_string, bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.jump_frame, DIGITS_IN_FRAMENUM);
|
||||
U32ToDecStr(framenum_string, bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.keyframe, DIGITS_IN_FRAMENUM);
|
||||
else
|
||||
U32ToDecStr(framenum_string, currFrameCounter, DIGITS_IN_FRAMENUM);
|
||||
SetTextColor(hBitmapDC, BRANCHES_TEXT_SHADOW_COLOR);
|
||||
|
@ -769,19 +769,19 @@ void BRANCHES::InvalidateBranchSlot(int slot)
|
|||
parents[i] = ITEM_UNDER_MOUSE_CLOUD;
|
||||
}
|
||||
}
|
||||
// returns the frame of first difference between snapshots of two Branches
|
||||
// returns the frame of first difference between InputLogs of snapshots of two Branches
|
||||
int BRANCHES::GetFirstDifference(int first_branch, int second_branch)
|
||||
{
|
||||
if (first_branch == second_branch)
|
||||
return bookmarks.bookmarks_array[first_branch].snapshot.size;
|
||||
return bookmarks.bookmarks_array[first_branch].snapshot.inputlog.size;
|
||||
|
||||
if (cached_first_difference[first_branch][second_branch] == FIRST_DIFFERENCE_UNKNOWN)
|
||||
{
|
||||
if (bookmarks.bookmarks_array[first_branch].not_empty && bookmarks.bookmarks_array[second_branch].not_empty)
|
||||
{
|
||||
int frame = bookmarks.bookmarks_array[first_branch].snapshot.findFirstChange(bookmarks.bookmarks_array[second_branch].snapshot);
|
||||
int frame = bookmarks.bookmarks_array[first_branch].snapshot.inputlog.findFirstChange(bookmarks.bookmarks_array[second_branch].snapshot.inputlog);
|
||||
if (frame < 0)
|
||||
frame = bookmarks.bookmarks_array[first_branch].snapshot.size;
|
||||
frame = bookmarks.bookmarks_array[first_branch].snapshot.inputlog.size;
|
||||
cached_first_difference[first_branch][second_branch] = frame;
|
||||
cached_first_difference[second_branch][first_branch] = frame;
|
||||
return frame;
|
||||
|
@ -796,7 +796,7 @@ int BRANCHES::FindFullTimelineForBranch(int branch_num)
|
|||
{
|
||||
cached_timelines[branch_num] = branch_num; // by default
|
||||
std::vector<int> candidates;
|
||||
int temp_jump_frame, temp_parent, max_jump_frame, max_first_difference;
|
||||
int temp_keyframe, temp_parent, max_keyframe, max_first_difference;
|
||||
// 1 - find max_first_difference among Branches that are in the same timeline
|
||||
max_first_difference = -1;
|
||||
int first_diff;
|
||||
|
@ -805,18 +805,18 @@ int BRANCHES::FindFullTimelineForBranch(int branch_num)
|
|||
if (i != branch_num && bookmarks.bookmarks_array[i].not_empty)
|
||||
{
|
||||
first_diff = GetFirstDifference(branch_num, i);
|
||||
if (first_diff >= bookmarks.bookmarks_array[i].snapshot.jump_frame)
|
||||
if (first_diff >= bookmarks.bookmarks_array[i].snapshot.keyframe)
|
||||
if (max_first_difference < first_diff)
|
||||
max_first_difference = first_diff;
|
||||
}
|
||||
}
|
||||
// 2 - find max_jump_frame among those Branches whose first_diff >= max_first_difference
|
||||
max_jump_frame = -1;
|
||||
// 2 - find max_keyframe among those Branches whose first_diff >= max_first_difference
|
||||
max_keyframe = -1;
|
||||
for (int i = TOTAL_BOOKMARKS-1; i >= 0; i--)
|
||||
{
|
||||
if (bookmarks.bookmarks_array[i].not_empty)
|
||||
{
|
||||
if (i != branch_num && GetFirstDifference(branch_num, i) >= max_first_difference && GetFirstDifference(branch_num, i) >= bookmarks.bookmarks_array[i].snapshot.jump_frame)
|
||||
if (i != branch_num && GetFirstDifference(branch_num, i) >= max_first_difference && GetFirstDifference(branch_num, i) >= bookmarks.bookmarks_array[i].snapshot.keyframe)
|
||||
{
|
||||
// ensure that this candidate belongs to children/grandchildren of current_branch
|
||||
temp_parent = parents[i];
|
||||
|
@ -825,17 +825,17 @@ int BRANCHES::FindFullTimelineForBranch(int branch_num)
|
|||
if (temp_parent == branch_num)
|
||||
{
|
||||
candidates.push_back(i);
|
||||
temp_jump_frame = bookmarks.bookmarks_array[i].snapshot.jump_frame;
|
||||
if (max_jump_frame < temp_jump_frame)
|
||||
max_jump_frame = temp_jump_frame;
|
||||
temp_keyframe = bookmarks.bookmarks_array[i].snapshot.keyframe;
|
||||
if (max_keyframe < temp_keyframe)
|
||||
max_keyframe = temp_keyframe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3 - remove those candidates who have jump_frame < max_jump_frame
|
||||
// 3 - remove those candidates who have keyframe < max_keyframe
|
||||
for (int i = candidates.size()-1; i >= 0; i--)
|
||||
{
|
||||
if (bookmarks.bookmarks_array[candidates[i]].snapshot.jump_frame < max_jump_frame)
|
||||
if (bookmarks.bookmarks_array[candidates[i]].snapshot.keyframe < max_keyframe)
|
||||
candidates.erase(candidates.begin() + i);
|
||||
}
|
||||
// 4 - get first of candidates (if there are many then it will be the Branch with highest id number)
|
||||
|
@ -882,21 +882,21 @@ void BRANCHES::RecalculateParents()
|
|||
{
|
||||
// find best parent for every Branch
|
||||
std::vector<int> candidates;
|
||||
int temp_jump_frame, temp_parent, max_jump_frame, max_first_difference;
|
||||
int temp_keyframe, temp_parent, max_keyframe, max_first_difference;
|
||||
for (int i1 = TOTAL_BOOKMARKS-1; i1 >= 0; i1--)
|
||||
{
|
||||
int i = (i1 + 1) % TOTAL_BOOKMARKS;
|
||||
if (bookmarks.bookmarks_array[i].not_empty)
|
||||
{
|
||||
int jump_frame = bookmarks.bookmarks_array[i].snapshot.jump_frame;
|
||||
// 1 - find all candidates and max_jump_frame among them
|
||||
int keyframe = bookmarks.bookmarks_array[i].snapshot.keyframe;
|
||||
// 1 - find all candidates and max_keyframe among them
|
||||
candidates.resize(0);
|
||||
max_jump_frame = -1;
|
||||
max_keyframe = -1;
|
||||
for (int t1 = TOTAL_BOOKMARKS-1; t1 >= 0; t1--)
|
||||
{
|
||||
int t = (t1 + 1) % TOTAL_BOOKMARKS;
|
||||
temp_jump_frame = bookmarks.bookmarks_array[t].snapshot.jump_frame;
|
||||
if (t != i && bookmarks.bookmarks_array[t].not_empty && temp_jump_frame <= jump_frame && GetFirstDifference(t, i) >= temp_jump_frame)
|
||||
temp_keyframe = bookmarks.bookmarks_array[t].snapshot.keyframe;
|
||||
if (t != i && bookmarks.bookmarks_array[t].not_empty && temp_keyframe <= keyframe && GetFirstDifference(t, i) >= temp_keyframe)
|
||||
{
|
||||
// ensure that this candidate doesn't belong to children/grandchildren of this Branch
|
||||
temp_parent = parents[t];
|
||||
|
@ -906,19 +906,19 @@ void BRANCHES::RecalculateParents()
|
|||
{
|
||||
// all ok, this is good candidate for being the parent of the Branch
|
||||
candidates.push_back(t);
|
||||
if (max_jump_frame < temp_jump_frame)
|
||||
max_jump_frame = temp_jump_frame;
|
||||
if (max_keyframe < temp_keyframe)
|
||||
max_keyframe = temp_keyframe;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (candidates.size())
|
||||
{
|
||||
// 2 - remove those candidates who have jump_frame < max_jump_frame
|
||||
// and for those who have jump_frame == max_jump_frame, find max_first_difference
|
||||
// 2 - remove those candidates who have keyframe < max_keyframe
|
||||
// and for those who have keyframe == max_keyframe, find max_first_difference
|
||||
max_first_difference = -1;
|
||||
for (int t = candidates.size()-1; t >= 0; t--)
|
||||
{
|
||||
if (bookmarks.bookmarks_array[candidates[t]].snapshot.jump_frame < max_jump_frame)
|
||||
if (bookmarks.bookmarks_array[candidates[t]].snapshot.keyframe < max_keyframe)
|
||||
candidates.erase(candidates.begin() + t);
|
||||
else if (max_first_difference < GetFirstDifference(candidates[t], i))
|
||||
max_first_difference = GetFirstDifference(candidates[t], i);
|
||||
|
|
|
@ -204,7 +204,7 @@ void EDITOR::InputSetPattern(int start, int end, int joy, int button, int consec
|
|||
for (int i = start; i <= end; ++i)
|
||||
{
|
||||
// skip lag frames
|
||||
if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(i))
|
||||
if (taseditor_config.pattern_skips_lag && greenzone.laglog.GetLagInfoAtFrame(i))
|
||||
continue;
|
||||
value = (autofire_patterns[current_pattern][pattern_offset] != 0);
|
||||
if (currMovieData.records[i].checkBit(joy, button) != value)
|
||||
|
@ -285,7 +285,7 @@ bool EDITOR::FrameColumnSetPattern()
|
|||
for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++)
|
||||
{
|
||||
// skip lag frames
|
||||
if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(*it))
|
||||
if (taseditor_config.pattern_skips_lag && greenzone.laglog.GetLagInfoAtFrame(*it))
|
||||
continue;
|
||||
if (autofire_patterns[current_pattern][pattern_offset])
|
||||
{
|
||||
|
@ -370,7 +370,7 @@ bool EDITOR::InputColumnSetPattern(int joy, int button)
|
|||
for(SelectionFrames::iterator it(current_selection_begin); it != current_selection_end; it++)
|
||||
{
|
||||
// skip lag frames
|
||||
if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(*it))
|
||||
if (taseditor_config.pattern_skips_lag && greenzone.laglog.GetLagInfoAtFrame(*it))
|
||||
continue;
|
||||
currMovieData.records[*it].setBitValue(joy, button, autofire_patterns[current_pattern][pattern_offset] != 0);
|
||||
pattern_offset++;
|
||||
|
@ -455,7 +455,7 @@ void EDITOR::AdjustUp(int at)
|
|||
// reduce Piano Roll
|
||||
piano_roll.UpdateItemCount();
|
||||
// check and register changes
|
||||
history.RegisterChanges(MODTYPE_ADJUST_UP, at);
|
||||
history.RegisterChanges(MODTYPE_ADJUST_LAG, at, -1, NULL, -1);
|
||||
greenzone.Invalidate(at);
|
||||
if (markers_changed)
|
||||
selection.must_find_current_marker = playback.must_find_current_marker = true;
|
||||
|
@ -473,7 +473,7 @@ void EDITOR::AdjustDown(int at)
|
|||
markers_changed = true;
|
||||
}
|
||||
// check and register changes
|
||||
history.RegisterChanges(MODTYPE_ADJUST_DOWN, at);
|
||||
history.RegisterChanges(MODTYPE_ADJUST_LAG, at, -1, NULL, 1);
|
||||
greenzone.Invalidate(at);
|
||||
if (markers_changed)
|
||||
selection.must_find_current_marker = playback.must_find_current_marker = true;
|
||||
|
|
|
@ -11,10 +11,10 @@ Greenzone - Access zone
|
|||
[Singleton]
|
||||
|
||||
* stores array of savestates, used for faster movie navigation by Playback cursor
|
||||
* also stores the frame-by-frame log of lag appearance
|
||||
* also stores LagLog of current movie Input
|
||||
* saves and loads the data from a project file. On error: truncates Greenzone to last successfully read savestate
|
||||
* regularly checks if there's a savestate of current emulation state, if there's no such savestate in array then creates one and updates lag info for previous frame
|
||||
* implements the working of "Auto-adjust Input due to lag"
|
||||
* implements the working of "Auto-adjust Input due to lag" feature
|
||||
* regularly runs gradual cleaning of the savestates array (for memory saving), deleting oldest savestates
|
||||
* on demand: (when movie Input was changed) truncates the size of Greenzone, deleting savestates that became irrelevant because of new Input. After truncating it may also move Playback cursor (which must always reside within Greenzone) and may launch Playback seeking
|
||||
* stores resources: save id, properties of gradual cleaning, timing of cleaning
|
||||
|
@ -49,7 +49,7 @@ void GREENZONE::free()
|
|||
{
|
||||
savestates.resize(0);
|
||||
greenZoneCount = 0;
|
||||
lag_history.resize(0);
|
||||
laglog.reset();
|
||||
}
|
||||
void GREENZONE::reset()
|
||||
{
|
||||
|
@ -57,8 +57,8 @@ void GREENZONE::reset()
|
|||
}
|
||||
void GREENZONE::update()
|
||||
{
|
||||
// keep memorizing savestates, this function should be called at the end of every frame
|
||||
if (greenZoneCount <= currFrameCounter || (int)savestates.size() <= currFrameCounter || !savestates[currFrameCounter].size() || (int)lag_history.size() <= currFrameCounter)
|
||||
// keep collecting savestates, this function should be called at the end of every frame
|
||||
if (greenZoneCount <= currFrameCounter || (int)savestates.size() <= currFrameCounter || !savestates[currFrameCounter].size() || laglog.GetSize() <= currFrameCounter)
|
||||
CollectCurrentState();
|
||||
|
||||
// run cleaning from time to time
|
||||
|
@ -74,8 +74,6 @@ void GREENZONE::CollectCurrentState()
|
|||
|
||||
if ((int)savestates.size() < greenZoneCount)
|
||||
savestates.resize(greenZoneCount);
|
||||
if ((int)lag_history.size() < greenZoneCount)
|
||||
lag_history.resize(greenZoneCount, 0);
|
||||
|
||||
// if frame changed - log savestate
|
||||
EMUFILE_MEMORY ms(&savestates[currFrameCounter]);
|
||||
|
@ -86,14 +84,14 @@ void GREENZONE::CollectCurrentState()
|
|||
if (currFrameCounter > 0)
|
||||
{
|
||||
// lagFlag indicates that lag was in previous frame
|
||||
int old_lagFlag = lag_history[currFrameCounter - 1];
|
||||
int old_lagFlag = laglog.GetLagInfoAtFrame(currFrameCounter - 1);
|
||||
// Auto-adjust Input due to lag
|
||||
if (taseditor_config.adjust_input_due_to_lag)
|
||||
{
|
||||
if (old_lagFlag && !lagFlag)
|
||||
{
|
||||
// there's no more lag on previous frame - shift Input up
|
||||
lag_history.erase(lag_history.begin() + (currFrameCounter - 1));
|
||||
laglog.EraseLagFrame(currFrameCounter - 1);
|
||||
editor.AdjustUp(currFrameCounter - 1);
|
||||
// since AdjustUp didn't restore Playback cursor, we must rewind here
|
||||
bool emu_was_paused = (FCEUI_EmulationPaused() != 0);
|
||||
|
@ -106,7 +104,7 @@ void GREENZONE::CollectCurrentState()
|
|||
} else if (!old_lagFlag && lagFlag)
|
||||
{
|
||||
// there's new lag on previous frame - shift Input down
|
||||
lag_history.insert(lag_history.begin() + (currFrameCounter - 1), 1);
|
||||
laglog.InsertLagFrame(currFrameCounter - 1);
|
||||
editor.AdjustDown(currFrameCounter - 1);
|
||||
// since AdjustDown didn't restore Playback cursor, we must rewind here
|
||||
bool emu_was_paused = (FCEUI_EmulationPaused() != 0);
|
||||
|
@ -116,13 +114,17 @@ void GREENZONE::CollectCurrentState()
|
|||
playback.SeekingStart(saved_pause_frame);
|
||||
if (emu_was_paused)
|
||||
playback.PauseEmulation();
|
||||
} else
|
||||
{
|
||||
// old_lagFlag == lagFlag
|
||||
laglog.SetLagInfo(currFrameCounter - 1, (lagFlag != 0));
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (lagFlag)
|
||||
lag_history[currFrameCounter - 1] = 1;
|
||||
laglog.SetLagInfo(currFrameCounter - 1, true);
|
||||
else
|
||||
lag_history[currFrameCounter - 1] = 0;
|
||||
laglog.SetLagInfo(currFrameCounter - 1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,17 +223,10 @@ void GREENZONE::save(EMUFILE *os, bool really_save)
|
|||
{
|
||||
// write "GREENZONE" string
|
||||
os->fwrite(greenzone_save_id, GREENZONE_ID_LEN);
|
||||
// write LagLog
|
||||
laglog.save(os);
|
||||
// write size
|
||||
write32le(greenZoneCount, os);
|
||||
// compress and write lag history
|
||||
int len = lag_history.size();
|
||||
if (len > currMovieData.getNumRecords())
|
||||
len = currMovieData.getNumRecords();
|
||||
uLongf comprlen = (len>>9)+12 + len;
|
||||
std::vector<uint8> cbuf(comprlen);
|
||||
compress(&cbuf[0], &comprlen, &lag_history[0], len);
|
||||
write32le(comprlen, os);
|
||||
os->fwrite(&cbuf[0], comprlen);
|
||||
// write Playback cursor position
|
||||
write32le(currFrameCounter, os);
|
||||
// write savestates
|
||||
|
@ -259,6 +254,8 @@ void GREENZONE::save(EMUFILE *os, bool really_save)
|
|||
{
|
||||
// write "GREENZONX" string
|
||||
os->fwrite(greenzone_skipsave_id, GREENZONE_ID_LEN);
|
||||
// write LagLog
|
||||
laglog.save(os);
|
||||
// write Playback cursor position
|
||||
write32le(currFrameCounter, os);
|
||||
if (currFrameCounter > 0)
|
||||
|
@ -288,6 +285,8 @@ bool GREENZONE::load(EMUFILE *is, bool really_load)
|
|||
if (!strcmp(greenzone_skipsave_id, save_id))
|
||||
{
|
||||
// string says to skip loading Greenzone
|
||||
// read LagLog
|
||||
laglog.load(is);
|
||||
// read Playback cursor position
|
||||
if (read32le(&frame, is))
|
||||
{
|
||||
|
@ -321,21 +320,13 @@ bool GREENZONE::load(EMUFILE *is, bool really_load)
|
|||
goto error;
|
||||
}
|
||||
if (strcmp(greenzone_save_id, save_id)) goto error; // string is not valid
|
||||
// read LagLog
|
||||
laglog.load(is);
|
||||
// read size
|
||||
if (read32le(&size, is) && size >= 0 && size <= currMovieData.getNumRecords())
|
||||
{
|
||||
greenZoneCount = size;
|
||||
savestates.resize(greenZoneCount);
|
||||
// read and uncompress lag history
|
||||
uLongf destlen = currMovieData.getNumRecords();
|
||||
lag_history.resize(destlen, 0);
|
||||
int comprlen;
|
||||
if (!read32le(&comprlen, is)) goto error;
|
||||
if (comprlen <= 0) goto error;
|
||||
std::vector<uint8> cbuf(comprlen);
|
||||
if (is->fread(&cbuf[0], comprlen) != comprlen) goto error;
|
||||
int e = uncompress(&lag_history[0], &destlen, &cbuf[0], comprlen);
|
||||
if (e != Z_OK && e != Z_BUF_ERROR) goto error;
|
||||
// read Playback cursor position
|
||||
if (read32le(&frame, is))
|
||||
{
|
||||
|
@ -485,13 +476,6 @@ int GREENZONE::GetSize()
|
|||
{
|
||||
return greenZoneCount;
|
||||
}
|
||||
bool GREENZONE::GetLagHistoryAtFrame(int frame)
|
||||
{
|
||||
if (frame < (int)lag_history.size())
|
||||
return lag_history[frame] != 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// this should only be used by Bookmark Set procedure
|
||||
std::vector<uint8>& GREENZONE::GetSavestate(int frame)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// Specification file for Greenzone class
|
||||
|
||||
#include "laglog.h"
|
||||
|
||||
#define GREENZONE_ID_LEN 10
|
||||
|
||||
#define TIME_BETWEEN_CLEANINGS 10000 // in milliseconds
|
||||
|
@ -34,20 +36,21 @@ public:
|
|||
int FindBeginningOfGreenZone(int starting_index = 0);
|
||||
|
||||
int GetSize();
|
||||
bool GetLagHistoryAtFrame(int frame);
|
||||
std::vector<uint8>& GetSavestate(int frame);
|
||||
void WriteSavestate(int frame, std::vector<uint8>& savestate);
|
||||
bool SavestateIsEmpty(int frame);
|
||||
|
||||
// saved data
|
||||
LAGLOG laglog;
|
||||
|
||||
private:
|
||||
void CollectCurrentState();
|
||||
|
||||
// saved data
|
||||
int greenZoneCount;
|
||||
std::vector<std::vector<uint8>> savestates;
|
||||
std::vector<uint8> lag_history;
|
||||
|
||||
// not saved data
|
||||
int next_cleaning_time;
|
||||
|
||||
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ History - History of movie modifications
|
|||
|
||||
* stores array of History items (snapshots, backup_bookmarks, backup_current_branch) and pointer to current snapshot
|
||||
* saves and loads the data from a project file. On error: clears the array and starts new history by making snapshot of current movie data
|
||||
* on demand: checks the difference between the last snapshot and current movie, and makes a decision to create new point of rollback. In special cases it can create a point of rollback without checking the difference, assuming that caller already checked it
|
||||
* on demand: checks the difference between the last snapshot's Inputlog and current movie Input, and makes a decision to create new point of rollback. In special cases it can create a point of rollback without checking the difference, assuming that caller already checked it
|
||||
* implements all restoring operations: undo, redo, revert to any snapshot from the array
|
||||
* also stores the state of "undo pointer"
|
||||
* regularly updates the state of "undo pointer"
|
||||
|
@ -103,7 +103,6 @@ char modCaptions[MODTYPES_TOTAL][20] = {" Initialization",
|
|||
" LUA Marker Remove",
|
||||
" LUA Marker Rename",
|
||||
" LUA Change",
|
||||
" AdjustLag",
|
||||
" AdjustLag" };
|
||||
char LuaCaptionPrefix[6] = " LUA ";
|
||||
char joypadCaptions[4][5] = {"(1P)", "(2P)", "(3P)", "(4P)"};
|
||||
|
@ -151,9 +150,9 @@ void HISTORY::reset()
|
|||
snap.init(currMovieData, taseditor_config.enable_hot_changes);
|
||||
snap.mod_type = MODTYPE_INIT;
|
||||
strcat(snap.description, modCaptions[snap.mod_type]);
|
||||
snap.jump_frame = -1;
|
||||
snap.keyframe = -1;
|
||||
snap.start_frame = 0;
|
||||
snap.end_frame = snap.size - 1;
|
||||
snap.end_frame = snap.inputlog.size - 1;
|
||||
AddItemToHistory(snap);
|
||||
UpdateHistoryList();
|
||||
RedrawHistoryList();
|
||||
|
@ -249,9 +248,10 @@ int HISTORY::JumpInTime(int new_pos)
|
|||
if (new_pos < 0)
|
||||
new_pos = 0;
|
||||
else if (new_pos >= history_total_items)
|
||||
new_pos = history_total_items-1;
|
||||
// if nothing is done, do not invalidate greenzone
|
||||
if (new_pos == history_cursor_pos) return -1;
|
||||
new_pos = history_total_items - 1;
|
||||
// if nothing is done, do not invalidate Greenzone
|
||||
if (new_pos == history_cursor_pos)
|
||||
return -1;
|
||||
|
||||
// make jump
|
||||
int old_pos = history_cursor_pos;
|
||||
|
@ -284,9 +284,9 @@ int HISTORY::JumpInTime(int new_pos)
|
|||
// swap Bookmark and its backup version
|
||||
slot = (mod_type - MODTYPE_BOOKMARK_0) % TOTAL_BOOKMARKS;
|
||||
BOOKMARK temp_bookmark(bookmarks.bookmarks_array[slot]);
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[slot].snapshot.jump_frame);
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[slot].snapshot.keyframe);
|
||||
bookmarks.bookmarks_array[slot] = backup_bookmarks[real_pos];
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[slot].snapshot.jump_frame);
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[slot].snapshot.keyframe);
|
||||
bookmarks_to_redraw.push_back(slot);
|
||||
backup_bookmarks[real_pos] = temp_bookmark;
|
||||
branches.InvalidateBranchSlot(slot);
|
||||
|
@ -307,9 +307,9 @@ int HISTORY::JumpInTime(int new_pos)
|
|||
// swap Bookmark and its backup version
|
||||
slot = (mod_type - MODTYPE_BOOKMARK_0) % TOTAL_BOOKMARKS;
|
||||
BOOKMARK temp_bookmark(bookmarks.bookmarks_array[slot]);
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[slot].snapshot.jump_frame);
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[slot].snapshot.keyframe);
|
||||
bookmarks.bookmarks_array[slot] = backup_bookmarks[real_pos];
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[slot].snapshot.jump_frame);
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[slot].snapshot.keyframe);
|
||||
bookmarks_to_redraw.push_back(slot);
|
||||
backup_bookmarks[real_pos] = temp_bookmark;
|
||||
branches.InvalidateBranchSlot(slot);
|
||||
|
@ -336,12 +336,12 @@ int HISTORY::JumpInTime(int new_pos)
|
|||
// current_branch was switched, redraw Bookmarks List to change the color of digits
|
||||
if (old_current_branch != ITEM_UNDER_MOUSE_CLOUD)
|
||||
{
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[old_current_branch].snapshot.jump_frame);
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[old_current_branch].snapshot.keyframe);
|
||||
bookmarks_to_redraw.push_back(old_current_branch);
|
||||
}
|
||||
if (current_branch != ITEM_UNDER_MOUSE_CLOUD)
|
||||
{
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[current_branch].snapshot.jump_frame);
|
||||
frames_to_redraw.push_back(bookmarks.bookmarks_array[current_branch].snapshot.keyframe);
|
||||
bookmarks_to_redraw.push_back(current_branch);
|
||||
}
|
||||
}
|
||||
|
@ -361,9 +361,9 @@ int HISTORY::JumpInTime(int new_pos)
|
|||
|
||||
// create undo_hint
|
||||
if (new_pos > old_pos)
|
||||
undo_hint_pos = GetCurrentSnapshot().jump_frame; // redo
|
||||
undo_hint_pos = GetCurrentSnapshot().keyframe; // redo
|
||||
else
|
||||
undo_hint_pos = GetNextToCurrentSnapshot().jump_frame; // undo
|
||||
undo_hint_pos = GetNextToCurrentSnapshot().keyframe; // undo
|
||||
undo_hint_time = clock() + UNDO_HINT_TIME;
|
||||
show_undo_hint = true;
|
||||
|
||||
|
@ -377,11 +377,12 @@ int HISTORY::JumpInTime(int new_pos)
|
|||
markers_changed = true;
|
||||
}
|
||||
|
||||
// update current movie data
|
||||
int first_change = snapshots[real_pos].findFirstChange(currMovieData);
|
||||
// update current movie data and Greenzone's LagLog
|
||||
int first_change = snapshots[real_pos].inputlog.findFirstChange(currMovieData);
|
||||
if (first_change >= 0)
|
||||
{
|
||||
snapshots[real_pos].toMovie(currMovieData, first_change);
|
||||
snapshots[real_pos].inputlog.toMovie(currMovieData, first_change);
|
||||
greenzone.laglog = snapshots[real_pos].laglog;
|
||||
selection.must_find_current_marker = playback.must_find_current_marker = true;
|
||||
project.SetProjectChanged();
|
||||
// Piano Roll Redraw will be called by Greenzone invalidation
|
||||
|
@ -403,14 +404,29 @@ int HISTORY::JumpInTime(int new_pos)
|
|||
|
||||
void HISTORY::undo()
|
||||
{
|
||||
int result = JumpInTime(history_cursor_pos - 1);
|
||||
int step = -1;
|
||||
if (taseditor_config.adjust_input_due_to_lag)
|
||||
{
|
||||
// if we're undoing an AdjustLag operation then undo two operations
|
||||
if (GetCurrentSnapshot().mod_type == MODTYPE_ADJUST_LAG)
|
||||
step = -2;
|
||||
}
|
||||
int result = JumpInTime(history_cursor_pos + step);
|
||||
if (result >= 0)
|
||||
greenzone.InvalidateAndCheck(result);
|
||||
return;
|
||||
}
|
||||
void HISTORY::redo()
|
||||
{
|
||||
int result = JumpInTime(history_cursor_pos + 1);
|
||||
int step = 1;
|
||||
if (taseditor_config.adjust_input_due_to_lag)
|
||||
{
|
||||
// if we're redoing an operation followed by AdjustLag then redo two operations
|
||||
if (history_cursor_pos + 2 <= history_total_items)
|
||||
if (snapshots[(history_start_pos + history_cursor_pos + 2) % history_size].mod_type == MODTYPE_ADJUST_LAG)
|
||||
step = 2;
|
||||
}
|
||||
int result = JumpInTime(history_cursor_pos + step);
|
||||
if (result >= 0)
|
||||
greenzone.InvalidateAndCheck(result);
|
||||
return;
|
||||
|
@ -418,7 +434,7 @@ void HISTORY::redo()
|
|||
// ----------------------------
|
||||
void HISTORY::AddItemToHistory(SNAPSHOT &snap, int cur_branch)
|
||||
{
|
||||
// history uses conveyor of items (vector with fixed size) to aviod frequent resizing, which would be awfully expensive with such large objects as SNAPSHOT and BOOKMARK
|
||||
// history uses conveyor of items (vector with fixed size) to aviod frequent reallocations caused by vector resizing, which would be awfully expensive with such large objects as SNAPSHOT and BOOKMARK
|
||||
if (history_total_items >= history_size)
|
||||
{
|
||||
// reached the end of available history_size - move history_start_pos (thus deleting oldest snapshot)
|
||||
|
@ -440,7 +456,7 @@ void HISTORY::AddItemToHistory(SNAPSHOT &snap, int cur_branch)
|
|||
}
|
||||
void HISTORY::AddItemToHistory(SNAPSHOT &snap, int cur_branch, BOOKMARK &bookm)
|
||||
{
|
||||
// history uses conveyor of items (vector with fixed size) to aviod frequent resizing, which would be awfully expensive with such large objects as SNAPSHOT and BOOKMARK
|
||||
// history uses conveyor of items (vector with fixed size) to aviod frequent reallocations caused by vector resizing, which would be awfully expensive with such large objects as SNAPSHOT and BOOKMARK
|
||||
if (history_total_items >= history_size)
|
||||
{
|
||||
// reached the end of available history_size - move history_start_pos (thus deleting oldest snapshot)
|
||||
|
@ -471,14 +487,14 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
|
|||
snap.init(currMovieData, taseditor_config.enable_hot_changes);
|
||||
// check if there are Input differences from latest snapshot
|
||||
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
|
||||
int first_changes = snap.findFirstChange(snapshots[real_pos], start, end);
|
||||
int first_changes = snap.inputlog.findFirstChange(snapshots[real_pos].inputlog, start, end);
|
||||
if (first_changes >= 0)
|
||||
{
|
||||
// differences found
|
||||
// fill description:
|
||||
snap.mod_type = mod_type;
|
||||
strcat(snap.description, modCaptions[snap.mod_type]);
|
||||
// set jump_frame
|
||||
// set keyframe
|
||||
switch (mod_type)
|
||||
{
|
||||
case MODTYPE_SET:
|
||||
|
@ -487,7 +503,7 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
|
|||
case MODTYPE_CLEAR:
|
||||
case MODTYPE_CUT:
|
||||
{
|
||||
snap.jump_frame = first_changes;
|
||||
snap.keyframe = first_changes;
|
||||
break;
|
||||
}
|
||||
case MODTYPE_INSERT:
|
||||
|
@ -495,31 +511,27 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
|
|||
case MODTYPE_PASTE:
|
||||
case MODTYPE_CLONE:
|
||||
case MODTYPE_PATTERN:
|
||||
case MODTYPE_ADJUST_UP:
|
||||
case MODTYPE_ADJUST_DOWN:
|
||||
case MODTYPE_ADJUST_LAG:
|
||||
{
|
||||
// for these changes user prefers to see frame of attempted change (Selection cursor position), not frame of actual differences
|
||||
snap.jump_frame = start;
|
||||
snap.keyframe = start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// set start_frame, end_frame, consecutive_tag
|
||||
if (snap.mod_type == MODTYPE_ADJUST_UP || snap.mod_type == MODTYPE_ADJUST_DOWN)
|
||||
if (snap.mod_type == MODTYPE_ADJUST_LAG)
|
||||
{
|
||||
// special operation: AdjustLag
|
||||
snap.start_frame = snap.end_frame = start;
|
||||
if (snap.mod_type == MODTYPE_ADJUST_UP)
|
||||
snap.consecutive_tag = -1;
|
||||
else
|
||||
snap.consecutive_tag = 1;
|
||||
snap.consecutive_tag = consecutive_tag; // -1 for Adjust Up, +1 for Adjust Down
|
||||
// combine Adjustment with previous snapshot if needed
|
||||
bool combine = false;
|
||||
if (snapshots[real_pos].mod_type == MODTYPE_ADJUST_UP || snapshots[real_pos].mod_type == MODTYPE_ADJUST_DOWN)
|
||||
if (snapshots[real_pos].mod_type == MODTYPE_ADJUST_LAG)
|
||||
combine = true;
|
||||
if (combine)
|
||||
{
|
||||
if (snap.jump_frame > snapshots[real_pos].jump_frame)
|
||||
snap.jump_frame = snapshots[real_pos].jump_frame;
|
||||
if (snap.keyframe > snapshots[real_pos].keyframe)
|
||||
snap.keyframe = snapshots[real_pos].keyframe;
|
||||
if (snap.start_frame > snapshots[real_pos].start_frame)
|
||||
snap.start_frame = snapshots[real_pos].start_frame;
|
||||
if (snap.end_frame < snapshots[real_pos].end_frame)
|
||||
|
@ -529,10 +541,12 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
|
|||
// set hotchanges
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
{
|
||||
if (snap.mod_type == MODTYPE_ADJUST_UP)
|
||||
snap.inheritHotChanges_DeleteNum(&snapshots[real_pos], start, 1, !combine);
|
||||
if (consecutive_tag < 0)
|
||||
// it was Adjust Up
|
||||
snap.inputlog.inheritHotChanges_DeleteNum(&snapshots[real_pos].inputlog, start, 1, !combine);
|
||||
else
|
||||
snap.inheritHotChanges_InsertNum(&snapshots[real_pos], start, 1, !combine);
|
||||
// it was Adjust Down
|
||||
snap.inputlog.inheritHotChanges_InsertNum(&snapshots[real_pos].inputlog, start, 1, !combine);
|
||||
}
|
||||
// add "consecutive_tag" to description
|
||||
char framenum[11];
|
||||
|
@ -577,8 +591,8 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
|
|||
if (consecutive_tag && taseditor_config.combine_consecutive && snapshots[real_pos].mod_type == snap.mod_type && snapshots[real_pos].consecutive_tag == snap.consecutive_tag)
|
||||
{
|
||||
// combine Drawing with previous snapshot
|
||||
if (snap.jump_frame > snapshots[real_pos].jump_frame)
|
||||
snap.jump_frame = snapshots[real_pos].jump_frame;
|
||||
if (snap.keyframe > snapshots[real_pos].keyframe)
|
||||
snap.keyframe = snapshots[real_pos].keyframe;
|
||||
if (snap.start_frame > snapshots[real_pos].start_frame)
|
||||
snap.start_frame = snapshots[real_pos].start_frame;
|
||||
if (snap.end_frame < snapshots[real_pos].end_frame)
|
||||
|
@ -603,8 +617,8 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
|
|||
// set hotchanges
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
{
|
||||
snap.copyHotChanges(&snapshots[real_pos]);
|
||||
snap.fillHotChanges(snapshots[real_pos], first_changes, end);
|
||||
snap.inputlog.copyHotChanges(&snapshots[real_pos].inputlog);
|
||||
snap.inputlog.fillHotChanges(snapshots[real_pos].inputlog, first_changes, end);
|
||||
}
|
||||
// replace current snapshot with this cloned snapshot and truncate history here
|
||||
snapshots[real_pos] = snap;
|
||||
|
@ -638,11 +652,11 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
|
|||
switch (mod_type)
|
||||
{
|
||||
case MODTYPE_DELETE:
|
||||
snap.inheritHotChanges_DeleteSelection(&snapshots[real_pos]);
|
||||
snap.inputlog.inheritHotChanges_DeleteSelection(&snapshots[real_pos].inputlog);
|
||||
break;
|
||||
case MODTYPE_INSERT:
|
||||
case MODTYPE_CLONE:
|
||||
snap.inheritHotChanges_InsertSelection(&snapshots[real_pos]);
|
||||
snap.inputlog.inheritHotChanges_InsertSelection(&snapshots[real_pos].inputlog);
|
||||
break;
|
||||
case MODTYPE_SET:
|
||||
case MODTYPE_UNSET:
|
||||
|
@ -650,11 +664,11 @@ int HISTORY::RegisterChanges(int mod_type, int start, int end, const char* comme
|
|||
case MODTYPE_CUT:
|
||||
case MODTYPE_PASTE:
|
||||
case MODTYPE_PATTERN:
|
||||
snap.inheritHotChanges(&snapshots[real_pos]);
|
||||
snap.fillHotChanges(snapshots[real_pos], first_changes, end);
|
||||
snap.inputlog.inheritHotChanges(&snapshots[real_pos].inputlog);
|
||||
snap.inputlog.fillHotChanges(snapshots[real_pos].inputlog, first_changes, end);
|
||||
break;
|
||||
case MODTYPE_TRUNCATE:
|
||||
snap.copyHotChanges(&snapshots[real_pos]);
|
||||
snap.inputlog.copyHotChanges(&snapshots[real_pos].inputlog);
|
||||
// do not add new hotchanges and do not fade old hotchanges, because there was nothing added
|
||||
break;
|
||||
}
|
||||
|
@ -674,14 +688,14 @@ int HISTORY::RegisterInsertNum(int start, int frames)
|
|||
snap.init(currMovieData, taseditor_config.enable_hot_changes);
|
||||
// check if there are Input differences from latest snapshot
|
||||
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
|
||||
int first_changes = snap.findFirstChange(snapshots[real_pos], start);
|
||||
int first_changes = snap.inputlog.findFirstChange(snapshots[real_pos].inputlog, start);
|
||||
if (first_changes >= 0)
|
||||
{
|
||||
// differences found
|
||||
// fill description:
|
||||
snap.mod_type = MODTYPE_INSERTNUM;
|
||||
strcat(snap.description, modCaptions[snap.mod_type]);
|
||||
snap.jump_frame = start;
|
||||
snap.keyframe = start;
|
||||
snap.start_frame = start;
|
||||
snap.end_frame = start + frames - 1;
|
||||
char framenum[11];
|
||||
|
@ -694,7 +708,7 @@ int HISTORY::RegisterInsertNum(int start, int frames)
|
|||
strcat(snap.description, framenum);
|
||||
// set hotchanges
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
snap.inheritHotChanges_InsertNum(&snapshots[real_pos], start, frames, true);
|
||||
snap.inputlog.inheritHotChanges_InsertNum(&snapshots[real_pos].inputlog, start, frames, true);
|
||||
AddItemToHistory(snap);
|
||||
branches.ChangesMadeSinceBranch();
|
||||
project.SetProjectChanged();
|
||||
|
@ -708,7 +722,7 @@ int HISTORY::RegisterPasteInsert(int start, SelectionFrames& inserted_set)
|
|||
snap.init(currMovieData, taseditor_config.enable_hot_changes);
|
||||
// check if there are Input differences from latest snapshot
|
||||
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
|
||||
int first_changes = snap.findFirstChange(snapshots[real_pos], start);
|
||||
int first_changes = snap.inputlog.findFirstChange(snapshots[real_pos].inputlog, start);
|
||||
if (first_changes >= 0)
|
||||
{
|
||||
// differences found
|
||||
|
@ -716,7 +730,7 @@ int HISTORY::RegisterPasteInsert(int start, SelectionFrames& inserted_set)
|
|||
snap.mod_type = MODTYPE_PASTEINSERT;
|
||||
strcat(snap.description, modCaptions[snap.mod_type]);
|
||||
// for PasteInsert user prefers to see frame of attempted change (Selection cursor position), not frame of actual differences
|
||||
snap.jump_frame = start;
|
||||
snap.keyframe = start;
|
||||
snap.start_frame = start;
|
||||
snap.end_frame = -1;
|
||||
// add upper frame to description
|
||||
|
@ -726,7 +740,7 @@ int HISTORY::RegisterPasteInsert(int start, SelectionFrames& inserted_set)
|
|||
strcat(snap.description, framenum);
|
||||
// set hotchanges
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
snap.inheritHotChanges_PasteInsert(&snapshots[real_pos], inserted_set);
|
||||
snap.inputlog.inheritHotChanges_PasteInsert(&snapshots[real_pos].inputlog, inserted_set);
|
||||
AddItemToHistory(snap);
|
||||
branches.ChangesMadeSinceBranch();
|
||||
project.SetProjectChanged();
|
||||
|
@ -741,7 +755,7 @@ void HISTORY::RegisterMarkersChange(int mod_type, int start, int end, const char
|
|||
// fill description:
|
||||
snap.mod_type = mod_type;
|
||||
strcat(snap.description, modCaptions[mod_type]);
|
||||
snap.jump_frame = start;
|
||||
snap.keyframe = start;
|
||||
snap.start_frame = start;
|
||||
snap.end_frame = end;
|
||||
// add the frame to description
|
||||
|
@ -768,7 +782,7 @@ void HISTORY::RegisterMarkersChange(int mod_type, int start, int end, const char
|
|||
}
|
||||
// Hotchanges aren't changed
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
snap.copyHotChanges(&GetCurrentSnapshot());
|
||||
snap.inputlog.copyHotChanges(&GetCurrentSnapshot().inputlog);
|
||||
AddItemToHistory(snap);
|
||||
branches.ChangesMadeSinceBranch();
|
||||
project.SetProjectChanged();
|
||||
|
@ -778,16 +792,16 @@ void HISTORY::RegisterBookmarkSet(int slot, BOOKMARK& backup_copy, int old_curre
|
|||
// create new snapshot
|
||||
SNAPSHOT snap;
|
||||
snap.init(currMovieData, taseditor_config.enable_hot_changes);
|
||||
// fill description: modification type + jump_frame of the Bookmark
|
||||
// fill description: modification type + keyframe of the Bookmark
|
||||
snap.mod_type = MODTYPE_BOOKMARK_0 + slot;
|
||||
strcat(snap.description, modCaptions[snap.mod_type]);
|
||||
snap.start_frame = snap.end_frame = snap.jump_frame = bookmarks.bookmarks_array[slot].snapshot.jump_frame;
|
||||
snap.start_frame = snap.end_frame = snap.keyframe = bookmarks.bookmarks_array[slot].snapshot.keyframe;
|
||||
char framenum[11];
|
||||
strcat(snap.description, " ");
|
||||
_itoa(snap.jump_frame, framenum, 10);
|
||||
_itoa(snap.keyframe, framenum, 10);
|
||||
strcat(snap.description, framenum);
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
snap.copyHotChanges(&GetCurrentSnapshot());
|
||||
snap.inputlog.copyHotChanges(&GetCurrentSnapshot().inputlog);
|
||||
AddItemToHistory(snap, old_current_branch, backup_copy);
|
||||
project.SetProjectChanged();
|
||||
}
|
||||
|
@ -798,7 +812,7 @@ int HISTORY::RegisterBranching(int slot, bool markers_changed)
|
|||
snap.init(currMovieData, taseditor_config.enable_hot_changes);
|
||||
// check if there are Input differences from latest snapshot
|
||||
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
|
||||
int first_changes = snap.findFirstChange(snapshots[real_pos]);
|
||||
int first_changes = snap.inputlog.findFirstChange(snapshots[real_pos].inputlog);
|
||||
if (first_changes >= 0)
|
||||
{
|
||||
// differences found
|
||||
|
@ -806,12 +820,12 @@ int HISTORY::RegisterBranching(int slot, bool markers_changed)
|
|||
snap.mod_type = MODTYPE_BRANCH_0 + slot;
|
||||
strcat(snap.description, modCaptions[snap.mod_type]);
|
||||
strcat(snap.description, bookmarks.bookmarks_array[slot].snapshot.description);
|
||||
snap.jump_frame = first_changes;
|
||||
snap.keyframe = first_changes;
|
||||
snap.start_frame = first_changes;
|
||||
snap.end_frame = -1;
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
// copy hotchanges of the Branch
|
||||
snap.copyHotChanges(&bookmarks.bookmarks_array[slot].snapshot);
|
||||
snap.inputlog.copyHotChanges(&bookmarks.bookmarks_array[slot].snapshot.inputlog);
|
||||
AddItemToHistory(snap, branches.GetCurrentBranch());
|
||||
project.SetProjectChanged();
|
||||
} else if (markers_changed)
|
||||
|
@ -820,12 +834,12 @@ int HISTORY::RegisterBranching(int slot, bool markers_changed)
|
|||
snap.mod_type = MODTYPE_BRANCH_MARKERS_0 + slot;
|
||||
strcat(snap.description, modCaptions[snap.mod_type]);
|
||||
strcat(snap.description, bookmarks.bookmarks_array[slot].snapshot.description);
|
||||
snap.jump_frame = bookmarks.bookmarks_array[slot].snapshot.jump_frame;
|
||||
snap.keyframe = bookmarks.bookmarks_array[slot].snapshot.keyframe;
|
||||
snap.start_frame = 0;
|
||||
snap.end_frame = -1;
|
||||
// Input was not changed, only Markers were changed
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
snap.copyHotChanges(&GetCurrentSnapshot());
|
||||
snap.inputlog.copyHotChanges(&GetCurrentSnapshot().inputlog);
|
||||
AddItemToHistory(snap, branches.GetCurrentBranch());
|
||||
project.SetProjectChanged();
|
||||
}
|
||||
|
@ -836,7 +850,7 @@ void HISTORY::RegisterRecording(int frame_of_change)
|
|||
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
|
||||
SNAPSHOT snap;
|
||||
snap.init(currMovieData, taseditor_config.enable_hot_changes);
|
||||
snap.fillJoypadsDiff(snapshots[real_pos], frame_of_change);
|
||||
snap.rec_joypad_diff_bits = snap.inputlog.fillJoypadsDiff(snapshots[real_pos].inputlog, frame_of_change);
|
||||
// fill description:
|
||||
snap.mod_type = MODTYPE_RECORD;
|
||||
strcat(snap.description, modCaptions[MODTYPE_RECORD]);
|
||||
|
@ -848,12 +862,12 @@ void HISTORY::RegisterRecording(int frame_of_change)
|
|||
&& snapshots[real_pos].rec_joypad_diff_bits == snap.rec_joypad_diff_bits) // c) recorded same set of joysticks
|
||||
{
|
||||
// clone this snapshot and continue chain of recorded frames
|
||||
snap.jump_frame = snapshots[real_pos].jump_frame;
|
||||
snap.start_frame = snapshots[real_pos].jump_frame;
|
||||
snap.keyframe = snapshots[real_pos].keyframe;
|
||||
snap.start_frame = snapshots[real_pos].keyframe;
|
||||
snap.end_frame = frame_of_change;
|
||||
snap.consecutive_tag = frame_of_change;
|
||||
// add info which joypads were affected
|
||||
int num = joysticks_per_frame[snap.input_type];
|
||||
int num = joysticks_per_frame[snap.inputlog.input_type];
|
||||
uint32 current_mask = 1;
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
|
@ -871,8 +885,8 @@ void HISTORY::RegisterRecording(int frame_of_change)
|
|||
// set hotchanges
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
{
|
||||
snap.copyHotChanges(&snapshots[real_pos]);
|
||||
snap.fillHotChanges(snapshots[real_pos], frame_of_change, frame_of_change);
|
||||
snap.inputlog.copyHotChanges(&snapshots[real_pos].inputlog);
|
||||
snap.inputlog.fillHotChanges(snapshots[real_pos].inputlog, frame_of_change, frame_of_change);
|
||||
}
|
||||
// replace current snapshot with this cloned snapshot and truncate history here
|
||||
snapshots[real_pos] = snap;
|
||||
|
@ -882,9 +896,9 @@ void HISTORY::RegisterRecording(int frame_of_change)
|
|||
} else
|
||||
{
|
||||
// not consecutive - add new snapshot to history
|
||||
snap.jump_frame = snap.start_frame = snap.end_frame = snap.consecutive_tag = frame_of_change;
|
||||
snap.keyframe = snap.start_frame = snap.end_frame = snap.consecutive_tag = frame_of_change;
|
||||
// add info which joypads were affected
|
||||
int num = joysticks_per_frame[snap.input_type];
|
||||
int num = joysticks_per_frame[snap.inputlog.input_type];
|
||||
uint32 current_mask = 1;
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
|
@ -899,8 +913,8 @@ void HISTORY::RegisterRecording(int frame_of_change)
|
|||
// set hotchanges
|
||||
if (taseditor_config.enable_hot_changes)
|
||||
{
|
||||
snap.inheritHotChanges(&snapshots[real_pos]);
|
||||
snap.fillHotChanges(snapshots[real_pos], frame_of_change, frame_of_change);
|
||||
snap.inputlog.inheritHotChanges(&snapshots[real_pos].inputlog);
|
||||
snap.inputlog.fillHotChanges(snapshots[real_pos].inputlog, frame_of_change, frame_of_change);
|
||||
}
|
||||
AddItemToHistory(snap);
|
||||
}
|
||||
|
@ -914,13 +928,13 @@ int HISTORY::RegisterImport(MovieData& md, char* filename)
|
|||
snap.init(md, taseditor_config.enable_hot_changes, GetInputType(currMovieData));
|
||||
// check if there are Input differences from latest snapshot
|
||||
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
|
||||
int first_changes = snap.findFirstChange(snapshots[real_pos]);
|
||||
int first_changes = snap.inputlog.findFirstChange(snapshots[real_pos].inputlog);
|
||||
if (first_changes >= 0)
|
||||
{
|
||||
// differences found
|
||||
snap.jump_frame = first_changes;
|
||||
snap.keyframe = first_changes;
|
||||
snap.start_frame = 0;
|
||||
snap.end_frame = snap.size - 1;
|
||||
snap.end_frame = snap.inputlog.size - 1;
|
||||
// fill description:
|
||||
snap.mod_type = MODTYPE_IMPORT;
|
||||
strcat(snap.description, modCaptions[snap.mod_type]);
|
||||
|
@ -930,10 +944,11 @@ int HISTORY::RegisterImport(MovieData& md, char* filename)
|
|||
if (taseditor_config.enable_hot_changes)
|
||||
{
|
||||
// do not inherit old hotchanges, because imported Input (most likely) doesn't have direct connection with recent edits, so old hotchanges are irrelevant and should not be copied
|
||||
snap.fillHotChanges(snapshots[real_pos], first_changes);
|
||||
snap.inputlog.fillHotChanges(snapshots[real_pos].inputlog, first_changes);
|
||||
}
|
||||
AddItemToHistory(snap);
|
||||
snap.toMovie(currMovieData);
|
||||
// Replace current movie data with this snapshot's InputLog, not changing Greenzone's LagLog
|
||||
snap.inputlog.toMovie(currMovieData);
|
||||
piano_roll.UpdateItemCount();
|
||||
branches.ChangesMadeSinceBranch();
|
||||
project.SetProjectChanged();
|
||||
|
@ -947,7 +962,7 @@ int HISTORY::RegisterLuaChanges(const char* name, int start, bool InsertionDelet
|
|||
snap.init(currMovieData, taseditor_config.enable_hot_changes);
|
||||
// check if there are Input differences from latest snapshot
|
||||
int real_pos = (history_start_pos + history_cursor_pos) % history_size;
|
||||
int first_changes = snap.findFirstChange(snapshots[real_pos], start);
|
||||
int first_changes = snap.inputlog.findFirstChange(snapshots[real_pos].inputlog, start);
|
||||
if (first_changes >= 0)
|
||||
{
|
||||
// differences found
|
||||
|
@ -963,7 +978,7 @@ int HISTORY::RegisterLuaChanges(const char* name, int start, bool InsertionDelet
|
|||
// set default name
|
||||
strcat(snap.description, modCaptions[snap.mod_type]);
|
||||
}
|
||||
snap.jump_frame = first_changes;
|
||||
snap.keyframe = first_changes;
|
||||
snap.start_frame = start;
|
||||
snap.end_frame = -1;
|
||||
// add upper frame to description
|
||||
|
@ -977,28 +992,28 @@ int HISTORY::RegisterLuaChanges(const char* name, int start, bool InsertionDelet
|
|||
if (InsertionDeletion_was_made)
|
||||
{
|
||||
// do it hard way: take old hot_changes and insert/delete rows to create a snapshot that is comparable to the snap
|
||||
if (snap.input_type == snapshots[real_pos].input_type)
|
||||
if (snap.inputlog.input_type == snapshots[real_pos].inputlog.input_type)
|
||||
{
|
||||
// create temp copy of current snapshot (we need it as a container for hot_changes)
|
||||
SNAPSHOT hotchanges_snapshot = snapshots[real_pos];
|
||||
if (hotchanges_snapshot.has_hot_changes)
|
||||
if (hotchanges_snapshot.inputlog.has_hot_changes)
|
||||
{
|
||||
hotchanges_snapshot.FadeHotChanges();
|
||||
hotchanges_snapshot.inputlog.FadeHotChanges();
|
||||
} else
|
||||
{
|
||||
hotchanges_snapshot.has_hot_changes = true;
|
||||
hotchanges_snapshot.hot_changes.resize(joysticks_per_frame[snap.input_type] * hotchanges_snapshot.size * HOTCHANGE_BYTES_PER_JOY);
|
||||
hotchanges_snapshot.inputlog.has_hot_changes = true;
|
||||
hotchanges_snapshot.inputlog.hot_changes.resize(joysticks_per_frame[snap.inputlog.input_type] * hotchanges_snapshot.inputlog.size * HOTCHANGE_BYTES_PER_JOY);
|
||||
}
|
||||
// insert/delete frames in hotchanges_snapshot, so that it will be the same size as the snap
|
||||
taseditor_lua.InsertDelete_rows_to_Snaphot(hotchanges_snapshot);
|
||||
snap.copyHotChanges(&hotchanges_snapshot);
|
||||
snap.fillHotChanges(hotchanges_snapshot, first_changes);
|
||||
snap.inputlog.copyHotChanges(&hotchanges_snapshot.inputlog);
|
||||
snap.inputlog.fillHotChanges(hotchanges_snapshot.inputlog, first_changes);
|
||||
}
|
||||
} else
|
||||
{
|
||||
// easy way: snap.size is equal to currentsnapshot.size, so we can simply inherit hotchanges
|
||||
snap.inheritHotChanges(&snapshots[real_pos]);
|
||||
snap.fillHotChanges(snapshots[real_pos], first_changes);
|
||||
snap.inputlog.inheritHotChanges(&snapshots[real_pos].inputlog);
|
||||
snap.inputlog.fillHotChanges(snapshots[real_pos].inputlog, first_changes);
|
||||
}
|
||||
}
|
||||
AddItemToHistory(snap);
|
||||
|
@ -1240,8 +1255,7 @@ int HISTORY::GetCategoryOfOperation(int mod_type)
|
|||
return CATEGORY_MARKERS_CHANGE;
|
||||
case MODTYPE_LUA_CHANGE:
|
||||
return CATEGORY_INPUT_MARKERS_CHANGE;
|
||||
case MODTYPE_ADJUST_UP:
|
||||
case MODTYPE_ADJUST_DOWN:
|
||||
case MODTYPE_ADJUST_LAG:
|
||||
return CATEGORY_INPUT_MARKERS_CHANGE;
|
||||
|
||||
}
|
||||
|
@ -1258,6 +1272,7 @@ SNAPSHOT& HISTORY::GetNextToCurrentSnapshot()
|
|||
if (history_cursor_pos < history_total_items)
|
||||
return snapshots[(history_start_pos + history_cursor_pos + 1) % history_size];
|
||||
else
|
||||
// return current snapshot
|
||||
return snapshots[(history_start_pos + history_cursor_pos) % history_size];
|
||||
}
|
||||
char* HISTORY::GetItemDesc(int pos)
|
||||
|
|
|
@ -66,8 +66,7 @@ enum MOD_TYPES
|
|||
MODTYPE_LUA_MARKER_REMOVE,
|
||||
MODTYPE_LUA_MARKER_RENAME,
|
||||
MODTYPE_LUA_CHANGE,
|
||||
MODTYPE_ADJUST_UP,
|
||||
MODTYPE_ADJUST_DOWN,
|
||||
MODTYPE_ADJUST_LAG,
|
||||
|
||||
MODTYPES_TOTAL
|
||||
};
|
||||
|
|
|
@ -0,0 +1,924 @@
|
|||
/* ---------------------------------------------------------------------------------
|
||||
Implementation file of InputLog class
|
||||
Copyright (c) 2011-2012 AnS
|
||||
|
||||
(The MIT License)
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------------
|
||||
InputLog - Log of Input
|
||||
|
||||
* stores the data about Input state: size, type of Input, Input Log data (commands and joysticks)
|
||||
* optionally can store map of Hot Changes
|
||||
* implements InputLog creation: copying Input, copying Hot Changes
|
||||
* implements full/partial restoring of data from InputLog: Input, Hot Changes
|
||||
* implements compression and decompression of stored data
|
||||
* saves and loads the data from a project file. On error: sends warning to caller
|
||||
* implements searching of first mismatch comparing two InputLogs or comparing this InputLog to a movie
|
||||
* provides interface for reading specific data: reading Input of any given frame, reading value at any point of Hot Changes map
|
||||
* implements all operations with Hot Changes maps: copying (full/partial), updating/fading, setting new hot places by comparing two InputLogs
|
||||
------------------------------------------------------------------------------------ */
|
||||
|
||||
#include "taseditor_project.h"
|
||||
#include "zlib.h"
|
||||
|
||||
extern SELECTION selection;
|
||||
extern int GetInputType(MovieData& md);
|
||||
|
||||
int joysticks_per_frame[NUM_SUPPORTED_INPUT_TYPES] = {1, 2, 4};
|
||||
|
||||
INPUTLOG::INPUTLOG()
|
||||
{
|
||||
}
|
||||
|
||||
void INPUTLOG::init(MovieData& md, bool hotchanges, int force_input_type)
|
||||
{
|
||||
has_hot_changes = hotchanges;
|
||||
if (force_input_type < 0)
|
||||
input_type = GetInputType(md);
|
||||
else
|
||||
input_type = force_input_type;
|
||||
// retrieve Input data from movie data
|
||||
size = md.getNumRecords();
|
||||
joysticks.resize(BYTES_PER_JOYSTICK * joysticks_per_frame[input_type] * size); // it's much faster to have this format than have [frame][joy] or other structures
|
||||
commands.resize(size); // commands take 1 byte per frame
|
||||
if (has_hot_changes)
|
||||
hot_changes.resize(joysticks_per_frame[input_type] * size * HOTCHANGE_BYTES_PER_JOY);
|
||||
|
||||
// fill Input vector
|
||||
int pos = 0;
|
||||
switch(input_type)
|
||||
{
|
||||
case INPUT_TYPE_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];
|
||||
commands[frame] = md.records[frame].commands;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_2P:
|
||||
{
|
||||
for (int frame = 0; frame < size; ++frame)
|
||||
{
|
||||
joysticks[pos++] = md.records[frame].joysticks[0];
|
||||
joysticks[pos++] = md.records[frame].joysticks[1];
|
||||
commands[frame] = md.records[frame].commands;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_1P:
|
||||
{
|
||||
for (int frame = 0; frame < size; ++frame)
|
||||
{
|
||||
joysticks[pos++] = md.records[frame].joysticks[0];
|
||||
commands[frame] = md.records[frame].commands;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
already_compressed = false;
|
||||
}
|
||||
|
||||
void INPUTLOG::toMovie(MovieData& md, int start, int end)
|
||||
{
|
||||
if (end < 0 || end >= size) end = size - 1;
|
||||
// write Input data to movie data
|
||||
md.records.resize(end + 1);
|
||||
switch(input_type)
|
||||
{
|
||||
case INPUT_TYPE_FOURSCORE:
|
||||
{
|
||||
int pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type];
|
||||
for (int frame = start; frame <= end; ++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++];
|
||||
md.records[frame].commands = commands[frame];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_2P:
|
||||
{
|
||||
int pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type];
|
||||
for (int frame = start; frame <= end; ++frame)
|
||||
{
|
||||
md.records[frame].joysticks[0] = joysticks[pos++];
|
||||
md.records[frame].joysticks[1] = joysticks[pos++];
|
||||
md.records[frame].commands = commands[frame];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_1P:
|
||||
{
|
||||
int pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type];
|
||||
for (int frame = start; frame <= end; ++frame)
|
||||
{
|
||||
md.records[frame].joysticks[0] = joysticks[pos++];
|
||||
md.records[frame].commands = commands[frame];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void INPUTLOG::compress_data()
|
||||
{
|
||||
// compress joysticks
|
||||
int len = joysticks.size();
|
||||
uLongf comprlen = (len>>9)+12 + len;
|
||||
joysticks_compressed.resize(comprlen);
|
||||
compress(&joysticks_compressed[0], &comprlen, &joysticks[0], len);
|
||||
joysticks_compressed.resize(comprlen);
|
||||
// compress commands
|
||||
len = commands.size();
|
||||
comprlen = (len>>9)+12 + len;
|
||||
commands_compressed.resize(comprlen);
|
||||
compress(&commands_compressed[0], &comprlen, &commands[0], len);
|
||||
commands_compressed.resize(comprlen);
|
||||
if (has_hot_changes)
|
||||
{
|
||||
// compress hot_changes
|
||||
len = hot_changes.size();
|
||||
comprlen = (len>>9)+12 + len;
|
||||
hot_changes_compressed.resize(comprlen);
|
||||
compress(&hot_changes_compressed[0], &comprlen, &hot_changes[0], len);
|
||||
hot_changes_compressed.resize(comprlen);
|
||||
}
|
||||
// don't recompress anymore
|
||||
already_compressed = true;
|
||||
}
|
||||
bool INPUTLOG::Get_already_compressed()
|
||||
{
|
||||
return already_compressed;
|
||||
}
|
||||
|
||||
void INPUTLOG::save(EMUFILE *os)
|
||||
{
|
||||
// write vars
|
||||
write32le(size, os);
|
||||
write8le(input_type, os);
|
||||
// write data
|
||||
if (!already_compressed)
|
||||
compress_data();
|
||||
// save joysticks data
|
||||
write32le(joysticks_compressed.size(), os);
|
||||
os->fwrite(&joysticks_compressed[0], joysticks_compressed.size());
|
||||
// save commands data
|
||||
write32le(commands_compressed.size(), os);
|
||||
os->fwrite(&commands_compressed[0], commands_compressed.size());
|
||||
if (has_hot_changes)
|
||||
{
|
||||
write8le((uint8)1, os);
|
||||
// save hot_changes data
|
||||
write32le(hot_changes_compressed.size(), os);
|
||||
os->fwrite(&hot_changes_compressed[0], hot_changes_compressed.size());
|
||||
} else
|
||||
{
|
||||
write8le((uint8)0, os);
|
||||
}
|
||||
}
|
||||
// returns true if couldn't load
|
||||
bool INPUTLOG::load(EMUFILE *is)
|
||||
{
|
||||
uint8 tmp;
|
||||
// read vars
|
||||
if (!read32le(&size, is)) return true;
|
||||
if (!read8le(&tmp, is)) return true;
|
||||
input_type = tmp;
|
||||
// read data
|
||||
already_compressed = true;
|
||||
int comprlen;
|
||||
uLongf destlen;
|
||||
// read and uncompress joysticks data
|
||||
destlen = size * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type];
|
||||
joysticks.resize(destlen);
|
||||
// read size
|
||||
if (!read32le(&comprlen, is)) return true;
|
||||
if (comprlen <= 0) return true;
|
||||
joysticks_compressed.resize(comprlen);
|
||||
if (is->fread(&joysticks_compressed[0], comprlen) != comprlen) return true;
|
||||
int e = uncompress(&joysticks[0], &destlen, &joysticks_compressed[0], comprlen);
|
||||
if (e != Z_OK && e != Z_BUF_ERROR) return true;
|
||||
// read and uncompress commands data
|
||||
destlen = size;
|
||||
commands.resize(destlen);
|
||||
// read size
|
||||
if (!read32le(&comprlen, is)) return true;
|
||||
if (comprlen <= 0) return true;
|
||||
commands_compressed.resize(comprlen);
|
||||
if (is->fread(&commands_compressed[0], comprlen) != comprlen) return true;
|
||||
e = uncompress(&commands[0], &destlen, &commands_compressed[0], comprlen);
|
||||
if (e != Z_OK && e != Z_BUF_ERROR) return true;
|
||||
// read hotchanges
|
||||
if (!read8le(&tmp, is)) return true;
|
||||
has_hot_changes = (tmp != 0);
|
||||
if (has_hot_changes)
|
||||
{
|
||||
// read and uncompress hot_changes data
|
||||
destlen = size * joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
hot_changes.resize(destlen);
|
||||
// read size
|
||||
if (!read32le(&comprlen, is)) return true;
|
||||
if (comprlen <= 0) return true;
|
||||
hot_changes_compressed.resize(comprlen);
|
||||
if (is->fread(&hot_changes_compressed[0], comprlen) != comprlen) return true;
|
||||
e = uncompress(&hot_changes[0], &destlen, &hot_changes_compressed[0], comprlen);
|
||||
if (e != Z_OK && e != Z_BUF_ERROR) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool INPUTLOG::skipLoad(EMUFILE *is)
|
||||
{
|
||||
int tmp;
|
||||
uint8 tmp1;
|
||||
// skip vars
|
||||
if (is->fseek(sizeof(int) + // size
|
||||
sizeof(uint8) // input_type
|
||||
, SEEK_CUR)) return true;
|
||||
// skip joysticks data
|
||||
if (!read32le(&tmp, is)) return true;
|
||||
if (is->fseek(tmp, SEEK_CUR) != 0) return true;
|
||||
// skip commands data
|
||||
if (!read32le(&tmp, is)) return true;
|
||||
if (is->fseek(tmp, SEEK_CUR) != 0) return true;
|
||||
// skip hot_changes data
|
||||
if (!read8le(&tmp1, is)) return true;
|
||||
if (tmp1)
|
||||
{
|
||||
if (!read32le(&tmp, is)) return true;
|
||||
if (is->fseek(tmp, SEEK_CUR) != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// fills map of bits judging on which joypads differ (this function is only used by "Record" modtype)
|
||||
uint32 INPUTLOG::fillJoypadsDiff(INPUTLOG& their_log, int frame)
|
||||
{
|
||||
uint32 joypad_diff_bits = 0;
|
||||
uint32 current_mask = 1;
|
||||
switch(input_type)
|
||||
{
|
||||
case INPUT_TYPE_FOURSCORE:
|
||||
case INPUT_TYPE_2P:
|
||||
case INPUT_TYPE_1P:
|
||||
{
|
||||
int pos = frame * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type];
|
||||
for (int i = 0; i < BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; ++i)
|
||||
{
|
||||
if (pos < (their_log.size * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]))
|
||||
{
|
||||
if (joysticks[pos+i] != their_log.joysticks[pos+i]) joypad_diff_bits |= current_mask;
|
||||
} else
|
||||
{
|
||||
if (joysticks[pos+i]) joypad_diff_bits |= current_mask;
|
||||
}
|
||||
current_mask <<= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return joypad_diff_bits;
|
||||
}
|
||||
// return number of first frame of difference between two InputLogs
|
||||
int INPUTLOG::findFirstChange(INPUTLOG& their_log, int start, int end)
|
||||
{
|
||||
// if these two InputLogs have different input_type (abnormal situation) then refuse to search and return the beginning
|
||||
if (their_log.input_type != input_type)
|
||||
return start;
|
||||
|
||||
// search for differences to the specified end (or to the end of this InputLog)
|
||||
if (end < 0 || end >= size) end = size-1;
|
||||
int their_log_end = their_log.size;
|
||||
switch(input_type)
|
||||
{
|
||||
case INPUT_TYPE_FOURSCORE:
|
||||
{
|
||||
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
|
||||
{
|
||||
// return the frame if found different byte, or found emptiness in their_log when there's non-zero value here
|
||||
if (frame < their_log_end)
|
||||
{
|
||||
if (joysticks[pos] != their_log.joysticks[pos]) return frame;
|
||||
pos++;
|
||||
if (joysticks[pos] != their_log.joysticks[pos]) return frame;
|
||||
pos++;
|
||||
if (joysticks[pos] != their_log.joysticks[pos]) return frame;
|
||||
pos++;
|
||||
if (joysticks[pos] != their_log.joysticks[pos]) return frame;
|
||||
pos++;
|
||||
if (commands[frame] != their_log.commands[frame]) return frame;
|
||||
} else
|
||||
{
|
||||
if (joysticks[pos++]) return frame;
|
||||
if (joysticks[pos++]) return frame;
|
||||
if (joysticks[pos++]) return frame;
|
||||
if (joysticks[pos++]) return frame;
|
||||
if (commands[frame]) return frame;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_2P:
|
||||
{
|
||||
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
|
||||
{
|
||||
// return the frame if found different byte, or found emptiness in their_log when there's non-zero value here
|
||||
if (frame < their_log_end)
|
||||
{
|
||||
if (joysticks[pos] != their_log.joysticks[pos]) return frame;
|
||||
pos++;
|
||||
if (joysticks[pos] != their_log.joysticks[pos]) return frame;
|
||||
pos++;
|
||||
if (commands[frame] != their_log.commands[frame]) return frame;
|
||||
} else
|
||||
{
|
||||
if (joysticks[pos++]) return frame;
|
||||
if (joysticks[pos++]) return frame;
|
||||
if (commands[frame]) return frame;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_1P:
|
||||
{
|
||||
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
|
||||
{
|
||||
// return the frame if found different byte, or found emptiness in their_log when there's non-zero value here
|
||||
if (frame < their_log_end)
|
||||
{
|
||||
if (joysticks[pos] != their_log.joysticks[pos]) return frame;
|
||||
pos++;
|
||||
if (commands[frame] != their_log.commands[frame]) return frame;
|
||||
} else
|
||||
{
|
||||
if (joysticks[pos++]) return frame;
|
||||
if (commands[frame]) return frame;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if my_size is less then their_size, return last frame + 1 (= size) as the frame of difference
|
||||
if (size < their_log_end) return size;
|
||||
// no changes were found
|
||||
return -1;
|
||||
}
|
||||
// return number of first frame of difference between this InputLog and MovieData
|
||||
int INPUTLOG::findFirstChange(MovieData& md, int start, int end)
|
||||
{
|
||||
// search for differences to the specified end (or to the end of this InputLog / to the end of the movie)
|
||||
if (end < 0 || end >= size) end = size-1;
|
||||
if (end >= md.getNumRecords()) end = md.getNumRecords()-1;
|
||||
|
||||
switch(input_type)
|
||||
{
|
||||
case INPUT_TYPE_FOURSCORE:
|
||||
{
|
||||
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; 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;
|
||||
if (commands[frame] != md.records[frame].commands) return frame;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_2P:
|
||||
{
|
||||
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
|
||||
{
|
||||
if (joysticks[pos++] != md.records[frame].joysticks[0]) return frame;
|
||||
if (joysticks[pos++] != md.records[frame].joysticks[1]) return frame;
|
||||
if (commands[frame] != md.records[frame].commands) return frame;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_1P:
|
||||
{
|
||||
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
|
||||
{
|
||||
if (joysticks[pos++] != md.records[frame].joysticks[0]) return frame;
|
||||
if (commands[frame] != md.records[frame].commands) return frame;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if sizes differ, return last frame + 1 from the lesser of them
|
||||
if (size < md.getNumRecords() && end >= size-1)
|
||||
return size;
|
||||
else if (size > md.getNumRecords() && end >= md.getNumRecords()-1)
|
||||
return md.getNumRecords();
|
||||
|
||||
return -1; // no changes were found
|
||||
}
|
||||
|
||||
int INPUTLOG::GetJoystickInfo(int frame, int joy)
|
||||
{
|
||||
if (frame < 0 || frame >= size) return 0;
|
||||
switch(input_type)
|
||||
{
|
||||
case INPUT_TYPE_FOURSCORE:
|
||||
case INPUT_TYPE_2P:
|
||||
case INPUT_TYPE_1P:
|
||||
{
|
||||
return joysticks[frame * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type] + joy];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int INPUTLOG::GetCommandsInfo(int frame)
|
||||
{
|
||||
if (frame < 0 || frame >= size) return 0;
|
||||
return commands[frame];
|
||||
}
|
||||
|
||||
void INPUTLOG::insertFrames(int at, int frames)
|
||||
{
|
||||
size += frames;
|
||||
if (at == -1)
|
||||
{
|
||||
// append frames to the end
|
||||
commands.resize(size);
|
||||
joysticks.resize(BYTES_PER_JOYSTICK * joysticks_per_frame[input_type] * size);
|
||||
if (has_hot_changes)
|
||||
{
|
||||
hot_changes.resize(joysticks_per_frame[input_type] * size * HOTCHANGE_BYTES_PER_JOY);
|
||||
// fill new hotchanges with max value
|
||||
int lower_limit = joysticks_per_frame[input_type] * (size - frames) * HOTCHANGE_BYTES_PER_JOY;
|
||||
for (int i = hot_changes.size() - 1; i >= lower_limit; i--)
|
||||
hot_changes[i] = 0xFF;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// insert frames
|
||||
// insert 1 byte of commands
|
||||
commands.insert(commands.begin() + at, frames, 0);
|
||||
// insert X bytes of joystics
|
||||
int bytes = BYTES_PER_JOYSTICK * joysticks_per_frame[input_type];
|
||||
joysticks.insert(joysticks.begin() + (at * bytes), frames * bytes, 0);
|
||||
if (has_hot_changes)
|
||||
{
|
||||
// insert X bytes of hot_changes
|
||||
bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
hot_changes.insert(hot_changes.begin() + (at * bytes), frames * bytes, 0xFF);
|
||||
}
|
||||
}
|
||||
// data was changed
|
||||
already_compressed = false;
|
||||
}
|
||||
void INPUTLOG::eraseFrame(int frame)
|
||||
{
|
||||
// erase 1 byte of commands
|
||||
commands.erase(commands.begin() + frame);
|
||||
// erase X bytes of joystics
|
||||
int bytes = BYTES_PER_JOYSTICK * joysticks_per_frame[input_type];
|
||||
joysticks.erase(joysticks.begin() + (frame * bytes), joysticks.begin() + ((frame + 1) * bytes));
|
||||
if (has_hot_changes)
|
||||
{
|
||||
// erase X bytes of hot_changes
|
||||
bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
hot_changes.erase(hot_changes.begin() + (frame * bytes), hot_changes.begin() + ((frame + 1) * bytes));
|
||||
}
|
||||
size--;
|
||||
// data was changed
|
||||
already_compressed = false;
|
||||
}
|
||||
// --------------------------------------------------------
|
||||
void INPUTLOG::copyHotChanges(INPUTLOG* source_of_hotchanges, int limit_frame_of_source)
|
||||
{
|
||||
// copy hot changes from source InputLog
|
||||
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
|
||||
{
|
||||
int min = hot_changes.size();
|
||||
if (min > (int)source_of_hotchanges->hot_changes.size())
|
||||
min = source_of_hotchanges->hot_changes.size();
|
||||
|
||||
// special case for Branches: if limit_frame if specified, then copy only hotchanges from 0 to limit_frame
|
||||
if (limit_frame_of_source >= 0)
|
||||
{
|
||||
if (min > limit_frame_of_source * joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY)
|
||||
min = limit_frame_of_source * joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
}
|
||||
|
||||
memcpy(&hot_changes[0], &source_of_hotchanges->hot_changes[0], min);
|
||||
}
|
||||
}
|
||||
void INPUTLOG::inheritHotChanges(INPUTLOG* source_of_hotchanges)
|
||||
{
|
||||
// copy hot changes from source InputLog and fade them
|
||||
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
|
||||
{
|
||||
int min = hot_changes.size();
|
||||
if (min > (int)source_of_hotchanges->hot_changes.size())
|
||||
min = source_of_hotchanges->hot_changes.size();
|
||||
|
||||
memcpy(&hot_changes[0], &source_of_hotchanges->hot_changes[0], min);
|
||||
FadeHotChanges();
|
||||
}
|
||||
}
|
||||
void INPUTLOG::inheritHotChanges_DeleteSelection(INPUTLOG* source_of_hotchanges)
|
||||
{
|
||||
// copy hot changes from source InputLog, but omit deleted frames (which are represented by current selection)
|
||||
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
|
||||
{
|
||||
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
int frame = 0, pos = 0, source_pos = 0;
|
||||
int this_size = hot_changes.size(), source_size = source_of_hotchanges->hot_changes.size();
|
||||
SelectionFrames::iterator it(selection.GetStrobedSelection().begin());
|
||||
while (pos < this_size && source_pos < source_size)
|
||||
{
|
||||
if (it != selection.GetStrobedSelection().end() && frame == *it)
|
||||
{
|
||||
// this frame is selected
|
||||
it++;
|
||||
// omit the frame
|
||||
source_pos += bytes;
|
||||
} else
|
||||
{
|
||||
// copy hotchanges of this frame
|
||||
memcpy(&hot_changes[pos], &source_of_hotchanges->hot_changes[source_pos], bytes);
|
||||
pos += bytes;
|
||||
source_pos += bytes;
|
||||
}
|
||||
frame++;
|
||||
}
|
||||
FadeHotChanges();
|
||||
}
|
||||
}
|
||||
void INPUTLOG::inheritHotChanges_InsertSelection(INPUTLOG* source_of_hotchanges)
|
||||
{
|
||||
// copy hot changes from source InputLog, but insert filled lines for inserted frames (which are represented by current selection)
|
||||
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
|
||||
{
|
||||
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
int frame = 0, region_len = 0, pos = 0, source_pos = 0;
|
||||
int this_size = hot_changes.size(), source_size = source_of_hotchanges->hot_changes.size();
|
||||
SelectionFrames::iterator it(selection.GetStrobedSelection().begin());
|
||||
SelectionFrames::iterator current_selection_end(selection.GetStrobedSelection().end());
|
||||
while (pos < this_size)
|
||||
{
|
||||
if (it != current_selection_end && frame == *it)
|
||||
{
|
||||
// this frame is selected
|
||||
it++;
|
||||
region_len++;
|
||||
// set filled line to the frame
|
||||
memset(&hot_changes[pos], 0xFF, bytes);
|
||||
} else if (source_pos < source_size)
|
||||
{
|
||||
// this frame is not selected
|
||||
frame -= region_len;
|
||||
region_len = 0;
|
||||
// copy hotchanges of this frame
|
||||
memcpy(&hot_changes[pos], &source_of_hotchanges->hot_changes[source_pos], bytes);
|
||||
FadeHotChanges(pos, pos + bytes);
|
||||
source_pos += bytes;
|
||||
}
|
||||
pos += bytes;
|
||||
frame++;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// no old data, just fill selected lines
|
||||
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
int frame = 0, region_len = 0, pos = 0;
|
||||
int this_size = hot_changes.size();
|
||||
SelectionFrames::iterator it(selection.GetStrobedSelection().begin());
|
||||
SelectionFrames::iterator current_selection_end(selection.GetStrobedSelection().end());
|
||||
while (pos < this_size)
|
||||
{
|
||||
if (it != current_selection_end && frame == *it)
|
||||
{
|
||||
// this frame is selected
|
||||
it++;
|
||||
region_len++;
|
||||
// set filled line to the frame
|
||||
memset(&hot_changes[pos], 0xFF, bytes);
|
||||
// exit loop when all frames in the Selection are handled
|
||||
if (it == current_selection_end) break;
|
||||
} else
|
||||
{
|
||||
// this frame is not selected
|
||||
frame -= region_len;
|
||||
region_len = 0;
|
||||
// leave zeros in this frame
|
||||
}
|
||||
pos += bytes;
|
||||
frame++;
|
||||
}
|
||||
}
|
||||
}
|
||||
void INPUTLOG::inheritHotChanges_DeleteNum(INPUTLOG* source_of_hotchanges, int start, int frames, bool fade_old)
|
||||
{
|
||||
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
// copy hot changes from source InputLog up to "start" and from "start+frames" to end
|
||||
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
|
||||
{
|
||||
int this_size = hot_changes.size(), source_size = source_of_hotchanges->hot_changes.size();
|
||||
int bytes_to_copy = bytes * start;
|
||||
int dest_pos = 0, source_pos = 0;
|
||||
if (bytes_to_copy > source_size)
|
||||
bytes_to_copy = source_size;
|
||||
memcpy(&hot_changes[dest_pos], &source_of_hotchanges->hot_changes[source_pos], bytes_to_copy);
|
||||
dest_pos += bytes_to_copy;
|
||||
source_pos += bytes_to_copy + bytes * frames;
|
||||
bytes_to_copy = this_size - dest_pos;
|
||||
if (bytes_to_copy > source_size - source_pos)
|
||||
bytes_to_copy = source_size - source_pos;
|
||||
memcpy(&hot_changes[dest_pos], &source_of_hotchanges->hot_changes[source_pos], bytes_to_copy);
|
||||
if (fade_old)
|
||||
FadeHotChanges();
|
||||
}
|
||||
}
|
||||
void INPUTLOG::inheritHotChanges_InsertNum(INPUTLOG* source_of_hotchanges, int start, int frames, bool fade_old)
|
||||
{
|
||||
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
// copy hot changes from source InputLog up to "start", then make a gap, then copy from "start+frames" to end
|
||||
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
|
||||
{
|
||||
int this_size = hot_changes.size(), source_size = source_of_hotchanges->hot_changes.size();
|
||||
int bytes_to_copy = bytes * start;
|
||||
int dest_pos = 0, source_pos = 0;
|
||||
if (bytes_to_copy > source_size)
|
||||
bytes_to_copy = source_size;
|
||||
memcpy(&hot_changes[dest_pos], &source_of_hotchanges->hot_changes[source_pos], bytes_to_copy);
|
||||
dest_pos += bytes_to_copy + bytes * frames;
|
||||
source_pos += bytes_to_copy;
|
||||
bytes_to_copy = this_size - dest_pos;
|
||||
if (bytes_to_copy > source_size - source_pos)
|
||||
bytes_to_copy = source_size - source_pos;
|
||||
memcpy(&hot_changes[dest_pos], &source_of_hotchanges->hot_changes[source_pos], bytes_to_copy);
|
||||
if (fade_old)
|
||||
FadeHotChanges();
|
||||
}
|
||||
// fill the gap with max_hot lines on frames from "start" to "start+frames"
|
||||
memset(&hot_changes[bytes * start], 0xFF, bytes * frames);
|
||||
}
|
||||
void INPUTLOG::inheritHotChanges_PasteInsert(INPUTLOG* source_of_hotchanges, SelectionFrames& inserted_set)
|
||||
{
|
||||
// copy hot changes from source InputLog and insert filled lines for inserted frames (which are represented by inserted_set)
|
||||
if (source_of_hotchanges && source_of_hotchanges->has_hot_changes && source_of_hotchanges->input_type == input_type)
|
||||
{
|
||||
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
int frame = 0, pos = 0, source_pos = 0;
|
||||
int this_size = hot_changes.size(), source_size = source_of_hotchanges->hot_changes.size();
|
||||
SelectionFrames::iterator it(inserted_set.begin());
|
||||
SelectionFrames::iterator inserted_set_end(inserted_set.end());
|
||||
while (pos < this_size)
|
||||
{
|
||||
if (it != inserted_set_end && frame == *it)
|
||||
{
|
||||
// this frame was inserted
|
||||
it++;
|
||||
// set filled line to the frame
|
||||
memset(&hot_changes[pos], 0xFF, bytes);
|
||||
} else if (source_pos < source_size)
|
||||
{
|
||||
// copy hotchanges of this frame
|
||||
memcpy(&hot_changes[pos], &source_of_hotchanges->hot_changes[source_pos], bytes);
|
||||
FadeHotChanges(pos, pos + bytes);
|
||||
source_pos += bytes;
|
||||
}
|
||||
pos += bytes;
|
||||
frame++;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// no old data, just fill selected lines
|
||||
int bytes = joysticks_per_frame[input_type] * HOTCHANGE_BYTES_PER_JOY;
|
||||
int frame = 0, pos = 0;
|
||||
int this_size = hot_changes.size();
|
||||
SelectionFrames::iterator it(inserted_set.begin());
|
||||
SelectionFrames::iterator inserted_set_end(inserted_set.end());
|
||||
while (pos < this_size)
|
||||
{
|
||||
if (it != inserted_set_end && frame == *it)
|
||||
{
|
||||
// this frame was inserted
|
||||
it++;
|
||||
// set filled line to the frame
|
||||
memset(&hot_changes[pos], 0xFF, bytes);
|
||||
pos += bytes;
|
||||
// exit loop when all inserted_set frames are handled
|
||||
if (it == inserted_set_end) break;
|
||||
} else
|
||||
{
|
||||
// leave zeros in this frame
|
||||
pos += bytes;
|
||||
}
|
||||
frame++;
|
||||
}
|
||||
}
|
||||
}
|
||||
void INPUTLOG::fillHotChanges(INPUTLOG& their_log, int start, int end)
|
||||
{
|
||||
// if these two InputLogs have different input_type (abnormal situation) then refuse to compare
|
||||
if (their_log.input_type != input_type)
|
||||
return;
|
||||
|
||||
// compare InputLogs to the specified end (or to the end of this InputLog)
|
||||
if (end < 0 || end >= size) end = size-1;
|
||||
int their_log_end = their_log.size;
|
||||
switch(input_type)
|
||||
{
|
||||
case INPUT_TYPE_FOURSCORE:
|
||||
{
|
||||
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
|
||||
{
|
||||
// consider changed if found different byte, or found emptiness in their_log when there's non-zero value here
|
||||
if (frame < their_log_end)
|
||||
{
|
||||
if (joysticks[pos] != their_log.joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 0, joysticks[pos] ^ their_log.joysticks[pos]);
|
||||
pos++;
|
||||
if (joysticks[pos] != their_log.joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 1, joysticks[pos] ^ their_log.joysticks[pos]);
|
||||
pos++;
|
||||
if (joysticks[pos] != their_log.joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 2, joysticks[pos] ^ their_log.joysticks[pos]);
|
||||
pos++;
|
||||
if (joysticks[pos] != their_log.joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 3, joysticks[pos] ^ their_log.joysticks[pos]);
|
||||
pos++;
|
||||
} else
|
||||
{
|
||||
if (joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 0, joysticks[pos]);
|
||||
pos++;
|
||||
if (joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 1, joysticks[pos]);
|
||||
pos++;
|
||||
if (joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 2, joysticks[pos]);
|
||||
pos++;
|
||||
if (joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 3, joysticks[pos]);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_2P:
|
||||
{
|
||||
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
|
||||
{
|
||||
// consider changed if found different byte, or found emptiness in their_log when there's non-zero value here
|
||||
if (frame < their_log_end)
|
||||
{
|
||||
if (joysticks[pos] != their_log.joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 0, joysticks[pos] ^ their_log.joysticks[pos]);
|
||||
pos++;
|
||||
if (joysticks[pos] != their_log.joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 1, joysticks[pos] ^ their_log.joysticks[pos]);
|
||||
pos++;
|
||||
} else
|
||||
{
|
||||
if (joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 0, joysticks[pos]);
|
||||
pos++;
|
||||
if (joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 1, joysticks[pos]);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_1P:
|
||||
{
|
||||
for (int frame = start, pos = start * BYTES_PER_JOYSTICK * joysticks_per_frame[input_type]; frame <= end; ++frame)
|
||||
{
|
||||
// consider changed if found different byte, or found emptiness in their_log when there's non-zero value here
|
||||
if (frame < their_log_end)
|
||||
{
|
||||
if (joysticks[pos] != their_log.joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 0, joysticks[pos] ^ their_log.joysticks[pos]);
|
||||
pos++;
|
||||
} else
|
||||
{
|
||||
if (joysticks[pos])
|
||||
SetMaxHotChange_Bits(frame, 0, joysticks[pos]);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void INPUTLOG::SetMaxHotChange_Bits(int frame, int joypad, uint8 joy_bits)
|
||||
{
|
||||
uint8 mask = 1;
|
||||
// check all 8 buttons and set max hot_changes for bits that are set
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (joy_bits & mask)
|
||||
SetMaxHotChange(frame, joypad * 8 + i);
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
void INPUTLOG::SetMaxHotChange(int frame, int absolute_button)
|
||||
{
|
||||
if (frame < 0 || frame >= size || !has_hot_changes) return;
|
||||
// set max value (15) to the button hotness
|
||||
switch(input_type)
|
||||
{
|
||||
case INPUT_TYPE_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 INPUT_TYPE_2P:
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
case INPUT_TYPE_1P:
|
||||
{
|
||||
// 8 buttons = 4bytes
|
||||
if (absolute_button & 1)
|
||||
// odd buttons (B, T, D, R) - set upper 4 bits of the byte
|
||||
hot_changes[(frame << 2) | (absolute_button >> 1)] |= 0xF0;
|
||||
else
|
||||
// even buttons (A, S, U, L) - set lower 4 bits of the byte
|
||||
hot_changes[(frame << 2) | (absolute_button >> 1)] |= 0x0F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void INPUTLOG::FadeHotChanges(int start_byte, int end_byte)
|
||||
{
|
||||
uint8 hi_half, low_half;
|
||||
if (end_byte < 0)
|
||||
end_byte = hot_changes.size();
|
||||
for (int i = end_byte - 1; i >= start_byte; i--)
|
||||
{
|
||||
if (hot_changes[i])
|
||||
{
|
||||
hi_half = hot_changes[i] >> 4;
|
||||
low_half = hot_changes[i] & 15;
|
||||
if (hi_half) hi_half--;
|
||||
if (low_half) low_half--;
|
||||
hot_changes[i] = (hi_half << 4) | low_half;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int INPUTLOG::GetHotChangeInfo(int frame, int absolute_button)
|
||||
{
|
||||
if (!has_hot_changes || frame < 0 || frame >= size || absolute_button < 0 || absolute_button >= NUM_JOYPAD_BUTTONS * joysticks_per_frame[input_type])
|
||||
return 0;
|
||||
|
||||
uint8 val;
|
||||
switch(input_type)
|
||||
{
|
||||
case INPUT_TYPE_FOURSCORE:
|
||||
{
|
||||
// 32 buttons, 16bytes
|
||||
val = hot_changes[(frame << 4) + (absolute_button >> 1)];
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_2P:
|
||||
{
|
||||
// 16 buttons, 8bytes
|
||||
val = hot_changes[(frame << 3) + (absolute_button >> 1)];
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_1P:
|
||||
{
|
||||
// 8 buttons, 4bytes
|
||||
val = hot_changes[(frame << 2) + (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,75 @@
|
|||
// Specification file for InputLog class
|
||||
|
||||
enum Input_types
|
||||
{
|
||||
INPUT_TYPE_1P,
|
||||
INPUT_TYPE_2P,
|
||||
INPUT_TYPE_FOURSCORE,
|
||||
|
||||
NUM_SUPPORTED_INPUT_TYPES
|
||||
};
|
||||
|
||||
#define BYTES_PER_JOYSTICK 1 // 1 byte per 1 joystick (8 buttons)
|
||||
#define HOTCHANGE_BYTES_PER_JOY 4 // 4 bytes per 8 buttons
|
||||
|
||||
class INPUTLOG
|
||||
{
|
||||
public:
|
||||
INPUTLOG();
|
||||
void init(MovieData& md, bool hotchanges, int force_input_type = -1);
|
||||
void toMovie(MovieData& md, int start = 0, int end = -1);
|
||||
|
||||
void save(EMUFILE *os);
|
||||
bool load(EMUFILE *is);
|
||||
bool skipLoad(EMUFILE *is);
|
||||
|
||||
void compress_data();
|
||||
bool Get_already_compressed();
|
||||
|
||||
uint32 INPUTLOG::fillJoypadsDiff(INPUTLOG& their_log, int frame);
|
||||
int findFirstChange(INPUTLOG& their_log, int start = 0, int end = -1);
|
||||
int findFirstChange(MovieData& md, int start = 0, int end = -1);
|
||||
|
||||
int GetJoystickInfo(int frame, int joy);
|
||||
int GetCommandsInfo(int frame);
|
||||
|
||||
void insertFrames(int at, int frames);
|
||||
void eraseFrame(int frame);
|
||||
|
||||
void copyHotChanges(INPUTLOG* source_of_hotchanges, int limit_frame_of_source = -1);
|
||||
void inheritHotChanges(INPUTLOG* source_of_hotchanges);
|
||||
void inheritHotChanges_DeleteSelection(INPUTLOG* source_of_hotchanges);
|
||||
void inheritHotChanges_InsertSelection(INPUTLOG* source_of_hotchanges);
|
||||
void inheritHotChanges_DeleteNum(INPUTLOG* source_of_hotchanges, int start, int frames, bool fade_old);
|
||||
void inheritHotChanges_InsertNum(INPUTLOG* source_of_hotchanges, int start, int frames, bool fade_old);
|
||||
void inheritHotChanges_PasteInsert(INPUTLOG* source_of_hotchanges, SelectionFrames& inserted_set);
|
||||
void fillHotChanges(INPUTLOG& their_log, int start = 0, int end = -1);
|
||||
|
||||
void SetMaxHotChange_Bits(int frame, int joypad, uint8 joy_bits);
|
||||
void SetMaxHotChange(int frame, int absolute_button);
|
||||
|
||||
void FadeHotChanges(int start_byte = 0, int end_byte = -1);
|
||||
|
||||
int GetHotChangeInfo(int frame, int absolute_button);
|
||||
|
||||
// saved data
|
||||
int size; // in frames
|
||||
int input_type; // theoretically TAS Editor can support any other Input types
|
||||
bool has_hot_changes;
|
||||
|
||||
// not saved data
|
||||
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> commands; // Format: commands-for-frame0, commands-for-frame1, ...
|
||||
std::vector<uint8> hot_changes; // Format: buttons01joy0-for-frame0, buttons23joy0-for-frame0, buttons45joy0-for-frame0, buttons67joy0-for-frame0, buttons01joy1-for-frame0, ...
|
||||
|
||||
private:
|
||||
|
||||
// also saved data
|
||||
std::vector<uint8> joysticks_compressed;
|
||||
std::vector<uint8> commands_compressed;
|
||||
std::vector<uint8> hot_changes_compressed;
|
||||
|
||||
// not saved data
|
||||
bool already_compressed; // to compress only once
|
||||
};
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/* ---------------------------------------------------------------------------------
|
||||
Implementation file of LagLog class
|
||||
Copyright (c) 2011-2012 AnS
|
||||
|
||||
(The MIT License)
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------------
|
||||
LagLog - Log of Lag appearance
|
||||
|
||||
* stores the frame-by-frame log of lag appearance
|
||||
* implements compression and decompression of stored data
|
||||
* saves and loads the data from a project file. On error: sends warning to caller
|
||||
* provides interface for reading and writing log data
|
||||
------------------------------------------------------------------------------------ */
|
||||
|
||||
#include "taseditor_project.h"
|
||||
#include "zlib.h"
|
||||
|
||||
LAGLOG::LAGLOG()
|
||||
{
|
||||
already_compressed = false;
|
||||
}
|
||||
|
||||
void LAGLOG::reset()
|
||||
{
|
||||
lag_log.resize(0);
|
||||
already_compressed = false;
|
||||
}
|
||||
|
||||
void LAGLOG::compress_data()
|
||||
{
|
||||
int len = lag_log.size() * sizeof(uint8);
|
||||
uLongf comprlen = (len>>9)+12 + len;
|
||||
lag_log_compressed.resize(comprlen);
|
||||
compress(&lag_log_compressed[0], &comprlen, (uint8*)&lag_log[0], len);
|
||||
lag_log_compressed.resize(comprlen);
|
||||
already_compressed = true;
|
||||
}
|
||||
bool LAGLOG::Get_already_compressed()
|
||||
{
|
||||
return already_compressed;
|
||||
}
|
||||
void LAGLOG::Reset_already_compressed()
|
||||
{
|
||||
already_compressed = false;
|
||||
}
|
||||
|
||||
void LAGLOG::save(EMUFILE *os)
|
||||
{
|
||||
// write size
|
||||
int size = lag_log.size();
|
||||
write32le(size, os);
|
||||
// write array
|
||||
if (!already_compressed)
|
||||
compress_data();
|
||||
write32le(lag_log_compressed.size(), os);
|
||||
os->fwrite(&lag_log_compressed[0], lag_log_compressed.size());
|
||||
}
|
||||
// returns true if couldn't load
|
||||
bool LAGLOG::load(EMUFILE *is)
|
||||
{
|
||||
int size;
|
||||
if (read32le(&size, is))
|
||||
{
|
||||
lag_log.resize(size);
|
||||
// read and uncompress array
|
||||
already_compressed = true;
|
||||
int comprlen;
|
||||
uLongf destlen = size * sizeof(int);
|
||||
if (!read32le(&comprlen, is)) return true;
|
||||
if (comprlen <= 0) return true;
|
||||
lag_log_compressed.resize(comprlen);
|
||||
if (is->fread(&lag_log_compressed[0], comprlen) != comprlen) return true;
|
||||
int e = uncompress((uint8*)&lag_log[0], &destlen, &lag_log_compressed[0], comprlen);
|
||||
if (e != Z_OK && e != Z_BUF_ERROR) return true;
|
||||
// all ok
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool LAGLOG::skipLoad(EMUFILE *is)
|
||||
{
|
||||
if (!(is->fseek(sizeof(int), SEEK_CUR)))
|
||||
{
|
||||
// read array
|
||||
int comprlen;
|
||||
if (!read32le(&comprlen, is)) return true;
|
||||
if (is->fseek(comprlen, SEEK_CUR) != 0) return true;
|
||||
// all ok
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
void LAGLOG::SetLagInfo(int frame, bool lagFlag)
|
||||
{
|
||||
if ((int)lag_log.size() <= frame)
|
||||
lag_log.resize(frame + 1);
|
||||
|
||||
if (lagFlag)
|
||||
lag_log[frame] = 1;
|
||||
else
|
||||
lag_log[frame] = 0;
|
||||
|
||||
already_compressed = false;
|
||||
}
|
||||
void LAGLOG::EraseLagFrame(int frame)
|
||||
{
|
||||
lag_log.erase(lag_log.begin() + (currFrameCounter - 1));
|
||||
}
|
||||
void LAGLOG::InsertLagFrame(int frame)
|
||||
{
|
||||
lag_log.insert(lag_log.begin() + frame, 1);
|
||||
}
|
||||
|
||||
// getters
|
||||
int LAGLOG::GetSize()
|
||||
{
|
||||
return lag_log.size();
|
||||
}
|
||||
bool LAGLOG::GetLagInfoAtFrame(int frame)
|
||||
{
|
||||
if (frame < (int)lag_log.size())
|
||||
return (lag_log[frame] != 0);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Specification file for LagLog class
|
||||
|
||||
class LAGLOG
|
||||
{
|
||||
public:
|
||||
LAGLOG();
|
||||
void reset();
|
||||
|
||||
void compress_data();
|
||||
bool Get_already_compressed();
|
||||
void Reset_already_compressed();
|
||||
|
||||
void save(EMUFILE *os);
|
||||
bool load(EMUFILE *is);
|
||||
bool skipLoad(EMUFILE *is);
|
||||
|
||||
void SetLagInfo(int frame, bool lagFlag);
|
||||
void EraseLagFrame(int frame);
|
||||
void InsertLagFrame(int frame);
|
||||
|
||||
int GetSize();
|
||||
bool GetLagInfoAtFrame(int frame);
|
||||
|
||||
private:
|
||||
// saved data
|
||||
std::vector<uint8> lag_log_compressed;
|
||||
|
||||
// not saved data
|
||||
std::vector<uint8> lag_log;
|
||||
bool already_compressed; // to compress only once
|
||||
};
|
|
@ -82,7 +82,6 @@ bool MARKERS::load(EMUFILE *is)
|
|||
}
|
||||
bool MARKERS::skipLoad(EMUFILE *is)
|
||||
{
|
||||
int size;
|
||||
if (!(is->fseek(sizeof(int), SEEK_CUR)))
|
||||
{
|
||||
// read array
|
||||
|
@ -90,9 +89,9 @@ bool MARKERS::skipLoad(EMUFILE *is)
|
|||
if (!read32le(&comprlen, is)) return true;
|
||||
if (is->fseek(comprlen, SEEK_CUR) != 0) return true;
|
||||
// read notes
|
||||
if (read32le(&size, is) && size >= 0)
|
||||
if (read32le(&comprlen, is) && comprlen >= 0)
|
||||
{
|
||||
for (int i = 0; i < size; ++i)
|
||||
for (int i = 0; i < comprlen; ++i)
|
||||
{
|
||||
if (!read32le(&len, is) || len < 0) return true;
|
||||
if (is->fseek(len, SEEK_CUR) != 0) return true;
|
||||
|
@ -117,8 +116,8 @@ bool MARKERS::Get_already_compressed()
|
|||
{
|
||||
return already_compressed;
|
||||
}
|
||||
void MARKERS::Set_already_compressed(bool value)
|
||||
void MARKERS::Reset_already_compressed()
|
||||
{
|
||||
already_compressed = value;
|
||||
already_compressed = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
|
||||
void compress_data();
|
||||
bool Get_already_compressed();
|
||||
void Set_already_compressed(bool value);
|
||||
void Reset_already_compressed();
|
||||
|
||||
// saved data
|
||||
std::vector<std::string> notes; // Format: 0th - note for intro (Marker 0), 1st - note for Marker1, 2nd - note for Marker2, ...
|
||||
|
|
|
@ -73,7 +73,7 @@ void MARKERS_MANAGER::save(EMUFILE *os, bool really_save)
|
|||
{
|
||||
// write "MARKERS" string
|
||||
os->fwrite(markers_save_id, MARKERS_ID_LEN);
|
||||
markers.Set_already_compressed(false); // must recompress data, because most likely it has changed since last compression
|
||||
markers.Reset_already_compressed(); // must recompress data, because most likely it has changed since last compression
|
||||
markers.save(os);
|
||||
} else
|
||||
{
|
||||
|
@ -293,7 +293,7 @@ void MARKERS_MANAGER::MakeCopyTo(MARKERS& destination)
|
|||
{
|
||||
destination.markers_array = markers.markers_array;
|
||||
destination.notes = markers.notes;
|
||||
destination.Set_already_compressed(false);
|
||||
destination.Reset_already_compressed();
|
||||
}
|
||||
void MARKERS_MANAGER::RestoreFromCopy(MARKERS& source)
|
||||
{
|
||||
|
|
|
@ -924,11 +924,11 @@ void PIANO_ROLL::FollowPlaybackIfNeeded()
|
|||
}
|
||||
void PIANO_ROLL::FollowUndo()
|
||||
{
|
||||
int jump_frame = history.GetUndoHint();
|
||||
if (taseditor_config.jump_to_undo && jump_frame >= 0)
|
||||
int keyframe = history.GetUndoHint();
|
||||
if (taseditor_config.jump_to_undo && keyframe >= 0)
|
||||
{
|
||||
if (!CheckItemVisible(jump_frame))
|
||||
CenterListAt(jump_frame);
|
||||
if (!CheckItemVisible(keyframe))
|
||||
CenterListAt(keyframe);
|
||||
}
|
||||
}
|
||||
void PIANO_ROLL::FollowSelection()
|
||||
|
@ -1253,7 +1253,7 @@ void PIANO_ROLL::GetDispInfo(NMLVDISPINFO* nmlvDispInfo)
|
|||
item.pszText[2] = 0;
|
||||
} else
|
||||
{
|
||||
if (taseditor_config.enable_hot_changes && history.GetCurrentSnapshot().GetHotChangeInfo(item.iItem, item.iSubItem - COLUMN_JOYPAD1_A))
|
||||
if (taseditor_config.enable_hot_changes && history.GetCurrentSnapshot().inputlog.GetHotChangeInfo(item.iItem, item.iSubItem - COLUMN_JOYPAD1_A))
|
||||
{
|
||||
item.pszText[0] = 45; // "-"
|
||||
item.pszText[1] = 0;
|
||||
|
@ -1281,7 +1281,7 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
{
|
||||
// text color
|
||||
if (taseditor_config.enable_hot_changes && cell_x >= COLUMN_JOYPAD1_A && cell_x <= COLUMN_JOYPAD4_R)
|
||||
msg->clrText = hot_changes_colors[history.GetCurrentSnapshot().GetHotChangeInfo(cell_y, cell_x - COLUMN_JOYPAD1_A)];
|
||||
msg->clrText = hot_changes_colors[history.GetCurrentSnapshot().inputlog.GetHotChangeInfo(cell_y, cell_x - COLUMN_JOYPAD1_A)];
|
||||
else
|
||||
msg->clrText = NORMAL_TEXT_COLOR;
|
||||
// bg color and text font
|
||||
|
@ -1323,7 +1323,7 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
if (!greenzone.SavestateIsEmpty(cell_y))
|
||||
{
|
||||
// the frame is normal Greenzone frame
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = LAG_FRAMENUM_COLOR;
|
||||
else
|
||||
msg->clrTextBk = GREENZONE_FRAMENUM_COLOR;
|
||||
|
@ -1333,14 +1333,14 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
|| (!greenzone.SavestateIsEmpty(cell_y & EVERY2ND) && !greenzone.SavestateIsEmpty((cell_y & EVERY2ND) + 2)))
|
||||
{
|
||||
// the frame is in a gap (in Greenzone tail)
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = PALE_LAG_FRAMENUM_COLOR;
|
||||
else
|
||||
msg->clrTextBk = PALE_GREENZONE_FRAMENUM_COLOR;
|
||||
} else
|
||||
{
|
||||
// the frame is above Greenzone tail
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = VERY_PALE_LAG_FRAMENUM_COLOR;
|
||||
else
|
||||
msg->clrTextBk = VERY_PALE_GREENZONE_FRAMENUM_COLOR;
|
||||
|
@ -1348,7 +1348,7 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
} else
|
||||
{
|
||||
// the frame is below Greenzone head
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = VERY_PALE_LAG_FRAMENUM_COLOR;
|
||||
else
|
||||
msg->clrTextBk = VERY_PALE_GREENZONE_FRAMENUM_COLOR;
|
||||
|
@ -1378,7 +1378,7 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
if (!greenzone.SavestateIsEmpty(cell_y))
|
||||
{
|
||||
// the frame is normal Greenzone frame
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = LAG_INPUT_COLOR1;
|
||||
else
|
||||
msg->clrTextBk = GREENZONE_INPUT_COLOR1;
|
||||
|
@ -1388,14 +1388,14 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
|| (!greenzone.SavestateIsEmpty(cell_y & EVERY2ND) && !greenzone.SavestateIsEmpty((cell_y & EVERY2ND) + 2)))
|
||||
{
|
||||
// the frame is in a gap (in Greenzone tail)
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = PALE_LAG_INPUT_COLOR1;
|
||||
else
|
||||
msg->clrTextBk = PALE_GREENZONE_INPUT_COLOR1;
|
||||
} else
|
||||
{
|
||||
// the frame is above Greenzone tail
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = VERY_PALE_LAG_INPUT_COLOR1;
|
||||
else
|
||||
msg->clrTextBk = VERY_PALE_GREENZONE_INPUT_COLOR1;
|
||||
|
@ -1403,7 +1403,7 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
} else
|
||||
{
|
||||
// the frame is below Greenzone head
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = VERY_PALE_LAG_INPUT_COLOR1;
|
||||
else
|
||||
msg->clrTextBk = VERY_PALE_GREENZONE_INPUT_COLOR1;
|
||||
|
@ -1433,7 +1433,7 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
if (!greenzone.SavestateIsEmpty(cell_y))
|
||||
{
|
||||
// the frame is normal Greenzone frame
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = LAG_INPUT_COLOR2;
|
||||
else
|
||||
msg->clrTextBk = GREENZONE_INPUT_COLOR2;
|
||||
|
@ -1443,14 +1443,14 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
|| (!greenzone.SavestateIsEmpty(cell_y & EVERY2ND) && !greenzone.SavestateIsEmpty((cell_y & EVERY2ND) + 2)))
|
||||
{
|
||||
// the frame is in a gap (in Greenzone tail)
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = PALE_LAG_INPUT_COLOR2;
|
||||
else
|
||||
msg->clrTextBk = PALE_GREENZONE_INPUT_COLOR2;
|
||||
} else
|
||||
{
|
||||
// the frame is above Greenzone tail
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = VERY_PALE_LAG_INPUT_COLOR2;
|
||||
else
|
||||
msg->clrTextBk = VERY_PALE_GREENZONE_INPUT_COLOR2;
|
||||
|
@ -1458,7 +1458,7 @@ LONG PIANO_ROLL::CustomDraw(NMLVCUSTOMDRAW* msg)
|
|||
} else
|
||||
{
|
||||
// the frame is below Greenzone head
|
||||
if (greenzone.GetLagHistoryAtFrame(cell_y))
|
||||
if (greenzone.laglog.GetLagInfoAtFrame(cell_y))
|
||||
msg->clrTextBk = VERY_PALE_LAG_INPUT_COLOR2;
|
||||
else
|
||||
msg->clrTextBk = VERY_PALE_GREENZONE_INPUT_COLOR2;
|
||||
|
|
|
@ -112,9 +112,9 @@ enum DRAG_MODES
|
|||
#define PALE_GREENZONE_INPUT_COLOR1 0xD3F9D2
|
||||
#define PALE_GREENZONE_INPUT_COLOR2 0xBAEBBA
|
||||
|
||||
#define VERY_PALE_GREENZONE_FRAMENUM_COLOR 0xF1FFF1
|
||||
#define VERY_PALE_GREENZONE_INPUT_COLOR1 0xE7FCE7
|
||||
#define VERY_PALE_GREENZONE_INPUT_COLOR2 0xD9F4D9
|
||||
#define VERY_PALE_GREENZONE_FRAMENUM_COLOR 0xF9FFF9
|
||||
#define VERY_PALE_GREENZONE_INPUT_COLOR1 0xE0FBE0
|
||||
#define VERY_PALE_GREENZONE_INPUT_COLOR2 0xD2F2D2
|
||||
|
||||
#define LAG_FRAMENUM_COLOR 0xDDDCFF
|
||||
#define LAG_INPUT_COLOR1 0xD2D0F0
|
||||
|
@ -124,9 +124,9 @@ enum DRAG_MODES
|
|||
#define PALE_LAG_INPUT_COLOR1 0xDADAF4
|
||||
#define PALE_LAG_INPUT_COLOR2 0xCFCEEA
|
||||
|
||||
#define VERY_PALE_LAG_FRAMENUM_COLOR 0xF0F0FF
|
||||
#define VERY_PALE_LAG_INPUT_COLOR1 0xEBEBF9
|
||||
#define VERY_PALE_LAG_INPUT_COLOR2 0xE5E5F3
|
||||
#define VERY_PALE_LAG_FRAMENUM_COLOR 0xE9E9FF
|
||||
#define VERY_PALE_LAG_INPUT_COLOR1 0xE5E5F7
|
||||
#define VERY_PALE_LAG_INPUT_COLOR2 0xE0E0F1
|
||||
|
||||
#define CUR_FRAMENUM_COLOR 0xFCF1CE
|
||||
#define CUR_INPUT_COLOR1 0xF8EBB6
|
||||
|
|
|
@ -68,7 +68,7 @@ void PLAYBACK::init()
|
|||
}
|
||||
void PLAYBACK::reset()
|
||||
{
|
||||
autopause_at_the_end = false;
|
||||
must_autopause_at_the_end = true;
|
||||
must_find_current_marker = true;
|
||||
shown_marker = 0;
|
||||
lastCursor = currFrameCounter;
|
||||
|
@ -141,7 +141,7 @@ void PLAYBACK::update()
|
|||
// pause when seeking hits pause_frame
|
||||
if (pause_frame && currFrameCounter + 1 >= pause_frame)
|
||||
SeekingStop();
|
||||
else if (currFrameCounter >= GetLostPosition() && currFrameCounter >= currMovieData.getNumRecords() - 1 && autopause_at_the_end && taseditor_config.autopause_at_finish)
|
||||
else if (currFrameCounter >= GetLostPosition() && currFrameCounter >= currMovieData.getNumRecords() - 1 && must_autopause_at_the_end && taseditor_config.autopause_at_finish)
|
||||
// pause at the end of the movie
|
||||
PauseEmulation();
|
||||
|
||||
|
@ -183,18 +183,22 @@ void PLAYBACK::update()
|
|||
{
|
||||
// externally unpaused - show empty progressbar
|
||||
SetProgressbar(0, 1);
|
||||
if (currFrameCounter < currMovieData.getNumRecords()-1)
|
||||
autopause_at_the_end = true;
|
||||
else
|
||||
autopause_at_the_end = false;
|
||||
} else
|
||||
{
|
||||
// externally paused - progressbar should be full
|
||||
SetProgressbar(1, 1);
|
||||
autopause_at_the_end = false;
|
||||
}
|
||||
}
|
||||
|
||||
// prepare to stop at the end of the movie if user unpauses emulator
|
||||
if (emu_paused)
|
||||
{
|
||||
if (currFrameCounter < currMovieData.getNumRecords() - 1)
|
||||
must_autopause_at_the_end = true;
|
||||
else
|
||||
must_autopause_at_the_end = false;
|
||||
}
|
||||
|
||||
// update the Playback cursor
|
||||
if (currFrameCounter != lastCursor)
|
||||
{
|
||||
|
|
|
@ -61,7 +61,7 @@ private:
|
|||
int lost_position_frame;
|
||||
bool lost_position_is_stable; // for when Greenzone invalidates several times, but the end of current segment must remain the same
|
||||
|
||||
bool autopause_at_the_end;
|
||||
bool must_autopause_at_the_end;
|
||||
bool old_emu_paused, emu_paused;
|
||||
int old_pauseframe;
|
||||
bool old_show_pauseframe, show_pauseframe;
|
||||
|
|
|
@ -245,10 +245,10 @@ void POPUP_DISPLAY::RedrawScreenshotBitmap()
|
|||
void POPUP_DISPLAY::ChangeDescrText()
|
||||
{
|
||||
// retrieve info from the pointed bookmark's Markers
|
||||
int frame = bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.jump_frame;
|
||||
int marker_id = markers_manager.GetMarkerUp(bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.GetMarkers(), frame);
|
||||
int frame = bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.keyframe;
|
||||
int marker_id = markers_manager.GetMarkerUp(bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.markers, frame);
|
||||
char new_text[MAX_NOTE_LEN];
|
||||
strcpy(new_text, markers_manager.GetNote(bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.GetMarkers(), marker_id).c_str());
|
||||
strcpy(new_text, markers_manager.GetNote(bookmarks.bookmarks_array[bookmarks.item_under_mouse].snapshot.markers, marker_id).c_str());
|
||||
SetWindowText(marker_note_descr, new_text);
|
||||
}
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@ void RECORDER::InputChanged()
|
|||
// take previous values from current snapshot, new Input from current movie
|
||||
for (int i = 0; i < num_joys; ++i)
|
||||
{
|
||||
old_joy[i] = history.GetCurrentSnapshot().GetJoystickInfo(currFrameCounter, i);
|
||||
old_joy[i] = history.GetCurrentSnapshot().inputlog.GetJoystickInfo(currFrameCounter, i);
|
||||
if (!taseditor_config.pattern_recording || editor.autofire_patterns[old_current_pattern][pattern_offset])
|
||||
new_joy[i] = currMovieData.records[currFrameCounter].joysticks[i];
|
||||
else
|
||||
|
@ -296,7 +296,7 @@ void RECORDER::InputChanged()
|
|||
if (!changes_made)
|
||||
{
|
||||
// check if new commands were recorded
|
||||
if (currMovieData.records[currFrameCounter].commands != history.GetCurrentSnapshot().GetCommandsInfo(currFrameCounter))
|
||||
if (currMovieData.records[currFrameCounter].commands != history.GetCurrentSnapshot().inputlog.GetCommandsInfo(currFrameCounter))
|
||||
changes_made = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -491,7 +491,7 @@ void SELECTION::SetRegionSelectionPattern(int start, int end)
|
|||
for (int i = start; i <= end; ++i)
|
||||
{
|
||||
// skip lag frames
|
||||
if (taseditor_config.pattern_skips_lag && greenzone.GetLagHistoryAtFrame(i))
|
||||
if (taseditor_config.pattern_skips_lag && greenzone.laglog.GetLagInfoAtFrame(i))
|
||||
continue;
|
||||
if (editor.autofire_patterns[current_pattern][pattern_offset])
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,16 +1,6 @@
|
|||
// Specification file for Snapshot class
|
||||
|
||||
enum Input_types
|
||||
{
|
||||
INPUT_TYPE_1P,
|
||||
INPUT_TYPE_2P,
|
||||
INPUT_TYPE_FOURSCORE,
|
||||
|
||||
NUM_SUPPORTED_INPUT_TYPES
|
||||
};
|
||||
|
||||
#define BYTES_PER_JOYSTICK 1 // 1 byte per 1 joystick (8 buttons)
|
||||
#define HOTCHANGE_BYTES_PER_JOY 4 // 4 bytes per 8 buttons
|
||||
#include "inputlog.h"
|
||||
|
||||
#define SNAPSHOT_DESC_MAX_LENGTH 100
|
||||
|
||||
|
@ -22,70 +12,27 @@ public:
|
|||
|
||||
bool MarkersDifferFromCurrent();
|
||||
void copyToMarkers();
|
||||
MARKERS& GetMarkers();
|
||||
|
||||
void toMovie(MovieData& md, int start = 0, int end = -1);
|
||||
void compress_data();
|
||||
bool Get_already_compressed();
|
||||
|
||||
void save(EMUFILE *os);
|
||||
bool load(EMUFILE *is);
|
||||
bool skipLoad(EMUFILE *is);
|
||||
|
||||
void compress_data();
|
||||
bool Get_already_compressed();
|
||||
|
||||
bool checkDiff(SNAPSHOT& snap);
|
||||
void fillJoypadsDiff(SNAPSHOT& snap, int frame);
|
||||
|
||||
int findFirstChange(SNAPSHOT& snap, int start = 0, int end = -1);
|
||||
int findFirstChange(MovieData& md, int start = 0, int end = -1);
|
||||
|
||||
int GetJoystickInfo(int frame, int joy);
|
||||
int GetCommandsInfo(int frame);
|
||||
|
||||
void insertFrames(int at, int frames);
|
||||
void eraseFrame(int frame);
|
||||
|
||||
void copyHotChanges(SNAPSHOT* source_of_hotchanges, int limit_frame_of_source = -1);
|
||||
void inheritHotChanges(SNAPSHOT* source_of_hotchanges);
|
||||
void inheritHotChanges_DeleteSelection(SNAPSHOT* source_of_hotchanges);
|
||||
void inheritHotChanges_InsertSelection(SNAPSHOT* source_of_hotchanges);
|
||||
void inheritHotChanges_DeleteNum(SNAPSHOT* source_of_hotchanges, int start, int frames, bool fade_old);
|
||||
void inheritHotChanges_InsertNum(SNAPSHOT* source_of_hotchanges, int start, int frames, bool fade_old);
|
||||
void inheritHotChanges_PasteInsert(SNAPSHOT* source_of_hotchanges, SelectionFrames& inserted_set);
|
||||
void fillHotChanges(SNAPSHOT& snap, int start = 0, int end = -1);
|
||||
|
||||
void SetMaxHotChange_Bits(int frame, int joypad, uint8 joy_bits);
|
||||
void SetMaxHotChange(int frame, int absolute_button);
|
||||
|
||||
void FadeHotChanges(int start_byte = 0, int end_byte = -1);
|
||||
|
||||
int GetHotChangeInfo(int frame, int absolute_button);
|
||||
|
||||
// saved data
|
||||
int size; // in frames
|
||||
int input_type; // theoretically TAS Editor can support any other Input types
|
||||
int jump_frame; // for jumping when making undo
|
||||
INPUTLOG inputlog;
|
||||
LAGLOG laglog;
|
||||
MARKERS markers;
|
||||
int keyframe; // for jumping when making undo
|
||||
int start_frame; // for consecutive Draws
|
||||
int end_frame; // for consecutive Draws
|
||||
int consecutive_tag; // for consecutive Recordings and Draws
|
||||
uint32 rec_joypad_diff_bits; // for consecutive Recordings
|
||||
int mod_type;
|
||||
char description[SNAPSHOT_DESC_MAX_LENGTH];
|
||||
bool has_hot_changes;
|
||||
|
||||
// not saved data
|
||||
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> commands; // Format: commands-for-frame0, commands-for-frame1, ...
|
||||
std::vector<uint8> hot_changes; // Format: buttons01joy0-for-frame0, buttons23joy0-for-frame0, buttons45joy0-for-frame0, buttons67joy0-for-frame0, buttons01joy1-for-frame0, ...
|
||||
|
||||
private:
|
||||
|
||||
// also saved data
|
||||
MARKERS my_markers;
|
||||
std::vector<uint8> joysticks_compressed;
|
||||
std::vector<uint8> commands_compressed;
|
||||
std::vector<uint8> hot_changes_compressed;
|
||||
|
||||
bool already_compressed; // to compress only once
|
||||
};
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ TASEDITOR_CONFIG::TASEDITOR_CONFIG()
|
|||
view_branches_tree = false;
|
||||
branch_scr_hud = true;
|
||||
restore_position = false;
|
||||
adjust_input_due_to_lag = false;
|
||||
adjust_input_due_to_lag = true;
|
||||
greenzone_capacity = GREENZONE_CAPACITY_DEFAULT;
|
||||
undo_levels = UNDO_LEVELS_DEFAULT;
|
||||
autosave_period = AUTOSAVE_PERIOD_DEFAULT;
|
||||
|
|
|
@ -75,22 +75,22 @@ void TASEDITOR_LUA::InsertDelete_rows_to_Snaphot(SNAPSHOT& snapshot)
|
|||
// apply changes to given snapshot (only insertion/deletion)
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
if (pending_changes[i].frame >= snapshot.size)
|
||||
if (pending_changes[i].frame >= snapshot.inputlog.size)
|
||||
// expand snapshot to fit the frame
|
||||
snapshot.insertFrames(-1, 1 + pending_changes[i].frame - snapshot.size);
|
||||
snapshot.inputlog.insertFrames(-1, 1 + pending_changes[i].frame - snapshot.inputlog.size);
|
||||
switch (pending_changes[i].type)
|
||||
{
|
||||
case LUA_CHANGE_TYPE_INSERTFRAMES:
|
||||
{
|
||||
snapshot.insertFrames(pending_changes[i].frame, pending_changes[i].data);
|
||||
snapshot.inputlog.insertFrames(pending_changes[i].frame, pending_changes[i].data);
|
||||
break;
|
||||
}
|
||||
case LUA_CHANGE_TYPE_DELETEFRAMES:
|
||||
{
|
||||
for (int t = pending_changes[i].data; t > 0; t--)
|
||||
{
|
||||
if (pending_changes[i].frame < snapshot.size)
|
||||
snapshot.eraseFrame(pending_changes[i].frame);
|
||||
if (pending_changes[i].frame < snapshot.inputlog.size)
|
||||
snapshot.inputlog.eraseFrame(pending_changes[i].frame);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../common.h"
|
||||
#include "taseditor_config.h"
|
||||
#include "taseditor_window.h"
|
||||
#include "greenzone.h"
|
||||
#include "selection.h"
|
||||
#include "markers_manager.h"
|
||||
#include "snapshot.h"
|
||||
|
@ -13,7 +14,6 @@
|
|||
#include "history.h"
|
||||
#include "playback.h"
|
||||
#include "recorder.h"
|
||||
#include "greenzone.h"
|
||||
#include "piano_roll.h"
|
||||
#include "taseditor_lua.h"
|
||||
#include "splicer.h"
|
||||
|
@ -29,7 +29,7 @@
|
|||
#define PIANO_ROLL_SAVED 16
|
||||
#define SELECTION_SAVED 32
|
||||
|
||||
#define PROJECT_FILE_CURRENT_VERSION 1
|
||||
#define PROJECT_FILE_CURRENT_VERSION 2
|
||||
|
||||
class TASEDITOR_PROJECT
|
||||
{
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#ifdef WIN32
|
||||
#include "drivers/win/common.h"
|
||||
#include "drivers/win/taseditor/selection.h"
|
||||
#include "drivers/win/taseditor/laglog.h"
|
||||
#include "drivers/win/taseditor/markers.h"
|
||||
#include "drivers/win/taseditor/snapshot.h"
|
||||
#include "drivers/win/taseditor/taseditor_lua.h"
|
||||
|
|
|
@ -427,6 +427,8 @@
|
|||
<ClCompile Include="..\src\drivers\win\taseditor\editor.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\taseditor\greenzone.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\taseditor\history.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\taseditor\inputlog.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\taseditor\laglog.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\taseditor\markers.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\taseditor\markers_manager.cpp" />
|
||||
<ClCompile Include="..\src\drivers\win\taseditor\piano_roll.cpp" />
|
||||
|
@ -755,6 +757,8 @@
|
|||
<ClInclude Include="..\src\drivers\win\taseditor\editor.h" />
|
||||
<ClInclude Include="..\src\drivers\win\taseditor\greenzone.h" />
|
||||
<ClInclude Include="..\src\drivers\win\taseditor\history.h" />
|
||||
<ClInclude Include="..\src\drivers\win\taseditor\inputlog.h" />
|
||||
<ClInclude Include="..\src\drivers\win\taseditor\laglog.h" />
|
||||
<ClInclude Include="..\src\drivers\win\taseditor\markers.h" />
|
||||
<ClInclude Include="..\src\drivers\win\taseditor\markers_manager.h" />
|
||||
<ClInclude Include="..\src\drivers\win\taseditor\piano_roll.h" />
|
||||
|
|
|
@ -964,6 +964,12 @@
|
|||
<ClCompile Include="..\src\boards\116.cpp">
|
||||
<Filter>boards</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\drivers\win\taseditor\inputlog.cpp">
|
||||
<Filter>drivers\win\taseditor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\drivers\win\taseditor\laglog.cpp">
|
||||
<Filter>drivers\win\taseditor</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\cart.h">
|
||||
|
@ -1459,6 +1465,12 @@
|
|||
<ClInclude Include="..\src\drivers\win\taseditor\popup_display.h">
|
||||
<Filter>drivers\win\taseditor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\drivers\win\taseditor\inputlog.h">
|
||||
<Filter>drivers\win\taseditor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\drivers\win\taseditor\laglog.h">
|
||||
<Filter>drivers\win\taseditor</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\src\drivers\win\res.rc">
|
||||
|
|
Loading…
Reference in New Issue