Back movie data off movie file structure

This commit is contained in:
Ilari Liusvaara 2014-02-01 17:35:22 +02:00
parent d9b70e893d
commit ceb35eb72c
14 changed files with 462 additions and 142 deletions

View file

@ -223,6 +223,6 @@ private:
void save(zip::writer& w) throw(std::bad_alloc, std::runtime_error);
};
void emerg_save_movie(const moviefile& mv, const controller_frame_vector& v);
void emerg_save_movie(const moviefile& mv);
#endif

View file

@ -18,6 +18,7 @@
#include <set>
#include "json.hpp"
#include "binarystream.hpp"
#include "integer-pool.hpp"
/**
* Memory to allocate for controller frame.
@ -1212,15 +1213,45 @@ public:
void notify_sync_change(short polarity) {
uint64_t old_frame_count = real_frame_count;
real_frame_count = real_frame_count + polarity;
if(on_framecount_change && !freeze_count) on_framecount_change(*this, old_frame_count);
if(!freeze_count) call_framecount_notification(old_frame_count);
}
/**
* Set where to deliver frame count change notifications to.
*
* Parameter cb: Callback to register.
* Returns: Handle for callback.
*/
void set_framecount_notification(std::function<void(controller_frame_vector& src, uint64_t old)> cb)
uint64_t set_framecount_notification(std::function<void(controller_frame_vector& src, uint64_t old)> cb)
{
on_framecount_change = cb;
integer_pool::holder h(cb_handles);
on_framecount_change[h()] = cb;
return h.commit();
}
/**
* Clear framecount change notification.
*
* Parameter handle: Handle to clear.
*/
void clear_framecount_notification(uint64_t handle)
{
on_framecount_change.erase(handle);
cb_handles(handle);
}
/**
* Call framecount change notification.
*/
void call_framecount_notification(uint64_t oldcount)
{
for(auto& i : on_framecount_change)
try { i.second(*this, oldcount); } catch(...) {}
}
/**
* Swap frame data.
*
* Only the frame data is swapped, not the notifications.
*/
void swap_data(controller_frame_vector& v) throw();
/**
* Freeze framecount notifications.
*/
@ -1237,8 +1268,7 @@ public:
{
frozen.freeze_count--;
if(frozen.freeze_count == 0)
if(frozen.on_framecount_change)
frozen.on_framecount_change(frozen, frozen.frame_count_at_freeze);
frozen.call_framecount_notification(frozen.frame_count_at_freeze);
}
private:
notify_freeze(const notify_freeze&);
@ -1263,7 +1293,8 @@ private:
uint64_t real_frame_count;
uint64_t frame_count_at_freeze;
size_t freeze_count;
std::function<void(controller_frame_vector& src, uint64_t old)> on_framecount_change;
std::map<uint64_t, std::function<void(controller_frame_vector& src, uint64_t old)>> on_framecount_change;
integer_pool cb_handles;
size_t walk_helper(size_t frame, bool sflag) throw();
void clear_cache()
{

View file

@ -0,0 +1,81 @@
#ifndef _library__integer_pool__hpp__included__
#define _library__integer_pool__hpp__included__
#include <cstdint>
#include <vector>
class integer_pool
{
public:
/**
* Create a new pool
*/
integer_pool() throw();
/**
* Draw a number from the pool.
*
* Returns: The number drawn.
* Throws std::bad_alloc: Not enough memory.
*/
uint64_t operator()() throw(std::bad_alloc);
/**
* Return a number into the pool.
*
* Parameter num: The number to return.
*/
void operator()(uint64_t num) throw();
/**
* Temporarily hold an integer.
*/
class holder
{
public:
/**
* Allocate an integer.
*/
holder(integer_pool& _pool)
: pool(_pool)
{
i = pool();
own = true;
}
/**
* Release an integer.
*/
~holder()
{
if(own) pool(i);
}
/**
* Grab the integer without transferring ownership.
*
* Returns: The integer.
*/
uint64_t operator()()
{
return i;
}
/**
* Transfer the ownership.
*
* Returns: The integer.
*/
uint64_t commit()
{
own = false;
return i;
}
private:
holder(const holder&);
holder& operator=(const holder&);
integer_pool& pool;
bool own;
uint64_t i;
};
private:
std::vector<uint8_t> _bits;
uint8_t _bits2;
uint8_t* bits;
};
#endif

View file

@ -19,6 +19,11 @@ public:
*/
movie() throw(std::bad_alloc);
/**
* Dtor.
*/
~movie();
/**
* Is the movie in readonly mode?
*
@ -71,7 +76,7 @@ public:
*
* returns: The number of frames.
*/
uint64_t get_frame_count() throw() { movie_data.count_frames(); }
uint64_t get_frame_count() throw() { movie_data->count_frames(); }
/**
* Get number of current frame in movie
@ -151,14 +156,6 @@ public:
void load(const std::string& rerecs, const std::string& project_id, controller_frame_vector& input)
throw(std::bad_alloc, std::runtime_error);
/**
* Saves the movie data.
*
* returns: The movie data.
* throws std::bad_alloc: Not enough memory.
*/
controller_frame_vector save() throw(std::bad_alloc);
/**
* This method serializes the state of movie code.
*
@ -241,10 +238,6 @@ public:
* Set the poll flag handler.
*/
void set_pflag_handler(poll_flag* handler);
/**
* Get the internal controller frame vector.
*/
controller_frame_vector& get_frame_vector() throw() { return movie_data; }
/**
* Flush caches.
*/
@ -282,8 +275,18 @@ public:
*/
bool compatible(controller_frame_vector& with)
{
return movie_data.compatible(with, current_frame, pollcounters.rawdata());
return movie_data->compatible(with, current_frame, pollcounters.rawdata());
}
/**
* Set external movie data.
*
* Parameter data: New movie data.
*/
void set_movie_data(controller_frame_vector* data);
/**
* Copy ctor.
*/
movie(const movie& mov);
private:
//Sequence number.
uint64_t seqno;
@ -298,7 +301,7 @@ private:
//Project ID.
std::string _project_id;
//The actual controller data.
controller_frame_vector movie_data;
controller_frame_vector* movie_data;
//Current frame + 1 (0 before next_frame() has been called.
uint64_t current_frame;
//First subframe in current frame (movie_data.size() if no subframes have been stored).
@ -312,6 +315,8 @@ private:
//Cached subframes.
uint64_t cached_frame;
uint64_t cached_subframe;
//Handle for notifications.
uint64_t movie_data_nh;
//Count present subframes in frame starting from first_subframe (returns 0 if out of movie).
uint32_t count_changes(uint64_t first_subframe) throw();
};

View file

@ -151,7 +151,7 @@ namespace
void fatal_signal_handler(int sig)
{
write(2, "Caught fatal signal!\n", 21);
emerg_save_movie(our_movie, movb.get_movie().get_frame_vector());
emerg_save_movie(our_movie);
signal(sig, SIG_DFL);
raise(sig);
}
@ -159,14 +159,14 @@ namespace
void terminate_handler()
{
write(2, "Terminating abnormally!\n", 24);
emerg_save_movie(our_movie, movb.get_movie().get_frame_vector());
emerg_save_movie(our_movie);
std::cerr << "Exiting on fatal error" << std::endl;
exit(1);
}
command::fnptr<const std::string&> test4(lsnes_cmd, "panicsave-movie", "", "",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
emerg_save_movie(our_movie, movb.get_movie().get_frame_vector());
emerg_save_movie(our_movie);
});
//% is intentionally missing.
@ -326,7 +326,7 @@ std::string get_config_path() throw(std::bad_alloc)
void OOM_panic()
{
emerg_save_movie(our_movie, movb.get_movie().get_frame_vector());
emerg_save_movie(our_movie);
messages << "FATAL: Out of memory!" << std::endl;
fatal_error();
}

View file

@ -222,7 +222,6 @@ void do_save_state(const std::string& filename, int binary) throw(std::bad_alloc
get_framebuffer().save(our_movie.screenshot);
movb.get_movie().save_state(our_movie.projectid, our_movie.save_frame, our_movie.lagged_frames,
our_movie.pollcounters);
our_movie.input = movb.get_movie().save();
our_movie.poll_flag = our_rom.rtype->get_pflag();
auto prj = project_get();
if(prj) {
@ -264,7 +263,6 @@ void do_save_movie(const std::string& filename, int binary) throw(std::bad_alloc
try {
uint64_t origtime = get_utime();
our_movie.is_savestate = false;
our_movie.input = movb.get_movie().save();
auto prj = project_get();
if(prj) {
our_movie.gamename = prj->gamename;
@ -312,9 +310,11 @@ void reinitialize_movie(core_sysregion* sysreg)
mov.lazy_project_create = true;
our_movie = mov;
movie newmovie;
newmovie.set_movie_data(&mov.input);
newmovie.load("0", mov.projectid, mov.input);
newmovie.readonly_mode(false);
movb.get_movie() = newmovie;
movb.get_movie().set_movie_data(&our_movie.input);
}
void do_load_beginning(bool reload) throw(std::bad_alloc, std::runtime_error)
@ -459,10 +459,13 @@ void do_load_state(struct moviefile& _movie, int lmode)
lmode = LOAD_STATE_PRESERVE;
movie newmovie;
if(lmode == LOAD_STATE_PRESERVE)
if(lmode == LOAD_STATE_PRESERVE) {
newmovie = movb.get_movie();
else
newmovie.set_movie_data(&our_movie.input);
} else {
newmovie.set_movie_data(&_movie.input);
newmovie.load(_movie.rerecords, _movie.projectid, _movie.input);
}
if(will_load_state)
newmovie.restore_state(_movie.save_frame, _movie.lagged_frames, _movie.pollcounters, true,
@ -512,9 +515,10 @@ void do_load_state(struct moviefile& _movie, int lmode)
}
//Okay, copy the movie data.
if(lmode != LOAD_STATE_PRESERVE)
if(lmode != LOAD_STATE_PRESERVE) {
our_movie = _movie;
else {
movb.get_movie().set_movie_data(&our_movie.input);
} else {
//Some fields MUST be taken from movie or one gets desyncs.
our_movie.is_savestate = _movie.is_savestate;
our_movie.rtc_second = _movie.rtc_second;
@ -533,6 +537,7 @@ void do_load_state(struct moviefile& _movie, int lmode)
if(lmode != LOAD_STATE_PRESERVE)
lua_callback_movie_lost("load");
movb.get_movie() = newmovie;
movb.get_movie().set_movie_data(&our_movie.input);
//Activate RW mode if needed.
if(lmode == LOAD_STATE_RW)
movb.get_movie().readonly_mode(false);

View file

@ -993,9 +993,10 @@ namespace
}
}
void emerg_save_movie(const moviefile& mv, const controller_frame_vector& v)
void emerg_save_movie(const moviefile& mv)
{
//Whee, assume state of the emulator is totally busted.
const controller_frame_vector& v = mv.input;
if(!mv.gametype)
return; //No valid movie. Trying to save would segfault.
char header[] = {'l', 's', 'm', 'v', '\x1a'};

View file

@ -8,7 +8,7 @@ __all__.files: $(CORES_FILES)
lua ../genfilelist.lua $^ >$@
cat $(CORES_FLAGS) >$(ALLFLAGS)
make-ports.exe: make-ports.cpp ../library/json.cpp ../library/utf8.cpp ../library/string.cpp ../library/controller-parse.cpp ../library/controller-data.cpp ../library/sha256.cpp ../library/assembler.cpp ../library/hex.cpp ../library/eatarg.cpp ../library/int24.cpp ../library/binarystream.cpp
make-ports.exe: make-ports.cpp ../library/json.cpp ../library/utf8.cpp ../library/string.cpp ../library/controller-parse.cpp ../library/controller-data.cpp ../library/sha256.cpp ../library/assembler.cpp ../library/hex.cpp ../library/eatarg.cpp ../library/int24.cpp ../library/binarystream.cpp ../library/integer-pool.cpp
$(HOSTCC) -g -std=gnu++0x -I../../include/library -o $@ $^ -lboost_regex$(HOST_BOOST_POSTFIX) -lboost_system$(HOST_BOOST_POSTFIX)
bsnes-legacy/$(ALLFILES): forcelook make-ports.exe

View file

@ -514,7 +514,7 @@ size_t controller_frame_vector::recount_frames() throw()
}
real_frame_count = ret;
if(on_framecount_change) on_framecount_change(*this, old_frame_count);
call_framecount_notification(old_frame_count);
return ret;
}
@ -528,7 +528,7 @@ void controller_frame_vector::clear(const port_type_set& p) throw(std::runtime_e
clear_cache();
pages.clear();
real_frame_count = 0;
if(on_framecount_change) on_framecount_change(*this, old_frame_count);
call_framecount_notification(old_frame_count);
}
controller_frame_vector::~controller_frame_vector() throw()
@ -601,7 +601,7 @@ controller_frame_vector& controller_frame_vector::operator=(const controller_fra
const page& pg2 = v.pages.find(i)->second;
pg = pg2;
}
if(on_framecount_change) on_framecount_change(*this, old_frame_count);
call_framecount_notification(old_frame_count);
return *this;
}
@ -625,7 +625,7 @@ void controller_frame_vector::resize(size_t newsize) throw(std::bad_alloc)
memset(pages[pages_needed - 1].content + offset, 0, CONTROLLER_PAGE_SIZE - offset);
}
frames = newsize;
if(on_framecount_change) on_framecount_change(*this, old_frame_count);
call_framecount_notification(old_frame_count);
} else if(newsize > frames) {
//Enlarge movie.
size_t current_pages = (frames + frames_per_page - 1) / frames_per_page;
@ -643,7 +643,7 @@ void controller_frame_vector::resize(size_t newsize) throw(std::bad_alloc)
}
frames = newsize;
//This can use real_frame_count, because the real frame count won't change.
if(on_framecount_change) on_framecount_change(*this, real_frame_count);
call_framecount_notification(real_frame_count);
}
}
@ -755,6 +755,24 @@ void controller_frame_vector::load_binary(binarystream::input& stream) throw(std
recount_frames();
}
void controller_frame_vector::swap_data(controller_frame_vector& v) throw()
{
uint64_t toldsize = real_frame_count;
uint64_t voldsize = v.real_frame_count;
std::swap(pages, v.pages);
std::swap(frames_per_page, v.frames_per_page);
std::swap(frame_size, v.frame_size);
std::swap(frames, v.frames);
std::swap(types, v.types);
std::swap(cache_page_num, v.cache_page_num);
std::swap(cache_page, v.cache_page);
std::swap(real_frame_count, v.real_frame_count);
if(!freeze_count)
call_framecount_notification(toldsize);
if(!v.freeze_count)
v.call_framecount_notification(voldsize);
}
controller_frame::controller_frame() throw()
{
memset(memory, 0, sizeof(memory));

View file

@ -0,0 +1,151 @@
#include "integer-pool.hpp"
#include <iostream>
#include <cassert>
#include <cstring>
namespace
{
const unsigned special_level = 21;
uint64_t level_base[] = {
0ULL,
1ULL,
9ULL,
73ULL,
585ULL,
4681ULL,
37449ULL,
299593ULL,
2396745ULL,
19173961ULL,
153391689ULL,
1227133513ULL,
9817068105ULL,
78536544841ULL,
628292358729ULL,
5026338869833ULL,
40210710958665ULL,
321685687669321ULL,
2573485501354569ULL,
20587884010836553ULL,
164703072086692425ULL,
1317624576693539401ULL,
3623467585907233353ULL, //Special: Fits 2^64 bits.
};
uint64_t level_size[] = {
1ULL,
8ULL,
64ULL,
512ULL,
4096ULL,
32768ULL,
262144ULL,
2097152ULL,
16777216ULL,
134217728ULL,
1073741824ULL,
8589934592ULL,
68719476736ULL,
549755813888ULL,
4398046511104ULL,
35184372088832ULL,
281474976710656ULL,
2251799813685248ULL,
18014398509481984ULL,
144115188075855872ULL,
1152921504606846976ULL,
2305843009213693952ULL, //Special: 2^64 bits.
};
const unsigned levels = 22;
unsigned level_from_size(uint64_t size)
{
for(unsigned i = 0; i < levels; i++) {
if(size <= level_base[i + 1]) return i;
}
return levels;
}
uint64_t get_levelsize(unsigned n)
{
static uint64_t table[levels];
static bool init = false;
if(!init) {
uint64_t r = 1;
for(unsigned i = 0; i < levels; i++) {
table[i] = r;
r = 8 * r + 1;
}
init = true;
}
return table[n];
}
unsigned lsbz(uint8_t b)
{
return ((b & 1) ? ((b & 2) ? ((b & 4) ? ((b & 8) ? ((b & 16) ? ((b & 32) ? ((b & 64) ?
((b & 128) ? 8 : 7) : 6) : 5) : 4) : 3) : 2) : 1) : 0);
}
}
integer_pool::integer_pool() throw()
{
_bits2 = 0;
bits = &_bits2;
}
uint64_t integer_pool::operator()() throw(std::bad_alloc)
{
//If the first byte is 0xFF, we got to expand the array.
if(bits[0] == 0xFF) {
unsigned level = level_from_size(_bits.size()); //If bits.size() == 0, this correctly returns 0.
assert(level < special_level);
std::vector<uint8_t> newbits;
newbits.resize(level_base[level + 2]);
memset(&newbits[0], 0, level_base[level + 2]);
for(unsigned i = 0; i <= level; i++)
memcpy(&newbits[level_base[i + 1]], &bits[level_base[i]], level_size[i]);
newbits[0] = 1;
std::swap(_bits, newbits);
bits = &_bits[0];
}
//Find a free byte.
unsigned level = level_from_size(_bits.size()); //If bits.size() == 0, this correctly returns 0.
uint64_t pathbits = 0;
for(unsigned i = 0; i < level; i++) {
uint64_t byte = level_base[i] + pathbits;
assert(bits[byte] < 255);
unsigned lsb = lsbz(bits[byte]);
pathbits = 8 * pathbits + lsb;
}
//Check if there are free integers in pool.
if(pathbits > 0x1FFFFFFFFFFFFFFFULL) throw std::bad_alloc();
//Reserve it, and propagate fullness downward if needed.
uint64_t byte = level_base[level] + pathbits;
assert(bits[byte] < 255);
unsigned lsb = lsbz(bits[byte]);
pathbits = 8 * pathbits + lsb;
uint64_t bit = pathbits;
bool carry = true;
for(unsigned i = level; i <= level; i--) {
if(carry) {
byte = level_base[i] + (pathbits >> 3);
bits[byte] |= (1 << (pathbits & 7));
carry = (bits[byte] == 255);
pathbits >>= 3;
} else
break;
}
return bit;
}
void integer_pool::operator()(uint64_t num) throw()
{
unsigned level = level_from_size(_bits.size()); //If bits.size() == 0, this correctly returns 0.
for(unsigned i = level; i <= level; i--) {
uint64_t byte = level_base[i] + (num >> 3);
bits[byte] &= ~(1 << (num & 7));
num >>= 3;
}
}

View file

@ -22,6 +22,12 @@ namespace
}
}
movie::~movie()
{
if(movie_data)
movie_data->clear_framecount_notification(movie_data_nh);
}
void movie::set_all_DRDY() throw()
{
pollcounters.set_all_DRDY();
@ -59,14 +65,14 @@ void movie::set_controls(controller_frame controls) throw()
uint32_t movie::count_changes(uint64_t first_subframe) throw()
{
return movie_data.subframe_count(first_subframe);
return movie_data->subframe_count(first_subframe);
}
controller_frame movie::get_controls() throw()
{
if(!readonly)
return current_controls;
controller_frame c = movie_data.blank_frame(false);
controller_frame c = movie_data->blank_frame(false);
//Before the beginning? Somebody screwed up (but return released / neutral anyway)...
if(current_frame == 0)
return c;
@ -74,10 +80,10 @@ controller_frame movie::get_controls() throw()
uint32_t changes = count_changes(current_frame_first_subframe);
if(!changes)
return c; //End of movie.
for(size_t i = 0; i < movie_data.get_types().indices(); i++) {
for(size_t i = 0; i < movie_data->get_types().indices(); i++) {
uint32_t polls = pollcounters.get_polls(i);
uint32_t index = (changes > polls) ? polls : changes - 1;
c.axis2(i, movie_data[current_frame_first_subframe + index].axis2(i));
c.axis2(i, (*movie_data)[current_frame_first_subframe + index].axis2(i));
}
return c;
}
@ -108,8 +114,8 @@ void movie::next_frame() throw(std::bad_alloc)
//debuglog << "Frame " << current_frame << " is lag" << std::endl << std::flush;
if(!readonly) {
//If in read-write mode, write a dummy record for the frame. Force sync flag.
//As index should be movie_data.size(), it is correct afterwards.
movie_data.append(current_controls.copy(true));
//As index should be movie_data->size(), it is correct afterwards.
movie_data->append(current_controls.copy(true));
}
}
@ -138,7 +144,7 @@ short movie::next_input(unsigned port, unsigned controller, unsigned ctrl) throw
if(readonly) {
//In readonly mode...
//If at the end of the movie, return released / neutral (but also record the poll)...
if(current_frame_first_subframe >= movie_data.size()) {
if(current_frame_first_subframe >= movie_data->size()) {
pollcounters.increment_polls(port, controller, ctrl);
return 0;
}
@ -149,7 +155,7 @@ short movie::next_input(unsigned port, unsigned controller, unsigned ctrl) throw
uint32_t changes = count_changes(current_frame_first_subframe);
uint32_t polls = pollcounters.get_polls(port, controller, ctrl);
uint32_t index = (changes > polls) ? polls : changes - 1;
int16_t data = movie_data[current_frame_first_subframe + index].axis3(port, controller, ctrl);
int16_t data = (*movie_data)[current_frame_first_subframe + index].axis3(port, controller, ctrl);
pollcounters.increment_polls(port, controller, ctrl);
return data;
} else {
@ -159,26 +165,26 @@ short movie::next_input(unsigned port, unsigned controller, unsigned ctrl) throw
if(current_frame == 0)
return 0;
//If at movie end, insert complete input with frame sync set (this is the first subframe).
if(current_frame_first_subframe >= movie_data.size()) {
movie_data.append(current_controls.copy(true));
//current_frame_first_subframe should be movie_data.size(), so it is right.
if(current_frame_first_subframe >= movie_data->size()) {
movie_data->append(current_controls.copy(true));
//current_frame_first_subframe should be movie_data->size(), so it is right.
pollcounters.increment_polls(port, controller, ctrl);
return movie_data[current_frame_first_subframe].axis3(port, controller, ctrl);
return (*movie_data)[current_frame_first_subframe].axis3(port, controller, ctrl);
}
short new_value = current_controls.axis3(port, controller, ctrl);
//Fortunately, we know this frame is the last one in movie_data.
uint32_t pollcounter = pollcounters.get_polls(port, controller, ctrl);
if(current_frame_first_subframe + pollcounter < movie_data.size()) {
if(current_frame_first_subframe + pollcounter < movie_data->size()) {
//The index is within existing size. Change the value and propagate to all subsequent
//subframes.
for(uint64_t i = current_frame_first_subframe + pollcounter; i < movie_data.size(); i++)
movie_data[i].axis3(port, controller, ctrl, new_value);
} else if(new_value != movie_data[movie_data.size() - 1].axis3(port, controller, ctrl)) {
for(uint64_t i = current_frame_first_subframe + pollcounter; i < movie_data->size(); i++)
(*movie_data)[i].axis3(port, controller, ctrl, new_value);
} else if(new_value != (*movie_data)[movie_data->size() - 1].axis3(port, controller, ctrl)) {
//The index is not within existing size and value does not match. We need to create a new
//subframes(s), copying the last subframe.
while(current_frame_first_subframe + pollcounter >= movie_data.size())
movie_data.append(movie_data[movie_data.size() - 1].copy(false));
movie_data[current_frame_first_subframe + pollcounter].axis3(port, controller, ctrl,
while(current_frame_first_subframe + pollcounter >= movie_data->size())
movie_data->append((*movie_data)[movie_data->size() - 1].copy(false));
(*movie_data)[current_frame_first_subframe + pollcounter].axis3(port, controller, ctrl,
new_value);
}
pollcounters.increment_polls(port, controller, ctrl);
@ -188,6 +194,7 @@ short movie::next_input(unsigned port, unsigned controller, unsigned ctrl) throw
movie::movie() throw(std::bad_alloc)
{
movie_data = NULL;
seqno = 0;
readonly = false;
rerecords = "0";
@ -197,17 +204,6 @@ movie::movie() throw(std::bad_alloc)
lag_frames = 0;
pflag_handler = NULL;
clear_caches();
movie_data.set_framecount_notification([this](controller_frame_vector& src, uint64_t old_frames) -> void {
//Recompute frame_first_subframe.
while(current_frame_first_subframe < movie_data.size() && current_frame > old_frames + 1) {
//OK, movie has been extended.
current_frame_first_subframe += count_changes(current_frame_first_subframe);
old_frames++;
}
//Nobody is this stupid, right?
current_frame_first_subframe = min(current_frame_first_subframe,
static_cast<uint64_t>(movie_data.size()));
});
}
void movie::load(const std::string& rerecs, const std::string& project_id, controller_frame_vector& input)
@ -224,16 +220,10 @@ void movie::load(const std::string& rerecs, const std::string& project_id, contr
current_frame_first_subframe = 0;
pollcounters = pollcounter_vector(input.get_types());
lag_frames = 0;
movie_data = input;
//This is to force internal type of current_controls to become correct.
current_controls = input.blank_frame(false);
}
controller_frame_vector movie::save() throw(std::bad_alloc)
{
return movie_data;
}
unsigned movie::next_poll_number()
{
return pollcounters.max_polls() + 1;
@ -248,16 +238,16 @@ void movie::readonly_mode(bool enable) throw(std::bad_alloc)
//Transitioning to readwrite mode, we have to adjust the length of the movie data.
if(current_frame == 0) {
//WTF... At before first frame. Blank the entiere movie.
movie_data.clear();
movie_data->clear();
return;
}
//Fun special case: Current frame is not in movie (current_frame_first_subframe >= movie_data.size()).
//In this case, we have to extend the movie data.
if(current_frame_first_subframe >= movie_data.size()) {
//Fun special case: Current frame is not in movie (current_frame_first_subframe >=
//movie_data->size()). In this case, we have to extend the movie data.
if(current_frame_first_subframe >= movie_data->size()) {
//Yes, this will insert one extra frame... But we will lose it later if it is not needed.
while(movie_data.count_frames() < current_frame)
movie_data.append(movie_data.blank_frame(true));
current_frame_first_subframe = movie_data.size() - 1;
while(movie_data->count_frames() < current_frame)
movie_data->append(movie_data->blank_frame(true));
current_frame_first_subframe = movie_data->size() - 1;
}
//We have to take the part up to furthest currently readable subframe. Also, we need to propagate
@ -268,14 +258,15 @@ void movie::readonly_mode(bool enable) throw(std::bad_alloc)
if(max_readable_subframes > next_frame_first_subframe)
max_readable_subframes = next_frame_first_subframe;
movie_data.resize(max_readable_subframes);
movie_data->resize(max_readable_subframes);
next_frame_first_subframe = max_readable_subframes;
//Propagate buttons. The only one that needs special handling is sync flag (index 0, tuple 0,0,0).
for(size_t i = 1; i < movie_data.get_types().indices(); i++) {
for(size_t i = 1; i < movie_data->get_types().indices(); i++) {
uint32_t polls = pollcounters.get_polls(i);
polls = polls ? polls : 1;
for(uint64_t j = current_frame_first_subframe + polls; j < next_frame_first_subframe; j++)
movie_data[j].axis2(i, movie_data[current_frame_first_subframe + polls - 1].axis2(i));
(*movie_data)[j].axis2(i, (*movie_data)[current_frame_first_subframe + polls - 1].
axis2(i));
}
}
}
@ -297,7 +288,7 @@ size_t movie::restore_state(uint64_t curframe, uint64_t lagframe, const std::vec
{
if(!pollcounters.check(pcounters))
throw std::runtime_error("Wrong number of poll counters");
if(old_movie && !movies_compatible(*old_movie, movie_data, curframe, &pcounters[0], old_projectid,
if(old_movie && !movies_compatible(*old_movie, *movie_data, curframe, &pcounters[0], old_projectid,
_project_id))
throw std::runtime_error("Save is not from this movie");
uint64_t tmp_firstsubframe = 0;
@ -342,11 +333,11 @@ controller_frame movie::read_subframe(uint64_t frame, uint64_t subframe) throw()
cached_subframe = p;
uint64_t max = count_changes(p);
if(!max) {
return movie_data.blank_frame(true);
return movie_data->blank_frame(true);
}
if(max <= subframe)
subframe = max - 1;
return movie_data[p + subframe];
return (*movie_data)[p + subframe];
}
void movie::reset_state() throw()
@ -371,7 +362,7 @@ void movie::fast_load(uint64_t& _frame, uint64_t& _ptr, uint64_t& _lagc, std::ve
{
readonly = true;
current_frame = _frame;
current_frame_first_subframe = (_ptr <= movie_data.size()) ? _ptr : movie_data.size();
current_frame_first_subframe = (_ptr <= movie_data->size()) ? _ptr : movie_data->size();
lag_frames = _lagc;
pollcounters.load_state(_counters);
readonly_mode(false);
@ -383,7 +374,6 @@ movie& movie::operator=(const movie& m)
readonly = m.readonly;
rerecords = m.rerecords;
_project_id = m._project_id;
movie_data = m.movie_data;
current_frame = m.current_frame;
current_frame_first_subframe = m.current_frame_first_subframe;
pollcounters = m.pollcounters;
@ -402,11 +392,11 @@ void movie::set_pflag_handler(poll_flag* handler)
int16_t movie::read_subframe_at_index(uint32_t subframe, unsigned port, unsigned controller, unsigned ctrl)
{
//Readwrite, Past the end of movie or before the beginning?
if(!readonly || current_frame_first_subframe >= movie_data.size() || current_frame == 0)
if(!readonly || current_frame_first_subframe >= movie_data->size() || current_frame == 0)
return 0;
uint32_t changes = count_changes(current_frame_first_subframe);
uint32_t index = (changes > subframe) ? subframe : changes - 1;
return movie_data[current_frame_first_subframe + index].axis3(port, controller, ctrl);
return (*movie_data)[current_frame_first_subframe + index].axis3(port, controller, ctrl);
}
void movie::write_subframe_at_index(uint32_t subframe, unsigned port, unsigned controller, unsigned ctrl,
@ -415,42 +405,81 @@ void movie::write_subframe_at_index(uint32_t subframe, unsigned port, unsigned c
if(!readonly || current_frame == 0)
return;
bool extended = false;
while(current_frame > movie_data.count_frames()) {
while(current_frame > movie_data->count_frames()) {
//Extend the movie by a blank frame.
extended = true;
movie_data.append(movie_data.blank_frame(true));
movie_data->append(movie_data->blank_frame(true));
}
if(extended) {
clear_caches();
current_frame_first_subframe = movie_data.size() - 1;
current_frame_first_subframe = movie_data->size() - 1;
}
if(current_frame < movie_data.count_frames()) {
if(current_frame < movie_data->count_frames()) {
//If we are not on the last frame, write is possible if it is not on extension.
uint32_t changes = count_changes(current_frame_first_subframe);
if(subframe < changes)
movie_data[current_frame_first_subframe + subframe].axis3(port, controller, ctrl, x);
(*movie_data)[current_frame_first_subframe + subframe].axis3(port, controller, ctrl, x);
} else {
//Writing to the last frame. If not on extension, handle like non-last frame.
//Note that if movie had to be extended, it was done before, resulting movie like in state with
//0 stored subframes.
uint32_t changes = count_changes(current_frame_first_subframe);
if(subframe < changes)
movie_data[current_frame_first_subframe + subframe].axis3(port, controller, ctrl, x);
(*movie_data)[current_frame_first_subframe + subframe].axis3(port, controller, ctrl, x);
else {
//If there is no frame at all, create one.
if(current_frame_first_subframe >= movie_data.size()) {
movie_data.append(movie_data.blank_frame(true));
if(current_frame_first_subframe >= movie_data->size()) {
movie_data->append(movie_data->blank_frame(true));
}
//Create needed subframes.
while(count_changes(current_frame_first_subframe) <= subframe)
movie_data.append(movie_data.blank_frame(false));
movie_data->append(movie_data->blank_frame(false));
//Write it.
movie_data[current_frame_first_subframe + subframe].axis3(port, controller, ctrl, x);
(*movie_data)[current_frame_first_subframe + subframe].axis3(port, controller, ctrl, x);
}
}
}
movie::poll_flag::~poll_flag()
{
}
movie::movie(const movie& mov)
{
seqno++;
readonly = mov.readonly;
latch_end = mov.latch_end;
rerecords = mov.rerecords;
_project_id = mov._project_id;
movie_data = NULL;
current_frame = mov.current_frame;
current_frame_first_subframe = mov.current_frame_first_subframe;
pollcounters = mov.pollcounters;
current_controls = mov.current_controls;
lag_frames = mov.lag_frames;
cached_frame = mov.cached_frame;
cached_subframe = mov.cached_subframe;
}
void movie::set_movie_data(controller_frame_vector* data)
{
uint64_t old_nh = movie_data_nh;
controller_frame_vector* old = movie_data;
if(data)
movie_data_nh = data->set_framecount_notification([this](controller_frame_vector& src,
uint64_t old_frames) {
//Recompute frame_first_subframe.
while(current_frame_first_subframe < movie_data->size() && current_frame > old_frames + 1) {
//OK, movie has been extended.
current_frame_first_subframe += count_changes(current_frame_first_subframe);
old_frames++;
}
//Nobody is this stupid, right?
current_frame_first_subframe = min(current_frame_first_subframe,
static_cast<uint64_t>(movie_data->size()));
});
movie_data = data;
clear_caches();
if(old)
old->clear_framecount_notification(old_nh);
}

View file

@ -114,14 +114,14 @@ namespace
movie& m = movb.get_movie();
if(!m.readonly_mode())
throw std::runtime_error("Not in read-only mode");
if(!allow_past_end && frame >= movb.get_movie().get_frame_vector().size())
if(!allow_past_end && frame >= our_movie.input.size())
throw std::runtime_error("Index out of movie");
int32_t pc = get_pc_for(port, controller, button, true);
if(pc < 0)
throw std::runtime_error("Invalid control to edit");
uint64_t firstframe = m.get_current_frame_first_subframe();
uint64_t minframe = firstframe + pc;
uint64_t msize = movb.get_movie().get_frame_vector().size();
uint64_t msize = our_movie.input.size();
if(minframe > msize || firstframe >= msize)
throw std::runtime_error("Can not edit finished movie");
if(frame < minframe)
@ -181,12 +181,12 @@ namespace
if(n >= v.size())
throw std::runtime_error("Requested frame outside movie");
//Checks if requested frame is from movie.
if(&v == &movb.get_movie().get_frame_vector())
if(&v == &our_movie.input)
check_can_edit(0, 0, 0, n);
v[n] = f->get_frame();
if(&v == &movb.get_movie().get_frame_vector()) {
if(&v == &our_movie.input) {
//This can't add frames, so no need to adjust the movie.
update_movie_state();
platform::notify_status();
@ -256,7 +256,7 @@ namespace
for(uint64_t i = 0; i < count; i++)
v.append(v.blank_frame(true));
}
if(&v == &movb.get_movie().get_frame_vector()) {
if(&v == &our_movie.input) {
update_movie_state();
platform::notify_status();
}
@ -271,13 +271,13 @@ namespace
P(f);
v.append(v.blank_frame(true));
if(&v == &movb.get_movie().get_frame_vector()) {
if(&v == &our_movie.input) {
update_movie_state();
platform::notify_status();
check_can_edit(0, 0, 0, v.size() - 1);
}
v[v.size() - 1] = f->get_frame();
if(&v == &movb.get_movie().get_frame_vector()) {
if(&v == &our_movie.input) {
if(!v[v.size() - 1].sync()) {
update_movie_state();
}
@ -295,10 +295,10 @@ namespace
if(n > v.size())
throw std::runtime_error("Requested truncate length longer than existing");
if(&v == &movb.get_movie().get_frame_vector())
if(&v == &our_movie.input)
check_can_edit(0, 0, 0, n);
v.resize(n);
if(&v == &movb.get_movie().get_frame_vector()) {
if(&v == &our_movie.input) {
update_movie_state();
platform::notify_status();
}
@ -319,11 +319,11 @@ namespace
P.expected("number or boolean");
movie& m = movb.get_movie();
if(&v == &movb.get_movie().get_frame_vector())
if(&v == &our_movie.input)
check_can_edit(port, controller, button, frame);
v[frame].axis3(port, controller, button, value);
if(&v == &movb.get_movie().get_frame_vector()) {
if(&v == &our_movie.input) {
update_movie_state();
platform::notify_status();
}
@ -348,7 +348,7 @@ namespace
throw std::runtime_error("Destination index out of movie");
movie& m = movb.get_movie();
if(&dstv == &movb.get_movie().get_frame_vector())
if(&dstv == &our_movie.input)
check_can_edit(0, 0, 0, dst, true);
{
@ -360,7 +360,7 @@ namespace
for(uint64_t i = backwards ? (count - 1) : 0; i < count; i = backwards ? (i - 1) : (i + 1))
dstv[dst + i] = srcv[src + i];
}
if(&dstv == &movb.get_movie().get_frame_vector()) {
if(&dstv == &our_movie.input) {
update_movie_state();
platform::notify_status();
}
@ -590,11 +590,11 @@ namespace
{
if(P.is_nil()) {
P.skip();
return movb.get_movie().get_frame_vector();
return our_movie.input;
} else if(P.is<lua_inputmovie>())
return *(P.arg<lua_inputmovie*>()->get_frame_vector());
else
return movb.get_movie().get_frame_vector();
return our_movie.input;
}
lua::_class<lua_inputmovie> class_inputmovie(lua_class_movie, "INPUTMOVIE", {}, {

View file

@ -794,7 +794,7 @@ namespace
uint64_t real_first_editable(frame_controls& fc, unsigned idx)
{
uint64_t cffs = movb.get_movie().get_current_frame_first_subframe();
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
pollcounter_vector& pv = movb.get_movie().get_pollcounters();
uint64_t vsize = fv.size();
uint32_t pc = fc.read_pollcount(pv, idx);
@ -817,7 +817,7 @@ namespace
uint64_t real_first_nextframe(frame_controls& fc)
{
uint64_t base = real_first_editable(fc, 0);
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t vsize = fv.size();
for(uint32_t i = 0;; i++)
if(base + i >= vsize || fv[base + i].sync())
@ -860,7 +860,7 @@ wxeditor_movie::_moviepanel::_moviepanel(wxeditor_movie* v)
void wxeditor_movie::_moviepanel::update_cache()
{
movie& m = movb.get_movie();
controller_frame_vector& fv = m.get_frame_vector();
controller_frame_vector& fv = our_movie.input;
if(&m == prev_obj && prev_seqno == m.get_seqno()) {
//Just process new subframes if any.
for(uint64_t i = max_subframe; i < fv.size(); i++) {
@ -979,7 +979,7 @@ void wxeditor_movie::_moviepanel::render_linen(text_framebuffer& fb, controller_
void wxeditor_movie::_moviepanel::render(text_framebuffer& fb, unsigned long long pos)
{
spos = pos;
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
controller_frame cf = fv.blank_frame(false);
int _width = width(cf);
fb.set_size(_width, lines_to_display + 3);
@ -1023,7 +1023,7 @@ void wxeditor_movie::_moviepanel::do_toggle_buttons(unsigned idx, uint64_t row1,
if(!movb.get_movie().readonly_mode())
return;
uint64_t fedit = real_first_editable(*_fcontrols, idx);
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
controller_frame_vector::notify_freeze freeze(fv);
for(uint64_t i = _press_line; i <= line; i++) {
if(i < fedit || i >= fv.size())
@ -1053,7 +1053,7 @@ void wxeditor_movie::_moviepanel::do_alter_axis(unsigned idx, uint64_t row1, uin
return;
}
uint64_t fedit = real_first_editable(*_fcontrols, idx);
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
if(line < fedit || line >= fv.size()) {
valid = false;
return;
@ -1077,7 +1077,7 @@ void wxeditor_movie::_moviepanel::do_alter_axis(unsigned idx, uint64_t row1, uin
std::swap(line, line2);
runemufn([idx, line, line2, value, _fcontrols]() {
uint64_t fedit = real_first_editable(*_fcontrols, idx);
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
controller_frame_vector::notify_freeze freeze(fv);
for(uint64_t i = line; i <= line2; i++) {
if(i < fedit || i >= fv.size())
@ -1105,7 +1105,7 @@ void wxeditor_movie::_moviepanel::do_sweep_axis(unsigned idx, uint64_t row1, uin
return;
}
uint64_t fedit = real_first_editable(*_fcontrols, idx);
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
if(line2 < fedit || line2 >= fv.size()) {
valid = false;
return;
@ -1119,7 +1119,7 @@ void wxeditor_movie::_moviepanel::do_sweep_axis(unsigned idx, uint64_t row1, uin
return;
runemufn([idx, line, line2, value, value2, _fcontrols]() {
uint64_t fedit = real_first_editable(*_fcontrols, idx);
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
controller_frame_vector::notify_freeze freeze(fv);
for(uint64_t i = line + 1; i <= line2 - 1; i++) {
if(i < fedit || i >= fv.size())
@ -1141,7 +1141,7 @@ void wxeditor_movie::_moviepanel::do_append_frames(uint64_t count)
runemufn([_count]() {
if(!movb.get_movie().readonly_mode())
return;
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
controller_frame_vector::notify_freeze freeze(fv);
for(uint64_t i = 0; i < _count; i++)
fv.append(fv.blank_frame(true));
@ -1174,7 +1174,7 @@ void wxeditor_movie::_moviepanel::do_insert_frame_after(uint64_t row)
runemufn([_row, _fcontrols]() {
if(!movb.get_movie().readonly_mode())
return;
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t fedit = real_first_editable(*_fcontrols, 0);
//Find the start of the next frame.
uint64_t nframe = _row + 1;
@ -1206,7 +1206,7 @@ void wxeditor_movie::_moviepanel::do_delete_frame(uint64_t row1, uint64_t row2,
frame_controls* _fcontrols = &fcontrols;
if(_row1 > _row2) std::swap(_row1, _row2);
runemufn([_row1, _row2, _wholeframe, _fcontrols]() {
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t vsize = fv.size();
if(_row1 >= vsize)
return; //Nothing to do.
@ -1275,7 +1275,7 @@ void wxeditor_movie::_moviepanel::do_truncate(uint64_t row)
uint64_t _row = row;
frame_controls* _fcontrols = &fcontrols;
runemufn([_row, _fcontrols]() {
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t vsize = fv.size();
if(_row >= vsize)
return;
@ -1380,7 +1380,7 @@ void wxeditor_movie::_moviepanel::popup_axis_panel(uint64_t row, control_info ci
runemufn([ciX, row, c, _fcontrols]() {
uint64_t fedit = real_first_editable(*_fcontrols, ciX.index);
if(row < fedit) return;
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
controller_frame cf = fv[row];
_fcontrols->write_index(cf, ciX.index, c.first);
});
@ -1416,7 +1416,7 @@ void wxeditor_movie::_moviepanel::popup_axis_panel(uint64_t row, control_info ci
uint64_t fedit = real_first_editable(*_fcontrols, ciX.index);
fedit = max(fedit, real_first_editable(*_fcontrols, ciY.index));
if(row < fedit) return;
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
controller_frame cf = fv[row];
_fcontrols->write_index(cf, ciX.index, c.first);
_fcontrols->write_index(cf, ciY.index, c.second);
@ -1428,7 +1428,7 @@ void wxeditor_movie::_moviepanel::popup_axis_panel(uint64_t row, control_info ci
uint64_t fedit = real_first_editable(*_fcontrols, ciX.index);
fedit = max(fedit, real_first_editable(*_fcontrols, ciY.index));
if(row < fedit) return;
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
controller_frame cf = fv[row];
_fcontrols->write_index(cf, ciX.index, c.first);
_fcontrols->write_index(cf, ciY.index, c.second);
@ -1765,7 +1765,7 @@ void wxeditor_movie::_moviepanel::on_mouse2(unsigned x, unsigned y, bool polarit
int wxeditor_movie::_moviepanel::get_lines()
{
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
return fv.size();
}
@ -1873,7 +1873,7 @@ void wxeditor_movie::_moviepanel::do_copy(uint64_t row1, uint64_t row2, unsigned
std::swap(line, line2);
std::string copied;
runemufn([port, controller, line, line2, _fcontrols, &copied]() {
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t vsize = fv.size();
if(!vsize)
return;
@ -1892,7 +1892,7 @@ void wxeditor_movie::_moviepanel::do_copy(uint64_t row1, uint64_t row2)
std::swap(line, line2);
std::string copied;
runemufn([line, line2, &copied]() {
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t vsize = fv.size();
if(!vsize)
return;
@ -1939,7 +1939,7 @@ void wxeditor_movie::_moviepanel::do_paste(uint64_t row, bool append)
while(std::getline(y, z))
gaplen++;
}
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t vsize = fv.size();
if(gapstart < real_first_editable(*_fcontrols, 0))
return;
@ -1997,7 +1997,7 @@ void wxeditor_movie::_moviepanel::do_paste(uint64_t row, unsigned port, unsigned
newframes++;
}
}
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t vsize = fv.size();
if(gapstart < real_first_editable(*_fcontrols, iset))
return;
@ -2036,7 +2036,7 @@ void wxeditor_movie::_moviepanel::do_insert_controller(uint64_t row, unsigned po
//Insert enough lines for the pasted content.
if(!movb.get_movie().readonly_mode())
return;
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t vsize = fv.size();
if(gapstart < real_first_editable(*_fcontrols, iset))
return;
@ -2065,7 +2065,7 @@ void wxeditor_movie::_moviepanel::do_delete_controller(uint64_t row1, uint64_t r
//Insert enough lines for the pasted content.
if(!movb.get_movie().readonly_mode())
return;
controller_frame_vector& fv = movb.get_movie().get_frame_vector();
controller_frame_vector& fv = our_movie.input;
uint64_t vsize = fv.size();
if(gapstart < real_first_editable(*_fcontrols, iset))
return;

View file

@ -581,7 +581,6 @@ void wxeditor_uploaddialog::on_ok(wxCommandEvent& e)
if(fn.length() < 6 || fn.substr(fn.length() - 5) != ".lsmv")
filename->SetValue(towxstring(fn + ".lsmv"));
our_movie.is_savestate = false;
our_movie.input = movb.get_movie().save();
auto prj = project_get();
if(prj) {
our_movie.gamename = prj->gamename;