mirror of
https://github.com/dborth/snes9xgx.git
synced 2024-12-25 02:31:50 +01:00
Add Interpolation option and Add Gamemenu Audio
This adds the following: - A new gamemenu option called Audio - Under the new gamemenu option an option Interpolation with three options: Gaussian (Default), Linear, None
This commit is contained in:
parent
16c80360ce
commit
1479319bb5
@ -130,6 +130,8 @@ extern const u8 icon_settings_network_png[];
|
|||||||
extern const u32 icon_settings_network_png_size;
|
extern const u32 icon_settings_network_png_size;
|
||||||
extern const u8 icon_settings_video_png[];
|
extern const u8 icon_settings_video_png[];
|
||||||
extern const u32 icon_settings_video_png_size;
|
extern const u32 icon_settings_video_png_size;
|
||||||
|
extern const u8 icon_settings_audio_png[];
|
||||||
|
extern const u32 icon_settings_audio_png_size;
|
||||||
extern const u8 icon_settings_screenshot_png[];
|
extern const u8 icon_settings_screenshot_png[];
|
||||||
extern const u32 icon_settings_screenshot_png_size;
|
extern const u32 icon_settings_screenshot_png_size;
|
||||||
|
|
||||||
|
BIN
source/images/icon_settings_audio.png
Normal file
BIN
source/images/icon_settings_audio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
128
source/menu.cpp
128
source/menu.cpp
@ -41,6 +41,7 @@
|
|||||||
#include "snes9x/snes9x.h"
|
#include "snes9x/snes9x.h"
|
||||||
#include "snes9x/fxemu.h"
|
#include "snes9x/fxemu.h"
|
||||||
#include "snes9x/memmap.h"
|
#include "snes9x/memmap.h"
|
||||||
|
#include "snes9x/apu/apu.h"
|
||||||
#include "snes9x/cheats.h"
|
#include "snes9x/cheats.h"
|
||||||
|
|
||||||
extern SCheatData Cheat;
|
extern SCheatData Cheat;
|
||||||
@ -1886,6 +1887,7 @@ static int MenuGameSettings()
|
|||||||
GuiImageData btnLargeOutlineOver(button_large_over_png);
|
GuiImageData btnLargeOutlineOver(button_large_over_png);
|
||||||
GuiImageData iconMappings(icon_settings_mappings_png);
|
GuiImageData iconMappings(icon_settings_mappings_png);
|
||||||
GuiImageData iconVideo(icon_settings_video_png);
|
GuiImageData iconVideo(icon_settings_video_png);
|
||||||
|
GuiImageData iconAudio(icon_settings_audio_png);
|
||||||
GuiImageData iconController(icon_game_controllers_png);
|
GuiImageData iconController(icon_game_controllers_png);
|
||||||
GuiImageData iconCheats(icon_game_cheats_png);
|
GuiImageData iconCheats(icon_game_cheats_png);
|
||||||
GuiImageData iconScreenshot(icon_settings_screenshot_png);
|
GuiImageData iconScreenshot(icon_settings_screenshot_png);
|
||||||
@ -1902,7 +1904,7 @@ static int MenuGameSettings()
|
|||||||
GuiImage mappingBtnIcon(&iconMappings);
|
GuiImage mappingBtnIcon(&iconMappings);
|
||||||
GuiButton mappingBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight());
|
GuiButton mappingBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight());
|
||||||
mappingBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
mappingBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||||
mappingBtn.SetPosition(-125, 120);
|
mappingBtn.SetPosition(-200, 120);
|
||||||
mappingBtn.SetLabel(&mappingBtnTxt);
|
mappingBtn.SetLabel(&mappingBtnTxt);
|
||||||
mappingBtn.SetImage(&mappingBtnImg);
|
mappingBtn.SetImage(&mappingBtnImg);
|
||||||
mappingBtn.SetImageOver(&mappingBtnImgOver);
|
mappingBtn.SetImageOver(&mappingBtnImgOver);
|
||||||
@ -1913,6 +1915,24 @@ static int MenuGameSettings()
|
|||||||
mappingBtn.SetTrigger(trig2);
|
mappingBtn.SetTrigger(trig2);
|
||||||
mappingBtn.SetEffectGrow();
|
mappingBtn.SetEffectGrow();
|
||||||
|
|
||||||
|
GuiText audioBtnTxt("Audio", 22, (GXColor){0, 0, 0, 255});
|
||||||
|
audioBtnTxt.SetWrap(true, btnLargeOutline.GetWidth()-20);
|
||||||
|
GuiImage audioBtnImg(&btnLargeOutline);
|
||||||
|
GuiImage audioBtnImgOver(&btnLargeOutlineOver);
|
||||||
|
GuiImage audioBtnIcon(&iconAudio);
|
||||||
|
GuiButton audioBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight());
|
||||||
|
audioBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||||
|
audioBtn.SetPosition(0, 120);
|
||||||
|
audioBtn.SetLabel(&audioBtnTxt);
|
||||||
|
audioBtn.SetImage(&audioBtnImg);
|
||||||
|
audioBtn.SetImageOver(&audioBtnImgOver);
|
||||||
|
audioBtn.SetIcon(&audioBtnIcon);
|
||||||
|
audioBtn.SetSoundOver(&btnSoundOver);
|
||||||
|
audioBtn.SetSoundClick(&btnSoundClick);
|
||||||
|
audioBtn.SetTrigger(trigA);
|
||||||
|
audioBtn.SetTrigger(trig2);
|
||||||
|
audioBtn.SetEffectGrow();
|
||||||
|
|
||||||
GuiText videoBtnTxt("Video", 22, (GXColor){0, 0, 0, 255});
|
GuiText videoBtnTxt("Video", 22, (GXColor){0, 0, 0, 255});
|
||||||
videoBtnTxt.SetWrap(true, btnLargeOutline.GetWidth()-20);
|
videoBtnTxt.SetWrap(true, btnLargeOutline.GetWidth()-20);
|
||||||
GuiImage videoBtnImg(&btnLargeOutline);
|
GuiImage videoBtnImg(&btnLargeOutline);
|
||||||
@ -1920,7 +1940,7 @@ static int MenuGameSettings()
|
|||||||
GuiImage videoBtnIcon(&iconVideo);
|
GuiImage videoBtnIcon(&iconVideo);
|
||||||
GuiButton videoBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight());
|
GuiButton videoBtn(btnLargeOutline.GetWidth(), btnLargeOutline.GetHeight());
|
||||||
videoBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
videoBtn.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||||
videoBtn.SetPosition(125, 120);
|
videoBtn.SetPosition(200, 120);
|
||||||
videoBtn.SetLabel(&videoBtnTxt);
|
videoBtn.SetLabel(&videoBtnTxt);
|
||||||
videoBtn.SetImage(&videoBtnImg);
|
videoBtn.SetImage(&videoBtnImg);
|
||||||
videoBtn.SetImageOver(&videoBtnImgOver);
|
videoBtn.SetImageOver(&videoBtnImgOver);
|
||||||
@ -2018,6 +2038,7 @@ static int MenuGameSettings()
|
|||||||
w.Append(&titleTxt);
|
w.Append(&titleTxt);
|
||||||
w.Append(&mappingBtn);
|
w.Append(&mappingBtn);
|
||||||
w.Append(&videoBtn);
|
w.Append(&videoBtn);
|
||||||
|
w.Append(&audioBtn);
|
||||||
w.Append(&controllerBtn);
|
w.Append(&controllerBtn);
|
||||||
w.Append(&screenshotBtn);
|
w.Append(&screenshotBtn);
|
||||||
w.Append(&cheatsBtn);
|
w.Append(&cheatsBtn);
|
||||||
@ -2040,6 +2061,10 @@ static int MenuGameSettings()
|
|||||||
{
|
{
|
||||||
menu = MENU_GAMESETTINGS_VIDEO;
|
menu = MENU_GAMESETTINGS_VIDEO;
|
||||||
}
|
}
|
||||||
|
else if(audioBtn.GetState() == STATE_CLICKED)
|
||||||
|
{
|
||||||
|
menu = MENU_GAMESETTINGS_AUDIO;
|
||||||
|
}
|
||||||
else if(controllerBtn.GetState() == STATE_CLICKED)
|
else if(controllerBtn.GetState() == STATE_CLICKED)
|
||||||
{
|
{
|
||||||
ControllerWindow();
|
ControllerWindow();
|
||||||
@ -3333,6 +3358,102 @@ static int MenuSettingsVideo()
|
|||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* MenuSettingsAudio
|
||||||
|
***************************************************************************/
|
||||||
|
static int MenuSettingsAudio()
|
||||||
|
{
|
||||||
|
int menu = MENU_NONE;
|
||||||
|
int ret;
|
||||||
|
int i = 0;
|
||||||
|
bool firstRun = true;
|
||||||
|
OptionList options;
|
||||||
|
sprintf(options.name[i++], "Interpolation");
|
||||||
|
options.length = i;
|
||||||
|
for(i=0; i < options.length; i++)
|
||||||
|
options.value[i][0] = 0;
|
||||||
|
GuiText titleTxt("Game Settings - Audio", 26, (GXColor){255, 255, 255, 255});
|
||||||
|
titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
|
||||||
|
titleTxt.SetPosition(50,50);
|
||||||
|
GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM);
|
||||||
|
GuiSound btnSoundClick(button_click_pcm, button_click_pcm_size, SOUND_PCM);
|
||||||
|
GuiImageData btnOutline(button_png);
|
||||||
|
GuiImageData btnOutlineOver(button_over_png);
|
||||||
|
GuiText backBtnTxt("Go Back", 22, (GXColor){0, 0, 0, 255});
|
||||||
|
GuiImage backBtnImg(&btnOutline);
|
||||||
|
GuiImage backBtnImgOver(&btnOutlineOver);
|
||||||
|
GuiButton backBtn(btnOutline.GetWidth(), btnOutline.GetHeight());
|
||||||
|
backBtn.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
|
||||||
|
backBtn.SetPosition(50, -35);
|
||||||
|
backBtn.SetLabel(&backBtnTxt);
|
||||||
|
backBtn.SetImage(&backBtnImg);
|
||||||
|
backBtn.SetImageOver(&backBtnImgOver);
|
||||||
|
backBtn.SetSoundOver(&btnSoundOver);
|
||||||
|
backBtn.SetSoundClick(&btnSoundClick);
|
||||||
|
backBtn.SetTrigger(trigA);
|
||||||
|
backBtn.SetTrigger(trig2);
|
||||||
|
backBtn.SetEffectGrow();
|
||||||
|
GuiOptionBrowser optionBrowser(552, 248, &options);
|
||||||
|
optionBrowser.SetPosition(0, 108);
|
||||||
|
optionBrowser.SetCol2Position(200);
|
||||||
|
optionBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||||
|
HaltGui();
|
||||||
|
GuiWindow w(screenwidth, screenheight);
|
||||||
|
w.Append(&backBtn);
|
||||||
|
mainWindow->Append(&optionBrowser);
|
||||||
|
mainWindow->Append(&w);
|
||||||
|
mainWindow->Append(&titleTxt);
|
||||||
|
ResumeGui();
|
||||||
|
|
||||||
|
while(menu == MENU_NONE)
|
||||||
|
{
|
||||||
|
usleep(THREAD_SLEEP);
|
||||||
|
ret = optionBrowser.GetClickedOption();
|
||||||
|
|
||||||
|
switch (ret)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
GCSettings.Interpolation++;
|
||||||
|
if (GCSettings.Interpolation > 2) {
|
||||||
|
GCSettings.Interpolation = 0;
|
||||||
|
}
|
||||||
|
switch(GCSettings.Interpolation)
|
||||||
|
{
|
||||||
|
case 0: Settings.InterpolationMethod = DSP_INTERPOLATION_GAUSSIAN; break;
|
||||||
|
case 1: Settings.InterpolationMethod = DSP_INTERPOLATION_LINEAR; break;
|
||||||
|
case 2: Settings.InterpolationMethod = DSP_INTERPOLATION_NONE; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
S9xReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ret >= 0 || firstRun)
|
||||||
|
{
|
||||||
|
firstRun = false;
|
||||||
|
|
||||||
|
switch(GCSettings.Interpolation)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
sprintf (options.value[0], "Gaussian (Accurate)"); break;
|
||||||
|
case 1:
|
||||||
|
sprintf (options.value[0], "Linear"); break;
|
||||||
|
case 2:
|
||||||
|
sprintf (options.value[0], "None"); break;
|
||||||
|
}
|
||||||
|
optionBrowser.TriggerUpdate();
|
||||||
|
}
|
||||||
|
if(backBtn.GetState() == STATE_CLICKED)
|
||||||
|
{
|
||||||
|
menu = MENU_GAMESETTINGS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HaltGui();
|
||||||
|
mainWindow->Remove(&optionBrowser);
|
||||||
|
mainWindow->Remove(&w);
|
||||||
|
mainWindow->Remove(&titleTxt);
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* MenuSettings
|
* MenuSettings
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
@ -4158,6 +4279,9 @@ MainMenu (int menu)
|
|||||||
case MENU_GAMESETTINGS_VIDEO:
|
case MENU_GAMESETTINGS_VIDEO:
|
||||||
currentMenu = MenuSettingsVideo();
|
currentMenu = MenuSettingsVideo();
|
||||||
break;
|
break;
|
||||||
|
case MENU_GAMESETTINGS_AUDIO:
|
||||||
|
currentMenu = MenuSettingsAudio();
|
||||||
|
break;
|
||||||
case MENU_GAMESETTINGS_CHEATS:
|
case MENU_GAMESETTINGS_CHEATS:
|
||||||
currentMenu = MenuGameCheats();
|
currentMenu = MenuGameCheats();
|
||||||
break;
|
break;
|
||||||
|
@ -41,6 +41,7 @@ enum
|
|||||||
MENU_GAMESETTINGS_MAPPINGS_CTRL,
|
MENU_GAMESETTINGS_MAPPINGS_CTRL,
|
||||||
MENU_GAMESETTINGS_MAPPINGS_MAP,
|
MENU_GAMESETTINGS_MAPPINGS_MAP,
|
||||||
MENU_GAMESETTINGS_VIDEO,
|
MENU_GAMESETTINGS_VIDEO,
|
||||||
|
MENU_GAMESETTINGS_AUDIO,
|
||||||
MENU_GAMESETTINGS_CHEATS
|
MENU_GAMESETTINGS_CHEATS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "button_mapping.h"
|
#include "button_mapping.h"
|
||||||
|
|
||||||
|
#include "snes9x/apu/apu.h"
|
||||||
|
|
||||||
struct SGCSettings GCSettings;
|
struct SGCSettings GCSettings;
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -151,6 +153,7 @@ preparePrefsData ()
|
|||||||
createXMLSetting("xshift", "Horizontal Video Shift", toStr(GCSettings.xshift));
|
createXMLSetting("xshift", "Horizontal Video Shift", toStr(GCSettings.xshift));
|
||||||
createXMLSetting("yshift", "Vertical Video Shift", toStr(GCSettings.yshift));
|
createXMLSetting("yshift", "Vertical Video Shift", toStr(GCSettings.yshift));
|
||||||
createXMLSetting("sfxOverclock", "SuperFX Overclock", toStr(GCSettings.sfxOverclock));
|
createXMLSetting("sfxOverclock", "SuperFX Overclock", toStr(GCSettings.sfxOverclock));
|
||||||
|
createXMLSetting("Interpolation", "Interpolation", toStr(GCSettings.Interpolation));
|
||||||
|
|
||||||
createXMLSection("Menu", "Menu Settings");
|
createXMLSection("Menu", "Menu Settings");
|
||||||
|
|
||||||
@ -335,7 +338,11 @@ decodePrefsData ()
|
|||||||
loadXMLSetting(&GCSettings.xshift, "xshift");
|
loadXMLSetting(&GCSettings.xshift, "xshift");
|
||||||
loadXMLSetting(&GCSettings.yshift, "yshift");
|
loadXMLSetting(&GCSettings.yshift, "yshift");
|
||||||
|
|
||||||
//Emulation Settings
|
// Audio Settings
|
||||||
|
|
||||||
|
loadXMLSetting(&GCSettings.Interpolation, "Interpolation");
|
||||||
|
|
||||||
|
// Emulation Settings
|
||||||
|
|
||||||
loadXMLSetting(&GCSettings.sfxOverclock, "sfxOverclock");
|
loadXMLSetting(&GCSettings.sfxOverclock, "sfxOverclock");
|
||||||
|
|
||||||
@ -489,6 +496,10 @@ DefaultSettings ()
|
|||||||
Settings.SoundInputRate = 31950;
|
Settings.SoundInputRate = 31950;
|
||||||
Settings.DynamicRateControl = true;
|
Settings.DynamicRateControl = true;
|
||||||
|
|
||||||
|
// Interpolation Method
|
||||||
|
GCSettings.Interpolation = 0;
|
||||||
|
Settings.InterpolationMethod = DSP_INTERPOLATION_GAUSSIAN;
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
Settings.Transparency = true;
|
Settings.Transparency = true;
|
||||||
Settings.SupportHiRes = true;
|
Settings.SupportHiRes = true;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// snes_spc 0.9.0. http://www.slack.net/~ant/
|
// snes_spc 0.9.0. http://www.slack.net/~ant/
|
||||||
|
|
||||||
|
#include "snes9x.h"
|
||||||
|
|
||||||
#include "SPC_DSP.h"
|
#include "SPC_DSP.h"
|
||||||
|
|
||||||
#include "blargg_endian.h"
|
#include "blargg_endian.h"
|
||||||
@ -127,25 +129,44 @@ static short const gauss [512] =
|
|||||||
|
|
||||||
inline int SPC_DSP::interpolate( voice_t const* v )
|
inline int SPC_DSP::interpolate( voice_t const* v )
|
||||||
{
|
{
|
||||||
// Make pointers into gaussian based on fractional position between samples
|
int out;
|
||||||
int offset = v->interp_pos >> 4 & 0xFF;
|
int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];
|
||||||
short const* fwd = gauss + 255 - offset;
|
switch (Settings.InterpolationMethod)
|
||||||
short const* rev = gauss + offset; // mirror left half of gaussian
|
{
|
||||||
|
case 0: // raw
|
||||||
int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];
|
{
|
||||||
int out;
|
out = v->buf [(v->interp_pos >> 12) + v->buf_pos] & ~1;
|
||||||
out = (fwd [ 0] * in [0]) >> 11;
|
break;
|
||||||
out += (fwd [256] * in [1]) >> 11;
|
}
|
||||||
out += (rev [256] * in [2]) >> 11;
|
case 1: // linear interpolation
|
||||||
out = (int16_t) out;
|
{
|
||||||
out += (rev [ 0] * in [3]) >> 11;
|
int fract = v->interp_pos & 0xFFF;
|
||||||
|
out = (0x1000 - fract) * in [0];
|
||||||
CLAMP16( out );
|
out += fract * in [1];
|
||||||
out &= ~1;
|
out >>= 12;
|
||||||
return out;
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
case 2: // Original gaussian filter
|
||||||
|
{
|
||||||
|
// Make pointers into gaussian based on fractional position between samples
|
||||||
|
int offset = v->interp_pos >> 4 & 0xFF;
|
||||||
|
short const* fwd = gauss + 255 - offset;
|
||||||
|
short const* rev = gauss + offset; // mirror left half of gaussian
|
||||||
|
int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];
|
||||||
|
out = (fwd [ 0] * in [0]) >> 11;
|
||||||
|
out += (fwd [256] * in [1]) >> 11;
|
||||||
|
out += (rev [256] * in [2]) >> 11;
|
||||||
|
out = (int16_t) out;
|
||||||
|
out += (rev [ 0] * in [3]) >> 11;
|
||||||
|
CLAMP16( out );
|
||||||
|
out &= ~1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//// Counters
|
//// Counters
|
||||||
|
|
||||||
int const simple_counter_range = 2048 * 5 * 3; // 30720
|
int const simple_counter_range = 2048 * 5 * 3; // 30720
|
||||||
|
@ -47,4 +47,8 @@ void S9xUpdateDynamicRate (double rate);
|
|||||||
|
|
||||||
extern SNES_SPC *spc_core;
|
extern SNES_SPC *spc_core;
|
||||||
|
|
||||||
|
#define DSP_INTERPOLATION_NONE 0
|
||||||
|
#define DSP_INTERPOLATION_LINEAR 1
|
||||||
|
#define DSP_INTERPOLATION_GAUSSIAN 2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -242,6 +242,7 @@ struct SSettings
|
|||||||
bool8 ReverseStereo;
|
bool8 ReverseStereo;
|
||||||
bool8 Mute;
|
bool8 Mute;
|
||||||
bool8 DynamicRateControl;
|
bool8 DynamicRateControl;
|
||||||
|
int32 InterpolationMethod;
|
||||||
|
|
||||||
bool8 SupportHiRes;
|
bool8 SupportHiRes;
|
||||||
bool8 Transparency;
|
bool8 Transparency;
|
||||||
|
@ -486,6 +486,13 @@ int main(int argc, char *argv[])
|
|||||||
S9xResetSuperFX();
|
S9xResetSuperFX();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (GCSettings.Interpolation)
|
||||||
|
{
|
||||||
|
case 0: Settings.InterpolationMethod = DSP_INTERPOLATION_GAUSSIAN; break;
|
||||||
|
case 1: Settings.InterpolationMethod = DSP_INTERPOLATION_LINEAR; break;
|
||||||
|
case 2: Settings.InterpolationMethod = DSP_INTERPOLATION_NONE; break;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) // main loop
|
while (1) // main loop
|
||||||
{
|
{
|
||||||
if(!autoboot) {
|
if(!autoboot) {
|
||||||
|
@ -119,6 +119,8 @@ struct SGCSettings{
|
|||||||
int PreviewImage;
|
int PreviewImage;
|
||||||
|
|
||||||
int sfxOverclock;
|
int sfxOverclock;
|
||||||
|
|
||||||
|
int Interpolation;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ExitApp();
|
void ExitApp();
|
||||||
|
Loading…
Reference in New Issue
Block a user