Actually call on_reset callback
[lsnes.git] / src / lua / inputmovie.cpp
blobe6cd979c972c989a9e441186eba889e33a405599
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"
10 #include <fstream>
13 namespace
15 class lua_inputmovie;
17 class lua_inputframe
19 friend class lua_inputmovie;
20 public:
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);
31 return 1;
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);
40 L.pushnumber(value);
41 return 1;
43 int set_axis(lua::state& L, lua::parameters& P)
45 unsigned port, controller, button;
46 short value;
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>();
51 else
52 P.expected("number or boolean");
54 setbutton(port, controller, button, value);
55 return 0;
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++) {
63 auto w = a[i / 4];
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);
69 return 0;
71 int serialize(lua::state& L, lua::parameters& P)
73 char buf[MAX_SERIALIZED_SIZE];
74 f.serialize(buf);
75 L.pushstring(buf);
76 return 1;
78 int unserialize(lua::state& L, lua::parameters& P)
80 std::string buf;
82 P(P.skipped(), buf);
84 f.deserialize(buf.c_str());
85 return 0;
87 int get_stride(lua::state& L, lua::parameters& P)
89 L.pushnumber(f.size());
90 return 1;
92 portctrl::frame& get_frame()
94 return f;
96 std::string print()
98 char buf[MAX_SERIALIZED_SIZE];
99 f.serialize(buf);
100 return buf;
102 private:
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);
111 portctrl::frame f;
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,
129 bool allow_past_end)
131 auto& core = CORE();
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);
138 if(pc < 0)
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");
145 if(frame < minframe)
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());
153 return 1;
156 int pollcounter(lua::state& L, lua::parameters& P)
158 unsigned port, controller, button;
160 P(port, controller, button);
162 uint32_t ret = 0;
163 ret = get_pc_for(port, controller, button);
164 L.pushnumber(ret);
165 return 1;
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);
175 return 1;
178 int _get_frame(lua::state& L, lua::parameters& P)
180 uint64_t n;
181 portctrl::frame_vector& v = framevector(L, P);
183 P(n);
185 if(n >= v.size())
186 throw std::runtime_error("Requested frame outside movie");
187 portctrl::frame _f = v[n];
188 lua::_class<lua_inputframe>::create(L, _f);
189 return 1;
192 int _set_frame(lua::state& L, lua::parameters& P)
194 auto& core = CORE();
195 uint64_t n;
196 lua_inputframe* f;
197 portctrl::frame_vector& v = framevector(L, P);
199 P(n, f);
201 if(n >= v.size())
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();
214 return 0;
217 int _get_size(lua::state& L, lua::parameters& P)
219 portctrl::frame_vector& v = framevector(L, P);
221 L.pushnumber(v.size());
222 return 1;
225 int _count_frames(lua::state& L, lua::parameters& P)
227 portctrl::frame_vector& v = framevector(L, P);
229 L.pushnumber(v.count_frames());
230 return 1;
233 int _find_frame(lua::state& L, lua::parameters& P)
235 uint64_t n;
236 portctrl::frame_vector& v = framevector(L, P);
238 P(n);
240 L.pushnumber(v.find_frame(n));
241 return 1;
244 int _subframe_to_frame(lua::state& L, lua::parameters& P)
246 uint64_t n;
247 portctrl::frame_vector& v = framevector(L, P);
249 P(n);
251 L.pushnumber(v.subframe_to_frame(n));
252 return 1;
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);
261 return 1;
264 int _append_frames(lua::state& L, lua::parameters& P)
266 auto& core = CORE();
267 uint64_t count;
268 portctrl::frame_vector& v = framevector(L, P);
270 P(count);
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();
281 return 0;
284 int _append_frame(lua::state& L, lua::parameters& P)
286 auto& core = CORE();
287 lua_inputframe* f;
288 portctrl::frame_vector& v = framevector(L, P);
290 P(f);
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();
305 return 0;
308 int _truncate(lua::state& L, lua::parameters& P)
310 auto& core = CORE();
311 uint64_t n;
312 portctrl::frame_vector& v = framevector(L, P);
314 P(n);
316 if(n > v.size())
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);
320 v.resize(n);
321 if(&v == core.mlogic->get_mfile().input) {
322 core.supdater->update();
323 core.dispatch->status_update();
325 return 0;
328 int _edit(lua::state& L, lua::parameters& P)
330 auto& core = CORE();
331 uint64_t frame;
332 unsigned port, controller, button;
333 short value;
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);
339 else
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();
350 return 0;
353 template<bool same>
354 int _copy_frames(lua::state& L, lua::parameters& P)
356 auto& core = CORE();
357 uint64_t dst, src, count;
358 bool backwards = same;
360 portctrl::frame_vector& dstv = framevector(L, P);
361 P(dst);
362 portctrl::frame_vector& srcv = same ? dstv : framevector(L, P);
363 P(src, count);
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();
387 return 0;
390 int _serialize(lua::state& L, lua::parameters& P)
392 std::string filename;
393 bool binary;
395 portctrl::frame_vector& v = framevector(L, P);
397 P(filename, binary);
399 std::ofstream file(filename, binary ? std::ios_base::binary : std::ios_base::out);
400 if(!file)
401 throw std::runtime_error("Can't open file to write output to");
402 if(binary) {
403 uint64_t stride = v.get_stride();
404 uint64_t pageframes = v.get_frames_per_page();
405 uint64_t vsize = v.size();
406 size_t pagenum = 0;
407 while(vsize > 0) {
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);
412 vsize -= count;
414 } else {
415 char buf[MAX_SERIALIZED_SIZE];
416 for(uint64_t i = 0; i < v.size(); i++) {
417 v[i].serialize(buf);
418 file << buf << std::endl;
421 return 0;
424 class lua_inputmovie
426 public:
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)
477 return _edit(L, 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++) {
491 v[i].serialize(buf);
492 messages << buf << std::endl;
494 return 0;
496 portctrl::frame_vector* get_frame_vector()
498 return &v;
500 std::string print()
502 size_t s = v.size();
503 return (stringfmt() << s << " " << ((s != 1) ? "frames" : "frame")).str();
505 private:
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)
567 return _edit(L, 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)
587 lua_inputframe* f;
588 std::string filename;
589 bool binary;
591 P(f, filename, binary);
593 std::istream& file = zip::openrel(filename, "");
594 if(!file)
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);
599 if(binary) {
600 uint64_t stride = v.get_stride();
601 uint64_t pageframes = v.get_frames_per_page();
602 uint64_t vsize = 0;
603 size_t pagenum = 0;
604 size_t pagesize = stride * pageframes;
605 while(file) {
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);
611 v.resize(vsize);
612 } else {
613 std::string line;
614 portctrl::frame tmpl = v.blank_frame(false);
615 while(file) {
616 std::getline(file, line);
617 istrip_CR(line);
618 if(line.length() == 0)
619 continue;
620 tmpl.deserialize(line.c_str());
621 v.append(tmpl);
624 return 1;
627 int current_branch(lua::state& L, lua::parameters& P)
629 L.pushlstring(CORE().mlogic->get_mfile().current_branch());
630 return 1;
633 int get_branches(lua::state& L, lua::parameters& P)
635 auto& core = CORE();
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)
643 auto& core = CORE();
644 if(P.is_nil()) {
645 P.skip();
646 return *core.mlogic->get_mfile().input;
647 } else if(P.is_string()) {
648 std::string x;
649 P(x);
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());
655 else
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},
702 {"edit", edit},
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)
713 f = _f;
716 void lua_inputmovie::common_init(lua::state& L)
720 lua_inputmovie::lua_inputmovie(lua::state& L, const portctrl::frame_vector& _v)
722 v = _v;
723 common_init(L);
726 lua_inputmovie::lua_inputmovie(lua::state& L, portctrl::frame& f)
728 v.clear(f.porttypes());
729 common_init(L);