1 #include "lua/internal.hpp"
2 #include "library/string.hpp"
3 #include "library/minmax.hpp"
4 #include "library/zip.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/instance.hpp"
7 #include "core/moviedata.hpp"
8 #include "core/messages.hpp"
9 #include "core/window.hpp"
19 friend class lua_inputmovie
;
21 lua_inputframe(lua::state
& L
, portctrl::frame _f
);
22 static size_t overcommit(portctrl::frame _f
) { return 0; }
23 int get_button(lua::state
& L
, lua::parameters
& P
)
25 unsigned port
, controller
, button
;
27 P(P
.skipped(), port
, controller
, button
);
29 short value
= getbutton(port
, controller
, button
);
30 L
.pushboolean(value
? 1 : 0);
33 int get_axis(lua::state
& L
, lua::parameters
& P
)
35 unsigned port
, controller
, button
;
37 P(P
.skipped(), port
, controller
, button
);
39 short value
= getbutton(port
, controller
, button
);
43 int set_axis(lua::state
& L
, lua::parameters
& P
)
45 unsigned port
, controller
, button
;
48 P(P
.skipped(), port
, controller
, button
);
49 if(P
.is_boolean()) value
= P
.arg
<bool>() ? 1 : 0;
50 else if(P
.is_number()) value
= P
.arg
<short>();
52 P
.expected("number or boolean");
54 setbutton(port
, controller
, button
, value
);
57 int fast_input(lua::state
& L
, lua::parameters
& P
)
59 unsigned short a
[4],m
;
60 P(P
.skipped(), a
[0], a
[1], a
[2], a
[3], m
);
61 for(unsigned i
= 0; i
< 4; i
++) a
[i
] ^= m
;
62 for(unsigned i
= 0; i
< 16; i
++) {
64 setbutton(1, 0, i
, (w
>> (6-i
%4*2))&1);
65 setbutton(1, 1, i
, (w
>> (7-i
%4*2))&1);
66 setbutton(2, 0, i
, (w
>> (14-i
%4*2))&1);
67 setbutton(2, 1, i
, (w
>> (15-i
%4*2))&1);
71 int serialize(lua::state
& L
, lua::parameters
& P
)
73 char buf
[MAX_SERIALIZED_SIZE
];
78 int unserialize(lua::state
& L
, lua::parameters
& P
)
84 f
.deserialize(buf
.c_str());
87 int get_stride(lua::state
& L
, lua::parameters
& P
)
89 L
.pushnumber(f
.size());
92 portctrl::frame
& get_frame()
98 char buf
[MAX_SERIALIZED_SIZE
];
103 short getbutton(unsigned port
, unsigned controller
, unsigned index
)
105 return f
.axis3(port
, controller
, index
);
107 void setbutton(unsigned port
, unsigned controller
, unsigned index
, short value
)
109 return f
.axis3(port
, controller
, index
, value
);
114 int32_t get_pc_for(unsigned port
, unsigned controller
, unsigned button
, bool extra0
= false);
115 int32_t get_pc_for(unsigned port
, unsigned controller
, unsigned button
, bool extra0
)
117 movie
& m
= CORE().mlogic
->get_movie();
118 if(port
== 0 && controller
== 0 && button
== 0)
119 return m
.get_pollcounters().max_polls() + (extra0
? 1 : 0);
120 if(port
== 0 && controller
== 0 && m
.get_pollcounters().get_framepflag())
121 return max(m
.get_pollcounters().get_polls(port
, controller
, button
), (uint32_t)1);
122 return m
.get_pollcounters().get_polls(port
, controller
, button
);
125 void check_can_edit(unsigned port
, unsigned controller
, unsigned button
, uint64_t frame
,
126 bool allow_past_end
= false);
128 void check_can_edit(unsigned port
, unsigned controller
, unsigned button
, uint64_t frame
,
132 movie
& m
= core
.mlogic
->get_movie();
133 if(!m
.readonly_mode())
134 throw std::runtime_error("Not in playback mode");
135 if(!allow_past_end
&& frame
>= core
.mlogic
->get_mfile().input
->size())
136 throw std::runtime_error("Index out of movie");
137 int32_t pc
= get_pc_for(port
, controller
, button
, true);
139 throw std::runtime_error("Invalid control to edit");
140 uint64_t firstframe
= m
.get_current_frame_first_subframe();
141 uint64_t minframe
= firstframe
+ pc
;
142 uint64_t msize
= core
.mlogic
->get_mfile().input
->size();
143 if(minframe
> msize
|| firstframe
>= msize
)
144 throw std::runtime_error("Can not edit finished movie");
146 throw std::runtime_error("Can not edit past");
149 int current_first_subframe(lua::state
& L
, lua::parameters
& P
)
151 movie
& m
= CORE().mlogic
->get_movie();
152 L
.pushnumber(m
.get_current_frame_first_subframe());
156 int pollcounter(lua::state
& L
, lua::parameters
& P
)
158 unsigned port
, controller
, button
;
160 P(port
, controller
, button
);
163 ret
= get_pc_for(port
, controller
, button
);
168 portctrl::frame_vector
& framevector(lua::state
& L
, lua::parameters
& P
);
170 int _copy_movie(lua::state
& L
, lua::parameters
& P
)
172 portctrl::frame_vector
& v
= framevector(L
, P
);
174 lua::_class
<lua_inputmovie
>::create(L
, v
);
178 int _get_frame(lua::state
& L
, lua::parameters
& P
)
181 portctrl::frame_vector
& v
= framevector(L
, P
);
186 throw std::runtime_error("Requested frame outside movie");
187 portctrl::frame _f
= v
[n
];
188 lua::_class
<lua_inputframe
>::create(L
, _f
);
192 int _set_frame(lua::state
& L
, lua::parameters
& P
)
197 portctrl::frame_vector
& v
= framevector(L
, P
);
202 throw std::runtime_error("Requested frame outside movie");
203 //Checks if requested frame is from movie.
204 if(&v
== core
.mlogic
->get_mfile().input
)
205 check_can_edit(0, 0, 0, n
);
207 v
[n
] = f
->get_frame();
209 if(&v
== core
.mlogic
->get_mfile().input
) {
210 //This can't add frames, so no need to adjust the movie.
211 core
.supdater
->update();
212 core
.dispatch
->status_update();
217 int _get_size(lua::state
& L
, lua::parameters
& P
)
219 portctrl::frame_vector
& v
= framevector(L
, P
);
221 L
.pushnumber(v
.size());
225 int _count_frames(lua::state
& L
, lua::parameters
& P
)
227 portctrl::frame_vector
& v
= framevector(L
, P
);
229 L
.pushnumber(v
.count_frames());
233 int _find_frame(lua::state
& L
, lua::parameters
& P
)
236 portctrl::frame_vector
& v
= framevector(L
, P
);
240 L
.pushnumber(v
.find_frame(n
));
244 int _subframe_to_frame(lua::state
& L
, lua::parameters
& P
)
247 portctrl::frame_vector
& v
= framevector(L
, P
);
251 L
.pushnumber(v
.subframe_to_frame(n
));
255 int _blank_frame(lua::state
& L
, lua::parameters
& P
)
257 portctrl::frame_vector
& v
= framevector(L
, P
);
259 portctrl::frame _f
= v
.blank_frame(true);
260 lua::_class
<lua_inputframe
>::create(L
, _f
);
264 int _append_frames(lua::state
& L
, lua::parameters
& P
)
268 portctrl::frame_vector
& v
= framevector(L
, P
);
273 portctrl::frame_vector::notify_freeze
freeze(v
);
274 for(uint64_t i
= 0; i
< count
; i
++)
275 v
.append(v
.blank_frame(true));
277 if(&v
== core
.mlogic
->get_mfile().input
) {
278 core
.supdater
->update();
279 core
.dispatch
->status_update();
284 int _append_frame(lua::state
& L
, lua::parameters
& P
)
288 portctrl::frame_vector
& v
= framevector(L
, P
);
292 v
.append(v
.blank_frame(true));
293 if(&v
== core
.mlogic
->get_mfile().input
) {
294 core
.supdater
->update();
295 core
.dispatch
->status_update();
296 check_can_edit(0, 0, 0, v
.size() - 1);
298 v
[v
.size() - 1] = f
->get_frame();
299 if(&v
== core
.mlogic
->get_mfile().input
) {
300 if(!v
[v
.size() - 1].sync()) {
301 core
.supdater
->update();
303 core
.dispatch
->status_update();
308 int _truncate(lua::state
& L
, lua::parameters
& P
)
312 portctrl::frame_vector
& v
= framevector(L
, P
);
317 throw std::runtime_error("Requested truncate length longer than existing");
318 if(&v
== core
.mlogic
->get_mfile().input
)
319 check_can_edit(0, 0, 0, n
);
321 if(&v
== core
.mlogic
->get_mfile().input
) {
322 core
.supdater
->update();
323 core
.dispatch
->status_update();
328 int _edit(lua::state
& L
, lua::parameters
& P
)
332 unsigned port
, controller
, button
;
334 portctrl::frame_vector
& v
= framevector(L
, P
);
336 P(frame
, port
, controller
, button
);
337 if(P
.is_boolean()) value
= P
.arg
<bool>() ? 1 : 0;
338 else if(P
.is_number()) P(value
);
340 P
.expected("number or boolean");
342 if(&v
== core
.mlogic
->get_mfile().input
)
343 check_can_edit(port
, controller
, button
, frame
);
344 v
[frame
].axis3(port
, controller
, button
, value
);
346 if(&v
== core
.mlogic
->get_mfile().input
) {
347 core
.supdater
->update();
348 core
.dispatch
->status_update();
354 int _copy_frames(lua::state
& L
, lua::parameters
& P
)
357 uint64_t dst
, src
, count
;
358 bool backwards
= same
;
360 portctrl::frame_vector
& dstv
= framevector(L
, P
);
362 portctrl::frame_vector
& srcv
= same
? dstv
: framevector(L
, P
);
364 if(same
) P(backwards
);
366 if(src
>= srcv
.size() || src
+ count
< src
)
367 throw std::runtime_error("Source index out of movie");
368 if(dst
> dstv
.size() || dst
+ count
< dst
)
369 throw std::runtime_error("Destination index out of movie");
371 if(&dstv
== core
.mlogic
->get_mfile().input
)
372 check_can_edit(0, 0, 0, dst
, true);
375 portctrl::frame_vector::notify_freeze
freeze(dstv
);
376 //Add enough blank frames to make the copy.
377 while(dst
+ count
> dstv
.size())
378 dstv
.append(dstv
.blank_frame(false));
380 for(uint64_t i
= backwards
? (count
- 1) : 0; i
< count
; i
= backwards
? (i
- 1) : (i
+ 1))
381 dstv
[dst
+ i
] = srcv
[src
+ i
];
383 if(&dstv
== core
.mlogic
->get_mfile().input
) {
384 core
.supdater
->update();
385 core
.dispatch
->status_update();
390 int _serialize(lua::state
& L
, lua::parameters
& P
)
392 std::string filename
;
395 portctrl::frame_vector
& v
= framevector(L
, P
);
399 std::ofstream
file(filename
, binary
? std::ios_base::binary
: std::ios_base::out
);
401 throw std::runtime_error("Can't open file to write output to");
403 uint64_t stride
= v
.get_stride();
404 uint64_t pageframes
= v
.get_frames_per_page();
405 uint64_t vsize
= v
.size();
408 uint64_t count
= (vsize
> pageframes
) ? pageframes
: vsize
;
409 size_t bytes
= count
* stride
;
410 unsigned char* content
= v
.get_page_buffer(pagenum
++);
411 file
.write(reinterpret_cast<char*>(content
), bytes
);
415 char buf
[MAX_SERIALIZED_SIZE
];
416 for(uint64_t i
= 0; i
< v
.size(); i
++) {
418 file
<< buf
<< std::endl
;
427 lua_inputmovie(lua::state
& L
, const portctrl::frame_vector
& _v
);
428 lua_inputmovie(lua::state
& L
, portctrl::frame
& _f
);
429 static size_t overcommit(const portctrl::frame_vector
& _v
) { return 0; }
430 static size_t overcommit(portctrl::frame
& _f
) { return 0; }
431 int copy_movie(lua::state
& L
, lua::parameters
& P
)
433 return _copy_movie(L
, P
);
435 int get_frame(lua::state
& L
, lua::parameters
& P
)
437 return _get_frame(L
, P
);
439 int set_frame(lua::state
& L
, lua::parameters
& P
)
441 return _set_frame(L
, P
);
443 int get_size(lua::state
& L
, lua::parameters
& P
)
445 return _get_size(L
, P
);
447 int count_frames(lua::state
& L
, lua::parameters
& P
)
449 return _count_frames(L
, P
);
451 int find_frame(lua::state
& L
, lua::parameters
& P
)
453 return _find_frame(L
, P
);
455 int subframe_to_frame(lua::state
& L
, lua::parameters
& P
)
457 return _subframe_to_frame(L
, P
);
459 int blank_frame(lua::state
& L
, lua::parameters
& P
)
461 return _blank_frame(L
, P
);
463 int append_frames(lua::state
& L
, lua::parameters
& P
)
465 return _append_frames(L
, P
);
467 int append_frame(lua::state
& L
, lua::parameters
& P
)
469 return _append_frame(L
, P
);
471 int truncate(lua::state
& L
, lua::parameters
& P
)
473 return _truncate(L
, P
);
475 int edit(lua::state
& L
, lua::parameters
& P
)
479 int copy_frames(lua::state
& L
, lua::parameters
& P
)
481 return _copy_frames
<true>(L
, P
);
483 int serialize(lua::state
& L
, lua::parameters
& P
)
485 return _serialize(L
, P
);
487 int debugdump(lua::state
& L
, lua::parameters
& P
)
489 char buf
[MAX_SERIALIZED_SIZE
];
490 for(uint64_t i
= 0; i
< v
.size(); i
++) {
492 messages
<< buf
<< std::endl
;
496 portctrl::frame_vector
* get_frame_vector()
503 return (stringfmt() << s
<< " " << ((s
!= 1) ? "frames" : "frame")).str();
506 void common_init(lua::state
& L
);
507 portctrl::frame_vector v
;
510 int copy_movie(lua::state
& L
, lua::parameters
& P
)
512 return _copy_movie(L
, P
);
515 int get_frame(lua::state
& L
, lua::parameters
& P
)
517 return _get_frame(L
, P
);
520 int set_frame(lua::state
& L
, lua::parameters
& P
)
522 return _set_frame(L
, P
);
525 int get_size(lua::state
& L
, lua::parameters
& P
)
527 return _get_size(L
, P
);
530 int count_frames(lua::state
& L
, lua::parameters
& P
)
532 return _count_frames(L
, P
);
535 int find_frame(lua::state
& L
, lua::parameters
& P
)
537 return _find_frame(L
, P
);
540 int subframe_to_frame(lua::state
& L
, lua::parameters
& P
)
542 return _subframe_to_frame(L
, P
);
545 int blank_frame(lua::state
& L
, lua::parameters
& P
)
547 return _blank_frame(L
, P
);
550 int append_frames(lua::state
& L
, lua::parameters
& P
)
552 return _append_frames(L
, P
);
555 int append_frame(lua::state
& L
, lua::parameters
& P
)
557 return _append_frame(L
, P
);
560 int truncate(lua::state
& L
, lua::parameters
& P
)
562 return _truncate(L
, P
);
565 int edit(lua::state
& L
, lua::parameters
& P
)
570 int copy_frames2(lua::state
& L
, lua::parameters
& P
)
572 return _copy_frames
<false>(L
, P
);
575 int copy_frames(lua::state
& L
, lua::parameters
& P
)
577 return _copy_frames
<true>(L
, P
);
580 int serialize(lua::state
& L
, lua::parameters
& P
)
582 return _serialize(L
, P
);
585 int unserialize(lua::state
& L
, lua::parameters
& P
)
588 std::string filename
;
591 P(f
, filename
, binary
);
593 std::istream
& file
= zip::openrel(filename
, "");
595 throw std::runtime_error("Can't open file to read input from");
596 lua_inputmovie
* m
= lua::_class
<lua_inputmovie
>::create(L
, f
->get_frame());
597 portctrl::frame_vector
& v
= *m
->get_frame_vector();
598 portctrl::frame_vector::notify_freeze
freeze(v
);
600 uint64_t stride
= v
.get_stride();
601 uint64_t pageframes
= v
.get_frames_per_page();
604 size_t pagesize
= stride
* pageframes
;
606 v
.resize(vsize
+ pageframes
);
607 unsigned char* contents
= v
.get_page_buffer(pagenum
++);
608 file
.read(reinterpret_cast<char*>(contents
), pagesize
);
609 vsize
+= (file
.gcount() / stride
);
614 portctrl::frame tmpl
= v
.blank_frame(false);
616 std::getline(file
, line
);
618 if(line
.length() == 0)
620 tmpl
.deserialize(line
.c_str());
627 int current_branch(lua::state
& L
, lua::parameters
& P
)
629 L
.pushlstring(CORE().mlogic
->get_mfile().current_branch());
633 int get_branches(lua::state
& L
, lua::parameters
& P
)
636 for(auto& i
: core
.mlogic
->get_mfile().branches
)
637 L
.pushlstring(i
.first
);
638 return core
.mlogic
->get_mfile().branches
.size();
641 portctrl::frame_vector
& framevector(lua::state
& L
, lua::parameters
& P
)
646 return *core
.mlogic
->get_mfile().input
;
647 } else if(P
.is_string()) {
650 if(!core
.mlogic
->get_mfile().branches
.count(x
))
651 throw std::runtime_error("No such branch");
652 return core
.mlogic
->get_mfile().branches
[x
];
653 } else if(P
.is
<lua_inputmovie
>())
654 return *(P
.arg
<lua_inputmovie
*>()->get_frame_vector());
656 return *core
.mlogic
->get_mfile().input
;
659 lua::_class
<lua_inputmovie
> LUA_class_inputmovie(lua_class_movie
, "INPUTMOVIE", {}, {
660 {"copy_movie", &lua_inputmovie::copy_movie
},
661 {"get_frame", &lua_inputmovie::get_frame
},
662 {"set_frame", &lua_inputmovie::set_frame
},
663 {"get_size", &lua_inputmovie::get_size
},
664 {"count_frames", &lua_inputmovie::count_frames
},
665 {"find_frame", &lua_inputmovie::find_frame
},
666 {"subframe_to_frame", &lua_inputmovie::subframe_to_frame
},
667 {"blank_frame", &lua_inputmovie::blank_frame
},
668 {"append_frames", &lua_inputmovie::append_frames
},
669 {"append_frame", &lua_inputmovie::append_frame
},
670 {"truncate", &lua_inputmovie::truncate
},
671 {"edit", &lua_inputmovie::edit
},
672 {"debugdump", &lua_inputmovie::debugdump
},
673 {"copy_frames", &lua_inputmovie::copy_frames
},
674 {"serialize", &lua_inputmovie::serialize
},
675 }, &lua_inputmovie::print
);
677 lua::_class
<lua_inputframe
> LUA_class_inputframe(lua_class_movie
, "INPUTFRAME", {}, {
678 {"get_button", &lua_inputframe::get_button
},
679 {"get_axis", &lua_inputframe::get_axis
},
680 {"set_axis", &lua_inputframe::set_axis
},
681 {"set_button", &lua_inputframe::set_axis
},
682 {"serialize", &lua_inputframe::serialize
},
683 {"unserialize", &lua_inputframe::unserialize
},
684 {"get_stride", &lua_inputframe::get_stride
},
685 {"snes_fast_input", &lua_inputframe::fast_input
},
686 }, &lua_inputframe::print
);
688 lua::functions
LUA_inputmovie_fns(lua_func_misc
, "movie", {
689 {"current_first_subframe", current_first_subframe
},
690 {"pollcounter", pollcounter
},
691 {"copy_movie", copy_movie
},
692 {"get_frame", get_frame
},
693 {"set_frame", set_frame
},
694 {"get_size", get_size
},
695 {"count_frames", count_frames
},
696 {"find_frame", find_frame
},
697 {"subframe_to_frame", subframe_to_frame
},
698 {"blank_frame", blank_frame
},
699 {"append_frames", append_frames
},
700 {"append_frame", append_frame
},
701 {"truncate", truncate
},
703 {"copy_frames2", copy_frames2
},
704 {"copy_frames", copy_frames
},
705 {"serialize", serialize
},
706 {"unserialize", unserialize
},
707 {"current_branch", current_branch
},
708 {"get_branches", get_branches
},
711 lua_inputframe::lua_inputframe(lua::state
& L
, portctrl::frame _f
)
716 void lua_inputmovie::common_init(lua::state
& L
)
720 lua_inputmovie::lua_inputmovie(lua::state
& L
, const portctrl::frame_vector
& _v
)
726 lua_inputmovie::lua_inputmovie(lua::state
& L
, portctrl::frame
& f
)
728 v
.clear(f
.porttypes());