add screen layout system
This commit is contained in:
parent
f79583bf16
commit
8f9369beeb
|
@ -89,6 +89,32 @@ bool SaveState(const char* filename);
|
||||||
void UndoStateLoad();
|
void UndoStateLoad();
|
||||||
|
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// * 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
|
||||||
|
// * screenGap: size of the gap between the two screens
|
||||||
|
// * integerScale: force screens to be scaled up at integer scaling factors
|
||||||
|
void SetupScreenLayout(int screenWidth, int screenHeight, int screenLayout, int rotation, int sizing, int screenGap, bool integerScale);
|
||||||
|
|
||||||
|
// get a 2x3 transform matrix for the given screen (0=top, 1=bottom)
|
||||||
|
// note: the transform assumes an origin point at the top left of the display,
|
||||||
|
// X going left and Y going down
|
||||||
|
// for each screen the source coordinates should be (0,0) and (256,192)
|
||||||
|
float* GetScreenTransform(int screen);
|
||||||
|
|
||||||
|
// de-transform the provided host display coordinates to get coordinates
|
||||||
|
// on the bottom screen
|
||||||
|
void GetTouchCoords(int& x, int& y);
|
||||||
|
|
||||||
|
|
||||||
// initialize the audio utility
|
// initialize the audio utility
|
||||||
void Init_Audio(int outputfreq);
|
void Init_Audio(int outputfreq);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,334 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2020 Arisotura
|
||||||
|
|
||||||
|
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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "FrontendUtil.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Frontend
|
||||||
|
{
|
||||||
|
|
||||||
|
float TopScreenMtx[6];
|
||||||
|
float BotScreenMtx[6];
|
||||||
|
float TouchMtx[6];
|
||||||
|
|
||||||
|
|
||||||
|
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_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)
|
||||||
|
{
|
||||||
|
float refpoints[4][2] =
|
||||||
|
{
|
||||||
|
{0, 0}, {256, 192},
|
||||||
|
{0, 0}, {256, 192}
|
||||||
|
};
|
||||||
|
|
||||||
|
int layout = screenLayout == 0
|
||||||
|
? ((rotation % 2 == 0) ? 0 : 1)
|
||||||
|
: screenLayout - 1;
|
||||||
|
|
||||||
|
float botScale = 1;
|
||||||
|
float botTrans[4] = {0};
|
||||||
|
|
||||||
|
M23_Identity(TopScreenMtx);
|
||||||
|
M23_Identity(BotScreenMtx);
|
||||||
|
|
||||||
|
M23_Translate(TopScreenMtx, -256/2, -192/2);
|
||||||
|
M23_Translate(BotScreenMtx, -256/2, -192/2);
|
||||||
|
|
||||||
|
// rotation
|
||||||
|
{
|
||||||
|
float rotmtx[6];
|
||||||
|
M23_Identity(rotmtx);
|
||||||
|
|
||||||
|
M23_RotateFast(rotmtx, rotation);
|
||||||
|
M23_Multiply(TopScreenMtx, rotmtx, TopScreenMtx);
|
||||||
|
M23_Multiply(BotScreenMtx, rotmtx, BotScreenMtx);
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// move screens apart
|
||||||
|
{
|
||||||
|
int idx = layout == 0 ? 1 : 0;
|
||||||
|
float offset =
|
||||||
|
(((layout == 0 && (rotation % 2 == 0)) || (layout == 1 && (rotation % 2 == 1))
|
||||||
|
? 192.f : 256.f)
|
||||||
|
+ screenGap) / 2.f;
|
||||||
|
if (rotation == 1 || rotation == 2)
|
||||||
|
offset *= -1.f;
|
||||||
|
|
||||||
|
M23_Translate(TopScreenMtx, (idx==0)?-offset:0, (idx==1)?-offset:0);
|
||||||
|
M23_Translate(BotScreenMtx, (idx==0)?offset:0, (idx==1)?offset:0);
|
||||||
|
|
||||||
|
refpoints[0][idx] -= offset;
|
||||||
|
refpoints[1][idx] -= offset;
|
||||||
|
refpoints[2][idx] += offset;
|
||||||
|
refpoints[3][idx] += offset;
|
||||||
|
|
||||||
|
botTrans[idx] = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// scale evenly
|
||||||
|
float scale = std::min(screenWidth / hSize, screenHeight / vSize);
|
||||||
|
|
||||||
|
if (integerScale)
|
||||||
|
scale = floor(scale);
|
||||||
|
|
||||||
|
M23_Scale(TopScreenMtx, scale);
|
||||||
|
M23_Scale(BotScreenMtx, scale);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
refpoints[i][0] *= scale;
|
||||||
|
refpoints[i][1] *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
botScale = scale;
|
||||||
|
}
|
||||||
|
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 (layout == 0)
|
||||||
|
{
|
||||||
|
if (screenHeight - primVSize * primScale < secVSize)
|
||||||
|
primScale = std::min((screenWidth - secHSize) / 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 - secVSize) / primVSize);
|
||||||
|
else
|
||||||
|
secScale = std::min((screenWidth - primHSize * primScale) / secHSize, screenHeight / secVSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (integerScale)
|
||||||
|
{
|
||||||
|
primScale = floor(primScale);
|
||||||
|
secScale = floor(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[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 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);
|
||||||
|
|
||||||
|
botTrans[2] = tx; botTrans[3] = 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
|
||||||
|
{
|
||||||
|
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_Translate(TouchMtx, 256/2, 192/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float* GetScreenTransform(int screen)
|
||||||
|
{
|
||||||
|
if (screen == 0) return TopScreenMtx;
|
||||||
|
else return BotScreenMtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetTouchCoords(int& x, int& y)
|
||||||
|
{
|
||||||
|
float vx = x;
|
||||||
|
float vy = y;
|
||||||
|
|
||||||
|
M23_Transform(TouchMtx, vx, vy);
|
||||||
|
|
||||||
|
x = (int)vx;
|
||||||
|
y = (int)vy;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ SET(SOURCES_QT_SDL
|
||||||
PlatformConfig.cpp
|
PlatformConfig.cpp
|
||||||
|
|
||||||
../Util_ROM.cpp
|
../Util_ROM.cpp
|
||||||
|
../Util_Video.cpp
|
||||||
../Util_Audio.cpp
|
../Util_Audio.cpp
|
||||||
../FrontendUtil.h
|
../FrontendUtil.h
|
||||||
../mic_blow.h
|
../mic_blow.h
|
||||||
|
|
|
@ -62,6 +62,8 @@ bool RunningSomething;
|
||||||
MainWindow* mainWindow;
|
MainWindow* mainWindow;
|
||||||
EmuThread* emuThread;
|
EmuThread* emuThread;
|
||||||
|
|
||||||
|
int autoScreenSizing = 0;
|
||||||
|
|
||||||
SDL_AudioDeviceID audioDevice;
|
SDL_AudioDeviceID audioDevice;
|
||||||
int audioFreq;
|
int audioFreq;
|
||||||
SDL_cond* audioSync;
|
SDL_cond* audioSync;
|
||||||
|
@ -250,16 +252,19 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||||
connect(this, SIGNAL(windowEmuStop()), mainWindow, SLOT(onEmuStop()));
|
connect(this, SIGNAL(windowEmuStop()), mainWindow, SLOT(onEmuStop()));
|
||||||
connect(this, SIGNAL(windowEmuPause()), mainWindow->actPause, SLOT(trigger()));
|
connect(this, SIGNAL(windowEmuPause()), mainWindow->actPause, SLOT(trigger()));
|
||||||
connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger()));
|
connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger()));
|
||||||
|
connect(this, SIGNAL(screenLayoutChange()), mainWindow->panel, SLOT(onScreenLayoutChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::run()
|
void EmuThread::run()
|
||||||
{
|
{
|
||||||
|
u32 mainScreenPos[3];
|
||||||
|
|
||||||
NDS::Init();
|
NDS::Init();
|
||||||
|
|
||||||
/*MainScreenPos[0] = 0;
|
mainScreenPos[0] = 0;
|
||||||
MainScreenPos[1] = 0;
|
mainScreenPos[1] = 0;
|
||||||
MainScreenPos[2] = 0;
|
mainScreenPos[2] = 0;
|
||||||
AutoScreenSizing = 0;*/
|
autoScreenSizing = 0;
|
||||||
|
|
||||||
/*if (Screen_UseGL)
|
/*if (Screen_UseGL)
|
||||||
{
|
{
|
||||||
|
@ -333,14 +338,14 @@ void EmuThread::run()
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
// auto screen layout
|
// auto screen layout
|
||||||
/*{
|
{
|
||||||
MainScreenPos[2] = MainScreenPos[1];
|
mainScreenPos[2] = mainScreenPos[1];
|
||||||
MainScreenPos[1] = MainScreenPos[0];
|
mainScreenPos[1] = mainScreenPos[0];
|
||||||
MainScreenPos[0] = NDS::PowerControl9 >> 15;
|
mainScreenPos[0] = NDS::PowerControl9 >> 15;
|
||||||
|
|
||||||
int guess;
|
int guess;
|
||||||
if (MainScreenPos[0] == MainScreenPos[2] &&
|
if (mainScreenPos[0] == mainScreenPos[2] &&
|
||||||
MainScreenPos[0] != MainScreenPos[1])
|
mainScreenPos[0] != mainScreenPos[1])
|
||||||
{
|
{
|
||||||
// constant flickering, likely displaying 3D on both screens
|
// constant flickering, likely displaying 3D on both screens
|
||||||
// TODO: when both screens are used for 2D only...???
|
// TODO: when both screens are used for 2D only...???
|
||||||
|
@ -348,18 +353,18 @@ void EmuThread::run()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (MainScreenPos[0] == 1)
|
if (mainScreenPos[0] == 1)
|
||||||
guess = 1;
|
guess = 1;
|
||||||
else
|
else
|
||||||
guess = 2;
|
guess = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guess != AutoScreenSizing)
|
if (guess != autoScreenSizing)
|
||||||
{
|
{
|
||||||
AutoScreenSizing = guess;
|
autoScreenSizing = guess;
|
||||||
SetupScreenRects(WindowWidth, WindowHeight);
|
emit screenLayoutChange();
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
// emulate
|
// emulate
|
||||||
u32 nlines = NDS::RunFrame();
|
u32 nlines = NDS::RunFrame();
|
||||||
|
@ -540,6 +545,9 @@ MainWindowPanel::MainWindowPanel(QWidget* parent) : QWidget(parent)
|
||||||
screen[0] = new QImage(256, 192, QImage::Format_RGB32);
|
screen[0] = new QImage(256, 192, QImage::Format_RGB32);
|
||||||
screen[1] = new QImage(256, 192, QImage::Format_RGB32);
|
screen[1] = new QImage(256, 192, QImage::Format_RGB32);
|
||||||
|
|
||||||
|
screenTrans[0].reset();
|
||||||
|
screenTrans[1].reset();
|
||||||
|
|
||||||
touching = false;
|
touching = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,6 +557,64 @@ MainWindowPanel::~MainWindowPanel()
|
||||||
delete screen[1];
|
delete screen[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindowPanel::ensureProperMinSize()
|
||||||
|
{
|
||||||
|
bool isHori = (Config::ScreenRotation == 1 || Config::ScreenRotation == 3);
|
||||||
|
int gap = Config::ScreenGap;
|
||||||
|
|
||||||
|
int w = 256;
|
||||||
|
int h = 192;
|
||||||
|
|
||||||
|
if (Config::ScreenLayout == 0) // natural
|
||||||
|
{
|
||||||
|
if (isHori)
|
||||||
|
setMinimumSize(h+gap+h, w);
|
||||||
|
else
|
||||||
|
setMinimumSize(w, h+gap+h);
|
||||||
|
}
|
||||||
|
else if (Config::ScreenLayout == 1) // vertical
|
||||||
|
{
|
||||||
|
if (isHori)
|
||||||
|
setMinimumSize(h, w+gap+w);
|
||||||
|
else
|
||||||
|
setMinimumSize(w, h+gap+h);
|
||||||
|
}
|
||||||
|
else // horizontal
|
||||||
|
{
|
||||||
|
if (isHori)
|
||||||
|
setMinimumSize(h+gap+h, w);
|
||||||
|
else
|
||||||
|
setMinimumSize(w+gap+w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindowPanel::setupScreenLayout()
|
||||||
|
{
|
||||||
|
int w = width();
|
||||||
|
int h = height();
|
||||||
|
float* mtx;
|
||||||
|
|
||||||
|
int sizing = Config::ScreenSizing;
|
||||||
|
if (sizing == 3) sizing = autoScreenSizing;
|
||||||
|
|
||||||
|
Frontend::SetupScreenLayout(w, h,
|
||||||
|
Config::ScreenLayout,
|
||||||
|
Config::ScreenRotation,
|
||||||
|
sizing,
|
||||||
|
Config::ScreenGap,
|
||||||
|
Config::IntegerScaling != 0);
|
||||||
|
|
||||||
|
mtx = Frontend::GetScreenTransform(0);
|
||||||
|
screenTrans[0].setMatrix(mtx[0], mtx[1], 0.f,
|
||||||
|
mtx[2], mtx[3], 0.f,
|
||||||
|
mtx[4], mtx[5], 1.f);
|
||||||
|
|
||||||
|
mtx = Frontend::GetScreenTransform(1);
|
||||||
|
screenTrans[1].setMatrix(mtx[0], mtx[1], 0.f,
|
||||||
|
mtx[2], mtx[3], 0.f,
|
||||||
|
mtx[4], mtx[5], 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindowPanel::paintEvent(QPaintEvent* event)
|
void MainWindowPanel::paintEvent(QPaintEvent* event)
|
||||||
{
|
{
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
|
@ -562,27 +628,18 @@ void MainWindowPanel::paintEvent(QPaintEvent* event)
|
||||||
memcpy(screen[0]->scanLine(0), GPU::Framebuffer[frontbuf][0], 256*192*4);
|
memcpy(screen[0]->scanLine(0), GPU::Framebuffer[frontbuf][0], 256*192*4);
|
||||||
memcpy(screen[1]->scanLine(0), GPU::Framebuffer[frontbuf][1], 256*192*4);
|
memcpy(screen[1]->scanLine(0), GPU::Framebuffer[frontbuf][1], 256*192*4);
|
||||||
|
|
||||||
QRect src = QRect(0, 0, 256, 192);
|
QRect screenrc = QRect(0, 0, 256, 192);
|
||||||
|
|
||||||
QRect dstTop = QRect(0, 0, 256, 192); // TODO
|
painter.setTransform(screenTrans[0]);
|
||||||
QRect dstBot = QRect(0, 192, 256, 192); // TODO
|
painter.drawImage(screenrc, *screen[0]);
|
||||||
|
|
||||||
painter.drawImage(dstTop, *screen[0]);
|
painter.setTransform(screenTrans[1]);
|
||||||
painter.drawImage(dstBot, *screen[1]);
|
painter.drawImage(screenrc, *screen[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindowPanel::resizeEvent(QResizeEvent* event)
|
||||||
void MainWindowPanel::transformTSCoords(int& x, int& y)
|
|
||||||
{
|
{
|
||||||
// TODO: actual screen de-transform taking screen layout/rotation/etc into account
|
setupScreenLayout();
|
||||||
|
|
||||||
y -= 192;
|
|
||||||
|
|
||||||
// clamp to screen range
|
|
||||||
if (x < 0) x = 0;
|
|
||||||
else if (x > 255) x = 255;
|
|
||||||
if (y < 0) y = 0;
|
|
||||||
else if (y > 191) y = 191;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindowPanel::mousePressEvent(QMouseEvent* event)
|
void MainWindowPanel::mousePressEvent(QMouseEvent* event)
|
||||||
|
@ -593,11 +650,11 @@ void MainWindowPanel::mousePressEvent(QMouseEvent* event)
|
||||||
int x = event->pos().x();
|
int x = event->pos().x();
|
||||||
int y = event->pos().y();
|
int y = event->pos().y();
|
||||||
|
|
||||||
if (x >= 0 && x < 256 && y >= 192 && y < 384)
|
Frontend::GetTouchCoords(x, y);
|
||||||
|
|
||||||
|
if (x >= 0 && x < 256 && y >= 0 && y < 192)
|
||||||
{
|
{
|
||||||
touching = true;
|
touching = true;
|
||||||
|
|
||||||
transformTSCoords(x, y);
|
|
||||||
NDS::TouchScreen(x, y);
|
NDS::TouchScreen(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -623,10 +680,22 @@ void MainWindowPanel::mouseMoveEvent(QMouseEvent* event)
|
||||||
int x = event->pos().x();
|
int x = event->pos().x();
|
||||||
int y = event->pos().y();
|
int y = event->pos().y();
|
||||||
|
|
||||||
transformTSCoords(x, y);
|
Frontend::GetTouchCoords(x, y);
|
||||||
|
|
||||||
|
// clamp to screen range
|
||||||
|
if (x < 0) x = 0;
|
||||||
|
else if (x > 255) x = 255;
|
||||||
|
if (y < 0) y = 0;
|
||||||
|
else if (y > 191) y = 191;
|
||||||
|
|
||||||
NDS::TouchScreen(x, y);
|
NDS::TouchScreen(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindowPanel::onScreenLayoutChanged()
|
||||||
|
{
|
||||||
|
setupScreenLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
{
|
{
|
||||||
|
@ -750,7 +819,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
int data = i*90;
|
int data = i*90;
|
||||||
actScreenRotation[i] = submenu->addAction(QString("%1°").arg(data));
|
actScreenRotation[i] = submenu->addAction(QString("%1°").arg(data));
|
||||||
actScreenRotation[i]->setActionGroup(grpScreenRotation);
|
actScreenRotation[i]->setActionGroup(grpScreenRotation);
|
||||||
actScreenRotation[i]->setData(QVariant(data));
|
actScreenRotation[i]->setData(QVariant(i));
|
||||||
actScreenRotation[i]->setCheckable(true);
|
actScreenRotation[i]->setCheckable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,8 +903,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
|
|
||||||
panel = new MainWindowPanel(this);
|
panel = new MainWindowPanel(this);
|
||||||
setCentralWidget(panel);
|
setCentralWidget(panel);
|
||||||
panel->setMinimumSize(256, 384);
|
panel->ensureProperMinSize();
|
||||||
|
|
||||||
|
resize(Config::WindowWidth, Config::WindowHeight);
|
||||||
|
|
||||||
for (int i = 0; i < 9; i++)
|
for (int i = 0; i < 9; i++)
|
||||||
{
|
{
|
||||||
|
@ -877,6 +947,16 @@ MainWindow::~MainWindow()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::resizeEvent(QResizeEvent* event)
|
||||||
|
{
|
||||||
|
int w = event->size().width();
|
||||||
|
int h = event->size().height();
|
||||||
|
|
||||||
|
Config::WindowWidth = w;
|
||||||
|
Config::WindowHeight = h;
|
||||||
|
|
||||||
|
// TODO: detect when the window gets maximized!
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::keyPressEvent(QKeyEvent* event)
|
void MainWindow::keyPressEvent(QKeyEvent* event)
|
||||||
{
|
{
|
||||||
|
@ -1264,32 +1344,79 @@ void MainWindow::onChangeSavestateSRAMReloc(bool checked)
|
||||||
|
|
||||||
void MainWindow::onChangeScreenSize()
|
void MainWindow::onChangeScreenSize()
|
||||||
{
|
{
|
||||||
//
|
int factor = ((QAction*)sender())->data().toInt();
|
||||||
|
|
||||||
|
bool isHori = (Config::ScreenRotation == 1 || Config::ScreenRotation == 3);
|
||||||
|
int gap = Config::ScreenGap;
|
||||||
|
|
||||||
|
int w = 256*factor;
|
||||||
|
int h = 192*factor;
|
||||||
|
|
||||||
|
QSize diff = size() - panel->size();
|
||||||
|
|
||||||
|
if (Config::ScreenLayout == 0) // natural
|
||||||
|
{
|
||||||
|
if (isHori)
|
||||||
|
resize(QSize(h+gap+h, w) + diff);
|
||||||
|
else
|
||||||
|
resize(QSize(w, h+gap+h) + diff);
|
||||||
|
}
|
||||||
|
else if (Config::ScreenLayout == 1) // vertical
|
||||||
|
{
|
||||||
|
if (isHori)
|
||||||
|
resize(QSize(h, w+gap+w) + diff);
|
||||||
|
else
|
||||||
|
resize(QSize(w, h+gap+h) + diff);
|
||||||
|
}
|
||||||
|
else // horizontal
|
||||||
|
{
|
||||||
|
if (isHori)
|
||||||
|
resize(QSize(h+gap+h, w) + diff);
|
||||||
|
else
|
||||||
|
resize(QSize(w+gap+w, h) + diff);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onChangeScreenRotation(QAction* act)
|
void MainWindow::onChangeScreenRotation(QAction* act)
|
||||||
{
|
{
|
||||||
//
|
int rot = act->data().toInt();
|
||||||
|
Config::ScreenRotation = rot;
|
||||||
|
|
||||||
|
panel->ensureProperMinSize();
|
||||||
|
panel->setupScreenLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onChangeScreenGap(QAction* act)
|
void MainWindow::onChangeScreenGap(QAction* act)
|
||||||
{
|
{
|
||||||
//
|
int gap = act->data().toInt();
|
||||||
|
Config::ScreenGap = gap;
|
||||||
|
|
||||||
|
panel->ensureProperMinSize();
|
||||||
|
panel->setupScreenLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onChangeScreenLayout(QAction* act)
|
void MainWindow::onChangeScreenLayout(QAction* act)
|
||||||
{
|
{
|
||||||
//
|
int layout = act->data().toInt();
|
||||||
|
Config::ScreenLayout = layout;
|
||||||
|
|
||||||
|
panel->ensureProperMinSize();
|
||||||
|
panel->setupScreenLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onChangeScreenSizing(QAction* act)
|
void MainWindow::onChangeScreenSizing(QAction* act)
|
||||||
{
|
{
|
||||||
//
|
int sizing = act->data().toInt();
|
||||||
|
Config::ScreenSizing = sizing;
|
||||||
|
|
||||||
|
panel->setupScreenLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onChangeIntegerScaling(bool checked)
|
void MainWindow::onChangeIntegerScaling(bool checked)
|
||||||
{
|
{
|
||||||
//
|
Config::IntegerScaling = checked?1:0;
|
||||||
|
|
||||||
|
panel->setupScreenLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onChangeScreenFiltering(bool checked)
|
void MainWindow::onChangeScreenFiltering(bool checked)
|
||||||
|
|
|
@ -54,6 +54,8 @@ signals:
|
||||||
|
|
||||||
void windowLimitFPSChange();
|
void windowLimitFPSChange();
|
||||||
|
|
||||||
|
void screenLayoutChange();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
volatile int EmuStatus;
|
volatile int EmuStatus;
|
||||||
int PrevEmuStatus;
|
int PrevEmuStatus;
|
||||||
|
@ -69,18 +71,25 @@ public:
|
||||||
explicit MainWindowPanel(QWidget* parent);
|
explicit MainWindowPanel(QWidget* parent);
|
||||||
~MainWindowPanel();
|
~MainWindowPanel();
|
||||||
|
|
||||||
|
void ensureProperMinSize();
|
||||||
|
void setupScreenLayout();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent* event) override;
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent* event) override;
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
void mouseMoveEvent(QMouseEvent* event) override;
|
void mouseMoveEvent(QMouseEvent* event) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onScreenLayoutChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QImage* screen[2];
|
QImage* screen[2];
|
||||||
|
QTransform screenTrans[2];
|
||||||
bool touching;
|
bool touching;
|
||||||
|
|
||||||
void transformTSCoords(int& x, int& y);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,6 +102,8 @@ public:
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
|
|
||||||
void keyPressEvent(QKeyEvent* event) override;
|
void keyPressEvent(QKeyEvent* event) override;
|
||||||
void keyReleaseEvent(QKeyEvent* event) override;
|
void keyReleaseEvent(QKeyEvent* event) override;
|
||||||
|
|
||||||
|
@ -138,9 +149,9 @@ private slots:
|
||||||
private:
|
private:
|
||||||
QString loadErrorStr(int error);
|
QString loadErrorStr(int error);
|
||||||
|
|
||||||
|
public:
|
||||||
MainWindowPanel* panel;
|
MainWindowPanel* panel;
|
||||||
|
|
||||||
public:
|
|
||||||
QAction* actOpenROM;
|
QAction* actOpenROM;
|
||||||
QAction* actBootFirmware;
|
QAction* actBootFirmware;
|
||||||
QAction* actSaveState[9];
|
QAction* actSaveState[9];
|
||||||
|
|
Loading…
Reference in New Issue