Make various instance stuff to take references to other instance objs
[lsnes.git] / src / core / multitrack.cpp
blob36ba429a548a9e4f2c0b4186b3afd4fdee29c867
1 #include <string>
2 #include "core/command.hpp"
3 #include "core/controller.hpp"
4 #include "core/dispatch.hpp"
5 #include "core/keymapper.hpp"
6 #include "core/instance.hpp"
7 #include "core/moviedata.hpp"
8 #include "core/multitrack.hpp"
9 #include "lua/internal.hpp"
11 void update_movie_state();
13 multitrack_edit::multitrack_edit(movie_logic& _mlogic, controller_state& _controls)
14 : mlogic(_mlogic), controls(_controls)
18 bool multitrack_edit::is_enabled()
20 return enabled;
23 void multitrack_edit::enable(bool state)
26 threads::alock h(mlock);
27 enabled = state;
28 controllerstate.clear();
30 update_movie_state();
33 void multitrack_edit::set(unsigned port, unsigned controller, state s)
36 threads::alock h(mlock);
37 controllerstate[std::make_pair(port, controller)] = s;
39 update_movie_state();
42 void multitrack_edit::set_and_notify(unsigned port, unsigned controller, state s)
44 if(!mlogic || !mlogic.get_movie().readonly_mode())
45 return;
46 set(port, controller, s);
47 notify_multitrack_change(port, controller, (int)s);
50 void multitrack_edit::rotate(bool forward)
52 if(!mlogic || !mlogic.get_movie().readonly_mode())
53 return;
54 std::vector<std::pair<unsigned, unsigned>> x;
55 for(unsigned i = 0;; i++) {
56 auto pcid = controls.lcid_to_pcid(i);
57 if(pcid.first < 0)
58 break;
59 x.push_back(std::make_pair(pcid.first, pcid.second));
61 auto old_controllerstate = controllerstate;
62 for(unsigned i = 0; i < x.size(); i++) {
63 state s = MT_PRESERVE;
64 if(old_controllerstate.count(x[i]))
65 s = old_controllerstate[x[i]];
66 unsigned i2;
67 if(forward) {
68 i2 = i + 1;
69 if(i2 >= x.size())
70 i2 = 0;
71 } else {
72 i2 = i - 1;
73 if(i2 >= x.size())
74 i2 = x.size() - 1;
76 controllerstate[x[i2]] = s;
77 notify_multitrack_change(x[i2].first, x[i2].second, s);
79 update_movie_state();
82 multitrack_edit::state multitrack_edit::get(unsigned port, unsigned controller)
84 threads::alock h(mlock);
85 auto key = std::make_pair(port, controller);
86 if(controllerstate.count(key))
87 return controllerstate[key];
88 return MT_PRESERVE;
91 void multitrack_edit::config_altered()
93 threads::alock h(mlock);
94 controllerstate.clear();
97 void multitrack_edit::process_frame(controller_frame& input)
99 if(!mlogic || !mlogic.get_movie().readonly_mode())
100 return;
101 threads::alock h(mlock);
102 bool any_need = false;
103 if(!enabled)
104 return;
105 for(auto i : controllerstate)
106 any_need = any_need || (i.second != MT_PRESERVE);
107 if(!any_need)
108 return; //No need to twiddle.
109 unsigned indices = input.get_index_count();
110 const port_type_set& portset = input.porttypes();
111 pollcounter_vector& p = mlogic.get_movie().get_pollcounters();
112 for(unsigned i = 0; i < indices; i++) {
113 port_index_triple t = portset.index_to_triple(i);
114 if(!t.valid)
115 continue;
116 auto key = std::make_pair(t.port, t.controller);
117 uint32_t pc = p.get_polls(i);
118 if(!controllerstate.count(key) || controllerstate[key] == MT_PRESERVE || (!t.port && !t.controller)) {
119 int16_t v = mlogic.get_movie().read_subframe_at_index(pc, t.port, t.controller,
120 t.control);
121 input.axis3(t.port, t.controller, t.control, v);
122 } else {
123 int16_t v = mlogic.get_movie().read_subframe_at_index(pc, t.port, t.controller,
124 t.control);
125 controllerstate[key];
126 const port_type& pt = portset.port_type(t.port);
127 auto pci = pt.controller_info->get(t.controller);
128 auto pb = pci ? pci->get(t.control) : NULL;
129 bool is_axis = (pb && pb->is_analog());
130 switch(controllerstate[key]) {
131 case MT_OR:
132 if(is_axis) {
133 int16_t v2 = input.axis3(t.port, t.controller, t.control);
134 if(v2)
135 v = v2;
136 } else
137 v |= input.axis3(t.port, t.controller, t.control);
138 break;
139 case MT_OVERWRITE:
140 v = input.axis3(t.port, t.controller, t.control);
141 break;
142 case MT_PRESERVE:
143 //No-op.
144 break;
145 case MT_XOR:
146 if(is_axis) {
147 int16_t v2 = input.axis3(t.port, t.controller, t.control);
148 if(v2)
149 v = v2;
150 } else
151 v ^= input.axis3(t.port, t.controller, t.control);
152 break;
154 mlogic.get_movie().write_subframe_at_index(pc, t.port, t.controller, t.control,
156 v = mlogic.get_movie().read_subframe_at_index(pc, t.port, t.controller,
157 t.control);
158 input.axis3(t.port, t.controller, t.control, v);
163 bool multitrack_edit::any_records()
165 if(!mlogic || !mlogic.get_movie().readonly_mode())
166 return true;
167 threads::alock h(mlock);
168 bool any_need = false;
169 for(auto i : controllerstate)
170 any_need = any_need || (i.second != MT_PRESERVE);
171 return any_need;
174 namespace
176 command::fnptr<> rotate_forward(lsnes_cmds, "rotate-multitrack", "Rotate multitrack",
177 "Syntax: rotate-multitrack\nRotate multitrack\n",
178 []() throw(std::bad_alloc, std::runtime_error) {
179 CORE().mteditor.rotate(true);
180 update_movie_state();
183 command::fnptr<> rotate_backward(lsnes_cmds, "rotate-multitrack-backwards", "Rotate multitrack backwards",
184 "Syntax: rotate-multitrack-backwards\nRotate multitrack backwards\n",
185 []() throw(std::bad_alloc, std::runtime_error) {
186 CORE().mteditor.rotate(false);
187 update_movie_state();
190 command::fnptr<const std::string&> set_mt(lsnes_cmds, "set-multitrack", "Set multitrack mode",
191 "Syntax: set-multitrack <controller> <mode>\nSet multitrack mode\n",
192 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
193 regex_results r = regex("(.*)[ \t]+(.*)", args);
194 if(!r)
195 throw std::runtime_error("Bad arguments");
196 auto c = controller_by_name(r[1]);
197 if(c.first < 0)
198 throw std::runtime_error("No such controller");
199 if(r[2] == "keep")
200 CORE().mteditor.set_and_notify(c.first, c.second, multitrack_edit::MT_PRESERVE);
201 else if(r[2] == "rewrite")
202 CORE().mteditor.set_and_notify(c.first, c.second, multitrack_edit::MT_OVERWRITE);
203 else if(r[2] == "or")
204 CORE().mteditor.set_and_notify(c.first, c.second, multitrack_edit::MT_OR);
205 else if(r[2] == "xor")
206 CORE().mteditor.set_and_notify(c.first, c.second, multitrack_edit::MT_XOR);
207 else
208 throw std::runtime_error("Invalid mode (keep, rewrite, or, xor)");
209 update_movie_state();
212 keyboard::invbind_info _mtback(lsnes_invbinds, "rotate-multitrack-backwards",
213 "Multitrack‣Rotate backwards");
214 keyboard::invbind_info _mtfwd(lsnes_invbinds, "rotate-multitrack", "Multitrack‣Rotate forward");
216 int multitrack_state(lua::state& L, lua::parameters& P)
218 unsigned port, controller;
220 P(port, controller);
222 auto s = CORE().mteditor.get(port, controller);
223 switch(s) {
224 case multitrack_edit::MT_OR:
225 L.pushstring("or");
226 return 1;
227 case multitrack_edit::MT_OVERWRITE:
228 L.pushstring("rewrite");
229 return 1;
230 case multitrack_edit::MT_PRESERVE:
231 L.pushstring("keep");
232 return 1;
233 case multitrack_edit::MT_XOR:
234 L.pushstring("xor");
235 return 1;
236 default:
237 return 0;
241 lua::functions mtfn(lua_func_misc, "input", {
242 {"multitrack_state", multitrack_state},