Make various instance stuff to take references to other instance objs
[lsnes.git] / src / core / controllerframe.cpp
blobff8127414a96ab9191c33e67f4250431f733ea17
1 #include "core/controller.hpp"
2 #include "core/controllerframe.hpp"
3 #include "core/dispatch.hpp"
4 #include "core/misc.hpp"
5 #include "core/instance.hpp"
6 #include "core/moviedata.hpp"
7 #include "interface/romtype.hpp"
9 #include <cstdio>
10 #include <iostream>
12 void update_movie_state();
14 namespace
16 port_type_set dummytypes;
19 controller_state::controller_state(project_state& _project, movie_logic& _mlogic) throw()
20 : project(_project), mlogic(_mlogic)
22 types = &dummytypes;
23 tasinput_enaged = false;
26 std::pair<int,int> controller_state::lcid_to_pcid(unsigned lcid) throw()
28 if(lcid >= types->number_of_controllers())
29 return std::make_pair(-1, -1);
30 auto k = types->lcid_to_pcid(lcid);
31 return std::make_pair(k.first, k.second);
34 std::pair<int, int> controller_state::legacy_pcid_to_pair(unsigned pcid) throw()
36 if(pcid >= types->number_of_legacy_pcids())
37 return std::make_pair(-1, -1);
38 auto k = types->legacy_pcid_to_pair(pcid);
39 return std::make_pair(k.first, k.second);
43 controller_frame controller_state::get(uint64_t framenum) throw()
45 controller_frame tmp = _input ^ _framehold ^ _autohold;
46 for(auto i : _autofire)
47 if(i.second.eval_at(framenum))
48 tmp.axis2(i.first, tmp.axis2(i.first) ^ 1);
49 if(tasinput_enaged)
50 for(auto i : _tasinput) {
51 if(i.second.mode == 0 && i.second.state)
52 tmp.axis2(i.first, tmp.axis2(i.first) ^ 1);
53 else if(i.second.mode == 1)
54 tmp.axis2(i.first, i.second.state);
56 apply_macro(tmp);
57 return tmp;
60 void controller_state::analog(unsigned port, unsigned controller, unsigned control, short x) throw()
62 _input.axis3(port, controller, control, x);
65 void controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
67 _autohold.axis3(port, controller, pbid, newstate ? 1 : 0);
68 notify_autohold_update(port, controller, pbid, newstate);
71 bool controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid) throw()
73 return (_autohold.axis3(port, controller, pbid) != 0);
76 void controller_state::autofire2(unsigned port, unsigned controller, unsigned pbid, unsigned duty, unsigned cyclelen)
77 throw()
79 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
80 if(duty) {
81 _autofire[idx].first_frame = mlogic.get_movie().get_current_frame();
82 _autofire[idx].duty = duty;
83 _autofire[idx].cyclelen = cyclelen;
84 } else
85 _autofire.erase(idx);
88 std::pair<unsigned, unsigned> controller_state::autofire2(unsigned port, unsigned controller, unsigned pbid) throw()
90 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
91 if(!_autofire.count(idx))
92 return std::make_pair(0, 1);
93 else
94 return std::make_pair(_autofire[idx].duty, _autofire[idx].cyclelen);
97 bool controller_state::autofire_info::eval_at(uint64_t frame)
99 if(frame < first_frame) {
100 uint64_t diff = first_frame - frame;
101 frame += ((diff / cyclelen) + 1) * cyclelen;
103 return frame % cyclelen < duty;
106 void controller_state::reset_framehold() throw()
108 _framehold = _framehold.blank_frame();
111 void controller_state::framehold2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
113 _framehold.axis3(port, controller, pbid, newstate ? 1 : 0);
116 bool controller_state::framehold2(unsigned port, unsigned controller, unsigned pbid) throw()
118 return (_framehold.axis3(port, controller, pbid) != 0);
121 void controller_state::button2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
123 _input.axis3(port, controller, pbid, newstate ? 1 : 0);
126 bool controller_state::button2(unsigned port, unsigned controller, unsigned pbid) throw()
128 return (_input.axis3(port, controller, pbid) != 0);
131 void controller_state::tasinput(unsigned port, unsigned controller, unsigned pbid, int16_t state) throw()
133 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
134 if(!_tasinput.count(idx))
135 _tasinput[idx].mode = 0; //Just to be sure.
136 _tasinput[idx].state = state;
139 int16_t controller_state::tasinput(unsigned port, unsigned controller, unsigned pbid) throw()
141 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
142 return _tasinput.count(idx) ? _tasinput[idx].state : 0;
145 void controller_state::tasinput_enable(bool enabled)
147 tasinput_enaged = enabled;
150 void reread_active_buttons();
152 void controller_state::reread_tasinput_mode(const port_type_set& ptype)
154 unsigned indices = ptype.indices();
155 _tasinput.clear();
156 for(unsigned i = 0; i < indices; i++) {
157 auto t = ptype.index_to_triple(i);
158 if(!t.valid)
159 continue;
160 //See what the heck that is...
161 const port_type& pt = ptype.port_type(t.port);
162 const port_controller_set& pci = *(pt.controller_info);
163 if(pci.controllers.size() <= t.controller)
164 continue;
165 const port_controller& pc = pci.controllers[t.controller];
166 if(pc.buttons.size() <= t.control)
167 continue;
168 const port_controller_button& pcb = pc.buttons[t.control];
169 if(pcb.shadow)
170 continue;
171 if(pcb.type == port_controller_button::TYPE_BUTTON)
172 _tasinput[i].mode = 0;
173 else
174 _tasinput[i].mode = 1;
175 _tasinput[i].state = 0;
179 void controller_state::set_ports(const port_type_set& ptype) throw(std::runtime_error)
181 const port_type_set* oldtype = types;
182 types = &ptype;
183 if(oldtype != types) {
184 _input.set_types(ptype);
185 _autohold.set_types(ptype);
186 _committed.set_types(ptype);
187 _framehold.set_types(ptype);
188 //The old autofire pattern no longer applies.
189 _autofire.clear();
190 reread_tasinput_mode(ptype);
191 _autohold = _autohold.blank_frame();
192 reread_active_buttons();
193 notify_autohold_reconfigure();
197 controller_frame controller_state::get_blank() throw()
199 return _input.blank_frame();
202 controller_frame controller_state::get_committed() throw()
204 return _committed;
207 void controller_state::commit(controller_frame controls) throw()
209 _committed = controls;
212 bool controller_state::is_present(unsigned port, unsigned controller) throw()
214 return _input.is_present(port, controller);
217 void controller_state::erase_macro(const std::string& macro)
220 threads::alock h(macro_lock);
221 if(!all_macros.count(macro))
222 return;
223 auto m = &all_macros[macro];
224 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
225 if(i->second == m) {
226 active_macros.erase(i);
227 break;
230 all_macros.erase(macro);
231 project_info* p = project.get();
232 if(p) {
233 p->macros.erase(macro);
234 p->flush();
237 load_macros(*this);
240 std::set<std::string> controller_state::enumerate_macro()
242 threads::alock h(macro_lock);
243 std::set<std::string> r;
244 for(auto i : all_macros)
245 r.insert(i.first);
246 return r;
249 controller_macro& controller_state::get_macro(const std::string& macro)
251 threads::alock h(macro_lock);
252 if(!all_macros.count(macro))
253 throw std::runtime_error("No such macro");
254 return all_macros[macro];
257 void controller_state::set_macro(const std::string& macro, const controller_macro& m)
260 threads::alock h(macro_lock);
261 controller_macro* old = NULL;
262 if(all_macros.count(macro))
263 old = &all_macros[macro];
264 all_macros[macro] = m;
265 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
266 if(i->second == old) {
267 i->second = &all_macros[macro];
268 break;
271 project_info* p = project.get();
272 if(p) {
273 p->macros[macro] = all_macros[macro].serialize();
274 p->flush();
277 load_macros(*this);
280 void controller_state::apply_macro(controller_frame& f)
282 threads::alock h(macro_lock);
283 for(auto i : active_macros)
284 i.second->write(f, i.first);
287 void controller_state::advance_macros()
289 threads::alock h(macro_lock);
290 for(auto& i : active_macros)
291 i.first++;
294 std::map<std::string, uint64_t> controller_state::get_macro_frames()
296 threads::alock h(macro_lock);
297 std::map<std::string, uint64_t> r;
298 for(auto i : active_macros) {
299 for(auto& j : all_macros)
300 if(i.second == &j.second) {
301 r[j.first] = i.first;
304 return r;
307 void controller_state::set_macro_frames(const std::map<std::string, uint64_t>& f)
309 threads::alock h(macro_lock);
310 std::list<std::pair<uint64_t, controller_macro*>> new_active_macros;
311 for(auto i : f)
312 if(all_macros.count(i.first))
313 new_active_macros.push_back(std::make_pair(i.second, &all_macros[i.first]));
314 else
315 messages << "Warning: Can't find defintion for '" << i.first << "'" << std::endl;
316 std::swap(active_macros, new_active_macros);
319 void controller_state::rename_macro(const std::string& old, const std::string& newn)
322 threads::alock h(macro_lock);
323 if(!all_macros.count(old))
324 throw std::runtime_error("Old macro doesn't exist");
325 if(all_macros.count(newn))
326 throw std::runtime_error("Target name already exists");
327 if(old == newn)
328 return;
329 all_macros[newn] = all_macros[old];
330 controller_macro* _old = &all_macros[old];
331 all_macros.erase(old);
332 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
333 if(i->second == _old) {
334 i->second = &all_macros[newn];
335 break;
338 project_info* p = project.get();
339 if(p) {
340 p->macros[newn] = p->macros[old];
341 p->macros.erase(old);
344 load_macros(*this);
347 void controller_state::do_macro(const std::string& a, int mode) {
349 threads::alock h(macro_lock);
350 if(!all_macros.count(a)) {
351 if(mode & 1) messages << "No such macro '" << a << "'" << std::endl;
352 return;
354 controller_macro* m = &all_macros[a];
355 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
356 if(i->second == m) {
357 if(mode & 2) active_macros.erase(i);
358 goto end;
361 if(mode & 4) active_macros.push_back(std::make_pair(0, m));
363 end:
364 update_movie_state();
365 notify_status_update();
368 std::set<std::string> controller_state::active_macro_set()
370 threads::alock h(macro_lock);
371 std::set<std::string> r;
372 for(auto i : active_macros) {
373 for(auto& j : all_macros)
374 if(i.second == &j.second) {
375 r.insert(j.first);
378 return r;