aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl
diff options
context:
space:
mode:
Diffstat (limited to 'src/libui_sdl')
-rw-r--r--src/libui_sdl/DlgAudioSettings.cpp183
-rw-r--r--src/libui_sdl/DlgAudioSettings.h29
-rw-r--r--src/libui_sdl/DlgEmuSettings.cpp13
-rw-r--r--src/libui_sdl/DlgEmuSettings.h2
-rw-r--r--src/libui_sdl/DlgInputConfig.cpp256
-rw-r--r--src/libui_sdl/DlgInputConfig.h4
-rw-r--r--src/libui_sdl/Platform.cpp2
-rw-r--r--src/libui_sdl/libui/ui.h2
-rw-r--r--src/libui_sdl/libui/unix/area.c30
-rw-r--r--src/libui_sdl/libui/unix/menu.c17
-rw-r--r--src/libui_sdl/libui/unix/stddialogs.c3
-rw-r--r--src/libui_sdl/libui/unix/window.c7
-rw-r--r--src/libui_sdl/libui/windows/button.cpp19
-rw-r--r--src/libui_sdl/main.cpp869
14 files changed, 1223 insertions, 213 deletions
diff --git a/src/libui_sdl/DlgAudioSettings.cpp b/src/libui_sdl/DlgAudioSettings.cpp
new file mode 100644
index 0000000..b02b474
--- /dev/null
+++ b/src/libui_sdl/DlgAudioSettings.cpp
@@ -0,0 +1,183 @@
+/*
+ Copyright 2016-2019 StapleButter
+
+ 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libui/ui.h"
+
+#include "../types.h"
+#include "../Config.h"
+
+#include "DlgAudioSettings.h"
+
+
+void MicLoadWav(char* path);
+
+
+namespace DlgAudioSettings
+{
+
+bool opened;
+uiWindow* win;
+
+uiSlider* slVolume;
+uiRadioButtons* rbMicInputType;
+uiEntry* txMicWavPath;
+
+int oldvolume;
+
+
+int OnCloseWindow(uiWindow* window, void* blarg)
+{
+ opened = false;
+ return 1;
+}
+
+void OnVolumeChanged(uiSlider* slider, void* blarg)
+{
+ Config::AudioVolume = uiSliderValue(slVolume);
+}
+
+void OnMicWavBrowse(uiButton* btn, void* blarg)
+{
+ char* file = uiOpenFile(win, "WAV file (*.wav)|*.wav|Any file|*.*", NULL);
+ if (!file)
+ {
+ return;
+ }
+
+ uiEntrySetText(txMicWavPath, file);
+ uiFreeText(file);
+}
+
+void OnCancel(uiButton* btn, void* blarg)
+{
+ Config::AudioVolume = oldvolume;
+
+ uiControlDestroy(uiControl(win));
+ opened = false;
+}
+
+void OnOk(uiButton* btn, void* blarg)
+{
+ Config::AudioVolume = uiSliderValue(slVolume);
+ Config::MicInputType = uiRadioButtonsSelected(rbMicInputType);
+
+ char* wavpath = uiEntryText(txMicWavPath);
+ strncpy(Config::MicWavPath, wavpath, 511);
+ uiFreeText(wavpath);
+
+ Config::Save();
+
+ if (Config::MicInputType == 3) MicLoadWav(Config::MicWavPath);
+
+ uiControlDestroy(uiControl(win));
+ opened = false;
+}
+
+void Open()
+{
+ if (opened)
+ {
+ uiControlSetFocus(uiControl(win));
+ return;
+ }
+
+ opened = true;
+ win = uiNewWindow("Audio settings - melonDS", 400, 100, 0, 0);
+ uiWindowSetMargined(win, 1);
+ uiWindowOnClosing(win, OnCloseWindow, NULL);
+
+ uiBox* top = uiNewVerticalBox();
+ uiWindowSetChild(win, uiControl(top));
+ uiBoxSetPadded(top, 1);
+
+ {
+ uiGroup* grp = uiNewGroup("Audio output");
+ uiBoxAppend(top, uiControl(grp), 0);
+ uiGroupSetMargined(grp, 1);
+
+ uiBox* in_ctrl = uiNewVerticalBox();
+ uiGroupSetChild(grp, uiControl(in_ctrl));
+
+ uiLabel* label_vol = uiNewLabel("Volume:");
+ uiBoxAppend(in_ctrl, uiControl(label_vol), 0);
+
+ slVolume = uiNewSlider(0, 256);
+ uiSliderOnChanged(slVolume, OnVolumeChanged, NULL);
+ uiBoxAppend(in_ctrl, uiControl(slVolume), 0);
+ }
+
+ {
+ uiGroup* grp = uiNewGroup("Microphone input");
+ uiBoxAppend(top, uiControl(grp), 0);
+ uiGroupSetMargined(grp, 1);
+
+ uiBox* in_ctrl = uiNewVerticalBox();
+ uiGroupSetChild(grp, uiControl(in_ctrl));
+
+ rbMicInputType = uiNewRadioButtons();
+ uiRadioButtonsAppend(rbMicInputType, "None");
+ uiRadioButtonsAppend(rbMicInputType, "Microphone");
+ uiRadioButtonsAppend(rbMicInputType, "White noise");
+ uiRadioButtonsAppend(rbMicInputType, "WAV file:");
+ uiBoxAppend(in_ctrl, uiControl(rbMicInputType), 0);
+
+ uiBox* path_box = uiNewHorizontalBox();
+ uiBoxAppend(in_ctrl, uiControl(path_box), 0);
+
+ txMicWavPath = uiNewEntry();
+ uiBoxAppend(path_box, uiControl(txMicWavPath), 1);
+
+ uiButton* path_browse = uiNewButton("...");
+ uiButtonOnClicked(path_browse, OnMicWavBrowse, NULL);
+ uiBoxAppend(path_box, uiControl(path_browse), 0);
+ }
+
+ {
+ uiBox* in_ctrl = uiNewHorizontalBox();
+ uiBoxSetPadded(in_ctrl, 1);
+ uiBoxAppend(top, uiControl(in_ctrl), 0);
+
+ uiLabel* dummy = uiNewLabel("");
+ uiBoxAppend(in_ctrl, uiControl(dummy), 1);
+
+ uiButton* btncancel = uiNewButton("Cancel");
+ uiButtonOnClicked(btncancel, OnCancel, NULL);
+ uiBoxAppend(in_ctrl, uiControl(btncancel), 0);
+
+ uiButton* btnok = uiNewButton("Ok");
+ uiButtonOnClicked(btnok, OnOk, NULL);
+ uiBoxAppend(in_ctrl, uiControl(btnok), 0);
+ }
+
+ if (Config::AudioVolume < 0) Config::AudioVolume = 0;
+ else if (Config::AudioVolume > 256) Config::AudioVolume = 256;
+
+ oldvolume = Config::AudioVolume;
+
+ uiSliderSetValue(slVolume, Config::AudioVolume);
+ uiRadioButtonsSetSelected(rbMicInputType, Config::MicInputType);
+ uiEntrySetText(txMicWavPath, Config::MicWavPath);
+
+ uiControlShow(uiControl(win));
+}
+
+}
diff --git a/src/libui_sdl/DlgAudioSettings.h b/src/libui_sdl/DlgAudioSettings.h
new file mode 100644
index 0000000..2333967
--- /dev/null
+++ b/src/libui_sdl/DlgAudioSettings.h
@@ -0,0 +1,29 @@
+/*
+ Copyright 2016-2019 StapleButter
+
+ 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 DLGAUDIOSETTINGS_H
+#define DLGAUDIOSETTINGS_H
+
+namespace DlgAudioSettings
+{
+
+void Open();
+
+}
+
+#endif // DLGAUDIOSETTINGS_H
diff --git a/src/libui_sdl/DlgEmuSettings.cpp b/src/libui_sdl/DlgEmuSettings.cpp
index 8cb2ccc..42c95b8 100644
--- a/src/libui_sdl/DlgEmuSettings.cpp
+++ b/src/libui_sdl/DlgEmuSettings.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2017 StapleButter
+ Copyright 2016-2019 StapleButter
This file is part of melonDS.
@@ -33,6 +33,7 @@ void ApplyNewSettings();
namespace DlgEmuSettings
{
+bool opened;
uiWindow* win;
uiCheckbox* cbDirectBoot;
@@ -42,12 +43,14 @@ uiCheckbox* cbBindAnyAddr;
int OnCloseWindow(uiWindow* window, void* blarg)
{
+ opened = false;
return 1;
}
void OnCancel(uiButton* btn, void* blarg)
{
uiControlDestroy(uiControl(win));
+ opened = false;
}
void OnOk(uiButton* btn, void* blarg)
@@ -59,12 +62,20 @@ void OnOk(uiButton* btn, void* blarg)
Config::Save();
uiControlDestroy(uiControl(win));
+ opened = false;
ApplyNewSettings();
}
void Open()
{
+ if (opened)
+ {
+ uiControlSetFocus(uiControl(win));
+ return;
+ }
+
+ opened = true;
win = uiNewWindow("Emu settings - melonDS", 300, 200, 0, 0);
uiWindowSetMargined(win, 1);
uiWindowOnClosing(win, OnCloseWindow, NULL);
diff --git a/src/libui_sdl/DlgEmuSettings.h b/src/libui_sdl/DlgEmuSettings.h
index f26ae14..f8da148 100644
--- a/src/libui_sdl/DlgEmuSettings.h
+++ b/src/libui_sdl/DlgEmuSettings.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2017 StapleButter
+ Copyright 2016-2019 StapleButter
This file is part of melonDS.
diff --git a/src/libui_sdl/DlgInputConfig.cpp b/src/libui_sdl/DlgInputConfig.cpp
index 5a98a91..287d7e3 100644
--- a/src/libui_sdl/DlgInputConfig.cpp
+++ b/src/libui_sdl/DlgInputConfig.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2017 StapleButter
+ Copyright 2016-2019 StapleButter
This file is part of melonDS.
@@ -35,19 +35,33 @@ extern SDL_Joystick* Joystick;
namespace DlgInputConfig
{
-uiWindow* win;
+typedef struct
+{
+ int type;
+ uiWindow* win;
+
+ uiAreaHandler areahandler;
+ uiArea* keypresscatcher;
+
+ int numkeys;
+ int keymap[32];
+ int joymap[32];
+
+ int pollid;
+ uiButton* pollbtn;
-uiAreaHandler areahandler;
-uiArea* keypresscatcher;
+} InputDlgData;
-int keyorder[12] = {0, 1, 10, 11, 5, 4, 6, 7, 9, 8, 3, 2};
-char keylabels[12][8] = {"A:", "B:", "Select:", "Start:", "Right:", "Left:", "Up:", "Down:", "R:", "L:", "X:", "Y:"};
-int keymap[12];
-int joymap[12];
+int dskeyorder[12] = {0, 1, 10, 11, 5, 4, 6, 7, 9, 8, 3, 2};
+char dskeylabels[12][8] = {"A:", "B:", "Select:", "Start:", "Right:", "Left:", "Up:", "Down:", "R:", "L:", "X:", "Y:"};
-int pollid;
-uiButton* pollbtn;
+int identity[32] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
+
+char hotkeylabels[HK_MAX][32] = {"Close/open lid:", "Microphone:"};
+
+int openedmask;
+InputDlgData inputdlg[2];
void JoyMappingName(int id, char* str)
@@ -97,7 +111,9 @@ void OnAreaResize(uiAreaHandler* handler, uiArea* area, int width, int height)
int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
{
- if (pollid < 0)
+ InputDlgData* dlg = (InputDlgData*)uiControl(area)->UserData;
+
+ if (dlg->pollid < 0)
return 0;
if (evt->Scancode == 0x38) // ALT
@@ -105,27 +121,27 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
if (evt->Modifiers == 0x2) // ALT+key
return 0;
- if (pollid > 12)
+ if (dlg->pollid > 12)
{
- if (pollid < 0x100) return 0;
- int id = pollid & 0xFF;
+ if (dlg->pollid < 0x100) return 0;
+ int id = dlg->pollid & 0xFF;
if (id > 12) return 0;
if (evt->Scancode != 0x1) // ESC
{
if (evt->Scancode == 0xE) // backspace
- joymap[id] = -1;
+ dlg->joymap[id] = -1;
else
return 1;
}
char keyname[16];
- JoyMappingName(joymap[id], keyname);
- uiButtonSetText(pollbtn, keyname);
- uiControlEnable(uiControl(pollbtn));
+ JoyMappingName(dlg->joymap[id], keyname);
+ uiButtonSetText(dlg->pollbtn, keyname);
+ uiControlEnable(uiControl(dlg->pollbtn));
- pollid = -1;
+ dlg->pollid = -1;
- uiControlSetFocus(uiControl(pollbtn));
+ uiControlSetFocus(uiControl(dlg->pollbtn));
return 1;
}
@@ -134,16 +150,16 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
{
// set key.
if (evt->Scancode != 0x1) // ESC
- keymap[pollid] = evt->Scancode;
+ dlg->keymap[dlg->pollid] = evt->Scancode;
- char* keyname = uiKeyName(keymap[pollid]);
- uiButtonSetText(pollbtn, keyname);
- uiControlEnable(uiControl(pollbtn));
+ char* keyname = uiKeyName(dlg->keymap[dlg->pollid]);
+ uiButtonSetText(dlg->pollbtn, keyname);
+ uiControlEnable(uiControl(dlg->pollbtn));
uiFreeText(keyname);
- pollid = -1;
+ dlg->pollid = -1;
- uiControlSetFocus(uiControl(pollbtn));
+ uiControlSetFocus(uiControl(dlg->pollbtn));
}
return 1;
@@ -151,8 +167,10 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
Uint32 JoyPoll(Uint32 interval, void* param)
{
- if (pollid < 0x100) return 0;
- int id = pollid & 0xFF;
+ InputDlgData* dlg = (InputDlgData*)param;
+
+ if (dlg->pollid < 0x100) return 0;
+ int id = dlg->pollid & 0xFF;
if (id > 12) return 0;
SDL_JoystickUpdate();
@@ -165,16 +183,16 @@ Uint32 JoyPoll(Uint32 interval, void* param)
{
if (SDL_JoystickGetButton(joy, i))
{
- joymap[id] = i;
+ dlg->joymap[id] = i;
char keyname[16];
- JoyMappingName(joymap[id], keyname);
- uiButtonSetText(pollbtn, keyname);
- uiControlEnable(uiControl(pollbtn));
+ JoyMappingName(dlg->joymap[id], keyname);
+ uiButtonSetText(dlg->pollbtn, keyname);
+ uiControlEnable(uiControl(dlg->pollbtn));
- pollid = -1;
+ dlg->pollid = -1;
- uiControlSetFocus(uiControl(pollbtn));
+ uiControlSetFocus(uiControl(dlg->pollbtn));
return 0;
}
}
@@ -187,16 +205,16 @@ Uint32 JoyPoll(Uint32 interval, void* param)
else if (blackhat & 0x4) blackhat = 0x4;
else blackhat = 0x8;
- joymap[id] = 0x100 | blackhat;
+ dlg->joymap[id] = 0x100 | blackhat;
char keyname[16];
- JoyMappingName(joymap[id], keyname);
- uiButtonSetText(pollbtn, keyname);
- uiControlEnable(uiControl(pollbtn));
+ JoyMappingName(dlg->joymap[id], keyname);
+ uiButtonSetText(dlg->pollbtn, keyname);
+ uiControlEnable(uiControl(dlg->pollbtn));
- pollid = -1;
+ dlg->pollid = -1;
- uiControlSetFocus(uiControl(pollbtn));
+ uiControlSetFocus(uiControl(dlg->pollbtn));
return 0;
}
@@ -206,98 +224,147 @@ Uint32 JoyPoll(Uint32 interval, void* param)
void OnKeyStartConfig(uiButton* btn, void* data)
{
- if (pollid != -1)
+ InputDlgData* dlg = (InputDlgData*)uiControl(btn)->UserData;
+
+ if (dlg->pollid != -1)
{
// TODO: handle this better?
- if (pollid <= 12)
- uiControlSetFocus(uiControl(keypresscatcher));
+ if (dlg->pollid <= 12)
+ uiControlSetFocus(uiControl(dlg->keypresscatcher));
return;
}
int id = *(int*)data;
- pollid = id;
- pollbtn = btn;
+ dlg->pollid = id;
+ dlg->pollbtn = btn;
uiButtonSetText(btn, "[press key]");
uiControlDisable(uiControl(btn));
- uiControlSetFocus(uiControl(keypresscatcher));
+ uiControlSetFocus(uiControl(dlg->keypresscatcher));
}
void OnJoyStartConfig(uiButton* btn, void* data)
{
- if (pollid != -1)
+ InputDlgData* dlg = (InputDlgData*)uiControl(btn)->UserData;
+
+ if (dlg->pollid != -1)
{
// TODO: handle this better?
- if (pollid <= 12)
- uiControlSetFocus(uiControl(keypresscatcher));
+ if (dlg->pollid <= 12)
+ uiControlSetFocus(uiControl(dlg->keypresscatcher));
return;
}
int id = *(int*)data;
- pollid = id | 0x100;
- pollbtn = btn;
+ dlg->pollid = id | 0x100;
+ dlg->pollbtn = btn;
uiButtonSetText(btn, "[press button]");
uiControlDisable(uiControl(btn));
- SDL_AddTimer(100, JoyPoll, NULL);
- uiControlSetFocus(uiControl(keypresscatcher));
+ SDL_AddTimer(100, JoyPoll, dlg);
+ uiControlSetFocus(uiControl(dlg->keypresscatcher));
}
int OnCloseWindow(uiWindow* window, void* blarg)
{
+ InputDlgData* dlg = (InputDlgData*)(uiControl(window)->UserData);
+ openedmask &= ~(1 << dlg->type);
return 1;
}
void OnGetFocus(uiWindow* window, void* blarg)
{
- if (pollid >= 0)
- uiControlSetFocus(uiControl(keypresscatcher));
+ InputDlgData* dlg = (InputDlgData*)(uiControl(window)->UserData);
+
+ if (dlg->pollid >= 0)
+ uiControlSetFocus(uiControl(dlg->keypresscatcher));
}
void OnLoseFocus(uiWindow* window, void* blarg)
{
}
-void OnCancel(uiButton* btn, void* blarg)
+void OnCancel(uiButton* btn, void* data)
{
- uiControlDestroy(uiControl(win));
+ InputDlgData* dlg = (InputDlgData*)data;
+
+ uiControlDestroy(uiControl(dlg->win));
+ openedmask &= ~(1 << dlg->type);
}
-void OnOk(uiButton* btn, void* blarg)
+void OnOk(uiButton* btn, void* data)
{
- memcpy(Config::KeyMapping, keymap, sizeof(int)*12);
- memcpy(Config::JoyMapping, joymap, sizeof(int)*12);
+ InputDlgData* dlg = (InputDlgData*)data;
+
+ if (dlg->type == 0)
+ {
+ memcpy(Config::KeyMapping, dlg->keymap, sizeof(int)*12);
+ memcpy(Config::JoyMapping, dlg->joymap, sizeof(int)*12);
+ }
+ else if (dlg->type == 1)
+ {
+ memcpy(Config::HKKeyMapping, dlg->keymap, sizeof(int)*HK_MAX);
+ memcpy(Config::HKJoyMapping, dlg->joymap, sizeof(int)*HK_MAX);
+ }
Config::Save();
- uiControlDestroy(uiControl(win));
+ uiControlDestroy(uiControl(dlg->win));
+ openedmask &= ~(1 << dlg->type);
}
-void Open()
+void Open(int type)
{
- pollid = -1;
+ InputDlgData* dlg = &inputdlg[type];
+
+ int mask = 1 << type;
+ if (openedmask & mask)
+ {
+ uiControlSetFocus(uiControl(dlg->win));
+ return;
+ }
- memcpy(keymap, Config::KeyMapping, sizeof(int)*12);
- memcpy(joymap, Config::JoyMapping, sizeof(int)*12);
+ openedmask |= mask;
- win = uiNewWindow("Input config - melonDS", 600, 400, 0, 0);
- uiWindowSetMargined(win, 1);
- uiWindowOnClosing(win, OnCloseWindow, NULL);
- uiWindowOnGetFocus(win, OnGetFocus, NULL);
- uiWindowOnLoseFocus(win, OnLoseFocus, NULL);
+ dlg->type = type;
+ dlg->pollid = -1;
- areahandler.Draw = OnAreaDraw;
- areahandler.MouseEvent = OnAreaMouseEvent;
- areahandler.MouseCrossed = OnAreaMouseCrossed;
- areahandler.DragBroken = OnAreaDragBroken;
- areahandler.KeyEvent = OnAreaKeyEvent;
- areahandler.Resize = OnAreaResize;
+ if (type == 0)
+ {
+ dlg->numkeys = 12;
+ memcpy(dlg->keymap, Config::KeyMapping, sizeof(int)*12);
+ memcpy(dlg->joymap, Config::JoyMapping, sizeof(int)*12);
+
+ dlg->win = uiNewWindow("Input config - melonDS", 600, 100, 0, 0);
+ }
+ else if (type == 1)
+ {
+ dlg->numkeys = HK_MAX;
+ memcpy(dlg->keymap, Config::HKKeyMapping, sizeof(int)*HK_MAX);
+ memcpy(dlg->joymap, Config::HKJoyMapping, sizeof(int)*HK_MAX);
+
+ dlg->win = uiNewWindow("Hotkey config - melonDS", 600, 100, 0, 0);
+ }
+
+ uiControl(dlg->win)->UserData = dlg;
+
+ uiWindowSetMargined(dlg->win, 1);
+ uiWindowOnClosing(dlg->win, OnCloseWindow, NULL);
+ uiWindowOnGetFocus(dlg->win, OnGetFocus, NULL);
+ uiWindowOnLoseFocus(dlg->win, OnLoseFocus, NULL);
+
+ dlg->areahandler.Draw = OnAreaDraw;
+ dlg->areahandler.MouseEvent = OnAreaMouseEvent;
+ dlg->areahandler.MouseCrossed = OnAreaMouseCrossed;
+ dlg->areahandler.DragBroken = OnAreaDragBroken;
+ dlg->areahandler.KeyEvent = OnAreaKeyEvent;
+ dlg->areahandler.Resize = OnAreaResize;
uiBox* top = uiNewVerticalBox();
- uiWindowSetChild(win, uiControl(top));
+ uiWindowSetChild(dlg->win, uiControl(top));
uiControlHide(uiControl(top));
{
@@ -309,22 +376,23 @@ void Open()
uiBoxAppend(in_ctrl, uiControl(g_key), 1);
uiGrid* b_key = uiNewGrid();
uiGroupSetChild(g_key, uiControl(b_key));
-
+
const int width = 120;
- for (int i = 0; i < 12; i++)
+ for (int i = 0; i < dlg->numkeys; i++)
{
- int j = keyorder[i];
+ int j = (type==0) ? dskeyorder[i] : i;
- uiLabel* label = uiNewLabel(keylabels[j]);
+ uiLabel* label = uiNewLabel((type==0) ? dskeylabels[j] : hotkeylabels[j]);
uiGridAppend(b_key, uiControl(label), 0, i, 1, 1, 1, uiAlignStart, 1, uiAlignCenter);
uiControlSetMinSize(uiControl(label), width, 1);
- char* keyname = uiKeyName(Config::KeyMapping[j]);
+ char* keyname = uiKeyName(dlg->keymap[j]);
uiButton* btn = uiNewButton(keyname);
+ uiControl(btn)->UserData = dlg;
uiGridAppend(b_key, uiControl(btn), 1, i, 1, 1, 1, uiAlignFill, 1, uiAlignCenter);
- uiButtonOnClicked(btn, OnKeyStartConfig, &keyorder[i]);
+ uiButtonOnClicked(btn, OnKeyStartConfig, (type==0) ? &dskeyorder[i] : &identity[i]);
uiControlSetMinSize(uiControl(btn), width, 1);
uiFreeText(keyname);
@@ -335,20 +403,21 @@ void Open()
uiGrid* b_joy = uiNewGrid();
uiGroupSetChild(g_joy, uiControl(b_joy));
- for (int i = 0; i < 12; i++)
+ for (int i = 0; i < dlg->numkeys; i++)
{
- int j = keyorder[i];
+ int j = (type==0) ? dskeyorder[i] : i;
- uiLabel* label = uiNewLabel(keylabels[j]);
+ uiLabel* label = uiNewLabel((type==0) ? dskeylabels[j] : hotkeylabels[j]);
uiGridAppend(b_joy, uiControl(label), 0, i, 1, 1, 1, uiAlignStart, 1, uiAlignCenter);
uiControlSetMinSize(uiControl(label), width, 1);
char keyname[16];
- JoyMappingName(Config::JoyMapping[j], keyname);
+ JoyMappingName(dlg->joymap[j], keyname);
uiButton* btn = uiNewButton(keyname);
+ uiControl(btn)->UserData = dlg;
uiGridAppend(b_joy, uiControl(btn), 1, i, 1, 1, 1, uiAlignFill, 1, uiAlignCenter);
- uiButtonOnClicked(btn, OnJoyStartConfig, &keyorder[i]);
+ uiButtonOnClicked(btn, OnJoyStartConfig, (type==0) ? &dskeyorder[i] : &identity[i]);
uiControlSetMinSize(uiControl(btn), width, 1);
}
}
@@ -364,21 +433,22 @@ void Open()
uiLabel* dummy = uiNewLabel("");
uiBoxAppend(in_ctrl, uiControl(dummy), 1);
- keypresscatcher = uiNewArea(&areahandler);
- uiBoxAppend(in_ctrl, uiControl(keypresscatcher), 0);
+ dlg->keypresscatcher = uiNewArea(&dlg->areahandler);
+ uiControl(dlg->keypresscatcher)->UserData = dlg;
+ uiBoxAppend(in_ctrl, uiControl(dlg->keypresscatcher), 0);
uiButton* btncancel = uiNewButton("Cancel");
- uiButtonOnClicked(btncancel, OnCancel, NULL);
+ uiButtonOnClicked(btncancel, OnCancel, dlg);
uiBoxAppend(in_ctrl, uiControl(btncancel), 0);
uiButton* btnok = uiNewButton("Ok");
- uiButtonOnClicked(btnok, OnOk, NULL);
+ uiButtonOnClicked(btnok, OnOk, dlg);
uiBoxAppend(in_ctrl, uiControl(btnok), 0);
}
uiControlShow(uiControl(top));
- uiControlShow(uiControl(win));
+ uiControlShow(uiControl(dlg->win));
}
}
diff --git a/src/libui_sdl/DlgInputConfig.h b/src/libui_sdl/DlgInputConfig.h
index 33529c2..2b0b6cb 100644
--- a/src/libui_sdl/DlgInputConfig.h
+++ b/src/libui_sdl/DlgInputConfig.h
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2017 StapleButter
+ Copyright 2016-2019 StapleButter
This file is part of melonDS.
@@ -22,7 +22,7 @@
namespace DlgInputConfig
{
-void Open();
+void Open(int type);
}
diff --git a/src/libui_sdl/Platform.cpp b/src/libui_sdl/Platform.cpp
index 1702685..733114e 100644
--- a/src/libui_sdl/Platform.cpp
+++ b/src/libui_sdl/Platform.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2017 StapleButter
+ Copyright 2016-2019 StapleButter
This file is part of melonDS.
diff --git a/src/libui_sdl/libui/ui.h b/src/libui_sdl/libui/ui.h
index e5a866d..1af8f59 100644
--- a/src/libui_sdl/libui/ui.h
+++ b/src/libui_sdl/libui/ui.h
@@ -76,6 +76,8 @@ struct uiControl {
void (*SetMinSize)(uiControl*, int, int);
int MinWidth, MinHeight;
+
+ void* UserData;
};
// TOOD add argument names to all arguments
#define uiControl(this) ((uiControl *) (this))
diff --git a/src/libui_sdl/libui/unix/area.c b/src/libui_sdl/libui/unix/area.c
index ea31676..2da9bab 100644
--- a/src/libui_sdl/libui/unix/area.c
+++ b/src/libui_sdl/libui/unix/area.c
@@ -77,6 +77,10 @@ static void areaWidget_init(areaWidget *aw)
static void areaWidget_dispose(GObject *obj)
{
+ // remove any draw order that might still be pending
+ areaWidget *aw = areaWidget(obj);
+ while (g_idle_remove_by_data(aw->a));
+
G_OBJECT_CLASS(areaWidget_parent_class)->dispose(obj);
}
@@ -519,16 +523,26 @@ char* uiKeyName(int scancode)
{
scancode = scancode_normal2unix(scancode);
+ char* ret;
guint* keyvals; int num;
- GdkKeymap* keymap = gdk_keymap_get_default();
- gdk_keymap_get_entries_for_keycode(keymap, scancode, NULL, &keyvals, &num);
-
- // TODO: pick smarter??
- int keyval = keyvals[0];
-
- g_free(keyvals);
+ GdkKeymap* keymap = gdk_keymap_get_for_display(gdk_display_get_default());
+ if (gdk_keymap_get_entries_for_keycode(keymap, scancode, NULL, &keyvals, &num))
+ {
+ // TODO: pick smarter??
+ int keyval = keyvals[0];
+
+ g_free(keyvals);
+
+ ret = gdk_keyval_name(keyval);
+ }
+ else
+ {
+ char tmp[16];
+ sprintf(tmp, "#%03X", scancode);
+ ret = tmp;
+ }
- return uiUnixStrdupText(gdk_keyval_name(keyval));
+ return uiUnixStrdupText(ret);
}
enum {
diff --git a/src/libui_sdl/libui/unix/menu.c b/src/libui_sdl/libui/unix/menu.c
index d6aa398..d641426 100644
--- a/src/libui_sdl/libui/unix/menu.c
+++ b/src/libui_sdl/libui/unix/menu.c
@@ -305,13 +305,13 @@ static void appendMenuItem(GtkMenuShell *submenu, uiMenuItem *item, uiWindow *w)
{
int j;
uiMenu* m;
- GtkWidget *submenu;
+ GtkWidget *c_submenu;
m = item->popupchild;
- submenu = gtk_menu_new();
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
+ c_submenu = gtk_menu_new();
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), c_submenu);
for (j = 0; j < m->items->len; j++)
- appendMenuItem(GTK_MENU_SHELL(submenu), g_array_index(m->items, uiMenuItem *, j), w);
+ appendMenuItem(GTK_MENU_SHELL(c_submenu), g_array_index(m->items, uiMenuItem *, j), w);
}
}
@@ -347,6 +347,7 @@ GtkWidget *makeMenubar(uiWindow *w)
struct freeMenuItemData {
GArray *items;
guint i;
+ guint* parent_i;
};
static void freeMenu(GtkWidget *widget, gpointer data);
@@ -359,7 +360,7 @@ static void freeMenuItem(GtkWidget *widget, gpointer data)
item = g_array_index(fmi->items, uiMenuItem *, fmi->i);
if (item->popupchild != NULL)
- freeMenu(widget, &item->popupchild->id);
+ freeMenu(widget, fmi->parent_i);//&item->popupchild->id);
w = (struct menuItemWindow *) g_hash_table_lookup(item->windows, widget);
if (g_hash_table_remove(item->windows, widget) == FALSE)
implbug("GtkMenuItem %p not in menu item's item/window map", widget);
@@ -374,14 +375,16 @@ static void freeMenu(GtkWidget *widget, gpointer data)
GtkMenuItem *item;
GtkWidget *submenu;
struct freeMenuItemData fmi;
-
+
m = g_array_index(menus, uiMenu *, *i);
item = GTK_MENU_ITEM(widget);
submenu = gtk_menu_item_get_submenu(item);
fmi.items = m->items;
fmi.i = 0;
- gtk_container_foreach(GTK_CONTAINER(submenu), freeMenuItem, &fmi);
(*i)++;
+ fmi.parent_i = i;
+ gtk_container_foreach(GTK_CONTAINER(submenu), freeMenuItem, &fmi);
+ //(*i)++;
}
void freeMenubar(GtkWidget *mb)
diff --git a/src/libui_sdl/libui/unix/stddialogs.c b/src/libui_sdl/libui/unix/stddialogs.c
index b793d06..d2b89b9 100644
--- a/src/libui_sdl/libui/unix/stddialogs.c
+++ b/src/libui_sdl/libui/unix/stddialogs.c
@@ -70,6 +70,9 @@ static char *filedialog(GtkWindow *parent, GtkFileChooserAction mode, const gcha
gtk_file_chooser_set_show_hidden(fc, TRUE);
gtk_file_chooser_set_do_overwrite_confirmation(fc, TRUE);
gtk_file_chooser_set_create_folders(fc, TRUE);
+ if (initpath && strlen(initpath)>0)
+ gtk_file_chooser_set_current_folder(fc, initpath);
+
response = gtk_dialog_run(GTK_DIALOG(fcd));
if (response != GTK_RESPONSE_ACCEPT) {
gtk_widget_destroy(fcd);
diff --git a/src/libui_sdl/libui/unix/window.c b/src/libui_sdl/libui/unix/window.c
index a3dde76..04630bc 100644
--- a/src/libui_sdl/libui/unix/window.c
+++ b/src/libui_sdl/libui/unix/window.c
@@ -145,11 +145,16 @@ static void uiWindowShow(uiControl *c)
gtk_window_resize(w->window, width, height);
}
+static void uiWindowSetFocus(uiControl* c)
+{
+ gtk_window_present(GTK_WINDOW(uiWindow(c)->widget));
+}
+
uiUnixControlDefaultHide(uiWindow)
uiUnixControlDefaultEnabled(uiWindow)
uiUnixControlDefaultEnable(uiWindow)
uiUnixControlDefaultDisable(uiWindow)
-uiUnixControlDefaultSetFocus(uiWindow)
+//uiUnixControlDefaultSetFocus(uiWindow)
uiUnixControlDefaultSetMinSize(uiWindow)
// TODO?
uiUnixControlDefaultSetContainer(uiWindow)
diff --git a/src/libui_sdl/libui/windows/button.cpp b/src/libui_sdl/libui/windows/button.cpp
index b83d6ec..aa34bfc 100644
--- a/src/libui_sdl/libui/windows/button.cpp
+++ b/src/libui_sdl/libui/windows/button.cpp
@@ -6,6 +6,9 @@ struct uiButton {
HWND hwnd;
void (*onClicked)(uiButton *, void *);
void *onClickedData;
+
+ SIZE idealSize;
+ int idealSizeCached;
};
static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult)
@@ -41,6 +44,13 @@ static void uiButtonMinimumSize(uiWindowsControl *c, int *width, int *height)
uiWindowsSizing sizing;
int y;
+ if (b->idealSizeCached)
+ {
+ *width = b->idealSize.cx;
+ *height = b->idealSize.cy;
+ return;
+ }
+
// try the comctl32 version 6 way
size.cx = 0; // explicitly ask for ideal size
size.cy = 0;
@@ -48,6 +58,9 @@ static void uiButtonMinimumSize(uiWindowsControl *c, int *width, int *height)
*width = size.cx;
if (*width < buttonMinWidth) *width = buttonMinWidth;
*height = size.cy;
+ b->idealSize.cx = *width;
+ b->idealSize.cy = *height;
+ b->idealSizeCached = true;
return;
}
@@ -60,6 +73,9 @@ static void uiButtonMinimumSize(uiWindowsControl *c, int *width, int *height)
uiWindowsGetSizing(b->hwnd, &sizing);
uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &y);
*height = y;
+ b->idealSize.cx = *width;
+ b->idealSize.cy = *height;
+ b->idealSizeCached = true;
}
static void defaultOnClicked(uiButton *b, void *data)
@@ -75,6 +91,7 @@ char *uiButtonText(uiButton *b)
void uiButtonSetText(uiButton *b, const char *text)
{
uiWindowsSetWindowText(b->hwnd, text);
+ b->idealSizeCached = 0;
// changing the text might necessitate a change in the button's size
uiWindowsControlMinimumSizeChanged(uiWindowsControl(b));
}
@@ -103,5 +120,7 @@ uiButton *uiNewButton(const char *text)
uiWindowsRegisterWM_COMMANDHandler(b->hwnd, onWM_COMMAND, uiControl(b));
uiButtonOnClicked(b, defaultOnClicked, NULL);
+ b->idealSizeCached = 0;
+
return b;
}
diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp
index 6736fbc..b30c81b 100644
--- a/src/libui_sdl/main.cpp
+++ b/src/libui_sdl/main.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2017 StapleButter
+ Copyright 2016-2019 StapleButter
This file is part of melonDS.
@@ -19,16 +19,19 @@
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
+#include <string.h>
#include <SDL2/SDL.h>
#include "libui/ui.h"
#include "../types.h"
+#include "../melon_fopen.h"
#include "../version.h"
#include "../Config.h"
#include "DlgEmuSettings.h"
#include "DlgInputConfig.h"
+#include "DlgAudioSettings.h"
#include "../NDS.h"
#include "../GPU.h"
@@ -37,6 +40,13 @@
#include "../Platform.h"
#include "../Config.h"
+#include "../Savestate.h"
+
+
+// savestate slot mapping
+// 1-8: regular slots (quick access)
+// '9': load/save arbitrary file
+const int kSavestateNum[9] = {1, 2, 3, 4, 5, 6, 7, 8, 0};
const int kScreenRot[4] = {0, 1, 2, 3};
const int kScreenGap[6] = {0, 1, 8, 64, 90, 128};
@@ -44,13 +54,25 @@ const int kScreenLayout[3] = {0, 1, 2};
const int kScreenSizing[4] = {0, 1, 2, 3};
+char* EmuDirectory;
+
+
uiWindow* MainWindow;
uiArea* MainDrawArea;
+uiMenuItem* MenuItem_SaveState;
+uiMenuItem* MenuItem_LoadState;
+uiMenuItem* MenuItem_UndoStateLoad;
+
+uiMenuItem* MenuItem_SaveStateSlot[9];
+uiMenuItem* MenuItem_LoadStateSlot[9];
+
uiMenuItem* MenuItem_Pause;
uiMenuItem* MenuItem_Reset;
uiMenuItem* MenuItem_Stop;
+uiMenuItem* MenuItem_SavestateSRAMReloc;
+
uiMenuItem* MenuItem_ScreenRot[4];
uiMenuItem* MenuItem_ScreenGap[6];
uiMenuItem* MenuItem_ScreenLayout[3];
@@ -62,6 +84,10 @@ volatile int EmuStatus;
bool RunningSomething;
char ROMPath[1024];
+char SRAMPath[1024];
+char PrevSRAMPath[1024]; // for savestate 'undo load'
+
+bool SavestateLoaded;
bool ScreenDrawInited = false;
uiDrawBitmap* ScreenBitmap = NULL;
@@ -83,11 +109,121 @@ uiDrawMatrix BottomScreenTrans;
bool Touching = false;
u32 KeyInputMask;
+bool LidCommand, LidStatus;
SDL_Joystick* Joystick;
+u32 MicBufferLength = 2048;
+s16 MicBuffer[2048];
+u32 MicBufferReadPos, MicBufferWritePos;
+
+u32 MicWavLength;
+s16* MicWavBuffer;
+
+u32 MicCommand;
+
void SetupScreenRects(int width, int height);
+void SaveState(int slot);
+void LoadState(int slot);
+void UndoStateLoad();
+void GetSavestateName(int slot, char* filename, int len);
+
+
+
+bool FileExists(const char* name)
+{
+ FILE* f = melon_fopen(name, "rb");
+ if (!f) return false;
+ fclose(f);
+ return true;
+}
+
+bool LocalFileExists(const char* name)
+{
+ FILE* f = melon_fopen_local(name, "rb");
+ if (!f) return false;
+ fclose(f);
+ return true;
+}
+
+
+void MicLoadWav(char* name)
+{
+ SDL_AudioSpec format;
+ memset(&format, 0, sizeof(SDL_AudioSpec));
+
+ if (MicWavBuffer) delete[] MicWavBuffer;
+ MicWavBuffer = NULL;
+ MicWavLength = 0;
+
+ u8* buf;
+ u32 len;
+ if (!SDL_LoadWAV(name, &format, &buf, &len))
+ return;
+
+ const u64 dstfreq = 44100;
+
+ if (format.format == AUDIO_S16 || format.format == AUDIO_U16)
+ {
+ int srcinc = format.channels;
+ len /= 2;
+
+ MicWavLength = (len * dstfreq) / format.freq;
+ if (MicWavLength < 735) MicWavLength = 735;
+ MicWavBuffer = new s16[MicWavLength];
+
+ float res_incr = len / (float)MicWavLength;
+ float res_timer = 0;
+ int res_pos = 0;
+
+ for (int i = 0; i < MicWavLength; i++)
+ {
+ u16 val = ((u16*)buf)[res_pos];
+ if (SDL_AUDIO_ISUNSIGNED(format.format)) val ^= 0x8000;
+
+ MicWavBuffer[i] = val;
+
+ res_timer += res_incr;
+ while (res_timer >= 1.0)
+ {
+ res_timer -= 1.0;
+ res_pos += srcinc;
+ }
+ }
+ }
+ else if (format.format == AUDIO_S8 || format.format == AUDIO_U8)
+ {
+ int srcinc = format.channels;
+
+ MicWavLength = (len * dstfreq) / format.freq;
+ if (MicWavLength < 735) MicWavLength = 735;
+ MicWavBuffer = new s16[MicWavLength];
+
+ float res_incr = len / (float)MicWavLength;
+ float res_timer = 0;
+ int res_pos = 0;
+
+ for (int i = 0; i < MicWavLength; i++)
+ {
+ u16 val = buf[res_pos] << 8;
+ if (SDL_AUDIO_ISUNSIGNED(format.format)) val ^= 0x8000;
+
+ MicWavBuffer[i] = val;
+
+ res_timer += res_incr;
+ while (res_timer >= 1.0)
+ {
+ res_timer -= 1.0;
+ res_pos += srcinc;
+ }
+ }
+ }
+ else
+ printf("bad WAV format %08X\n", format.format);
+
+ SDL_FreeWAV(buf);
+}
void UpdateWindowTitle(void* data)
@@ -101,7 +237,6 @@ void AudioCallback(void* data, Uint8* stream, int len)
// buffer length is 1024 samples
// which is 710 samples at the original sample rate
- //SPU::ReadOutput((s16*)stream, len>>2);
s16 buf_in[710*2];
s16* buf_out = (s16*)stream;
@@ -124,11 +259,13 @@ void AudioCallback(void* data, Uint8* stream, int len)
float res_timer = 0;
int res_pos = 0;
+ int volume = Config::AudioVolume;
+
for (int i = 0; i < 1024; i++)
{
// TODO: interp!!
- buf_out[i*2 ] = buf_in[res_pos*2 ];
- buf_out[i*2+1] = buf_in[res_pos*2+1];
+ buf_out[i*2 ] = (buf_in[res_pos*2 ] * volume) >> 8;
+ buf_out[i*2+1] = (buf_in[res_pos*2+1] * volume) >> 8;
res_timer += res_incr;
while (res_timer >= 1.0)
@@ -139,6 +276,106 @@ void AudioCallback(void* data, Uint8* stream, int len)
}
}
+void MicCallback(void* data, Uint8* stream, int len)
+{
+ if (Config::MicInputType != 1) return;
+
+ s16* input = (s16*)stream;
+ len /= sizeof(s16);
+
+ if ((MicBufferWritePos + len) > MicBufferLength)
+ {
+ u32 len1 = MicBufferLength - MicBufferWritePos;
+ memcpy(&MicBuffer[MicBufferWritePos], &input[0], len1*sizeof(s16));
+ memcpy(&MicBuffer[0], &input[len1], (len - len1)*sizeof(s16));
+ MicBufferWritePos = len - len1;
+ }
+ else
+ {
+ memcpy(&MicBuffer[MicBufferWritePos], input, len*sizeof(s16));
+ MicBufferWritePos += len;
+ }
+}
+
+bool JoyButtonPressed(int btnid, int njoybuttons, Uint8* joybuttons, Uint32 hat)
+{
+ bool pressed;
+ if (btnid == 0x101) // up
+ pressed = (hat & SDL_HAT_UP);
+ else if (btnid == 0x104) // down
+ pressed = (hat & SDL_HAT_DOWN);
+ else if (btnid == 0x102) // right
+ pressed = (hat & SDL_HAT_RIGHT);
+ else if (btnid == 0x108) // left
+ pressed = (hat & SDL_HAT_LEFT);
+ else
+ pressed = (btnid < njoybuttons) ? joybuttons[btnid] : false;
+
+ return pressed;
+}
+
+void FeedMicInput()
+{
+ int type = Config::MicInputType;
+ if ((type != 1 && MicCommand == 0) ||
+ (type == 3 && MicWavBuffer == NULL))
+ {
+ type = 0;
+ MicBufferReadPos = 0;
+ }
+
+ switch (type)
+ {
+ case 0: // no mic
+ NDS::MicInputFrame(NULL, 0);
+ break;
+
+ case 1: // host mic
+ if ((MicBufferReadPos + 735) > MicBufferLength)
+ {
+ s16 tmp[735];
+ u32 len1 = MicBufferLength - MicBufferReadPos;
+ memcpy(&tmp[0], &MicBuffer[MicBufferReadPos], len1*sizeof(s16));
+ memcpy(&tmp[len1], &MicBuffer[0], (735 - len1)*sizeof(s16));
+
+ NDS::MicInputFrame(tmp, 735);
+ MicBufferReadPos = 735 - len1;
+ }
+ else
+ {
+ NDS::MicInputFrame(&MicBuffer[MicBufferReadPos], 735);
+ MicBufferReadPos += 735;
+ }
+ break;
+
+ case 2: // white noise
+ {
+ s16 tmp[735];
+ for (int i = 0; i < 735; i++) tmp[i] = rand() & 0xFFFF;
+ NDS::MicInputFrame(tmp, 735);
+ }
+ break;
+
+ case 3: // WAV
+ if ((MicBufferReadPos + 735) > MicWavLength)
+ {
+ s16 tmp[735];
+ u32 len1 = MicWavLength - MicBufferReadPos;
+ memcpy(&tmp[0], &MicWavBuffer[MicBufferReadPos], len1*sizeof(s16));
+ memcpy(&tmp[len1], &MicWavBuffer[0], (735 - len1)*sizeof(s16));
+
+ NDS::MicInputFrame(tmp, 735);
+ MicBufferReadPos = 735 - len1;
+ }
+ else
+ {
+ NDS::MicInputFrame(&MicWavBuffer[MicBufferReadPos], 735);
+ MicBufferReadPos += 735;
+ }
+ break;
+ }
+}
+
int EmuThreadFunc(void* burp)
{
NDS::Init();
@@ -150,32 +387,18 @@ int EmuThreadFunc(void* burp)
ScreenDrawInited = false;
Touching = false;
+ KeyInputMask = 0xFFF;
+ LidCommand = false;
+ LidStatus = false;
+ MicCommand = 0;
- SDL_AudioSpec whatIwant, whatIget;
- memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
- whatIwant.freq = 47340;
- whatIwant.format = AUDIO_S16LSB;
- whatIwant.channels = 2;
- whatIwant.samples = 1024;
- whatIwant.callback = AudioCallback;
- SDL_AudioDeviceID audio = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, 0);
- if (!audio)
- {
- printf("Audio init failed: %s\n", SDL_GetError());
- }
- else
+ Uint8* joybuttons = NULL; int njoybuttons = 0;
+ if (Joystick)
{
- SDL_PauseAudioDevice(audio, 0);
+ njoybuttons = SDL_JoystickNumButtons(Joystick);
+ if (njoybuttons) joybuttons = new Uint8[njoybuttons];
}
- KeyInputMask = 0xFFF;
-
- // TODO: support more joysticks
- if (SDL_NumJoysticks() > 0)
- Joystick = SDL_JoystickOpen(0);
- else
- Joystick = NULL;
-
u32 nframes = 0;
u32 starttick = SDL_GetTicks();
u32 lasttick = starttick;
@@ -190,6 +413,7 @@ int EmuThreadFunc(void* burp)
{
EmuStatus = 1;
+
// poll input
u32 keymask = KeyInputMask;
u32 joymask = 0xFFF;
@@ -201,28 +425,49 @@ int EmuThreadFunc(void* burp)
Sint16 axisX = SDL_JoystickGetAxis(Joystick, 0);
Sint16 axisY = SDL_JoystickGetAxis(Joystick, 1);
+ for (int i = 0; i < njoybuttons; i++)
+ joybuttons[i] = SDL_JoystickGetButton(Joystick, i);
+
for (int i = 0; i < 12; i++)
{
int btnid = Config::JoyMapping[i];
if (btnid < 0) continue;
- bool pressed;
- if (btnid == 0x101) // up
- pressed = (hat & SDL_HAT_UP) || (axisY <= -16384);
- else if (btnid == 0x104) // down
- pressed = (hat & SDL_HAT_DOWN) || (axisY >= 16384);
- else if (btnid == 0x102) // right
- pressed = (hat & SDL_HAT_RIGHT) || (axisX >= 16384);
- else if (btnid == 0x108) // left
- pressed = (hat & SDL_HAT_LEFT) || (axisX <= -16384);
- else
- pressed = SDL_JoystickGetButton(Joystick, btnid);
+ bool pressed = JoyButtonPressed(btnid, njoybuttons, joybuttons, hat);
+
+ if (i == 4) // right
+ pressed = pressed || (axisX >= 16384);
+ else if (i == 5) // left
+ pressed = pressed || (axisX <= -16384);
+ else if (i == 6) // up
+ pressed = pressed || (axisY <= -16384);
+ else if (i == 7) // down
+ pressed = pressed || (axisY >= 16384);
if (pressed) joymask &= ~(1<<i);
}
+
+ if (JoyButtonPressed(Config::HKJoyMapping[HK_Lid], njoybuttons, joybuttons, hat))
+ {
+ LidStatus = !LidStatus;
+ LidCommand = true;
+ }
+ if (JoyButtonPressed(Config::HKJoyMapping[HK_Mic], njoybuttons, joybuttons, hat))
+ MicCommand |= 2;
+ else
+ MicCommand &= ~2;
}
NDS::SetKeyMask(keymask & joymask);
+ if (LidCommand)
+ {
+ NDS::SetLidClosed(LidStatus);
+ LidCommand = false;
+ }
+
+ // microphone input
+ FeedMicInput();
+
// emulate
u32 nlines = NDS::RunFrame();
@@ -301,8 +546,6 @@ int EmuThreadFunc(void* burp)
}
else
{
- EmuStatus = 2;
-
// paused
nframes = 0;
lasttick = SDL_GetTicks();
@@ -310,16 +553,20 @@ int EmuThreadFunc(void* burp)
lastmeasuretick = lasttick;
fpslimitcount = 0;
- uiAreaQueueRedrawAll(MainDrawArea);
+ if (EmuRunning == 2)
+ {
+ uiAreaQueueRedrawAll(MainDrawArea);
+ }
+
+ EmuStatus = EmuRunning;
+
SDL_Delay(100);
}
}
EmuStatus = 0;
- if (Joystick) SDL_JoystickClose(Joystick);
-
- if (audio) SDL_CloseAudioDevice(audio);
+ if (joybuttons) delete[] joybuttons;
NDS::DeInit();
@@ -438,20 +685,51 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
if (evt->Modifiers == 0x2) // ALT+key
return 0;
+ // d0rp
+ if (!RunningSomething)
+ return 1;
+
if (evt->Up)
{
for (int i = 0; i < 12; i++)
if (evt->Scancode == Config::KeyMapping[i])
KeyInputMask |= (1<<i);
+
+ if (evt->Scancode == Config::HKKeyMapping[HK_Mic])
+ MicCommand &= ~1;
}
else if (!evt->Repeat)
{
+ // F keys: 3B-44, 57-58 | SHIFT: mod. 0x4
+ if (evt->Scancode >= 0x3B && evt->Scancode <= 0x42) // F1-F8, quick savestate
+ {
+ if (evt->Modifiers == 0x4) SaveState(1 + (evt->Scancode - 0x3B));
+ else if (evt->Modifiers == 0x0) LoadState(1 + (evt->Scancode - 0x3B));
+ }
+ else if (evt->Scancode == 0x43) // F9, savestate from/to file
+ {
+ if (evt->Modifiers == 0x4) SaveState(0);
+ else if (evt->Modifiers == 0x0) LoadState(0);
+ }
+ else if (evt->Scancode == 0x58) // F12, undo savestate
+ {
+ if (evt->Modifiers == 0x0) UndoStateLoad();
+ }
+
for (int i = 0; i < 12; i++)
if (evt->Scancode == Config::KeyMapping[i])
KeyInputMask &= ~(1<<i);
- //if (evt->Scancode == 0x58) // F12
- // NDS::debug(0);
+ if (evt->Scancode == Config::HKKeyMapping[HK_Lid])
+ {
+ LidStatus = !LidStatus;
+ LidCommand = true;
+ }
+ if (evt->Scancode == Config::HKKeyMapping[HK_Mic])
+ MicCommand |= 1;
+
+ if (evt->Scancode == 0x57) // F11
+ NDS::debug(0);
}
return 1;
@@ -710,6 +988,25 @@ void Run()
EmuRunning = 1;
RunningSomething = true;
+ uiMenuItemEnable(MenuItem_SaveState);
+ uiMenuItemEnable(MenuItem_LoadState);
+
+ if (SavestateLoaded)
+ uiMenuItemEnable(MenuItem_UndoStateLoad);
+ else
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
+ for (int i = 0; i < 8; i++)
+ {
+ char ssfile[1024];
+ GetSavestateName(i+1, ssfile, 1024);
+ if (FileExists(ssfile)) uiMenuItemEnable(MenuItem_LoadStateSlot[i]);
+ else uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
+ }
+
+ for (int i = 0; i < 9; i++) uiMenuItemEnable(MenuItem_SaveStateSlot[i]);
+ uiMenuItemEnable(MenuItem_LoadStateSlot[8]);
+
uiMenuItemEnable(MenuItem_Pause);
uiMenuItemEnable(MenuItem_Reset);
uiMenuItemEnable(MenuItem_Stop);
@@ -723,6 +1020,12 @@ void Stop(bool internal)
while (EmuStatus != 2);
RunningSomething = false;
+ uiWindowSetTitle(MainWindow, "melonDS " MELONDS_VERSION);
+
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_SaveStateSlot[i]);
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
uiMenuItemDisable(MenuItem_Pause);
uiMenuItemDisable(MenuItem_Reset);
uiMenuItemDisable(MenuItem_Stop);
@@ -732,16 +1035,33 @@ void Stop(bool internal)
uiAreaQueueRedrawAll(MainDrawArea);
}
+void SetupSRAMPath()
+{
+ strncpy(SRAMPath, ROMPath, 1023);
+ SRAMPath[1023] = '\0';
+ strncpy(SRAMPath + strlen(ROMPath) - 3, "sav", 3);
+}
+
void TryLoadROM(char* file, int prevstatus)
{
char oldpath[1024];
+ char oldsram[1024];
strncpy(oldpath, ROMPath, 1024);
+ strncpy(oldsram, SRAMPath, 1024);
strncpy(ROMPath, file, 1023);
ROMPath[1023] = '\0';
- if (NDS::LoadROM(ROMPath, Config::DirectBoot))
+ SetupSRAMPath();
+
+ if (NDS::LoadROM(ROMPath, SRAMPath, Config::DirectBoot))
+ {
+ SavestateLoaded = false;
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
+ strncpy(PrevSRAMPath, SRAMPath, 1024); // safety
Run();
+ }
else
{
uiMsgBoxError(MainWindow,
@@ -749,18 +1069,200 @@ void TryLoadROM(char* file, int prevstatus)
"Make sure the file can be accessed and isn't opened in another application.");
strncpy(ROMPath, oldpath, 1024);
+ strncpy(SRAMPath, oldsram, 1024);
EmuRunning = prevstatus;
}
}
-int OnCloseWindow(uiWindow* window, void* blarg)
+// SAVESTATE TODO
+// * configurable paths. not everyone wants their ROM directory to be polluted, I guess.
+
+void GetSavestateName(int slot, char* filename, int len)
{
- if (RunningSomething)
+ int pos;
+
+ if (ROMPath[0] == '\0') // running firmware, no ROM
{
- EmuRunning = 2;
- while (EmuStatus != 2);
+ strcpy(filename, "firmware");
+ pos = 8;
+ }
+ else
+ {
+ int l = strlen(ROMPath);
+ pos = l;
+ while (ROMPath[pos] != '.' && pos > 0) pos--;
+ if (pos == 0) pos = l;
+
+ // avoid buffer overflow. shoddy
+ if (pos > len-5) pos = len-5;
+
+ strncpy(&filename[0], ROMPath, pos);
}
+ strcpy(&filename[pos], ".ml");
+ filename[pos+3] = '0'+slot;
+ filename[pos+4] = '\0';
+}
+
+void LoadState(int slot)
+{
+ int prevstatus = EmuRunning;
+ EmuRunning = 2;
+ while (EmuStatus != 2);
+
+ char filename[1024];
+
+ if (slot > 0)
+ {
+ GetSavestateName(slot, filename, 1024);
+ }
+ else
+ {
+ char* file = uiOpenFile(MainWindow, "melonDS savestate (any)|*.ml1;*.ml2;*.ml3;*.ml4;*.ml5;*.ml6;*.ml7;*.ml8;*.mln", Config::LastROMFolder);
+ if (!file)
+ {
+ EmuRunning = prevstatus;
+ return;
+ }
+
+ strncpy(filename, file, 1023);
+ filename[1023] = '\0';
+ uiFreeText(file);
+ }
+
+ if (!FileExists(filename))
+ {
+ EmuRunning = prevstatus;
+ return;
+ }
+
+ // backup
+ Savestate* backup = new Savestate("timewarp.mln", true);
+ NDS::DoSavestate(backup);
+ delete backup;
+
+ bool failed = false;
+
+ Savestate* state = new Savestate(filename, false);
+ if (state->Error)
+ {
+ delete state;
+
+ uiMsgBoxError(MainWindow, "Error", "Could not load savestate file.");
+
+ // current state might be crapoed, so restore from sane backup
+ state = new Savestate("timewarp.mln", false);
+ failed = true;
+ }
+
+ NDS::DoSavestate(state);
+ delete state;
+
+ if (!failed)
+ {
+ if (Config::SavestateRelocSRAM && ROMPath[0]!='\0')
+ {
+ strncpy(PrevSRAMPath, SRAMPath, 1024);
+
+ strncpy(SRAMPath, filename, 1019);
+ int len = strlen(SRAMPath);
+ strcpy(&SRAMPath[len], ".sav");
+ SRAMPath[len+4] = '\0';
+
+ NDS::RelocateSave(SRAMPath, false);
+ }
+
+ SavestateLoaded = true;
+ uiMenuItemEnable(MenuItem_UndoStateLoad);
+ }
+
+ EmuRunning = prevstatus;
+}
+
+void SaveState(int slot)
+{
+ int prevstatus = EmuRunning;
+ EmuRunning = 2;
+ while (EmuStatus != 2);
+
+ char filename[1024];
+
+ if (slot > 0)
+ {
+ GetSavestateName(slot, filename, 1024);
+ }
+ else
+ {
+ char* file = uiSaveFile(MainWindow, "melonDS savestate (*.mln)|*.mln", Config::LastROMFolder);
+ if (!file)
+ {
+ EmuRunning = prevstatus;
+ return;
+ }
+
+ strncpy(filename, file, 1023);
+ filename[1023] = '\0';
+ uiFreeText(file);
+ }
+
+ Savestate* state = new Savestate(filename, true);
+ if (state->Error)
+ {
+ delete state;
+
+ uiMsgBoxError(MainWindow, "Error", "Could not save state.");
+ }
+ else
+ {
+ NDS::DoSavestate(state);
+ delete state;
+
+ if (slot > 0)
+ uiMenuItemEnable(MenuItem_LoadStateSlot[slot-1]);
+
+ if (Config::SavestateRelocSRAM && ROMPath[0]!='\0')
+ {
+ strncpy(SRAMPath, filename, 1019);
+ int len = strlen(SRAMPath);
+ strcpy(&SRAMPath[len], ".sav");
+ SRAMPath[len+4] = '\0';
+
+ NDS::RelocateSave(SRAMPath, true);
+ }
+ }
+
+ EmuRunning = prevstatus;
+}
+
+void UndoStateLoad()
+{
+ if (!SavestateLoaded) return;
+
+ int prevstatus = EmuRunning;
+ EmuRunning = 2;
+ while (EmuStatus != 2);
+
+ // pray that this works
+ // what do we do if it doesn't???
+ // but it should work.
+ Savestate* backup = new Savestate("timewarp.mln", false);
+ NDS::DoSavestate(backup);
+ delete backup;
+
+ if (ROMPath[0]!='\0')
+ {
+ strncpy(SRAMPath, PrevSRAMPath, 1024);
+ NDS::RelocateSave(SRAMPath, false);
+ }
+
+ EmuRunning = prevstatus;
+}
+
+
+int OnCloseWindow(uiWindow* window, void* blarg)
+{
+ EmuRunning = 3;
+ while (EmuStatus != 3);
uiQuit();
return 1;
@@ -795,6 +1297,9 @@ void OnLoseFocus(uiWindow* window, void* blarg)
void OnCloseByMenu(uiMenuItem* item, uiWindow* window, void* blarg)
{
+ EmuRunning = 3;
+ while (EmuStatus != 3);
+
uiControlDestroy(uiControl(window));
uiQuit();
}
@@ -805,17 +1310,39 @@ void OnOpenFile(uiMenuItem* item, uiWindow* window, void* blarg)
EmuRunning = 2;
while (EmuStatus != 2);
- char* file = uiOpenFile(window, "DS ROM (*.nds)|*.nds;*.srl|Any file|*.*", NULL);
+ char* file = uiOpenFile(window, "DS ROM (*.nds)|*.nds;*.srl|Any file|*.*", Config::LastROMFolder);
if (!file)
{
EmuRunning = prevstatus;
return;
}
+
+ int pos = strlen(file)-1;
+ while (file[pos] != '/' && file[pos] != '\\' && pos > 0) pos--;
+ strncpy(Config::LastROMFolder, file, pos);
+ Config::LastROMFolder[pos] = '\0';
TryLoadROM(file, prevstatus);
uiFreeText(file);
}
+void OnSaveState(uiMenuItem* item, uiWindow* window, void* param)
+{
+ int slot = *(int*)param;
+ SaveState(slot);
+}
+
+void OnLoadState(uiMenuItem* item, uiWindow* window, void* param)
+{
+ int slot = *(int*)param;
+ LoadState(slot);
+}
+
+void OnUndoStateLoad(uiMenuItem* item, uiWindow* window, void* param)
+{
+ UndoStateLoad();
+}
+
void OnRun(uiMenuItem* item, uiWindow* window, void* blarg)
{
if (!RunningSomething)
@@ -852,10 +1379,16 @@ void OnReset(uiMenuItem* item, uiWindow* window, void* blarg)
EmuRunning = 2;
while (EmuStatus != 2);
+ SavestateLoaded = false;
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
if (ROMPath[0] == '\0')
NDS::LoadBIOS();
else
- NDS::LoadROM(ROMPath, Config::DirectBoot);
+ {
+ SetupSRAMPath();
+ NDS::LoadROM(ROMPath, SRAMPath, Config::DirectBoot);
+ }
Run();
}
@@ -874,7 +1407,23 @@ void OnOpenEmuSettings(uiMenuItem* item, uiWindow* window, void* blarg)
void OnOpenInputConfig(uiMenuItem* item, uiWindow* window, void* blarg)
{
- DlgInputConfig::Open();
+ DlgInputConfig::Open(0);
+}
+
+void OnOpenHotkeyConfig(uiMenuItem* item, uiWindow* window, void* blarg)
+{
+ DlgInputConfig::Open(1);
+}
+
+void OnOpenAudioSettings(uiMenuItem* item, uiWindow* window, void* blarg)
+{
+ DlgAudioSettings::Open();
+}
+
+
+void OnSetSavestateSRAMReloc(uiMenuItem* item, uiWindow* window, void* param)
+{
+ Config::SavestateRelocSRAM = uiMenuItemChecked(item) ? 1:0;
}
@@ -1005,15 +1554,6 @@ void ApplyNewSettings()
}
-bool _fileexists(char* name)
-{
- FILE* f = fopen(name, "rb");
- if (!f) return false;
- fclose(f);
- return true;
-}
-
-
int main(int argc, char** argv)
{
srand(time(NULL));
@@ -1021,6 +1561,19 @@ int main(int argc, char** argv)
printf("melonDS " MELONDS_VERSION "\n");
printf(MELONDS_URL "\n");
+ {
+ int len = strlen(argv[0]);
+ while (len > 0)
+ {
+ if (argv[0][len] == '/') break;
+ if (argv[0][len] == '\\') break;
+ len--;
+ }
+ EmuDirectory = new char[len];
+ strncpy(EmuDirectory, argv[0], len);
+ EmuDirectory[len] = '\0';
+ }
+
// http://stackoverflow.com/questions/14543333/joystick-wont-work-using-sdl
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
@@ -1048,7 +1601,10 @@ int main(int argc, char** argv)
Config::Load();
- if (!Config::HasConfigFile("bios7.bin") || !Config::HasConfigFile("bios9.bin") || !Config::HasConfigFile("firmware.bin"))
+ if (Config::AudioVolume < 0) Config::AudioVolume = 0;
+ else if (Config::AudioVolume > 256) Config::AudioVolume = 256;
+
+ if (!LocalFileExists("bios7.bin") || !LocalFileExists("bios9.bin") || !LocalFileExists("firmware.bin"))
{
uiMsgBoxError(
NULL,
@@ -1072,6 +1628,48 @@ int main(int argc, char** argv)
menuitem = uiMenuAppendItem(menu, "Open ROM...");
uiMenuItemOnClicked(menuitem, OnOpenFile, NULL);
uiMenuAppendSeparator(menu);
+ {
+ uiMenu* submenu = uiNewMenu("Save state");
+
+ for (int i = 0; i < 9; i++)
+ {
+ char name[32];
+ if (i < 8)
+ sprintf(name, "%d\tShift+F%d", kSavestateNum[i], kSavestateNum[i]);
+ else
+ strcpy(name, "File...\tShift+F9");
+
+ uiMenuItem* ssitem = uiMenuAppendItem(submenu, name);
+ uiMenuItemOnClicked(ssitem, OnSaveState, (void*)&kSavestateNum[i]);
+
+ MenuItem_SaveStateSlot[i] = ssitem;
+ }
+
+ MenuItem_SaveState = uiMenuAppendSubmenu(menu, submenu);
+ }
+ {
+ uiMenu* submenu = uiNewMenu("Load state");
+
+ for (int i = 0; i < 9; i++)
+ {
+ char name[32];
+ if (i < 8)
+ sprintf(name, "%d\tF%d", kSavestateNum[i], kSavestateNum[i]);
+ else
+ strcpy(name, "File...\tF9");
+
+ uiMenuItem* ssitem = uiMenuAppendItem(submenu, name);
+ uiMenuItemOnClicked(ssitem, OnLoadState, (void*)&kSavestateNum[i]);
+
+ MenuItem_LoadStateSlot[i] = ssitem;
+ }
+
+ MenuItem_LoadState = uiMenuAppendSubmenu(menu, submenu);
+ }
+ menuitem = uiMenuAppendItem(menu, "Undo state load\tF12");
+ uiMenuItemOnClicked(menuitem, OnUndoStateLoad, NULL);
+ MenuItem_UndoStateLoad = menuitem;
+ uiMenuAppendSeparator(menu);
menuitem = uiMenuAppendItem(menu, "Quit");
uiMenuItemOnClicked(menuitem, OnCloseByMenu, NULL);
@@ -1090,10 +1688,25 @@ int main(int argc, char** argv)
MenuItem_Stop = menuitem;
menu = uiNewMenu("Config");
- menuitem = uiMenuAppendItem(menu, "Emu settings");
- uiMenuItemOnClicked(menuitem, OnOpenEmuSettings, NULL);
- menuitem = uiMenuAppendItem(menu, "Input config");
- uiMenuItemOnClicked(menuitem, OnOpenInputConfig, NULL);
+ {
+ menuitem = uiMenuAppendItem(menu, "Emu settings");
+ uiMenuItemOnClicked(menuitem, OnOpenEmuSettings, NULL);
+ menuitem = uiMenuAppendItem(menu, "Input config");
+ uiMenuItemOnClicked(menuitem, OnOpenInputConfig, NULL);
+ menuitem = uiMenuAppendItem(menu, "Hotkey config");
+ uiMenuItemOnClicked(menuitem, OnOpenHotkeyConfig, NULL);
+ menuitem = uiMenuAppendItem(menu, "Audio settings");
+ uiMenuItemOnClicked(menuitem, OnOpenAudioSettings, NULL);
+ }
+ uiMenuAppendSeparator(menu);
+ {
+ uiMenu* submenu = uiNewMenu("Savestate settings");
+
+ MenuItem_SavestateSRAMReloc = uiMenuAppendCheckItem(submenu, "Separate savefiles");
+ uiMenuItemOnClicked(MenuItem_SavestateSRAMReloc, OnSetSavestateSRAMReloc, NULL);
+
+ uiMenuAppendSubmenu(menu, submenu);
+ }
uiMenuAppendSeparator(menu);
{
uiMenu* submenu = uiNewMenu("Screen rotation");
@@ -1167,6 +1780,12 @@ int main(int argc, char** argv)
uiWindowOnGetFocus(MainWindow, OnGetFocus, NULL);
uiWindowOnLoseFocus(MainWindow, OnLoseFocus, NULL);
+ //uiMenuItemDisable(MenuItem_SaveState);
+ //uiMenuItemDisable(MenuItem_LoadState);
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_SaveStateSlot[i]);
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
uiMenuItemDisable(MenuItem_Pause);
uiMenuItemDisable(MenuItem_Reset);
uiMenuItemDisable(MenuItem_Stop);
@@ -1195,6 +1814,8 @@ int main(int argc, char** argv)
SANITIZE(ScreenSizing, 0, 3);
#undef SANITIZE
+ uiMenuItemSetChecked(MenuItem_SavestateSRAMReloc, Config::SavestateRelocSRAM?1:0);
+
uiMenuItemSetChecked(MenuItem_ScreenRot[ScreenRotation], 1);
uiMenuItemSetChecked(MenuItem_ScreenLayout[ScreenLayout], 1);
uiMenuItemSetChecked(MenuItem_ScreenSizing[ScreenSizing], 1);
@@ -1207,6 +1828,53 @@ int main(int argc, char** argv)
OnSetScreenRotation(MenuItem_ScreenRot[ScreenRotation], MainWindow, (void*)&kScreenRot[ScreenRotation]);
+ SDL_AudioSpec whatIwant, whatIget;
+ memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
+ whatIwant.freq = 47340;
+ whatIwant.format = AUDIO_S16LSB;
+ whatIwant.channels = 2;
+ whatIwant.samples = 1024;
+ whatIwant.callback = AudioCallback;
+ SDL_AudioDeviceID audio = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, 0);
+ if (!audio)
+ {
+ printf("Audio init failed: %s\n", SDL_GetError());
+ }
+ else
+ {
+ SDL_PauseAudioDevice(audio, 0);
+ }
+
+ memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
+ whatIwant.freq = 44100;
+ whatIwant.format = AUDIO_S16LSB;
+ whatIwant.channels = 1;
+ whatIwant.samples = 1024;
+ whatIwant.callback = MicCallback;
+ SDL_AudioDeviceID mic = SDL_OpenAudioDevice(NULL, 1, &whatIwant, &whatIget, 0);
+ if (!mic)
+ {
+ printf("Mic init failed: %s\n", SDL_GetError());
+ MicBufferLength = 0;
+ }
+ else
+ {
+ SDL_PauseAudioDevice(mic, 0);
+ }
+
+ memset(MicBuffer, 0, sizeof(MicBuffer));
+ MicBufferReadPos = 0;
+ MicBufferWritePos = 0;
+
+ MicWavBuffer = NULL;
+ if (Config::MicInputType == 3) MicLoadWav(Config::MicWavPath);
+
+ // TODO: support more joysticks
+ if (SDL_NumJoysticks() > 0)
+ Joystick = SDL_JoystickOpen(0);
+ else
+ Joystick = NULL;
+
EmuRunning = 2;
RunningSomething = false;
EmuThread = SDL_CreateThread(EmuThreadFunc, "melonDS magic", NULL);
@@ -1221,7 +1889,9 @@ int main(int argc, char** argv)
strncpy(ROMPath, file, 1023);
ROMPath[1023] = '\0';
- if (NDS::LoadROM(ROMPath, Config::DirectBoot))
+ SetupSRAMPath();
+
+ if (NDS::LoadROM(ROMPath, SRAMPath, Config::DirectBoot))
Run();
}
}
@@ -1233,6 +1903,12 @@ int main(int argc, char** argv)
EmuRunning = 0;
SDL_WaitThread(EmuThread, NULL);
+ if (Joystick) SDL_JoystickClose(Joystick);
+ if (audio) SDL_CloseAudioDevice(audio);
+ if (mic) SDL_CloseAudioDevice(mic);
+
+ if (MicWavBuffer) delete[] MicWavBuffer;
+
Config::ScreenRotation = ScreenRotation;
Config::ScreenGap = ScreenGap;
Config::ScreenLayout = ScreenLayout;
@@ -1244,6 +1920,7 @@ int main(int argc, char** argv)
uiUninit();
SDL_Quit();
+ delete[] EmuDirectory;
return 0;
}
@@ -1253,41 +1930,35 @@ int main(int argc, char** argv)
int CALLBACK WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int cmdshow)
{
- char cmdargs[16][256];
- int arg = 1;
- int j = 0;
- bool inquote = false;
- int len = strlen(cmdline);
- for (int i = 0; i < len; i++)
- {
- char c = cmdline[i];
- if (c == '\0') break;
- if (c == '"') inquote = !inquote;
- if (!inquote && c==' ')
- {
- if (j > 255) j = 255;
- if (arg < 16) cmdargs[arg][j] = '\0';
- arg++;
- j = 0;
- }
- else
- {
- if (arg < 16 && j < 255) cmdargs[arg][j] = c;
- j++;
- }
+ int argc = 0;
+ wchar_t** argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
+ char* nullarg = "";
+
+ char** argv = new char*[argc];
+ for (int i = 0; i < argc; i++)
+ {
+ int len = WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, NULL, 0, NULL, NULL);
+ if (len < 1) return NULL;
+ argv[i] = new char[len];
+ int res = WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, argv[i], len, NULL, NULL);
+ if (res != len) { delete[] argv[i]; argv[i] = nullarg; }
+ }
+
+ if (AttachConsole(ATTACH_PARENT_PROCESS))
+ {
+ freopen("CONOUT$", "w", stdout);
+ freopen("CONOUT$", "w", stderr);
+ printf("\n");
}
- if (j > 255) j = 255;
- if (arg < 16) cmdargs[arg][j] = '\0';
- if (len > 0) arg++;
- // FIXME!!
- strncpy(cmdargs[0], "melonDS.exe", 256);
+ int ret = main(argc, argv);
+
+ printf("\n\n>");
- char* cmdargptr[16];
- for (int i = 0; i < 16; i++)
- cmdargptr[i] = &cmdargs[i][0];
+ for (int i = 0; i < argc; i++) if (argv[i] != nullarg) delete[] argv[i];
+ delete[] argv;
- return main(arg, cmdargptr);
+ return ret;
}
#endif