Skip to content

Commit

Permalink
Desktop: add an option to split screens across windows
Browse files Browse the repository at this point in the history
  • Loading branch information
Hydr8gon committed Jun 30, 2024
1 parent e7813f6 commit 0f6fac0
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 139 deletions.
4 changes: 2 additions & 2 deletions src/common/screen_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ void ScreenLayout::addSettings()
Settings::add(layoutSettings);
}

void ScreenLayout::update(int winWidth, int winHeight, bool gbaMode)
void ScreenLayout::update(int winWidth, int winHeight, bool gbaMode, bool splitScreens)
{
// Update the window dimensions
this->winWidth = winWidth;
this->winHeight = winHeight;

if (screenArrangement == 3 || (gbaMode && gbaCrop)) // Single screen
if (screenArrangement == 3 || (gbaMode && gbaCrop) || splitScreens) // Single screen
{
// Determine the screen dimensions based on the current rotation
int width = (gbaMode && gbaCrop) ? (screenRotation ? 160 : 240) : (screenRotation ? 192 : 256);
Expand Down
2 changes: 1 addition & 1 deletion src/common/screen_layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ScreenLayout

static void addSettings();

void update(int winWidth, int winHeight, bool gbaMode);
void update(int winWidth, int winHeight, bool gbaMode, bool splitScreens = false);
int getTouchX(int x, int y);
int getTouchY(int x, int y);
};
Expand Down
23 changes: 18 additions & 5 deletions src/desktop/layout_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ enum LayoutEvent
FILT_LINEAR,
INT_SCALE,
GBA_CROP,
SPLIT_SCREENS,
SCREEN_GHOST
};

Expand Down Expand Up @@ -76,6 +77,7 @@ EVT_RADIOBUTTON(FILT_UPSCALE, LayoutDialog::filtUpscale)
EVT_RADIOBUTTON(FILT_LINEAR, LayoutDialog::filtLinear)
EVT_CHECKBOX(INT_SCALE, LayoutDialog::intScale)
EVT_CHECKBOX(GBA_CROP, LayoutDialog::gbaCrop)
EVT_CHECKBOX(SPLIT_SCREENS, LayoutDialog::splitScreens)
EVT_CHECKBOX(SCREEN_GHOST, LayoutDialog::screenGhost)
EVT_BUTTON(wxID_CANCEL, LayoutDialog::cancel)
EVT_BUTTON(wxID_OK, LayoutDialog::confirm)
Expand All @@ -92,7 +94,8 @@ LayoutDialog::LayoutDialog(NooApp *app): wxDialog(nullptr, wxID_ANY, "Screen Lay
prevSettings[5] = Settings::screenFilter;
prevSettings[6] = ScreenLayout::integerScale;
prevSettings[7] = ScreenLayout::gbaCrop;
prevSettings[8] = Settings::screenGhost;
prevSettings[8] = NooApp::splitScreens;
prevSettings[9] = Settings::screenGhost;

// Determine the height of a button
// Borders are measured in pixels, so this value can be used to make values that scale with the DPI/font size
Expand Down Expand Up @@ -165,11 +168,12 @@ LayoutDialog::LayoutDialog(NooApp *app): wxDialog(nullptr, wxID_ANY, "Screen Lay
filtSizer->Add(filtBtns[2] = new wxRadioButton(this, FILT_LINEAR, "Linear"), 0, wxLEFT, size / 8);

// Set up the checkbox settings
wxCheckBox *boxes[3];
wxCheckBox *boxes[4];
wxBoxSizer *checkSizer = new wxBoxSizer(wxHORIZONTAL);
checkSizer->Add(boxes[0] = new wxCheckBox(this, INT_SCALE, "Integer Scale"), 0, wxLEFT, size / 8);
checkSizer->Add(boxes[1] = new wxCheckBox(this, GBA_CROP, "GBA Crop"), 0, wxLEFT, size / 8);
checkSizer->Add(boxes[2] = new wxCheckBox(this, SCREEN_GHOST, "Simulate Ghosting"), 0, wxLEFT, size / 8);
checkSizer->Add(boxes[2] = new wxCheckBox(this, SPLIT_SCREENS, "Split Screens"), 0, wxLEFT, size / 8);
checkSizer->Add(boxes[3] = new wxCheckBox(this, SCREEN_GHOST, "Simulate Ghosting"), 0, wxLEFT, size / 8);

// Set the current values of the radio buttons
if (ScreenLayout::screenPosition < 5)
Expand All @@ -188,7 +192,8 @@ LayoutDialog::LayoutDialog(NooApp *app): wxDialog(nullptr, wxID_ANY, "Screen Lay
// Set the current values of the checkboxes
boxes[0]->SetValue(ScreenLayout::integerScale);
boxes[1]->SetValue(ScreenLayout::gbaCrop);
boxes[2]->SetValue(Settings::screenGhost);
boxes[2]->SetValue(NooApp::splitScreens);
boxes[3]->SetValue(Settings::screenGhost);

// Set up the cancel and confirm buttons
wxBoxSizer *buttonSizer = new wxBoxSizer(wxHORIZONTAL);
Expand Down Expand Up @@ -386,6 +391,13 @@ void LayoutDialog::gbaCrop(wxCommandEvent &event)
app->updateLayouts();
}

void LayoutDialog::splitScreens(wxCommandEvent &event)
{
// Toggle the split screens setting
NooApp::splitScreens = !NooApp::splitScreens;
app->updateLayouts();
}

void LayoutDialog::screenGhost(wxCommandEvent &event)
{
// Toggle the screen ghost setting
Expand All @@ -404,7 +416,8 @@ void LayoutDialog::cancel(wxCommandEvent &event)
Settings::screenFilter = prevSettings[5];
ScreenLayout::integerScale = prevSettings[6];
ScreenLayout::gbaCrop = prevSettings[7];
Settings::screenGhost = prevSettings[8];
NooApp::splitScreens = prevSettings[8];
Settings::screenGhost = prevSettings[9];
app->updateLayouts();
event.Skip(true);
}
Expand Down
3 changes: 2 additions & 1 deletion src/desktop/layout_dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class LayoutDialog: public wxDialog

private:
NooApp *app;
int prevSettings[9];
int prevSettings[10];

void posCenter(wxCommandEvent &event);
void posTop(wxCommandEvent &event);
Expand All @@ -57,6 +57,7 @@ class LayoutDialog: public wxDialog
void filtLinear(wxCommandEvent &event);
void intScale(wxCommandEvent &event);
void gbaCrop(wxCommandEvent &event);
void splitScreens(wxCommandEvent &event);
void screenGhost(wxCommandEvent &event);
void cancel(wxCommandEvent &event);
void confirm(wxCommandEvent &event);
Expand Down
14 changes: 8 additions & 6 deletions src/desktop/noo_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ EVT_TIMER(UPDATE, NooApp::update)
wxEND_EVENT_TABLE()

int NooApp::micEnable = 0;
int NooApp::splitScreens = 0;
int NooApp::keyBinds[] = { 'L', 'K', 'G', 'H', 'D', 'A', 'W', 'S', 'P', 'Q', 'O', 'I', WXK_TAB, 0, WXK_ESCAPE, 0, WXK_BACK };

bool NooApp::OnInit()
Expand All @@ -45,6 +46,7 @@ bool NooApp::OnInit()
std::vector<Setting> platformSettings =
{
Setting("micEnable", &micEnable, false),
Setting("splitScreens", &splitScreens, false),
Setting("keyA", &keyBinds[0], false),
Setting("keyB", &keyBinds[1], false),
Setting("keySelect", &keyBinds[2], false),
Expand Down Expand Up @@ -141,8 +143,8 @@ void NooApp::connectCore(int id)
for (int i = 0; i < MAX_FRAMES; i++)
{
if (!frames[i] || i == id) continue;
if (Core *core = frames[i]->getCore())
core->wifi.addConnection(frames[id]->getCore());
if (Core *core = frames[i]->core)
core->wifi.addConnection(frames[id]->core);
}
}

Expand All @@ -152,8 +154,8 @@ void NooApp::disconnCore(int id)
for (int i = 0; i < MAX_FRAMES; i++)
{
if (!frames[i] || i == id) continue;
if (Core *core = frames[i]->getCore())
core->wifi.remConnection(frames[id]->getCore());
if (Core *core = frames[i]->core)
core->wifi.remConnection(frames[id]->core);
}
}

Expand Down Expand Up @@ -219,7 +221,7 @@ int NooApp::audioCallback(const void *in, void *out, unsigned long count,
for (size_t i = 0; i < MAX_FRAMES; i++)
{
if (!frames[i]) continue;
if (Core *core = frames[i]->getCore())
if (Core *core = frames[i]->core)
{
uint32_t *samples = core->spu.getSamples(699);
if (!original)
Expand Down Expand Up @@ -260,7 +262,7 @@ int NooApp::micCallback(const void *in, void *out, unsigned long count,
// Find the core with the lowest instance ID
for (size_t i = 0; i < MAX_FRAMES; i++)
{
if (frames[i] && (core = frames[i]->getCore()))
if (frames[i] && (core = frames[i]->core))
break;
}

Expand Down
1 change: 1 addition & 0 deletions src/desktop/noo_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class NooApp: public wxApp
{
public:
static int micEnable;
static int splitScreens;
static int keyBinds[MAX_KEYS];

void createFrame();
Expand Down
56 changes: 38 additions & 18 deletions src/desktop/noo_canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,21 @@ NooCanvas::NooCanvas(NooFrame *frame): CANVAS_CLASS(frame, wxID_ANY, CANVAS_PARA
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#endif

// Set focus so that key presses will be registered
SetFocus();
// Create a new framebuffer or share one if the screens are split
if (frame->mainFrame)
{
framebuffer = new uint32_t[256 * 192 * 8];
memset(framebuffer, 0, 256 * 192 * 8 * sizeof(uint32_t));
}
else
{
framebuffer = frame->partner->canvas->framebuffer;
}

// Update the screen layout and set focus for key presses
splitScreens = NooApp::splitScreens && ScreenLayout::screenArrangement != 3;
frame->SendSizeEvent();
SetFocus();
}

void NooCanvas::drawScreen(int x, int y, int w, int h, int wb, int hb, uint32_t *buf)
Expand Down Expand Up @@ -123,20 +135,22 @@ void NooCanvas::draw(wxPaintEvent &event)
glClear(GL_COLOR_BUFFER_BIT);
#endif

if (frame->getCore())
// Update the screen layout if it changed
bool gba = ScreenLayout::gbaCrop && frame->core && frame->core->gbaMode;
bool split = NooApp::splitScreens && ScreenLayout::screenArrangement != 3 && !gba;
if (gbaMode != gba || splitScreens != split)
{
// Update the layout if GBA mode changed
bool gba = (frame->getCore()->gbaMode && ScreenLayout::gbaCrop);
if (gbaMode != gba)
{
gbaMode = gba;
frame->SendSizeEvent();
}
gbaMode = gba;
splitScreens = split;
frame->SendSizeEvent();
}

if (frame->core)
{
// Emulation is limited by audio, so frames aren't always generated at a consistent rate
// This can mess up frame pacing at higher refresh rates when frames are ready too soon
// To solve this, use a software-based swap interval to wait before getting the next frame
if (++frameCount >= swapInterval && frame->getCore()->gpu.getFrame(framebuffer, gba))
if (frame->mainFrame && ++frameCount >= swapInterval && frame->core->gpu.getFrame(framebuffer, gba))
frameCount = 0;

// Shift the screen resolutions if high-res is enabled
Expand All @@ -148,6 +162,12 @@ void NooCanvas::draw(wxPaintEvent &event)
drawScreen(layout.topX, layout.topY, layout.topWidth,
layout.topHeight, 240 << shift, 160 << shift, &framebuffer[0]);
}
else if (frame->partner)
{
// Draw one of the DS screens
drawScreen(layout.topX, layout.topY, layout.topWidth, layout.topHeight, 256 << shift,
192 << shift, &framebuffer[!frame->mainFrame * ((256 * 192) << (shift * 2))]);
}
else
{
// Draw the DS top and bottom screens
Expand Down Expand Up @@ -181,7 +201,7 @@ void NooCanvas::resize(wxSizeEvent &event)
{
// Update the screen layout
wxSize size = GetSize();
layout.update(size.x, size.y, gbaMode);
layout.update(size.x, size.y, gbaMode, splitScreens);

// Full screen breaks the minimum frame size, but changing to a different value fixes it
// As a workaround, clear the minimum size on full screen and reset it shortly after
Expand Down Expand Up @@ -225,23 +245,23 @@ void NooCanvas::releaseKey(wxKeyEvent &event)
void NooCanvas::pressScreen(wxMouseEvent &event)
{
// Ensure the left mouse button is clicked
if (!frame->isRunning() || !event.LeftIsDown()) return;
if (!frame->running || !event.LeftIsDown()) return;

// Determine the touch position relative to the emulated touch screen
int touchX = layout.getTouchX(event.GetX(), event.GetY());
int touchY = layout.getTouchY(event.GetX(), event.GetY());

// Send the touch coordinates to the core
frame->getCore()->input.pressScreen();
frame->getCore()->spi.setTouch(touchX, touchY);
frame->core->input.pressScreen();
frame->core->spi.setTouch(touchX, touchY);
}

void NooCanvas::releaseScreen(wxMouseEvent &event)
{
// Send a touch release to the core
if (frame->isRunning())
if (frame->running)
{
frame->getCore()->input.releaseScreen();
frame->getCore()->spi.clearTouch();
frame->core->input.releaseScreen();
frame->core->spi.clearTouch();
}
}
7 changes: 4 additions & 3 deletions src/desktop/noo_canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,19 @@ class wxGLContext;
class NooCanvas: public CANVAS_CLASS
{
public:
NooCanvas(NooFrame *frame);
bool gbaMode = false;

NooCanvas(NooFrame *frame);
void resetFrame() { sizeReset = 2; }
void finish() { finished = true; }

private:
NooFrame *frame;
wxGLContext *context;
uint32_t *framebuffer;
bool splitScreens;

ScreenLayout layout;
uint32_t framebuffer[256 * 192 * 8] = {};
bool gbaMode = false;
uint8_t sizeReset = 0;
bool finished = false;

Expand Down
Loading

0 comments on commit 0f6fac0

Please sign in to comment.