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 "core/moviedata.hpp"
9 #include "core/moviefile.hpp"
10 #include "fonts/wrapper.hpp"
11 #include "library/framebuffer.hpp"
12 #include "library/pixfmt-lrgb.hpp"
14 framebuffer_raw screen_corrupt
;
30 triplebuffer_logic buffering
;
35 render_info
& get_write_buffer()
37 unsigned i
= buffering
.start_write();
50 render_info
& get_read_buffer()
52 unsigned i
= buffering
.start_read();
65 struct render_list_entry
73 struct render_list_entry rl_corrupt
[] = {
95 void draw_special_screen(uint32_t* target
, struct render_list_entry
* rlist
)
98 auto g
= main_font
.get_glyph(rlist
->codepoint
);
99 for(uint32_t j
= 0; j
< 16; j
++) {
100 for(uint32_t i
= 0; i
< (g
.wide
? 16 : 8); i
++) {
101 uint32_t slice
= g
.data
[j
/ (g
.wide
? 2 : 4)];
102 uint32_t bit
= 31 - ((j
% (g
.wide
? 2 : 4)) * (g
.wide
? 16 : 8) + i
);
103 uint32_t value
= (slice
>> bit
) & 1;
105 uint32_t basex
= rlist
->x
+ rlist
->scale
* i
;
106 uint32_t basey
= rlist
->y
+ rlist
->scale
* j
;
107 for(uint32_t j2
= 0; j2
< rlist
->scale
; j2
++)
108 for(uint32_t i2
= 0; i2
< rlist
->scale
; i2
++)
109 target
[(basey
+ j2
) * 512 + (basex
+ i2
)] = 0x7FFFF;
117 void draw_corrupt(uint32_t* target
)
119 for(unsigned i
= 0; i
< 512 * 448; i
++)
121 draw_special_screen(target
, rl_corrupt
);
124 function_ptr_command
<arg_filename
> take_screenshot_cmd(lsnes_cmd
, "take-screenshot", "Takes a screenshot",
125 "Syntax: take-screenshot <file>\nSaves screenshot to PNG file <file>\n",
126 [](arg_filename file
) throw(std::bad_alloc
, std::runtime_error
) {
127 take_screenshot(file
);
128 messages
<< "Saved PNG screenshot" << std::endl
;
131 bool last_redraw_no_lua
= true;
134 framebuffer
<false> main_screen
;
136 void take_screenshot(const std::string
& file
) throw(std::bad_alloc
, std::runtime_error
)
138 render_info
& ri
= get_read_buffer();
139 ri
.fbuf
.save_png(file
);
140 buffering
.end_read();
144 void init_special_screens() throw(std::bad_alloc
)
146 std::vector
<uint32_t> buf
;
149 framebuffer_info inf
;
150 inf
.type
= &_pixel_format_lrgb
;
151 inf
.mem
= reinterpret_cast<char*>(&buf
[0]);
153 inf
.physheight
= 448;
154 inf
.physstride
= 2048;
161 draw_corrupt(&buf
[0]);
162 screen_corrupt
= framebuffer_raw(inf
);
165 void redraw_framebuffer(framebuffer_raw
& todraw
, bool no_lua
, bool spontaneous
)
168 auto g
= our_rom
.rtype
->get_scale_factors(todraw
.get_width(), todraw
.get_height());
171 render_info
& ri
= get_write_buffer();
173 struct lua_render_context lrc
;
179 lrc
.width
= todraw
.get_width() * hscl
;
180 lrc
.height
= todraw
.get_height() * vscl
;
182 lua_callback_do_paint(&lrc
, spontaneous
);
183 render_subtitles(lrc
);
188 ri
.lgap
= lrc
.left_gap
;
189 ri
.rgap
= lrc
.right_gap
;
190 ri
.tgap
= lrc
.top_gap
;
191 ri
.bgap
= lrc
.bottom_gap
;
192 buffering
.end_write();
193 notify_screen_update();
194 last_redraw_no_lua
= no_lua
;
197 void redraw_framebuffer()
199 render_info
& ri
= get_read_buffer();
200 framebuffer_raw copy
= ri
.fbuf
;
201 buffering
.end_read();
202 //Redraws are never spontaneous
203 redraw_framebuffer(copy
, last_redraw_no_lua
, false);
207 void render_framebuffer()
209 render_info
& ri
= get_read_buffer();
210 main_screen
.reallocate(ri
.fbuf
.get_width() * ri
.hscl
+ ri
.lgap
+ ri
.rgap
, ri
.fbuf
.get_height() * ri
.vscl
+
212 main_screen
.set_origin(ri
.lgap
, ri
.tgap
);
213 main_screen
.copy_from(ri
.fbuf
, ri
.hscl
, ri
.vscl
);
214 ri
.rq
.run(main_screen
);
215 notify_set_screen(main_screen
);
216 //We would want divide by 2, but we'll do it ourselves in order to do mouse.
217 keyboard_key
* mouse_x
= lsnes_kbd
.try_lookup_key("mouse_x");
218 keyboard_key
* mouse_y
= lsnes_kbd
.try_lookup_key("mouse_y");
219 keyboard_mouse_calibration xcal
;
220 keyboard_mouse_calibration ycal
;
221 xcal
.offset
= ri
.lgap
;
222 ycal
.offset
= ri
.tgap
;
223 if(mouse_x
&& mouse_x
->get_type() == KBD_KEYTYPE_MOUSE
)
224 mouse_x
->cast_mouse()->set_calibration(xcal
);
225 if(mouse_y
&& mouse_y
->get_type() == KBD_KEYTYPE_MOUSE
)
226 mouse_y
->cast_mouse()->set_calibration(ycal
);
227 buffering
.end_read();
230 std::pair
<uint32_t, uint32_t> get_framebuffer_size()
233 render_info
& ri
= get_read_buffer();
234 v
= ri
.fbuf
.get_width();
235 h
= ri
.fbuf
.get_height();
236 buffering
.end_read();
237 return std::make_pair(h
, v
);
240 framebuffer_raw
get_framebuffer() throw(std::bad_alloc
)
242 render_info
& ri
= get_read_buffer();
243 framebuffer_raw copy
= ri
.fbuf
;
244 buffering
.end_read();
249 triplebuffer_logic::triplebuffer_logic() throw(std::bad_alloc
)
251 last_complete_slot
= 0;
253 write_active
= false;
254 read_active_slot
= 0;
255 write_active_slot
= 0;
258 triplebuffer_logic::~triplebuffer_logic() throw()
262 unsigned triplebuffer_logic::start_write() throw()
266 //We need to avoid hitting last complete slot or slot that is active for read.
267 if(last_complete_slot
!= 0 && read_active_slot
!= 0)
268 write_active_slot
= 0;
269 else if(last_complete_slot
!= 1 && read_active_slot
!= 1)
270 write_active_slot
= 1;
272 write_active_slot
= 2;
275 return write_active_slot
;
278 void triplebuffer_logic::end_write() throw()
282 last_complete_slot
= write_active_slot
;
285 unsigned triplebuffer_logic::start_read() throw()
289 read_active_slot
= last_complete_slot
;
291 return read_active_slot
;
294 void triplebuffer_logic::end_read() throw()
300 void render_kill_request(void* obj
)
302 buffer1
.rq
.kill_request(obj
);
303 buffer2
.rq
.kill_request(obj
);
304 buffer3
.rq
.kill_request(obj
);
307 framebuffer_raw
& render_get_latest_screen()
309 return get_read_buffer().fbuf
;
312 void render_get_latest_screen_end()
314 buffering
.end_read();