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();
26 framebuffer::raw fbuf
;
27 framebuffer::queue rq
;
39 triplebuffer::triplebuffer
<render_info
> buffering(buffer1
, buffer2
, buffer3
);
41 struct render_list_entry
49 struct render_list_entry rl_corrupt
[] = {
71 void draw_special_screen(uint32_t* target
, struct render_list_entry
* rlist
)
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;
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;
93 void draw_corrupt(uint32_t* target
)
95 for(unsigned i
= 0; i
< 512 * 448; i
++)
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
;
133 framebuffer::info inf
;
134 inf
.type
= &framebuffer::pixfmt_lrgb
;
135 inf
.mem
= reinterpret_cast<char*>(&buf
[0]);
137 inf
.physheight
= 448;
138 inf
.physstride
= 2048;
145 draw_corrupt(&buf
[0]);
146 screen_corrupt
= framebuffer::raw(inf
);
149 void redraw_framebuffer(framebuffer::raw
& todraw
, bool no_lua
, bool spontaneous
)
152 auto g
= our_rom
.rtype
->get_scale_factors(todraw
.get_width(), todraw
.get_height());
155 render_info
& ri
= buffering
.get_write();
157 struct lua_render_context lrc
;
163 lrc
.width
= todraw
.get_width() * hscl
;
164 lrc
.height
= todraw
.get_height() * vscl
;
166 lua_callback_do_paint(&lrc
, spontaneous
);
167 render_subtitles(lrc
);
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
+
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()
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();
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();