Fix SA1 open bus
[lsnes.git] / src / core / framebuffer.cpp
blobc30b422c5eaef3e55798630b2a3d7dd162ca452f
1 #include "core/command.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/framebuffer.hpp"
4 #include "core/keymapper.hpp"
5 #include "core/memorywatch.hpp"
6 #include "core/misc.hpp"
7 #include "core/moviedata.hpp"
8 #include "core/moviefile.hpp"
9 #include "core/subtitles.hpp"
10 #include "core/settings.hpp"
11 #include "core/window.hpp"
12 #include "lua/lua.hpp"
13 #include "fonts/wrapper.hpp"
14 #include "library/framebuffer.hpp"
15 #include "library/framebuffer-pixfmt-lrgb.hpp"
16 #include "library/minmax.hpp"
17 #include "library/triplebuffer.hpp"
19 framebuffer::raw screen_corrupt;
20 void update_movie_state();
22 namespace
24 struct render_info
26 framebuffer::raw fbuf;
27 framebuffer::queue rq;
28 uint32_t hscl;
29 uint32_t vscl;
30 uint32_t lgap;
31 uint32_t rgap;
32 uint32_t tgap;
33 uint32_t bgap;
36 render_info buffer1;
37 render_info buffer2;
38 render_info buffer3;
39 triplebuffer::triplebuffer<render_info> buffering(buffer1, buffer2, buffer3);
41 struct render_list_entry
43 uint32_t codepoint;
44 uint32_t x;
45 uint32_t y;
46 uint32_t scale;
49 struct render_list_entry rl_corrupt[] = {
50 {'S', 88, 56, 7},
51 {'Y', 144, 56, 7},
52 {'S', 200, 56, 7},
53 {'T', 256, 56, 7},
54 {'E', 312, 56, 7},
55 {'M', 368, 56, 7},
56 {'S', 116, 168, 7},
57 {'T', 172, 168, 7},
58 {'A', 224, 168, 7},
59 {'T', 280, 168, 7},
60 {'E', 336, 168, 7},
61 {'C', 60, 280, 7},
62 {'O', 116, 280, 7},
63 {'R', 172, 280, 7},
64 {'R', 228, 280, 7},
65 {'U', 284, 280, 7},
66 {'P', 340, 280, 7},
67 {'T', 396, 280, 7},
68 {0, 0, 0, 0}
71 void draw_special_screen(uint32_t* target, struct render_list_entry* rlist)
73 while(rlist->scale) {
74 auto g = main_font.get_glyph(rlist->codepoint);
75 for(uint32_t j = 0; j < 16; j++) {
76 for(uint32_t i = 0; i < (g.wide ? 16 : 8); i++) {
77 uint32_t slice = g.data[j / (g.wide ? 2 : 4)];
78 uint32_t bit = 31 - ((j % (g.wide ? 2 : 4)) * (g.wide ? 16 : 8) + i);
79 uint32_t value = (slice >> bit) & 1;
80 if(value) {
81 uint32_t basex = rlist->x + rlist->scale * i;
82 uint32_t basey = rlist->y + rlist->scale * j;
83 for(uint32_t j2 = 0; j2 < rlist->scale; j2++)
84 for(uint32_t i2 = 0; i2 < rlist->scale; i2++)
85 target[(basey + j2) * 512 + (basex + i2)] = 0x7FFFF;
89 rlist++;
93 void draw_corrupt(uint32_t* target)
95 for(unsigned i = 0; i < 512 * 448; i++)
96 target[i] = 0x7FC00;
97 draw_special_screen(target, rl_corrupt);
100 command::fnptr<command::arg_filename> take_screenshot_cmd(lsnes_cmd, "take-screenshot", "Takes a screenshot",
101 "Syntax: take-screenshot <file>\nSaves screenshot to PNG file <file>\n",
102 [](command::arg_filename file) throw(std::bad_alloc, std::runtime_error) {
103 take_screenshot(file);
104 messages << "Saved PNG screenshot" << std::endl;
107 settingvar::variable<settingvar::model_int<0, 8191>> dtb(lsnes_vset, "top-border", "UI‣Top padding", 0);
108 settingvar::variable<settingvar::model_int<0, 8191>> dbb(lsnes_vset, "bottom-border",
109 "UI‣Bottom padding", 0);
110 settingvar::variable<settingvar::model_int<0, 8191>> dlb(lsnes_vset, "left-border",
111 "UI‣Left padding", 0);
112 settingvar::variable<settingvar::model_int<0, 8191>> drb(lsnes_vset, "right-border", "UI‣Right padding",
115 bool last_redraw_no_lua = false;
118 framebuffer::fb<false> main_screen;
120 void take_screenshot(const std::string& file) throw(std::bad_alloc, std::runtime_error)
122 render_info& ri = buffering.get_read();
123 ri.fbuf.save_png(file);
124 buffering.put_read();
128 void init_special_screens() throw(std::bad_alloc)
130 std::vector<uint32_t> buf;
131 buf.resize(512*448);
133 framebuffer::info inf;
134 inf.type = &framebuffer::pixfmt_lrgb;
135 inf.mem = reinterpret_cast<char*>(&buf[0]);
136 inf.physwidth = 512;
137 inf.physheight = 448;
138 inf.physstride = 2048;
139 inf.width = 512;
140 inf.height = 448;
141 inf.stride = 2048;
142 inf.offset_x = 0;
143 inf.offset_y = 0;
145 draw_corrupt(&buf[0]);
146 screen_corrupt = framebuffer::raw(inf);
149 void redraw_framebuffer(framebuffer::raw& todraw, bool no_lua, bool spontaneous)
151 uint32_t hscl, vscl;
152 auto g = our_rom.rtype->get_scale_factors(todraw.get_width(), todraw.get_height());
153 hscl = g.first;
154 vscl = g.second;
155 render_info& ri = buffering.get_write();
156 ri.rq.clear();
157 struct lua_render_context lrc;
158 lrc.left_gap = 0;
159 lrc.right_gap = 0;
160 lrc.bottom_gap = 0;
161 lrc.top_gap = 0;
162 lrc.queue = &ri.rq;
163 lrc.width = todraw.get_width() * hscl;
164 lrc.height = todraw.get_height() * vscl;
165 if(!no_lua) {
166 lua_callback_do_paint(&lrc, spontaneous);
167 render_subtitles(lrc);
169 ri.fbuf = todraw;
170 ri.hscl = hscl;
171 ri.vscl = vscl;
172 ri.lgap = max(lrc.left_gap, (unsigned)dlb);
173 ri.rgap = max(lrc.right_gap, (unsigned)drb);
174 ri.tgap = max(lrc.top_gap, (unsigned)dtb);
175 ri.bgap = max(lrc.bottom_gap, (unsigned)dbb);
176 lsnes_memorywatch.watch(ri.rq);
177 buffering.put_write();
178 notify_screen_update();
179 last_redraw_no_lua = no_lua;
180 update_movie_state();
183 void redraw_framebuffer()
185 render_info& ri = buffering.get_read();
186 framebuffer::raw copy = ri.fbuf;
187 buffering.put_read();
188 //Redraws are never spontaneous
189 redraw_framebuffer(copy, last_redraw_no_lua, false);
192 void render_framebuffer()
194 render_info& ri = buffering.get_read();
195 main_screen.reallocate(ri.fbuf.get_width() * ri.hscl + ri.lgap + ri.rgap, ri.fbuf.get_height() * ri.vscl +
196 ri.tgap + ri.bgap);
197 main_screen.set_origin(ri.lgap, ri.tgap);
198 main_screen.copy_from(ri.fbuf, ri.hscl, ri.vscl);
199 ri.rq.run(main_screen);
200 notify_set_screen(main_screen);
201 //We would want divide by 2, but we'll do it ourselves in order to do mouse.
202 keyboard::key* mouse_x = lsnes_kbd.try_lookup_key("mouse_x");
203 keyboard::key* mouse_y = lsnes_kbd.try_lookup_key("mouse_y");
204 keyboard::mouse_calibration xcal;
205 keyboard::mouse_calibration ycal;
206 xcal.offset = ri.lgap;
207 ycal.offset = ri.tgap;
208 if(mouse_x && mouse_x->get_type() == keyboard::KBD_KEYTYPE_MOUSE)
209 mouse_x->cast_mouse()->set_calibration(xcal);
210 if(mouse_y && mouse_y->get_type() == keyboard::KBD_KEYTYPE_MOUSE)
211 mouse_y->cast_mouse()->set_calibration(ycal);
212 buffering.put_read();
215 std::pair<uint32_t, uint32_t> get_framebuffer_size()
217 uint32_t v, h;
218 render_info& ri = buffering.get_read();
219 v = ri.fbuf.get_width();
220 h = ri.fbuf.get_height();
221 buffering.put_read();
222 return std::make_pair(h, v);
225 framebuffer::raw get_framebuffer() throw(std::bad_alloc)
227 render_info& ri = buffering.get_read();
228 framebuffer::raw copy = ri.fbuf;
229 buffering.put_read();
230 return copy;
233 void render_kill_request(void* obj)
235 buffer1.rq.kill_request(obj);
236 buffer2.rq.kill_request(obj);
237 buffer3.rq.kill_request(obj);
240 framebuffer::raw& render_get_latest_screen()
242 return buffering.get_read().fbuf;
245 void render_get_latest_screen_end()
247 buffering.put_read();