Fix some memory leak complaints from Valgrind
[lsnes.git] / src / core / controllerframe.cpp
blob9b3fdecaa5fc93ad05bd3dc76102d1d4bcf3a8ce
1 #include "core/controller.hpp"
2 #include "core/controllerframe.hpp"
3 #include "core/dispatch.hpp"
4 #include "core/misc.hpp"
5 #include "core/moviedata.hpp"
6 #include "interface/romtype.hpp"
8 #include <cstdio>
9 #include <iostream>
11 void update_movie_state();
13 namespace
15 port_type_set dummytypes;
18 controller_state::controller_state() throw()
20 types = &dummytypes;
21 tasinput_enaged = false;
24 std::pair<int,int> controller_state::lcid_to_pcid(unsigned lcid) throw()
26 if(lcid >= types->number_of_controllers())
27 return std::make_pair(-1, -1);
28 auto k = types->lcid_to_pcid(lcid);
29 return std::make_pair(k.first, k.second);
32 std::pair<int, int> controller_state::legacy_pcid_to_pair(unsigned pcid) throw()
34 if(pcid >= types->number_of_legacy_pcids())
35 return std::make_pair(-1, -1);
36 auto k = types->legacy_pcid_to_pair(pcid);
37 return std::make_pair(k.first, k.second);
41 controller_frame controller_state::get(uint64_t framenum) throw()
43 controller_frame tmp = _input ^ _framehold ^ _autohold;
44 for(auto i : _autofire)
45 if(i.second.eval_at(framenum))
46 tmp.axis2(i.first, tmp.axis2(i.first) ^ 1);
47 if(tasinput_enaged)
48 for(auto i : _tasinput) {
49 if(i.second.mode == 0 && i.second.state)
50 tmp.axis2(i.first, tmp.axis2(i.first) ^ 1);
51 else if(i.second.mode == 1)
52 tmp.axis2(i.first, i.second.state);
54 apply_macro(tmp);
55 return tmp;
58 void controller_state::analog(unsigned port, unsigned controller, unsigned control, short x) throw()
60 _input.axis3(port, controller, control, x);
63 void controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
65 _autohold.axis3(port, controller, pbid, newstate ? 1 : 0);
66 notify_autohold_update(port, controller, pbid, newstate);
69 bool controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid) throw()
71 return (_autohold.axis3(port, controller, pbid) != 0);
74 void controller_state::autofire2(unsigned port, unsigned controller, unsigned pbid, unsigned duty, unsigned cyclelen)
75 throw()
77 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
78 if(duty) {
79 _autofire[idx].first_frame = movb.get_movie().get_current_frame();
80 _autofire[idx].duty = duty;
81 _autofire[idx].cyclelen = cyclelen;
82 } else
83 _autofire.erase(idx);
86 std::pair<unsigned, unsigned> controller_state::autofire2(unsigned port, unsigned controller, unsigned pbid) throw()
88 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
89 if(!_autofire.count(idx))
90 return std::make_pair(0, 1);
91 else
92 return std::make_pair(_autofire[idx].duty, _autofire[idx].cyclelen);
95 bool controller_state::autofire_info::eval_at(uint64_t frame)
97 if(frame < first_frame) {
98 uint64_t diff = first_frame - frame;
99 frame += ((diff / cyclelen) + 1) * cyclelen;
101 uint64_t diff2 = frame - first_frame;
102 return frame % cyclelen < duty;
105 void controller_state::reset_framehold() throw()
107 _framehold = _framehold.blank_frame();
110 void controller_state::framehold2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
112 _framehold.axis3(port, controller, pbid, newstate ? 1 : 0);
115 bool controller_state::framehold2(unsigned port, unsigned controller, unsigned pbid) throw()
117 return (_framehold.axis3(port, controller, pbid) != 0);
120 void controller_state::button2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
122 _input.axis3(port, controller, pbid, newstate ? 1 : 0);
125 bool controller_state::button2(unsigned port, unsigned controller, unsigned pbid) throw()
127 return (_input.axis3(port, controller, pbid) != 0);
130 void controller_state::tasinput(unsigned port, unsigned controller, unsigned pbid, int16_t state) throw()
132 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
133 if(!_tasinput.count(idx))
134 _tasinput[idx].mode = 0; //Just to be sure.
135 _tasinput[idx].state = state;
138 int16_t controller_state::tasinput(unsigned port, unsigned controller, unsigned pbid) throw()
140 unsigned idx = _input.porttypes().triple_to_index(port, controller, pbid);
141 return _tasinput.count(idx) ? _tasinput[idx].state : 0;
144 void controller_state::tasinput_enable(bool enabled)
146 tasinput_enaged = enabled;
149 void reread_active_buttons();
151 void controller_state::reread_tasinput_mode(const port_type_set& ptype)
153 unsigned indices = ptype.indices();
154 _tasinput.clear();
155 for(unsigned i = 0; i < indices; i++) {
156 auto t = ptype.index_to_triple(i);
157 if(!t.valid)
158 continue;
159 //See what the heck that is...
160 const port_type& pt = ptype.port_type(t.port);
161 const port_controller_set& pci = *(pt.controller_info);
162 if(pci.controllers.size() <= t.controller)
163 continue;
164 const port_controller& pc = pci.controllers[t.controller];
165 if(pc.buttons.size() <= t.control)
166 continue;
167 const port_controller_button& pcb = pc.buttons[t.control];
168 if(pcb.shadow)
169 continue;
170 if(pcb.type == port_controller_button::TYPE_BUTTON)
171 _tasinput[i].mode = 0;
172 else
173 _tasinput[i].mode = 1;
174 _tasinput[i].state = 0;
178 void controller_state::set_ports(const port_type_set& ptype) throw(std::runtime_error)
180 const port_type_set* oldtype = types;
181 types = &ptype;
182 if(oldtype != types) {
183 _input.set_types(ptype);
184 _autohold.set_types(ptype);
185 _committed.set_types(ptype);
186 _framehold.set_types(ptype);
187 //The old autofire pattern no longer applies.
188 _autofire.clear();
189 reread_tasinput_mode(ptype);
190 _autohold = _autohold.blank_frame();
192 reread_active_buttons();
193 notify_autohold_reconfigure();
196 controller_frame controller_state::get_blank() throw()
198 return _input.blank_frame();
201 controller_frame controller_state::get_committed() throw()
203 return _committed;
206 void controller_state::commit(controller_frame controls) throw()
208 _committed = controls;
211 bool controller_state::is_present(unsigned port, unsigned controller) throw()
213 return _input.is_present(port, controller);
216 void controller_state::erase_macro(const std::string& macro)
219 umutex_class h(macro_lock);
220 if(!all_macros.count(macro))
221 return;
222 auto m = &all_macros[macro];
223 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
224 if(i->second == m) {
225 active_macros.erase(i);
226 break;
229 all_macros.erase(macro);
230 project_info* p = project_get();
231 if(p) {
232 p->macros.erase(macro);
233 p->flush();
236 load_macros(*this);
239 std::set<std::string> controller_state::enumerate_macro()
241 umutex_class h(macro_lock);
242 std::set<std::string> r;
243 for(auto i : all_macros)
244 r.insert(i.first);
245 return r;
248 controller_macro& controller_state::get_macro(const std::string& macro)
250 umutex_class h(macro_lock);
251 if(!all_macros.count(macro))
252 throw std::runtime_error("No such macro");
253 return all_macros[macro];
256 void controller_state::set_macro(const std::string& macro, const controller_macro& m)
259 umutex_class h(macro_lock);
260 controller_macro* old = NULL;
261 if(all_macros.count(macro))
262 old = &all_macros[macro];
263 all_macros[macro] = m;
264 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
265 if(i->second == old) {
266 i->second = &all_macros[macro];
267 break;
270 project_info* p = project_get();
271 if(p) {
272 p->macros[macro] = all_macros[macro].serialize();
273 p->flush();
276 load_macros(*this);
279 void controller_state::apply_macro(controller_frame& f)
281 umutex_class h(macro_lock);
282 for(auto i : active_macros)
283 i.second->write(f, i.first);
286 void controller_state::advance_macros()
288 umutex_class h(macro_lock);
289 for(auto& i : active_macros)
290 i.first++;
293 std::map<std::string, uint64_t> controller_state::get_macro_frames()
295 umutex_class h(macro_lock);
296 std::map<std::string, uint64_t> r;
297 for(auto i : active_macros) {
298 for(auto& j : all_macros)
299 if(i.second == &j.second) {
300 r[j.first] = i.first;
303 return r;
306 void controller_state::set_macro_frames(const std::map<std::string, uint64_t>& f)
308 umutex_class h(macro_lock);
309 std::list<std::pair<uint64_t, controller_macro*>> new_active_macros;
310 for(auto i : f)
311 if(all_macros.count(i.first))
312 new_active_macros.push_back(std::make_pair(i.second, &all_macros[i.first]));
313 else
314 messages << "Warning: Can't find defintion for '" << i.first << "'" << std::endl;
315 std::swap(active_macros, new_active_macros);
318 void controller_state::rename_macro(const std::string& old, const std::string& newn)
321 umutex_class h(macro_lock);
322 if(!all_macros.count(old))
323 throw std::runtime_error("Old macro doesn't exist");
324 if(all_macros.count(newn))
325 throw std::runtime_error("Target name already exists");
326 if(old == newn)
327 return;
328 all_macros[newn] = all_macros[old];
329 controller_macro* _old = &all_macros[old];
330 all_macros.erase(old);
331 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
332 if(i->second == _old) {
333 i->second = &all_macros[newn];
334 break;
337 project_info* p = project_get();
338 if(p) {
339 p->macros[newn] = p->macros[old];
340 p->macros.erase(old);
343 load_macros(*this);
346 void controller_state::do_macro(const std::string& a, int mode) {
348 umutex_class h(macro_lock);
349 if(!all_macros.count(a)) {
350 if(mode & 1) messages << "No such macro '" << a << "'" << std::endl;
351 return;
353 controller_macro* m = &all_macros[a];
354 for(auto i = active_macros.begin(); i != active_macros.end(); i++) {
355 if(i->second == m) {
356 if(mode & 2) active_macros.erase(i);
357 goto end;
360 if(mode & 4) active_macros.push_back(std::make_pair(0, m));
362 end:
363 update_movie_state();
364 notify_status_update();
367 std::set<std::string> controller_state::active_macro_set()
369 umutex_class h(macro_lock);
370 std::set<std::string> r;
371 for(auto i : active_macros) {
372 for(auto& j : all_macros)
373 if(i.second == &j.second) {
374 r.insert(j.first);
377 return r;