Skip to content

Commit 0f6fac0

Browse files
committed
Desktop: add an option to split screens across windows
1 parent e7813f6 commit 0f6fac0

11 files changed

+206
-139
lines changed

src/common/screen_layout.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ void ScreenLayout::addSettings()
4646
Settings::add(layoutSettings);
4747
}
4848

49-
void ScreenLayout::update(int winWidth, int winHeight, bool gbaMode)
49+
void ScreenLayout::update(int winWidth, int winHeight, bool gbaMode, bool splitScreens)
5050
{
5151
// Update the window dimensions
5252
this->winWidth = winWidth;
5353
this->winHeight = winHeight;
5454

55-
if (screenArrangement == 3 || (gbaMode && gbaCrop)) // Single screen
55+
if (screenArrangement == 3 || (gbaMode && gbaCrop) || splitScreens) // Single screen
5656
{
5757
// Determine the screen dimensions based on the current rotation
5858
int width = (gbaMode && gbaCrop) ? (screenRotation ? 160 : 240) : (screenRotation ? 192 : 256);

src/common/screen_layout.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class ScreenLayout
4040

4141
static void addSettings();
4242

43-
void update(int winWidth, int winHeight, bool gbaMode);
43+
void update(int winWidth, int winHeight, bool gbaMode, bool splitScreens = false);
4444
int getTouchX(int x, int y);
4545
int getTouchY(int x, int y);
4646
};

src/desktop/layout_dialog.cpp

+18-5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ enum LayoutEvent
4848
FILT_LINEAR,
4949
INT_SCALE,
5050
GBA_CROP,
51+
SPLIT_SCREENS,
5152
SCREEN_GHOST
5253
};
5354

@@ -76,6 +77,7 @@ EVT_RADIOBUTTON(FILT_UPSCALE, LayoutDialog::filtUpscale)
7677
EVT_RADIOBUTTON(FILT_LINEAR, LayoutDialog::filtLinear)
7778
EVT_CHECKBOX(INT_SCALE, LayoutDialog::intScale)
7879
EVT_CHECKBOX(GBA_CROP, LayoutDialog::gbaCrop)
80+
EVT_CHECKBOX(SPLIT_SCREENS, LayoutDialog::splitScreens)
7981
EVT_CHECKBOX(SCREEN_GHOST, LayoutDialog::screenGhost)
8082
EVT_BUTTON(wxID_CANCEL, LayoutDialog::cancel)
8183
EVT_BUTTON(wxID_OK, LayoutDialog::confirm)
@@ -92,7 +94,8 @@ LayoutDialog::LayoutDialog(NooApp *app): wxDialog(nullptr, wxID_ANY, "Screen Lay
9294
prevSettings[5] = Settings::screenFilter;
9395
prevSettings[6] = ScreenLayout::integerScale;
9496
prevSettings[7] = ScreenLayout::gbaCrop;
95-
prevSettings[8] = Settings::screenGhost;
97+
prevSettings[8] = NooApp::splitScreens;
98+
prevSettings[9] = Settings::screenGhost;
9699

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

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

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

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

394+
void LayoutDialog::splitScreens(wxCommandEvent &event)
395+
{
396+
// Toggle the split screens setting
397+
NooApp::splitScreens = !NooApp::splitScreens;
398+
app->updateLayouts();
399+
}
400+
389401
void LayoutDialog::screenGhost(wxCommandEvent &event)
390402
{
391403
// Toggle the screen ghost setting
@@ -404,7 +416,8 @@ void LayoutDialog::cancel(wxCommandEvent &event)
404416
Settings::screenFilter = prevSettings[5];
405417
ScreenLayout::integerScale = prevSettings[6];
406418
ScreenLayout::gbaCrop = prevSettings[7];
407-
Settings::screenGhost = prevSettings[8];
419+
NooApp::splitScreens = prevSettings[8];
420+
Settings::screenGhost = prevSettings[9];
408421
app->updateLayouts();
409422
event.Skip(true);
410423
}

src/desktop/layout_dialog.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class LayoutDialog: public wxDialog
3131

3232
private:
3333
NooApp *app;
34-
int prevSettings[9];
34+
int prevSettings[10];
3535

3636
void posCenter(wxCommandEvent &event);
3737
void posTop(wxCommandEvent &event);
@@ -57,6 +57,7 @@ class LayoutDialog: public wxDialog
5757
void filtLinear(wxCommandEvent &event);
5858
void intScale(wxCommandEvent &event);
5959
void gbaCrop(wxCommandEvent &event);
60+
void splitScreens(wxCommandEvent &event);
6061
void screenGhost(wxCommandEvent &event);
6162
void cancel(wxCommandEvent &event);
6263
void confirm(wxCommandEvent &event);

src/desktop/noo_app.cpp

+8-6
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ EVT_TIMER(UPDATE, NooApp::update)
3535
wxEND_EVENT_TABLE()
3636

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

4041
bool NooApp::OnInit()
@@ -45,6 +46,7 @@ bool NooApp::OnInit()
4546
std::vector<Setting> platformSettings =
4647
{
4748
Setting("micEnable", &micEnable, false),
49+
Setting("splitScreens", &splitScreens, false),
4850
Setting("keyA", &keyBinds[0], false),
4951
Setting("keyB", &keyBinds[1], false),
5052
Setting("keySelect", &keyBinds[2], false),
@@ -141,8 +143,8 @@ void NooApp::connectCore(int id)
141143
for (int i = 0; i < MAX_FRAMES; i++)
142144
{
143145
if (!frames[i] || i == id) continue;
144-
if (Core *core = frames[i]->getCore())
145-
core->wifi.addConnection(frames[id]->getCore());
146+
if (Core *core = frames[i]->core)
147+
core->wifi.addConnection(frames[id]->core);
146148
}
147149
}
148150

@@ -152,8 +154,8 @@ void NooApp::disconnCore(int id)
152154
for (int i = 0; i < MAX_FRAMES; i++)
153155
{
154156
if (!frames[i] || i == id) continue;
155-
if (Core *core = frames[i]->getCore())
156-
core->wifi.remConnection(frames[id]->getCore());
157+
if (Core *core = frames[i]->core)
158+
core->wifi.remConnection(frames[id]->core);
157159
}
158160
}
159161

@@ -219,7 +221,7 @@ int NooApp::audioCallback(const void *in, void *out, unsigned long count,
219221
for (size_t i = 0; i < MAX_FRAMES; i++)
220222
{
221223
if (!frames[i]) continue;
222-
if (Core *core = frames[i]->getCore())
224+
if (Core *core = frames[i]->core)
223225
{
224226
uint32_t *samples = core->spu.getSamples(699);
225227
if (!original)
@@ -260,7 +262,7 @@ int NooApp::micCallback(const void *in, void *out, unsigned long count,
260262
// Find the core with the lowest instance ID
261263
for (size_t i = 0; i < MAX_FRAMES; i++)
262264
{
263-
if (frames[i] && (core = frames[i]->getCore()))
265+
if (frames[i] && (core = frames[i]->core))
264266
break;
265267
}
266268

src/desktop/noo_app.h

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class NooApp: public wxApp
3232
{
3333
public:
3434
static int micEnable;
35+
static int splitScreens;
3536
static int keyBinds[MAX_KEYS];
3637

3738
void createFrame();

src/desktop/noo_canvas.cpp

+38-18
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,21 @@ NooCanvas::NooCanvas(NooFrame *frame): CANVAS_CLASS(frame, wxID_ANY, CANVAS_PARA
5555
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5656
#endif
5757

58-
// Set focus so that key presses will be registered
59-
SetFocus();
58+
// Create a new framebuffer or share one if the screens are split
59+
if (frame->mainFrame)
60+
{
61+
framebuffer = new uint32_t[256 * 192 * 8];
62+
memset(framebuffer, 0, 256 * 192 * 8 * sizeof(uint32_t));
63+
}
64+
else
65+
{
66+
framebuffer = frame->partner->canvas->framebuffer;
67+
}
68+
69+
// Update the screen layout and set focus for key presses
70+
splitScreens = NooApp::splitScreens && ScreenLayout::screenArrangement != 3;
6071
frame->SendSizeEvent();
72+
SetFocus();
6173
}
6274

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

126-
if (frame->getCore())
138+
// Update the screen layout if it changed
139+
bool gba = ScreenLayout::gbaCrop && frame->core && frame->core->gbaMode;
140+
bool split = NooApp::splitScreens && ScreenLayout::screenArrangement != 3 && !gba;
141+
if (gbaMode != gba || splitScreens != split)
127142
{
128-
// Update the layout if GBA mode changed
129-
bool gba = (frame->getCore()->gbaMode && ScreenLayout::gbaCrop);
130-
if (gbaMode != gba)
131-
{
132-
gbaMode = gba;
133-
frame->SendSizeEvent();
134-
}
143+
gbaMode = gba;
144+
splitScreens = split;
145+
frame->SendSizeEvent();
146+
}
135147

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

142156
// Shift the screen resolutions if high-res is enabled
@@ -148,6 +162,12 @@ void NooCanvas::draw(wxPaintEvent &event)
148162
drawScreen(layout.topX, layout.topY, layout.topWidth,
149163
layout.topHeight, 240 << shift, 160 << shift, &framebuffer[0]);
150164
}
165+
else if (frame->partner)
166+
{
167+
// Draw one of the DS screens
168+
drawScreen(layout.topX, layout.topY, layout.topWidth, layout.topHeight, 256 << shift,
169+
192 << shift, &framebuffer[!frame->mainFrame * ((256 * 192) << (shift * 2))]);
170+
}
151171
else
152172
{
153173
// Draw the DS top and bottom screens
@@ -181,7 +201,7 @@ void NooCanvas::resize(wxSizeEvent &event)
181201
{
182202
// Update the screen layout
183203
wxSize size = GetSize();
184-
layout.update(size.x, size.y, gbaMode);
204+
layout.update(size.x, size.y, gbaMode, splitScreens);
185205

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

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

234254
// Send the touch coordinates to the core
235-
frame->getCore()->input.pressScreen();
236-
frame->getCore()->spi.setTouch(touchX, touchY);
255+
frame->core->input.pressScreen();
256+
frame->core->spi.setTouch(touchX, touchY);
237257
}
238258

239259
void NooCanvas::releaseScreen(wxMouseEvent &event)
240260
{
241261
// Send a touch release to the core
242-
if (frame->isRunning())
262+
if (frame->running)
243263
{
244-
frame->getCore()->input.releaseScreen();
245-
frame->getCore()->spi.clearTouch();
264+
frame->core->input.releaseScreen();
265+
frame->core->spi.clearTouch();
246266
}
247267
}

src/desktop/noo_canvas.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,19 @@ class wxGLContext;
4040
class NooCanvas: public CANVAS_CLASS
4141
{
4242
public:
43-
NooCanvas(NooFrame *frame);
43+
bool gbaMode = false;
4444

45+
NooCanvas(NooFrame *frame);
4546
void resetFrame() { sizeReset = 2; }
4647
void finish() { finished = true; }
4748

4849
private:
4950
NooFrame *frame;
5051
wxGLContext *context;
52+
uint32_t *framebuffer;
53+
bool splitScreens;
5154

5255
ScreenLayout layout;
53-
uint32_t framebuffer[256 * 192 * 8] = {};
54-
bool gbaMode = false;
5556
uint8_t sizeReset = 0;
5657
bool finished = false;
5758

0 commit comments

Comments
 (0)