1 #include "core/command.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/framebuffer.hpp"
4 #include "core/subtitles.hpp"
6 #include "core/misc.hpp"
7 #include "core/window.hpp"
8 #include "fonts/wrapper.hpp"
9 #include "library/framebuffer.hpp"
10 #include "library/pixfmt-lrgb.hpp"
12 framebuffer_raw screen_nosignal
;
13 framebuffer_raw screen_corrupt
;
29 triplebuffer_logic buffering
;
34 render_info
& get_write_buffer()
36 unsigned i
= buffering
.start_write();
49 render_info
& get_read_buffer()
51 unsigned i
= buffering
.start_read();
64 struct render_list_entry
72 struct render_list_entry rl_nosignal
[] = {
84 struct render_list_entry rl_corrupt
[] = {
106 void draw_special_screen(uint32_t* target
, struct render_list_entry
* rlist
)
108 while(rlist
->scale
) {
109 auto g
= main_font
.get_glyph(rlist
->codepoint
);
110 for(uint32_t j
= 0; j
< 16; j
++) {
111 for(uint32_t i
= 0; i
< (g
.wide
? 16 : 8); i
++) {
112 uint32_t slice
= g
.data
[j
/ (g
.wide
? 2 : 4)];
113 uint32_t bit
= 31 - ((j
% (g
.wide
? 2 : 4)) * (g
.wide
? 16 : 8) + i
);
114 uint32_t value
= (slice
>> bit
) & 1;
116 uint32_t basex
= rlist
->x
+ rlist
->scale
* i
;
117 uint32_t basey
= rlist
->y
+ rlist
->scale
* j
;
118 for(uint32_t j2
= 0; j2
< rlist
->scale
; j2
++)
119 for(uint32_t i2
= 0; i2
< rlist
->scale
; i2
++)
120 target
[(basey
+ j2
) * 512 + (basex
+ i2
)] = 0x7FFFF;
128 void draw_nosignal(uint32_t* target
)
130 for(unsigned i
= 0; i
< 512 * 448; i
++)
132 draw_special_screen(target
, rl_nosignal
);
135 void draw_corrupt(uint32_t* target
)
137 for(unsigned i
= 0; i
< 512 * 448; i
++)
139 draw_special_screen(target
, rl_corrupt
);
142 function_ptr_command
<arg_filename
> take_screenshot_cmd(lsnes_cmd
, "take-screenshot", "Takes a screenshot",
143 "Syntax: take-screenshot <file>\nSaves screenshot to PNG file <file>\n",
144 [](arg_filename file
) throw(std::bad_alloc
, std::runtime_error
) {
145 take_screenshot(file
);
146 messages
<< "Saved PNG screenshot" << std::endl
;
149 bool last_redraw_no_lua
= true;
152 framebuffer
<false> main_screen
;
154 void take_screenshot(const std::string
& file
) throw(std::bad_alloc
, std::runtime_error
)
156 render_info
& ri
= get_read_buffer();
157 ri
.fbuf
.save_png(file
);
158 buffering
.end_read();
162 void init_special_screens() throw(std::bad_alloc
)
164 std::vector
<uint32_t> buf
;
167 framebuffer_info inf
;
168 inf
.type
= &_pixel_format_lrgb
;
169 inf
.mem
= reinterpret_cast<char*>(&buf
[0]);
171 inf
.physheight
= 448;
172 inf
.physstride
= 2048;
179 draw_nosignal(&buf
[0]);
180 screen_nosignal
= framebuffer_raw(inf
);
181 draw_corrupt(&buf
[0]);
182 screen_corrupt
= framebuffer_raw(inf
);
185 void redraw_framebuffer(framebuffer_raw
& todraw
, bool no_lua
, bool spontaneous
)
188 auto g
= get_scale_factors(todraw
.get_width(), todraw
.get_height());
191 render_info
& ri
= get_write_buffer();
193 struct lua_render_context lrc
;
199 lrc
.width
= todraw
.get_width() * hscl
;
200 lrc
.height
= todraw
.get_height() * vscl
;
202 lua_callback_do_paint(&lrc
, spontaneous
);
203 render_subtitles(lrc
);
208 ri
.lgap
= lrc
.left_gap
;
209 ri
.rgap
= lrc
.right_gap
;
210 ri
.tgap
= lrc
.top_gap
;
211 ri
.bgap
= lrc
.bottom_gap
;
212 buffering
.end_write();
213 information_dispatch::do_screen_update();
214 last_redraw_no_lua
= no_lua
;
217 void redraw_framebuffer()
219 render_info
& ri
= get_read_buffer();
220 framebuffer_raw copy
= ri
.fbuf
;
221 buffering
.end_read();
222 //Redraws are never spontaneous
223 redraw_framebuffer(copy
, last_redraw_no_lua
, false);
227 void render_framebuffer()
229 static uint32_t val1
, val2
, val3
, val4
;
230 uint32_t nval1
, nval2
, nval3
, nval4
;
231 render_info
& ri
= get_read_buffer();
232 main_screen
.reallocate(ri
.fbuf
.get_width() * ri
.hscl
+ ri
.lgap
+ ri
.rgap
, ri
.fbuf
.get_height() * ri
.vscl
+
234 main_screen
.set_origin(ri
.lgap
, ri
.tgap
);
235 main_screen
.copy_from(ri
.fbuf
, ri
.hscl
, ri
.vscl
);
236 ri
.rq
.run(main_screen
);
237 information_dispatch::do_set_screen(main_screen
);
238 //We would want divide by 2, but we'll do it ourselves in order to do mouse.
239 keyboard_key
* mouse_x
= lsnes_kbd
.try_lookup_key("mouse_x");
240 keyboard_key
* mouse_y
= lsnes_kbd
.try_lookup_key("mouse_y");
241 keyboard_mouse_calibration xcal
;
242 keyboard_mouse_calibration ycal
;
243 xcal
.offset
= ri
.lgap
;
244 ycal
.offset
= ri
.tgap
;
245 if(mouse_x
&& mouse_x
->get_type() == KBD_KEYTYPE_MOUSE
)
246 mouse_x
->cast_mouse()->set_calibration(xcal
);
247 if(mouse_y
&& mouse_y
->get_type() == KBD_KEYTYPE_MOUSE
)
248 mouse_y
->cast_mouse()->set_calibration(ycal
);
251 nval3
= ri
.fbuf
.get_width() * ri
.hscl
+ ri
.rgap
;
252 nval4
= ri
.fbuf
.get_height() * ri
.vscl
+ ri
.bgap
;
257 buffering
.end_read();
260 std::pair
<uint32_t, uint32_t> get_framebuffer_size()
263 render_info
& ri
= get_read_buffer();
264 v
= ri
.fbuf
.get_width();
265 h
= ri
.fbuf
.get_height();
266 buffering
.end_read();
267 return std::make_pair(h
, v
);
270 framebuffer_raw
get_framebuffer() throw(std::bad_alloc
)
272 render_info
& ri
= get_read_buffer();
273 framebuffer_raw copy
= ri
.fbuf
;
274 buffering
.end_read();
279 triplebuffer_logic::triplebuffer_logic() throw(std::bad_alloc
)
281 mut
= &mutex::aquire();
282 last_complete_slot
= 0;
284 write_active
= false;
285 read_active_slot
= 0;
286 write_active_slot
= 0;
289 triplebuffer_logic::~triplebuffer_logic() throw()
294 unsigned triplebuffer_logic::start_write() throw()
296 mutex::holder
h(*mut
);
298 //We need to avoid hitting last complete slot or slot that is active for read.
299 if(last_complete_slot
!= 0 && read_active_slot
!= 0)
300 write_active_slot
= 0;
301 else if(last_complete_slot
!= 1 && read_active_slot
!= 1)
302 write_active_slot
= 1;
304 write_active_slot
= 2;
307 return write_active_slot
;
310 void triplebuffer_logic::end_write() throw()
312 mutex::holder
h(*mut
);
314 last_complete_slot
= write_active_slot
;
317 unsigned triplebuffer_logic::start_read() throw()
319 mutex::holder
h(*mut
);
321 read_active_slot
= last_complete_slot
;
323 return read_active_slot
;
326 void triplebuffer_logic::end_read() throw()
328 mutex::holder
h(*mut
);