1
// Copyright (c) 2012- PPSSPP Project.
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
18
// NativeApp implementation for platforms that will use that framework, like:
19
// Android, Linux, MacOSX.
21
// Native is a cross platform framework. It's not very mature and mostly
22
// just built according to the needs of my own apps.
24
// Windows has its own code that bypasses the framework entirely.
27
// Background worker threads should be spawned in NativeInit and joined
31
// Linux doesn't like using std::find with std::vector<int> without this :/
32
#if !defined(MOBILE_DEVICE)
38
#include "Windows/DSoundStream.h"
39
#include "Windows/MainWindow.h"
40
#include "Windows/D3D9Base.h"
43
#include "base/display.h"
44
#include "base/logging.h"
45
#include "base/mutex.h"
46
#include "base/NativeApp.h"
48
#include "file/zip_read.h"
49
#include "thread/thread.h"
50
#include "net/http_client.h"
51
#include "gfx_es2/draw_text.h"
52
#include "gfx_es2/gpu_features.h"
53
#include "gfx/gl_lost_manager.h"
54
#include "i18n/i18n.h"
55
#include "input/input_state.h"
56
#include "math/fast/fast_math.h"
57
#include "math/math_util.h"
58
#include "math/lin/matrix4x4.h"
59
#include "profiler/profiler.h"
60
#include "thin3d/thin3d.h"
62
#include "ui/screen.h"
63
#include "ui/ui_context.h"
65
#include "util/text/utf8.h"
67
#include "Common/CPUDetect.h"
68
#include "Common/FileUtil.h"
69
#include "Common/LogManager.h"
70
#include "Common/MemArena.h"
71
#include "Core/Config.h"
72
#include "Core/Core.h"
73
#include "Core/FileLoaders/DiskCachingFileLoader.h"
74
#include "Core/Host.h"
75
#include "Core/SaveState.h"
76
#include "Core/Screenshot.h"
77
#include "Core/System.h"
78
#include "Core/HLE/__sceAudio.h"
79
#include "Core/HLE/sceCtrl.h"
80
#include "Core/Util/GameManager.h"
81
#include "Core/Util/AudioFormat.h"
84
#include "EmuScreen.h"
85
#include "GameInfoCache.h"
86
#include "HostTypes.h"
87
#include "UI/OnScreenDisplay.h"
88
#include "UI/MiscScreens.h"
89
#include "UI/TiltEventProcessor.h"
90
#include "UI/BackgroundAudio.h"
92
#if !defined(MOBILE_DEVICE)
93
#include "Common/KeyMap.h"
97
#define unique_ptr auto_ptr
100
// The new UI framework, for initialization
102
static UI::Theme ui_theme;
105
#include "../../android/jni/ArmEmitterTest.h"
107
#include "../../android/jni/Arm64EmitterTest.h"
111
#include "ios/iOSCoreAudio.h"
112
#elif defined(__APPLE__)
113
#include <mach-o/dyld.h>
116
// https://github.com/richq/android-ndk-profiler
117
#ifdef ANDROID_NDK_PROFILER
119
#include "android/android-ndk-profiler/prof.h"
122
Thin3DTexture *uiTexture;
124
ScreenManager *screenManager;
125
std::string config_filename;
131
// Really need to clean this mess of globals up... but instead I add more :P
132
bool g_TakeScreenshot;
134
static bool resized = false;
136
struct PendingMessage {
141
static recursive_mutex pendingMutex;
142
static std::vector<PendingMessage> pendingMessages;
143
static Thin3DContext *thin3d;
144
static UIContext *uiContext;
147
WindowsAudioBackend *winAudioBackend;
150
Thin3DContext *GetThin3D() {
154
std::thread *graphicsLoadThread;
156
class AndroidLogger : public LogListener {
158
void Log(LogTypes::LOG_LEVELS level, const char *msg) {
160
case LogTypes::LVERBOSE:
161
case LogTypes::LDEBUG:
162
case LogTypes::LINFO:
165
case LogTypes::LERROR:
168
case LogTypes::LWARNING:
171
case LogTypes::LNOTICE:
180
int Win32Mix(short *buffer, int numSamples, int bits, int rate, int channels) {
181
return NativeMix(buffer, numSamples);
187
static AndroidLogger *logger = 0;
190
std::string boot_filename = "";
192
void NativeHost::InitSound() {
198
void NativeHost::ShutdownSound() {
200
iOSCoreAudioShutdown();
204
#if !defined(MOBILE_DEVICE) && defined(USING_QT_UI)
205
void QtHost::InitSound() { }
206
void QtHost::ShutdownSound() { }
209
std::string NativeQueryConfig(std::string query) {
211
if (query == "screenRotation") {
212
sprintf(temp, "%i", g_Config.iScreenRotation);
213
return std::string(temp);
214
} else if (query == "immersiveMode") {
215
return std::string(g_Config.bImmersiveMode ? "1" : "0");
216
} else if (query == "hwScale") {
217
int scale = g_Config.iAndroidHwScale;
219
// If g_Config.iInternalResolution is also set to Auto (1), we fall back to "Device resolution" (0). It works out.
220
scale = g_Config.iInternalResolution;
221
} else if (scale >= 2) {
225
int max_res = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 1;
226
sprintf(temp, "%i", std::min(scale, max_res));
227
return std::string(temp);
228
} else if (query == "force44khz") {
229
return std::string("0");
235
int NativeMix(short *audio, int num_samples) {
236
if (GetUIState() != UISTATE_INGAME) {
237
PlayBackgroundAudio();
240
int sample_rate = System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE);
241
num_samples = __AudioMix(audio, num_samples, sample_rate > 0 ? sample_rate : 44100);
244
winAudioBackend->Update();
250
// This is called before NativeInit so we do a little bit of initialization here.
251
void NativeGetAppInfo(std::string *app_dir_name, std::string *app_nice_name, bool *landscape, std::string *version) {
252
*app_nice_name = "PPSSPP";
253
*app_dir_name = "ppsspp";
255
*version = PPSSPP_GIT_VERSION;
257
#if defined(ARM) && defined(ANDROID)
259
#elif defined(ARM64) && defined(ANDROID)
265
bool CheckFontIsUsable(const wchar_t *fontFace) {
266
wchar_t actualFontFace[1024] = { 0 };
268
HFONT f = CreateFont(0, 0, 0, 0, FW_LIGHT, 0, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, fontFace);
270
HDC hdc = CreateCompatibleDC(nullptr);
271
if (hdc != nullptr) {
272
SelectObject(hdc, f);
273
GetTextFace(hdc, 1024, actualFontFace);
279
// If we were able to get the font name, did it load?
280
if (actualFontFace[0] != 0) {
281
return wcsncmp(actualFontFace, fontFace, ARRAY_SIZE(actualFontFace)) == 0;
287
void NativeInit(int argc, const char *argv[],
288
const char *savegame_directory, const char *external_directory, const char *installID, bool fs) {
289
#ifdef ANDROID_NDK_PROFILER
290
setenv("CPUPROFILE_FREQUENCY", "500", 1);
291
setenv("CPUPROFILE", "/sdcard/gmon.out", 1);
292
monstartup("ppsspp_jni.so");
295
InitFastMath(cpu_info.bNEON);
298
bool skipLogo = false;
299
setlocale( LC_ALL, "C" );
300
std::string user_data_path = savegame_directory;
301
pendingMessages.clear();
303
user_data_path += "/";
306
// We want this to be FIRST.
308
VFSRegister("", new AssetsAssetReader());
309
#elif defined(BLACKBERRY) || defined(IOS)
310
// Packed assets are included in app
311
VFSRegister("", new DirectoryAssetReader(external_directory));
312
#elif !defined(MOBILE_DEVICE) && !defined(_WIN32)
313
VFSRegister("", new DirectoryAssetReader((File::GetExeDirectory() + "assets/").c_str()));
314
VFSRegister("", new DirectoryAssetReader((File::GetExeDirectory()).c_str()));
315
VFSRegister("", new DirectoryAssetReader("/usr/share/ppsspp/assets/"));
317
VFSRegister("", new DirectoryAssetReader("assets/"));
319
VFSRegister("", new DirectoryAssetReader(savegame_directory));
321
#if defined(MOBILE_DEVICE) || !defined(USING_QT_UI)
322
host = new NativeHost();
326
g_Config.internalDataDirectory = savegame_directory;
327
// Maybe there should be an option to use internal memory instead, but I think
328
// that for most people, using external memory (SDCard/USB Storage) makes the
330
g_Config.memStickDirectory = std::string(external_directory) + "/";
331
g_Config.flash0Directory = std::string(external_directory) + "/flash0/";
332
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(MAEMO) || defined(IOS)
333
g_Config.memStickDirectory = user_data_path;
334
g_Config.flash0Directory = std::string(external_directory) + "/flash0/";
335
#elif !defined(_WIN32)
337
if (getenv("XDG_CONFIG_HOME") != NULL)
338
config = getenv("XDG_CONFIG_HOME");
339
else if (getenv("HOME") != NULL)
340
config = getenv("HOME") + std::string("/.config");
344
g_Config.memStickDirectory = config + "/ppsspp/";
345
g_Config.flash0Directory = File::GetExeDirectory() + "/flash0/";
349
logger = new AndroidLogger();
352
LogManager *logman = LogManager::GetInstance();
354
g_Config.AddSearchPath(user_data_path);
355
g_Config.AddSearchPath(g_Config.memStickDirectory + "PSP/SYSTEM/");
356
g_Config.SetDefaultPath(g_Config.memStickDirectory + "PSP/SYSTEM/");
358
g_Config.externalDirectory = external_directory;
362
// On Android, create a PSP directory tree in the external_directory,
363
// to hopefully reduce confusion a bit.
364
ILOG("Creating %s", (g_Config.memStickDirectory + "PSP").c_str());
365
File::CreateDir((g_Config.memStickDirectory + "PSP").c_str());
366
File::CreateDir((g_Config.memStickDirectory + "PSP/SAVEDATA").c_str());
367
File::CreateDir((g_Config.memStickDirectory + "PSP/GAME").c_str());
370
const char *fileToLog = 0;
371
const char *stateToLoad = 0;
374
// Parse command line
375
LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO;
376
for (int i = 1; i < argc; i++) {
377
if (argv[i][0] == '-') {
378
switch (argv[i][1]) {
380
// Enable debug logging
381
// Note that you must also change the max log level in Log.h.
382
logLevel = LogTypes::LDEBUG;
388
g_Config.bJit = true;
389
g_Config.bSaveSettings = false;
392
g_Config.bJit = false;
393
g_Config.bSaveSettings = false;
396
if (!strncmp(argv[i], "--log=", strlen("--log=")) && strlen(argv[i]) > strlen("--log="))
397
fileToLog = argv[i] + strlen("--log=");
398
if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
399
stateToLoad = argv[i] + strlen("--state=");
400
#if !defined(MOBILE_DEVICE)
401
if (!strncmp(argv[i], "--escape-exit", strlen("--escape-exit")))
402
g_Config.bPauseExitsEmulator = true;
407
if (boot_filename.empty()) {
408
boot_filename = argv[i];
411
std::unique_ptr<FileLoader> fileLoader(ConstructFileLoader(boot_filename));
412
if (!fileLoader->Exists()) {
413
fprintf(stderr, "File not found: %s\n", boot_filename.c_str());
417
fprintf(stderr, "Can only boot one file");
423
if (fileToLog != NULL)
424
LogManager::GetInstance()->ChangeFileLog(fileToLog);
427
if (g_Config.currentDirectory == "") {
429
g_Config.currentDirectory = external_directory;
430
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(MAEMO) || defined(IOS) || defined(_WIN32)
431
g_Config.currentDirectory = savegame_directory;
433
if (getenv("HOME") != NULL)
434
g_Config.currentDirectory = getenv("HOME");
436
g_Config.currentDirectory = "./";
440
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
442
LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
443
logman->SetEnable(type, true);
444
logman->SetLogLevel(type, gfxLog && i == LogTypes::G3D ? LogTypes::LDEBUG : logLevel);
446
logman->AddListener(type, logger);
449
// Special hack for G3D as it's very spammy. Need to make a flag for this.
451
logman->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);
453
// Allow the lang directory to be overridden for testing purposes (e.g. Android, where it's hard to
454
// test new languages without recompiling the entire app, which is a hassle).
455
const std::string langOverridePath = g_Config.memStickDirectory + "PSP/SYSTEM/lang/";
457
// If we run into the unlikely case that "lang" is actually a file, just use the built-in translations.
458
if (!File::Exists(langOverridePath) || !File::IsDirectory(langOverridePath))
459
i18nrepo.LoadIni(g_Config.sLanguageIni);
461
i18nrepo.LoadIni(g_Config.sLanguageIni, langOverridePath);
463
I18NCategory *des = GetI18NCategory("DesktopUI");
464
// Note to translators: do not translate this/add this to PPSSPP-lang's files.
465
// It's intended to be custom for every user.
466
// Only add it to your own personal copies of PPSSPP.
468
// TODO: Could allow a setting to specify a font file to load?
469
// TODO: Make this a constant if we can sanely load the font on other systems?
470
AddFontResourceEx(L"assets/Roboto-Condensed.ttf", FR_PRIVATE, NULL);
471
// The font goes by two names, let's allow either one.
472
if (CheckFontIsUsable(L"Roboto Condensed")) {
473
g_Config.sFont = des->T("Font", "Roboto Condensed");
475
g_Config.sFont = des->T("Font", "Roboto");
479
if (!boot_filename.empty() && stateToLoad != NULL)
480
SaveState::Load(stateToLoad);
482
g_gameInfoCache.Init();
484
screenManager = new ScreenManager();
486
screenManager->switchScreen(new EmuScreen(boot_filename));
488
screenManager->switchScreen(new LogoScreen());
491
std::string sysName = System_GetProperty(SYSPROP_NAME);
492
isOuya = KeyMap::IsOuya(sysName);
494
#if !defined(MOBILE_DEVICE) && defined(USING_QT_UI)
495
MainWindow* mainWindow = new MainWindow(0,fs);
497
host = new QtHost(mainWindow);
500
// We do this here, instead of in NativeInitGraphics, because the display may be reset.
501
// When it's reset we don't want to forget all our managed things.
502
if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) {
503
gl_lost_manager_init();
507
void NativeInitGraphics() {
509
// Force backend to GL
510
g_Config.iGPUBackend = GPU_BACKEND_OPENGL;
513
if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) {
514
thin3d = T3DCreateGLContext();
518
thin3d = D3D9_CreateThin3DContext();
522
ui_draw2d.SetAtlas(&ui_atlas);
523
ui_draw2d_front.SetAtlas(&ui_atlas);
525
// memset(&ui_theme, 0, sizeof(ui_theme));
528
ui_theme.uiFont = UI::FontStyle(UBUNTU24, g_Config.sFont.c_str(), 22);
529
ui_theme.uiFontSmall = UI::FontStyle(UBUNTU24, g_Config.sFont.c_str(), 15);
530
ui_theme.uiFontSmaller = UI::FontStyle(UBUNTU24, g_Config.sFont.c_str(), 12);
532
ui_theme.uiFont = UI::FontStyle(UBUNTU24, "", 20);
533
ui_theme.uiFontSmall = UI::FontStyle(UBUNTU24, "", 14);
534
ui_theme.uiFontSmaller = UI::FontStyle(UBUNTU24, "", 11);
537
ui_theme.checkOn = I_CHECKEDBOX;
538
ui_theme.checkOff = I_SQUARE;
539
ui_theme.whiteImage = I_SOLIDWHITE;
540
ui_theme.sliderKnob = I_CIRCLE;
541
ui_theme.dropShadow4Grid = I_DROP_SHADOW;
543
ui_theme.itemStyle.background = UI::Drawable(0x55000000);
544
ui_theme.itemStyle.fgColor = 0xFFFFFFFF;
545
ui_theme.itemFocusedStyle.background = UI::Drawable(0xFFedc24c);
546
ui_theme.itemDownStyle.background = UI::Drawable(0xFFbd9939);
547
ui_theme.itemDownStyle.fgColor = 0xFFFFFFFF;
548
ui_theme.itemDisabledStyle.background = UI::Drawable(0x55E0D4AF);
549
ui_theme.itemDisabledStyle.fgColor = 0x80EEEEEE;
550
ui_theme.itemHighlightedStyle.background = UI::Drawable(0x55bdBB39);
551
ui_theme.itemHighlightedStyle.fgColor = 0xFFFFFFFF;
553
ui_theme.buttonStyle = ui_theme.itemStyle;
554
ui_theme.buttonFocusedStyle = ui_theme.itemFocusedStyle;
555
ui_theme.buttonDownStyle = ui_theme.itemDownStyle;
556
ui_theme.buttonDisabledStyle = ui_theme.itemDisabledStyle;
557
ui_theme.buttonHighlightedStyle = ui_theme.itemHighlightedStyle;
559
ui_theme.popupTitle.fgColor = 0xFFE3BE59;
562
ui_theme.itemFocusedStyle.background = UI::Drawable(0xFF4cc2ed);
563
ui_theme.itemDownStyle.background = UI::Drawable(0xFF39a9ee);
564
ui_theme.itemDisabledStyle.background = UI::Drawable(0x55AFD4E0);
565
ui_theme.itemHighlightedStyle.background = UI::Drawable(0x5539BBbd);
567
ui_theme.popupTitle.fgColor = 0xFF59BEE3;
570
ui_draw2d.Init(thin3d);
571
ui_draw2d_front.Init(thin3d);
574
uiTexture = thin3d->CreateTextureFromFile("ui_atlas_lowmem.zim", T3DImageType::ZIM);
577
uiTexture = thin3d->CreateTextureFromFile("ui_atlas.zim", T3DImageType::ZIM);
580
PanicAlert("Failed to load ui_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory.");
581
ELOG("Failed to load ui_atlas.zim");
584
ExitProcess(ExitCode);
588
uiContext = new UIContext();
589
uiContext->theme = &ui_theme;
591
uiContext->Init(thin3d, thin3d->GetShaderSetPreset(SS_TEXTURE_COLOR_2D), thin3d->GetShaderSetPreset(SS_COLOR_2D), uiTexture, &ui_draw2d, &ui_draw2d_front);
592
if (uiContext->Text())
593
uiContext->Text()->SetFont("Tahoma", 20, 0);
595
screenManager->setUIContext(uiContext);
596
screenManager->setThin3DContext(thin3d);
599
winAudioBackend = CreateAudioBackend((AudioBackendType)g_Config.iAudioBackend);
600
winAudioBackend->Init(MainWindow::GetHWND(), &Win32Mix, 44100);
604
void NativeShutdownGraphics() {
606
delete winAudioBackend;
607
winAudioBackend = NULL;
610
screenManager->deviceLost();
612
g_gameInfoCache.Clear();
614
uiTexture->Release();
619
ui_draw2d.Shutdown();
620
ui_draw2d_front.Shutdown();
625
void TakeScreenshot() {
626
g_TakeScreenshot = false;
628
#if defined(_WIN32) || (defined(USING_QT_UI) && !defined(MOBILE_DEVICE))
629
std::string path = GetSysDirectory(DIRECTORY_SCREENSHOT);
630
while (path.length() > 0 && path.back() == '/') {
631
path.resize(path.size() - 1);
633
if (!File::Exists(path)) {
634
File::CreateDir(path);
637
// First, find a free filename.
640
std::string gameId = g_paramSFO.GetValueString("DISC_ID");
641
if (gameId.empty()) {
647
if (g_Config.bScreenshotsAsPNG)
648
snprintf(filename, sizeof(filename), "%s/%s_%05d.png", path.c_str(), gameId.c_str(), i);
650
snprintf(filename, sizeof(filename), "%s/%s_%05d.jpg", path.c_str(), gameId.c_str(), i);
652
if (!getFileInfo(filename, &info))
657
bool success = TakeGameScreenshot(filename, g_Config.bScreenshotsAsPNG ? SCREENSHOT_PNG : SCREENSHOT_JPG, SCREENSHOT_DISPLAY);
661
I18NCategory *err = GetI18NCategory("Error");
662
osm.Show(err->T("Could not save screenshot file"));
667
void DrawDownloadsOverlay(UIContext &dc) {
668
// Thin bar at the top of the screen like Chrome.
669
std::vector<float> progress = g_DownloadManager.GetCurrentProgress();
670
if (progress.empty()) {
674
static const uint32_t colors[4] = {
683
for (size_t i = 0; i < progress.size(); i++) {
684
float barWidth = 10 + (dc.GetBounds().w - 10) * progress[i];
685
Bounds bounds(0, h * i, barWidth, h);
686
UI::Drawable solid(colors[i & 3]);
687
dc.FillRect(solid, bounds);
693
void NativeRender() {
694
g_GameManager.Update();
696
thin3d->Clear(T3DClear::COLOR | T3DClear::DEPTH | T3DClear::STENCIL, 0xFF000000, 0.0f, 0);
698
T3DViewport viewport;
699
viewport.TopLeftX = 0;
700
viewport.TopLeftY = 0;
701
viewport.Width = pixel_xres;
702
viewport.Height = pixel_yres;
703
viewport.MaxDepth = 1.0;
704
viewport.MinDepth = 0.0;
705
thin3d->SetViewports(1, &viewport);
706
thin3d->SetTargetSize(pixel_xres, pixel_yres);
708
float xres = dp_xres;
709
float yres = dp_yres;
711
// Apply the UIContext bounds as a 2D transformation matrix.
713
if (g_Config.iGPUBackend == GPU_BACKEND_DIRECT3D9) {
714
ortho.setOrthoD3D(0.0f, xres, yres, 0.0f, -1.0f, 1.0f);
715
Matrix4x4 translation;
716
translation.setTranslation(Vec3(-0.5f, -0.5f, 0.0f));
717
ortho = translation * ortho;
719
ortho.setOrtho(0.0f, xres, yres, 0.0f, -1.0f, 1.0f);
722
ui_draw2d.SetDrawMatrix(ortho);
723
ui_draw2d_front.SetDrawMatrix(ortho);
725
screenManager->render();
726
if (screenManager->getUIContext()->Text()) {
727
screenManager->getUIContext()->Text()->OncePerFrame();
730
DrawDownloadsOverlay(*screenManager->getUIContext());
732
if (g_TakeScreenshot) {
738
if (g_Config.iGPUBackend == GPU_BACKEND_DIRECT3D9) {
746
void HandleGlobalMessage(const std::string &msg, const std::string &value) {
747
if (msg == "inputDeviceConnected") {
748
KeyMap::NotifyPadConnected(value);
751
if (msg == "cacheDir") {
752
DiskCachingFileLoaderCache::SetCacheDir(value);
756
void NativeUpdate(InputState &input) {
760
lock_guard lock(pendingMutex);
761
for (size_t i = 0; i < pendingMessages.size(); i++) {
762
HandleGlobalMessage(pendingMessages[i].msg, pendingMessages[i].value);
763
screenManager->sendMessage(pendingMessages[i].msg.c_str(), pendingMessages[i].value.c_str());
765
pendingMessages.clear();
768
g_DownloadManager.Update();
769
screenManager->update(input);
772
void NativeDeviceLost() {
773
g_gameInfoCache.Clear();
774
screenManager->deviceLost();
776
if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) {
779
// Should dirty EVERYTHING
782
bool NativeIsAtTopLevel() {
783
Screen *currentScreen = screenManager->topScreen();
785
bool top = currentScreen->isTopLevel();
786
ILOG("Screen toplevel: %i", (int)top);
787
return currentScreen->isTopLevel();
789
ELOG("No current screen");
794
bool NativeTouch(const TouchInput &touch) {
796
screenManager->touch(touch);
803
bool NativeKey(const KeyInput &key) {
804
// ILOG("Key code: %i flags: %i", key.keyCode, key.flags);
805
#if !defined(MOBILE_DEVICE)
806
if (g_Config.bPauseExitsEmulator) {
807
static std::vector<int> pspKeys;
809
if (KeyMap::KeyToPspButton(key.deviceId, key.keyCode, &pspKeys)) {
810
if (std::find(pspKeys.begin(), pspKeys.end(), VIRTKEY_PAUSE) != pspKeys.end()) {
811
System_SendMessage("finish", "");
817
g_buttonTracker.Process(key);
820
retval = screenManager->key(key);
824
bool NativeAxis(const AxisInput &axis) {
825
using namespace TiltEventProcessor;
827
// only handle tilt events if tilt is enabled.
828
if (g_Config.iTiltInputType == TILT_NULL) {
829
// if tilt events are disabled, then run it through the usual way.
831
return screenManager->axis(axis);
837
// create the base coordinate tilt system from the calibration data.
838
// This is static for no particular reason, can be un-static'ed
839
static Tilt baseTilt;
840
baseTilt.x_ = g_Config.fTiltBaseX;
841
baseTilt.y_ = g_Config.fTiltBaseY;
843
// figure out what the current tilt orientation is by checking the axis event
844
// This is static, since we need to remember where we last were (in terms of orientation)
845
static Tilt currentTilt;
847
// x and y are flipped if we are in landscape orientation. The events are
848
// sent with respect to the portrait coordinate system, while we
849
// take all events in landscape.
850
// see [http://developer.android.com/guide/topics/sensors/sensors_overview.html] for details
851
bool portrait = dp_yres > dp_xres;
852
switch (axis.axisId) {
853
case JOYSTICK_AXIS_ACCELEROMETER_X:
855
currentTilt.x_ = axis.value;
857
currentTilt.y_ = axis.value;
861
case JOYSTICK_AXIS_ACCELEROMETER_Y:
863
currentTilt.y_ = axis.value;
865
currentTilt.x_ = axis.value;
869
case JOYSTICK_AXIS_ACCELEROMETER_Z:
870
//don't handle this now as only landscape is enabled.
871
//TODO: make this generic.
874
case JOYSTICK_AXIS_OUYA_UNKNOWN1:
875
case JOYSTICK_AXIS_OUYA_UNKNOWN2:
876
case JOYSTICK_AXIS_OUYA_UNKNOWN3:
877
case JOYSTICK_AXIS_OUYA_UNKNOWN4:
878
//Don't know how to handle these. Someone should figure it out.
879
//Does the Ouya even have an accelerometer / gyro? I can't find any reference to these
880
//in the Ouya docs...
884
// Don't take over completely!
885
return screenManager->axis(axis);
888
//figure out the sensitivity of the tilt. (sensitivity is originally 0 - 100)
889
//We divide by 50, so that the rest of the 50 units can be used to overshoot the
890
//target. If you want control, you'd keep the sensitivity ~50.
891
//For games that don't need much control but need fast reactions,
892
//then a value of 70-80 is the way to go.
893
float xSensitivity = g_Config.iTiltSensitivityX / 50.0;
894
float ySensitivity = g_Config.iTiltSensitivityY / 50.0;
896
//now transform out current tilt to the calibrated coordinate system
897
Tilt trueTilt = GenTilt(baseTilt, currentTilt, g_Config.bInvertTiltX, g_Config.bInvertTiltY, g_Config.fDeadzoneRadius, xSensitivity, ySensitivity);
899
//now send the appropriate tilt event
900
switch (g_Config.iTiltInputType) {
902
GenerateAnalogStickEvent(trueTilt);
906
GenerateDPadEvent(trueTilt);
909
case TILT_ACTION_BUTTON:
910
GenerateActionButtonEvent(trueTilt);
916
void NativeMessageReceived(const char *message, const char *value) {
917
// We can only have one message queued.
918
lock_guard lock(pendingMutex);
919
PendingMessage pendingMessage;
920
pendingMessage.msg = message;
921
pendingMessage.value = value;
922
pendingMessages.push_back(pendingMessage);
925
void NativeResized() {
929
// Modifying the bounds here can be used to "inset" the whole image to gain borders for TV overscan etc.
930
// The UI now supports any offset but not the EmuScreen yet.
931
uiContext->SetBounds(Bounds(0, 0, dp_xres, dp_yres));
932
// uiContext->SetBounds(Bounds(dp_xres/2, 0, dp_xres / 2, dp_yres / 2));
935
// OSX 10.6 and SDL 1.2 bug.
936
#if defined(__APPLE__) && !defined(USING_QT_UI)
937
static int dp_xres_old=dp_xres;
938
if (dp_xres != dp_xres_old) {
939
// uiTexture->Load("ui_atlas.zim");
940
dp_xres_old = dp_xres;
946
void NativeShutdown() {
947
if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) {
948
gl_lost_manager_shutdown();
951
screenManager->shutdown();
952
delete screenManager;
955
g_gameInfoCache.Shutdown();
961
LogManager::Shutdown();
963
#ifdef ANDROID_NDK_PROFILER
967
ILOG("NativeShutdown called");
969
System_SendMessage("finish", "");
970
// This means that the activity has been completely destroyed. PPSSPP does not
971
// boot up correctly with "dirty" global variables currently, so we hack around that
972
// by simply exiting.
978
RemoveFontResourceEx(L"assets/Roboto-Condensed.ttf", FR_PRIVATE, NULL);