diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h index 91f5d88144..51f8f613a4 100644 --- a/src/frontend/FrontendUtil.h +++ b/src/frontend/FrontendUtil.h @@ -1,99 +1,119 @@ -/* - Copyright 2016-2022 melonDS team - - This file is part of melonDS. - - melonDS is free software: you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation, either version 3 of the License, or (at your option) - any later version. - - melonDS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with melonDS. If not, see http://www.gnu.org/licenses/. -*/ - -#ifndef FRONTENDUTIL_H -#define FRONTENDUTIL_H - -#include "types.h" - -#include -#include - -namespace Frontend -{ - -// setup the display layout based on the provided display size and parameters -// * screenWidth/screenHeight: size of the host display -// * screenLayout: how the DS screens are laid out -// 0 = natural (top screen above bottom screen always) -// 1 = vertical -// 2 = horizontal -// 3 = hybrid -// * rotation: angle at which the DS screens are presented: 0/1/2/3 = 0/90/180/270 -// * sizing: how the display size is shared between the two screens -// 0 = even (both screens get same size) -// 1 = emphasize top screen (make top screen as big as possible, fit bottom screen in remaining space) -// 2 = emphasize bottom screen -// 4 = top only -// 5 = bottom only -// * screenGap: size of the gap between the two screens -// * integerScale: force screens to be scaled up at integer scaling factors -// * screenSwap: whether to swap the position of both screens -// * topAspect/botAspect: ratio by which to scale the top and bottom screen respectively -void SetupScreenLayout(int screenWidth, int screenHeight, - int screenLayout, - int rotation, - int sizing, - int screenGap, - bool integerScale, - bool swapScreens, - float topAspect, float botAspect); - -const int MaxScreenTransforms = 3; - -// get a 2x3 transform matrix for each screen and whether it's a top or bottom screen -// note: the transform assumes an origin point at the top left of the display, -// X going right and Y going down -// for each screen the source coordinates should be (0,0) and (256,192) -// 'out' should point to an array of 6*MaxScreenTransforms floats -// 'kind' should point to an array of MaxScreenTransforms ints -// (0 = indicates top screen, 1 = bottom screen) -// returns the amount of screens -int GetScreenTransforms(float* out, int* kind); - -// de-transform the provided host display coordinates to get coordinates -// on the bottom screen -bool GetTouchCoords(int& x, int& y, bool clamp); - - -// initialize the audio utility -void Init_Audio(int outputfreq); - -// get how many samples to read from the core audio output -// based on how many are needed by the frontend (outlen in samples) -int AudioOut_GetNumSamples(int outlen); - -// resample audio from the core audio output to match the frontend's -// output frequency, and apply specified volume -// note: this assumes the output buffer is interleaved stereo -void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen, int volume); - -// feed silence to the microphone input -void Mic_FeedSilence(); - -// feed random noise to the microphone input -void Mic_FeedNoise(); - -// feed an external buffer to the microphone input -// buffer should be mono -void Mic_FeedExternalBuffer(); -void Mic_SetExternalBuffer(s16* buffer, u32 len); - -} - -#endif // FRONTENDUTIL_H +/* + Copyright 2016-2022 melonDS team + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef FRONTENDUTIL_H +#define FRONTENDUTIL_H + +#include "types.h" + +#include +#include + +namespace Frontend +{ + +enum ScreenLayout +{ + screenLayout_Natural, // top screen above bottom screen always + screenLayout_Horizontal, + screenLayout_Vertical, + screenLayout_Hybrid, + screenLayout_MAX, +}; + +enum ScreenRotation +{ + screenRot_0Deg, + screenRot_90Deg, + screenRot_180Deg, + screenRot_270Deg, + screenRot_MAX, +}; + +enum ScreenSizing +{ + screenSizing_Even, // both screens get same size + screenSizing_EmphTop, // make top screen as big as possible, fit bottom screen in remaining space + screenSizing_EmphBot, + screenSizing_Auto, // not applied in SetupScreenLayout + screenSizing_TopOnly, + screenSizing_BotOnly, + screenSizing_MAX, +}; + +// setup the display layout based on the provided display size and parameters +// * screenWidth/screenHeight: size of the host display +// * screenLayout: how the DS screens are laid out +// * rotation: angle at which the DS screens are presented +// * sizing: how the display size is shared between the two screens +// * screenGap: size of the gap between the two screens in pixels +// * integerScale: force screens to be scaled up at integer scaling factors +// * screenSwap: whether to swap the position of both screens +// * topAspect/botAspect: ratio by which to scale the top and bottom screen respectively +void SetupScreenLayout(int screenWidth, int screenHeight, + ScreenLayout screenLayout, + ScreenRotation rotation, + ScreenSizing sizing, + int screenGap, + bool integerScale, + bool swapScreens, + float topAspect, float botAspect); + +const int MaxScreenTransforms = 3; + +// get a 2x3 transform matrix for each screen and whether it's a top or bottom screen +// note: the transform assumes an origin point at the top left of the display, +// X going right and Y going down +// for each screen the source coordinates should be (0,0) and (256,192) +// 'out' should point to an array of 6*MaxScreenTransforms floats +// 'kind' should point to an array of MaxScreenTransforms ints +// (0 = indicates top screen, 1 = bottom screen) +// returns the amount of screens +int GetScreenTransforms(float* out, int* kind); + +// de-transform the provided host display coordinates to get coordinates +// on the bottom screen +bool GetTouchCoords(int& x, int& y, bool clamp); + + +// initialize the audio utility +void Init_Audio(int outputfreq); + +// get how many samples to read from the core audio output +// based on how many are needed by the frontend (outlen in samples) +int AudioOut_GetNumSamples(int outlen); + +// resample audio from the core audio output to match the frontend's +// output frequency, and apply specified volume +// note: this assumes the output buffer is interleaved stereo +void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen, int volume); + +// feed silence to the microphone input +void Mic_FeedSilence(); + +// feed random noise to the microphone input +void Mic_FeedNoise(); + +// feed an external buffer to the microphone input +// buffer should be mono +void Mic_FeedExternalBuffer(); +void Mic_SetExternalBuffer(s16* buffer, u32 len); + +} + +#endif // FRONTENDUTIL_H diff --git a/src/frontend/Util_Video.cpp b/src/frontend/Util_Video.cpp index 778c299dc4..e4c49e91df 100644 --- a/src/frontend/Util_Video.cpp +++ b/src/frontend/Util_Video.cpp @@ -1,553 +1,553 @@ -/* - Copyright 2016-2022 melonDS team - - This file is part of melonDS. - - melonDS is free software: you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation, either version 3 of the License, or (at your option) - any later version. - - melonDS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with melonDS. If not, see http://www.gnu.org/licenses/. -*/ - -#include -#include -#include -#include -#include - -#include "FrontendUtil.h" - - -namespace Frontend -{ - -float TopScreenMtx[6]; -float BotScreenMtx[6]; -float HybScreenMtx[6]; -float TouchMtx[6]; -float HybTouchMtx[6]; -bool TopEnable; -bool BotEnable; -bool HybEnable; -int HybScreen; -int HybPrevTouchScreen; // 0:unknown, 1:buttom screen, 2:hybrid screen - -void M23_Identity(float* m) -{ - m[0] = 1; m[1] = 0; - m[2] = 0; m[3] = 1; - m[4] = 0; m[5] = 0; -} - -void M23_Scale(float* m, float s) -{ - m[0] *= s; m[1] *= s; - m[2] *= s; m[3] *= s; - m[4] *= s; m[5] *= s; -} - -void M23_Scale(float* m, float x, float y) -{ - m[0] *= x; m[1] *= y; - m[2] *= x; m[3] *= y; - m[4] *= x; m[5] *= y; -} - -void M23_RotateFast(float* m, int angle) -{ - if (angle == 0) return; - - float temp[4]; memcpy(temp, m, sizeof(float)*4); - - switch (angle) - { - case 1: // 90 - m[0] = temp[2]; - m[1] = temp[3]; - m[2] = -temp[0]; - m[3] = -temp[1]; - break; - - case 2: // 180 - m[0] = -temp[0]; - m[1] = -temp[1]; - m[2] = -temp[2]; - m[3] = -temp[3]; - break; - - case 3: // 270 - m[0] = -temp[2]; - m[1] = -temp[3]; - m[2] = temp[0]; - m[3] = temp[1]; - break; - } -} - -void M23_Translate(float* m, float tx, float ty) -{ - m[4] += tx; - m[5] += ty; -} - -void M23_Multiply(float* m, float* _a, float* _b) -{ - float a[6]; memcpy(a, _a, 6*sizeof(float)); - float b[6]; memcpy(b, _b, 6*sizeof(float)); - - m[0] = (a[0] * b[0]) + (a[2] * b[1]); - m[1] = (a[1] * b[0]) + (a[3] * b[1]); - - m[2] = (a[0] * b[2]) + (a[2] * b[3]); - m[3] = (a[1] * b[2]) + (a[3] * b[3]); - - m[4] = (a[0] * b[4]) + (a[2] * b[5]) + a[4]; - m[5] = (a[1] * b[4]) + (a[3] * b[5]) + a[5]; -} - -void M23_Transform(float* m, float& x, float& y) -{ - float vx = x; - float vy = y; - - x = (vx * m[0]) + (vy * m[2]) + m[4]; - y = (vx * m[1]) + (vy * m[3]) + m[5]; -} - - -void SetupScreenLayout(int screenWidth, int screenHeight, - int screenLayout, - int rotation, - int sizing, - int screenGap, - bool integerScale, - bool swapScreens, - float topAspect, float botAspect) -{ - HybEnable = screenLayout == 3; - if (HybEnable) - { - screenLayout = 0; - sizing = 0; - HybScreen = swapScreens ? 1 : 0; - swapScreens = false; - topAspect = botAspect = 1; - HybPrevTouchScreen = 0; - } - - float refpoints[6][2] = - { - {0, 0}, {256, 192}, - {0, 0}, {256, 192}, - {0, 0}, {256, 192} - }; - - int layout = screenLayout == 0 - ? rotation % 2 - : screenLayout - 1; - - float botScale = 1; - float hybScale = 1; - float botTrans[4] = {0}; - float hybTrans[2] = {0}; - - M23_Identity(TopScreenMtx); - M23_Identity(BotScreenMtx); - M23_Identity(HybScreenMtx); - - M23_Translate(TopScreenMtx, -256/2, -192/2); - M23_Translate(BotScreenMtx, -256/2, -192/2); - - M23_Scale(TopScreenMtx, topAspect, 1); - M23_Scale(BotScreenMtx, botAspect, 1); - - // rotation - { - float rotmtx[6]; - M23_Identity(rotmtx); - - M23_RotateFast(rotmtx, rotation); - M23_Multiply(TopScreenMtx, rotmtx, TopScreenMtx); - M23_Multiply(BotScreenMtx, rotmtx, BotScreenMtx); - M23_Multiply(HybScreenMtx, rotmtx, HybScreenMtx); - - M23_Transform(TopScreenMtx, refpoints[0][0], refpoints[0][1]); - M23_Transform(TopScreenMtx, refpoints[1][0], refpoints[1][1]); - M23_Transform(BotScreenMtx, refpoints[2][0], refpoints[2][1]); - M23_Transform(BotScreenMtx, refpoints[3][0], refpoints[3][1]); - } - - int posRefPointOffset = 0; - int posRefPointCount = HybEnable ? 6 : 4; - - if (sizing == 4 || sizing == 5) - { - float* mtx = sizing == 4 ? TopScreenMtx : BotScreenMtx; - int primOffset = sizing == 4 ? 0 : 2; - int secOffset = sizing == 5 ? 2 : 0; - - float hSize = fabsf(refpoints[primOffset][0] - refpoints[primOffset+1][0]); - float vSize = fabsf(refpoints[primOffset][1] - refpoints[primOffset+1][1]); - - float scale = std::min(screenWidth / hSize, screenHeight / vSize); - if (integerScale) - scale = floorf(scale); - - TopEnable = sizing == 4; - BotEnable = sizing == 5; - botScale = scale; - - M23_Scale(mtx, scale); - refpoints[primOffset][0] *= scale; - refpoints[primOffset][1] *= scale; - refpoints[primOffset+1][0] *= scale; - refpoints[primOffset+1][1] *= scale; - - posRefPointOffset = primOffset; - posRefPointCount = 2; - } - else - { - TopEnable = BotEnable = true; - - // move screens apart - { - int idx = layout == 0 ? 1 : 0; - - bool moveV = rotation % 2 == layout; - - float offsetBot = (moveV ? 192.0 : 256.0 * botAspect) / 2.0 + screenGap / 2.0; - float offsetTop = -((moveV ? 192.0 : 256.0 * topAspect) / 2.0 + screenGap / 2.0); - - if ((rotation == 1 || rotation == 2) ^ swapScreens) - { - offsetTop *= -1; - offsetBot *= -1; - } - - M23_Translate(TopScreenMtx, (idx==0)?offsetTop:0, (idx==1)?offsetTop:0); - M23_Translate(BotScreenMtx, (idx==0)?offsetBot:0, (idx==1)?offsetBot:0); - - refpoints[0][idx] += offsetTop; - refpoints[1][idx] += offsetTop; - refpoints[2][idx] += offsetBot; - refpoints[3][idx] += offsetBot; - - botTrans[idx] = offsetBot; - } - - // scale - { - if (sizing == 0) - { - float minX = refpoints[0][0], maxX = minX; - float minY = refpoints[0][1], maxY = minY; - - for (int i = 1; i < 4; i++) - { - minX = std::min(minX, refpoints[i][0]); - minY = std::min(minY, refpoints[i][1]); - maxX = std::max(maxX, refpoints[i][0]); - maxY = std::max(maxY, refpoints[i][1]); - } - - float hSize = maxX - minX; - float vSize = maxY - minY; - - if (HybEnable) - { - hybScale = layout == 0 - ? (4 * vSize) / (3 * hSize) - : (4 * hSize) / (3 * vSize); - if (layout == 0) - hSize += (vSize * 4) / 3; - else - vSize += (hSize * 4) / 3; - } - - // scale evenly - float scale = std::min(screenWidth / hSize, screenHeight / vSize); - - if (integerScale) - scale = floor(scale); - - hybScale *= scale; - - M23_Scale(TopScreenMtx, scale); - M23_Scale(BotScreenMtx, scale); - M23_Scale(HybScreenMtx, hybScale); - - for (int i = 0; i < 4; i++) - { - refpoints[i][0] *= scale; - refpoints[i][1] *= scale; - } - - botScale = scale; - - // move screens aside - if (HybEnable) - { - float hybWidth = layout == 0 - ? (scale * vSize * 4) / 3 - : (scale * hSize * 4) / 3; - - if (rotation > 1) - hybWidth *= -1; - - M23_Translate(TopScreenMtx, (layout==0)?hybWidth:0, (layout==1)?hybWidth:0); - M23_Translate(BotScreenMtx, (layout==0)?hybWidth:0, (layout==1)?hybWidth:0); - refpoints[0][layout] += hybWidth; - refpoints[1][layout] += hybWidth; - refpoints[2][layout] += hybWidth; - refpoints[3][layout] += hybWidth; - - botTrans[2+layout] += hybWidth; - - hybTrans[0] = scale * (rotation == 0 || rotation == 3 ? minX : maxX); - hybTrans[1] = scale * (rotation == 0 || rotation == 1 ? minY : maxY); - M23_Translate(HybScreenMtx, hybTrans[0], hybTrans[1]); - - M23_Transform(HybScreenMtx, refpoints[4][0], refpoints[4][1]); - M23_Transform(HybScreenMtx, refpoints[5][0], refpoints[5][1]); - } - } - else - { - int primOffset = (sizing == 1) ? 0 : 2; - int secOffset = (sizing == 1) ? 2 : 0; - float* primMtx = (sizing == 1) ? TopScreenMtx : BotScreenMtx; - float* secMtx = (sizing == 1) ? BotScreenMtx : TopScreenMtx; - - float primMinX = refpoints[primOffset][0], primMaxX = primMinX; - float primMinY = refpoints[primOffset][1], primMaxY = primMinY; - float secMinX = refpoints[secOffset][0], secMaxX = secMinX; - float secMinY = refpoints[secOffset][1], secMaxY = secMinY; - - primMinX = std::min(primMinX, refpoints[primOffset+1][0]); - primMinY = std::min(primMinY, refpoints[primOffset+1][1]); - primMaxX = std::max(primMaxX, refpoints[primOffset+1][0]); - primMaxY = std::max(primMaxY, refpoints[primOffset+1][1]); - - secMinX = std::min(secMinX, refpoints[secOffset+1][0]); - secMinY = std::min(secMinY, refpoints[secOffset+1][1]); - secMaxX = std::max(secMaxX, refpoints[secOffset+1][0]); - secMaxY = std::max(secMaxY, refpoints[secOffset+1][1]); - - float primHSize = layout == 1 ? std::max(primMaxX, -primMinX) : primMaxX - primMinX; - float primVSize = layout == 0 ? std::max(primMaxY, -primMinY) : primMaxY - primMinY; - - float secHSize = layout == 1 ? std::max(secMaxX, -secMinX) : secMaxX - secMinX; - float secVSize = layout == 0 ? std::max(secMaxY, -secMinY) : secMaxY - secMinY; - - float primScale = std::min(screenWidth / primHSize, screenHeight / primVSize); - float secScale = 1.f; - - if (integerScale) - primScale = floorf(primScale); - - if (layout == 0) - { - if (screenHeight - primVSize * primScale < secVSize) - primScale = std::min(screenWidth / primHSize, (screenHeight - secVSize) / primVSize); - else - secScale = std::min((screenHeight - primVSize * primScale) / secVSize, screenWidth / secHSize); - } - else - { - if (screenWidth - primHSize * primScale < secHSize) - primScale = std::min((screenWidth - secHSize) / primHSize, screenHeight / primVSize); - else - secScale = std::min((screenWidth - primHSize * primScale) / secHSize, screenHeight / secVSize); - } - - if (integerScale) - { - primScale = floorf(primScale); - secScale = floorf(secScale); - } - - M23_Scale(primMtx, primScale); - M23_Scale(secMtx, secScale); - - refpoints[primOffset+0][0] *= primScale; - refpoints[primOffset+0][1] *= primScale; - refpoints[primOffset+1][0] *= primScale; - refpoints[primOffset+1][1] *= primScale; - refpoints[secOffset+0][0] *= secScale; - refpoints[secOffset+0][1] *= secScale; - refpoints[secOffset+1][0] *= secScale; - refpoints[secOffset+1][1] *= secScale; - - botScale = (sizing == 1) ? secScale : primScale; - } - } - } - - // position - { - float minX = refpoints[posRefPointOffset][0], maxX = minX; - float minY = refpoints[posRefPointOffset][1], maxY = minY; - - for (int i = posRefPointOffset + 1; i < posRefPointOffset + posRefPointCount; i++) - { - minX = std::min(minX, refpoints[i][0]); - minY = std::min(minY, refpoints[i][1]); - maxX = std::max(maxX, refpoints[i][0]); - maxY = std::max(maxY, refpoints[i][1]); - } - - float width = maxX - minX; - float height = maxY - minY; - - float tx = (screenWidth/2) - (width/2) - minX; - float ty = (screenHeight/2) - (height/2) - minY; - - M23_Translate(TopScreenMtx, tx, ty); - M23_Translate(BotScreenMtx, tx, ty); - M23_Translate(HybScreenMtx, tx, ty); - - botTrans[2] += tx; botTrans[3] += ty; - hybTrans[0] += tx; hybTrans[1] += ty; - } - - // prepare a 'reverse' matrix for the touchscreen - // this matrix undoes the transforms applied to the bottom screen - // and can be used to calculate touchscreen coords from host screen coords - if (BotEnable) - { - M23_Identity(TouchMtx); - - M23_Translate(TouchMtx, -botTrans[2], -botTrans[3]); - M23_Scale(TouchMtx, 1.f / botScale); - M23_Translate(TouchMtx, -botTrans[0], -botTrans[1]); - - float rotmtx[6]; - M23_Identity(rotmtx); - M23_RotateFast(rotmtx, (4-rotation) & 3); - M23_Multiply(TouchMtx, rotmtx, TouchMtx); - - M23_Scale(TouchMtx, 1.f/botAspect, 1); - M23_Translate(TouchMtx, 256/2, 192/2); - - if (HybEnable && HybScreen == 1) - { - M23_Identity(HybTouchMtx); - - M23_Translate(HybTouchMtx, -hybTrans[0], -hybTrans[1]); - M23_Scale(HybTouchMtx, 1.f/hybScale); - M23_Multiply(HybTouchMtx, rotmtx, HybTouchMtx); - } - } -} - -int GetScreenTransforms(float* out, int* kind) -{ - int num = 0; - if (TopEnable) - { - memcpy(out + 6*num, TopScreenMtx, sizeof(TopScreenMtx)); - kind[num++] = 0; - } - if (BotEnable) - { - memcpy(out + 6*num, BotScreenMtx, sizeof(BotScreenMtx)); - kind[num++] = 1; - } - if (HybEnable) - { - memcpy(out + 6*num, HybScreenMtx, sizeof(HybScreenMtx)); - kind[num++] = HybScreen; - } - return num; -} - -bool GetTouchCoords(int& x, int& y, bool clamp) -{ - if (HybEnable && HybScreen == 1) - { - float vx = x; - float vy = y; - float hvx = x; - float hvy = y; - - M23_Transform(TouchMtx, vx, vy); - M23_Transform(HybTouchMtx, hvx, hvy); - - if (clamp) - { - if (HybPrevTouchScreen == 1) - { - x = std::clamp((int)vx, 0, 255); - y = std::clamp((int)vy, 0, 191); - - return true; - } - if (HybPrevTouchScreen == 2) - { - x = std::clamp((int)hvx, 0, 255); - y = std::clamp((int)hvy, 0, 191); - - return true; - } - } - else - { - if (vx >= 0 && vx < 256 && vy >= 0 && vy < 192) - { - HybPrevTouchScreen = 1; - - x = (int)vx; - y = (int)vy; - - return true; - } - if (hvx >= 0 && hvx < 256 && hvy >= 0 && hvy < 192) - { - HybPrevTouchScreen = 2; - - x = (int)hvx; - y = (int)hvy; - - return true; - } - } - } - else if (BotEnable) - { - float vx = x; - float vy = y; - - M23_Transform(TouchMtx, vx, vy); - - if (clamp) - { - x = std::clamp((int)vx, 0, 255); - y = std::clamp((int)vy, 0, 191); - - return true; - } - else - { - if (vx >= 0 && vx < 256 && vy >= 0 && vy < 192) - { - x = (int)vx; - y = (int)vy; - - return true; - } - } - } - - return false; -} - -} - +/* + Copyright 2016-2022 melonDS team + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include +#include +#include +#include +#include + +#include "FrontendUtil.h" + + +namespace Frontend +{ + +float TopScreenMtx[6]; +float BotScreenMtx[6]; +float HybScreenMtx[6]; +float TouchMtx[6]; +float HybTouchMtx[6]; +bool TopEnable; +bool BotEnable; +bool HybEnable; +int HybScreen; +int HybPrevTouchScreen; // 0:unknown, 1:buttom screen, 2:hybrid screen + +void M23_Identity(float* m) +{ + m[0] = 1; m[1] = 0; + m[2] = 0; m[3] = 1; + m[4] = 0; m[5] = 0; +} + +void M23_Scale(float* m, float s) +{ + m[0] *= s; m[1] *= s; + m[2] *= s; m[3] *= s; + m[4] *= s; m[5] *= s; +} + +void M23_Scale(float* m, float x, float y) +{ + m[0] *= x; m[1] *= y; + m[2] *= x; m[3] *= y; + m[4] *= x; m[5] *= y; +} + +void M23_RotateFast(float* m, int angle) +{ + if (angle == 0) return; + + float temp[4]; memcpy(temp, m, sizeof(float)*4); + + switch (angle) + { + case 1: // 90 + m[0] = temp[2]; + m[1] = temp[3]; + m[2] = -temp[0]; + m[3] = -temp[1]; + break; + + case 2: // 180 + m[0] = -temp[0]; + m[1] = -temp[1]; + m[2] = -temp[2]; + m[3] = -temp[3]; + break; + + case 3: // 270 + m[0] = -temp[2]; + m[1] = -temp[3]; + m[2] = temp[0]; + m[3] = temp[1]; + break; + } +} + +void M23_Translate(float* m, float tx, float ty) +{ + m[4] += tx; + m[5] += ty; +} + +void M23_Multiply(float* m, float* _a, float* _b) +{ + float a[6]; memcpy(a, _a, 6*sizeof(float)); + float b[6]; memcpy(b, _b, 6*sizeof(float)); + + m[0] = (a[0] * b[0]) + (a[2] * b[1]); + m[1] = (a[1] * b[0]) + (a[3] * b[1]); + + m[2] = (a[0] * b[2]) + (a[2] * b[3]); + m[3] = (a[1] * b[2]) + (a[3] * b[3]); + + m[4] = (a[0] * b[4]) + (a[2] * b[5]) + a[4]; + m[5] = (a[1] * b[4]) + (a[3] * b[5]) + a[5]; +} + +void M23_Transform(float* m, float& x, float& y) +{ + float vx = x; + float vy = y; + + x = (vx * m[0]) + (vy * m[2]) + m[4]; + y = (vx * m[1]) + (vy * m[3]) + m[5]; +} + + +void SetupScreenLayout(int screenWidth, int screenHeight, + ScreenLayout screenLayout, + ScreenRotation rotation, + ScreenSizing sizing, + int screenGap, + bool integerScale, + bool swapScreens, + float topAspect, float botAspect) +{ + HybEnable = screenLayout == 3; + if (HybEnable) + { + screenLayout = screenLayout_Natural; + sizing = screenSizing_Even; + HybScreen = swapScreens ? 1 : 0; + swapScreens = false; + topAspect = botAspect = 1; + HybPrevTouchScreen = 0; + } + + float refpoints[6][2] = + { + {0, 0}, {256, 192}, + {0, 0}, {256, 192}, + {0, 0}, {256, 192} + }; + + int layout = screenLayout == screenLayout_Natural + ? rotation % 2 + : screenLayout - 1; + + float botScale = 1; + float hybScale = 1; + float botTrans[4] = {0}; + float hybTrans[2] = {0}; + + M23_Identity(TopScreenMtx); + M23_Identity(BotScreenMtx); + M23_Identity(HybScreenMtx); + + M23_Translate(TopScreenMtx, -256/2, -192/2); + M23_Translate(BotScreenMtx, -256/2, -192/2); + + M23_Scale(TopScreenMtx, topAspect, 1); + M23_Scale(BotScreenMtx, botAspect, 1); + + // rotation + { + float rotmtx[6]; + M23_Identity(rotmtx); + + M23_RotateFast(rotmtx, rotation); + M23_Multiply(TopScreenMtx, rotmtx, TopScreenMtx); + M23_Multiply(BotScreenMtx, rotmtx, BotScreenMtx); + M23_Multiply(HybScreenMtx, rotmtx, HybScreenMtx); + + M23_Transform(TopScreenMtx, refpoints[0][0], refpoints[0][1]); + M23_Transform(TopScreenMtx, refpoints[1][0], refpoints[1][1]); + M23_Transform(BotScreenMtx, refpoints[2][0], refpoints[2][1]); + M23_Transform(BotScreenMtx, refpoints[3][0], refpoints[3][1]); + } + + int posRefPointOffset = 0; + int posRefPointCount = HybEnable ? 6 : 4; + + if (sizing == screenSizing_TopOnly || sizing == screenSizing_BotOnly) + { + float* mtx = sizing == screenSizing_TopOnly ? TopScreenMtx : BotScreenMtx; + int primOffset = sizing == screenSizing_TopOnly ? 0 : 2; + int secOffset = sizing == screenSizing_BotOnly ? 2 : 0; + + float hSize = fabsf(refpoints[primOffset][0] - refpoints[primOffset+1][0]); + float vSize = fabsf(refpoints[primOffset][1] - refpoints[primOffset+1][1]); + + float scale = std::min(screenWidth / hSize, screenHeight / vSize); + if (integerScale) + scale = floorf(scale); + + TopEnable = sizing == screenSizing_TopOnly; + BotEnable = sizing == screenSizing_BotOnly; + botScale = scale; + + M23_Scale(mtx, scale); + refpoints[primOffset][0] *= scale; + refpoints[primOffset][1] *= scale; + refpoints[primOffset+1][0] *= scale; + refpoints[primOffset+1][1] *= scale; + + posRefPointOffset = primOffset; + posRefPointCount = 2; + } + else + { + TopEnable = BotEnable = true; + + // move screens apart + { + int idx = layout == 0 ? 1 : 0; + + bool moveV = rotation % 2 == layout; + + float offsetBot = (moveV ? 192.0 : 256.0 * botAspect) / 2.0 + screenGap / 2.0; + float offsetTop = -((moveV ? 192.0 : 256.0 * topAspect) / 2.0 + screenGap / 2.0); + + if ((rotation == 1 || rotation == 2) ^ swapScreens) + { + offsetTop *= -1; + offsetBot *= -1; + } + + M23_Translate(TopScreenMtx, (idx==0)?offsetTop:0, (idx==1)?offsetTop:0); + M23_Translate(BotScreenMtx, (idx==0)?offsetBot:0, (idx==1)?offsetBot:0); + + refpoints[0][idx] += offsetTop; + refpoints[1][idx] += offsetTop; + refpoints[2][idx] += offsetBot; + refpoints[3][idx] += offsetBot; + + botTrans[idx] = offsetBot; + } + + // scale + { + if (sizing == screenSizing_Even) + { + float minX = refpoints[0][0], maxX = minX; + float minY = refpoints[0][1], maxY = minY; + + for (int i = 1; i < 4; i++) + { + minX = std::min(minX, refpoints[i][0]); + minY = std::min(minY, refpoints[i][1]); + maxX = std::max(maxX, refpoints[i][0]); + maxY = std::max(maxY, refpoints[i][1]); + } + + float hSize = maxX - minX; + float vSize = maxY - minY; + + if (HybEnable) + { + hybScale = layout == 0 + ? (4 * vSize) / (3 * hSize) + : (4 * hSize) / (3 * vSize); + if (layout == 0) + hSize += (vSize * 4) / 3; + else + vSize += (hSize * 4) / 3; + } + + // scale evenly + float scale = std::min(screenWidth / hSize, screenHeight / vSize); + + if (integerScale) + scale = floor(scale); + + hybScale *= scale; + + M23_Scale(TopScreenMtx, scale); + M23_Scale(BotScreenMtx, scale); + M23_Scale(HybScreenMtx, hybScale); + + for (int i = 0; i < 4; i++) + { + refpoints[i][0] *= scale; + refpoints[i][1] *= scale; + } + + botScale = scale; + + // move screens aside + if (HybEnable) + { + float hybWidth = layout == 0 + ? (scale * vSize * 4) / 3 + : (scale * hSize * 4) / 3; + + if (rotation > screenRot_90Deg) + hybWidth *= -1; + + M23_Translate(TopScreenMtx, (layout==0)?hybWidth:0, (layout==1)?hybWidth:0); + M23_Translate(BotScreenMtx, (layout==0)?hybWidth:0, (layout==1)?hybWidth:0); + refpoints[0][layout] += hybWidth; + refpoints[1][layout] += hybWidth; + refpoints[2][layout] += hybWidth; + refpoints[3][layout] += hybWidth; + + botTrans[2+layout] += hybWidth; + + hybTrans[0] = scale * (rotation == screenRot_0Deg || rotation == screenRot_270Deg ? minX : maxX); + hybTrans[1] = scale * (rotation == screenRot_0Deg || rotation == screenRot_90Deg ? minY : maxY); + M23_Translate(HybScreenMtx, hybTrans[0], hybTrans[1]); + + M23_Transform(HybScreenMtx, refpoints[4][0], refpoints[4][1]); + M23_Transform(HybScreenMtx, refpoints[5][0], refpoints[5][1]); + } + } + else + { + int primOffset = (sizing == screenSizing_EmphTop) ? 0 : 2; + int secOffset = (sizing == screenSizing_EmphTop) ? 2 : 0; + float* primMtx = (sizing == screenSizing_EmphTop) ? TopScreenMtx : BotScreenMtx; + float* secMtx = (sizing == screenSizing_EmphTop) ? BotScreenMtx : TopScreenMtx; + + float primMinX = refpoints[primOffset][0], primMaxX = primMinX; + float primMinY = refpoints[primOffset][1], primMaxY = primMinY; + float secMinX = refpoints[secOffset][0], secMaxX = secMinX; + float secMinY = refpoints[secOffset][1], secMaxY = secMinY; + + primMinX = std::min(primMinX, refpoints[primOffset+1][0]); + primMinY = std::min(primMinY, refpoints[primOffset+1][1]); + primMaxX = std::max(primMaxX, refpoints[primOffset+1][0]); + primMaxY = std::max(primMaxY, refpoints[primOffset+1][1]); + + secMinX = std::min(secMinX, refpoints[secOffset+1][0]); + secMinY = std::min(secMinY, refpoints[secOffset+1][1]); + secMaxX = std::max(secMaxX, refpoints[secOffset+1][0]); + secMaxY = std::max(secMaxY, refpoints[secOffset+1][1]); + + float primHSize = layout == 1 ? std::max(primMaxX, -primMinX) : primMaxX - primMinX; + float primVSize = layout == 0 ? std::max(primMaxY, -primMinY) : primMaxY - primMinY; + + float secHSize = layout == 1 ? std::max(secMaxX, -secMinX) : secMaxX - secMinX; + float secVSize = layout == 0 ? std::max(secMaxY, -secMinY) : secMaxY - secMinY; + + float primScale = std::min(screenWidth / primHSize, screenHeight / primVSize); + float secScale = 1.f; + + if (integerScale) + primScale = floorf(primScale); + + if (layout == 0) + { + if (screenHeight - primVSize * primScale < secVSize) + primScale = std::min(screenWidth / primHSize, (screenHeight - secVSize) / primVSize); + else + secScale = std::min((screenHeight - primVSize * primScale) / secVSize, screenWidth / secHSize); + } + else + { + if (screenWidth - primHSize * primScale < secHSize) + primScale = std::min((screenWidth - secHSize) / primHSize, screenHeight / primVSize); + else + secScale = std::min((screenWidth - primHSize * primScale) / secHSize, screenHeight / secVSize); + } + + if (integerScale) + { + primScale = floorf(primScale); + secScale = floorf(secScale); + } + + M23_Scale(primMtx, primScale); + M23_Scale(secMtx, secScale); + + refpoints[primOffset+0][0] *= primScale; + refpoints[primOffset+0][1] *= primScale; + refpoints[primOffset+1][0] *= primScale; + refpoints[primOffset+1][1] *= primScale; + refpoints[secOffset+0][0] *= secScale; + refpoints[secOffset+0][1] *= secScale; + refpoints[secOffset+1][0] *= secScale; + refpoints[secOffset+1][1] *= secScale; + + botScale = (sizing == screenSizing_EmphTop) ? secScale : primScale; + } + } + } + + // position + { + float minX = refpoints[posRefPointOffset][0], maxX = minX; + float minY = refpoints[posRefPointOffset][1], maxY = minY; + + for (int i = posRefPointOffset + 1; i < posRefPointOffset + posRefPointCount; i++) + { + minX = std::min(minX, refpoints[i][0]); + minY = std::min(minY, refpoints[i][1]); + maxX = std::max(maxX, refpoints[i][0]); + maxY = std::max(maxY, refpoints[i][1]); + } + + float width = maxX - minX; + float height = maxY - minY; + + float tx = (screenWidth/2) - (width/2) - minX; + float ty = (screenHeight/2) - (height/2) - minY; + + M23_Translate(TopScreenMtx, tx, ty); + M23_Translate(BotScreenMtx, tx, ty); + M23_Translate(HybScreenMtx, tx, ty); + + botTrans[2] += tx; botTrans[3] += ty; + hybTrans[0] += tx; hybTrans[1] += ty; + } + + // prepare a 'reverse' matrix for the touchscreen + // this matrix undoes the transforms applied to the bottom screen + // and can be used to calculate touchscreen coords from host screen coords + if (BotEnable) + { + M23_Identity(TouchMtx); + + M23_Translate(TouchMtx, -botTrans[2], -botTrans[3]); + M23_Scale(TouchMtx, 1.f / botScale); + M23_Translate(TouchMtx, -botTrans[0], -botTrans[1]); + + float rotmtx[6]; + M23_Identity(rotmtx); + M23_RotateFast(rotmtx, (4-rotation) & 3); + M23_Multiply(TouchMtx, rotmtx, TouchMtx); + + M23_Scale(TouchMtx, 1.f/botAspect, 1); + M23_Translate(TouchMtx, 256/2, 192/2); + + if (HybEnable && HybScreen == 1) + { + M23_Identity(HybTouchMtx); + + M23_Translate(HybTouchMtx, -hybTrans[0], -hybTrans[1]); + M23_Scale(HybTouchMtx, 1.f/hybScale); + M23_Multiply(HybTouchMtx, rotmtx, HybTouchMtx); + } + } +} + +int GetScreenTransforms(float* out, int* kind) +{ + int num = 0; + if (TopEnable) + { + memcpy(out + 6*num, TopScreenMtx, sizeof(TopScreenMtx)); + kind[num++] = 0; + } + if (BotEnable) + { + memcpy(out + 6*num, BotScreenMtx, sizeof(BotScreenMtx)); + kind[num++] = 1; + } + if (HybEnable) + { + memcpy(out + 6*num, HybScreenMtx, sizeof(HybScreenMtx)); + kind[num++] = HybScreen; + } + return num; +} + +bool GetTouchCoords(int& x, int& y, bool clamp) +{ + if (HybEnable && HybScreen == 1) + { + float vx = x; + float vy = y; + float hvx = x; + float hvy = y; + + M23_Transform(TouchMtx, vx, vy); + M23_Transform(HybTouchMtx, hvx, hvy); + + if (clamp) + { + if (HybPrevTouchScreen == 1) + { + x = std::clamp((int)vx, 0, 255); + y = std::clamp((int)vy, 0, 191); + + return true; + } + if (HybPrevTouchScreen == 2) + { + x = std::clamp((int)hvx, 0, 255); + y = std::clamp((int)hvy, 0, 191); + + return true; + } + } + else + { + if (vx >= 0 && vx < 256 && vy >= 0 && vy < 192) + { + HybPrevTouchScreen = 1; + + x = (int)vx; + y = (int)vy; + + return true; + } + if (hvx >= 0 && hvx < 256 && hvy >= 0 && hvy < 192) + { + HybPrevTouchScreen = 2; + + x = (int)hvx; + y = (int)hvy; + + return true; + } + } + } + else if (BotEnable) + { + float vx = x; + float vy = y; + + M23_Transform(TouchMtx, vx, vy); + + if (clamp) + { + x = std::clamp((int)vx, 0, 255); + y = std::clamp((int)vy, 0, 191); + + return true; + } + else + { + if (vx >= 0 && vx < 256 && vy >= 0 && vy < 192) + { + x = (int)vx; + y = (int)vy; + + return true; + } + } + } + + return false; +} + +} + diff --git a/src/frontend/qt_sdl/Config.h b/src/frontend/qt_sdl/Config.h index b2b56f2c42..1cd0e56238 100644 --- a/src/frontend/qt_sdl/Config.h +++ b/src/frontend/qt_sdl/Config.h @@ -42,17 +42,6 @@ enum HK_MAX }; -enum -{ - screenSizing_Even, - screenSizing_EmphTop, - screenSizing_EmphBot, - screenSizing_Auto, - screenSizing_TopOnly, - screenSizing_BotOnly, - screenSizing_MAX, -}; - enum { micInputType_Silence, diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index a7a1b96944..e5e1977ba8 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -174,13 +174,14 @@ const struct { int id; float ratio; const char* label; } aspectRatios[] = { 2, (21.f / 9) / (4.f / 3), "21:9" }, { 3, 0, "window" } }; +constexpr int AspectRatiosNum = sizeof(aspectRatios) / sizeof(aspectRatios[0]); EmuThread::EmuThread(QObject* parent) : QThread(parent) { - EmuStatus = 0; - EmuRunning = 2; - EmuPause = 0; + EmuStatus = emuStatus_Exit; + EmuRunning = emuStatus_Paused; + EmuPauseStack = EmuPauseStackRunning; RunningSomething = false; connect(this, SIGNAL(windowUpdate()), mainWindow->panelWidget, SLOT(repaint())); @@ -353,7 +354,7 @@ void EmuThread::run() char melontitle[100]; - while (EmuRunning != 0) + while (EmuRunning != emuStatus_Exit) { Input::Process(); @@ -425,10 +426,10 @@ void EmuThread::run() DSi_BPTWL::ProcessVolumeSwitchInput(currentTime); } - if (EmuRunning == 1 || EmuRunning == 3) + if (EmuRunning == emuStatus_Running || EmuRunning == emuStatus_FrameStep) { - EmuStatus = 1; - if (EmuRunning == 3) EmuRunning = 2; + EmuStatus = emuStatus_Running; + if (EmuRunning == emuStatus_FrameStep) EmuRunning = emuStatus_Paused; // update render settings if needed // HACK: @@ -473,7 +474,7 @@ void EmuThread::run() AudioInOut::MicProcess(); // auto screen layout - if (Config::ScreenSizing == screenSizing_Auto) + if (Config::ScreenSizing == Frontend::screenSizing_Auto) { mainScreenPos[2] = mainScreenPos[1]; mainScreenPos[1] = mainScreenPos[0]; @@ -485,14 +486,14 @@ void EmuThread::run() { // constant flickering, likely displaying 3D on both screens // TODO: when both screens are used for 2D only...??? - guess = screenSizing_Even; + guess = Frontend::screenSizing_Even; } else { if (mainScreenPos[0] == 1) - guess = screenSizing_EmphTop; + guess = Frontend::screenSizing_EmphTop; else - guess = screenSizing_EmphBot; + guess = Frontend::screenSizing_EmphBot; } if (guess != autoScreenSizing) @@ -528,7 +529,7 @@ void EmuThread::run() MelonCap::Update(); #endif // MELONCAP - if (EmuRunning == 0) break; + if (EmuRunning == emuStatus_Exit) break; winUpdateCount++; if (winUpdateCount >= winUpdateFreq && !oglContext) @@ -632,21 +633,21 @@ void EmuThread::run() if (oglContext) drawScreenGL(); - int contextRequest = ContextRequest; - if (contextRequest == 1) + ContextRequestKind contextRequest = ContextRequest; + if (contextRequest == contextRequest_InitGL) { initOpenGL(); - ContextRequest = 0; + ContextRequest = contextRequest_None; } - else if (contextRequest == 2) + else if (contextRequest == contextRequest_DeInitGL) { deinitOpenGL(); - ContextRequest = 0; + ContextRequest = contextRequest_None; } } } - EmuStatus = 0; + EmuStatus = emuStatus_Exit; GPU::DeInitRenderer(); NDS::DeInit(); @@ -660,8 +661,8 @@ void EmuThread::changeWindowTitle(char* title) void EmuThread::emuRun() { - EmuRunning = 1; - EmuPause = 0; + EmuRunning = emuStatus_Running; + EmuPauseStack = EmuPauseStackRunning; RunningSomething = true; // checkme @@ -671,34 +672,34 @@ void EmuThread::emuRun() void EmuThread::initContext() { - ContextRequest = 1; - while (ContextRequest != 0); + ContextRequest = contextRequest_InitGL; + while (ContextRequest != contextRequest_None); } void EmuThread::deinitContext() { - ContextRequest = 2; - while (ContextRequest != 0); + ContextRequest = contextRequest_DeInitGL; + while (ContextRequest != contextRequest_None); } void EmuThread::emuPause() { - EmuPause++; - if (EmuPause > 1) return; + EmuPauseStack++; + if (EmuPauseStack > EmuPauseStackPauseThreshold) return; PrevEmuStatus = EmuRunning; - EmuRunning = 2; - while (EmuStatus != 2); + EmuRunning = emuStatus_Paused; + while (EmuStatus != emuStatus_Paused); AudioInOut::Disable(); } void EmuThread::emuUnpause() { - if (EmuPause < 1) return; + if (EmuPauseStack < EmuPauseStackPauseThreshold) return; - EmuPause--; - if (EmuPause > 0) return; + EmuPauseStack--; + if (EmuPauseStack >= EmuPauseStackPauseThreshold) return; EmuRunning = PrevEmuStatus; @@ -707,21 +708,21 @@ void EmuThread::emuUnpause() void EmuThread::emuStop() { - EmuRunning = 0; - EmuPause = 0; + EmuRunning = emuStatus_Exit; + EmuPauseStack = EmuPauseStackRunning; AudioInOut::Disable(); } void EmuThread::emuFrameStep() { - if (EmuPause < 1) emit windowEmuPause(); - EmuRunning = 3; + if (EmuPauseStack < EmuPauseStackPauseThreshold) emit windowEmuPause(); + EmuRunning = emuStatus_FrameStep; } bool EmuThread::emuIsRunning() { - return (EmuRunning == 1); + return EmuRunning == emuStatus_Running; } bool EmuThread::emuIsActive() @@ -830,9 +831,9 @@ void ScreenHandler::screenSetupLayout(int w, int h) aspectBot = ((float) w / h) / (4.f / 3.f); Frontend::SetupScreenLayout(w, h, - Config::ScreenLayout, - Config::ScreenRotation, - sizing, + static_cast(Config::ScreenLayout), + static_cast(Config::ScreenRotation), + static_cast(sizing), Config::ScreenGap, Config::IntegerScaling != 0, Config::ScreenSwap != 0, @@ -844,32 +845,34 @@ void ScreenHandler::screenSetupLayout(int w, int h) QSize ScreenHandler::screenGetMinSize(int factor = 1) { - bool isHori = (Config::ScreenRotation == 1 || Config::ScreenRotation == 3); + bool isHori = (Config::ScreenRotation == Frontend::screenRot_90Deg + || Config::ScreenRotation == Frontend::screenRot_270Deg); int gap = Config::ScreenGap * factor; int w = 256 * factor; int h = 192 * factor; - if (Config::ScreenSizing == 4 || Config::ScreenSizing == 5) + if (Config::ScreenSizing == Frontend::screenSizing_TopOnly + || Config::ScreenSizing == Frontend::screenSizing_BotOnly) { return QSize(w, h); } - if (Config::ScreenLayout == 0) // natural + if (Config::ScreenLayout == Frontend::screenLayout_Natural) { if (isHori) return QSize(h+gap+h, w); else return QSize(w, h+gap+h); } - else if (Config::ScreenLayout == 1) // vertical + else if (Config::ScreenLayout == Frontend::screenLayout_Vertical) { if (isHori) return QSize(h, w+gap+w); else return QSize(w, h+gap+h); } - else if (Config::ScreenLayout == 2) // horizontal + else if (Config::ScreenLayout == Frontend::screenLayout_Horizontal) { if (isHori) return QSize(h+gap+h, w); @@ -1610,7 +1613,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) QMenu* submenu = menu->addMenu("Screen rotation"); grpScreenRotation = new QActionGroup(submenu); - for (int i = 0; i < 4; i++) + for (int i = 0; i < Frontend::screenRot_MAX; i++) { int data = i*90; actScreenRotation[i] = submenu->addAction(QString("%1°").arg(data)); @@ -1644,7 +1647,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) const char* screenlayout[] = {"Natural", "Vertical", "Horizontal", "Hybrid"}; - for (int i = 0; i < 4; i++) + for (int i = 0; i < Frontend::screenLayout_MAX; i++) { actScreenLayout[i] = submenu->addAction(QString(screenlayout[i])); actScreenLayout[i]->setActionGroup(grpScreenLayout); @@ -1666,7 +1669,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) const char* screensizing[] = {"Even", "Emphasize top", "Emphasize bottom", "Auto", "Top only", "Bottom only"}; - for (int i = 0; i < screenSizing_MAX; i++) + for (int i = 0; i < Frontend::screenSizing_MAX; i++) { actScreenSizing[i] = submenu->addAction(QString(screensizing[i])); actScreenSizing[i]->setActionGroup(grpScreenSizing); @@ -1686,8 +1689,8 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) QMenu* submenu = menu->addMenu("Aspect ratio"); grpScreenAspectTop = new QActionGroup(submenu); grpScreenAspectBot = new QActionGroup(submenu); - actScreenAspectTop = new QAction*[sizeof(aspectRatios) / sizeof(aspectRatios[0])]; - actScreenAspectBot = new QAction*[sizeof(aspectRatios) / sizeof(aspectRatios[0])]; + actScreenAspectTop = new QAction*[AspectRatiosNum]; + actScreenAspectBot = new QAction*[AspectRatiosNum]; for (int i = 0; i < 2; i++) { @@ -1701,7 +1704,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) actions = actScreenAspectBot; } - for (int j = 0; j < sizeof(aspectRatios) / sizeof(aspectRatios[0]); j++) + for (int j = 0; j < AspectRatiosNum; j++) { auto ratio = aspectRatios[j]; QString label = QString("%1 %2").arg(i ? "Bottom" : "Top", ratio.label); @@ -1806,7 +1809,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) actScreenSwap->setChecked(Config::ScreenSwap); - for (int i = 0; i < sizeof(aspectRatios) / sizeof(aspectRatios[0]); i++) + for (int i = 0; i < AspectRatiosNum; i++) { if (Config::ScreenAspectTop == aspectRatios[i].id) actScreenAspectTop[i]->setChecked(true); @@ -3011,18 +3014,18 @@ void MainWindow::onChangeScreenSwap(bool checked) Config::ScreenSwap = checked?1:0; // Swap between top and bottom screen when displaying one screen. - if (Config::ScreenSizing == screenSizing_TopOnly) + if (Config::ScreenSizing == Frontend::screenSizing_TopOnly) { // Bottom Screen. - Config::ScreenSizing = screenSizing_BotOnly; - actScreenSizing[screenSizing_TopOnly]->setChecked(false); + Config::ScreenSizing = Frontend::screenSizing_BotOnly; + actScreenSizing[Frontend::screenSizing_TopOnly]->setChecked(false); actScreenSizing[Config::ScreenSizing]->setChecked(true); } - else if (Config::ScreenSizing == screenSizing_BotOnly) + else if (Config::ScreenSizing == Frontend::screenSizing_BotOnly) { // Top Screen. - Config::ScreenSizing = screenSizing_TopOnly; - actScreenSizing[screenSizing_BotOnly]->setChecked(false); + Config::ScreenSizing = Frontend::screenSizing_TopOnly; + actScreenSizing[Frontend::screenSizing_BotOnly]->setChecked(false); actScreenSizing[Config::ScreenSizing]->setChecked(true); } @@ -3111,13 +3114,13 @@ void MainWindow::onFullscreenToggled() void MainWindow::onScreenEmphasisToggled() { int currentSizing = Config::ScreenSizing; - if (currentSizing == screenSizing_EmphTop) + if (currentSizing == Frontend::screenSizing_EmphTop) { - Config::ScreenSizing = screenSizing_EmphBot; + Config::ScreenSizing = Frontend::screenSizing_EmphBot; } - else if (currentSizing == screenSizing_EmphBot) + else if (currentSizing == Frontend::screenSizing_EmphBot) { - Config::ScreenSizing = screenSizing_EmphTop; + Config::ScreenSizing = Frontend::screenSizing_EmphTop; } emit screenLayoutChange(); @@ -3279,12 +3282,12 @@ int main(int argc, char** argv) SANITIZE(Config::AudioInterp, 0, 3); SANITIZE(Config::AudioVolume, 0, 256); SANITIZE(Config::MicInputType, 0, (int)micInputType_MAX); - SANITIZE(Config::ScreenRotation, 0, 3); + SANITIZE(Config::ScreenRotation, 0, (int)Frontend::screenRot_MAX); SANITIZE(Config::ScreenGap, 0, 500); - SANITIZE(Config::ScreenLayout, 0, 3); - SANITIZE(Config::ScreenSizing, 0, (int)screenSizing_MAX); - SANITIZE(Config::ScreenAspectTop, 0, 4); - SANITIZE(Config::ScreenAspectBot, 0, 4); + SANITIZE(Config::ScreenLayout, 0, (int)Frontend::screenLayout_MAX); + SANITIZE(Config::ScreenSizing, 0, (int)Frontend::screenSizing_MAX); + SANITIZE(Config::ScreenAspectTop, 0, AspectRatiosNum); + SANITIZE(Config::ScreenAspectBot, 0, AspectRatiosNum); #undef SANITIZE AudioInOut::Init(); diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 8a902ee64f..44283a922e 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -94,12 +94,29 @@ class EmuThread : public QThread void initOpenGL(); void deinitOpenGL(); - std::atomic EmuStatus; - int PrevEmuStatus; - int EmuRunning; - int EmuPause; - - std::atomic ContextRequest = 0; + enum EmuStatusKind + { + emuStatus_Exit, + emuStatus_Running, + emuStatus_Paused, + emuStatus_FrameStep, + }; + std::atomic EmuStatus; + + EmuStatusKind PrevEmuStatus; + EmuStatusKind EmuRunning; + + constexpr static int EmuPauseStackRunning = 0; + constexpr static int EmuPauseStackPauseThreshold = 1; + int EmuPauseStack; + + enum ContextRequestKind + { + contextRequest_None = 0, + contextRequest_InitGL, + contextRequest_DeInitGL + }; + std::atomic ContextRequest = contextRequest_None; GL::Context* oglContext = nullptr; GLuint screenVertexBuffer, screenVertexArray; @@ -404,14 +421,14 @@ private slots: QAction* actSavestateSRAMReloc; QAction* actScreenSize[4]; QActionGroup* grpScreenRotation; - QAction* actScreenRotation[4]; + QAction* actScreenRotation[Frontend::screenRot_MAX]; QActionGroup* grpScreenGap; QAction* actScreenGap[6]; QActionGroup* grpScreenLayout; - QAction* actScreenLayout[4]; + QAction* actScreenLayout[Frontend::screenLayout_MAX]; QAction* actScreenSwap; QActionGroup* grpScreenSizing; - QAction* actScreenSizing[6]; + QAction* actScreenSizing[Frontend::screenSizing_MAX]; QAction* actIntegerScaling; QActionGroup* grpScreenAspectTop; QAction** actScreenAspectTop;