10 //std::ofstream debuglog("movie-debugging-log", std::ios::out | std::ios::app);
14 const char* movie_id
= "Movies";
15 bool movies_compatible(portctrl::frame_vector
& old_movie
, portctrl::frame_vector
& new_movie
,
16 uint64_t frame
, const uint32_t* polls
, const std::string
& old_projectid
,
17 const std::string
& new_projectid
)
19 //Project IDs have to match.
20 if(old_projectid
!= new_projectid
)
22 return old_movie
.compatible(new_movie
, frame
, polls
);
29 movie_data
->clear_framecount_notification(_listener
);
32 void movie::set_all_DRDY() throw()
34 pollcounters
.set_all_DRDY();
37 std::string
movie::rerecord_count() throw(std::bad_alloc
)
42 void movie::rerecord_count(const std::string
& count
) throw(std::bad_alloc
)
47 std::string
movie::project_id() throw(std::bad_alloc
)
52 void movie::project_id(const std::string
& id
) throw(std::bad_alloc
)
57 bool movie::readonly_mode() throw()
62 void movie::set_controls(portctrl::frame controls
) throw()
64 current_controls
= controls
;
67 uint32_t movie::count_changes(uint64_t first_subframe
) throw()
69 return movie_data
->subframe_count(first_subframe
);
72 portctrl::frame
movie::get_controls() throw()
75 return current_controls
;
76 portctrl::frame c
= movie_data
->blank_frame(false);
77 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
78 if(current_frame
== 0)
80 //Otherwise find the last valid frame of input.
81 uint32_t changes
= count_changes(current_frame_first_subframe
);
83 return c
; //End of movie.
84 for(size_t i
= 0; i
< movie_data
->get_types().indices(); i
++) {
85 uint32_t polls
= pollcounters
.get_polls(i
);
86 uint32_t index
= (changes
> polls
) ? polls
: changes
- 1;
87 c
.axis2(i
, (*movie_data
)[current_frame_first_subframe
+ index
].axis2(i
));
92 uint64_t movie::get_current_frame() throw()
97 uint64_t movie::get_lag_frames() throw()
102 void movie::next_frame() throw(std::bad_alloc
)
104 //Adjust lag count. Frame 0 MUST NOT be considered lag.
105 bool pflag
= pflag_handler
? pflag_handler
->get_pflag() : false;
106 if(current_frame
&& !pflag
)
108 else if(pflag_handler
)
109 pflag_handler
->set_pflag(false);
111 //If all poll counters are zero for all real controls, this frame is lag.
112 bool this_frame_lag
= !pollcounters
.has_polled();
113 //Oh, frame 0 must not be considered lag.
114 if(current_frame
&& this_frame_lag
) {
115 //debuglog << "Frame " << current_frame << " is lag" << std::endl << std::flush;
117 //If in read-write mode, write a dummy record for the frame. Force sync flag.
118 //As index should be movie_data->size(), it is correct afterwards.
119 movie_data
->append(current_controls
.copy(true));
123 //Reset the poll counters and DRDY flags.
124 pollcounters
.clear();
126 //Increment the current frame counter and subframe counter. Note that first subframe is undefined for
127 //frame 0 and 0 for frame 1.
129 current_frame_first_subframe
= current_frame_first_subframe
+
130 count_changes(current_frame_first_subframe
);
132 current_frame_first_subframe
= 0;
136 bool movie::get_DRDY(unsigned port
, unsigned controller
, unsigned ctrl
) throw(std::logic_error
)
138 return pollcounters
.get_DRDY(port
, controller
, ctrl
);
141 short movie::next_input(unsigned port
, unsigned controller
, unsigned ctrl
) throw(std::bad_alloc
, std::logic_error
)
143 pollcounters
.clear_DRDY(port
, controller
, ctrl
);
146 //In readonly mode...
147 //If at the end of the movie, return released / neutral (but also record the poll)...
148 if(current_frame_first_subframe
>= movie_data
->size()) {
149 pollcounters
.increment_polls(port
, controller
, ctrl
);
152 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
153 if(current_frame
== 0)
155 //Otherwise find the last valid frame of input.
156 uint32_t changes
= count_changes(current_frame_first_subframe
);
157 uint32_t polls
= pollcounters
.get_polls(port
, controller
, ctrl
);
158 uint32_t index
= (changes
> polls
) ? polls
: changes
- 1;
159 int16_t data
= (*movie_data
)[current_frame_first_subframe
+ index
].axis3(port
, controller
, ctrl
);
160 pollcounters
.increment_polls(port
, controller
, ctrl
);
164 //Before the beginning? Somebody screwed up (but return released / neutral anyway)...
165 //Also, frame 0 must not be added to movie file.
166 if(current_frame
== 0)
168 //If at movie end, insert complete input with frame sync set (this is the first subframe).
169 if(current_frame_first_subframe
>= movie_data
->size()) {
170 movie_data
->append(current_controls
.copy(true));
171 //current_frame_first_subframe should be movie_data->size(), so it is right.
172 pollcounters
.increment_polls(port
, controller
, ctrl
);
173 return (*movie_data
)[current_frame_first_subframe
].axis3(port
, controller
, ctrl
);
175 short new_value
= current_controls
.axis3(port
, controller
, ctrl
);
176 //Fortunately, we know this frame is the last one in movie_data.
177 uint32_t pollcounter
= pollcounters
.get_polls(port
, controller
, ctrl
);
178 if(current_frame_first_subframe
+ pollcounter
< movie_data
->size()) {
179 //The index is within existing size. Change the value and propagate to all subsequent
181 for(uint64_t i
= current_frame_first_subframe
+ pollcounter
; i
< movie_data
->size(); i
++)
182 (*movie_data
)[i
].axis3(port
, controller
, ctrl
, new_value
);
183 } else if(new_value
!= (*movie_data
)[movie_data
->size() - 1].axis3(port
, controller
, ctrl
)) {
184 //The index is not within existing size and value does not match. We need to create a new
185 //subframes(s), copying the last subframe.
186 while(current_frame_first_subframe
+ pollcounter
>= movie_data
->size())
187 movie_data
->append((*movie_data
)[movie_data
->size() - 1].copy(false));
188 (*movie_data
)[current_frame_first_subframe
+ pollcounter
].axis3(port
, controller
, ctrl
,
191 pollcounters
.increment_polls(port
, controller
, ctrl
);
196 movie::movie() throw(std::bad_alloc
)
197 : _listener(*this), tracker(memtracker::singleton(), movie_id
, sizeof(*this))
205 current_frame_first_subframe
= 0;
207 pflag_handler
= NULL
;
211 void movie::load(const std::string
& rerecs
, const std::string
& project_id
, portctrl::frame_vector
& input
)
212 throw(std::bad_alloc
, std::runtime_error
)
214 if(input
.size() > 0 && !input
[0].sync())
215 throw std::runtime_error("First subframe MUST have frame sync flag set");
220 _project_id
= project_id
;
222 current_frame_first_subframe
= 0;
223 pollcounters
= portctrl::counters(input
.get_types());
225 //This is to force internal type of current_controls to become correct.
226 current_controls
= input
.blank_frame(false);
229 unsigned movie::next_poll_number()
231 return pollcounters
.max_polls() + 1;
234 void movie::readonly_mode(bool enable
) throw(std::bad_alloc
)
236 bool was_in_readonly
= readonly
;
238 if(was_in_readonly
&& !readonly
) {
240 //Transitioning to readwrite mode, we have to adjust the length of the movie data.
241 if(current_frame
== 0) {
242 //WTF... At before first frame. Blank the entiere movie.
246 //Fun special case: Current frame is not in movie (current_frame_first_subframe >=
247 //movie_data->size()). In this case, we have to extend the movie data.
248 if(current_frame_first_subframe
>= movie_data
->size()) {
249 //Yes, this will insert one extra frame... But we will lose it later if it is not needed.
250 while(movie_data
->count_frames() < current_frame
)
251 movie_data
->append(movie_data
->blank_frame(true));
252 current_frame_first_subframe
= movie_data
->size() - 1;
255 //We have to take the part up to furthest currently readable subframe. Also, we need to propagate
256 //forward values with smaller poll counters.
257 uint64_t next_frame_first_subframe
= current_frame_first_subframe
+
258 count_changes(current_frame_first_subframe
);
259 uint64_t max_readable_subframes
= current_frame_first_subframe
+ pollcounters
.max_polls();
260 if(max_readable_subframes
> next_frame_first_subframe
)
261 max_readable_subframes
= next_frame_first_subframe
;
263 movie_data
->resize(max_readable_subframes
);
264 next_frame_first_subframe
= max_readable_subframes
;
265 //Propagate buttons. The only one that needs special handling is sync flag (index 0, tuple 0,0,0).
266 for(size_t i
= 1; i
< movie_data
->get_types().indices(); i
++) {
267 uint32_t polls
= pollcounters
.get_polls(i
);
268 polls
= polls
? polls
: 1;
269 for(uint64_t j
= current_frame_first_subframe
+ polls
; j
< next_frame_first_subframe
; j
++)
270 (*movie_data
)[j
].axis2(i
, (*movie_data
)[current_frame_first_subframe
+ polls
- 1].
276 //Save state of movie code.
277 void movie::save_state(std::string
& proj_id
, uint64_t& curframe
, uint64_t& lagframes
, std::vector
<uint32_t>& pcounters
)
278 throw(std::bad_alloc
)
280 pollcounters
.save_state(pcounters
);
281 proj_id
= _project_id
;
282 curframe
= current_frame
;
283 lagframes
= lag_frames
;
286 //Restore state of movie code. Throws if state is invalid. Flag gives new state of readonly flag.
287 size_t movie::restore_state(uint64_t curframe
, uint64_t lagframe
, const std::vector
<uint32_t>& pcounters
, bool ro
,
288 portctrl::frame_vector
* old_movie
, const std::string
& old_projectid
) throw(std::bad_alloc
,
291 if(!pollcounters
.check(pcounters
))
292 throw std::runtime_error("Wrong number of poll counters");
293 if(old_movie
&& !movies_compatible(*old_movie
, *movie_data
, curframe
, &pcounters
[0], old_projectid
,
295 throw std::runtime_error("Save is not from this movie");
296 uint64_t tmp_firstsubframe
= 0;
297 for(uint64_t i
= 1; i
< curframe
; i
++)
298 tmp_firstsubframe
= tmp_firstsubframe
+ count_changes(tmp_firstsubframe
);
299 //Checks have passed, copy the data.
301 current_frame
= curframe
;
302 current_frame_first_subframe
= tmp_firstsubframe
;
303 lag_frames
= lagframe
;
304 pollcounters
.load_state(pcounters
);
309 uint64_t movie::frame_subframes(uint64_t frame
) throw()
311 if(frame
< cached_frame
)
313 uint64_t p
= cached_subframe
;
314 for(uint64_t i
= cached_frame
; i
< frame
; i
++)
315 p
= p
+ count_changes(p
);
316 cached_frame
= frame
;
318 return count_changes(p
);
321 void movie::clear_caches() throw()
327 portctrl::frame
movie::read_subframe(uint64_t frame
, uint64_t subframe
) throw()
329 if(frame
< cached_frame
)
331 uint64_t p
= cached_subframe
;
332 for(uint64_t i
= cached_frame
; i
< frame
; i
++)
333 p
= p
+ count_changes(p
);
334 cached_frame
= frame
;
336 uint64_t max
= count_changes(p
);
338 return movie_data
->blank_frame(true);
342 return (*movie_data
)[p
+ subframe
];
345 void movie::reset_state() throw()
349 current_frame_first_subframe
= 0;
350 pollcounters
.clear();
355 void movie::fast_save(uint64_t& _frame
, uint64_t& _ptr
, uint64_t& _lagc
, std::vector
<uint32_t>& _counters
)
357 pollcounters
.save_state(_counters
);
358 _frame
= current_frame
;
359 _ptr
= current_frame_first_subframe
;
363 void movie::fast_load(uint64_t& _frame
, uint64_t& _ptr
, uint64_t& _lagc
, std::vector
<uint32_t>& _counters
)
366 current_frame
= _frame
;
367 current_frame_first_subframe
= (_ptr
<= movie_data
->size()) ? _ptr
: movie_data
->size();
369 pollcounters
.load_state(_counters
);
370 readonly_mode(false);
373 void movie::set_pflag_handler(poll_flag
* handler
)
375 pflag_handler
= handler
;
378 int16_t movie::read_subframe_at_index(uint32_t subframe
, unsigned port
, unsigned controller
, unsigned ctrl
)
380 //Readwrite, Past the end of movie or before the beginning?
381 if(!readonly
|| current_frame_first_subframe
>= movie_data
->size() || current_frame
== 0)
383 uint32_t changes
= count_changes(current_frame_first_subframe
);
384 uint32_t index
= (changes
> subframe
) ? subframe
: changes
- 1;
385 return (*movie_data
)[current_frame_first_subframe
+ index
].axis3(port
, controller
, ctrl
);
388 void movie::write_subframe_at_index(uint32_t subframe
, unsigned port
, unsigned controller
, unsigned ctrl
,
391 if(!readonly
|| current_frame
== 0)
393 bool extended
= false;
394 while(current_frame
> movie_data
->count_frames()) {
395 //Extend the movie by a blank frame.
397 movie_data
->append(movie_data
->blank_frame(true));
401 current_frame_first_subframe
= movie_data
->size() - 1;
403 if(current_frame
< movie_data
->count_frames()) {
404 //If we are not on the last frame, write is possible if it is not on extension.
405 uint32_t changes
= count_changes(current_frame_first_subframe
);
406 if(subframe
< changes
)
407 (*movie_data
)[current_frame_first_subframe
+ subframe
].axis3(port
, controller
, ctrl
, x
);
409 //Writing to the last frame. If not on extension, handle like non-last frame.
410 //Note that if movie had to be extended, it was done before, resulting movie like in state with
411 //0 stored subframes.
412 uint32_t changes
= count_changes(current_frame_first_subframe
);
413 if(subframe
< changes
)
414 (*movie_data
)[current_frame_first_subframe
+ subframe
].axis3(port
, controller
, ctrl
, x
);
416 //If there is no frame at all, create one.
417 if(current_frame_first_subframe
>= movie_data
->size()) {
418 movie_data
->append(movie_data
->blank_frame(true));
420 //Create needed subframes.
421 while(count_changes(current_frame_first_subframe
) <= subframe
)
422 movie_data
->append(movie_data
->blank_frame(false));
424 (*movie_data
)[current_frame_first_subframe
+ subframe
].axis3(port
, controller
, ctrl
, x
);
429 movie::poll_flag::~poll_flag()
433 void movie::set_movie_data(portctrl::frame_vector
* data
)
435 portctrl::frame_vector
* old
= movie_data
;
437 data
->set_framecount_notification(_listener
);
441 old
->clear_framecount_notification(_listener
);
444 movie::fchange_listener::fchange_listener(movie
& m
)
449 movie::fchange_listener::~fchange_listener()
453 void movie::fchange_listener::notify(portctrl::frame_vector
& src
, uint64_t old
)
455 //Recompute frame_first_subframe.
456 while(mov
.current_frame_first_subframe
< mov
.movie_data
->size() && mov
.current_frame
> old
+ 1) {
457 //OK, movie has been extended.
458 mov
.current_frame_first_subframe
+= mov
.count_changes(mov
.current_frame_first_subframe
);
461 //Nobody is this stupid, right?
462 mov
.current_frame_first_subframe
= min(mov
.current_frame_first_subframe
,
463 static_cast<uint64_t>(mov
.movie_data
->size()));