1 #include "cmdhelp/framebuffer.hpp"
2 #include "core/command.hpp"
3 #include "core/dispatch.hpp"
4 #include "core/emustatus.hpp"
5 #include "core/framebuffer.hpp"
6 #include "core/instance.hpp"
7 #include "core/memorywatch.hpp"
8 #include "core/messages.hpp"
9 #include "core/misc.hpp"
10 #include "core/moviedata.hpp"
11 #include "core/rom.hpp"
12 #include "core/settings.hpp"
13 #include "core/subtitles.hpp"
14 #include "fonts/wrapper.hpp"
15 #include "library/framebuffer.hpp"
16 #include "library/framebuffer-pixfmt-lrgb.hpp"
17 #include "library/minmax.hpp"
18 #include "library/triplebuffer.hpp"
19 #include "lua/lua.hpp"
23 struct render_list_entry
31 const struct render_list_entry rl_corrupt
[] = {
53 void draw_special_screen(uint32_t* target
, const struct render_list_entry
* rlist
)
56 auto g
= main_font
.get_glyph(rlist
->codepoint
);
57 for(uint32_t j
= 0; j
< g
.get_height(); j
++) {
58 for(uint32_t i
= 0; i
< g
.get_width(); i
++) {
59 if(g
.read_pixel(i
, j
)) {
60 uint32_t basex
= rlist
->x
+ rlist
->scale
* i
;
61 uint32_t basey
= rlist
->y
+ rlist
->scale
* j
;
62 for(uint32_t j2
= 0; j2
< rlist
->scale
; j2
++)
63 for(uint32_t i2
= 0; i2
< rlist
->scale
; i2
++)
64 target
[(basey
+ j2
) * 512 + (basex
+ i2
)] = 0x7FFFF;
72 void draw_corrupt(uint32_t* target
)
74 for(unsigned i
= 0; i
< 512 * 448; i
++)
76 draw_special_screen(target
, rl_corrupt
);
79 settingvar::supervariable
<settingvar::model_int
<0, 8191>> SET_dtb(lsnes_setgrp
, "top-border",
81 settingvar::supervariable
<settingvar::model_int
<0, 8191>> SET_dbb(lsnes_setgrp
, "bottom-border",
82 "UI‣Bottom padding", 0);
83 settingvar::supervariable
<settingvar::model_int
<0, 8191>> SET_dlb(lsnes_setgrp
, "left-border",
84 "UI‣Left padding", 0);
85 settingvar::supervariable
<settingvar::model_int
<0, 8191>> SET_drb(lsnes_setgrp
, "right-border",
86 "UI‣Right padding", 0);
89 framebuffer::raw
emu_framebuffer::screen_corrupt
;
91 emu_framebuffer::emu_framebuffer(subtitle_commentary
& _subtitles
, settingvar::group
& _settings
, memwatch_set
& _mwatch
,
92 keyboard::keyboard
& _keyboard
, emulator_dispatch
& _dispatch
, lua_state
& _lua2
, loaded_rom
& _rom
,
93 status_updater
& _supdater
, command::group
& _cmd
, input_queue
& _iqueue
)
94 : buffering(buffer1
, buffer2
, buffer3
), subtitles(_subtitles
), settings(_settings
), mwatch(_mwatch
),
95 keyboard(_keyboard
), edispatch(_dispatch
), lua2(_lua2
), rom(_rom
), supdater(_supdater
), cmd(_cmd
),
96 iqueue(_iqueue
), screenshot(cmd
, CFRAMEBUF::ss
, [this](command::arg_filename a
) { this->do_screenshot(a
); })
98 last_redraw_no_lua
= false;
101 void emu_framebuffer::do_screenshot(command::arg_filename file
)
103 std::string fn
= file
;
105 messages
<< "Saved PNG screenshot to '" << fn
<< "'" << std::endl
;
108 void emu_framebuffer::take_screenshot(const std::string
& file
) throw(std::bad_alloc
, std::runtime_error
)
110 render_info
& ri
= buffering
.get_read();
111 ri
.fbuf
.save_png(file
);
112 buffering
.put_read();
116 void emu_framebuffer::init_special_screens() throw(std::bad_alloc
)
118 std::vector
<uint32_t> buf
;
121 framebuffer::info inf
;
122 inf
.type
= &framebuffer::pixfmt_lrgb
;
123 inf
.mem
= reinterpret_cast<char*>(&buf
[0]);
125 inf
.physheight
= 448;
126 inf
.physstride
= 2048;
133 draw_corrupt(&buf
[0]);
134 screen_corrupt
= framebuffer::raw(inf
);
137 void emu_framebuffer::redraw_framebuffer(framebuffer::raw
& todraw
, bool no_lua
, bool spontaneous
)
140 auto g
= rom
.get_scale_factors(todraw
.get_width(), todraw
.get_height());
143 render_info
& ri
= buffering
.get_write();
145 struct lua::render_context lrc
;
151 lrc
.width
= todraw
.get_width() * hscl
;
152 lrc
.height
= todraw
.get_height() * vscl
;
154 lua2
.callback_do_paint(&lrc
, spontaneous
);
155 subtitles
.render(lrc
);
160 ri
.lgap
= max(lrc
.left_gap
, (unsigned)SET_dlb(settings
));
161 ri
.rgap
= max(lrc
.right_gap
, (unsigned)SET_drb(settings
));
162 ri
.tgap
= max(lrc
.top_gap
, (unsigned)SET_dtb(settings
));
163 ri
.bgap
= max(lrc
.bottom_gap
, (unsigned)SET_dbb(settings
));
165 buffering
.put_write();
166 edispatch
.screen_update();
167 last_redraw_no_lua
= no_lua
;
171 void emu_framebuffer::redraw_framebuffer()
173 framebuffer::raw copy
;
174 buffering
.read_last_write_synchronous([©
](render_info
& ri
) { copy
= ri
.fbuf
; });
175 //Redraws are never spontaneous
176 redraw_framebuffer(copy
, last_redraw_no_lua
, false);
179 void emu_framebuffer::render_framebuffer()
181 render_info
& ri
= buffering
.get_read();
182 main_screen
.reallocate(ri
.fbuf
.get_width() * ri
.hscl
+ ri
.lgap
+ ri
.rgap
, ri
.fbuf
.get_height() * ri
.vscl
+
184 main_screen
.set_origin(ri
.lgap
, ri
.tgap
);
185 main_screen
.copy_from(ri
.fbuf
, ri
.hscl
, ri
.vscl
);
186 ri
.rq
.run(main_screen
);
187 //We would want divide by 2, but we'll do it ourselves in order to do mouse.
188 keyboard::mouse_calibration xcal
;
189 keyboard::mouse_calibration ycal
;
190 xcal
.offset
= ri
.lgap
;
191 ycal
.offset
= ri
.tgap
;
192 auto kbd
= &keyboard
;
193 iqueue
.run_async([kbd
, xcal
, ycal
]() {
194 keyboard::key
* mouse_x
= kbd
->try_lookup_key("mouse_x");
195 keyboard::key
* mouse_y
= kbd
->try_lookup_key("mouse_y");
196 if(mouse_x
&& mouse_x
->get_type() == keyboard::KBD_KEYTYPE_MOUSE
)
197 mouse_x
->cast_mouse()->set_calibration(xcal
);
198 if(mouse_y
&& mouse_y
->get_type() == keyboard::KBD_KEYTYPE_MOUSE
)
199 mouse_y
->cast_mouse()->set_calibration(ycal
);
200 }, [](std::exception
& e
){});
201 buffering
.put_read();
204 std::pair
<uint32_t, uint32_t> emu_framebuffer::get_framebuffer_size()
207 render_info
& ri
= buffering
.get_read();
208 v
= ri
.fbuf
.get_width();
209 h
= ri
.fbuf
.get_height();
210 buffering
.put_read();
211 return std::make_pair(h
, v
);
214 framebuffer::raw
emu_framebuffer::get_framebuffer() throw(std::bad_alloc
)
216 render_info
& ri
= buffering
.get_read();
217 framebuffer::raw copy
= ri
.fbuf
;
218 buffering
.put_read();
222 void emu_framebuffer::render_kill_request(void* obj
)
224 buffer1
.rq
.kill_request(obj
);
225 buffer2
.rq
.kill_request(obj
);
226 buffer3
.rq
.kill_request(obj
);
229 framebuffer::raw
& emu_framebuffer::render_get_latest_screen()
231 return buffering
.get_read().fbuf
;
234 void emu_framebuffer::render_get_latest_screen_end()
236 buffering
.put_read();