From 43fe0ba2835748ade22faae42504155b1816ce15 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Tue, 15 Nov 2011 05:10:12 +0200 Subject: [PATCH] Direct framebuffer Allow screen to directly write into mapped framebuffer. Should be slightly faster. --- Makefile | 4 +- include/core/dispatch.hpp | 44 +++ include/core/render.hpp | 18 +- include/core/window.hpp | 18 -- include/plat-sdl/paint.hpp | 100 ++++++ src/core/avidump-control.cpp | 3 +- src/core/controller.cpp | 4 +- src/core/dispatch.cpp | 56 ++++ src/core/framebuffer.cpp | 12 +- src/core/jmd-control.cpp | 3 +- src/core/mainloop.cpp | 17 +- src/core/memorywatch.cpp | 3 +- src/core/render.cpp | 31 +- src/plat-dummy/graphics.cpp | 2 - src/plat-sdl/graphics.cpp | 528 +++--------------------------- src/plat-sdl/paint.cpp | 748 +++++++++++++++++++++++++++++++++++++++++++ src/plat-wxwidgets/emufn.cpp | 57 +++- 17 files changed, 1081 insertions(+), 567 deletions(-) create mode 100644 include/plat-sdl/paint.hpp create mode 100644 src/plat-sdl/paint.cpp diff --git a/Makefile b/Makefile index 3e453f33..e7da5230 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ endif #Graphics stuff. ifeq ($(GRAPHICS), SDL) -PLATFORM_OBJECTS += src/plat-sdl/main.$(OBJECT_SUFFIX) src/plat-sdl/graphics.$(OBJECT_SUFFIX) +PLATFORM_OBJECTS += src/plat-sdl/main.$(OBJECT_SUFFIX) src/plat-sdl/graphics.$(OBJECT_SUFFIX) src/plat-sdl/paint.$(OBJECT_SUFFIX) PLATFORM_CFLAGS += $(shell $(CROSS_PREFIX)sdl-config --cflags) PLATFORM_LDFLAGS += $(shell $(CROSS_PREFIX)sdl-config --libs) else @@ -121,7 +121,7 @@ PLAT_DUMMY_OBJECTS=$(patsubst %.cpp,%.$(OBJECT_SUFFIX),$(wildcard src/plat-dummy HOST_CFLAGS=$(HOSTCCFLAGS) $(USER_HOSTCCFLAGS) HOST_LDFLAGS=$(HOSTLDFLAGS) $(USER_HOSTLDFLAGS) -.PRECIOUS: %.$(EXECUTABLE_SUFFIX) %.$(OBJECT_SUFFIX) +.PRECIOUS: % #Stuff compiled with core CFLAGS. avi/%.$(OBJECT_SUFFIX): avi/%.cpp diff --git a/include/core/dispatch.hpp b/include/core/dispatch.hpp index 674b3446..9320ed9a 100644 --- a/include/core/dispatch.hpp +++ b/include/core/dispatch.hpp @@ -397,6 +397,50 @@ public: * parameter vscl: Vertical scaling factor. */ static void do_click_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl); +/** + * Render buffer needs to be (possibly) resized, so that graphics plugin can update the mappings. + * + * Default implementation does nothing. + * + * parameter scr: The render buffer object. + * parameter w: The width needed. + * parameter h: The height needed. + */ + virtual void on_screen_resize(screen& scr, uint32_t w, uint32_t h); +/** + * Call on_screen_resize on all objects. + */ + static void do_screen_resize(screen& scr, uint32_t w, uint32_t h) throw(); +/** + * Notify that render buffer updating starts. + * + * Default implementation does nothing. + */ + virtual void on_render_update_start(); +/** + * Call on_render_update_start() in all objects. + */ + static void do_render_update_start() throw(); +/** + * Notify that render buffer updating ends. + * + * Default implementation does nothing. + */ + virtual void on_render_update_end(); +/** + * Call on_render_update_end() in all objects. + */ + static void do_render_update_end() throw(); +/** + * Notify that status buffer has been updated. + * + * Default implementation does nothing. + */ + virtual void on_status_update(); +/** + * Call on_status_update() in all objects. + */ + static void do_status_update() throw(); private: static void update_dumpers(bool nocalls = false) throw(); bool known_if_dumper; diff --git a/include/core/render.hpp b/include/core/render.hpp index 12b01198..a2badad8 100644 --- a/include/core/render.hpp +++ b/include/core/render.hpp @@ -137,25 +137,27 @@ struct screen * parameter _memory: The memory buffer. * parameter _width: Width of screen. * parameter _height: Height of screen. - * parameter _originx: X coordinate for origin. - * parameter _originy: Y coordinate for origin. * parameter _pitch: Distance in bytes between successive scanlines. */ - void set(uint32_t* _memory, uint32_t _width, uint32_t _height, uint32_t _originx, uint32_t _originy, - uint32_t _pitch) throw(); + void set(uint32_t* _memory, uint32_t _width, uint32_t _height, uint32_t _pitch) throw(); /** * Sets the size of the screen. The memory is freed if screen is reallocated or destroyed. * * parameter _width: Width of screen. * parameter _height: Height of screen. - * parameter _originx: X coordinate for origin. - * parameter _originy: Y coordinate for origin. * parameter upside_down: If true, image is upside down in memory. * throws std::bad_alloc: Not enough memory. */ - void reallocate(uint32_t _width, uint32_t _height, uint32_t _originx, uint32_t _originy, - bool upside_down = false) throw(std::bad_alloc); + void reallocate(uint32_t _width, uint32_t _height, bool upside_down = false) throw(std::bad_alloc); + +/** + * Set origin + * + * parameter _originx: X coordinate for origin. + * parameter _originy: Y coordinate for origin. + */ + void set_origin(uint32_t _originx, uint32_t _originy) throw(); /** * Paints low-color screen into screen. The upper-left of image will be at origin. Scales the image by given factors. diff --git a/include/core/window.hpp b/include/core/window.hpp index 56aeb93a..c099f49e 100644 --- a/include/core/window.hpp +++ b/include/core/window.hpp @@ -157,24 +157,6 @@ public: static void poll_inputs() throw(std::bad_alloc); /** - * Notify that the screen has been updated. - * - * Needs to be implemented by the graphics plugin. - * - * parameter full: Do full refresh if true. - */ - static void notify_screen_update(bool full = false) throw(); - -/** - * Set the screen to use as main surface. - * - * Needs to be implemented by the graphics plugin. - * - * parameter scr: The screen to use. - */ - static void set_main_surface(screen& scr) throw(); - -/** * Enable/Disable pause mode. * * Needs to be implemented by the graphics plugin. diff --git a/include/plat-sdl/paint.hpp b/include/plat-sdl/paint.hpp new file mode 100644 index 00000000..d557da09 --- /dev/null +++ b/include/plat-sdl/paint.hpp @@ -0,0 +1,100 @@ +#ifndef _plat_sdl__paint__hpp__included__ +#define _plat_sdl__paint__hpp__included__ + +#include +#include + +#include + +struct sdlw_display_parameters +{ + //Fill this structure. + sdlw_display_parameters(); + sdlw_display_parameters(uint32_t rscrw, uint32_t rscrh, bool cactive); + //Real width of screen buffer. + uint32_t real_screen_w; + //Real height of screen buffer. + uint32_t real_screen_h; + //Fullscreen console active flag. + bool fullscreen_console; + //Virtual width of screen area. + uint32_t virtual_screen_w; + //Virtual height of screen area. + uint32_t virtual_screen_h; + //Display width. + uint32_t display_w; + //Display height. + uint32_t display_h; + //Screen area left edge x. + uint32_t screenarea_x; + //Screen area top edge y. + uint32_t screenarea_y; + //Screen area width. + uint32_t screenarea_w; + //Screen area height. + uint32_t screenarea_h; + //Status area left edge x. + uint32_t statusarea_x; + //Status area top edge y. + uint32_t statusarea_y; + //Status area width. + uint32_t statusarea_w; + //Status area height. + uint32_t statusarea_h; + //Status area lines. + uint32_t statusarea_lines; + //Message area left edge x. + uint32_t messagearea_x; + //Message area top edge y. + uint32_t messagearea_y; + //Message area width. + uint32_t messagearea_w; + //Message area height. + uint32_t messagearea_h; + //Message area lines. + uint32_t messagearea_lines; + //Message area trailing blank top edge y. + uint32_t messagearea_trailing_y; + //Message area trailing blank height. + uint32_t messagearea_trailing_h; + //Command line left edge x. + uint32_t cmdline_x; + //Command line top edge y. + uint32_t cmdline_y; + //Command line width + uint32_t cmdline_w; +}; + +struct command_status +{ + bool active; + bool overwrite; + uint32_t rawpos; + std::string encoded; +}; + +//Query status of command line. +struct command_status get_current_command(); + +//Draw outline box. The surface must be locked. +void draw_box(SDL_Surface* surf, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color); +//Draw main screen. The surface must be locked. +bool paint_screen(SDL_Surface* surf, const sdlw_display_parameters& p, bool full); +//Draw status area. The surface must be locked. +bool paint_status(SDL_Surface* surf, const sdlw_display_parameters& p, bool full); +//Draw messages. The surface must be locked. +bool paint_messages(SDL_Surface* surf, const sdlw_display_parameters& p, bool full); +//Draw command. The surface must be locked. +bool paint_command(SDL_Surface* surf, const sdlw_display_parameters& p, bool full); +//Draw a modal dialog. The surface must be locked. +void paint_modal_dialog(SDL_Surface* surf, const std::string& text, bool confirm); + +void sdlw_paint_modal_dialog(const std::string& text, bool confirm); +void sdlw_clear_modal_dialog(); +void sdlw_screen_paintable(); +void sdlw_command_updated(); +void sdlw_fullscreen_console(bool enable); +void sdlw_force_paint(); +std::string sdlw_decode_string(std::string e); + +#endif diff --git a/src/core/avidump-control.cpp b/src/core/avidump-control.cpp index e37506d7..29fed837 100644 --- a/src/core/avidump-control.cpp +++ b/src/core/avidump-control.cpp @@ -105,7 +105,8 @@ namespace sp.max_segment_frames = _parameters.max_frames_per_segment; vid_dumper->set_segment_parameters(sp); dscr.reallocate(lrc.left_gap + hscl * _frame.width + lrc.right_gap, lrc.top_gap + vscl * - _frame.height + lrc.bottom_gap, lrc.left_gap, lrc.top_gap, false); + _frame.height + lrc.bottom_gap, false); + dscr.set_origin(lrc.left_gap, lrc.top_gap); dscr.copy_from(_frame, hscl, vscl); rq.run(dscr); vid_dumper->video(dscr.memory); diff --git a/src/core/controller.cpp b/src/core/controller.cpp index 7a24c63b..e63e3b3d 100644 --- a/src/core/controller.cpp +++ b/src/core/controller.cpp @@ -223,7 +223,7 @@ namespace auto i = buttonmap[button]; do_button_action(i.first, i.second, (type != 1) ? 1 : 0, (type == 2)); update_movie_state(); - window::notify_screen_update(); + information_dispatch::do_status_update(); } std::string get_short_help() throw(std::bad_alloc) { @@ -375,7 +375,7 @@ void change_autohold(unsigned pid, unsigned idx, bool newstate) autoheld_controls(pid / MAX_CONTROLLERS_PER_PORT, pid % MAX_CONTROLLERS_PER_PORT, idx) = (newstate ? 1 : 0); information_dispatch::do_autohold_update(pid, idx, newstate); update_movie_state(); - window::notify_screen_update(); + information_dispatch::do_status_update(); } bool get_autohold(unsigned pid, unsigned idx) diff --git a/src/core/dispatch.cpp b/src/core/dispatch.cpp index c0542d6d..8bc4536e 100644 --- a/src/core/dispatch.cpp +++ b/src/core/dispatch.cpp @@ -492,3 +492,59 @@ void information_dispatch::do_click_compensation(uint32_t xoffset, uint32_t yoff vc_hscl = hscl; vc_vscl = vscl; } + +void information_dispatch::on_screen_resize(screen& scr, uint32_t w, uint32_t h) +{ + //Do nothing. +} + +void information_dispatch::do_screen_resize(screen& scr, uint32_t w, uint32_t h) throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_screen_resize(scr, w, h); + END_EH_BLOCK(i, "on_screen_resize"); + } +} + +void information_dispatch::on_render_update_start() +{ + //Do nothing. +} + +void information_dispatch::do_render_update_start() throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_render_update_start(); + END_EH_BLOCK(i, "on_render_update_start"); + } +} + +void information_dispatch::on_render_update_end() +{ + //Do nothing. +} + +void information_dispatch::do_render_update_end() throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_render_update_end(); + END_EH_BLOCK(i, "on_render_update_end"); + } +} + +void information_dispatch::on_status_update() +{ + //Do nothing. +} + +void information_dispatch::do_status_update() throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_status_update(); + END_EH_BLOCK(i, "on_status_update"); + } +} diff --git a/src/core/framebuffer.cpp b/src/core/framebuffer.cpp index a31c09b5..c8db7da3 100644 --- a/src/core/framebuffer.cpp +++ b/src/core/framebuffer.cpp @@ -128,13 +128,17 @@ void redraw_framebuffer() lrc.width = framebuffer.width * hscl; lrc.height = framebuffer.height * vscl; lua_callback_do_paint(&lrc); - main_screen.reallocate(framebuffer.width * hscl + lrc.left_gap + lrc.right_gap, framebuffer.height * vscl + - lrc.top_gap + lrc.bottom_gap, lrc.left_gap, lrc.top_gap); + information_dispatch::do_screen_resize(main_screen, framebuffer.width * hscl + lrc.left_gap + lrc.right_gap, + framebuffer.height * vscl + lrc.top_gap + lrc.bottom_gap); + + information_dispatch::do_render_update_start(); + main_screen.set_origin(lrc.left_gap, lrc.top_gap); main_screen.copy_from(framebuffer, hscl, vscl); + rq.run(main_screen); + information_dispatch::do_render_update_end(); + //We would want divide by 2, but we'll do it ourselves in order to do mouse. information_dispatch::do_click_compensation(lrc.left_gap, lrc.top_gap, 1, 1); - rq.run(main_screen); - window::notify_screen_update(); } std::pair get_scale_factors(uint32_t width, uint32_t height) diff --git a/src/core/jmd-control.cpp b/src/core/jmd-control.cpp index 412ee7a9..449395b7 100644 --- a/src/core/jmd-control.cpp +++ b/src/core/jmd-control.cpp @@ -54,7 +54,8 @@ namespace lua_callback_do_video(&lrc); dscr.set_palette(0, 8, 16); dscr.reallocate(lrc.left_gap + _frame.width + lrc.right_gap, lrc.top_gap + _frame.height + - lrc.bottom_gap, lrc.left_gap, lrc.top_gap, false); + lrc.bottom_gap, false); + dscr.set_origin(lrc.left_gap, lrc.top_gap); dscr.copy_from(_frame, 1, 1); rq.run(dscr); diff --git a/src/core/mainloop.cpp b/src/core/mainloop.cpp index f0aa2286..1d7ba1de 100644 --- a/src/core/mainloop.cpp +++ b/src/core/mainloop.cpp @@ -169,7 +169,7 @@ controls_t movie_logic::update_controls(bool subframe) throw(std::bad_alloc, std update_movie_state(); } - window::notify_screen_update(); + information_dispatch::do_status_update(); window::poll_inputs(); if(!subframe && pending_reset_cycles >= 0) set_curcontrols_reset(pending_reset_cycles); @@ -452,7 +452,7 @@ namespace if(save_jukebox_pointer >= save_jukebox.size()) save_jukebox_pointer = 0; update_movie_state(); - window::notify_screen_update(); + information_dispatch::do_status_update(); }); function_ptr_command<> save_jukebox_next("cycle-jukebox-forward", "Cycle save jukebox forwards", @@ -465,7 +465,7 @@ namespace if(save_jukebox_pointer >= save_jukebox.size()) save_jukebox_pointer = 0; update_movie_state(); - window::notify_screen_update(); + information_dispatch::do_status_update(); }); function_ptr_command add_jukebox("add-jukebox-save", "Add save to jukebox", @@ -473,7 +473,7 @@ namespace [](arg_filename filename) throw(std::bad_alloc, std::runtime_error) { save_jukebox.push_back(filename); update_movie_state(); - window::notify_screen_update(); + information_dispatch::do_status_update(); }); function_ptr_command<> load_jukebox("load-jukebox", "Load save from jukebox", @@ -592,7 +592,7 @@ namespace information_dispatch::do_mode_change(false); lua_callback_do_readwrite(); update_movie_state(); - window::notify_screen_update(); + information_dispatch::do_status_update(); }); function_ptr_command<> set_romode("set-romode", "Switch to read-only mode", @@ -601,7 +601,7 @@ namespace movb.get_movie().readonly_mode(true); information_dispatch::do_mode_change(true); update_movie_state(); - window::notify_screen_update(); + information_dispatch::do_status_update(); }); function_ptr_command<> toggle_rwmode("toggle-rwmode", "Toggle read/write mode", @@ -613,7 +613,7 @@ namespace if(c) lua_callback_do_readwrite(); update_movie_state(); - window::notify_screen_update(); + information_dispatch::do_status_update(); }); function_ptr_command<> repaint("repaint", "Redraw the screen", @@ -711,7 +711,7 @@ namespace if(!system_corrupt) { location_special = SPECIAL_SAVEPOINT; update_movie_state(); - window::notify_screen_update(); + information_dispatch::do_status_update(); window::poll_inputs(); } return 1; @@ -843,7 +843,6 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_ lua_callback_startup(); //print_controller_mappings(); - window::set_main_surface(main_screen); redraw_framebuffer(); window::paused(false); amode = ADVANCE_PAUSE; diff --git a/src/core/memorywatch.cpp b/src/core/memorywatch.cpp index d5bd4fb2..f80e6c7e 100644 --- a/src/core/memorywatch.cpp +++ b/src/core/memorywatch.cpp @@ -1,4 +1,5 @@ #include "core/command.hpp" +#include "core/dispatch.hpp" #include "core/memorymanip.hpp" #include "core/memorywatch.hpp" #include "core/window.hpp" @@ -256,7 +257,7 @@ void set_watchexpr_for(const std::string& w, const std::string& expr) throw(std: watches.erase(w); status.erase("M[" + w + "]"); } - window::notify_screen_update(); + information_dispatch::do_status_update(); } void do_watch_memory() diff --git a/src/core/render.cpp b/src/core/render.cpp index 4bdcb74e..e1944c0b 100644 --- a/src/core/render.cpp +++ b/src/core/render.cpp @@ -460,13 +460,18 @@ void lcscreen::save_png(const std::string& file) throw(std::bad_alloc, std::runt void screen::copy_from(lcscreen& scr, uint32_t hscale, uint32_t vscale) throw() { + if(width < originx || height < originy) { + //Just clear the screen. + for(uint32_t y = 0; y < height; y++) + memset(rowptr(y), 0, 4 * width); + return; + } uint32_t copyable_width = (width - originx) / hscale; uint32_t copyable_height = (height - originy) / vscale; copyable_width = (copyable_width > scr.width) ? scr.width : copyable_width; copyable_height = (copyable_height > scr.height) ? scr.height : copyable_height; - for(uint32_t y = 0; y < height; y++) { + for(uint32_t y = 0; y < height; y++) memset(rowptr(y), 0, 4 * width); - } for(uint32_t y = 0; y < copyable_height; y++) { uint32_t line = y * vscale + originy; uint32_t* ptr = rowptr(line) + originx; @@ -481,14 +486,10 @@ void screen::copy_from(lcscreen& scr, uint32_t hscale, uint32_t vscale) throw() } } -void screen::reallocate(uint32_t _width, uint32_t _height, uint32_t _originx, uint32_t _originy, bool upside_down) - throw(std::bad_alloc) +void screen::reallocate(uint32_t _width, uint32_t _height, bool upside_down) throw(std::bad_alloc) { - if(_width == width && _height == height) { - originx = _originx; - originy = _originy; + if(_width == width && _height == height) return; - } if(!_width || !_height) { width = height = originx = originy = pitch = 0; if(memory && !user_memory) @@ -501,8 +502,6 @@ void screen::reallocate(uint32_t _width, uint32_t _height, uint32_t _originx, ui uint32_t* newmem = new uint32_t[_width * _height]; width = _width; height = _height; - originx = _originx; - originy = _originy; pitch = 4 * _width; if(memory && !user_memory) delete[] memory; @@ -511,21 +510,25 @@ void screen::reallocate(uint32_t _width, uint32_t _height, uint32_t _originx, ui flipped = upside_down; } -void screen::set(uint32_t* _memory, uint32_t _width, uint32_t _height, uint32_t _originx, uint32_t _originy, - uint32_t _pitch) throw() +void screen::set(uint32_t* _memory, uint32_t _width, uint32_t _height, uint32_t _pitch) throw() { if(memory && !user_memory) delete[] memory; width = _width; height = _height; - originx = _originx; - originy = _originy; pitch = _pitch; user_memory = true; memory = _memory; flipped = false; } +void screen::set_origin(uint32_t _originx, uint32_t _originy) throw() +{ + originx = _originx; + originy = _originy; +} + + uint32_t* screen::rowptr(uint32_t row) throw() { if(flipped) diff --git a/src/plat-dummy/graphics.cpp b/src/plat-dummy/graphics.cpp index 54e2fea8..8a46f788 100644 --- a/src/plat-dummy/graphics.cpp +++ b/src/plat-dummy/graphics.cpp @@ -11,8 +11,6 @@ namespace void graphics_init() {} void graphics_quit() {} void window::poll_inputs() throw(std::bad_alloc) {} -void window::notify_screen_update(bool full) throw() {} -void window::set_main_surface(screen& scr) throw() {} void window::paused(bool enable) throw() {} void window::wait_usec(uint64_t usec) throw(std::bad_alloc) {} void window::cancel_wait() throw() {} diff --git a/src/plat-sdl/graphics.cpp b/src/plat-sdl/graphics.cpp index 714d7c61..70a59cdc 100644 --- a/src/plat-sdl/graphics.cpp +++ b/src/plat-sdl/graphics.cpp @@ -9,6 +9,8 @@ #include "core/render.hpp" #include "core/settings.hpp" +#include "plat-sdl/paint.hpp" + #include #include #include @@ -465,7 +467,6 @@ namespace bool modconfirm; bool modal_return_flag; bool delayed_close_flag; - std::string modmsg; std::string command_buf; bool command_overwrite; size_t command_cursor; @@ -497,245 +498,9 @@ namespace { state = WINSTATE_IDENTIFY; window::message("Press key to identify."); - window::notify_screen_update(); poll_inputs_internal(); } - std::string decode_string(std::string e) - { - std::string x; - for(size_t i = 0; i < e.length(); i += 4) { - char tmp[5] = {0}; - uint32_t c1 = e[i] - 33; - uint32_t c2 = e[i + 1] - 33; - uint32_t c3 = e[i + 2] - 33; - uint32_t c4 = e[i + 3] - 33; - uint32_t c = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4; - if(c < 0x80) { - tmp[0] = c; - } else if(c < 0x800) { - tmp[0] = 0xC0 | (c >> 6); - tmp[1] = 0x80 | (c & 0x3F); - } else if(c < 0x10000) { - tmp[0] = 0xE0 | (c >> 12); - tmp[1] = 0x80 | ((c >> 6) & 0x3F); - tmp[2] = 0x80 | (c & 0x3F); - } else { - tmp[0] = 0xF0 | (c >> 18); - tmp[1] = 0x80 | ((c >> 12) & 0x3F); - tmp[2] = 0x80 | ((c >> 6) & 0x3F); - tmp[3] = 0x80 | (c & 0x3F); - } - x = x + tmp; - } - return x; - } - - void draw_rectangle(uint8_t* data, uint32_t pitch, uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, - uint32_t color, uint32_t thickness) - { - for(uint32_t i = x1; i < x2; i++) - for(uint32_t j = 0; j < thickness; j++) { - reinterpret_cast(data + pitch * (y1 + j))[i] = color; - reinterpret_cast(data + pitch * (y2 - 1 - j))[i] = color; - } - for(uint32_t i = y1; i < y2; i++) - for(uint32_t j = 0; j < thickness; j++) { - reinterpret_cast(data + pitch * i)[x1 + j] = color; - reinterpret_cast(data + pitch * i)[x2 - 1 - j] = color; - } - } - - std::vector decode_utf8(std::string s) - { - std::vector ret; - for(auto i = s.begin(); i != s.end(); i++) { - uint32_t j = static_cast(*i); - if(j < 128) - ret.push_back(j); - else if(j < 192) - continue; - else if(j < 224) { - uint32_t j2 = static_cast(*(++i)); - ret.push_back((j - 192) * 64 + (j2 - 128)); - } else if(j < 240) { - uint32_t j2 = static_cast(*(++i)); - uint32_t j3 = static_cast(*(++i)); - ret.push_back((j - 224) * 4096 + (j2 - 128) * 64 + (j3 - 128)); - } else { - uint32_t j2 = static_cast(*(++i)); - uint32_t j3 = static_cast(*(++i)); - uint32_t j4 = static_cast(*(++i)); - ret.push_back((j - 240) * 262144 + (j2 - 128) * 4096 + (j3 - 128) * 64 + (j4 - 128)); - } - } - return ret; - } - - void draw_string(uint8_t* base, uint32_t pitch, std::vector s, uint32_t x, uint32_t y, - uint32_t maxwidth, uint32_t hilite_mode = 0, uint32_t hilite_pos = 0) - { - base += y * static_cast(pitch) + 4 * x; - int32_t pos_x = 0; - int32_t pos_y = 0; - unsigned c = 0; - for(auto si : s) { - uint32_t old_x = pos_x; - uint32_t curstart = 16; - if(c == hilite_pos && hilite_mode == 1) - curstart = 14; - if(c == hilite_pos && hilite_mode == 2) - curstart = 0; - auto g = find_glyph(si, pos_x, pos_y, 0, pos_x, pos_y); - if(pos_y) - pos_x = old_x; - uint32_t mw = maxwidth - old_x; - if(mw > g.first) - mw = g.first; - if(g.second == NULL) { - //Empty glyph. - for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + pitch * j); - for(unsigned i = 0; i < mw; i++) - ptr[old_x + i] = (j >= curstart) ? 0xFFFFFFFFU : 0; - } - } else if(g.first == 16) { - //Wide glyph. - for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + pitch * j) + old_x; - uint32_t dataword = g.second[j >> 1]; - unsigned rbit = ~((j << 4) & 0x1F); - for(uint32_t i = 0; i < mw; i++) { - bool b = (((dataword >> (rbit - i)) & 1)); - b ^= (j >= curstart); - ptr[i] = b ? 0xFFFFFFFFU : 0; - } - } - } else { - //Narrow glyph. - for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + pitch * j); - uint32_t dataword = g.second[j >> 2]; - unsigned rbit = ~((j << 3) & 0x1F); - for(uint32_t i = 0; i < mw; i++) { - bool b = (((dataword >> (rbit - i)) & 1)); - b ^= (j >= curstart); - ptr[old_x + i] = b ? 0xFFFFFFFFU : 0; - } - } - } - c++; - } - for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + pitch * j); - uint32_t curstart = 16; - if(c == hilite_pos && hilite_mode == 1) - curstart = 14; - if(c == hilite_pos && hilite_mode == 2) - curstart = 0; - for(uint32_t i = pos_x; i < maxwidth; i++) - ptr[i] = ((i - pos_x) < 8 && j >= curstart) ? 0xFFFFFFFFU : 0; - } - } - - void draw_string(uint8_t* base, uint32_t pitch, std::string s, uint32_t x, uint32_t y, uint32_t maxwidth, - uint32_t hilite_mode = 0, uint32_t hilite_pos = 0) - { - draw_string(base, pitch, decode_utf8(s), x, y, maxwidth, hilite_mode, hilite_pos); - } - - void draw_command(uint8_t* base, uint32_t pitch, std::string s, size_t cursor, uint32_t x, uint32_t y, - uint32_t maxwidth, bool overwrite) - { - //FIXME, scroll text if too long. - uint32_t hilite_mode = overwrite ? 2 : 1; - auto s2 = decode_utf8(s); - draw_string(base, pitch, s2, x, y, maxwidth, hilite_mode, cursor); - } - - void draw_modal_dialog(SDL_Surface* surf, std::string msg, bool confirm) - { - int32_t pos_x = 0; - int32_t pos_y = 0; - uint32_t width = 0; - uint32_t height = 0; - if(confirm) - msg = msg + "\n\nHit Enter to confirm, Esc to cancel"; - else - msg = msg + "\n\nHit Enter or Esc to dismiss"; - auto s2 = decode_utf8(msg); - for(auto i : s2) { - auto g = find_glyph(i, pos_x, pos_y, 0, pos_x, pos_y); - if(pos_x + g.first > width) - width = static_cast(pos_x + g.first); - if(pos_y + 16 > static_cast(height)) - height = static_cast(pos_y + 16); - } - uint32_t x1; - uint32_t x2; - uint32_t y1; - uint32_t y2; - if(width + 12 >= static_cast(surf->w)) { - x1 = 6; - x2 = surf->w - 6; - width = x2 - x1; - } else { - x1 = (surf->w - width) / 2; - x2 = x1 + width; - } - if(height + 12 >= static_cast(surf->h)) { - y1 = 6; - y2 = surf->h - 6; - height = y2 - y1; - } else { - y1 = (surf->h - height) / 2; - y2 = y1 + height; - } - for(uint32_t j = y1 - 6; j < y2 + 6; j++) - memset(reinterpret_cast(surf->pixels) + j * surf->pitch + 4 * (x1 - 6), 0, - 4 * (x2 - x1 + 12)); - uint32_t bordercolor = (0xFF << surf->format->Rshift) | (0x80 << surf->format->Gshift); - draw_rectangle(reinterpret_cast(surf->pixels), surf->pitch, x1 - 4, y1 - 4, x2 + 4, y2 + 4, - bordercolor, 2); - - pos_x = 0; - pos_y = 0; - for(auto i : s2) { - uint32_t ox = pos_x; - uint32_t oy = pos_y; - auto g = find_glyph(i, pos_x, pos_y, 0, pos_x, pos_y); - if(static_cast(pos_y) > height) - break; - uint8_t* base = reinterpret_cast(surf->pixels) + (y1 + oy) * surf->pitch + - 4 * (x1 + ox); - uint32_t mw = width - ox; - if(mw > g.first) - mw = g.first; - if(g.second && g.first == 16) { - //Wide glyph. - for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + surf->pitch * j); - uint32_t dataword = g.second[j >> 1]; - uint32_t rbit = ~(j << 4) & 0x1F; - for(uint32_t i = 0; i < mw; i++) { - bool b = (dataword >> (rbit - i) & 1); - ptr[i] = b ? bordercolor : 0; - } - } - } else if(g.second) { - //Narrow glyph. - for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + surf->pitch * j); - uint32_t dataword = g.second[j >> 2]; - uint32_t rbit = ~(j << 3) & 0x1F; - for(uint32_t i = 0; i < mw; i++) { - bool b = (dataword >> (rbit - i) & 1); - ptr[i] = b ? bordercolor : 0; - } - } - } - } - } void do_keyboard_command_edit(SDL_keysym k) { @@ -768,11 +533,11 @@ namespace switch(k.sym) { case SDLK_INSERT: command_overwrite = !command_overwrite; - window::notify_screen_update(); + sdlw_command_updated(); return; case SDLK_END: command_cursor = command_buf.length(); - window::notify_screen_update(); + sdlw_command_updated(); return; case SDLK_DOWN: case SDLK_PAGEDOWN: @@ -782,20 +547,20 @@ namespace if(command_cursor > command_buf.length()) command_cursor = command_buf.length(); } - window::notify_screen_update(); + sdlw_command_updated(); return; case SDLK_LEFT: command_cursor = (command_cursor > 0) ? (command_cursor - 4) : 0; - window::notify_screen_update(); + sdlw_command_updated(); return; case SDLK_RIGHT: command_cursor = (command_cursor < command_buf.length()) ? (command_cursor + 4) : command_buf.length(); - window::notify_screen_update(); + sdlw_command_updated(); return; case SDLK_HOME: command_cursor = 0; - window::notify_screen_update(); + sdlw_command_updated(); return; case SDLK_UP: case SDLK_PAGEUP: { @@ -806,14 +571,14 @@ namespace if(command_cursor > command_buf.length()) command_cursor = command_buf.length(); } - window::notify_screen_update(); + sdlw_command_updated(); return; } case SDLK_DELETE: if(command_cursor < command_buf.length()) command_buf = command_buf.substr(0, command_cursor) + command_buf.substr(command_cursor + 4); - window::notify_screen_update(); + sdlw_command_updated(); *commandhistory_itr = command_buf; return; case SDLK_BACKSPACE: @@ -822,7 +587,7 @@ namespace command_buf.substr(command_cursor); command_cursor -= 4; } - window::notify_screen_update(); + sdlw_command_updated(); *commandhistory_itr = command_buf; return; default: @@ -853,24 +618,23 @@ namespace command_cursor += 4; } *commandhistory_itr = command_buf; - window::notify_screen_update(); + sdlw_command_updated(); } void do_event(SDL_Event& e) throw(std::bad_alloc) { #ifdef SIGALRM - alarm(WATCHDOG_TIMEOUT); + //alarm(WATCHDOG_TIMEOUT); #endif if(e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_ESCAPE && e.key.keysym.mod == (KMOD_LCTRL | KMOD_LALT)) exit(1); if(e.type == SDL_USEREVENT && e.user.code == 0) { - if(screen_is_dirty) - window::notify_screen_update(); + sdlw_screen_paintable(); } SDLKey key; - if(e.type == SDL_ACTIVEEVENT && e.active.gain && e.active.state == SDL_APPACTIVE) { - window::notify_screen_update(); + if(e.type == SDL_ACTIVEEVENT && e.active.gain) { + sdlw_force_paint(); return; } if(e.type == SDL_KEYDOWN || e.type == SDL_KEYUP) @@ -925,7 +689,7 @@ namespace if(commandhistory.size() > MAXHISTORY) commandhistory.pop_back(); commandhistory_itr = commandhistory.begin(); - window::notify_screen_update(); + sdlw_command_updated(); poll_inputs_internal(); return; } @@ -940,15 +704,13 @@ namespace state = WINSTATE_NORMAL; modconfirm = false; modal_return_flag = true; - modmsg = ""; - window::notify_screen_update(true); + sdlw_clear_modal_dialog(); return; } if(e.type == SDL_KEYUP && (key == SDLK_RETURN || key == SDLK_KP_ENTER)) { state = WINSTATE_NORMAL; modal_return_flag = true; - modmsg = ""; - window::notify_screen_update(true); + sdlw_clear_modal_dialog(); return; } break; @@ -960,7 +722,7 @@ namespace if(e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_ESCAPE) { state = WINSTATE_NORMAL; command_buf = ""; - window::notify_screen_update(); + sdlw_command_updated(); if(commandhistory.front() == "") commandhistory.pop_front(); return; @@ -970,9 +732,9 @@ namespace state = WINSTATE_NORMAL; if(commandhistory.front() == "") commandhistory.pop_front(); - command::invokeC(decode_string(command_buf)); + command::invokeC(sdlw_decode_string(command_buf)); command_buf = ""; - window::notify_screen_update(); + sdlw_command_updated(); autorepeat_phase = 0; return; } @@ -1008,7 +770,7 @@ void graphics_init() SDL_initialized = true; #ifdef SIGALRM signal(SIGALRM, sigalrm_handler); - alarm(WATCHDOG_TIMEOUT); + //alarm(WATCHDOG_TIMEOUT); #endif init_keys(); if(!sdl_init) { @@ -1028,7 +790,7 @@ void graphics_init() delayed_close_flag = false; console_mode = false; - window::notify_screen_update(); + sdlw_force_paint(); std::string windowname = "lsnes rr" + lsnes_version + "[" + bsnes_core_version + "]"; SDL_WM_SetCaption(windowname.c_str(), "lsnes"); @@ -1048,236 +810,18 @@ void graphics_quit() bool window::modal_message(const std::string& msg, bool confirm) throw(std::bad_alloc) { modconfirm = confirm; - modmsg = msg; state = WINSTATE_MODAL; - notify_screen_update(); + sdlw_paint_modal_dialog(msg, confirm); poll_inputs_internal(); bool ret = modconfirm; if(delayed_close_flag) { delayed_close_flag = false; information_dispatch::do_close(); } + sdlw_force_paint(); return ret; } -void window::notify_message() throw(std::bad_alloc, std::runtime_error) -{ - notify_screen_update(); -} - -void window::set_main_surface(screen& scr) throw() -{ - current_screen = &scr; - notify_screen_update(true); -} - -namespace -{ - bool is_time_for_screen_update(bool full) - { - uint64_t curtime = get_utime(); - //Always do full updates. - if(!full && last_ui_update < curtime && last_ui_update + MIN_UPDATE_TIME > curtime) { - screen_is_dirty = true; - return false; - } - last_ui_update = curtime; - screen_is_dirty = false; - return true; - } - - std::pair compute_screen_size(uint32_t width, uint32_t height) - { - if(width < 512) - width = 512; - if(height < 448) - height = 448; - return std::make_pair(width, height); - } - - std::pair compute_window_size(uint32_t width, uint32_t height) - { - auto g = compute_screen_size(width, height); - uint32_t win_w = ((g.first + 15) >> 4 << 4) + 278; - uint32_t win_h = g.second + MAXMESSAGES * 16 + 48; - return std::make_pair(win_w, win_h); - } - - void show_fps() - { - auto& emustatus = window::get_emustatus(); - try { - std::ostringstream y; - y << get_framerate(); - emustatus["FPS"] = y.str(); - } catch(...) { - } - } - - void redraw_borders(SDL_Surface* swsurf, std::pair screensize, - std::pair windowsize) - { - //Blank the screen and draw borders. - memset(swsurf->pixels, 0, windowsize.second * swsurf->pitch); - uint32_t bordercolor = 0xFF << (swsurf->format->Gshift); - uint32_t msgbox_min_x = 2; - uint32_t msgbox_min_y = 2; - uint32_t msgbox_max_x = windowsize.first - 2; - uint32_t msgbox_max_y = windowsize.second - 28; - uint32_t cmdbox_min_x = 2; - uint32_t cmdbox_max_x = windowsize.first - 2; - uint32_t cmdbox_min_y = windowsize.second - 26; - uint32_t cmdbox_max_y = windowsize.second - 2; - if(!console_mode) { - uint32_t scrbox_min_x = 2; - uint32_t scrbox_max_x = screensize.first + 10; - uint32_t scrbox_min_y = 2; - uint32_t scrbox_max_y = screensize.second + 10; - uint32_t stsbox_min_x = screensize.first + 12; - uint32_t stsbox_max_x = windowsize.first - 2; - uint32_t stsbox_min_y = 2; - uint32_t stsbox_max_y = screensize.second + 10; - msgbox_min_y = screensize.second + 12; - draw_rectangle(reinterpret_cast(swsurf->pixels), swsurf->pitch, scrbox_min_x, - scrbox_min_y, scrbox_max_x, scrbox_max_y, bordercolor, 2); - draw_rectangle(reinterpret_cast(swsurf->pixels), swsurf->pitch, stsbox_min_x, - stsbox_min_y, stsbox_max_x, stsbox_max_y, bordercolor, 2); - } - draw_rectangle(reinterpret_cast(swsurf->pixels), swsurf->pitch, msgbox_min_x, - msgbox_min_y, msgbox_max_x, msgbox_max_y, bordercolor, 2); - draw_rectangle(reinterpret_cast(swsurf->pixels), swsurf->pitch, cmdbox_min_x, - cmdbox_min_y, cmdbox_max_x, cmdbox_max_y, bordercolor, 2); - } - - void draw_main_screen(SDL_Surface* swsurf, std::pair screensize) - { - uint32_t cw = current_screen ? current_screen->width : 0; - uint32_t ch = current_screen ? current_screen->height : 0; - //Blank parts not drawn. - for(uint32_t i = 6; i < ch + 6; i++) - memset(reinterpret_cast(swsurf->pixels) + i * swsurf->pitch + 24 + 4 * cw, 0, - 4 * (screensize.first - cw)); - for(uint32_t i = ch + 6; i < screensize.second + 6; i++) - memset(reinterpret_cast(swsurf->pixels) + i * swsurf->pitch + 24, 0, - 4 * screensize.first); - if(current_screen) { - for(uint32_t i = 0; i < ch; i++) - memcpy(reinterpret_cast(swsurf->pixels) + (i + 6) * swsurf->pitch + 24, - reinterpret_cast(current_screen->memory) + current_screen->pitch * i, - 4 * cw); - } - } - - void draw_status_area(SDL_Surface* swsurf, std::pair screensize) - { - uint32_t status_x = screensize.first + 16; - uint32_t status_y = 6; - auto& emustatus = window::get_emustatus(); - for(auto i : emustatus) { - std::string msg = i.first + " " + i.second; - draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, msg, status_x, status_y, - 256); - status_y += 16; - } - while(status_y - 6 < screensize.second / 16 * 16) { - draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, "", status_x, status_y, - 256); - status_y += 16; - } - } - - void draw_messages(SDL_Surface* swsurf, std::pair screensize, - std::pair windowsize) - { - uint32_t message_y; - if(!console_mode) - message_y = screensize.second + 16; - else - message_y = 6; - size_t maxmessages = window::msgbuf.get_max_window_size(); - size_t msgnum = window::msgbuf.get_visible_first(); - size_t visible = window::msgbuf.get_visible_count(); - for(size_t j = 0; j < maxmessages; j++) - try { - std::ostringstream o; - if(j < visible) - o << (msgnum + j + 1) << ": " << window::msgbuf.get_message(msgnum + j); - draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, o.str(), 6, - message_y + 16 * j, windowsize.first - 12); - } catch(...) { - } - if(window::msgbuf.is_more_messages()) - try { - draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, "--More--", - windowsize.first - 76, message_y + 16 * maxmessages - 16, 64); - } catch(...) { - } - } - - void draw_command(SDL_Surface* swsurf, std::pair windowsize) - { - uint32_t command_y = windowsize.second - 22; - try { - std::string command_showas = decode_string(command_buf); - if(state == WINSTATE_COMMAND) - draw_command(reinterpret_cast(swsurf->pixels), swsurf->pitch, command_showas, - command_cursor / 4, 6, command_y, windowsize.first - 12, command_overwrite); - else - draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, "", 6, - command_y, windowsize.first - 12); - } catch(...) { - } - } -} - -void window::notify_screen_update(bool full) throw() -{ - bool resize_screen = false; - if(!is_time_for_screen_update(full)) { - return; - } - auto windowsize = compute_window_size(current_screen ? current_screen->width : 0, current_screen ? - current_screen->height : 0); - auto screensize = compute_screen_size(current_screen ? current_screen->width : 0, current_screen ? - current_screen->height : 0); - show_fps(); - - - if(!hwsurf || windowsize != current_windowsize) { - //Create/Resize the window. - SDL_Surface* hwsurf2 = SDL_SetVideoMode(windowsize.first, windowsize.second, 32, SDL_SWSURFACE); - if(!hwsurf2) { - //We are in too fucked up state to even print error as message. - std::cout << "PANIC: Can't create/resize window: " << SDL_GetError() << std::endl; - exit(1); - } - hwsurf = hwsurf2; - full = true; - current_windowsize = windowsize; - } - if(current_screen) - current_screen->set_palette(hwsurf->format->Rshift, hwsurf->format->Gshift, hwsurf->format->Bshift); - SDL_LockSurface(hwsurf); - if(full) - redraw_borders(hwsurf, screensize, windowsize); - if(!console_mode) { - draw_main_screen(hwsurf, screensize); - draw_status_area(hwsurf, screensize); - } - draw_messages(hwsurf, screensize, windowsize); - draw_command(hwsurf, windowsize); - - //Draw modal dialog. - if(state == WINSTATE_MODAL) - try { - draw_modal_dialog(hwsurf, modmsg, modconfirm); - } catch(...) { - } - SDL_UnlockSurface(hwsurf); - //SDL_BlitSurface(swsurf, NULL, hwsurf, NULL); - SDL_UpdateRect(hwsurf, 0, 0, 0, 0); -} - void poll_inputs_internal() throw(std::bad_alloc) { SDL_Event e; @@ -1318,10 +862,19 @@ void window::poll_inputs() throw(std::bad_alloc) } } +struct command_status get_current_command() +{ + struct command_status s; + s.active = (state == WINSTATE_COMMAND); + s.overwrite = command_overwrite; + s.rawpos = command_cursor; + s.encoded = command_buf; + return s; +} + void window::paused(bool enable) throw() { pause_active = enable; - notify_screen_update(); } namespace @@ -1360,11 +913,7 @@ namespace "Syntax: toggle-console\nToggles console between small and large.\n", []() throw(std::bad_alloc, std::runtime_error) { console_mode = !console_mode; - if(console_mode) - window::msgbuf.set_max_window_size(hwsurf ? (hwsurf->h - 38) / 16 : 36); - else - window::msgbuf.set_max_window_size(MAXMESSAGES); - window::notify_screen_update(true); + sdlw_fullscreen_console(console_mode); }); } @@ -1392,8 +941,7 @@ void window::fatal_error2() throw() { try { message("PANIC: Cannot continue, press ESC or close window to exit."); - //Force redraw. - notify_screen_update(true); + sdlw_force_paint(); } catch(...) { //Just crash. exit(1); diff --git a/src/plat-sdl/paint.cpp b/src/plat-sdl/paint.cpp new file mode 100644 index 00000000..ca6a0471 --- /dev/null +++ b/src/plat-sdl/paint.cpp @@ -0,0 +1,748 @@ +#include "core/dispatch.hpp" +#include "core/framebuffer.hpp" +#include "core/framerate.hpp" +#include "core/window.hpp" + +#include "plat-sdl/paint.hpp" + +#define MAXMESSAGES 6 + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +#define WRITE3(ptr, idx, c) do {\ + (ptr)[(idx) + 0] = (c) >> 16; \ + (ptr)[(idx) + 1] = (c) >> 8; \ + (ptr)[(idx) + 2] = (c); \ + } while(0) +#else +#define WRITE3(ptr, idx, c) do {\ + (ptr)[(idx) + 0] = (c); \ + (ptr)[(idx) + 1] = (c) >> 8; \ + (ptr)[(idx) + 2] = (c) >> 16; \ + } while(0) +#endif + +namespace +{ + SDL_Surface* hwsurf; + screen* our_screen; + sdlw_display_parameters dp; + bool fullscreen_console_active; + bool video_locked; + bool screen_paintable; + bool screen_dirty; + bool modal_dialog_shown; + std::string modal_dialog_text; + bool modal_dialog_confirm; + bool have_received_frames; + + void paint_line(uint8_t* ptr, uint32_t length, uint32_t step, uint32_t pbytes, uint32_t color) + { + switch(pbytes) { + case 1: + for(uint32_t i = 0; i < length; i++) { + *ptr = color; + ptr += step; + } + break; + case 2: + for(uint32_t i = 0; i < length; i++) { + *reinterpret_cast(ptr) = color; + ptr += step; + } + break; + case 3: + for(uint32_t i = 0; i < length; i++) { + WRITE3(ptr, 0, color); + ptr += step; + } + break; + case 4: + for(uint32_t i = 0; i < length; i++) { + *reinterpret_cast(ptr) = color; + ptr += step; + } + break; + } + } + + std::vector decode_utf8(std::string s) + { + std::vector ret; + for(auto i = s.begin(); i != s.end(); i++) { + uint32_t j = static_cast(*i); + if(j < 128) + ret.push_back(j); + else if(j < 192) + continue; + else if(j < 224) { + uint32_t j2 = static_cast(*(++i)); + ret.push_back((j - 192) * 64 + (j2 - 128)); + } else if(j < 240) { + uint32_t j2 = static_cast(*(++i)); + uint32_t j3 = static_cast(*(++i)); + ret.push_back((j - 224) * 4096 + (j2 - 128) * 64 + (j3 - 128)); + } else { + uint32_t j2 = static_cast(*(++i)); + uint32_t j3 = static_cast(*(++i)); + uint32_t j4 = static_cast(*(++i)); + ret.push_back((j - 240) * 262144 + (j2 - 128) * 4096 + (j3 - 128) * 64 + (j4 - 128)); + } + } + return ret; + } + + inline void draw_blank_glyph_3(uint8_t* base, uint32_t pitch, uint32_t w, uint32_t color, uint32_t curstart) + { + for(uint32_t j = 0; j < 16; j++) { + uint8_t* ptr = base + j * pitch; + uint32_t c = (j >= curstart) ? color : 0; + for(uint32_t i = 0; i < w; i++) + WRITE3(ptr, 3 * i, c); + } + } + + template + inline void draw_blank_glyph_T(uint8_t* base, uint32_t pitch, uint32_t w, uint32_t color, uint32_t curstart) + { + for(uint32_t j = 0; j < 16; j++) { + T* ptr = reinterpret_cast(base + j * pitch); + T c = (j >= curstart) ? color : 0; + for(uint32_t i = 0; i < w; i++) + ptr[i] = c; + } + } + + template + inline void draw_glyph_3(uint8_t* base, uint32_t pitch, uint32_t w, const uint32_t* gdata, uint32_t color, + uint32_t curstart) + { + for(uint32_t j = 0; j < 16; j++) { + uint8_t* ptr = base + j * pitch; + uint32_t bgc = (j >= curstart) ? color : 0; + uint32_t fgc = (j >= curstart) ? 0 : color; + uint32_t dataword = gdata[j >> (wide ? 1 : 2)]; + unsigned rbit = (~(j << (wide ? 4 : 3))) & 0x1F; + for(uint32_t i = 0; i < w; i++) { + bool b = (((dataword >> (rbit - i)) & 1)); + WRITE3(ptr, 3 * i, b ? fgc : bgc); + } + } + } + + template + inline void draw_glyph_T(uint8_t* base, uint32_t pitch, uint32_t w, const uint32_t* gdata, uint32_t color, + uint32_t curstart) + { + for(uint32_t j = 0; j < 16; j++) { + T* ptr = reinterpret_cast(base + j * pitch); + T bgc = (j >= curstart) ? color : 0; + T fgc = (j >= curstart) ? 0 : color; + uint32_t dataword = gdata[j >> (wide ? 1 : 2)]; + unsigned rbit = (~(j << (wide ? 4 : 3))) & 0x1F; + for(uint32_t i = 0; i < w; i++) { + bool b = (((dataword >> (rbit - i)) & 1)); + ptr[i] = b ? fgc : bgc; + } + } + } + + + void draw_blank_glyph(uint8_t* base, uint32_t pitch, uint32_t pbytes, uint32_t w, uint32_t wleft, + uint32_t color, uint32_t hilite_mode) + { + if(w > wleft) + w = wleft; + if(!w) + return; + uint32_t curstart = 16; + if(hilite_mode == 1) + curstart = 14; + if(hilite_mode == 2) + curstart = 0; + switch(pbytes) { + case 1: + draw_blank_glyph_T(base, pitch, w, color, curstart); + break; + case 2: + draw_blank_glyph_T(base, pitch, w, color, curstart); + break; + case 3: + draw_blank_glyph_3(base, pitch, w, color, curstart); + break; + case 4: + draw_blank_glyph_T(base, pitch, w, color, curstart); + break; + } + } + + void draw_glyph(uint8_t* base, uint32_t pitch, uint32_t pbytes, const uint32_t* gdata, uint32_t w, + uint32_t wleft, uint32_t color, uint32_t hilite_mode) + { + bool wide = (w > 8); + if(w > wleft) + w = wleft; + if(!w) + return; + uint32_t curstart = 16; + if(hilite_mode == 1) + curstart = 14; + if(hilite_mode == 2) + curstart = 0; + switch(pbytes) { + case 1: + if(wide) + draw_glyph_T(base, pitch, w, gdata, color, curstart); + else + draw_glyph_T(base, pitch, w, gdata, color, curstart); + break; + case 2: + if(wide) + draw_glyph_T(base, pitch, w, gdata, color, curstart); + else + draw_glyph_T(base, pitch, w, gdata, color, curstart); + break; + case 3: + if(wide) + draw_glyph_3(base, pitch, w, gdata, color, curstart); + else + draw_glyph_3(base, pitch, w, gdata, color, curstart); + break; + case 4: + if(wide) + draw_glyph_T(base, pitch, w, gdata, color, curstart); + else + draw_glyph_T(base, pitch, w, gdata, color, curstart); + break; + } + } + + void draw_string(uint8_t* base, uint32_t pitch, uint32_t pbytes, std::vector s, uint32_t x, + uint32_t y, uint32_t maxwidth, uint32_t color, uint32_t hilite_mode = 0, uint32_t hilite_pos = 0) + { + int32_t pos_x = 0; + int32_t pos_y = 0; + size_t xo = pbytes; + size_t yo = pitch; + unsigned c = 0; + for(auto si : s) { + uint32_t old_x = pos_x; + uint32_t old_y = pos_y; + auto g = find_glyph(si, pos_x, pos_y, 0, pos_x, pos_y); + uint32_t mw = maxwidth - old_x; + if(maxwidth < old_x) + mw = 0; + if(mw > g.first) + mw = g.first; + uint8_t* cbase = base + (y + old_y) * yo + (x + old_x) * xo; + if(g.second == NULL) + draw_blank_glyph(cbase, pitch, pbytes, g.first, mw, color, + (c == hilite_pos) ? hilite_mode : 0); + else + draw_glyph(cbase, pitch, pbytes, g.second, g.first, mw, color, + (c == hilite_pos) ? hilite_mode : 0); + c++; + } + if(c == hilite_pos) { + uint32_t old_x = pos_x; + uint32_t mw = maxwidth - old_x; + if(maxwidth < old_x) + mw = 0; + draw_blank_glyph(base + y * yo + (x + old_x) * xo, pitch, pbytes, 8, mw, 0xFFFFFFFFU, + hilite_mode); + pos_x += 8; + } + if(pos_x < maxwidth) + draw_blank_glyph(base + y * yo + (x + pos_x) * xo, pitch, pbytes, maxwidth - pos_x, + maxwidth - pos_x, 0, 0); + } + + void draw_string(uint8_t* base, uint32_t pitch, uint32_t pbytes, std::string s, uint32_t x, uint32_t y, + uint32_t maxwidth, uint32_t color, uint32_t hilite_mode = 0, uint32_t hilite_pos = 0) + { + draw_string(base, pitch, pbytes, decode_utf8(s), x, y, maxwidth, color, hilite_mode, hilite_pos); + } +} + +void draw_box(SDL_Surface* surf, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color) +{ + if(!w || !h) + return; + uint32_t sx, sy, ex, ey; + uint32_t bsx, bsy, bex, bey; + uint32_t pbytes = surf->format->BytesPerPixel; + uint32_t lstride = surf->pitch; + uint8_t* p = reinterpret_cast(surf->pixels); + size_t xo = surf->format->BytesPerPixel; + size_t yo = surf->pitch; + sx = (x < 6) ? 0 : (x - 6); + sy = (y < 6) ? 0 : (y - 6); + ex = (x + w + 6 > surf->w) ? surf->w : (x + w + 6); + ey = (y + h + 6 > surf->h) ? surf->h : (y + h + 6); + bsx = (x < 4) ? 0 : (x - 4); + bsy = (y < 4) ? 0 : (y - 4); + bex = (x + w + 4 > surf->w) ? surf->w : (x + w + 4); + bey = (y + h + 4 > surf->h) ? surf->h : (y + h + 4); + //First, blank the area. + for(uint32_t j = sy; j < ey; j++) + memset(p + j * yo + sx * xo, 0, (ex - sx) * xo); + //Paint the borders. + if(x >= 4) + paint_line(p + bsy * yo + (x - 4) * xo, bey - bsy, yo, xo, color); + if(x >= 3) + paint_line(p + bsy * yo + (x - 3) * xo, bey - bsy, yo, xo, color); + if(y >= 4) + paint_line(p + (y - 4) * yo + bsx * xo, bex - bsx, xo, xo, color); + if(y >= 3) + paint_line(p + (y - 3) * yo + bsx * xo, bex - bsx, xo, xo, color); + if(x + w + 3 < surf->w) + paint_line(p + bsy * yo + (x + w + 2) * xo, bey - bsy, yo, xo, color); + if(x + w + 4 < surf->w) + paint_line(p + bsy * yo + (x + w + 3) * xo, bey - bsy, yo, xo, color); + if(y + h + 3 < surf->h) + paint_line(p + (y + h + 2) * yo + bsx * xo, bex - bsx, xo, xo, color); + if(y + h + 4 < surf->h) + paint_line(p + (y + h + 3) * yo + bsx * xo, bex - bsx, xo, xo, color); +} + +sdlw_display_parameters::sdlw_display_parameters() +{ + real_screen_w = 0; + real_screen_h = 0; + fullscreen_console = false; + virtual_screen_w = 512; + virtual_screen_h = 448; + display_w = virtual_screen_w + 278; + display_h = virtual_screen_h + 16 * MAXMESSAGES + 48; + screenarea_x = 6; + screenarea_y = 6; + statusarea_x = virtual_screen_w + 16; + statusarea_y = 6; + messagearea_x = 6; + cmdline_x = 6; + cmdline_y = display_h - 22; + cmdline_w = display_w - 12; + messagearea_w = display_w - 12; + screenarea_w = virtual_screen_w; + screenarea_h = virtual_screen_h; + statusarea_w = 256; + statusarea_lines = virtual_screen_h / 16; + messagearea_y = virtual_screen_h + 16; + messagearea_lines = MAXMESSAGES; + messagearea_trailing_y = messagearea_y + MAXMESSAGES; + messagearea_trailing_h = 0; + statusarea_h = statusarea_lines * 16; + messagearea_h = messagearea_lines * 16 + messagearea_trailing_h; +} + +sdlw_display_parameters::sdlw_display_parameters(uint32_t rscrw, uint32_t rscrh, bool cactive) +{ + real_screen_w = rscrw; + real_screen_h = rscrh; + fullscreen_console = cactive; + virtual_screen_w = (((real_screen_w < 512) ? 512 : real_screen_w) + 15) >> 4 << 4; + virtual_screen_h = (((real_screen_w < 448) ? 448 : real_screen_h) + 15) >> 4 << 4; + display_w = virtual_screen_w + 278; + display_h = virtual_screen_h + 16 * MAXMESSAGES + 48; + screenarea_x = 6; + screenarea_y = 6; + statusarea_x = virtual_screen_w + 16; + statusarea_y = 6; + messagearea_x = 6; + cmdline_x = 6; + cmdline_y = display_h - 22; + cmdline_w = display_w - 12; + messagearea_w = display_w - 12; + if(fullscreen_console) { + screenarea_w = 0; + screenarea_h = 0; + statusarea_w = 0; + statusarea_lines = 0; + messagearea_y = 6; + messagearea_lines = (display_h - 38) / 16; + messagearea_trailing_y = messagearea_y + 16 * messagearea_lines; + messagearea_trailing_h = (display_h - 38) % 16; + } else { + screenarea_w = virtual_screen_w; + screenarea_h = virtual_screen_h; + statusarea_w = 256; + statusarea_lines = virtual_screen_h / 16; + messagearea_y = virtual_screen_h + 16; + messagearea_lines = MAXMESSAGES; + messagearea_trailing_y = messagearea_y + MAXMESSAGES; + messagearea_trailing_h = 0; + } + statusarea_h = statusarea_lines * 16; + messagearea_h = messagearea_lines * 16 + messagearea_trailing_h; +} + +bool paint_command(SDL_Surface* surf, const sdlw_display_parameters& p, bool full) +{ + static bool cached_command_active = false; + static bool cached_overwrite = false; + static uint32_t cached_rawcursor = 0; + static std::string cached_command; + + //Query status of command line. + auto cmd = get_current_command(); + + if(full) { + draw_box(surf, p.cmdline_x, p.cmdline_y, p.cmdline_w, 16, surf->format->Gmask); + cached_command_active = false; + cached_overwrite = false; + cached_rawcursor = 0; + cached_command = ""; + } + if(cached_command_active == cmd.active && cached_overwrite == cmd.overwrite && + cached_rawcursor == cmd.rawpos && cached_command == cmd.encoded) + return full; + try { + if(cmd.active) { + //FIXME, scroll text if too long. + uint32_t hilite_mode = cmd.overwrite ? 2 : 1; + auto s2 = decode_utf8(sdlw_decode_string(cmd.encoded)); + draw_string(reinterpret_cast(surf->pixels), surf->pitch, surf->format->BytesPerPixel, + s2, p.cmdline_x, p.cmdline_y, p.cmdline_w, 0xFFFFFFFFU, hilite_mode, cmd.rawpos / 4); + } else + draw_string(reinterpret_cast(surf->pixels), surf->pitch, surf->format->BytesPerPixel, + "", p.cmdline_x, p.cmdline_y, p.cmdline_w, 0xFFFFFFFFU); + cached_command_active = cmd.active; + cached_overwrite = cmd.overwrite; + cached_rawcursor = cmd.rawpos; + cached_command = cmd.encoded; + } catch(...) { + } + return true; +} + +bool paint_messages(SDL_Surface* surf, const sdlw_display_parameters& p, bool full) +{ + static uint64_t cached_first = 0; + static uint64_t cached_messages = 0; + if(full) { + draw_box(surf, p.messagearea_x, p.messagearea_y, p.messagearea_w, p.messagearea_h, + surf->format->Gmask); + cached_first = 0; + cached_messages = 0; + } + uint32_t message_y = p.messagearea_y; + size_t maxmessages = window::msgbuf.get_max_window_size(); + size_t msgnum = window::msgbuf.get_visible_first(); + size_t visible = window::msgbuf.get_visible_count(); + if((!visible && cached_messages == 0) || (msgnum == cached_first && visible == cached_messages)) + return full; + if(cached_messages == 0) + cached_first = msgnum; //Little trick. + for(size_t j = 0; j < maxmessages; j++) + try { + if(msgnum == cached_first && j < cached_messages) + continue; //Don't draw lines that stayed the same. + if(j >= visible && j >= cached_messages) + continue; //Don't draw blank lines. + std::ostringstream o; + if(j < visible) + o << (msgnum + j + 1) << ": " << window::msgbuf.get_message(msgnum + j); + draw_string(reinterpret_cast(surf->pixels), surf->pitch, + surf->format->BytesPerPixel, o.str(), p.messagearea_x, + message_y + 16 * j, p.messagearea_w, 0xFFFFFFFFU); + } catch(...) { + } + if(window::msgbuf.is_more_messages()) + try { + draw_string(reinterpret_cast(surf->pixels), surf->pitch, + surf->format->BytesPerPixel, "--More--", + p.messagearea_x + p.messagearea_w - 64, message_y + 16 * maxmessages - 16, 64, + 0xFFFFFFFFU); + } catch(...) { + } + cached_first = msgnum; + cached_messages = visible; + return true; +} + +bool paint_status(SDL_Surface* surf, const sdlw_display_parameters& p, bool full) +{ + auto& status = window::get_emustatus(); + try { + std::ostringstream y; + y << get_framerate(); + status["FPS"] = y.str(); + } catch(...) { + } + if(!p.statusarea_w || !p.statusarea_h) + return full; + uint32_t y = p.statusarea_y; + uint32_t lines = 0; + static std::map old_status; + size_t old_lines = old_status.size(); + if(full) { + old_status.clear(); + draw_box(surf, p.statusarea_x, p.statusarea_y, p.statusarea_w, p.statusarea_h, + surf->format->Gmask); + } + bool paint_any = false; + bool desynced = false; + for(auto i : status) { + if(!old_status.count(i.first)) + desynced = true; + if(!desynced && old_status[i.first] == i.second) { + y += 16; + lines++; + continue; + } + //Paint in full. + paint_any = true; + try { + std::string str = i.first + " " + i.second; + draw_string(reinterpret_cast(surf->pixels), surf->pitch, + surf->format->BytesPerPixel, str, p.statusarea_x, y, p.statusarea_w, + 0xFFFFFFFFU); + old_status[i.first] = i.second; + } catch(...) { + } + y += 16; + lines++; + } + for(size_t i = lines; i < old_lines; i++) { + draw_string(reinterpret_cast(surf->pixels), surf->pitch, + surf->format->BytesPerPixel, "", p.statusarea_x, y, p.statusarea_w, 0); + y += 16; + } + return paint_any || full; +} + +bool paint_screen(SDL_Surface* surf, const sdlw_display_parameters& p, bool full) +{ + if(full) { + draw_box(surf, p.screenarea_x, p.screenarea_y, p.screenarea_w, p.screenarea_h, + surf->format->Gmask); + } +} + +void paint_modal_dialog(SDL_Surface* surf, const std::string& text, bool confirm) +{ + std::string realtext; + if(confirm) + realtext = text + "\n\nHit Enter to confirm, Esc to cancel"; + else + realtext = text + "\n\nHit Enter or Esc to dismiss"; + unsigned extent_w = 0; + unsigned extent_h = 0; + int32_t pos_x = 0; + int32_t pos_y = 0; + auto s2 = decode_utf8(realtext); + for(auto i : s2) { + auto g = find_glyph(i, pos_x, pos_y, 0, pos_x, pos_y); + if(pos_x + g.first > extent_w) + extent_w = static_cast(pos_x + g.first); + if(pos_y + 16 > static_cast(extent_h)) + extent_h = static_cast(pos_y + 16); + } + uint32_t x1; + uint32_t x2; + uint32_t y1; + uint32_t y2; + if(extent_w + 12 >= static_cast(surf->w)) { + x1 = 6; + x2 = surf->w - 6; + extent_w = x2 - x1; + } else { + x1 = (surf->w - extent_w) / 2; + x2 = x1 + extent_w; + } + if(extent_h + 12 >= static_cast(surf->h)) { + y1 = 6; + y2 = surf->h - 6; + extent_h = y2 - y1; + } else { + y1 = (surf->h - extent_h) / 2; + y2 = y1 + extent_h; + } + uint32_t color = surf->format->Rmask | ((surf->format->Gmask >> 1) & surf->format->Gmask); + draw_box(surf, x1, y1, extent_w, extent_h, color); + draw_string(reinterpret_cast(surf->pixels), surf->pitch, surf->format->BytesPerPixel, s2, + x1, y1, extent_w, color); +} + +void sdlw_paint_modal_dialog(const std::string& text, bool confirm) +{ + modal_dialog_shown = true; + modal_dialog_text = text; + modal_dialog_confirm = confirm; + SDL_LockSurface(hwsurf); + paint_modal_dialog(hwsurf, text, confirm); + SDL_UnlockSurface(hwsurf); + SDL_UpdateRect(hwsurf, 0, 0, 0, 0); +} + +void sdlw_clear_modal_dialog() +{ + modal_dialog_shown = false; +} + + +namespace +{ + class painter_listener : public information_dispatch + { + public: + painter_listener(); + void on_screen_resize(screen& scr, uint32_t w, uint32_t h); + void on_render_update_start(); + void on_render_update_end(); + void on_status_update(); + } plistener; + + painter_listener::painter_listener() : information_dispatch("SDL-painter-listener") {} + + void painter_listener::on_screen_resize(screen& scr, uint32_t w, uint32_t h) + { + if(w != dp.real_screen_w || h != dp.real_screen_h || !hwsurf || + fullscreen_console_active != dp.fullscreen_console) { + dp = sdlw_display_parameters(w, h, fullscreen_console_active); + SDL_Surface* hwsurf2 = SDL_SetVideoMode(dp.display_w, dp.display_h, 32, SDL_SWSURFACE); + if(!hwsurf2) { + //We are in too fucked up state to even print error as message. + std::cout << "PANIC: Can't create/resize window: " << SDL_GetError() << std::endl; + exit(1); + } + hwsurf = hwsurf2; + } + scr.set_palette(hwsurf->format->Rshift, hwsurf->format->Gshift, hwsurf->format->Bshift); + if(fullscreen_console_active) + //We have to render to memory buffer. + scr.reallocate(w, h, false); + else { + //Render direct to screen. But delay setting the buffer. + } + our_screen = &scr; + } + + void painter_listener::on_render_update_start() + { + if(fullscreen_console_active) + return; + SDL_LockSurface(hwsurf); + video_locked = true; + our_screen->set(reinterpret_cast(reinterpret_cast(hwsurf->pixels) + + dp.screenarea_y * hwsurf->pitch + dp.screenarea_y * hwsurf->format->BytesPerPixel), + dp.real_screen_w, dp.real_screen_h, hwsurf->pitch); + our_screen->set_palette(hwsurf->format->Rshift, hwsurf->format->Gshift, hwsurf->format->Bshift); + } + + void painter_listener::on_render_update_end() + { + if(!video_locked) + return; + SDL_UnlockSurface(hwsurf); + video_locked = false; + if(screen_paintable) { + SDL_UpdateRect(hwsurf, 6, 6, dp.real_screen_w, dp.real_screen_h); + screen_paintable = false; + } else + screen_dirty = true; + have_received_frames = true; + } + + void painter_listener::on_status_update() + { + SDL_LockSurface(hwsurf); + bool update = paint_status(hwsurf, dp, false); + SDL_UnlockSurface(hwsurf); + if(update) + SDL_UpdateRect(hwsurf, dp.statusarea_x, dp.statusarea_y, dp.statusarea_w, dp.statusarea_h); + } +} + +void sdlw_command_updated() +{ + SDL_LockSurface(hwsurf); + bool update = paint_command(hwsurf, dp, false); + SDL_UnlockSurface(hwsurf); + if(update) + SDL_UpdateRect(hwsurf, dp.cmdline_x, dp.cmdline_y, dp.cmdline_w, 16); +} + +void sdlw_screen_paintable() +{ + if(screen_dirty) { + SDL_UpdateRect(hwsurf, 6, 6, dp.real_screen_w, dp.real_screen_h); + screen_dirty = false; + } else + screen_paintable = true; +} + +void window::notify_message() throw(std::bad_alloc, std::runtime_error) +{ + SDL_LockSurface(hwsurf); + bool update = paint_messages(hwsurf, dp, false); + SDL_UnlockSurface(hwsurf); + if(update) + SDL_UpdateRect(hwsurf, dp.messagearea_x, dp.messagearea_y, dp.messagearea_w, dp.messagearea_h); +} + +void sdlw_fullscreen_console(bool enable) +{ + fullscreen_console_active = enable; + window::msgbuf.set_max_window_size(dp.messagearea_lines); + sdlw_force_paint(); +} + +void sdlw_force_paint() +{ + if(!hwsurf) { + //Initialize video. + dp = sdlw_display_parameters(0, 0, fullscreen_console_active); + SDL_Surface* hwsurf2 = SDL_SetVideoMode(dp.display_w, dp.display_h, 32, SDL_SWSURFACE); + if(!hwsurf2) { + //We are in too fucked up state to even print error as message. + std::cout << "PANIC: Can't create/resize window: " << SDL_GetError() << std::endl; + exit(1); + } + hwsurf = hwsurf2; + } + SDL_LockSurface(hwsurf); + paint_screen(hwsurf, dp, true); + paint_status(hwsurf, dp, true); + paint_messages(hwsurf, dp, true); + paint_command(hwsurf, dp, true); + SDL_UnlockSurface(hwsurf); + SDL_UpdateRect(hwsurf, 0, 0, 0, 0); + if(have_received_frames) + redraw_framebuffer(); + if(modal_dialog_shown) { + SDL_LockSurface(hwsurf); + paint_modal_dialog(hwsurf, modal_dialog_text, modal_dialog_confirm); + SDL_UnlockSurface(hwsurf); + SDL_UpdateRect(hwsurf, 0, 0, 0, 0); + } +} + +std::string sdlw_decode_string(std::string e) +{ + std::string x; + for(size_t i = 0; i < e.length(); i += 4) { + char tmp[5] = {0}; + uint32_t c1 = e[i] - 33; + uint32_t c2 = e[i + 1] - 33; + uint32_t c3 = e[i + 2] - 33; + uint32_t c4 = e[i + 3] - 33; + uint32_t c = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4; + if(c < 0x80) { + tmp[0] = c; + } else if(c < 0x800) { + tmp[0] = 0xC0 | (c >> 6); + tmp[1] = 0x80 | (c & 0x3F); + } else if(c < 0x10000) { + tmp[0] = 0xE0 | (c >> 12); + tmp[1] = 0x80 | ((c >> 6) & 0x3F); + tmp[2] = 0x80 | (c & 0x3F); + } else { + tmp[0] = 0xF0 | (c >> 18); + tmp[1] = 0x80 | ((c >> 12) & 0x3F); + tmp[2] = 0x80 | ((c >> 6) & 0x3F); + tmp[3] = 0x80 | (c & 0x3F); + } + x = x + tmp; + } + return x; +} diff --git a/src/plat-wxwidgets/emufn.cpp b/src/plat-wxwidgets/emufn.cpp index 1a5afa04..42c07338 100644 --- a/src/plat-wxwidgets/emufn.cpp +++ b/src/plat-wxwidgets/emufn.cpp @@ -780,6 +780,7 @@ void emulator_main_panel::on_paint(wxPaintEvent& e) if(h < 448) h = 448; SetMinSize(wxSize(w, h)); + main_window->Fit(); } srcs[0] = 4 * main_screen->width; dsts[0] = 3 * main_screen->width; @@ -1013,7 +1014,6 @@ void emulator_main_window::menu_readonly(wxCommandEvent& e) if(!s) lua_callback_do_readwrite(); update_movie_state(); - window::notify_screen_update(); } void emulator_main_window::menu_edit_authors(wxCommandEvent& e) @@ -1520,25 +1520,52 @@ void window::poll_inputs() throw(std::bad_alloc) } while(1); } -void window::notify_screen_update(bool full) throw() +namespace { - screen_updated_full = true; - screen_updated = true; - if(main_window && !main_window_dirty) { - main_window_dirty = true; - main_window->request_paint(); + class painter_listener : public information_dispatch + { + public: + painter_listener(); + void on_screen_resize(screen& scr, uint32_t w, uint32_t h); + void on_render_update_start(); + void on_render_update_end(); + void on_status_update(); + } plistener; + + painter_listener::painter_listener() : information_dispatch("wx-painter-listener") {} + + void painter_listener::on_screen_resize(screen& scr, uint32_t w, uint32_t h) + { + main_screen = &scr; + scr.reallocate(w, h, false); + screen_updated_full = true; + screen_updated = true; } - if(wx_status_window::ptr) - wx_status_window::ptr->notify_status_change(); -} -void window::set_main_surface(screen& scr) throw() -{ - main_screen = &scr; - screen_updated_full = true; - screen_updated = true; + void painter_listener::on_render_update_start() + { + } + + void painter_listener::on_render_update_end() + { + screen_updated_full = true; + screen_updated = true; + if(main_window && !main_window_dirty) { + main_window_dirty = true; + main_window->request_paint(); + } + if(wx_status_window::ptr) + wx_status_window::ptr->notify_status_change(); + } + + void painter_listener::on_status_update() + { + if(wx_status_window::ptr) + wx_status_window::ptr->notify_status_change(); + } } + void window::paused(bool enable) throw() { e_paused = enable; -- 2.11.4.GIT