more screen modes

- add support for different aspect ratios
- add support for displaying only one screen at once
This commit is contained in:
RSDuck
2021-01-24 22:32:02 +01:00
parent 536902d610
commit b9a56bc4e4
6 changed files with 314 additions and 147 deletions

View File

@ -31,7 +31,8 @@ namespace Frontend
float TopScreenMtx[6];
float BotScreenMtx[6];
float TouchMtx[6];
bool TopEnable;
bool BotEnable;
void M23_Identity(float* m)
{
@ -47,6 +48,13 @@ void M23_Scale(float* m, float 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;
@ -109,7 +117,14 @@ void M23_Transform(float* m, float& x, float& y)
}
void SetupScreenLayout(int screenWidth, int screenHeight, int screenLayout, int rotation, int sizing, int screenGap, bool integerScale, int swapScreens)
void SetupScreenLayout(int screenWidth, int screenHeight,
int screenLayout,
int rotation,
int sizing,
int screenGap,
bool integerScale,
bool swapScreens,
float topAspect, float botAspect)
{
float refpoints[4][2] =
{
@ -130,6 +145,9 @@ void SetupScreenLayout(int screenWidth, int screenHeight, int screenLayout, int
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];
@ -145,136 +163,174 @@ void SetupScreenLayout(int screenWidth, int screenHeight, int screenLayout, int
M23_Transform(BotScreenMtx, refpoints[3][0], refpoints[3][1]);
}
// move screens apart
int posRefPointOffset = 0;
int posRefPointCount = 4;
if (sizing == 4 || sizing == 5)
{
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) ^ swapScreens)
offset *= -1.f;
float* mtx = sizing == 4 ? TopScreenMtx : BotScreenMtx;
int primOffset = sizing == 4 ? 0 : 2;
int secOffset = sizing == 5 ? 2 : 0;
M23_Translate(TopScreenMtx, (idx==0)?-offset:0, (idx==1)?-offset:0);
M23_Translate(BotScreenMtx, (idx==0)?offset:0, (idx==1)?offset:0);
float hSize = fabsf(refpoints[primOffset][0] - refpoints[primOffset+1][0]);
float vSize = fabsf(refpoints[primOffset][1] - refpoints[primOffset+1][1]);
refpoints[0][idx] -= offset;
refpoints[1][idx] -= offset;
refpoints[2][idx] += offset;
refpoints[3][idx] += offset;
float scale = std::min(screenWidth / hSize, screenHeight / vSize);
if (integerScale)
scale = floorf(scale);
botTrans[idx] = offset;
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;
}
// scale
else
{
if (sizing == 0)
TopEnable = BotEnable = true;
// move screens apart
{
float minX = refpoints[0][0], maxX = minX;
float minY = refpoints[0][1], maxY = minY;
int idx = layout == 0 ? 1 : 0;
for (int i = 1; i < 4; i++)
bool moveV = rotation % 2 == layout;
float offsetTop = (moveV ? 192 : 256 * topAspect) / 2 + screenGap / 2;
float offsetBot = (moveV ? 192 : 256 * botAspect) / 2 + screenGap / 2;
if ((rotation == 1 || rotation == 2) ^ swapScreens)
{
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]);
offsetTop *= -1;
offsetBot *= -1;
}
float hSize = maxX - minX;
float vSize = maxY - minY;
M23_Translate(TopScreenMtx, (idx==0)?-offsetTop:0, (idx==1)?-offsetTop:0);
M23_Translate(BotScreenMtx, (idx==0)?offsetBot:0, (idx==1)?offsetBot:0);
// scale evenly
float scale = std::min(screenWidth / hSize, screenHeight / vSize);
refpoints[0][idx] -= offsetTop;
refpoints[1][idx] -= offsetTop;
refpoints[2][idx] += offsetBot;
refpoints[3][idx] += offsetBot;
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;
botTrans[idx] = offsetBot;
}
else
// scale
{
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 (sizing == 0)
{
if (screenHeight - primVSize * primScale < secVSize)
primScale = std::min(screenWidth / primHSize, (screenHeight - secVSize) / primVSize);
else
secScale = std::min((screenHeight - primVSize * primScale) / secVSize, screenWidth / secHSize);
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
{
if (screenWidth - primHSize * primScale < secHSize)
primScale = std::min((screenWidth - secHSize) / primHSize, screenHeight / primVSize);
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 / primHSize, (screenHeight - secVSize) / primVSize);
else
secScale = std::min((screenHeight - primVSize * primScale) / secVSize, screenWidth / secHSize);
}
else
secScale = std::min((screenWidth - primHSize * primScale) / secHSize, screenHeight / secVSize);
{
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 = 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;
}
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;
float minX = refpoints[posRefPointOffset][0], maxX = minX;
float minY = refpoints[posRefPointOffset][1], maxY = minY;
for (int i = 1; i < 4; i++)
for (int i = posRefPointOffset + 1; i < posRefPointOffset + posRefPointCount; i++)
{
minX = std::min(minX, refpoints[i][0]);
minY = std::min(minY, refpoints[i][1]);
@ -297,6 +353,7 @@ void SetupScreenLayout(int screenWidth, int screenHeight, int screenLayout, int
// 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);
@ -309,25 +366,45 @@ void SetupScreenLayout(int screenWidth, int screenHeight, int screenLayout, int
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);
}
}
void GetScreenTransforms(float* top, float* bot)
int GetScreenTransforms(float* out, int* kind)
{
memcpy(top, TopScreenMtx, 6*sizeof(float));
memcpy(bot, BotScreenMtx, 6*sizeof(float));
int num = 0;
if (TopEnable)
{
memcpy(out + 6*num, TopScreenMtx, sizeof(TopScreenMtx));
kind[num] = 0;
num++;
}
if (BotEnable)
{
memcpy(out + 6*num, BotScreenMtx, sizeof(BotScreenMtx));
kind[num] = 1;
num++;
}
return num;
}
void GetTouchCoords(int& x, int& y)
bool GetTouchCoords(int& x, int& y)
{
float vx = x;
float vy = y;
if (BotEnable)
{
float vx = x;
float vy = y;
M23_Transform(TouchMtx, vx, vy);
M23_Transform(TouchMtx, vx, vy);
x = (int)vx;
y = (int)vy;
x = (int)vx;
y = (int)vy;
if (x >= 0 && x < 256 && y >= 0 && y < 192)
return true;
}
return false;
}
}