diff --git a/src/lgfx/v1/platforms/sdl/Panel_sdl.cpp b/src/lgfx/v1/platforms/sdl/Panel_sdl.cpp index bfc13c31..13b5cc58 100644 --- a/src/lgfx/v1/platforms/sdl/Panel_sdl.cpp +++ b/src/lgfx/v1/platforms/sdl/Panel_sdl.cpp @@ -29,11 +29,17 @@ Porting for SDL: #include "../../Bus.hpp" #include +#include +#include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif namespace lgfx { inline namespace v1 { + SDL_Keymod Panel_sdl::_keymod = KMOD_NONE; static SDL_semaphore *_update_in_semaphore = nullptr; static SDL_semaphore *_update_out_semaphore = nullptr; volatile static uint32_t _in_step_exec = 0; @@ -53,6 +59,28 @@ namespace lgfx } //---------------------------------------------------------------------------- + static std::vector _key_code_map; + + void Panel_sdl::addKeyCodeMapping(SDL_KeyCode keyCode, uint8_t gpio) + { + if (gpio > EMULATED_GPIO_MAX) + return; + KeyCodeMapping_t map; + map.keycode = keyCode; + map.gpio = gpio; + _key_code_map.push_back(map); + } + + int Panel_sdl::getKeyCodeMapping(SDL_KeyCode keyCode) + { + for (const auto& i : _key_code_map) + { + if (i.keycode == keyCode) + return i.gpio; + } + return -1; + } + void Panel_sdl::_event_proc(void) { SDL_Event event; @@ -60,14 +88,51 @@ namespace lgfx { if ((event.type == SDL_KEYDOWN) || (event.type == SDL_KEYUP)) { + auto mon = getMonitorByWindowID(event.button.windowID); int gpio = -1; - switch (event.key.keysym.sym) - { /// M5StackのBtnA~BtnCのエミュレート; - case SDLK_LEFT: gpio = 39; break; - case SDLK_DOWN: gpio = 38; break; - case SDLK_RIGHT: gpio = 37; break; - case SDLK_UP: gpio = 36; break; - default: continue; + + /// Check key mapping + gpio = getKeyCodeMapping((SDL_KeyCode)event.key.keysym.sym); + if (gpio < 0) + { + switch (event.key.keysym.sym) + { /// M5StackのBtnA~BtnCのエミュレート; + // case SDLK_LEFT: gpio = 39; break; + // case SDLK_DOWN: gpio = 38; break; + // case SDLK_RIGHT: gpio = 37; break; + // case SDLK_UP: gpio = 36; break; + + /// L/Rキーで画面回転 + case SDLK_r: + case SDLK_l: + if (event.type == SDL_KEYDOWN && event.key.keysym.mod == _keymod) + { + if (mon != nullptr) + { + mon->frame_rotation = (mon->frame_rotation += event.key.keysym.sym == SDLK_r ? 1 : -1); + int x, y, w, h; + SDL_GetWindowSize(mon->window, &w, &h); + SDL_GetWindowPosition(mon->window, &x, &y); + SDL_SetWindowSize(mon->window, h, w); + SDL_SetWindowPosition(mon->window, x + (w-h)/2, y + (h-w)/2); + mon->panel->sdl_invalidate(); + } + } + break; + + /// 1~6キーで画面拡大率変更 + case SDLK_1: case SDLK_2: case SDLK_3: case SDLK_4: case SDLK_5: case SDLK_6: + if (event.type == SDL_KEYDOWN && event.key.keysym.mod == _keymod) + { + if (mon != nullptr) + { + int size = 1 + (event.key.keysym.sym - SDLK_1); + _update_scaling(mon, size, size); + } + } + break; + default: continue; + } } if (event.type == SDL_KEYDOWN) { gpio_lo(gpio); @@ -80,11 +145,24 @@ namespace lgfx auto mon = getMonitorByWindowID(event.button.windowID); if (mon != nullptr) { - int x, y, w, h; - SDL_GetWindowSize(mon->window, &w, &h); - SDL_GetMouseState(&x, &y); - mon->touch_x = x * mon->panel->config().panel_width / w; - mon->touch_y = y * mon->panel->config().panel_height / h; + { + int x, y, w, h; + SDL_GetWindowSize(mon->window, &w, &h); + SDL_GetMouseState(&x, &y); + float sf = sinf(mon->frame_angle * M_PI / 180); + float cf = cosf(mon->frame_angle * M_PI / 180); + x -= w / 2.0f; + y -= h / 2.0f; + float nx = y * sf + x * cf; + float ny = y * cf - x * sf; + if (mon->frame_rotation & 1) { + std::swap(w, h); + } + x = (nx * mon->frame_width / w) + (mon->frame_width >> 1); + y = (ny * mon->frame_height / h) + (mon->frame_height >> 1); + mon->touch_x = x - mon->frame_inner_x; + mon->touch_y = y - mon->frame_inner_y; + } if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT) { mon->touched = true; @@ -95,12 +173,18 @@ namespace lgfx } } } - else - if (event.type == SDL_WINDOWEVENT - || event.type == SDL_QUIT) { + else if (event.type == SDL_WINDOWEVENT) + { auto monitor = getMonitorByWindowID(event.window.windowID); if (monitor) { if (event.window.event == SDL_WINDOWEVENT_RESIZED) { + int mw, mh; + SDL_GetRendererOutputSize(monitor->renderer, &mw, &mh); + if (monitor->frame_rotation & 1) { + std::swap(mw, mh); + } + monitor->scaling_x = (mw * 2 / monitor->frame_width) / 2.0f; + monitor->scaling_y = (mh * 2 / monitor->frame_height) / 2.0f; monitor->panel->sdl_invalidate(); } else @@ -109,6 +193,13 @@ namespace lgfx } } } + else if (event.type == SDL_QUIT) + { + for (auto& m : _list_monitor) + { + m->closing = true; + } + } } } @@ -133,6 +224,7 @@ namespace lgfx for (auto it = _list_monitor.begin(); it != _list_monitor.end(); ) { if ((*it)->closing) { + if ((*it)->texture_frameimage) { SDL_DestroyTexture((*it)->texture_frameimage); } SDL_DestroyTexture((*it)->texture); SDL_DestroyRenderer((*it)->renderer); SDL_DestroyWindow((*it)->window); @@ -153,6 +245,13 @@ namespace lgfx if (_inited) return 1; _inited = true; + /// Add default keycode mapping + /// M5StackのBtnA~BtnCのエミュレート; + addKeyCodeMapping(SDLK_LEFT, 39); + addKeyCodeMapping(SDLK_DOWN, 38); + addKeyCodeMapping(SDLK_RIGHT, 37); + addKeyCodeMapping(SDLK_UP, 36); + SDL_CreateThread((SDL_ThreadFunction)detectDebugger, "dbg", &_inited); _update_in_semaphore = SDL_CreateSemaphore(0); @@ -224,6 +323,21 @@ namespace lgfx monitor.scaling_y = scaling_y; } + void Panel_sdl::setFrameImage(const void* frame_image, int frame_width, int frame_height, int inner_x, int inner_y) + { + monitor.frame_image = frame_image; + monitor.frame_width = frame_width; + monitor.frame_height = frame_height; + monitor.frame_inner_x = inner_x; + monitor.frame_inner_y = inner_y; + } + + void Panel_sdl::setFrameRotation(uint_fast16_t frame_rotation) + { + monitor.frame_rotation = frame_rotation; + monitor.frame_angle = (monitor.frame_rotation) * 90; + } + Panel_sdl::~Panel_sdl(void) { _list_monitor.remove(&monitor); @@ -322,6 +436,10 @@ namespace lgfx void Panel_sdl::display(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h) { + (void)x; + (void)y; + (void)w; + (void)h; if (_in_step_exec) { if (_display_counter != _modified_counter) { @@ -336,6 +454,7 @@ namespace lgfx uint_fast8_t Panel_sdl::getTouchRaw(touch_point_t* tp, uint_fast8_t count) { + (void)count; tp->x = monitor.touch_x; tp->y = monitor.touch_y; tp->size = monitor.touched ? 1 : 0; @@ -351,20 +470,68 @@ namespace lgfx } } + void Panel_sdl::_update_scaling(monitor_t * mon, float sx, float sy) + { + mon->scaling_x = sx; + mon->scaling_y = sy; + int nw = mon->frame_width; + int nh = mon->frame_height; + if (mon->frame_rotation & 1) { + std::swap(nw, nh); + } + + int x, y, w, h; + int rw, rh; + SDL_GetRendererOutputSize(mon->renderer, &rw, &rh); + SDL_GetWindowSize(mon->window, &w, &h); + nw = nw * sx * w / rw; + nh = nh * sy * h / rh; + SDL_GetWindowPosition(mon->window, &x, &y); + SDL_SetWindowSize(mon->window, nw, nh); + SDL_SetWindowPosition(mon->window, x + (w-nw)/2, y + (h-nh)/2); + mon->panel->sdl_invalidate(); + } + void Panel_sdl::sdl_create(monitor_t * m) { - int flag = SDL_WINDOW_RESIZABLE; + int flag = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; #if SDL_FULLSCREEN flag |= SDL_WINDOW_FULLSCREEN; #endif - m->window = SDL_CreateWindow(_window_title, - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - _cfg.panel_width * m->scaling_x, _cfg.panel_height * m->scaling_y, flag); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/ + if (m->frame_width < _cfg.panel_width) { m->frame_width = _cfg.panel_width; } + if (m->frame_height < _cfg.panel_height) { m->frame_height = _cfg.panel_height; } + + int window_width = m->frame_width * m->scaling_x; + int window_height = m->frame_height * m->scaling_y; + int scaling_x = m->scaling_x; + int scaling_y = m->scaling_y; + if (m->frame_rotation & 1) { + std::swap(window_width, window_height); + std::swap(scaling_x, scaling_y); + } + + { + m->window = SDL_CreateWindow(_window_title, + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + window_width, window_height, flag); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/ + } m->renderer = SDL_CreateRenderer(m->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); m->texture = SDL_CreateTexture(m->renderer, SDL_PIXELFORMAT_RGB24, - SDL_TEXTUREACCESS_STATIC, _cfg.panel_width, _cfg.panel_height); + SDL_TEXTUREACCESS_STREAMING, _cfg.panel_width, _cfg.panel_height); SDL_SetTextureBlendMode(m->texture, SDL_BLENDMODE_NONE); + + if (m->frame_image) { +// 枠画像用のサーフェイスを作成 + auto sf = SDL_CreateRGBSurfaceFrom((void*)m->frame_image, m->frame_width, m->frame_height, 32, m->frame_width* 4, 0xFF000000, 0xFF0000, 0xFF00, 0xFF); + if (sf != nullptr) { + // 枠画像からテクスチャを作成 + m->texture_frameimage = SDL_CreateTextureFromSurface(m->renderer, sf); + SDL_FreeSurface(sf); + } + } + SDL_SetTextureBlendMode(m->texture_frameimage, SDL_BLENDMODE_BLEND); + _update_scaling(m, scaling_x, scaling_y); } void Panel_sdl::sdl_update(void) @@ -402,6 +569,20 @@ namespace lgfx } } + int angle = monitor.frame_angle; + int target = (monitor.frame_rotation) * 90; + angle = (((target * 4) + (angle * 4) + (angle < target ? 8 : 0)) >> 3); + + if (monitor.frame_angle != angle) + { // 表示する向きを変える + monitor.frame_angle = angle; + sdl_invalidate(); + } else if (monitor.frame_rotation & ~3u) { + monitor.frame_rotation &= 3; + monitor.frame_angle = (monitor.frame_rotation) * 90; + sdl_invalidate(); + } + if (_invalidated || (_display_counter != _texupdate_counter)) { SDL_RendererInfo info; @@ -412,17 +593,54 @@ namespace lgfx SDL_RenderSetVSync(monitor.renderer, !step_exec); } } - SDL_RenderCopy(monitor.renderer, monitor.texture, nullptr, nullptr); + { + int red = 0; + int green = 0; + int blue = 0; +#if defined (M5GFX_BACK_COLOR) + red = ((M5GFX_BACK_COLOR) >> 16) & 0xFF; + green = ((M5GFX_BACK_COLOR) >> 8) & 0xFF; + blue = ((M5GFX_BACK_COLOR) ) & 0xFF; +#endif + SDL_SetRenderDrawColor(monitor.renderer, red, green, blue, 0xFF); + } + SDL_RenderClear(monitor.renderer); + if (_invalidated) + { + _invalidated = false; + int mw, mh; + SDL_GetRendererOutputSize(monitor.renderer , &mw, &mh); + } + render_texture(monitor.texture, monitor.frame_inner_x, monitor.frame_inner_y, _cfg.panel_width, _cfg.panel_height, angle); + render_texture(monitor.texture_frameimage, 0, 0, monitor.frame_width, monitor.frame_height, angle); SDL_RenderPresent(monitor.renderer); _display_counter = _texupdate_counter; if (_invalidated) { _invalidated = false; - SDL_RenderCopy(monitor.renderer, monitor.texture, nullptr, nullptr); + SDL_SetRenderDrawColor(monitor.renderer, 0, 0, 0, 0xFF); + SDL_RenderClear(monitor.renderer); + render_texture(monitor.texture, monitor.frame_inner_x, monitor.frame_inner_y, _cfg.panel_width, _cfg.panel_height, angle); + render_texture(monitor.texture_frameimage, 0, 0, monitor.frame_width, monitor.frame_height, angle); SDL_RenderPresent(monitor.renderer); } } } + void Panel_sdl::render_texture(SDL_Texture* texture, int tx, int ty, int tw, int th, float angle) + { + SDL_Point pivot; + pivot.x = (monitor.frame_width /2.0f - tx) * (float)monitor.scaling_x; + pivot.y = (monitor.frame_height/2.0f - ty) * (float)monitor.scaling_y; + SDL_Rect dstrect; + dstrect.w = tw * monitor.scaling_x; + dstrect.h = th * monitor.scaling_y; + int mw, mh; + SDL_GetRendererOutputSize(monitor.renderer, &mw, &mh); + dstrect.x = mw / 2.0f - pivot.x; + dstrect.y = mh / 2.0f - pivot.y; + SDL_RenderCopyEx(monitor.renderer, texture, nullptr, &dstrect, angle, &pivot, SDL_RendererFlip::SDL_FLIP_NONE); + } + bool Panel_sdl::initFrameBuffer(size_t width, size_t height) { uint8_t** lineArray = (uint8_t**)heap_alloc_dma(height * sizeof(uint8_t*)); @@ -440,7 +658,7 @@ namespace lgfx auto fb = framebuffer; { - for (int y = 0; y < height; ++y) + for (size_t y = 0; y < height; ++y) { lineArray[y] = fb; fb += width; diff --git a/src/lgfx/v1/platforms/sdl/Panel_sdl.hpp b/src/lgfx/v1/platforms/sdl/Panel_sdl.hpp index eb2abe4f..c0226a10 100644 --- a/src/lgfx/v1/platforms/sdl/Panel_sdl.hpp +++ b/src/lgfx/v1/platforms/sdl/Panel_sdl.hpp @@ -21,6 +21,7 @@ Porting for SDL: #pragma once #include "common.hpp" +#include #if defined (SDL_h_) #include "../../panel/Panel_FrameBufferBase.hpp" #include "../../misc/range.hpp" @@ -36,10 +37,21 @@ namespace lgfx SDL_Window* window = nullptr; SDL_Renderer* renderer = nullptr; SDL_Texture* texture = nullptr; + SDL_Texture* texture_frameimage = nullptr; Panel_sdl* panel = nullptr; - int scaling_x = 1; - int scaling_y = 1; - int touch_x, touch_y; + +// 外枠 + const void* frame_image = 0; + uint_fast16_t frame_width = 0; + uint_fast16_t frame_height = 0; + uint_fast16_t frame_inner_x = 0; + uint_fast16_t frame_inner_y = 0; + int_fast16_t frame_rotation = 0; + int_fast16_t frame_angle = 0; + + float scaling_x = 1; + float scaling_y = 1; + int_fast16_t touch_x, touch_y; bool touched = false; bool closing = false; }; @@ -80,6 +92,8 @@ namespace lgfx void setWindowTitle(const char* title); void setScaling(uint_fast8_t scaling_x, uint_fast8_t scaling_y); + void setFrameImage(const void* frame_image, int frame_width, int frame_height, int inner_x, int inner_y); + void setFrameRotation(uint_fast16_t frame_rotaion); static int setup(void); static int loop(void); @@ -87,6 +101,16 @@ namespace lgfx static int main(int(*fn)(bool*), uint32_t msec_step_exec = 512); + static void setShortcutKeymod(SDL_Keymod keymod) { _keymod = keymod; } + + struct KeyCodeMapping_t + { + SDL_KeyCode keycode = SDLK_UNKNOWN; + uint8_t gpio = 0; + }; + static void addKeyCodeMapping(SDL_KeyCode keyCode, uint8_t gpio); + static int getKeyCodeMapping(SDL_KeyCode keyCode); + protected: const char* _window_title = "LGFX Simulator"; SDL_mutex *_sdl_mutex = nullptr; @@ -105,10 +129,14 @@ namespace lgfx static void _event_proc(void); static void _update_proc(void); + static void _update_scaling(monitor_t * m, float sx, float sy); void sdl_invalidate(void) { _invalidated = true; } + void render_texture(SDL_Texture* texture, int tx, int ty, int tw, int th, float angle); bool initFrameBuffer(size_t width, size_t height); void deinitFrameBuffer(void); + static SDL_Keymod _keymod; + struct lock_t { lock_t(Panel_sdl* parent); ~lock_t();