Cleanup lua code by introducing lua::functions
[lsnes.git] / src / lua / inputmovie.cpp
blobca71de926ebdfcccef6128db46f0e1a1dd7168d4
1 #include "lua/internal.hpp"
2 #include "library/string.hpp"
3 #include "library/minmax.hpp"
4 #include "core/movie.hpp"
5 #include "core/moviedata.hpp"
6 #include "core/window.hpp"
7 #include <fstream>
9 void update_movie_state();
11 namespace
13 class lua_inputmovie;
15 class lua_inputframe
17 friend class lua_inputmovie;
18 public:
19 lua_inputframe(lua::state& L, controller_frame _f);
20 int get_button(lua::state& L, lua::parameters& P)
22 unsigned port, controller, button;
24 P(P.skipped(), port, controller, button);
26 short value = getbutton(port, controller, button);
27 L.pushboolean(value ? 1 : 0);
28 return 1;
30 int get_axis(lua::state& L, lua::parameters& P)
32 unsigned port, controller, button;
34 P(P.skipped(), port, controller, button);
36 short value = getbutton(port, controller, button);
37 L.pushnumber(value);
38 return 1;
40 int set_axis(lua::state& L, lua::parameters& P)
42 unsigned port, controller, button;
43 short value;
45 P(P.skipped(), port, controller, button);
46 if(P.is_boolean()) value = P.arg<bool>() ? 1 : 0;
47 else if(P.is_number()) value = P.arg<short>();
48 else
49 P.expected("number or boolean");
51 setbutton(port, controller, button, value);
52 return 0;
54 int serialize(lua::state& L, lua::parameters& P)
56 char buf[MAX_SERIALIZED_SIZE];
57 f.serialize(buf);
58 L.pushstring(buf);
59 return 1;
61 int unserialize(lua::state& L, lua::parameters& P)
63 std::string buf;
65 P(P.skipped(), buf);
67 f.deserialize(buf.c_str());
68 return 0;
70 int get_stride(lua::state& L, lua::parameters& P)
72 L.pushnumber(f.size());
73 return 1;
75 controller_frame& get_frame()
77 return f;
79 std::string print()
81 char buf[MAX_SERIALIZED_SIZE];
82 f.serialize(buf);
83 return buf;
85 private:
86 short getbutton(unsigned port, unsigned controller, unsigned index)
88 return f.axis3(port, controller, index);
90 void setbutton(unsigned port, unsigned controller, unsigned index, short value)
92 return f.axis3(port, controller, index, value);
94 controller_frame f;
97 int32_t get_pc_for(unsigned port, unsigned controller, unsigned button, bool extra0 = false);
98 int32_t get_pc_for(unsigned port, unsigned controller, unsigned button, bool extra0)
100 movie& m = movb.get_movie();
101 if(port == 0 && controller == 0 && button == 0)
102 return m.get_pollcounters().max_polls() + (extra0 ? 1 : 0);
103 if(port == 0 && controller == 0 && m.get_pollcounters().get_framepflag())
104 return max(m.get_pollcounters().get_polls(port, controller, button), (uint32_t)1);
105 return m.get_pollcounters().get_polls(port, controller, button);
108 void check_can_edit(unsigned port, unsigned controller, unsigned button, uint64_t frame,
109 bool allow_past_end = false);
111 void check_can_edit(unsigned port, unsigned controller, unsigned button, uint64_t frame,
112 bool allow_past_end)
114 movie& m = movb.get_movie();
115 if(!m.readonly_mode())
116 throw std::runtime_error("Not in read-only mode");
117 if(!allow_past_end && frame >= movb.get_mfile().input->size())
118 throw std::runtime_error("Index out of movie");
119 int32_t pc = get_pc_for(port, controller, button, true);
120 if(pc < 0)
121 throw std::runtime_error("Invalid control to edit");
122 uint64_t firstframe = m.get_current_frame_first_subframe();
123 uint64_t minframe = firstframe + pc;
124 uint64_t msize = movb.get_mfile().input->size();
125 if(minframe > msize || firstframe >= msize)
126 throw std::runtime_error("Can not edit finished movie");
127 if(frame < minframe)
128 throw std::runtime_error("Can not edit past");
131 int current_first_subframe(lua::state& L, lua::parameters& P)
133 movie& m = movb.get_movie();
134 L.pushnumber(m.get_current_frame_first_subframe());
135 return 1;
138 int pollcounter(lua::state& L, lua::parameters& P)
140 unsigned port, controller, button;
142 P(port, controller, button);
144 uint32_t ret = 0;
145 ret = get_pc_for(port, controller, button);
146 L.pushnumber(ret);
147 return 1;
150 controller_frame_vector& framevector(lua::state& L, lua::parameters& P);
152 int _copy_movie(lua::state& L, lua::parameters& P)
154 controller_frame_vector& v = framevector(L, P);
156 lua_inputmovie* m = lua::_class<lua_inputmovie>::create(L, v);
157 return 1;
160 int _get_frame(lua::state& L, lua::parameters& P)
162 uint64_t n;
163 controller_frame_vector& v = framevector(L, P);
165 P(n);
167 if(n >= v.size())
168 throw std::runtime_error("Requested frame outside movie");
169 controller_frame _f = v[n];
170 lua_inputframe* f = lua::_class<lua_inputframe>::create(L, _f);
171 return 1;
174 int _set_frame(lua::state& L, lua::parameters& P)
176 uint64_t n;
177 lua_inputframe* f;
178 controller_frame_vector& v = framevector(L, P);
180 P(n, f);
182 if(n >= v.size())
183 throw std::runtime_error("Requested frame outside movie");
184 //Checks if requested frame is from movie.
185 if(&v == movb.get_mfile().input)
186 check_can_edit(0, 0, 0, n);
188 v[n] = f->get_frame();
190 if(&v == movb.get_mfile().input) {
191 //This can't add frames, so no need to adjust the movie.
192 update_movie_state();
193 platform::notify_status();
195 return 0;
198 int _get_size(lua::state& L, lua::parameters& P)
200 int ptr = 1;
201 controller_frame_vector& v = framevector(L, P);
203 L.pushnumber(v.size());
204 return 1;
207 int _count_frames(lua::state& L, lua::parameters& P)
209 int ptr = 1;
210 controller_frame_vector& v = framevector(L, P);
212 L.pushnumber(v.count_frames());
213 return 1;
216 int _find_frame(lua::state& L, lua::parameters& P)
218 uint64_t n;
219 controller_frame_vector& v = framevector(L, P);
221 P(n);
223 if(!n) {
224 L.pushnumber(-1);
225 return 1;
227 uint64_t c = 0;
228 uint64_t s = v.size();
229 for(uint64_t i = 0; i < s; i++)
230 if(v[i].sync() && ++c == n) {
231 L.pushnumber(i);
232 return 1;
234 L.pushnumber(-1);
235 return 1;
238 int _blank_frame(lua::state& L, lua::parameters& P)
240 int ptr = 1;
241 controller_frame_vector& v = framevector(L, P);
243 controller_frame _f = v.blank_frame(true);
244 lua_inputframe* f = lua::_class<lua_inputframe>::create(L, _f);
245 return 1;
248 int _append_frames(lua::state& L, lua::parameters& P)
250 uint64_t count;
251 controller_frame_vector& v = framevector(L, P);
253 P(count);
256 controller_frame_vector::notify_freeze freeze(v);
257 for(uint64_t i = 0; i < count; i++)
258 v.append(v.blank_frame(true));
260 if(&v == movb.get_mfile().input) {
261 update_movie_state();
262 platform::notify_status();
264 return 0;
267 int _append_frame(lua::state& L, lua::parameters& P)
269 lua_inputframe* f;
270 controller_frame_vector& v = framevector(L, P);
272 P(f);
274 v.append(v.blank_frame(true));
275 if(&v == movb.get_mfile().input) {
276 update_movie_state();
277 platform::notify_status();
278 check_can_edit(0, 0, 0, v.size() - 1);
280 v[v.size() - 1] = f->get_frame();
281 if(&v == movb.get_mfile().input) {
282 if(!v[v.size() - 1].sync()) {
283 update_movie_state();
285 platform::notify_status();
287 return 0;
290 int _truncate(lua::state& L, lua::parameters& P)
292 uint64_t n;
293 controller_frame_vector& v = framevector(L, P);
295 P(n);
297 if(n > v.size())
298 throw std::runtime_error("Requested truncate length longer than existing");
299 if(&v == movb.get_mfile().input)
300 check_can_edit(0, 0, 0, n);
301 v.resize(n);
302 if(&v == movb.get_mfile().input) {
303 update_movie_state();
304 platform::notify_status();
306 return 0;
309 int _edit(lua::state& L, lua::parameters& P)
311 uint64_t frame;
312 unsigned port, controller, button;
313 short value;
314 controller_frame_vector& v = framevector(L, P);
316 P(frame, port, controller, button);
317 if(P.is_boolean()) value = P.arg<bool>() ? 1 : 0;
318 else if(P.is_number()) P(value);
319 else
320 P.expected("number or boolean");
322 movie& m = movb.get_movie();
323 if(&v == movb.get_mfile().input)
324 check_can_edit(port, controller, button, frame);
325 v[frame].axis3(port, controller, button, value);
327 if(&v == movb.get_mfile().input) {
328 update_movie_state();
329 platform::notify_status();
331 return 0;
334 template<bool same>
335 int _copy_frames(lua::state& L, lua::parameters& P)
337 uint64_t dst, src, count;
338 bool backwards = same;
340 controller_frame_vector& dstv = framevector(L, P);
341 P(dst);
342 controller_frame_vector& srcv = same ? dstv : framevector(L, P);
343 P(src, count);
344 if(same) P(backwards);
346 if(src >= srcv.size() || src + count < src)
347 throw std::runtime_error("Source index out of movie");
348 if(dst > dstv.size() || dst + count < dst)
349 throw std::runtime_error("Destination index out of movie");
351 movie& m = movb.get_movie();
352 if(&dstv == movb.get_mfile().input)
353 check_can_edit(0, 0, 0, dst, true);
356 controller_frame_vector::notify_freeze freeze(dstv);
357 //Add enough blank frames to make the copy.
358 while(dst + count > dstv.size())
359 dstv.append(dstv.blank_frame(false));
361 for(uint64_t i = backwards ? (count - 1) : 0; i < count; i = backwards ? (i - 1) : (i + 1))
362 dstv[dst + i] = srcv[src + i];
364 if(&dstv == movb.get_mfile().input) {
365 update_movie_state();
366 platform::notify_status();
368 return 0;
371 int _serialize(lua::state& L, lua::parameters& P)
373 std::string filename;
374 bool binary;
376 controller_frame_vector& v = framevector(L, P);
378 P(filename, binary);
380 std::ofstream file(filename, binary ? std::ios_base::binary : std::ios_base::out);
381 if(!file)
382 throw std::runtime_error("Can't open file to write output to");
383 if(binary) {
384 uint64_t pages = v.get_page_count();
385 uint64_t stride = v.get_stride();
386 uint64_t pageframes = v.get_frames_per_page();
387 uint64_t vsize = v.size();
388 size_t pagenum = 0;
389 while(vsize > 0) {
390 uint64_t count = (vsize > pageframes) ? pageframes : vsize;
391 size_t bytes = count * stride;
392 unsigned char* content = v.get_page_buffer(pagenum++);
393 file.write(reinterpret_cast<char*>(content), bytes);
394 vsize -= count;
396 } else {
397 char buf[MAX_SERIALIZED_SIZE];
398 for(uint64_t i = 0; i < v.size(); i++) {
399 v[i].serialize(buf);
400 file << buf << std::endl;
403 return 0;
406 class lua_inputmovie
408 public:
409 lua_inputmovie(lua::state& L, const controller_frame_vector& _v);
410 lua_inputmovie(lua::state& L, controller_frame& _f);
411 int copy_movie(lua::state& L, lua::parameters& P)
413 return _copy_movie(L, P);
415 int get_frame(lua::state& L, lua::parameters& P)
417 return _get_frame(L, P);
419 int set_frame(lua::state& L, lua::parameters& P)
421 return _set_frame(L, P);
423 int get_size(lua::state& L, lua::parameters& P)
425 return _get_size(L, P);
427 int count_frames(lua::state& L, lua::parameters& P)
429 return _count_frames(L, P);
431 int find_frame(lua::state& L, lua::parameters& P)
433 return _find_frame(L, P);
435 int blank_frame(lua::state& L, lua::parameters& P)
437 return _blank_frame(L, P);
439 int append_frames(lua::state& L, lua::parameters& P)
441 return _append_frames(L, P);
443 int append_frame(lua::state& L, lua::parameters& P)
445 return _append_frame(L, P);
447 int truncate(lua::state& L, lua::parameters& P)
449 return _truncate(L, P);
451 int edit(lua::state& L, lua::parameters& P)
453 return _edit(L, P);
455 int copy_frames(lua::state& L, lua::parameters& P)
457 return _copy_frames<true>(L, P);
459 int serialize(lua::state& L, lua::parameters& P)
461 return _serialize(L, P);
463 int debugdump(lua::state& L, lua::parameters& P)
465 char buf[MAX_SERIALIZED_SIZE];
466 for(uint64_t i = 0; i < v.size(); i++) {
467 v[i].serialize(buf);
468 messages << buf << std::endl;
470 return 0;
472 controller_frame_vector* get_frame_vector()
474 return &v;
476 std::string print()
478 size_t s = v.size();
479 return (stringfmt() << s << " " << ((s != 1) ? "frames" : "frame")).str();
481 private:
482 void common_init(lua::state& L);
483 controller_frame_vector v;
486 int copy_movie(lua::state& L, lua::parameters& P)
488 return _copy_movie(L, P);
491 int get_frame(lua::state& L, lua::parameters& P)
493 return _get_frame(L, P);
496 int set_frame(lua::state& L, lua::parameters& P)
498 return _set_frame(L, P);
501 int get_size(lua::state& L, lua::parameters& P)
503 return _get_size(L, P);
506 int count_frames(lua::state& L, lua::parameters& P)
508 return _count_frames(L, P);
511 int find_frame(lua::state& L, lua::parameters& P)
513 return _find_frame(L, P);
516 int blank_frame(lua::state& L, lua::parameters& P)
518 return _blank_frame(L, P);
521 int append_frames(lua::state& L, lua::parameters& P)
523 return _append_frames(L, P);
526 int append_frame(lua::state& L, lua::parameters& P)
528 return _append_frame(L, P);
531 int truncate(lua::state& L, lua::parameters& P)
533 return _truncate(L, P);
536 int edit(lua::state& L, lua::parameters& P)
538 return _edit(L, P);
541 int copy_frames2(lua::state& L, lua::parameters& P)
543 return _copy_frames<false>(L, P);
546 int copy_frames(lua::state& L, lua::parameters& P)
548 return _copy_frames<true>(L, P);
551 int serialize(lua::state& L, lua::parameters& P)
553 return _serialize(L, P);
556 int unserialize(lua::state& L, lua::parameters& P)
558 lua_inputframe* f;
559 std::string filename;
560 bool binary;
562 P(f, filename, binary);
564 std::ifstream file(filename, binary ? std::ios_base::binary : std::ios_base::in);
565 if(!file)
566 throw std::runtime_error("Can't open file to read input from");
567 lua_inputmovie* m = lua::_class<lua_inputmovie>::create(L, f->get_frame());
568 controller_frame_vector& v = *m->get_frame_vector();
569 controller_frame_vector::notify_freeze freeze(v);
570 if(binary) {
571 uint64_t stride = v.get_stride();
572 uint64_t pageframes = v.get_frames_per_page();
573 uint64_t vsize = 0;
574 size_t pagenum = 0;
575 size_t pagesize = stride * pageframes;
576 while(file) {
577 v.resize(vsize + pageframes);
578 unsigned char* contents = v.get_page_buffer(pagenum++);
579 file.read(reinterpret_cast<char*>(contents), pagesize);
580 vsize += (file.gcount() / stride);
582 v.resize(vsize);
583 } else {
584 std::string line;
585 controller_frame tmpl = v.blank_frame(false);
586 while(file) {
587 std::getline(file, line);
588 istrip_CR(line);
589 if(line.length() == 0)
590 continue;
591 tmpl.deserialize(line.c_str());
592 v.append(tmpl);
595 return 1;
598 int current_branch(lua::state& L, lua::parameters& P)
600 L.pushlstring(movb.get_mfile().current_branch());
601 return 1;
604 int get_branches(lua::state& L, lua::parameters& P)
606 for(auto& i : movb.get_mfile().branches)
607 L.pushlstring(i.first);
608 return movb.get_mfile().branches.size();
611 controller_frame_vector& framevector(lua::state& L, lua::parameters& P)
613 if(P.is_nil()) {
614 P.skip();
615 return *movb.get_mfile().input;
616 } else if(P.is_string()) {
617 std::string x;
618 P(x);
619 if(!movb.get_mfile().branches.count(x))
620 throw std::runtime_error("No such branch");
621 return movb.get_mfile().branches[x];
622 } else if(P.is<lua_inputmovie>())
623 return *(P.arg<lua_inputmovie*>()->get_frame_vector());
624 else
625 return *movb.get_mfile().input;
628 lua::_class<lua_inputmovie> class_inputmovie(lua_class_movie, "INPUTMOVIE", {}, {
629 {"copy_movie", &lua_inputmovie::copy_movie},
630 {"get_frame", &lua_inputmovie::get_frame},
631 {"set_frame", &lua_inputmovie::set_frame},
632 {"get_size", &lua_inputmovie::get_size},
633 {"count_frames", &lua_inputmovie::count_frames},
634 {"find_frame", &lua_inputmovie::find_frame},
635 {"blank_frame", &lua_inputmovie::blank_frame},
636 {"append_frames", &lua_inputmovie::append_frames},
637 {"append_frame", &lua_inputmovie::append_frame},
638 {"truncate", &lua_inputmovie::truncate},
639 {"edit", &lua_inputmovie::edit},
640 {"debugdump", &lua_inputmovie::debugdump},
641 {"copy_frames", &lua_inputmovie::copy_frames},
642 {"serialize", &lua_inputmovie::serialize},
643 }, &lua_inputmovie::print);
645 lua::_class<lua_inputframe> class_inputframe(lua_class_movie, "INPUTFRAME", {}, {
646 {"get_button", &lua_inputframe::get_button},
647 {"get_axis", &lua_inputframe::get_axis},
648 {"set_axis", &lua_inputframe::set_axis},
649 {"set_button", &lua_inputframe::set_axis},
650 {"serialize", &lua_inputframe::serialize},
651 {"unserialize", &lua_inputframe::unserialize},
652 {"get_stride", &lua_inputframe::get_stride},
653 }, &lua_inputframe::print);
655 lua::functions inputmovie_fns(lua_func_misc, "movie", {
656 {"current_first_subframe", current_first_subframe},
657 {"pollcounter", pollcounter},
658 {"copy_movie", copy_movie},
659 {"get_frame", get_frame},
660 {"set_frame", set_frame},
661 {"get_size", get_size},
662 {"count_frames", count_frames},
663 {"find_frame", find_frame},
664 {"blank_frame", blank_frame},
665 {"append_frames", append_frames},
666 {"append_frame", append_frame},
667 {"truncate", truncate},
668 {"edit", edit},
669 {"copy_frames2", copy_frames2},
670 {"copy_frames", copy_frames},
671 {"serialize", serialize},
672 {"unserialize", unserialize},
673 {"current_branch", current_branch},
674 {"get_branches", get_branches},
677 lua_inputframe::lua_inputframe(lua::state& L, controller_frame _f)
679 f = _f;
682 void lua_inputmovie::common_init(lua::state& L)
686 lua_inputmovie::lua_inputmovie(lua::state& L, const controller_frame_vector& _v)
688 v = _v;
689 common_init(L);
692 lua_inputmovie::lua_inputmovie(lua::state& L, controller_frame& f)
694 v.clear(f.porttypes());
695 common_init(L);