Taseditor: gradual History Log autocompression when idle

This commit is contained in:
ansstuff 2012-04-16 20:09:16 +00:00
parent d188a2def2
commit 1e2d18b747
7 changed files with 98 additions and 20 deletions

View File

@ -16,6 +16,7 @@ History - History of movie modifications
* 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"
* regularly (when emulator is paused) searches for uncompressed items in the History Log and compresses first found item
* implements the working of History List: creating, redrawing, clicks, auto-scrolling
* stores resources: save id, ids and names of all possible types of modification, timings of "undo pointer"
------------------------------------------------------------------------------------ */
@ -121,6 +122,8 @@ void HISTORY::init()
lvc.cx = 500;
lvc.fmt = LVCFMT_LEFT;
ListView_InsertColumn(hwndHistoryList, 0, &lvc);
// shedule first autocompression
next_autocompress_time = clock() + TIME_BETWEEN_AUTOCOMPRESSIONS;
}
void HISTORY::free()
{
@ -169,6 +172,30 @@ void HISTORY::update()
}
if (old_show_undo_hint != show_undo_hint)
piano_roll.RedrawRow(undo_hint_pos); // not changing Bookmarks List
// when cpu is idle, compress items from time to time
if (clock() > next_autocompress_time)
{
if (FCEUI_EmulationPaused())
{
// search for first occurence of an item with snapshot that is not compressed yet
int real_pos;
for (int i = history_total_items - 1; i >= 0; i--)
{
real_pos = (history_start_pos + i) % history_size;
if (!snapshots[real_pos].Get_already_compressed())
{
snapshots[real_pos].compress_data();
break;
} else if (backup_bookmarks[real_pos].not_empty && backup_bookmarks[real_pos].snapshot.Get_already_compressed())
{
backup_bookmarks[real_pos].snapshot.compress_data();
break;
}
}
}
next_autocompress_time = clock() + TIME_BETWEEN_AUTOCOMPRESSIONS;
}
}
void HISTORY::HistorySizeChanged()
@ -911,7 +938,11 @@ void HISTORY::save(EMUFILE *os, bool really_save)
snapshots[real_pos].save(os);
backup_bookmarks[real_pos].save(os);
os->fwrite(&backup_current_branch[real_pos], 1);
if (i / SAVING_HISTORY_PROGRESSBAR_UPDATE_RATE > last_tick)
{
playback.SetProgressbar(i, history_total_items);
last_tick = i / PROGRESSBAR_UPDATE_RATE;
}
}
} else
{

View File

@ -2,6 +2,9 @@
#define UNDO_HINT_TIME 200
#define SAVING_HISTORY_PROGRESSBAR_UPDATE_RATE 10
#define TIME_BETWEEN_AUTOCOMPRESSIONS 500 // in milliseconds
enum MOD_TYPES
{
MODTYPE_INIT,
@ -132,18 +135,21 @@ private:
void AddItemToHistory(SNAPSHOT &snap, int cur_branch = 0);
void AddItemToHistory(SNAPSHOT &snap, int cur_branch, BOOKMARK &bookm);
// saved variables
std::vector<SNAPSHOT> snapshots;
std::vector<BOOKMARK> backup_bookmarks;
std::vector<int8> backup_current_branch;
int history_cursor_pos;
int history_start_pos;
int history_total_items;
// not saved variables
int history_start_pos;
int history_size;
int undo_hint_pos, old_undo_hint_pos;
int undo_hint_time;
bool old_show_undo_hint, show_undo_hint;
int next_autocompress_time;
};

View File

@ -10,6 +10,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
Markers - Snapshot of Markers state
* stores the data about Markers state: array of distributing Markers among movie frames, and array of Notes
* implements compression and decompression of stored data
* saves and loads the data from a project file. On error: sends warning to caller
* stores resources: max length of a Note
------------------------------------------------------------------------------------ */
@ -20,20 +21,20 @@ Markers - Snapshot of Markers state
MARKERS::MARKERS()
{
already_compressed = false;
}
void MARKERS::save(EMUFILE *os)
{
// write size
int size = markers_array.size();
int len;
write32le(size, os);
// compress and write array
int len = markers_array.size() * sizeof(int);
uLongf comprlen = (len>>9)+12 + len;
std::vector<uint8> cbuf(comprlen);
compress(&cbuf[0], &comprlen, (uint8*)&markers_array[0], len);
write32le(comprlen, os);
os->fwrite(&cbuf[0], comprlen);
// write array
if (!already_compressed)
compress_data();
write32le(markers_array_compressed.size(), os);
os->fwrite(&markers_array_compressed[0], markers_array_compressed.size());
// write notes
size = notes.size();
write32le(size, os);
@ -53,13 +54,14 @@ bool MARKERS::load(EMUFILE *is)
{
markers_array.resize(size);
// read and uncompress array
already_compressed = true;
int comprlen, len;
uLongf destlen = size * sizeof(int);
if (!read32le(&comprlen, is)) return true;
if (comprlen <= 0) return true;
std::vector<uint8> cbuf(comprlen);
if (is->fread(&cbuf[0], comprlen) != comprlen) return true;
int e = uncompress((uint8*)&markers_array[0], &destlen, &cbuf[0], comprlen);
markers_array_compressed.resize(comprlen);
if (is->fread(&markers_array_compressed[0], comprlen) != comprlen) return true;
int e = uncompress((uint8*)&markers_array[0], &destlen, &markers_array_compressed[0], comprlen);
if (e != Z_OK && e != Z_BUF_ERROR) return true;
// read notes
if (read32le(&size, is) && size >= 0)
@ -101,3 +103,22 @@ bool MARKERS::skipLoad(EMUFILE *is)
}
return true;
}
void MARKERS::compress_data()
{
int len = markers_array.size() * sizeof(int);
uLongf comprlen = (len>>9)+12 + len;
markers_array_compressed.resize(comprlen);
compress(&markers_array_compressed[0], &comprlen, (uint8*)&markers_array[0], len);
markers_array_compressed.resize(comprlen);
already_compressed = true;
}
bool MARKERS::Get_already_compressed()
{
return already_compressed;
}
void MARKERS::Set_already_compressed(bool value)
{
already_compressed = value;
}

View File

@ -11,9 +11,18 @@ public:
bool load(EMUFILE *is);
bool skipLoad(EMUFILE *is);
std::vector<int> markers_array; // Format: 0th = marker num (id) for frame 0, 1st = marker num for frame 1, ...
void compress_data();
bool Get_already_compressed();
void Set_already_compressed(bool value);
// saved data
std::vector<std::string> notes; // Format: 0th - note for intro (Marker 0), 1st - note for Marker1, 2nd - note for Marker2, ...
// not saved data
std::vector<int> markers_array; // Format: 0th = marker num (id) for frame 0, 1st = marker num for frame 1, ...
private:
// also saved data
std::vector<uint8> markers_array_compressed;
bool already_compressed; // to compress only once
};

View File

@ -72,6 +72,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 it has changed, probably
markers.save(os);
} else
{
@ -291,6 +292,7 @@ void MARKERS_MANAGER::MakeCopyTo(MARKERS& destination)
{
destination.markers_array = markers.markers_array;
destination.notes = markers.notes;
destination.Set_already_compressed(false);
}
void MARKERS_MANAGER::RestoreFromCopy(MARKERS& source, int until_frame)
{

View File

@ -181,6 +181,13 @@ void SNAPSHOT::compress_data()
}
// don't recompress anymore
already_compressed = true;
// also see if we can compress my_markers
if (!my_markers.Get_already_compressed())
my_markers.compress_data();
}
bool SNAPSHOT::Get_already_compressed()
{
return already_compressed;
}
void SNAPSHOT::save(EMUFILE *os)

View File

@ -30,6 +30,9 @@ public:
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);
@ -60,22 +63,21 @@ public:
// saved data
int size; // in frames
int input_type; // theoretically TAS Editor can support any other input types
std::vector<uint8> joysticks; // Format: joy0-for-frame0, joy1-for-frame0, joy2-for-frame0, joy3-for-frame0, joy0-for-frame1, joy1-for-frame1, ...
std::vector<uint8> 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, ...
int jump_frame; // 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:
void compress_data();
// also saved data
MARKERS my_markers;