Fix zero luma corner case
[lsnes.git] / src / core / window.cpp
blob038b789daba8f37575b5189aa94b883ac208c024
1 #include "core/command.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/misc.hpp"
4 #include "core/render.hpp"
5 #include "core/window.hpp"
7 #include <fstream>
8 #include <boost/iostreams/categories.hpp>
9 #include <boost/iostreams/copy.hpp>
10 #include <boost/iostreams/stream.hpp>
11 #include <boost/iostreams/stream_buffer.hpp>
12 #include <boost/iostreams/filter/symmetric.hpp>
13 #include <boost/iostreams/filter/zlib.hpp>
14 #include <boost/iostreams/filtering_stream.hpp>
15 #include <boost/iostreams/device/back_inserter.hpp>
17 #define MAXMESSAGES 5000
18 #define INIT_WIN_SIZE 6
21 namespace
23 function_ptr_command<> identify_key("show-plugins", "Show plugins in use",
24 "Syntax: show-plugins\nShows plugins in use.\n",
25 []() throw(std::bad_alloc, std::runtime_error) {
26 window::message(std::string("Graphics:\t") + graphics_plugin_name);
27 window::message(std::string("Sound:\t") + sound_plugin_name);
28 window::message(std::string("Joystick:\t") + joystick_plugin_name);
29 });
31 function_ptr_command<const std::string&> enable_sound("enable-sound", "Enable/Disable sound",
32 "Syntax: enable-sound <on/off>\nEnable or disable sound.\n",
33 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
34 std::string s = args;
35 if(s == "on" || s == "true" || s == "1" || s == "enable" || s == "enabled") {
36 if(!window::sound_initialized())
37 throw std::runtime_error("Sound failed to initialize and is disabled");
38 window::sound_enable(true);
39 } else if(s == "off" || s == "false" || s == "0" || s == "disable" || s == "disabled") {
40 if(window::sound_initialized())
41 window::sound_enable(false);
42 } else
43 throw std::runtime_error("Bad sound setting");
44 });
46 function_ptr_command<const std::string&> set_sound_device("set-sound-device", "Set sound device",
47 "Syntax: set-sound-device <id>\nSet sound device to <id>.\n",
48 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
49 if(!window::sound_initialized())
50 throw std::runtime_error("Sound failed to initialize and is disabled");
51 window::set_sound_device(args);
52 });
54 function_ptr_command<> get_sound_devices("show-sound-devices", "Show sound devices",
55 "Syntax: show-sound-devices\nShow listing of available sound devices\n",
56 []() throw(std::bad_alloc, std::runtime_error) {
57 if(!window::sound_initialized())
58 throw std::runtime_error("Sound failed to initialize and is disabled");
59 auto r = window::get_sound_devices();
60 auto s = window::get_current_sound_device();
61 std::string dname = "unknown";
62 if(r.count(s))
63 dname = r[s];
64 window::out() << "Detected " << r.size() << " sound output devices."
65 << std::endl;
66 for(auto i : r)
67 window::out() << "Audio device " << i.first << ": " << i.second << std::endl;
68 window::out() << "Currently using device " << window::get_current_sound_device() << " ("
69 << dname << ")" << std::endl;
70 });
72 function_ptr_command<> get_sound_status("show-sound-status", "Show sound status",
73 "Syntax: show-sound-status\nShow current sound status\n",
74 []() throw(std::bad_alloc, std::runtime_error) {
75 window::out() << "Sound plugin: " << sound_plugin_name << std::endl;
76 if(!window::sound_initialized())
77 window::out() << "Sound initialization failed, sound disabled" << std::endl;
78 else {
79 auto r = window::get_sound_devices();
80 auto s = window::get_current_sound_device();
81 std::string dname = "unknown";
82 if(r.count(s))
83 dname = r[s];
84 window::out() << "Current sound device " << s << " (" << dname << ")" << std::endl;
86 });
88 std::map<std::string, std::string> emustatus;
90 class window_output
92 public:
93 typedef char char_type;
94 typedef boost::iostreams::sink_tag category;
95 window_output(window* win)
99 void close()
103 std::streamsize write(const char* s, std::streamsize n)
105 size_t oldsize = stream.size();
106 stream.resize(oldsize + n);
107 memcpy(&stream[oldsize], s, n);
108 while(true) {
109 size_t lf = stream.size();
110 for(size_t i = 0; i < stream.size(); i++)
111 if(stream[i] == '\n') {
112 lf = i;
113 break;
115 if(lf == stream.size())
116 break;
117 std::string foo(stream.begin(), stream.begin() + lf);
118 window::message(foo);
119 if(lf + 1 < stream.size())
120 memmove(&stream[0], &stream[lf + 1], stream.size() - lf - 1);
121 stream.resize(stream.size() - lf - 1);
123 return n;
125 protected:
126 std::vector<char> stream;
129 class msgcallback : public messagebuffer::update_handler
131 public:
132 ~msgcallback() throw() {};
133 void messagebuffer_update() throw(std::bad_alloc, std::runtime_error)
135 window::notify_message();
137 } msg_callback_obj;
139 std::ofstream system_log;
140 bool sounds_enabled = true;
143 std::map<std::string, std::string>& window::get_emustatus() throw()
145 return emustatus;
148 void window::sound_enable(bool enable) throw()
150 _sound_enable(enable);
151 sounds_enabled = enable;
152 information_dispatch::do_sound_unmute(enable);
155 void window::set_sound_device(const std::string& dev) throw()
157 try {
158 _set_sound_device(dev);
159 } catch(std::exception& e) {
160 out() << "Error changing sound device: " << e.what() << std::endl;
162 //After failed change, we don't know what is selected.
163 information_dispatch::do_sound_change(get_current_sound_device());
166 bool window::is_sound_enabled() throw()
168 return sounds_enabled;
172 void window::init()
174 msgbuf.register_handler(msg_callback_obj);
175 system_log.open("lsnes.log", std::ios_base::out | std::ios_base::app);
176 time_t curtime = __real_time(NULL);
177 struct tm* tm = localtime(&curtime);
178 char buffer[1024];
179 strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
180 system_log << "-----------------------------------------------------------------------" << std::endl;
181 system_log << "lsnes started at " << buffer << std::endl;
182 system_log << "-----------------------------------------------------------------------" << std::endl;
183 do_init_font();
184 graphics_init();
185 sound_init();
186 joystick_init();
189 void window::quit()
191 joystick_quit();
192 sound_quit();
193 graphics_quit();
194 msgbuf.unregister_handler(msg_callback_obj);
195 time_t curtime = __real_time(NULL);
196 struct tm* tm = localtime(&curtime);
197 char buffer[1024];
198 strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
199 system_log << "-----------------------------------------------------------------------" << std::endl;
200 system_log << "lsnes shutting down at " << buffer << std::endl;
201 system_log << "-----------------------------------------------------------------------" << std::endl;
202 system_log.close();
205 std::ostream& window::out() throw(std::bad_alloc)
207 static std::ostream* cached = NULL;
208 window* win = NULL;
209 if(!cached)
210 cached = new boost::iostreams::stream<window_output>(win);
211 return *cached;
214 messagebuffer window::msgbuf(MAXMESSAGES, INIT_WIN_SIZE);
217 void window::message(const std::string& msg) throw(std::bad_alloc)
219 std::string msg2 = msg;
220 while(msg2 != "") {
221 size_t s = msg2.find_first_of("\n");
222 std::string forlog;
223 if(s >= msg2.length()) {
224 msgbuf.add_message(forlog = msg2);
225 if(system_log)
226 system_log << forlog << std::endl;
227 break;
228 } else {
229 msgbuf.add_message(forlog = msg2.substr(0, s));
230 if(system_log)
231 system_log << forlog << std::endl;
232 msg2 = msg2.substr(s + 1);
237 void window::fatal_error() throw()
239 time_t curtime = __real_time(NULL);
240 struct tm* tm = localtime(&curtime);
241 char buffer[1024];
242 strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
243 system_log << "-----------------------------------------------------------------------" << std::endl;
244 system_log << "lsnes paniced at " << buffer << std::endl;
245 system_log << "-----------------------------------------------------------------------" << std::endl;
246 system_log.close();
247 fatal_error2();
248 exit(1);