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/moviedata.hpp"
10 #include "core/rom.hpp"
11 #include "core/settings.hpp"
12 #include "core/subtitles.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"
18 #include "lua/lua.hpp"
22 struct render_list_entry
30 const struct render_list_entry rl_corrupt
[] = {
52 void draw_special_screen(uint32_t* target
, const struct render_list_entry
* rlist
)
55 auto g
= main_font
.get_glyph(rlist
->codepoint
);
56 for(uint32_t j
= 0; j
< 16; j
++) {
57 for(uint32_t i
= 0; i
< (g
.wide
? 16 : 8); i
++) {
58 uint32_t slice
= g
.data
[j
/ (g
.wide
? 2 : 4)];
59 uint32_t bit
= 31 - ((j
% (g
.wide
? 2 : 4)) * (g
.wide
? 16 : 8) + i
);
60 uint32_t value
= (slice
>> bit
) & 1;
62 uint32_t basex
= rlist
->x
+ rlist
->scale
* i
;
63 uint32_t basey
= rlist
->y
+ rlist
->scale
* j
;
64 for(uint32_t j2
= 0; j2
< rlist
->scale
; j2
++)
65 for(uint32_t i2
= 0; i2
< rlist
->scale
; i2
++)
66 target
[(basey
+ j2
) * 512 + (basex
+ i2
)] = 0x7FFFF;
74 void draw_corrupt(uint32_t* target
)
76 for(unsigned i
= 0; i
< 512 * 448; i
++)
78 draw_special_screen(target
, rl_corrupt
);
81 settingvar::supervariable
<settingvar::model_int
<0, 8191>> SET_dtb(lsnes_setgrp
, "top-border",
83 settingvar::supervariable
<settingvar::model_int
<0, 8191>> SET_dbb(lsnes_setgrp
, "bottom-border",
84 "UI‣Bottom padding", 0);
85 settingvar::supervariable
<settingvar::model_int
<0, 8191>> SET_dlb(lsnes_setgrp
, "left-border",
86 "UI‣Left padding", 0);
87 settingvar::supervariable
<settingvar::model_int
<0, 8191>> SET_drb(lsnes_setgrp
, "right-border",
88 "UI‣Right padding", 0);
91 framebuffer::raw
emu_framebuffer::screen_corrupt
;
93 emu_framebuffer::emu_framebuffer(subtitle_commentary
& _subtitles
, settingvar::group
& _settings
, memwatch_set
& _mwatch
,
94 keyboard::keyboard
& _keyboard
, emulator_dispatch
& _dispatch
, lua_state
& _lua2
, loaded_rom
& _rom
,
95 status_updater
& _supdater
, command::group
& _cmd
)
96 : buffering(buffer1
, buffer2
, buffer3
), subtitles(_subtitles
), settings(_settings
), mwatch(_mwatch
),
97 keyboard(_keyboard
), edispatch(_dispatch
), lua2(_lua2
), rom(_rom
), supdater(_supdater
), cmd(_cmd
),
98 screenshot(cmd
, CFRAMEBUF::ss
, [this](command::arg_filename a
) { this->do_screenshot(a
); })
100 last_redraw_no_lua
= false;
103 void emu_framebuffer::do_screenshot(command::arg_filename file
)
105 std::string fn
= file
;
107 messages
<< "Saved PNG screenshot to '" << fn
<< "'" << std::endl
;
110 void emu_framebuffer::take_screenshot(const std::string
& file
) throw(std::bad_alloc
, std::runtime_error
)
112 render_info
& ri
= buffering
.get_read();
113 ri
.fbuf
.save_png(file
);
114 buffering
.put_read();
118 void emu_framebuffer::init_special_screens() throw(std::bad_alloc
)
120 std::vector
<uint32_t> buf
;
123 framebuffer::info inf
;
124 inf
.type
= &framebuffer::pixfmt_lrgb
;
125 inf
.mem
= reinterpret_cast<char*>(&buf
[0]);
127 inf
.physheight
= 448;
128 inf
.physstride
= 2048;
135 draw_corrupt(&buf
[0]);
136 screen_corrupt
= framebuffer::raw(inf
);
139 void emu_framebuffer::redraw_framebuffer(framebuffer::raw
& todraw
, bool no_lua
, bool spontaneous
)
142 auto g
= rom
.get_scale_factors(todraw
.get_width(), todraw
.get_height());
145 render_info
& ri
= buffering
.get_write();
147 struct lua::render_context lrc
;
153 lrc
.width
= todraw
.get_width() * hscl
;
154 lrc
.height
= todraw
.get_height() * vscl
;
156 lua2
.callback_do_paint(&lrc
, spontaneous
);
157 subtitles
.render(lrc
);
162 ri
.lgap
= max(lrc
.left_gap
, (unsigned)SET_dlb(settings
));
163 ri
.rgap
= max(lrc
.right_gap
, (unsigned)SET_drb(settings
));
164 ri
.tgap
= max(lrc
.top_gap
, (unsigned)SET_dtb(settings
));
165 ri
.bgap
= max(lrc
.bottom_gap
, (unsigned)SET_dbb(settings
));
167 buffering
.put_write();
168 edispatch
.screen_update();
169 last_redraw_no_lua
= no_lua
;
173 void emu_framebuffer::redraw_framebuffer()
175 render_info
& ri
= buffering
.get_read();
176 framebuffer::raw copy
= ri
.fbuf
;
177 buffering
.put_read();
178 //Redraws are never spontaneous
179 redraw_framebuffer(copy
, last_redraw_no_lua
, false);
182 void emu_framebuffer::render_framebuffer()
184 render_info
& ri
= buffering
.get_read();
185 main_screen
.reallocate(ri
.fbuf
.get_width() * ri
.hscl
+ ri
.lgap
+ ri
.rgap
, ri
.fbuf
.get_height() * ri
.vscl
+
187 main_screen
.set_origin(ri
.lgap
, ri
.tgap
);
188 main_screen
.copy_from(ri
.fbuf
, ri
.hscl
, ri
.vscl
);
189 ri
.rq
.run(main_screen
);
190 //We would want divide by 2, but we'll do it ourselves in order to do mouse.
191 keyboard::key
* mouse_x
= keyboard
.try_lookup_key("mouse_x");
192 keyboard::key
* mouse_y
= keyboard
.try_lookup_key("mouse_y");
193 keyboard::mouse_calibration xcal
;
194 keyboard::mouse_calibration ycal
;
195 xcal
.offset
= ri
.lgap
;
196 ycal
.offset
= ri
.tgap
;
197 if(mouse_x
&& mouse_x
->get_type() == keyboard::KBD_KEYTYPE_MOUSE
)
198 mouse_x
->cast_mouse()->set_calibration(xcal
);
199 if(mouse_y
&& mouse_y
->get_type() == keyboard::KBD_KEYTYPE_MOUSE
)
200 mouse_y
->cast_mouse()->set_calibration(ycal
);
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();